1.5JavaScript语言的变量(Variable)

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

注意:如果赋值表达式右侧是原始类型的值,则原始类型的值会被自动转换成对象,但是 undefinednull 不会被自动转换成对象。

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

(0)
huoxiaoqiang的头像huoxiaoqiang
上一篇 2020年8月4日
下一篇 2020年8月6日

相关推荐

  • 1.8JavaScript语言的语句(Statement)

    1.空(Empty)语句 空语句只使用一个分号 ; 表示,表示不提供任何语句。与空语句相反的是块语句。 比如,以下的例子将 for 循环语句后的 {} 替换为 ;。 2.块(Block)语句 块(Block)语句又被称为代码块(Code Block)语句。 块语句由一对花括号 {} 组成,花括号内部包括零条或多条语句。…

  • 2.11JavaScript语言的异步函数

    1.异步函数声明 如果您想声明一个异步函数,只需要首先在普通函数前添加一个 async 关键字,然后在函数体内至少包含一个 await 关键字即可。普通函数支持函数声明、函数表达式、箭头函数、立即调用的函数表达式和实例方法。 2.await表达式 await 关键字后的表达式可以是 实现了 Thenable 接口的对象…

  • 2.3JavaScript原始类型之符号(Symbol)

    一个符号实例用于表示一个唯一的标识符。 1.创建符号实例 注意:符号实例不支持字面量创建方式。 注意:符号实例不支持 new Symbol() 创建方式。 Symbol() 函数可选地接受一个字符串实参,字符串实参仅仅作为对符号实例的描述,将来可以通过这个字符串实参来调试代码,不影响任何事情。 Symbol() 函数的…

发表回复

登录后才能评论