JavaScript中的this详解

JavaScript中的this详解

this一直都是难点所在,我查阅资料,对this进行了一些用法和误解的举例与分析,也帮助自己学习和理解。

目录

  • 默认绑定
  • 隐式绑定
  • 显式绑定
  • new绑定
  • 一些特殊例子
默认绑定
var a = 2;
function foo(){
    console.log(this.a);
}
foo();//2

这是一个this最简单的例子,看懂一段代码最好的方法就是先忽略那些声明的变量和函数,去看函数调用的地方。在这段代码里只有最后一行foo()是在调用,然后找到foo函数,里面执行console.log(this.a);因为foo在全局调用,所以它的this是window,再去window的作用域查找a为2。
现在来说说this的机制:this是在运行时进行绑定的,并不是在编写时绑定,与函数声明的位置没有关系。看函数被什么调用,也就是.函数名()前面的名字,如果没有则为默认绑定即全局对象。

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

按照默认绑定所说的方法分析,obj.foo(),那么foo()的this就是obj,所以输出obj.a为2。
总结来说,隐式绑定就是被调用的函数是否被某个对象拥有或者包含,若是有,则this就指向这个对象。

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

这里bar = obj.foo,看起来似乎这两个是一样的,仔细看看,obj.foo会找到obj里面的foo,然后执行foo(),此时的this是obj,所以会输出2;而当令bar = obj.foo时,obj.foo = foo,所以会先令bar = foo,此时再执行bar(),与执行foo()没有区别,因此会输出window.a。

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

将obj.foo作为参数传入doFoo(),传参的过程就是在doFoo中声明一个变量fn,然后令fn等于obj.foo,在这里就跟上一个例子的赋值操作相似了,因此相当于foo()直接在doFoo中执行,foo的调用位置没有显式调用对象,所以默认绑定为全局,this为window,所以输出window.a。
以上两个例子都说明了隐式丢失的问题,最明显的特征就是存在赋值操作,因此在赋值操作时,不要急于将this带入,而是应该将整个函数完整保留再赋值,最后再执行该函数。

显式绑定

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

显式绑定的第一种方式就是使用call()、apply()和bind()来显示指明this,它们的用法相似,第一个参数就是用来指定this。在这个例子中,call的第一个参数是obj,那么this就是obj,输出obj.a为2。
其实显式绑定比隐式绑定更为灵活,在隐式绑定中,必须将函数添加到对象中,再使用对象来调用才能绑定this的值,然而显式绑定写法更加简单,它通过使用JavaScript内置函数来改变this的指向。

new绑定

在JavaScript设计模式中提到过构造函数,包括内置函数在内的所有函数都可以用new来调用,这种函数调用被称为构造函数调用。

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

首先new关键字会创建一个空的对象,然后会自动调用一个函数apply方法,将this指向这个空对象,这样的话函数内部的this就会被这个空的对象替代。在上面例子中,new foo()返回一个对象,此时将this绑定为bar,再通过foo()里面的this.a给bar.a赋值为2,所以输出2。
* 总结一下上述四条规则的优先级:new绑定 > 显式绑定 > 隐式绑定 > 默认绑定。

一些特殊例子

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

将null或者undefined作为this的绑定对象传入call、apply或者bind,这些值在调用的时候会被忽略,实际还是默认绑定,因此输出2。

function foo(){
    console.log(this.a);
}
var a = 2;
var o = {a:3,foo:foo};
var p = {a:4};
o.foo();
(p.foo = o.foo)();
p.foo();

o.foo()就是上面提到的隐式绑定,输出o.a为3;(p.foo = o.foo)()是先将o.foo的foo()的引用返回给p.foo,这句表达式是一个立即执行函数,因此第一个括号里就是foo(),而不是p.foo(),这里就为默认绑定,输出2;p.foo()在上一行给p定义了foo函数,此时输出为4。

var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a);
        }
    }
}
o.b.fn();

前面说this绑定的是调用函数的对象,但是这里fn()前面有两个对象,他们是包含关系,但是this绑定有个规则,它绑定的是紧挨着函数的对象,所以输出12。

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

在new绑定时说到,new函数时为构造这个函数的实例,所以bar.a应该输出2,但是实际上输出的undefined,正是因为有return语句,这里return了一个对象,所以this指向的就是那个返回的对象,而这个对象为空,所以bar.a自然为undefined。如果返回值不是一个对象那么this还是指向函数的实例。若是改为return 3,bar依然为fn()的实例,别忘了函数也是对象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值