JavaScript--this的绑定规则

JavaScript中有四条调用规则,我们可以根据这四条调用规则来判断当前this的指向。

第一条:默认绑定。

function foo(){
    console.log(this.a);
}
var a = 2;
foo();   // 2
代码很简单,那要怎么给默认绑定一个定义呢?答案就是: 不带任何修饰的函数引用进行调用
这个时候this指向window.(严格模式下指向undefined)

第二条:隐式绑定

隐式绑定,需要在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把this间接绑定到这个对象上。

function foo(){
    console.log(this.a);
}
var obj = {
    a:2,
    foo:foo
}
obj.foo();   // 2
这里在调用的时候增加了一个上下文对象,隐式绑定会把函数调用中的this绑定到这个上下文对象。如果存在多层,按照最近的一层合账。a.b.c.foo();   则实际指向的是c.

在这里呢,有一种特殊的情况,函数的赋值操作。

function foo(){
    console.log(this.a);
}
function lee(func){
    func();
}
var obj = {
    a:2,
    foo:foo
}
var a = 1;
doFoo(obj.foo);    //1
看似是隐式绑定,但是函数在传递参数的时候就执行了赋值操作,这个时候再次调用的绑定规则应该为默认绑定,所以指向window.

第三条:显式绑定

这里呢,关于 call和apply以及bind的知识,之前有说过,不清楚的可以先了解一下。

这些函数都可以直接指定this的指向,所以是显式绑定。call和apply 仍然可以通过调用时传递的参数去修改当前this的绑定,现在想象一个场景:在一个函数内部要调用一个函数,需要将这个函数绑定在一个obj对象上,但是会有其他因素影响函数绑定到obj对象上,这样一来就会产生丢失绑定的问题。这个时候可以使用硬绑定:

function foo(){
    console.log(this.a);
}
var obj = {
    a:2,
}

var bar = function(){
    foo.call(obj);
}
bar();   //2
setTimeout(bar,100);   //2
bar.call(window);   //2
这样一来,就无法修改函数的绑定对象了。

ES5提供了内置方法,Function.prototype.bind方法,每个function都自带bind方法,

var bar = foo.bind(obj)
如此就可以使用了。

第四条:new绑定

也就是通过new去实例化一个对象。、

function foo(a){
    this.a = a;
}
var bar = new foo(2);
console.log(bar.a);   //2
一言以蔽之: 构造一个新对象,并把它绑定到foo()调用中的this上

多说一句:这里foo()是一个普通的函数,通过new关键字调用就是对函数的构造调用。由此可得出JS中实际上并不存在所谓的构造函数,只有对函数的构造调用。

优先级:

说了四种方式,既然存在那难免就会有个比较,到底谁更优先呢?

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

var obj1 = {
    foo:foo
}

var obj2 = {}

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

obj1.foo.call(obj2,3);
console.log(obj2.a);   //3  显式 > 隐式
--------------------------------------------

var oo1 = {};
var bar = foo.bind(oo1);
bar(2);    //001.a = 2

var oo2 = new bar(3);

//  oo1.a = 2,oo2.a = 3;   => new > 显式
之前我们看过的硬绑定的实现方式,按道理来说应该是无法修改才对的,而实际使用的时候bind()有自己的实现机制,所以new调用仍然会修改当前指向对象。

这里是传统的四种绑定方式,有没有例外呢,有。感兴趣的可以看下我总结的箭头函数对this的影响








猜你喜欢

转载自blog.csdn.net/run_youngman/article/details/79172309
今日推荐