ES6 新特性

变量的解构赋值

数组的解构赋值

基本用法:

let [a, b, c] = [1, 2, 3];
console.log({a, b, c}); // { a: 1, b: 2, c: 3}

上面代码表示,可以从数组中提取值,按照对应的位置,对变量进行赋值。


如果解构不成功,变量的值就等于undefined。

let [foo] = [];
let [bar, foo] = [1];

以上两种情况都属于解构不成功,foo的值都会等于undefined。


在进行解构时,也可以只解构一部分数据。

let [x, y] = [1, 2, 3];
console.log({x, y});  // { x: 1, y: 2 }

这种情况是属于不完全解构


默认值:

解构赋值允许指定默认值。

let [x= 1] = [];
x // 1

let [x, y] = [1];
{x, y} // { x: 1, y: undefined }
let [x, y = 2] = [1, undefined];
{x, y} // { x: 1, y: 2 }

在 ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。

let [x = 1] = [undefined]
x // 1

let [x = 1] = [null]
x // null

对象的解构赋值

基本用法:

let { x, y } = { x: 'a', y: 'b' };
x // 'a'
y // 'b'

let { y, x, z } = { x: 'a', y: 'b' }
x // 'a'
y // 'b'
z // undefined

变量必须与对象的属性同名,才能取到正确的值,否则undefined。


对象的解构赋值是下面形式的简写。

let { x: x, y: y } = { x: 'a', y: 'b' };

也就是说,对象的解构赋值的内部机制,是先找到同名的属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

let { x: name } = { x: 'a' }
name // 'a'
x // error: x is not defined

默认值:

let { x = 3 } = {}
x // 3

默认值生效的条件是,对象的属性值严格等于undefined。

let { x = 3 } = { x: undefined }
x // 3

let { x = 3 } = { x: null };
x // null

字符串的解构赋值

字符串在进行解构赋值时会被转换成一个类似数组的对象。

let [x, y, z] = 'age'
x // a
y // g
z // e

let { length: len } = 'age'
len // 3

函数参数的解构赋值

function log([x, y]) {
  console.log({ x, y }); // { x: 1, y: 2 }
}

log([1, 2]);

函数参数的解构赋值也可以使用默认值:

function log({ x = 0, y = 0 } = {}) {
  console.log({ x, y });
}

log({ x: 1, y: 2 }); // { x: 1, y: 2 }
log({ x: 1 });       // { x: 1, y: 0 }
log({});             // { x: 0, y: 0 }
log();               // { x: 0, y: 0 }

用途

交换变量的值:

let x = 1,
  y = 2;

[x, y] = [y, x];
console.log({ x, y }); // { x: 2, y: 1 }

从函数返回多个值:

function log1() {
  // 返回一个数组
  return [1, 2, 3];
}

function log2() {
  // 返回一个对象
  return { name: "Tom", age: 100 };
}

let [a, b, c] = log1();
console.log({ a, b, c });   // { a: 1, b: 2, c: 3 }

let { name, age } = log2();
console.log({ name, age }); // { name: "Tom", age: 100 }

函数参数的定义:

// 参数是一组有次序的值
function log([name, age, color]) {
  console.log({ name, age, color });  // { name: 'Tom', age: 18, color: 'pink' }
}
log(["Tom", 18, "pink"]);

// 参数是一组无次序的值
function log({ name, age, color }) {
  console.log({ name, age, color });  // { name: 'Tom', age: 18, color: 'pink' }
}
log({ age: 18, color: "pink", name: "Tom" });

字符串的扩展

遍历器接口:
for...of为字符串添加了遍历器接口,使得字符串可以被for...of循环遍历。

for (let key of "name") {
  console.log(key);  // n a m e
}

模板字符串

