JavaScript this绑定规则

每个函数的this是在调用时被绑定的,完全取决于函数的调用位置

1 默认绑定
function foo()
{
    console.log(this);      //输出:Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
    console.log(this.a);    //输出:2
}
var a=2;
foo();

当调用foo()时,this.a被解析成了全局变量a。函数调用时应用了默认绑定,因此this指向全局对象。在代码中,foo()是直接使用不带任何修饰的函数引用进行调用的,因此只能使用默认绑定,无法应用其他规则。

function foo()
{
    'use strict'
    console.log(this);      //输出:undefined
    console.log(this.a);    //Uncaught TypeError: Cannot read property 'a' of undefined
}
var a=2;
foo();
如果使用严格模式(strict mode),则不能将全局对象用于默认绑定,因此this会绑定到undefined。


2 隐式绑定
function foo()
{
    console.log(this.a);
}
var obj={
    a:2,
    foo:foo
}
obj.foo();           //输出:2

当foo()被调用时,它的前面加上了obj的引用,当函数引用有上下文时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。因此调用foo()时this被绑定到obj。

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

可以看到bar()被调用时,this指向全局对象。bar()其实是一个不带任何修饰的函数调用,因此应用了默认绑定,bar是obj.foo的一个引用。

var obj={
    a:'obj a',
    foo:{
        a:'foo a',
        bar:function ()
        {
            console.log(this.a);
        }
    }
}
var a='global a';
var baz=obj.foo.bar;
obj.foo.bar();     //输出:foo a
baz();             //输出:global a
obj.foo.bar()被调用时,this指向foo,对象属性引用链中只有上一层或者说最后一层在调用位置中起作用。因此obj.foo.bar()调用时输出’foo a’而不是’obj a’。


3 显式绑定

call apply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向。可以通过直接指定this的绑定对象,因此称之为显式绑定

function foo(b,c)
{
    console.log(this.a+b+c);
}
var obj={
    a:2
}
var a=1;
foo(3,4);                //输出:8   (1+3+4)

//使用call方法
foo.call(obj,3,4);       //输出:9     (2+3+4)

//使用apply方法
foo.apply(obj,[3,4]);    //输出:9     (2+3+4)

call 和 apply二者的作用完全一样,只是接受参数的方式不太一样。foo.call(obj,3,4); 和foo.apply(obj,[3,4]);调用时this指向obj。

ES5提供了内置的方法Function.Prototype.bind 使用bind(..)会返回一个新函数,它会把指定的参数设置为this的上下文并调用原始函数。

function foo()
{
    console.log(this.a);
}
var obj={
    a:2
};
var bar=foo.bind(obj);
bar();                       //输出:2

如果把null或者undefined作为this的绑定对象传入call、apply、bind.这些值在调用时会被忽略,实际应用的是默认绑定规则。


4 new绑定

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


在使用new实例化对象时,this指向这个实例对象。
function foo(a,b)
{
    this.a=a;
    this.b=b;
}
foo.c=12;
foo.prototype.getSum=function()
{
    return this.a+this.b;
}
foo.prototype.getC=function()
{
    return this.c;
}

var bar=new foo(2,3);
console.log(bar.a);                   //输出:2
console.log(bar.b);                   //输出:3
console.log(bar.c);                   //输出:undefined
console.log(foo.c);                   //输出:12

var sum=bar.getSum();
console.log(sum);                    //输出:5

bar.c=5;
console.log(bar.c);                   //输出:5
console.log(bar.getC());              //输出:5
执行完上述操作之后的bar



this绑定优先级

New绑定>显式绑定>隐式绑定>默认绑定


ES6箭头函数

ES6新增了箭头函数,箭头函数不使用this的四种绑定规则,而是根据外层作用域来决定this,且箭头函数的绑定无法被修改。

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

var bar=foo.call(obj1);
bar.call(obj2);                   //输出:2

var bar1=foo1.call(obj1);
bar1.call(obj2);                  //输出:3


参考:你不知道的JavaScript上卷

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值