javascript中的this词法

本文详细介绍了JavaScript中this关键字的绑定规则,包括默认绑定、隐式绑定、显示绑定及new绑定等四种主要规则,并通过实例解释了如何判断this的绑定情况。

this的绑定规则

this是在运行时进行绑定的,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。
当一个函数被调用时,会创建一个活动记录(执行上下文),这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this就是记录其中的一个属性,会在函数执行的过程中用到。

绑定规则

1. 默认绑定
最常用的函数调用类型:独立函数调用。

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

this.a被解析成了全局变量a,因为函数调用应用了this的默认绑定,因此this指向全局变量。在这里,foo()直接使用了不带任何修饰符的函数引用进行调用,因此看出foo()只能使用默认绑定,无法应用其他规则。

如果使用严格模式,那么全局对象无法使用默认绑定,this会被绑定到undefined。严格模式下与foo()的调用位置无关。

2. 隐式绑定
考虑规则:调用位置是否有上下文,或者说是被某个对象包含。

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

当foo()被调用时,它的落脚点指向了obj对象。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象,因为调用foo时this绑定到obj,因此this.a和obj.a是一样的。

    对象属性引用链中只有最顶层会影响调用位置。
function foo(){
    console.log(this.a);
}
var obj2={
    a:42;
    foo:foo
};
var obj1={
    a:2,
    obj2:obj2
};
obj1.obj2.foo();//42
隐式丢失:一个常见的this绑定问题就是被隐式绑定的函数会丢失绑定对象,也就是说会应用默认绑定,从而把this绑定到全局对象或者undefined上,取决于是否是严格模式。
function foo(){
    console.log(this.a);
}
var obj={
    a:2,
    foo:foo
};
var bar=obj.foo;//函数别名
var a="oops,global";
bar();

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

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

参数传递实际就是一种隐式赋值,因此我们传入函数时也会被隐式赋值。

隐式绑定时,我们必须在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把this绑定到这个对象上。
window.id='window';
document.getElementById('div').onclick=function(){
    alert(this.id);//div1
    var callback=function(){
        alert(this.id);//window
    }
}
document.getElementById('div1').onclick=function(){
    var that=this;
    var callback=function(){
        alert(that.id);//div1
    }
    callback();
}

3. 显示绑定

 显示绑定可以解决丢失绑定的问题

1、硬绑定

function foo(){
    console.log(this.a);
}
var obj={
    a:2
};
var bar=function(){
    foo.call(obj);
};
bar();//2
setTimeout(bar,100);//2
//硬绑定的bar不能再修改它的this
bar.call(window);//2
硬绑定的应用场景就是创建一个包裹函数,传入所有的参数并返回接收到的所有值。

2、API调用的“上下文”

function foo(el){
    console.log(el,this.id);
}
var obj={
    id:"awesome"
};
[1,2,3].forEach(foo,obj);

4. new绑定

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


判断this

1、函数是否在new中调用,如果是的话this绑定的是新创建的对象
2、函数是否通过call、apply或者硬绑定调用,如果是的话,this绑定的是指定的对象
3、函数是否在某个上下文对象中调用(隐式绑定),如果是的话,this绑定的是那个上下文对象
4、如果都不是的话,使用默认绑定,严格模式下,绑定到undefined,否则绑定到全局对象。

this的四种使用场景

this要在执行时才能确认值,定义时无法确认。
var a={
    name:'A',
    fn:function(){
        console.log(this.name)
    }
}
a.fn() //this===a
a.fn.call({name:'B'})//this==={name:'B'}
var fn1=a.fn
fn1()//this===window

1、作为构造函数执行

function Foo(name){
    this.name=name
}
var f=new Foo('zhangsan')

2、作为对象属性执行

var obj={
    name:'A',
    printName:function(){
        console.log(this.name)
    }
}
obj.printName()

3、作为普通函数执行

function fn(){
    console.log(this)
}
fn()

4、call apply bind

function fn1(name){
    alert(name);
    console.log(this)
}
fn1.call({x:100},'zhangsan')

var fn2=function(name,age){
    alert(name);
    console.log(this);
}.bind({y:200})
fn2('zhangsan',20)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值