JavaScript

基础

输出

alert("hello");  			// 弹出警告对话框
document.write("hello");    // 向body中输出内容
console.log("hello");  		// 向控制台输出

输入

prompt函数可以弹出带文本框的提示框,输入的内容作为返回值(字符串类型),参数为提示文字。

result = prompt("请输入文字:");

编写位置

script标签中

type可以省略

<script type="text/javascript">
    alert("hello");
</script>

导入外部js

如果script标签使用了src属性,则标签之间的js代码会被忽略。

<script src="script.js"></script>

一些标签的属性中

<button onclick="alert('hello');">按钮</button>
<a href="javascript:alert('hello');">超链接1</a>
<a href="javascript:;">超链接2</a>

基本语法

  • 严格区分大小写

  • (强烈建议)以;结尾

  • 标识符:由字母、数字、_$组成,不能以数字开头

  • 字符串单双引号都可以

数据类型

6种数据类型:String、Number、Boolean、Null、Undefined、Object

检查变量类型

var a = 123;
console.log(typeof a);

Number

Number.MAX_VALUE	// 1.7976931348623157e+308
Number.MIN_VALUE	// 5e-324

// 超过最大值的话
var a = Number.MAX_VALUE * Number.MAX_VALUE;
console.log(a);		// Infinity,如果是负的话就是-Infinity
console.log(typeof Infinity);	// number,Infinity是字面量

// NaN也是字面量
var b = "abc" * "bcd";
console.log(b);				// NaN
console.log(typeof NaN);	// number

进制

  • 16进制:0x开头
  • 8进制:0开头
  • 2进制:0b开头,但不是所有的浏览器都支持

Boolean

truefalse

Null

null:表示空对象

console.log(typeof null);	// object

Undefined

undefined:声明但未赋值的变量

console.log(typeof undefined);	// undefined

强制类型转换

转为String

// 方法一
// Number Boolean可以使用toString()方法,null或undefined使用此方法会报错
var a = 123;
console.log(typeof a.toString());

// 方法二
// 用String()方法,支持null和undefined
console.log(typeof String(a));

转为Number

// 方法一
// Number()方法.不能转换则输出NaN,空串或空白字符串输出0;true转为1,false转为0;null转为0;undefined转为NaN
a = "123";
b = Number(a);

// 方法二
// parseInt()。从左往右提取整数,遇到其他字符则停止
// parseFloat()。同理提取小数
// 对于非String类型,会先转换为String,再parse
a = "123.456px";
b = parseInt(a);	// 123
c = parseFloat(a);	// 123.456
parseInt(true);		// N

a = "070";
b = parseInt(a);	// 有些浏览器会当成十进制,有些当成八进制
c = parseInt(a, 8);	// 指定进制

转为Boolean

// Boolean()
// 数字:0, NaN是false
// 字符串:空串是false
// null, undefined是false
// 其余都是true

