默认绑定
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>