this绑定规则

默认绑定

function foo(){
    console.log(this.a)
}
var a=2;
foo();  // 2

声明在全局作用域中的变量(var a=2)就是全局对象的一个同名属性。在调用foo()时,this.a被解析成了全局变量a。因为在本例中,函数调用时应用了this的默认绑定,因此this指向全局对象。在代码中,foo()是直接使用不带任何修饰的函数引用进行调用的,因此只能是默认绑定

隐式绑定

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

当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。

隐式丢失

function foo(){
    console.log(this.a)
}
var obj={
    a:2,
    foo:foo
};
var bar=obj.foo;
var a='oops,global'; 
bar();  // oops,global

虽然bar是obj.foo的一个引用,但实际上,它引用的是foo函数本身,因此bar()其实是一个不带任何修饰的函数调用,因此应用了默认绑定。

显示绑定

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

通过foo.call(…),我们可以在调用foo时强制把它的this绑定在obj上

硬绑定可以解决丢失绑定的问题

function foo(){
    console.log(this.a)
}
var obj={
    a:2,
};
var bar=function(){
    foo.call(obj)
};
bar();
setTimeout(bar,100);
bar.call(window)

硬绑定是一种常用的模式,ES5提供了内置的方法Function.prototype.bind,用法如下

function foo(something){
    console.log(this.a,something);
    return this.a+something;
}
var obj={
    a:2
}
var bar=foo.bind(obj);
var b=bar(3);
console.log(b)

new绑定
使用new来调用函数,会自动执行下面的操作
1.创建一个全新的对象
2.这个新对象会被执行【原型】连接
3.这个新对象会绑定到函数调用的this
4.如果函数没有返回其他对象, 那么new表达式中的函数调用会自动返回这个新对象

function foo(a){
    this.a=a;
}
var bar=new foo(2);
console.log(bar.a);  // 2

判断this绑定的优先顺序
1.函数是否在new中调用(new绑定)?如果时的话,this绑定的新创建的对象。

2.函数是否通过call,apply(显示绑定)或者硬绑定调用?如果是的话,this绑定的是指定的对象

3.函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是哪个上下文对象

4.如果都不是的话,使用默认绑定

箭头函数不适用this的四种标准规则

function foo(){
    return (a)=>{
        console.log(this.a)
    };
}
var obj1={
    a:2
};
var obj2={
    a:3
};
var bar=foo.call(obj1);
bar.call(obj2);  // 2

foo()内部创建的箭头会捕获调用时foo()的this.由于foo()的this绑定到obj1,bar(引用箭头的函数)的this也会绑定到obj1.箭头函数的绑定无法被修改,new也不行

在 div 节点的事件函数内部,有一个局部的 callback 方法,callback 被作为普通函数调用时, callback 内部的 this 指向了 window,但我们往往是想让它指向该 div 节点.

<html>
<body>
<div id="div1">我是一个 div</div>
</body>
<script>
window.id = 'window';
document.getElementById( 'div1' ).onclick = function(){
    alert ( this.id ); // 输出: 'div1'
    var callback = function(){
        alert ( this.id ); // 输出: 'window'
    }
    callback();
};
</script>
</html>

有一种简单的解决方案,可以用一个变量保存 div 节点的引用:

<html>
<body>
<div id="div1">我是一个 div</div>
</body>
<script>
window.id = 'window';
document.getElementById( 'div1' ).onclick = function(){
    var that = this; // 保存 div 的引用
    var callback = function(){
        alert ( that.id ); // 输出: 'div1'
    }
    callback();
};
</script>
</html>

丢失的this
当调用 obj.getName 时, getName 方法是作为 obj 对象的属性被调用的,此时的 this 指向 obj 对象,所以 obj.getName()输出’sven’。
当用另外一个变量 getName2 来引用 obj.getName,并且调用 getName2 时,根据 2.1.2 节提到的
规律,此时是普通函数调用方式, this 是指向全局 window 的,所以程序的执行结果是 123123。

myName = "123123"
var obj = {
    myName: 'sven',
    getName: function(){
        return this.myName;
    }
};
console.log( obj.getName() ); // 输出: 'sven'
var getName2 = obj.getName;
console.log( getName2() ); // 123123

这段代码抛出了一个异常。这是因为许多引擎的 document.getElementById 方法的内部实现中需要用到 this。这个 this 本来被期望指向document,当 getElementById 方法作为 document 对象的属性被调用时,方法内部的 this 确实是指向 document 的。
但当用 getId 来引用 document.getElementById 之后, 再调用 getId,此时就成了普通函数调用,函数内部的 this 指向了 window,而不是原来的 document。

<html>
<body>
<div id="div1">我是一个 div</div>
</body>
<script>
    var getId = document.getElementById;
    getId( 'div1' );
</script>
</html>

将document.getElementById方法绑定到document对象

<html>
<body>
<div id="div1">我是一个 div</div>
</body>
<script>
document.getElementById = (function( func ){
    return function(){
        return func.apply( document, arguments );
    }
})( document.getElementById );
var getId = document.getElementById;
var div = getId( 'div1' );
console.log (div.id); // 输出: div1
</script>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值