1.super关键字

(1)咱们晓得,this关键字总是指向函数所在的以后对象,ES6 又新增了另一个相似的关键字super,指向以后对象的原型对象

const proto = {  foo: 'hello'};const obj = {  foo: 'world',  find() {    return super.foo;        //这里的super指向的是obj对象原型  }};Object.setPrototypeOf(obj, proto);obj.find() // "hello"

Object.setPrototypeOf(_obj, prototype_):该函数的作用是为一个对象设置原型。

下面代码中,对象obj.find()办法之中,通过super.foo援用了原型对象proto的foo属性

(2)留神,super关键字示意原型对象时,只能用在对象的办法之中,用在其余中央都会报错。请看上面的例子:

// 报错const obj = {  foo: super.foo}// 报错const obj = {  foo: () => super.foo}// 报错const obj = {  foo: function () {    return super.foo  }}

下面三种super的用法都会报错,因为对于 JavaScript 引擎来说,这里的super都没有用在对象的办法之中第一种写法是super用在属性外面,第二种和第三种写法是super用在一个函数外面,而后赋值给foo属性。目前,只有对象办法的简写法能够让 JavaScript 引擎确认,定义的是对象的办法。

在这里,可能第二种写法和第三种写法为什么谬误会让人混同,其实是这样的,在对象中,是有上面这种模式才会默认是对象的办法:

const obj = {  foo() {},            //foo是对象的办法  func: function foo1() {}        //foo1不是对象的办法}

(3)JavaScript 引擎外部,super.foo等同于Object.getPrototypeOf(this).foo(属性)或Object.getPrototypeOf(this).foo.call(this)(办法)。

(4)如果在一个对象的办法中应用了super.protoFunc(),而且在该对象的原型对象中的protoFunc办法中应用了this,该this不是指向原型对象,而是指向实例对象

const proto = {  x: 'hello',  foo() {    console.log(this.x);            //这里的this仍旧是绑定了obj对象  },};const obj = {  x: 'world',  foo() {    super.foo();  }}Object.setPrototypeOf(obj, proto);obj.foo() // "world"

下面代码中,super.foo指向原型对象proto的foo办法,然而绑定的this却还是以后对象obj,因而输入的就是world。起因也很简略,因为一般函数的this是指向执行作用域的,恰好this执行时的作用域是在obj对象中,所以这里的this是指向了obj对象。

2.对象的扩大运算符

(1)对象的解构赋值用于从一个对象取值,相当于将指标对象本身的所有可遍历的(enumerable)、但尚未被读取的属性,调配到指定的对象下面。所有的键和它们的值,都会拷贝到新对象下面。

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };x // 1y // 2z // { a: 3, b: 4 }

下面代码中,变量z是解构赋值所在的对象。它获取等号左边的所有尚未读取的键(a和b),将它们连同值一起拷贝过去。

在这里,解构要留神几点

  • 因为解构赋值要求等号左边是一个对象,所以如果等号左边是undefined或null,就会报错,因为它们无奈转为对象
let { ...z } = null; // 运行时谬误let { ...z } = undefined; // 运行时谬误
  • 解构赋值必须是最初一个参数,否则会报错。
let { ...x, y, z } = someObject; // 句法谬误let { x, ...y, ...z } = someObject; // 句法谬误
  • 解构赋值的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么解构赋值拷贝的是这个值的援用,而不是这个值的正本(意思就是指其实两者是指向同一块地址空间)。
let obj = { a: { b: 1 } };let { ...x } = obj;obj.a.b = 2;x.a.b // 2

留神,这里x.a.b不是1而是2,因为x其实就是对obj的另一个援用,并没有开拓新的地址空间。

  • 扩大运算符的解构赋值,不能复制继承自原型对象的属性
let o1 = { a: 1 };let o2 = { b: 2 };o2.__proto__ = o1;let { ...o3 } = o2;o3 // { b: 2 }o3.a // undefined

下面代码中,对象o3复制了o2,然而只复制了o2本身的属性,没有复制它的原型对象o1的属性

  • ES6 规定,变量申明语句之中,如果应用解构赋值,扩大运算符前面必须是一个变量名,而不能是一个解构赋值表达式,所以下面代码引入了两头变量newObj,如果写成上面这样会报错。
let { x, ...{ y, z } } = o;// SyntaxError: ... must be followed by an identifier in declaration contexts
  • 解构赋值的一个用途,是扩大某个函数的参数,引入其余操作。
function baseFunction({ a, b }) {  // ...}function wrapperFunction({ x, y, ...restConfig }) {  // 应用 x 和 y 参数进行操作  // 其余参数传给原始函数  return baseFunction(restConfig);}

下面代码中,原始函数baseFunction承受a和b作为参数,函数wrapperFunction在baseFunction的根底上进行了扩大,可能承受多余的参数,并且保留原始函数的行为。