资讯专栏INFORMATION COLUMN

JS中this的4种绑定规则

Null / 1525人阅读

摘要:硬绑定硬绑定后无论怎么调用,都不会影响函数的绑定硬绑定的典型应用是如下的包裹函数将对象硬编码进去即将内部函数用硬绑定到某个对象,无论怎么调用这个包裹函数,都不会影响内部函数的。

this

ES6中的箭头函数采用的是词法作用域。

为什么要使用this:使API设计得更简洁且易于复用。

this即不指向自身,也不指向函数的词法作用域。

this的指向只取决于函数的调用方式

this绑定规则

new > 显示绑定 > 隐式绑定 > 默认绑定

默认绑定

当独立函数调用时,不管是否在调用栈中,this都指向全局对象(浏览器中为window)

严格模式下,不能将全局对象用于默认绑定。

</>复制代码

  1. var a = 2;
  2. function foo(){
  3. console.log(this.a);
  4. }
  5. function bar(){
  6. var a = 5;
  7. foo();
  8. }
  9. bar(); // 2
隐式绑定

当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。

对象属性引用链中只有最后一层在调用位置中起作用。

要求:对象内部必须包含一个指向函数的属性,该对象可通过这个属性间接引用函数。

</>复制代码

  1. function foo() {
  2. console.log( this.a );
  3. }
  4. var obj2 = {
  5. a: 42,
  6. foo: foo
  7. };
  8. var obj1 = {
  9. a: 2,
  10. obj2: obj2
  11. };
  12. obj1.obj2.foo(); // 42

隐式丢失

</>复制代码

  1. function foo() {
  2. console.log( this.a );
  3. }
  4. var obj = {
  5. a: 2,
  6. foo: foo
  7. };
  8. var bar = obj.foo; // 这里bar将引用foo函数本身,所以不带有函数对象的上下文
  9. var a = "oops, global"; // a是全局对象的属性
  10. bar(); // "oops, global"

和回调函数的情况下(参数传递时的隐式赋值)

</>复制代码

  1. function foo() {
  2. console.log( this.a );
  3. }
  4. function doFoo(fn) {
  5. // 参数传递时,相当于fn = obj.foo,就和上个例子一样了
  6. fn(); // <-- call-site!
  7. }
  8. var obj = {
  9. a: 2,
  10. foo: foo
  11. };
  12. var a = "oops, global"; // `a` also property on global object
  13. doFoo( obj.foo ); // "oops, global"
显式绑定

采用call()和apply(),通过传入一个对象(若为基本类型,会被封装函数转为对象—装箱),将this绑定到该对象。

硬绑定

</>复制代码

  1. function foo() {
  2. console.log( this.a );
  3. }
  4. var obj = {
  5. a: 2
  6. };
  7. var bar = function() {
  8. foo.call( obj );
  9. };
  10. bar(); // 2
  11. setTimeout( bar, 100 ); // 2
  12. // 硬绑定后bar无论怎么调用,都不会影响foo函数的this绑定
  13. bar.call( window ); // 2

硬绑定的典型应用是如下的包裹函数:

</>复制代码

  1. function foo(something) {
  2. console.log( this.a, something );
  3. return this.a + something;
  4. }
  5. var obj = {
  6. a: 2
  7. };
  8. var bar = function() {
  9. return foo.apply( obj, arguments ); // 将obj对象硬编码进去
  10. };
  11. var b = bar( 3 ); // 2 3
  12. console.log( b ); // 5

即将内部函数用apply硬绑定到某个对象,无论怎么调用这个包裹函数,都不会影响内部函数的this。
bind辅助函数如下:

</>复制代码

  1. function foo(something) {
  2. console.log( this.a, something );
  3. return this.a + something;
  4. }
  5. // simple `bind` helper
  6. function bind(fn, obj) {
  7. return function() {
  8. return fn.apply( obj, arguments ); // 利用参数将obj传入进去
  9. };
  10. }
  11. var obj = {
  12. a: 2
  13. };
  14. var bar = bind( foo, obj ); // bind( foo, obj )会返回一个包裹函数
  15. var b = bar( 3 ); // 2 3
  16. console.log( b ); // 5

总结:上述包裹函数,想要包裹其他函数,只能一个一个重复写,硬编码的方式导致不能被重用,当某种功能需要多次重复使用时,将其抽象出来,成为函数。

new绑定

任何函数都可能被用作构造函数,当函数被new操作符“构造调用”时,会执行下面操作:

