资讯专栏INFORMATION COLUMN

【读书笔记】你不知道的JavaScript--this

Me_Kun / 3008人阅读

摘要:但是如果某个函数确实使用了,那默认绑定规则会把绑定到全局对象在浏览器中这个对象是,这将导致不可预计的后果比如修改全局对象。实际上并不存在所谓的构造函数,只有对于函数的构造调用。使用来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。

this 实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用(也就是函数的调用方法)。

1. 默认绑定

独立函数调用时,应用 this 的默认绑定, this 指向全局对象
如果使用严格模式(strict mode),那么全局对象将无法使用默认绑定,因此 this 会绑定到 undefined
观察下面这段代码

function aba () {
    console.log(this)
}
function bab () {
    "use strict"
    console.log(this)
}
var obj = {
    aba: aba,
    bab: bab
}
aba() //Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
bab()  //undefined
obj.aba() //{aba: ƒ, bab: ƒ}
obj.bab() //{aba: ƒ, bab: ƒ}
2. 隐式绑定

在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把 this 间接(隐式)绑定到这个对象上。
当函数引用有上下文对象时,隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象。
所以上个示例代码中, 调用 obj.aba()this 被绑定到 obj,因此 this.abaobj.aba 是一样的。

对象属性引用链中只有最顶层或者说最后一层会影响调用位置。

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

一个最常见的 this 绑定问题就是被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定,从而把 this 绑定到全局对象或者 undefined 上,取决于是否是严格模式。

function fun1 () {
    console.log(this)
}
var obj = {
    fun1: fun1,
    fun2: function () {
        console.log(this)
    }
}
var getfun1 = obj.fun1
var getfun2 = obj.fun2
function doCallBack (cb) { //参数传递其实就是一种隐式赋值,因此我们传入函数时也会被隐式赋值
    cb()
}
function testSetTimeout (fun) {
    setTimeout(fun, 0)
}
fun1()                    // Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
obj.fun1()                // {fun1: ƒ, fun2: ƒ}
obj.fun2()                // {fun1: ƒ, fun2: ƒ}
getfun1()                 // Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
getfun2()                 // Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
doCallBack(obj.fun1)      // Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
doCallBack(obj.fun2)      // Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
testSetTimeout(obj.fun1)  // Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
testSetTimeout(obj.fun2)  // Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
3. 显式绑定

使用 callapplybind 或者箭头函数显示绑定函数调用的 this
如果把 null 或者 undefined 作为 this 的绑定对象传入 callapply 或者 bind,这些值在调用时会被忽略,实际应用的是默认绑定规则

var obj = {
    c: 33,
    fun: function (a,b) {
        console.log( "a:" + a + ", b:" + b + ", c:" + this.c )
    }
}
// 把数组“展开”成参数
obj.fun.apply( null, [2, 3] ); a:2, b:3, c:undefined
// 使用 bind(..) 进行柯里化
var bar = obj.fun.bind( null, 2 );
bar( 3 ); // a:2, b:3, c:undefined

上面代码中 applybind 这两种方法都需要传入一个参数当作 this 的绑定对象。如果函数并不关心 this 的话,仍然需要传入一个占位值,这时 null 可能是一个不错的选择。
但是如果某个函数确实使用了 this,那默认绑定规则会把 this 绑定到全局对象(在浏览器中这个对象是 window),这将导致不可预计的后果(比如修改全局对象)。

4. new绑定

在 JavaScript 中,构造函数只是一些被 new 操作符调用的普通函数而已。
实际上并不存在所谓的“构造函数”,只有对于函数的“构造调用”。

使用 new 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
1 创建(或者说构造)一个全新的对象。
2 这个新对象会被执行 [[ 原型 ]] 连接。
3 这个新对象会绑定到函数调用的 this。
4 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。

注意: 对 bind 返回的函数进行构造调用时,实际调用的是原函数,调用 bind 时传入的第一个参数将被忽略,剩余参数作为构造调用的参数传入原函数

function test (a, b) {
    this.a = a
    this.b = b
    this.say = function () {
        console.log(`a: ${this.a}, b: ${this.b}, c: ${this.c}`)
    }
}
var bindObj = {
    c: 12
}
var bindReturn = test.bind(bindObj, 1, 2)
var newBindReturn = new bindReturn()
newBindReturn.say()  // a: 1, b: 2, c: undefined
console.log(bindObj) // {c: 12}
bindReturn()
console.log(bindObj) // {c: 12, a: 1, b: 2, say: ƒ}

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

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

相关文章

  • 你不知道JS》读书笔记---作用域及闭包

    摘要:注此读书笔记只记录本人原先不太理解的内容经过阅读你不知道的后的理解。作用域及闭包基础,代码运行的幕后工作者引擎及编译器。 注:此读书笔记只记录本人原先不太理解的内容经过阅读《你不知道的JS》后的理解。 作用域及闭包基础,JS代码运行的幕后工作者:引擎及编译器。引擎负责JS程序的编译及执行,编译器负责词法分析和代码生成。那么作用域就像一个容器,引擎及编译器都从这里提取东西。 ...

    denson 评论0 收藏0
  • 读书笔记你不知道JavaScript--内置类型

    摘要:有种内置类型,分别是除对象之外,其他统称为基本类型。另一个需要注意的是数组确切地说,数组也是的一个子类型我们可以通过下面的方法检查变量是不是数组处理未声明的变量时,会返回这是因为有一个特殊的安全防范机制。 js有7种内置类型,分别是undefined null boolean string number symbol object除对象之 Object 外,其他统称为基本类型。符号 ...

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

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

    Jacendfeng 评论0 收藏0
  • 你不知道JS》读书笔记之闭包在循环中应用

    摘要:闭包在循环中的应用延迟函数的回调会在循环结束时才执行事实上,当定时器运行时即使没给迭代中执行的是多有的回调函数依然是在循环结束后才会被执行,因此会每次输出一个出来。 闭包在循环中的应用 延迟函数的回调会在循环结束时才执行;事实上,当定时器运行时即使没给迭代中执行的是 setTime(..., 0),多有的回调函数依然是在循环结束后才会被执行,因此会每次输出一个6出来。 for(var...

    weapon 评论0 收藏0
  • 你不知道JavaScript上卷之作用域与闭包·读书笔记

    摘要:的分句会创建一个块作用域,其声明的变量仅在中有效。而闭包的神奇作用是阻止此事发生。依然持有对该作用域的引用,而这个引用就叫做闭包。当然,无论使用何种方式对函数类型的值进行传递,当函数在别处被调用时都可以观察到闭包。 date: 16.12.8 Thursday 第一章 作用域是什么 LHS:赋值操作的目标是谁? 比如: a = 2; RHS:谁是赋值操作的源头? 比如: conso...

    Raaabbit 评论0 收藏0

发表评论

0条评论

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