深入学习javascript——this绑定(代码片段)

chanwunsam chanwunsam     2022-12-05     648

关键词:

this 绑定是面试题常考的类型,同时,它和原型链、闭包结合在一起,可以实现很多复杂的功能。本文将 this 绑定涉及相关知识做了一个归纳整理,当然,也从中收获了很多。

介绍 this 绑定

这里直接列出 this 绑定的四大规则,这些规则都是《你不知道的JavaScript》一书中提到的关键词,个人觉得比较好理解。因为这里只涉及常识性的介绍,如果已经了解的话可以快速跳过,进入下一小节。如果你还不熟悉,可能会碰到很多陌生又让你心痒的概念。这里建议你先暂时放下,我会在后文详细说明,或贴上我觉得不错的博客。

  • 默认绑定
  • 隐式绑定
  • 显式绑定
  • new绑定

默认绑定

又可以叫函数调用。正如其名,它指的是在没有其它规则的情况下默认使用的绑定规则,一般就是直接调用函数的情况。在一般情况下,默认绑定的对象是全局对象 window;当函数内部处于严格模式下时,它绑定的是 undefined

case1.1.1

// 这里是通常情况下的默认绑定
var a = 0; 
function foo() 
    var a = 10;
    console.log(“a=” + this.a); // window.a

foo(); 
// a=0

case1.1.2

// 严格模式下的默认绑定(注意 use strict 位置)
var a = 0; 
function foo() 
    "use strict";
    var a = 10;
    console.log(“a=” + this.a); // window.a

foo(); 
// a=0

可以看到,这里的 this.a 绑定的对象是全局对象。

隐式绑定

隐式绑定又可以叫对象方法调用,即作为对象方法使用。既然是对象调用,那么就少不了对象的使用。具体的使用情况如下:

case1.2

var a = 0;
var b = 
    a: 10,
    foo: function() 
        var a = 20;
        console.log("a=" + this.a); // b.a
    
;
b.foo();
// a=10

其实挺好理解,这里面 this 的绑定对象是 b。但是,使用隐式绑定时,我们仍然很容易踩到一些坑,这个坑后文会提到。

显式绑定

显式绑定看似和上面的隐式绑定相对应,其实没太大关系。它又可以叫做 apply/call 调用,其实就是使用了 JavaScript 中很强大的两个方法。这两个方法使用效果,简而言之是强行为所指定函数绑定所指定对象。这里贴上相关的补充链接,不过即使你不看也不影响浏览本文:JS 中的 call、apply、bind 方法详解

假如你差不多了解清楚了,看看下面的例子。

case1.3

var a = 0;
var b = 
    a: 10
;
var c = 
    a: 20, // c.a === 20
    foo: function() 
        console.log("a=" + this.a);
    
;
c.foo.call(b);  // 为foo的this指定绑定对象b
// a=10

上面是显式绑定的一个例子。可以看到,首先 foo 是由 c 作为对象方法进行调用的,然后使用了 call 方法显式绑定到 b上,最后的输出结果就如上。大家也可以猜到,这里显式绑定的优先级高于隐式绑定,至于其它几种组合方式,也等到后文再详细介绍。

new 绑定

也叫构造函数调用。不过,对于 JS 的构造函数,不熟悉的同学千万别将之与 C/Java 之类的构造函数相提并论,两者实质是完全不同的(虽然下例看起来好像很相似)!这里先上代码,更深层次的内容后文再说~

case1.4

var a = 0;
function Foo() 
    this.a = 10; // 当作为构造函数时,这里可以看作 a: 10 的声明形式

var foo = new Foo();
console.log(foo.a); // foo 此时是一个对象而不是函数
// 10
console.log(Foo.a);  // 将 Foo 作为对象调用试试看?
// undefined

看起来和上面那三种毫无联系,实际上它的原理与显式绑定紧密相关。如果你看到这里还没懵的话,那就接着下一节看吧~(如果懵的话,可以将上面四个示例在 codepen 敲一遍)

剖析 this 绑定

上面总结的四个绑定规则,在实际应用中有各种各样的变式出现。如果对这些意外情况进行仔细分析,也能帮助我们更好地理解 JS。

绑定优先级和 new 绑定原理

上文其实部分涉猎了绑定优先级的问题。很显然,默认绑定的优先级一定是最低的;在 case1.3 中,我们又知道了显式绑定优先级高于隐式绑定。但是,我们如何确定 new 绑定的优先级呢?

在 case1.4 中,我们了解到构造函数 new 返回的是一个对象,但需要注意的是,这个返回对象是新构造的,即不与原来的任何函数或对象产生联系。怎么理解这一点呢?看下面这个例子

case2.2.1

var obj = 
    a: 10,
    foo: function(a) 
        this.a = a;
    

obj.foo(20);
console.log(obj.a);
// 20
var bar = new obj.foo(30);
console.log(bar.a);
// 30
console.log(obj.a);
// 20

case2.2.1 可以印证之前所说的。同时,通过这个例子我们也可以看到,对于 bar 接受的返回值来说,new 绑定的优先级高于隐式绑定。

那么,new 绑定与显式绑定的优先级如何对比呢?《你不知道的 JavaScript》一书提到一个例子,但这个例子个人觉得还不足以说明问题,所以这里将原文的例子进行了改进和补充。

case2.2.2

function foo(a) 
    this.a = a;


var obj = ;
var bar = foo.bind(obj); // bind 和 apply/call 功能类似,但返回的是一个函数引用
bar(2); // 执行了 this.a = 2
console.log(obj.a);
// 2

var baz = new bar(3); // 将显式绑定返回的函数作为构造函数使用,看看结果怎样?
console.log(obj.a); // 前面提到的,构造函数返回的对象不影响原来的对象或函数
// 2
console.log(baz.a); // 这里说明,new 绑定的结果不受显式绑定的影响
// 3
bar(4); // 假如再执行一次呢?如果无效,说明 new 绑定优先级比较高
console.log(obj.a); // 这里说明,两种绑定实际上互不干扰
// 4

其实上面绕来绕去的,理解问题的一个关键就是 new 绑定的原理到底是什么?这是一个写起来又能撑一篇的问题,老惯例,贴出我认为写得比较好的博客。

详解 JS 中 new 调用函数原理

绑定丢失和 this 底层原理

这是《你不知道的 JavaScript》中提到的例子,这里将之收集起来,做一个统一汇总。

case2.1.1

var b = 
    a: 10,
    foo: function () 
        console.log(this.a);
    

var fn = b.foo;
fn();
// undefined

case2.1 中,fn 引用的是一个 foo 函数,而不是 b.foo 的对象方法。也就是说,在赋值操作后,foo 所处的环境是全局域而不是 b 的词法作用域内。

case2.1.2

function foo() 
    console.log(this.a);

var a = 2;
var o = a: 3, foo: foo;
var p = a: 4;
o.foo();
// 3
(p.foo = o.foo)();
// 2

case2.1.2 的原因与 case2.1.1 是一样的。看到此处,有些人可能对 JS 中奇怪的各种作用域产生疑惑,为什么一个赋值操作会改变所处作用域呢?

这里涉及的问题其实是 JS 的内存数据结构设计的问题。具体的可以点下面链接,看完这个链接,相信你之前的一些疑惑都会得到解答。

阮一峰——JavaScript 的 this 原理

后记

这篇文章攒了比较久,说实话自己想写的很多点都还没能写出来。一方面是因为避免写得太杂,所以有一些问题我会贴出博客,如果还是不能解决可以私信我;另一方面也是能力有限,即使只是做一些整理性的工作,仍然耗费了我大量的时间,而且再拖下去也没太大意义。所以,这篇我认为还算有深度,勉强算原创的文章就写到这吧。

今天是劳动节,作者没有放假而是一下午肝了这篇,因为这算是上周欠下的了。同时,我计划会在劳动节假期再更一篇,要写哪些方向已经想好了,到时候会从下面两条中挑一条(我希望我能挑战好第二条,所以给个鼓励吧~)

  • 原型链
  • 从闭包、this绑定角度、原型链剖析 bind、jQuery 事件绑定机制以及柯里化


来自为知笔记(Wiz)


深入解析javascript中的this关键字

如果问初学者js中什么东西比较难懂,很多回答会是this关键字。this在不同场景下所指向的对象不同,这就有一种扑朔迷离的感觉,放佛魔法一般神秘:this到底是什么?这里有四种绑定规则。 1.默认绑定默认绑定是无法应用... 查看详情

深入浅出javascript中的this

深入浅出JavaScript中的this在Java等面向对象的语言中,this关键字的含义是明确且具体的,即指代当前对象。一般在编译期确定下来,或称为编译期绑定。而在JavaScript中,this是动态绑定,或称为运行期绑定的,这就导致JavaScript中... 查看详情

javascript中this的绑定

JavaScript中this有很多种绑定方式,最近学习过程中总结了一下,有默认绑定、隐式绑定、显示绑定、强制绑定、实例绑定。接下来我们看看:默认绑定:代码如下:functionfoo(){  console.log(this.a);}vara=3;foo();//3全局作用域下this默认... 查看详情

对this关键字的深入探究

  this无疑是javascript中特别复杂的机制了,最使我们困扰的就是this的指向,仅以本文对我所理解的this做一个总结和记录。每一句话都是重点!文章参考《你不知道的javascript》。  首先需要对this有一个大概的理解:每个函数... 查看详情

深入理解jsthis绑定(无需死记硬背,尾部有总结和面试题解析)(代码片段)

...?在讨论this绑定前,我们得先搞清楚this代表什么。this是JavaScript的关键字之一。它是对象自动生成的一个内部对象,只能在对象内部使用。随着函数使用场合的不同,this的值会发生变化。this指 查看详情

深入学习javascript系列——对象/继承(代码片段)

本篇为此系列第六篇第一篇:#深入学习JavaScript系列(一)——ES6中的JS执行上下文第二篇:#深入学习JavaScript系列(二)——作用域和作用域链第三篇:#深入学习JavaScript系列(三)——this第四... 查看详情

第一百二十一节,javascript事件绑定及深入

JavaScript事件绑定及深入  学习要点: 1.传统事件绑定的问题 2.W3C事件处理函数 3.IE事件处理函数 4.事件对象的其他补充  查看详情

深入学习jquery事件绑定

×目录[1]bind[2]trigger[3]delegate[4]on[5]one前面的话  javascript有HTML、DOM0级、DOM2级和IE这四种事件处理程序,而jQuery对这四种事件处理程序进行了兼容处理,以更简单的方式就可以实现事件绑定。本文将详细介绍jQuery事件绑定 ... 查看详情

javascript高级this绑定绑定优先级相关面试题与箭头函数(代码片段)

...is使用相关面试题1234参考资料this绑定函数在调用时,JavaScript会默认给this绑定一个值this的绑定与定义的位置无关this的绑定与调用方式以及调用的位置有关this在运行时被绑定this有四种绑定规则: 查看详情

一文搞定javascript的this指向问题(代码片段)

一文搞定JavaScript的this指向问题代码执行时this在内存中的位置this绑定规则规则一:默认绑定(独立函数调用)规则二:隐式绑定规则三:显示绑定规则四:new绑定系统API中的this指向多个绑定优先级的比较... 查看详情

javascript深入浅出——学习笔记

在慕课之前学过JS深入浅出,最近发现很多东西都记不太清楚了,再复习一遍好了,感觉这个课程真的超级棒的,做做笔记,再添加一些学习内容??随时补充课程大纲1.数据类型2.表达式和运算符3.语句4.对象5.数组6.函数7.this8.闭包... 查看详情

深入浅出javascript中的this(代码片段)

...么是执行上下文简而言之,执行上下文是评估和执行JavaScript代码的环境的抽象概念。每当Javascript代码在运行的时候,它都是在执行上下文中运行JavaScript中有三种执行上下文类型全局执行上下文—这是默认或者说基础的... 查看详情

深入理解es6箭头函数中的this(代码片段)

简要介绍:箭头函数中的this,指向与一般function定义的函数不同,比较容易绕晕,箭头函数this的定义:箭头函数中的this是在定义函数的时候绑定,而不是在执行函数的时候绑定。 1、何为定义时绑定我们来看下面这个例子:... 查看详情

javascript学习--item21漂移的this

而在JavaScript中,this是动态绑定,或称为运行期绑定的,这就导致JavaScript中的this关键字有能力具备多重含义,带来灵活性的同时,也为初学者带来不少困惑。本文仅就这一问题展开讨论,阅罢本文,读... 查看详情

javascript中的this绑定

一、this的作用this一般在函数或对象的方法中使用this用于自动引用合适的上下文对象,也就是自动引用调用函数的对象,相对于显式引用更加灵活,代码更加简洁二、this的绑定this在函数被调用时绑定,this的指向取决于函数在哪... 查看详情

深入理解this

...#中的this就是指向一个他的实例对象,      但是在javascript中,我可能要告诉你,他是在运行时动态绑定的他指向什么,完全取决于函数在哪里调用             查看详情

javascript--this机制

  this在javascript中很常见同时也是种比较复杂的机制,正确地了解this并且学会正确使用,可以让我们写出更高效、优雅的代码。  this是在代码运行时进行绑定的,并不在编写时,它的上下文环境取决于韩式调用时的各种条... 查看详情

《2w字大章38道面试题》彻底理清js中this指向问题(代码片段)

...this都不成问题。学习this之前,建议先学习以下知识:JavaScript之预编译[1]JavaScript之手撕new[2]JavaScript之手撕call/apply[3]JavaScript之静态作用域与动态作用域[4]JavaScript之手撕数组高阶函数[5]在文章的最开始,陈列一下本篇文章... 查看详情