模板字符串是增强版的字符串,用反引号(`)标识,它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

// 普通模板字符串
const str1 = `hello world`;

// 多行字符串
const str2 = `hello
world
`;

// 字符串中签入变量
const name = "Tom";
const str3 = `名字:${name}`;

console.log(str1);
console.log(str2);
console.log(str3);

在这里插入图片描述


函数的扩展

参数的默认值

// ES5 写法
function log(x, y) {
	if (typeof y === 'undefined') {
		y = 100;
	}
	console.log(x, y);
}

log(10);     // 10 100
log(10, 20); // 10 20

// ES6 写法
function log(x, y = 100) {
	console.log(x, y);
}

log(10);     // 10 100
log(10, 20); // 10 20

与解构赋值默认值结合使用

function log({ x, y = 100 }) {
  console.log(x, y);
}

log({ x: 10 });        // 10 100
log({ x: 10, y: 20 }); // 10 20
log();                 // Cannot destructure property 'x' of 'undefined' as it is undefined.
                       // 无法对“undefined”的属性“x”进行分解,因为它是未定义的。

上面代码只使用了对象的解构赋值默认值,没有使用函数参数的默认值。只有当函数log的参数是一个对象时,变量x和y才会通过解构赋值生成。如果函数log调用时没有提供参数,变量x和y就不会生成,从而报错。解决方法如下:提供函数参数的默认值

function log({ x, y = 100 } = {}) {
  console.log(x, y);
}

log();  // undefined 100

上面代码指定,如果没有提供参数,函数log的参数默认为一个空对象。

下面两种写法有什么差别:

// 写法一
function log1({ x = 0, y = 0 } = {}) {
  console.log([x, y]);
}

function log2({ x, y } = { x: 0, y: 1 }) {
  console.log([x, y]);
}

区别是写法一函数参数的默认值是空对象,但是设置了对象解构赋值的默认值;写法二函数参数的默认值是一个具体属性的对象,但是没有设置对象解构赋值的默认值。


rest 参数

ES6 引入rest 参数(...变量名),用于获取函数的多余参数。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

function log(...par) {
  console.log(par);
}

log(1, 2, 3);  // [1, 2, 3]

注意,rest参数之后不能再有其它参数(即只能是最后一个参数),否则会报错。

function log(...par, name) {
  console.log(par);
}

log(1, 2, 3);  // Rest parameter must be last formal parameter
               // Rest参数必须是最后一个形式参数

对象的扩展

属性的简洁表示法

const person {
	name,
	age
}

// 等同于

const person {
	name: name,
	age: age
}

除了属性简写,方法也可以简写:

const person = {
	getName() {
		return "Tom"
	}
}

// 等同于

const person = {
	getName: function() {
		return "Tom"
	}
}

这种简洁写法在打印对象时也很有用:

const person1 = {
  name: "Tom",
};

const person2 = {
  name: "Jerry",
};

console.log(person1, person2); // {name: "Tom"} {name: "Jerry"}

console.log({ person1, person2 }); // {person1:{name: "Tom"}, person2: {name: "Jerry"}}

上面代码中,把两个对象放在大括号里面输出,就变成了对象的简洁表示法,每组键值对前面会打印对象名,这样就比较清晰了。

注意,简写的对象方法不能用作构造函数,会报错:

const obj = {
  person1: function () {
    this.name = "Tom";
  },
  person2() {
    this.name = "Jerry";
  },
};

const person1 = new obj.person1();
console.log(person1); // { name: "Tom" }

const person2 = new obj.person2(); // obj.person2 is not a constructor

属性名表达式

在 ES5 中,对象字面量定义对象时,只能使用标识符作为属性名:

const person = {
	name: "Tom"
}

但在 ES6 中,可以使用表达式作为对象的属性名,即把表达式放在方括号内:

const obj = {
  ["na" + 'me']: "Tom"
}

// 等同于

const obj = {
	name: "Tom"
}

super 关键字

在 ES6 中新增了super关键字,指向当前对象的原型对象。

const animal = {
  type: "animal",
};

const cat = {
  type: "cat",
  getType() {
    console.log(super.type);
    // 等同于
    // Object.getPrototypeOf(this).foo
  },
};

Object.setPrototypeOf(cat, animal);
cat.getType(); // animal

上面代码中,对象cat.getType()方法之中,通过super.type引用了原型对象animaltype属性。

注意:super关键字表示原型对象时,只能用在对象的方法之中,用在其它地方都会报错:

const animal = {
  type: "animal",
};

const cat = {
  type: super.type, // 'super' keyword unexpected here
  _getType: () => super.type, // 'super' keyword unexpected here
  getType: function () { 
    return super.type; // 'super' keyword unexpected here
  },
};

Object.setPrototypeOf(cat, animal);

上面三种super的用法都会报错,因为对于 JS 引擎来说,这里的super都没有用在对象的方法之中。第一种写法是super用在属性里面,第二种和第三种写法是super用在一个函数里面,然后赋值给_getType/getType属性。目前,只有对象方法的简写法可以让 JS 引擎确认,定义的是对象的方法。

在 JS 引擎内部,super.xxx有下面两种情况:

super.属性
// 等同于 
Object.getPrototypeOf(this).type

super.方法
// 等同于
Object.getPrototypeOf(this).getType.call(this)
const animal = {
  type: "animal",
  _getType() {
    return this.type;
  },
};

const cat = {
  type: "cat",
  getType() {
    return super._getType(); // Object.getPrototype(this)._getType.call(this)
  },
};

Object.setPrototypeOf(cat, animal);

console.log(cat.getType()); // 'cat'

上面代码中,super._getType指向原型对象animal_getType方法,但是绑定的this却还是当前对象cat,因此输出的是cat


扩展运算符

笔记


参考

阮一峰 ES6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值