【前端--JavaScript】知识点(四)——关于this你不知道的事 (三)

189 阅读3分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战**

昨天少了一点内容,关于new有个地方很有意思,在传统的是面向类的语言中,“构造函数”是类中的一些特殊方法,使用new初始化类时会调用类中的构造函数,通常是这样的: something = new MyClass(..);

JavaScript中的new操作符,使用方法看起来和面向类的语言一样,绝大多数开发者都认为JavaScript中new的机制也和那些语言一样,然而,JavaScript中的new的机制实际上和面向类的语言完全不同。

在这里重新定义一下JavaScript中的“构造函数”,在JavaScript中,构造函数只是一些使用new操作符时被调用的函数,他们不属于某个类,也不会实例化一个类,实际上,他们甚至都不能说是一种特殊的函数类型,他们只是被new操作符调用的普通函数而已。实际上并不存在所谓的“构造函数”,只有对于函数的“构造调用”。

使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作:

  1. 创建(或者说构造)一个全新的对象。
  2. 这个新对象会被执行[[prototype]]连接。
  3. 这个新对象会绑定到函数调用的this。
  4. 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。

上一篇中分析了this绑定的四条规则,那么这些规则的优先级是怎么设定的呢?

毫无疑问,默认绑定的优先级是最低的,暂时先不考虑默认绑定。

先看显式绑定和隐式绑定哪个优先级更高:

function foo() {
  console.log( this.a );
}

var obj1 = {
  a: 2,
  foo: foo
};

var obj2 = {
 a: 3,
 foo: foo
};

obj1.foo(); // 2
obj2.foo(); // 3

obj1.foo.call( obj2 ); // 3
obj2.foo.call( obj1 ); // 2

可以看出,显式绑定的优先级更高

再来看隐式绑定和new绑定的优先级谁高:

function foo() {
  this.a = something;
}

var obj1 = {
  foo: foo
};

var obj2 = {};

obj1.foo( 2 ); 
console.log( obj.a ); // 2

obj1.foo.call( obj2, 3);
console.log( obj2.a ); // 3

var bar = new obj1.foo( 4 );
console.log( obj1.a ); // 2
console.log( bar.a ); // 4

可以看到new绑定比隐式绑定优先级更高。

new和call/apply无法一起使用,因此不能通过new foo.call(obj1)来直接进行测试。 (这两个的测试比较复杂,暂时不讲解。)

直接说绑定规则

  • 函数是否在new中调用(new绑定)?是的话this绑定的是新创建的对象。var bar = new foo();
  • 函数是否通过callapply显式绑定)调用?是的话this绑定的是指定的对象。var bar = foo.call(obj2);
  • 函数是否在某个上下文对象中调用(隐式绑定)?是的话this就绑定的是那个上下文对象。 var bar = obj1.foo();
  • 如果都不是的话就是默认绑定,在严格模式下就绑定到undefined,否则绑定到全局对象。var bar = foo();

规则之外的情况:

  • 如果把null或者undefined作为this的绑定对象传入callapply或者bind,这些值在调用时候会被忽略,实际应用的是默认绑定规则。

  • ES6中的箭头函数并不会使用四条标准的绑定规则,而是根据当前的词法作用域来决定this,具体来说,箭头函数会继承外层函数调用的this绑定(无论this绑定到什么)。