美文网首页JavaScript
[JS] 先bind后new,this的指向

[JS] 先bind后new,this的指向

作者: 何幻 | 来源:发表于2018-04-22 19:00 被阅读10次

1. 严格模式this绑定为undefined

非严格模式下,以下调用方式中,this绑定为全局对象window

function f() {
    console.log(this);  // window
}

f();

而在严格模式下,this绑定为undefined

function f() {
    'use strict';

    console.log(this);  // undefined
}

f();

值得注意是的,只有this处于严格模式中,才会绑定为undefined
f被调用的位置是否处于严格模式无关。

function f() {
    console.log(this);  // window
}

(function () {
    'use strict';

    f();  // 在严格模式中调用f
})();

2. bind和new的优先级

function f() {
    return this;
}

const g = f.bind({ a: 1 });

g();  // {a:1}

const obj = new g;

// instanceof都为true
console.assert(obj instanceof f);
console.assert(obj instanceof g);

// Symbol.hasInstance
console.assert(f[Symbol.hasInstance](obj));
console.assert(g[Symbol.hasInstance](obj));

// f为constructor
console.assert(obj.constructor === f);
console.assert(obj.constructor !== g);

// f的prototype在obj的原型链上
console.assert(obj.__proto__ === f.prototype);

// g的prototype为undefined
console.assert(g.prototype === undefined);

可见newthis的影响比bind优先级要高,
g虽然通过bind绑定了this指向的对象为{a:1}
但是使用new g调用的时候,this仍然指向以f为构造函数的实例。

值得注意的有两点,
(1)bind之后,g.prototypeundefined

(2)new g返回的对象obj,使用instanceof判断fg都为true
原因就在于,V instanceof target首先会先用target[Symbol.hasInstance](V)来判断,
然后再判断,target.prototype是否在V的原型链上,参考ECMAScript Language Specification

但是bind的柯里化作用还是有用的,

function f(p1, p2) {
    this.v = p1 + p2;
}

const g = f.bind(null, 'x');

const obj = new g('y');
console.log(obj.v);  // xy

3. call null会将this绑定为全局对象

使用call或者apply,将this绑定为nullundefined并不会凑效,
此时,this将绑定为全局对象。

function f(){
    return this;
}

f.call(null);  // window
f.call(undefined);  // window

然而,在严格模式下,this将绑定为nullundefined

function f(){
    'use strict';

    return this;
}

f.call(null);  // window
f.call(undefined);  // window

值得一提的是,在非严格模式下,f.call(1);会自动将1包装成new Number(1)
然后this指向的是这个包装对象。

而在严格模式下,f.call(1);会将this绑定为1

function f(){
    return this;
}

function g(){
    'use strict';
    return this;
}

f.call(1);  // Number {1}
g.call(1);  // 1

4. Object.create(null)与{}的区别

const a = Object.create(null);
console.assert(a.__proto__ === undefined);
// 会创建一个原型为undefined的对象

const b = {};
console.assert(b.__proto__ === Object.prototype);

b={}相当于b=new Object,因此,bObject构造函数的实例。
Object.create(null)会创建一个空对象,它没有原型。

注意,Object.create(undefined);会报错,

Uncaught TypeError: Object prototype may only be an Object or null: undefined

5. 赋值表达式的返回值

window.a = 0;
function f(){
    return this.a;
}

const obj1 = {
    a:1,
    f,
};

const obj2 = {
    a:2,
};

(obj2.f=obj1.f)();  // 0

赋值表达式的返回值是函数的引用,因此相当于f()
而不是obj1.f(),也不是obj2.f()


参考

你不知道的JavaScript(上卷)

相关文章

网友评论

    本文标题:[JS] 先bind后new,this的指向

    本文链接:https://www.haomeiwen.com/subject/enbclftx.html