资讯专栏INFORMATION COLUMN

《你不知道的javascript》中关于this的记录

tommego / 3025人阅读

摘要:使用调用函数时,会自动执行以下操作创建一个全新的对象该对象会被执行连接该对象会绑定到函数调用的若函数没有返回其他对象,表达式中的函数调用会自动返回该对象。

使用this可以减少传入上下文对象,可以隐式传递一个对象引用。使API简洁而复用,可以自动引用合适的上下文对象。

【要注意的几个点】
1. this不一定指向自身;
2. this不一定指向函数作用域(因为作用域无法通过js代码访问,它存在js引擎内部);
3. this是在运行时(函数被调用时)绑定的,不是编写代码时绑定。this的绑定取决于函数的调用位置,不是函数声明的位置;
4. 不能通过this来引用一个词法作用域内部的东西

####【找this的指向】
分析调用栈(为了到达当前执行位置所调用的所有函数),找到当前正在执行的函数的前一个调用,即调用栈的第二个元素。因为函数被调用时,会创建一个活动记录(执行上下文)。该活动记录包括(函数的调用栈、传入的参数、函数的调用方法……)

[方法]:在代码前插入一条debugger语句,在开发者工具中查看call stack中的第二个元素,就是this的调用位置.
function first(){
    //当前调用栈first
    //当前的调用位置是全局作用域
    console.log("first");
    second();//second的调用位置
}
function second(){
    //当前调用栈first->second
    //当前的调用位置是first
    console.log("second");
    third();//third的调用位置
}
function third(){
    //当前调用栈first->second->third
    //当前的调用位置是second
    console.log("third");
}

//first的调用位置
first();//firstsecondthird
【四条this规则】:

1.默认绑定(绑定到全局对象),但严格模式下this会绑定到undefin
ed:
【例子】:不带任何修饰的函数调用

function example(){
    console.log(this.a);
}
var a="karine";
example(); //karine

2.隐式绑定
(在一个对象内部包含一个指向函数的属性,通过该属性间接地引用函数,从而把this间接地绑定到该对象上。)

function example(){
    console.log(this.a);
}
var obj={
    a:"karine",
    example:example
};
obj.example(); //karine

在对象属性引用链中,只有最顶层(最后一层)会影响调用位置。

function example(){
    console.log(this.a);
}
var obj1={
    a:"karine",
    example:example
};
var obj2={
    a:"wu",
    obj1:obj1
};

obj2.obj1.example(); //karine

当函数引用有上下文对象时,函数里的this绑定在这个上下文对象上。
但是这种情况可能会出现“隐式丢失”,即丢失绑定的对象,应用默认绑定(全局对象/undefinded):

1. 将函数引用赋值给一个新变量,然后执行。
var obj3 = obj1.example; 
obj3(); //全局or undefined
实际上obj3引用的是example函数本身,因此this还是指向全局/undefined

2. 或者是调用回调函数的函数修改了this
function test(fn){
    fn();
}
test(obj1.example);  //全局or undefined
实际上,参数传递也是一种赋值,只不过是隐式赋值。所以道理同上。也会指向全局。

3.显式绑定
(在对象上强制调用函数,可以使用call(对象)、apply(对象)方法,会把形参里的对象绑定到this上,接着在调用函数时指定这个this。如果传入的参数为原始值(string、number、boolean),该原始值会自动转为其对象形式(new String()、new Number()、new Boolean()),这通常被称为“装箱”)

function example(){
    console.log(this.a);
}
var obj = {
    a:"karine"
};
example.call(obj); //karine

example.apply(obj);//karine

var o = example.bind(obj);
o(); //karine
“硬绑定”bind 的this不会被显示or隐式绑定修改。

4.new绑定
在js中,构造函数只是使用new操作符是被调用的普通函数而已,不属于某个类,也不会实例化一个类。使用new调用函数时,会自动执行以下操作:

1.创建一个全新的对象
2.该对象会被执行[[prototype]]连接
3.该对象会绑定到函数调用的this
4.若函数没有返回其他对象,new表达式中的函数调用会自动返回该对象。
function example(a){
    this.a=a;
}
var obj4 = new example(“karine”);
console.log(obj4.a);//“karine”
【四种this绑定方法的优先级】

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

【例外】:

1.null、undefined作为this的绑定对象传入call、apply、bind时,会被忽略,实际应用的是默认绑定(全局对象)