运算符

  • typeof的结果类型为字符串

  • 算数运算符

    + - * / %

    • 非数值参与运算先转为数值(除字符串加法)

    • 任何值和NaN运算结果都为NaN(除字符串加法)

    • 字符串相加为拼接

    • 任何值和字符串相加都会将该值转换为字符串再拼接

  • 一元运算符

    + -

    • 对于非数值类型会先转换为数字,如+"123"的结果为数值123
  • 自增++, 自减--

  • 逻辑运算符

    ! && ||

    • 短路计算

    • 非布尔值先转换为布尔值,返回的是原值

      // 与运算:如果第一个值为true,返回第二个值;如果第一个值为false,返回第一个值
      console.log(5 && 6);	// 6
      console.log(0 && 2);	// 0
      console.log(2 && 0);	// 0
      console.log(NaN && 0);	// NaN
      console.log(0 && NaN);	// 0
      // 或运算:第一个为true,返回第一个;第一个为false,返回第二个
      console.log(2 || 1);	// 2
      console.log(NaN || 1);	// 1

  • 赋值运算符=+=-=、...

  • 关系运算符

    • 非数值转换为数值
    • 任何值和NaN做任何比较都为false
    • 如果两边都是字符串,会比较字符串中字符的unicode编码(一个一个比;如果前面的字符相同,有字符大于空字符,"ab" > "a"
  • 相等运算符

    • ==!=

      • 类型不同会转换为相同的类型

      • 特殊情况

        console.log(null == 0);		// false
        console.log(null == undefined);	// true
        // NaN不等于任何值包括它自己

      • 通过isNaN()函数判断是否为NaN

    • ===!==

      • 类型不同直接返回
  • 条件运算符(三元运算符):条件 ? 语句1 : 语句2

使用Unicode

  • js中:\u + 4位16进制编码

  • HTML中:&#十进制编码;

代码块

{}

只有分组的作用。代码块内的内容在代码块外完全可见

条件语句

if () {
} else if () {
} else {
}
switch () {
    case 表达式:
        语句
        break;
    case 表达式:
        语句
        break;
    default:
        语句
}

循环语句

while (条件) {
}
do {
} while (条件);
for (;;) {
}

break和continue

可以为循环创建一个标签,break或continue后加标签将会结束指定的循环而不是最近的。

// 输出1 1后结束
outer:
for (var i = 1; i <= 5; i++) {
    for (var j = 1; j <= 5; j++) {
        console.log(i, j);
        break outer;
    }
}
// 输出1 1到5 1
outer:
for (var i = 1; i <= 5; i++) {
    for (var j = 1; j <= 5; j++) {
        console.log(i, j);
        continue outer;
    }
}

对象

分类

  • 内建对象:由ES标准定义的对象,在任何ES的实现中都可以使用。如:Math、String、Number、Boolean、Function、Object……
  • 宿主对象:由JS运行环境提供的对象(主要指浏览器提供的对象)。如:BOM(浏览器对象)、DOM(文档对象)
  • 自定义对象

基本操作

// 使用new关键字调用的函数是构造函数
var obj = new Object();

// 向对象添加属性
obj.name = "孙悟空";
obj.gender = "男";

// 读取属性
console.log(obj.name);

// 读取对象中没有的属性会返回undefined
console.log(obj.hello);

// 修改属性值
obj.name = "Tom";

// 删除属性
delete obj.name;

属性名和属性值

属性名不强制要求遵守标识符的规范。

如果要使用特殊的属性名,不能采用.的方式操作,使用对象["属性名"]的方式。

使用[]的方式操作属性更灵活,[]中可以传递一个变量。

obj["123"] = 789;
var tmp = "123";
console.log(obj["123"]);
console.log(obj[tmp]);

属性值可以是任意数据类型。

in运算符可以检查一个对象中是否含有指定的属性。

console.log("name" in obj);
console.log("hello" in obj);

字面量

和调用构造方法一样,可以同时指定属性。

字面量的属性名可以加引号也可以不加(推荐),如果使用特殊的名字必须加引号。最后一个属性之后没有逗号。

var obj = {};
obj.name = "孙悟空";

var obj = {
    name: "猪八戒",
    age: 29,
    test: {
        name: "沙和尚"
    }
};

函数

函数也是一个对象。

// 创建1:几乎不用
var fun = new Function();
console.log(typeof fun);	// function

// 可以将代码以字符串的形式传给构造函数
var fun = new Function("console.log('hello')");

// 创建2:使用函数声明
function fun2(形参) {
    
}

// 创建3(将匿名函数赋值给变量)
var fun3 = function(形参) {
    
};

// 调用函数
fun(实参);

参数

调用函数时,不会检查实参的类型。

也不会检查实参的数量,多余的不会被赋值,少了的话形参就是undefined。

参数可以是任意类型,包括对象、函数。

function sum(a, b) {
    console.log(a + b);
}
sum(123, 456, "hello");		// 579

返回值

return语句后不写任何值或不写return语句,则返回undefined。

返回值可以是任意类型,包括函数。

function sum(a, b) {
    return a + b;
}
var result = sum(1, 2);

function fun() {
    function fun2() {
        alert("hello");
    }
    return fun2;
}
fun()();

立即执行函数

// 函数用()包起来表示一个整体,不然会报错
(function sum(a, b) {
    console.log(a + b);
})(123, 456);

call和apply方法

  • fun()fun.call()fun.apply()都可以调用函数
  • call和apply会将第一个参数指定为函数中的this
  • call依次传实参,apply以数组的形式传参
function sum(a, b) {
    console.log(this.name, a + b);
}
var obj = {name: "Tom"};
sum.call(obj, 1, 2);
sum.apply(obj, [1, 2]);

arguments

表示函数的参数。和this一样,是传给函数的隐含参数。arguments是一个类数组对象(不是Array),可以用索引操作和获取长度。它有一个属性callee,就是当前的函数对象。不论有没有写形参,都能通过arguments获取到传入的实参。

function fun(a) {
    var b = arguments[1];
    console.log(arguments.length);          // 2
    console.log(a, b);                      // 1 2
    console.log(arguments.callee == fun);   // true
}
fun(1, 2);

方法

函数作为一个对象的属性。

var obj = new Object();
obj.name = "孙悟空";
obj.sayName = function() {
}

var obj2 = {
    name: "猪八戒",
    sayName: function() {
    }
}

枚举属性

// 将obj的属性名赋值给n
for (var n in obj) {
    console.log(n, obj[n]);		// 输出属性名和属性值
}

作用域

全局作用域

  • 页面打开时创建,关闭时销毁。

  • 全局作用域中有一个全局对象window,代表浏览器窗口,由浏览器创建可以直接使用。

  • 在全局作用域创建的变量都会作为window对象的属性保存。

    var a = 10;
    console.log(window.a);

  • 在全局作用域创建的函数都会作为window对象的方法保存。

变量的声明提前

使用var关键字声明的变量会在所有的代码执行之前被声明,如果声明变量不使用var,则不会声明提前。

a = 10;		// 相当于window.a
console.log(a);		// 10
console.log(a);		// 报错,a未定义
a = 10;
// 相当于在最前面声明了a,所以没有报错
console.log(a);		// undefined
var a = 10;

// 等价于
var a;
console.log(a);		// undefined
a = 10;

函数的声明提前

使用函数声明形式创建的函数会在所有代码执行之前被创建。

fun();		// 不会报错
function fun() {
    console.log("hello");
}

fun2();		// 报错,未定义
var fun2 = function() {
    console.log("hi");
}

函数作用域

调用时创建,函数执行完毕后销毁。

函数作用域中访问全局变量加window.

也有声明提前

在函数中不使用var声明的变量都会成为全局变量。

var a = 1;
function fun() {
    a = 2;
    b = 3;
}
fun();
console.log(a, b);	// 2 3

this

调用函数时会向函数传递一个隐含参数this,称为函数执行的上下文对象,根据函数调用方式的不同,this会指向不同的对象:

  • 以函数形式调用,this是window
  • 以方法形式调用,this是调用方法的对象

其实第一种是第二种的特殊情况,直接调用函数相当于window.xxx

var name = "孙悟空";
function fun() {
    console.log(this.name);
}
var obj = {
    name: "沙和尚",
    sayName: fun
};
fun();              // 孙悟空
obj.sayName();      // 沙和尚

构造函数

就是一个普通的函数,习惯首字母大写。调用时需要使用new关键字。

执行流程:

  • 创建一个新对象
  • 将新对象设置为函数中的this
  • 执行函数代码
  • 返回新对象

同一个构造函数创建的对象称为一类对象,也将构造函数称为一个类。将通过构造函数创建的对象称为该类的实例。

function Person(name, age, gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
}
var person = new Person("孙悟空", 18, "男");

instanceof

检查一个对象是否是一个类的实例。所有对象都是Object的后代。

console.log(person instanceof Person);

原型(prototype)

每一个函数都有prototype属性,这个属性对应一个对象,即原型对象。

当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性指向原型对象,可以通过__proto__来访问。

原型对象相当于一个公共区域,同一个类的实例都可以访问,可以将对象中共有的内容设置到原型对象中。

当访问一个对象的属性或方法时:

  • 先在对象自身寻找
  • 没有则去原型对象中寻找
  • 没有则去原型的原型中寻找
  • 直到找到Object对象的原型。Object对象的原型没有原型。在Object的原型中依然没有找到则返回undefined

function MyClass() {
}
MyClass.prototype.a = 123;
MyClass.prototype.sayHello = function() {
    console.log("hello");
}
var mc1 = new MyClass();
var mc2 = new MyClass();
console.log(mc1.__proto__ == mc2.__proto__);    // true
console.log(mc1.a);
mc2.sayHello();

// 使用in关键字检查对象中是否含有某个属性时,如果原型中有也会返回true。
console.log("a" in mc1);        // true
// 使用对象的hasOwnProperty()来检查自身对象中是否含有该属性
console.log(mc1.hasOwnProperty("a"))    // false

// 原型链
console.log(mc1.__proto__.__proto__);	// Object
console.log(mc1.__proto__.__proto__.__proto__);	// null

结论:创建构造函数时可以将共有的属性和方法添加到原型对象中。

toString

打印一个对象相当于输出对象toString方法的返回值。toString方法定义在Object的原型中。

console.log(mc1.__proto__.__proto__.hasOwnProperty("toString"));	// true
// 为Person原型添加toString方法覆盖Object原型的toString方法
Person.prototype.toString = function() {
    return xxx;
};

垃圾回收(GC)

JS拥有垃圾自动回收机制,只需要我们将不再使用的对象设置为null。

数组

也是对象。使用数字(从0开始)作为索引操作元素。元素可以是任意类型。

基本操作

// 创建
var arr = new Array();
var arr = new Array(10);	// 创建长度为10的数组
var arr = new Array(10, 20, 30);	// 创建元素为10 20 30的数组

// 添加
arr[0] = 10;
arr[1] = 45;
arr[arr.length] = 62;	// 向数组最后添加

// 读取
// 读取不存在的索引返回undefined
console.log(arr[0]);

// 获取长度
// 对于连续数组就是元素的个数,对于非连续数组结果为最大索引+1
console.log(arr.length);

// 修改长度
// 大于原长度,多余的会空出来
// 小于则多出的被删除
arr.length = 10;

字面量

使用[],还可以指定初始元素。

var arr = [];
var arr = ["hello", 1, true, null, undefined];

方法

push

向数组末尾添加一个或多个元素,并返回新的长度。

arr.push(1, 2, "唐僧");
var result = arr.push(1, 2, "唐僧");

pop

删除并返回数组最后一个元素。

arr.pop();
var result = arr.pop();

unshift

向数组开头添加一个或多个元素,并返回新数组的长度。

shift

删除并返回数组的第一个元素。

slice

提取指定开始到结尾位置(前闭后开)的元素,不会改变原数组。不传第二个参数表示取到尾。负数表示倒着数。

var arr = [0, 1, 2, 3, 4];
result = arr.slice(1, 3);   // 1, 2
result = arr.slice(2);      // 2, 3, 4
result = arr.slice(2, -1);  // 2, 3

splice

删除数组中指定位置的元素,插入新元素,并返回被删除的元素。

  • 参数1:开始位置索引
  • 参数2:删除的数量(为0表示不删)
  • 参数3及以后:插入到开始位置前面的元素
var arr = [0, 1, 2, 3, 4];
console.log(arr.splice(1, 2));  // 1, 2
console.log(arr);   // 0, 3, 4

var arr = [0, 1, 2, 3, 4];
console.log(arr.splice(1, 2, 10, 11));  // 1, 2
console.log(arr);   // 0, 10, 11, 3, 4

concat

连接两个或多个数组/元素,并返回新数组,不会改变原数组。

var result = arr.concat(arr2, arr3, "a", 1);

join

将数组转为字符串并返回,不改变原数组。可以指定分隔符(默认,)。

var arr = [0, 1, 2, 3, 4];
console.log(arr.join("@"));     // 0@1@2@3@4

reverse

反转数组,会修改原数组。

sort

排序,会修改原数组。对字符串或数字会按照unicode编码排序(所以用于数字排序可能会出错)。

var arr = [3, 11, 2];
arr.sort();
console.log(arr);     // 11, 2, 3

可以指定比较函数,函数返回值大于0表示要交换。

arr.sort(function(x, y) {
    return x - y;	// 升序
    return y - x;	// 降序
});

遍历

for (var i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}
// 支持IE8以上浏览器
/* 浏览器会向函数传递三个参数
 * 第一个参数:遍历的元素
 * 第二个参数:元素的索引
 * 第三个参数:遍历的数组
 */
arr.forEach(function(value, index, array) {
    console.log(index, value, array);
});

Date

// 默认为当前时间
var d = new Date();

// 指定时间:月/日/年 时:分:秒
var d2 = new Date("01/10/2023 15:04:36");

// 方法
// 获取日
console.log(d2.getDate());      // 10
// 获取星期,0表示星期天
console.log(d2.getDay());       // 2
// 获取月,0~11
console.log(d2.getMonth());     // 0
// 获取年
console.log(d2.getFullYear());  // 2023
// 获取时间戳,1970.1.1
console.log(d2.getTime());      // 1673334276000
// 获取当前时间戳
console.log(Date.now());

Math

不是构造函数,是一个工具类。

属性EPI

方法abs()ceil()floor()round()random()0到1的随机数、max()min()pow()sqrt()

包装类

StringNumberBoolean

var num = new Number(3);

当对一些基本数据类型的值去调用属性和方法时,浏览器会临时将其转换为包装类对象,然后再调用属性和方法,调用完再转换回基本数据类型。

String

在底层以数组形式保存。

var str = "hello";
console.log(str[0]);		// h
console.log(str.length);	// 5

方法

// 指定位置字符
console.log(str.charAt(0));     // h

// 指定位置字符的unicode编码
console.log(str.charCodeAt(0)); // 104

// 根据unicode编码获取字符
console.log(String.fromCharCode(104));  // h

// 拼接,同+
console.log(str.concat(" world"));  // hello world

// 查找,第二个参数表示开始查找的位置。返回第一次出现的位置,否则-1
console.log(str.indexOf("h"));      // 0
console.log(str.indexOf("h", 1));   // -1
console.log(str.lastIndexOf("l"));      // 3
console.log(str.lastIndexOf("l", 2));   // 2

// 截取
str.slice		// 同数组
str.substring	// 不能传负数,负数会转为0,如果第二个参数小于第一个会交换参数
str.substr		// 同substring,非标准方法

// 大小写转换
str.toLowerCase()
str.toUpperCase()

支持正则的方法

// 拆分。传空串则拆分每一个字符
console.log(str.split("e"));        // ['h', 'llo']
console.log(str.split(/[a-z]/));	// 根据小写字母拆分

// 搜索。参数为普通字符同indexOf,参数还可以是正则表达式对象,返回第一次匹配的位置
console.log("skd6ds".search(/[0-9]/));	// 3

// 匹配。加g则匹配多个,返回数组。
console.log("1a2b3C".match(/[a-z]/));       // {'a', index: 1, input: '1a2b3C', groups: undefined}
console.log("1a2b3C".match(/[a-z]/g));      // ['a', 'b']
console.log("1a2b3C".match(/[a-z]/ig));     // ['a', 'b', 'C']

// 替换。加g替换多个
console.log("1a2a3A".replace(/[a-z]/ig, "@"));  // 1@2@3@

正则表达式

// 创建正则表达式对象
// 构造函数:RegExp(正则表达式, 匹配模式)
// 字面量:/正则表达式/匹配模式
// 第二个参数是匹配模式:i 忽略大小写,g 全局匹配模式
var reg = new RegExp("a");
var reg2 = new RegExp("a", "i");
var reg3 = /a/i;
var reg4 = new RegExp("\\.");	// 在构造函数中使用转义要两个\

// 检查匹配
console.log(reg.test("A"));     // false
console.log(reg2.test("A"));     // true

// 语法
| 				// 或
[ab],[a-z]		// []中任意字符
[^0-9]			// 除了
{n}				// n次
{m,n}			// m到n次
{m,}			// m次以上
()				// 括号
+				// 至少一次
*				// 0次或多次
?				// 0次或1次
^				// 开头
$				// 结尾

.				// 任意字符
\				// 转义
\w				// 任意字母、数字、下划线
\W				// 与\w相反
\d				// 任意数字
\D				// 非数字
\s				// 空白字符
\S				// 非空白字符
\b				// 单词边界
\B				// 除了单词边界

// \b演示
console.log(/child/.test("hello children"));        // true
console.log(/\bchild\b/.test("hello children"));    // false

// 去除开头结尾空格
str.replace(/^\s*|\s*$/g, );

JavaScript
https://shuusui.site/blog/2022/12/31/js/
作者
Shuusui
发布于
2022年12月31日
更新于
2022年12月31日
许可协议