资讯专栏INFORMATION COLUMN

浅谈 javascript 中的this绑定问题

duan199226 / 1448人阅读

摘要:绑定使用方式进行调用函数时,会发生构造函数的调用。先上图,然后根据文字阅读使用调用函数之后,该函数才作为构造函数进行调用,构造一个全新的对象赋值给,而对象的指向了的对象,的对象有一个属性指向的构造函数这个就是的原型链,也是的特性。

javascript语言是在运行时前即进行编译的,而this的绑定也是在运行时进行绑定的。也就是说,this实际上是在函数被调用时候发生绑定的,它指向什么完全取决于函数在哪里被调用。

1.默认绑定

例如直接在全局作用域下声明:

var a=2;
console.log(this.a);

在全局作用域下声明的变量或者函数等,都会作为window对象的属性。

这个时候,默认this是绑定到全局作用域下的window对象,如果你去console.log(this);你会发现,你打印出来的是window,尽管你没有声明this就是window,但是js进行了默认绑定。

以至于你运行以下的代码片段:
function foo(){
console.log(this.a);
}
var a=2;
foo();
浏览器控制台打印出来的是 2 ;

2.隐式绑定

当函数引用有上下文对象时,在函数调用时,会进行隐式绑定。这么说肯定很抽象,还是举例说明吧。
var a=4;
function foo(){
console.log(this.a);
}
var obj={
  a:2,
  foo:foo
}
foo();
obj.foo();
两次会打印出来什么呢?猜一下?

foo()会打印出来4,obj.foo()会打印出来2

第一个foo() 使用了默认绑定,this绑定到了全局对象window,打印 this.a 就是打印window.a;

第二个foo()外层的foo函数引用作为obj.foo的属性值,通过obj进行调用,此时的obj就是这个函数引用的上下文对象,this会隐式绑定到obj这个对象上。此时打印的this.a就是obj.a了。

3.显式绑定

在上面两种绑定中,我们都没有去明确地进行强制绑定,而是使用了默认规则的绑定,那么如果我们想要在调用某个函数时特定地改变this的绑定,这个时候就可以用显式绑定了。

还是上代码,然后进行分析。

var a=4;
function foo(){
console.log(this.a);
}
var obj={
  a:2,
  foo:foo
}
var foo1=foo.bind(obj);
foo();
foo.call(obj);
foo.apply(obj);
foo.call(window);
foo1();
按照顺序打印出的是 4 ,2 ,2, 4,2

第一次打印了4 使用了默认绑定,foo函数的this绑定到了window。

第二次打印了2 使用了call函数,显式地将foo函数的this绑定到obj对象。

第三次打印了2 apply方法的效果跟call方法一样。

第四次打印了4 call方法显示地将foo函数的this绑定到了obj对象,效果跟默认绑定一样了。

第五次打印了2,bind方法显示地将foo函数的this绑定到了obj,并且返回了一个硬编码后的新函数,赋值给foo1变量进行调用,硬编码就是新函数内部this直接绑定到了指定的对象,也就是obj。

4.new 绑定

使用new方式进行调用函数时,会发生构造函数的调用。怎么解释呢,还是直接上代码加分析。
function foo(a){
 this.a=a;
}
foo(3);
var test=new foo(2);
console.log(a);
console.log(test.a);
打印出来的是 3 ,2

foo函数只是一个普通的函数,直接调用foo(3)只是作为普通函数的调用,会使用默认绑定将this绑定到window上,对window.a也就会全局变量a进行赋值,所以打印出来的是3;

foo函数,进行构造调用,this绑定到test对象,故而this.a作为test对象的属性并进行传参赋值。打印出来的test就是{a:2},this.a就是2了。

先上图,然后根据文字阅读