function example(){
    console.log("a:"+this.a);
}
var a = "karine";
example.call(null); //a:karine

传入null的情况:
(1)使用apply来展开一个数组
(2)使用bind进行柯里化

function example(a,b){
    console.log("a:"+a+“,b:”+b);
}
//使用apply来展开一个数组
example.apply(null,[2,3]); //a:2,b:3
//使用bind进行柯里化(预先设置一些参数)
var o = example.bind(null,2); 
o(3);//a:2,b:3

若想避免不必要的this绑定,可以使用ES6的…操作符来代替apply()

example.apply(null,[2,3]) ===  example(…[2,3])

为了安全,若想忽略this绑定,可以给this传入一个空的非委托对象Φ ("Object.create(null)"),不会产生任何副作用,因为this会限制在这个空对象中,不会对全局对象产生任何影响。

**Object.create(null)**和{}很像,但是不会创建object.prototype,所以比{}“更空”


var Φ = Object.create(null);
example.apply(Φ,[2,3]); //a:2,b:3
var o = example.bind(Φ,2); 
o(3); //a:2,b:3

2.间接引用(经常在赋值时发生),会应用默认绑定。

3.ES6中 "=>"定义的箭头函数不使用this的四种标准规则。而是根据外层作用域来决定this。箭头函数的绑定无法修改。

function example(){
    return(a)=>{
        console.log(this.a);
    }
}
var obj1={a:2};
var obj2={a:3};
var test = example.call(obj1);
test.call(obj2); //2

由于example()的this绑定到obj1,所以test中引用箭头函数的this也会绑定到obj1。

总结】:

1.找到this的调用位置
2.根据四条规则判定this的绑定对象:

(1)new:绑定到新创建的对象
(2)call、apply、bind:绑定到指定的对象
(3)上下文对象:绑定到该上下文对象
(4)默认:全局或者undefined(严格模式下)

3.箭头函数根据当前的词法作用域来决定this
4.有些调用可能无意中使用默认规则,可以使用一个空对象Object.create(null)忽略this绑定,来保护全局对象

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

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

相关文章

  • 你不知道js中关this绑定机制解析[看完还不懂算我输]

    摘要:绑定书中提到在中,实际上并不存在所谓的构造函数,只有对于函数的构造调用。规则使用构造调用的时候,会自动绑定在期间创建的对象上。指向新创建的对象绑定比隐式绑定优先级高。 showImg(http://ww1.sinaimg.cn/large/005Y4rCogy1fstcwvzkjzj30sg0g0qqn.jpg); 前言 最近正在看《你不知道的JavaScript》,里面关于this绑...

    dunizb 评论0 收藏0
  • javascript中关new理解

    摘要:中,实例化一个对象,会用到关键字。这里再解释一下构造函数我们一般把后面的函数称为构造函数,如,其中就为构造函数第四点的,可能比较难理解。有点需要注意如果构造函数内没有返回值,则默认是返回当前上下文,要不然就返回任意非原始类型值。 Javascript中,实例化一个对象,会用到new关键字。 经常有人会问对于一个函数,什么时候该使用new关键字。 在回答这个问题之前,需要先了解清楚new...

    stackvoid 评论0 收藏0
  • JavaScript深入浅出

    摘要:理解的函数基础要搞好深入浅出原型使用原型模型,虽然这经常被当作缺点提及,但是只要善于运用,其实基于原型的继承模型比传统的类继承还要强大。中文指南基本操作指南二继续熟悉的几对方法,包括,,。商业转载请联系作者获得授权,非商业转载请注明出处。 怎样使用 this 因为本人属于伪前端,因此文中只看懂了 8 成左右,希望能够给大家带来帮助....(据说是阿里的前端妹子写的) this 的值到底...

    blair 评论0 收藏0
  • 你不知道this

    摘要:本内容来自你不知道的上卷,做了简单的总结。如果不使用这段代码该如何写呢那就需要给和显示传入一个上下文对象对比发现提供了额一种更优雅的方式来隐式传递一个对象引用。四总结随着你使用的模式越来越复杂,显式传递上下文对象会让代码变得越来越混乱。 本内容来自《你不知道的JavaScript(上卷)》,做了简单的总结。 this关键字是javascript最复杂的机制之一。它是一个很特别的关键字,...

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

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

    FingerLiu 评论0 收藏0

发表评论

0条评论

tommego

|高级讲师

TA的文章

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