1.变量声明
注意:在同一个作用域,相同名称的变量不可以重复声明,否则会报错。
//声明后再初始化
let 变量名[ = undefined];
变量名 = 值;
//声明时同时初始化
let 变量名 = 值;
变量在赋值后可以通过重新赋值改变其值。
注意:新的值的类型不一定与老的值的类型相同。
let a = 1;
a = { name: "张三" };
console.log(a); // { name: "张三" }
2.变量声明提升(Hoisting)
变量声明不支持提升。
console.log(a); // 报错
let a = 1;
3.变量作用域
变量的作用域是块作用域,即外围离变量最近的代码块。全局变量的作用域是定义它们的文件。
3.1全局变量
名称 | 修饰符 |
全局变量 | let |
3.2成员变量
注意:静态字段、实例字段、数据属性声明时,变量名前务必不要添加 let
关键字。
名称 | 修饰符 |
静态字段(类) | static |
实例字段(类) | —————— |
数据属性(对象字面量) | —————— |
3.3局部变量
名称 | 修饰符 |
局部变量 | let |
值形参 | —————— |
默认值形参 | —————— |
剩余形参 | ... |
4.赋值
当我们将一个原始类型的值赋给变量时,我们是将原始类型的值本身存储到了变量中。
当我们将一个引用类型的值(即对象)赋给变量时,我们并没有将对象本身存储到了变量中,而是将对象的引用存储到了变量中。
5.变量引用表达式
变量名;
6.复制值
通过变量将一个原始类型的值赋给另一个变量时,原始类型的值会被复制到新变量中。此时,两个变量是独立的,互不干扰。
let a = 1;
let b = a;
console.log(b); // 1
a = 2;
console.log(b); // 1
通过变量将一个引用类型的值(即对象)赋给另一个变量时,对象的引用会被复制到新变量中。此时,因为两个变量都存储的是同一个对象的引用,所以一个对象上的变化会在另一个对象上反应出来。
let o1 = { a: 1 };
let o2 = o1;
console.log(o2.a); // 1
o1.a = 2;
console.log(o2.a); // 2
7.解构(Destructuring)赋值
解构赋值用于在一条语句中给多个(或一个)变量(或常量)赋值。
数组字面量解构赋值是按位置赋值,而对象字面量解构赋值是按命名赋值。
注意:赋值表达式右侧的数组字面量和对象字面量是复合数据结构,所以只占用一个值的空间,同理,赋值表达式左侧的类似于数组字面量和对象字面量的复合数据结构也只占用一个变量或常量的空间。
注意:对赋值表达式左侧变量的值的更改不会反应到赋值表达式右侧原来的数组字面量或对象字面量。
注意:与普通赋值不同,解构赋值是并行赋值,最常见的示例就是使用解构赋值交换两个变量的值。
//使用普通赋值交换两个变量的值
let a = 1;
let b = 2;
let arr = [b, a];
a = arr[0];
b = arr[1];
console.log(a, b); // 2 1
//使用数组字面量解构赋值交换两个变量的值
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a, b); // 2 1
//使用对象字面量解构赋值交换两个变量的值
let a = 1;
let b = 2;
({ a, b } = { a: b, b: a });
console.log(a, b); // 2 1
7.1数组字面量解构赋值
7.1.1用于变量赋值
let [变量名, 变量名 = 默认值, ...剩余变量名] = 可迭代对象;
//左侧数量等于右侧数量
let [a, b] = [1, 2];
console.log(a, b); // 1 2
//左侧数量小于右侧数量
//右侧多余的元素会被忽略
let [a, b] = [1, 2, 3];
console.log(a, b); // 1 2
//右侧多余的元素会被打包成数组字面量
let [a, b, ...rest] = [1, 2, 3, 4, 5];
console.log(rest); // [3, 4, 5]
//左侧数量大于右侧数量
//左侧多余的变量会被赋予undefined值
let [a, b, c] = [1, 2];
console.log(a, b, c); // 1 2 undefined
//左侧多余的变量会被赋予默认值
let [a, b, c = 3] = [1, 2];
console.log(a, b, c); // 1 2 3
//左侧数组为稀疏数组(一个空槽也占一个元素的位置)
//空槽在前面
let [ , a, b] = [1, 2, 3];
console.log(a, b); // 2 3
//空槽在中间
let [a, , b] = [1, 2, 3];
console.log(a, b); // 1 3
//注意:末尾的逗号是为了添加一个新元素时方便,不是空槽。
let [a, b, ] = [1, 2, 3];
console.log(a, b); // 1 2
//给已声明的变量赋值时,不需要在赋值表达式左侧添加let关键字。
let a, b;
[a, b] = [1, 2];
console.log(a, b); // 1 2
实际上,赋值表达式左侧内的变量名可以是任何可赋值的标识符,比如对象字面量的属性访问表达式。
let o = {};
[o.a, o.b] = [1, 2];
console.log(o.a, o.b); // 1 2
实际上,赋值表达式右侧可以是任何可迭代(Iterable)对象。
let [a, b] = "12";
console.log(a, b); // 1 2
let [a, b] = new Set([1, 2]);
console.log(a, b); // 1 2
赋值表达式右侧内的元素还可以是函数声明。
//命名函数
let [a, b] = [1, function f() {
return 2;
}];
//匿名函数
let [a, b] = [1, function () {
return 2;
}];
//箭头函数
let [a, b] = [1, () => {
return 2;
}];
//都输出一样
console.log(a, b()); // 1 2
7.1.2用于函数形参
规则参考上面的“用于变量赋值”章节。
function f([a, b]) {
console.log(a, b);
}
f([1, 2]); // 1 2
7.2对象字面量解构赋值
7.2.1用于变量赋值
let { 属性名: 变量名, 属性名, 属性名 = 默认值, 属性名: 变量名 = 默认值, ...剩余变量名 } = 对象字面量;
//左侧数量等于右侧数量
//属性名与变量名不相同(前面a是右侧对象字面量内的属性名,后面x是变量名)
let { a: x, b: y } = { a: 1, b: 2 };
console.log(x, y); // 1 2
//属性名与变量名相同(前面a是右侧对象字面量内的属性名,后面a是变量名)
let { a: a, b: b } = { a: 1, b: 2 };
//简写
let { a, b } = { a: 1, b: 2 };
console.log(a, b); // 1 2
//左侧数量小于右侧数量
//右侧多余的属性会被忽略
let { a, b } = { a: 1, b: 2, c: 3 };
console.log(a, b); // 1 2
//右侧多余的属性会被打包成对象字面量
let { a, b, ...rest } = { a: 1, b: 2, c: 3, d: 4, e: 5 };
console.log(rest); // { c: 3, d: 4, e: 5 }
//左侧数量大于右侧数量
//左侧多余的变量会被赋予undefined值
let { a, b, c } = { a: 1, b: 2 };
console.log(a, b, c); // 1 2 undefined
//左侧多余的变量会被赋予默认值
let { a, b, c = 3 } = { a: 1, b: 2 };
console.log(a, b, c); // 1 2 3
//给已声明的变量赋值时,不需要在赋值表达式左侧添加let关键字,但赋值表达式必须被包裹在一对圆括号内。
let a, b;
({ a, b } = { a: 1, b: 2 });
console.log(a, b); // 1 2
实际上,赋值表达式左侧内的变量名可以是任何可赋值的标识符,比如数组的元素访问表达式。
let arr = [];
({ a: arr[0], b: arr[1] } = { a: 1, b: 2 });
console.log(arr[0], arr[1]); // 1 2
注意:如果赋值表达式右侧是原始类型的值,则原始类型的值会被自动转换成对象,但是 undefined
和 null
不会被自动转换成对象。
let { constructor: c } = 8;
console.log(c === Number); // true
let { length } = "foobar";
console.log(length); // 6
let { _ } = undefined;
console.log(_); // 报错
let { _ } = Object(undefined);
console.log(_); // undefined
let { _ } = null;
console.log(_); // 报错
let { _ } = Object(null);
console.log(_); // undefined
赋值表达式右侧内的属性值还可以是函数声明。
//命名函数
let { a, b } = { a: 1, b: function f() {
return 2;
}};
//匿名函数
let { a, b } = { a: 1, b: function () {
return 2;
}};
//箭头函数
let { a, b } = { a: 1, b: () => {
return 2;
}};
//都输出一样
console.log(a, b()); // 1 2
7.2.2用于函数形参
规则参考上面的“用于变量赋值”章节。
function f1( { a: x, b: y } ) {
console.log(x, y);
}
function f2( { a, b } ) {
console.log(a, b);
}
f1({ a: 1, b: 2 }); // 1 2
f2({ a: 1, b: 2 }); // 1 2
原创文章,作者:huoxiaoqiang,如若转载,请注明出处:https://www.huoxiaoqiang.com/javascript/javascriptlang/4734.html