您的位置:首页 > Web前端 > JavaScript

JavaScript--this的绑定规则

2018-01-27 13:25 836 查看
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对象上,但是在这个函数中无法访问到这个对象,这样一来就会产生丢失绑定的问题。这个时候可以使用硬绑定:

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的影响
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: