资讯专栏INFORMATION COLUMN

《你不知道的javascript》笔记_this

cpupro / 2666人阅读

下一篇:《你不知道的javascript》笔记_对象&原型

写在前面

上一篇博客我们知道词法作用域是由变量书写的位置决定的,那this又是在哪里确定的呢?如何能够精准的判断this的指向?这篇博客会逐条阐述

书中有这样几句话:

this是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件
this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式

当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this 就是记录的其中一个属性,会在函数执行的过程中用到。

关于执行上下文,可以参考《javascript高级程序设计》笔记:内存与执行环境

一、 绑定规则 1.1 默认绑定
最常用的函数调用类型——独立函数调用,使用的即为默认绑定规则,在非strict mode下,this指向全局对象
function foo1() {
    console.log(this.a);
}
var a = 10;
foo1(); // 10

// 即使函数嵌套比较深
function foo2() {
    foo1();
}
function foo3() {
    foo2();
}
foo3();

当然,我们实际使用中,难以判别的并不是直接型的默认绑定模式,而是隐式绑定丢失型的默认绑定(下面会着重说明)

1.2 隐式绑定【重点】
调用的位置是否有上下文对象,或者说被某个对象拥有或包含
// 基本形式
function foo() {
    console.log(this.a);
}
var obj = { a: 10, foo };
obj.foo(); // 10

隐式绑定中的几个雷区:

1. 多个对象嵌套引用时,只有最后一层在调用位置中起作用

function foo() {
    console.log(this.a);
}
var obj2 = { a: 42, foo };
var obj1 = { a: 10, obj2 };
obj1.obj2.foo(); // 42

2.【隐式丢失】当调用函数被重新赋值为新变量,调用新变量时this指向会有不同

// 共用部分
function foo(){
    console.log(this.a);
}
var obj = { a: 10, foo };
var a = "opps, global";

// 直接赋值
var bar = obj.foo;
bar(); // "oops, global"

// 回调间接赋值1
function doFoo(fn) {
    fn();
}
doFoo(obj.foo); // "oops, global" 相当于间接赋值

// 回调间接赋值2
setTimeout(obj.foo, 100); // "oops, global" 内置的setTimeout也相当于间接赋值

经典综合案例:

var length = 10;
function fn(){
    console.log(this.length);
}
var obj = {
    length: 5,
    method: function (fn) {
        fn();
        arguments[0]();
    }
};

obj.method(fn, 123);

分析:fn()为函数fn的引用,默认绑定,指向全局;arguments[0]();相当于下面的引用,数据隐式绑定,绑定对象为arguments,其属性length值为参数数量2

arguments: {
    "0": function fn(){
        console.log(this.length);
    }
}

答案:10 2

1.3 显式绑定
call()/apply()/bind()能够显式修改this指向

通过上述方法调用的方式为显示绑定,它们第一个参数是一个对象,在调用函数时,绑定在this中。

关于三者的基本用法和说明在之前博客《javascript高级程序设计》函数调用模式 & this深度理解中已作说明,在此不做唠述

两点注意

1. 通过显式绑定的不能再修改它的this指向

function foo() {
    console.log(this.a);
}
var obj = { a: 2 };
var bar = function() {
    foo.call(obj);
}
bar(); // 2
setTimeout(bar, 200); // 2

bar.call(window); // 2

2. 将null/undefined作为第一个参数时,调用会忽略这些值,采用默认绑定规则

function foo() {
    console.log(this.a);
}
var a = 2;
foo.call(null); // 2
1.4 new绑定
使用关键字new执行函数,当函数无返回值或返回值非对象时,this指向为实例对象

new关键字执行函数流程:

创建一个全新的对象

这个新对象会被执行[[prototype]]连接

这个新对象会绑定到函数调用的this

如果函数没有返回其他对象,所执行函数会自动返回这个新的对象

须知:构造函数与普通函数无异,作为区分,我们一般讲通过new调用的函数称为构造函数,并大写第一个单词。所有函数均可由关键字new调用

function foo(a) {
    this.a = a;
}
var bar = new foo(2);
console.log(bar.a); // 2
二、优先级&判断规则 2.1 优先级

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

2.2. 判断规则【重点】

new绑定】函数是否在new中调用?如果是,this绑定的是新创建的对象

显式绑定】函数是否在call/aplly/bind中调用?如果是,this绑定的是指定对象

隐式绑定】函数是否在某个上下文中调用?如果是,this绑定到那个上下文对象

默认绑定】如果都不是,this绑定严格模式下为undefined,非严格模式下为全局对象

三、箭头函数中的this
ES6中箭头函数不使用上面this的四种标准规格,而是根据外层(函数或者全局)作用域来决定this指向

下面是一个普通函数和箭头函数的对比:

function foo1() {
    setTimeout(() => {
        console.log(this.a)
    }, 100)
}
function foo2() {
    setTimeout(function() {
        console.log(this.a)
    }, 100)
}

var a = 10;
var obj = { a: 2 };

foo1.call(obj); // 2 箭头函数this指向外层(obj)
foo2.call(obj); // 10 隐式丢失,默认绑定

【利用闭包】理解箭头函数中的this:

// 上例中的箭头函数相当于
function foo1() {
    var self = this;
    setTimeout(function() {
        console.log(self.a)
    }, 100)
}

上一篇:《你不知道的javascript》笔记_作用域与闭包
下一篇:《你不知道的javascript》笔记_对象&原型

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

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

相关文章

  • 你不知道javascript笔记_对象&原型

    摘要:上一篇你不知道的笔记写在前面这是年第一篇博客,回顾去年年初列的学习清单,发现仅有部分完成了。当然,这并不影响年是向上的一年在新的城市稳定连续坚持健身三个月早睡早起游戏时间大大缩减,学会生活。 上一篇:《你不知道的javascript》笔记_this 写在前面 这是2019年第一篇博客,回顾去年年初列的学习清单,发现仅有部分完成了。当然,这并不影响2018年是向上的一年:在新的城市稳定、...

    seasonley 评论0 收藏0
  • 你不知道javascript笔记_作用域与闭包

    摘要:建筑的顶层代表全局作用域。实际的块级作用域远不止如此块级作用域函数作用域早期盛行的立即执行函数就是为了形成块级作用域,不污染全局。这便是闭包的特点吧经典面试题下面的代码输出内容答案个如何处理能够输出闭包方式方式下一篇你不知道的笔记 下一篇:《你不知道的javascript》笔记_this 写在前面 这一系列的笔记是在《javascript高级程序设计》读书笔记系列的升华版本,旨在将零碎...

    galaxy_robot 评论0 收藏0
  • 你不知道JavaScript》 (下) 阅读摘要

    摘要:本书属于基础类书籍,会有比较多的基础知识,所以这里仅记录平常不怎么容易注意到的知识点,不会全记,供大家和自己翻阅不错,下册的知识点就这么少,非常不推介看下册上中下三本的读书笔记你不知道的上读书笔记你不知道的中读书笔记你不知道的下读书笔记第三 本书属于基础类书籍,会有比较多的基础知识,所以这里仅记录平常不怎么容易注意到的知识点,不会全记,供大家和自己翻阅; 不错,下册的知识点就这么少,非...

    Jacendfeng 评论0 收藏0
  • 你不知道JavaScript》 (上) 阅读摘要

    摘要:但是如果非全局的变量如果被遮蔽了,无论如何都无法被访问到。但是如果引擎在代码中找到,就会完全不做任何优化。结构的分句中具有块级作用域。第四章提升编译器函数声明会被提升,而函数表达式不会被提升。 本书属于基础类书籍,会有比较多的基础知识,所以这里仅记录平常不怎么容易注意到的知识点,不会全记,供大家和自己翻阅; 上中下三本的读书笔记: 《你不知道的JavaScript》 (上) 读书笔记...

    FingerLiu 评论0 收藏0
  • 你不知道JS上》笔记

    摘要:隐式绑定即绑定到最顶层或最近调用对象上显式绑定即用或手动进行绑定方法实现绑定构造函数不存在其实在中不存在构造函数,我们所说的构造函数其实就是普通的函数,它只是用被构造调用而已。 JS是编译型语言 编译发生在代码执行前几微秒,简单来说就是js在执行前要进行编译,编译过程发生在代码执行前几微妙,甚至更短。 编译的步骤 词法分析以var a = 2 为例,词法分析会将其分成三个有意义的代码...

    VPointer 评论0 收藏0

发表评论

0条评论

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