使用new 调用函数之后,该foo函数才作为构造函数进行调用,构造一个全新的对象赋值给test,而test对象的_proto_
指向了test的prototype对象,test的prototype对象有一个属性constructor,指向test的构造函数foo,这个就是javascript的原型链,也是javascript的特性。对于test对象调用的方法以及属性,会先在test对象进行寻找,如果找到的话,就直接进行调用,寻找停止。如果寻找不到,顺着原型链,在test对象的prototype对象寻找,如果找到的话,进行调用,寻找停止,如果还是找不到,会在prototype对象的原型上进行寻找,这个时候_proto_指向了Object的prototype对象,Object的prototype的constructor指向了Object()本身,而一些Obejct的函数如toString等等就是在这个原型上进行调用的,这个时候如果还是找不到需要属性或者方法,那么就是语法错误,未定义了。因为Object的prototype的_proto_指向是null了,也就没有任何对象属性以及方法了。

不是说程序员可以new 很多个对象嘛,但是new出来的对象 原型最终结果却是指向了 空(null),所以还是自己动手丰衣足食吧,哈哈。

一般情况下,使用new函数之后构造的对象,会优先将函数调用到的this绑定到这个对象,如果函数没有返回其它对象,会自动调用返回这个新对象。

总结:

只有对于this绑定的情况有了基本的了解,才能在编写代码时候,避免产生由于绑定带来的未知bug。如果你在调用某个框架插件或者绑定事件的时候,发现this不好用了,有可能是你的this使用绑定错了,打印下console.log(this)在控制台看一看,也许就发现问题了。

如果在阅读中遇到什么问题,欢迎评论以及留言。同时欢迎我的博客陈建光的博客

欢迎评论以及留言,同时欢迎关注我的博客定时不断地更新我的文章 陈建光的博客

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94221.html

相关文章

  • 浅谈React事件机制

    摘要:事件简介事件是合成事件,所有事件都自动绑定到最外层上。支持事件的冒泡机制,我们可以使用和来中断它。这样做简化了事件处理和回收机制,效率也有很大提升。事件类型合成事件的事件类型是原生事件类型的一个子集。 React事件简介 React事件是合成事件,所有事件都自动绑定到最外层上。因为Virtual DOM 在内存中是以对象的形式存在的,所以React 基于 Virtual DOM 实现了...

    moven_j 评论0 收藏0
  • 浅谈React事件机制

    摘要:事件简介事件是合成事件,所有事件都自动绑定到最外层上。支持事件的冒泡机制,我们可以使用和来中断它。这样做简化了事件处理和回收机制,效率也有很大提升。事件类型合成事件的事件类型是原生事件类型的一个子集。 React事件简介 React事件是合成事件,所有事件都自动绑定到最外层上。因为Virtual DOM 在内存中是以对象的形式存在的,所以React 基于 Virtual DOM 实现了...

    MyFaith 评论0 收藏0
  • 浅谈-this

    摘要:回调函数中调用在回调函数中一般有两种情况回调函数为匿名函数时,回调函数的会指向,需要对回调函数。回调函数为箭头函数时,回调函数的会指向他的直接上层。 浅谈-this this简单而又神秘,使用场景多变而又复杂,这造就了它成为了初级javascript开发人员不愿接触的东西,高级javascript都想探究的东西。文本亦是对this的致敬。 this是什么? this是当前执行环境...

    archieyang 评论0 收藏0
  • 浅谈javascript里面的this、call、apply、bind

    摘要:如果该参数的值为或,则表示不需要传入任何参数,从开始可以使用类数组对象。当使用操作符调用绑定函数时,该参数无效。当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。 在了解call,apply之前需要先了解下javascrit中this指向 this的指向在ES5里面,this永远指向最后调用它的那个对象举个栗子: var name = outerName; function...

    Lemon_95 评论0 收藏0
  • 浅谈Javascript闭包中作用域及内存泄漏问题

    摘要:将作用域赋值给变量这里的作用域是,而不是将作用域赋值给一个变量闭包返回浏览器中内存泄漏问题大家都知道,闭包会使变量驻留在内存中,这也就导致了内存泄漏。 上一章我们讲了匿名函数和闭包,这次我们来谈谈闭包中作用域this的问题。 大家都知道,this对象是在运行时基于函数的执行环境绑定的,如果this在全局就是[object window],如果在对象内部就是指向这个对象,而闭包却是在运行...

    source 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<