1. 创建一个新对象(若该函数不是JS内置的,则创建一个新的Object对象);
2. 将this绑定到这个对象;
3. 执行构造函数中的代码(为这个新对象添加属性);
4. 若函数没有返回其他对象,则自动返回这个新对象;若函数有return返回的是非对象,则还是自动返回这个新对象,即覆盖那个非对象。

</>复制代码

  1. function foo(a) {
  2. this.a = a;
  3. }
  4. var bar = new foo( 2 );
  5. console.log( bar.a ); // 2
补充说明

间接引用

</>复制代码

  1. function foo() {
  2. console.log( this.a );
  3. }
  4. var a = 2;
  5. var o = { a: 3, foo: foo };
  6. var p = { a: 4 };
  7. o.foo(); // 3
  8. (p.foo = o.foo)(); // 2,由于p.foo = o.foo的返回值是目标函数的引用,所以调用位置是foo(),而不是p.foo()或o.foo()

箭头函数:不使用这四个this规则,根据词法作用域来决定this。

</>复制代码

  1. function foo() {
  2. // 返回一个箭头函数
  3. return (a) => {
  4. // `this` here is lexically adopted from `foo()`
  5. console.log( this.a );
  6. };
  7. }
  8. var obj1 = {
  9. a: 2
  10. };
  11. var obj2 = {
  12. a: 3
  13. };
  14. // foo()不是箭头函数,他的this被绑定到obj1
  15. var bar = foo.call( obj1 ); // foo.call( obj1 )返回箭头函数,所以bar为箭头函数
  16. bar.call( obj2 ); // 2! 箭头函数的this无法被修改,new也不行

如下为和箭头函数一样的模式:

</>复制代码

  1. function foo() {
  2. var self = this; // lexical capture of `this`
  3. setTimeout( function(){
  4. console.log( self.a );
  5. }, 100 );
  6. }
  7. var obj = {
  8. a: 2
  9. };
  10. foo.call( obj ); // 2
this绑定的趣题:

知乎链接-arguments对象调用

更多博客:https://github.com/Lmagic16/blog

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

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

相关文章

  • 彻底搞懂 JS this 机制

    摘要:的四种绑定规则的种绑定规则分别是默认绑定隐式绑定显示绑定绑定。绑定中的操作符,和其他语言中如的机制是不一样的。规则例外在显示绑定中,对于和的绑定将不会生效。它也是作为机制的一种替换,解决之前绑定过程各种规则带来的复杂性。 彻底搞懂 JS 中 this 机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.com/jasonGeng88/blog 目录 t...

    李世赞 评论0 收藏0
  • JSthis详解

    摘要:实际上并不存在什么构造函数,只存在对于函数的构造调用发生构造函数的调用时,会自动执行下边的操作创建一个全新的对象。说明绑定的优先级高于硬绑定。 原文阅读   js中的this是很容易让人觉得困惑的地方,这篇文章打算说一下this绑定的几种情况,相信可以解决大部分关于this的疑惑。 this是在运行的时候绑定的,不是在编写的时候绑定的,函数调用的方式不同,就可能使this所绑定的对象不...

    Mike617 评论0 收藏0
  • 【进阶3-1期】JavaScript深入之史上最全--5this绑定全面解析

    摘要:在严格模式下调用函数则不影响默认绑定。回调函数丢失绑定是非常常见的。因为直接指定的绑定对象,称之为显示绑定。调用时强制把的绑定到上显示绑定无法解决丢失绑定问题。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周正式开始前端进阶的第三期,本周的主题是this全面解析,今天是第9天。 本计划一共28期,每期重点攻克一个面试重...

    xavier 评论0 收藏0
  • jsthis总结

    摘要:关于的指向问题算的上是中的一个十分重要的问题了。首先,的指向问题可以用一句话总结就是总是指向调用的对象,也就是说指向谁与函数声明的位置没有关系,只与调用的位置有关。此外注意几种特殊情况,特别是中的箭头函数。 关于this的指向问题算的上是js中的一个十分重要的问题了。今天把这个问题总结下,加深下自己对this的理解。首先,this的指向问题可以用一句话总结就是:this总是指向调用的对...

    light 评论0 收藏0
  • 《You Don't Know JS》阅读理解——this

    摘要:运行规则根据的运作原理,我们可以看到,的值和调用栈通过哪些函数的调用运行到调用当前函数的过程以及如何被调用有关。 1. this的诞生 假设我们有一个speak函数,通过this的运行机制,当使用不同的方法调用它时,我们可以灵活的输出不同的name。 var me = {name: me}; function speak() { console.log(this.name); }...

    tianren124 评论0 收藏0

发表评论

0条评论

Null

|高级讲师

TA的文章

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