资讯专栏INFORMATION COLUMN

[JS]《你不知道的Javascript·上》——this关键字

Chiclaim / 512人阅读

摘要:的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。这是一种显示的强制绑定,称为硬绑定。调用的上下文调用的时候把绑定到绑定关于,有一个重要的点实际上并不存在所谓的构造函数,只有对于函数的构造调用。

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

当一个函数被调用时,会创建一个活动记录(也称执行上下文)。

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

this的绑定规则 默认绑定
function foo(){
    console.log(this.a);
}

var a=2;
foo();//2

本例中函数调用时应用了this的默认绑定,因为foo()是直接使用不带任何修饰的函数引用进行调用的,因此this指向全局对象。

*:如果使用严格模式,则不能将全局对象用于默认绑定,因此this会绑定到undefined。
**:对于默认绑定来说,决定this绑定对象的并不是调用位置是否处于严格模式,而是函数体是否处于严格模式。

隐式绑定
function foo(){
    console.log(this.a);
}

var obj={
    a:2,
    foo:foo
};

obj.foo();//2

当foo()被调用时,它的前面确确实实加上了对obj的引用。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。因此调用foo()时this被绑定到obj,因此this.a和obj.a是一样的。

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

隐式丢失
function foo(){
    console.log(this.a);
}

var obj={
    a:2,
    foo:foo
};

var bar=obj.foo;

var a=3;

bar();//3

虽然bar是obj.foo的一个引用,实际上,它引用的是foo函数本身,因此此时的bar()其实是一个不带任何修饰的函数调用,因此应用了默认绑定。

同样,传人回调函数时也会发生隐式丢失,不管传入的是自己声明的函数还是传入语言内置的函数。

显式绑定
function foo(){
    consol.log(this.a);
}

var obj={
    a:2
};

foo.call(obj);//2

通过foo.call(),我们在调用foo()时强制把它的this绑定到obj上。

*:从this绑定的角度来看,call()和apply()是一样的。

硬绑定
function foo(){
    console.log(this.a);
}

var obj={
    a:2
};

var bar=function(){
    foo.call(obj);
};

bar();//2

setTimeout(bar,100);//2

bar.call(window);//2

本例中我们创建了bar(),并在内部手动调用了foo.call(obj),强制把foo的this绑定到了obj。无论之后怎样调用bar,它都会手动在obj上调用foo。这是一种显示的强制绑定,称为硬绑定。

由于硬绑定是一种非常常用的模式,ES5内置了bind()方法。其会返回一个新函数,把你指定的参数设置为this的上下文并调用原始函数。

API调用的上下文
function foo(el){
    console.log(el,this.id);
}

var obj={
    id="awesome"
};

//调用 foo()的时候把this绑定到obj
[1,2,3].forEach(foo,obj);
//1 awesome 2 awesome 3 awesome
new绑定
关于new,有一个重要的点:实际上并不存在所谓的“构造函数”,只有对于函数的“构造调用”。
使用new来调用函数,或者说发生构造函数调用时,会执行下列操作:
(1):创建一个全新的对象
(2):这个新对象会被执行[[Prototype]]连接
(3):这个新对象会绑定到函数调用的this
(4):如果函数没有返回其他对象,那么new表达式中的函数会自动返回这个新对象
function foo(a){
    this.a=a;
}

var bar=new foo(2);
console.log(bar.a);//2

使用new来调用foo()时,我们会构造一个新对象并把它绑定到foo()调用的this上。

优先级

判断this:

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

var bar=new foo();

函数是否通过call、apply(显式绑定)或者硬绑定调用?如果是的话,this绑定的是指定的对象

var bar=foo.call(obj2);

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

var var=obj1.foo();

如果都不是的话,使用默认绑定。如果在于按个模式下,就绑定到undefined,否则绑定到全局对象

var bar =foo();

绑定例外 被忽略的this
如果你把null或者undefined作为this的绑定对象传入call、apply或者bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。
function foo(a,b){
    console.log("a:"+a+",","b:"+b);
}

//把数组展开成参数
foo.apply(null,[2,3]);//a:2,b:3

//使用bind()进行柯里化
var bar=foo.bind(null,2);
bar(3);//a:2,b:3
更安全的this
一种更安全的做法是把this绑定到一个特殊的对象,且不会对程序造成任何副作用。可以使用一个DMZ对象,比如"xx"=Object.create(null)以保护全局变量。
间接引用

间接引用最容易在赋值时发生:

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————p.foo=o.foo的返回值是目标函数的引用,因此调用位置是foo()而不是p.foo()或o.foo(),这里应用的是默认绑定
软绑定
function foo(){
    console.log("name"+this.name);
}
var obj={ name:"obj"};
var obj1={ name:"obj1"};
var obj2={ name:"obj2"}; 

var fooOBJ=foo.softBind(obj);
fooOBJ();//obj

obj2.foo=foo.softBind(obj);
obj2.foo();//obj2

fooOBJ.call(obj3);//obj3

setTimeout(obj.foo,10);//obj
this词法
function fo(){
    return (a)=>{
        console.log(this.a);
    };
}

var obj1={a:1};
var obj2={a:2};

var bar=foo.call(obj1);

bar.call(obj2);//1

foo()内部创建的箭头函数会捕获到调用foo()的this,由于foo()的this绑定到obj1,bar的this也会绑定到obj1,箭头函数的绑定无法被修改

具体来说,箭头函数会继承外层函数调用的this绑定。

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

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

相关文章

  • 你不知道JavaScript》 () 阅读摘要

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

    FingerLiu 评论0 收藏0
  • 笔记-你不知道JS-this

    摘要:绑定使用来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。 1 this的概念 this 在任何情况下都不指向函数的词法作用域。作用域对象无法通过 JavaScript代码访问,它存在于 JavaScript 引擎内部。 this 是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方...

    leanote 评论0 收藏0
  • 你不知道JavaScript(ES6与之未来)

    摘要:然而,临近规范发布时,有建议提及未来的版本号切换为编年制,比如用同来指代在年末前被定稿的所有版本。总得来说就是版本号不再那么重要了,开始变得更像一个万古长青的活标准。 你不知道的JS(下卷)ES6与之未来 第一章:ES的今与明 在你想深入这本书之前,你应该对(在读此书时)JavaScript的最近标准掌握熟练,也就是ES5(专业来说是ES 5.1)。在此,我们决定全方面地谈论关于将近的...

    Julylovin 评论0 收藏0
  • 你不知道js中关于this绑定机制解析[看完还不懂算我输]

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

    dunizb 评论0 收藏0
  • 精读《你不知道javascript(中卷)》

    摘要:强制类型转换本章介绍了的数据类型之间的转换即强制类型转换包括显式和隐式。强制类型转换常常为人诟病但实际上很多时候它们是非常有用的。隐式强制类型转换则没有那么明显是其他操作的副作用。在处理强制类型转换的时候要十分小心尤其是隐式强制类型转换。 前言 《你不知道的 javascript》是一个前端学习必读的系列,让不求甚解的JavaScript开发者迎难而上,深入语言内部,弄清楚JavaSc...

    李世赞 评论0 收藏0

发表评论

0条评论

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