《你不知道的JavaScript》-- 精读(六)
栏目: JavaScript · 发布时间: 6年前
内容简介:这段代码可以在不同的上下文对象(me和you)中重复使用函数identify()和speak(),不用针对每个对象编写不同版本的函数。如果不使用this,那就需要给identify()和speak()显式传入一个上下文对象。然而,this提供了一种更优雅的方式来隐式“传递”一个对象引用,因此可以将API设计得更加简洁并且易于复用。
function identify(){
return this.name.toUpperCase();
}
function speak(){
var greeting = "Hello, I'm " + identify.call(this);
console.log(greeting);
}
var me = {
name: "Kyle"
}
var you = {
name: "Reader"
}
identify.call(me); // KYLE
identify.call(you); // READER
speak.call(me); // Hello,我是KYLE
speak.call(you); // Hello,我是READER
复制代码
这段代码可以在不同的上下文对象(me和you)中重复使用函数identify()和speak(),不用针对每个对象编写不同版本的函数。
如果不使用this,那就需要给identify()和speak()显式传入一个上下文对象。
function identify(context){
return context.name.toUppperCase();
}
function speak(context){
var greeting = "Hello, I'm " + identify(context);
console.log(greeting);
}
identify(you); // READER
speak(me); // hello,I'm + identify(context)
复制代码
然而,this提供了一种更优雅的方式来隐式“传递”一个对象引用,因此可以将API设计得更加简洁并且易于复用。
随着你的使用模式越来越复杂,显式传递上下文对象会让代码变得越来越混乱,使用this则不会这样。
2.关于this的误解
2.1 指向自身
function foo(num){
console.log("foo:" + num);
// 记录foo被调用的次数
this.count++;
}
foo.count = 0;
var i;
for(i = 0; i < 10; i++){
if (i > 5){
foo(i);
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo被调用了多少次?
console.log(foo.count); // 0 -- 什么?!
复制代码
执行foo.count = 0时,的确向函数对象foo添加了一个属性count。但是函数内部代码this.count中的this并不是指向那个函数对象,所以虽然属性名相同,根对象却并不相同,困惑随之产生。
实际上,如果深入探索,就会发现这段代码无意中创建了一个全局变量count,其值为NaN。
遇到这样的问题,大多数人会选择下面的解决方案,创建另一个带有count属性的对象。
function foo(num){
console.log("foo: " + num);
// 记录foo被调用的次数
data.count++
}
var data = {
count: 0
}
var i;
for (i = 0; i < 10; i++){
if (i > 5){
foo(i);
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo被调用了多少次?
console.log(data.count);
复制代码
上面使用词法作用域“解决”了问题,但是忽视了真正的问题--无法理解this的含义和工作原理。
如果要从函数对象内部引用它自身,那只使用this是不够的。一般来说你需要通过一个指向函数对象的词法标识符(变量)来引用它。
思考下面的这两个函数
function foo(){
foo.count = 4; // foo指向它自身
}
setTimeout(function (){
// 匿名(没有名字的)函数无法指向自身
},10)
复制代码
第一个函数被称为具名函数,在它内部可以使用foo来引用自身。
第二个例子中,传入setTimeout(...)的回调函数没有名称标识符(这种函数被称为匿名函数),因此无法从函数内部引用自身。
所以,对于我们的例子来说,另一种解决方法是使用foo标识符替代this来引用函数对象:
function foo(num){
console.log("foo:" + num);
// 记录foo被调用的次数
foo.count++;
}
foo.count = 0;
var i;
for(i = 0; i < 10; i++){
if (i > 5){
foo(i);
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo被调用了多少次?
console.log(foo.count); // 4
复制代码
然而,这种方法同样回避了this的问题,并且完全依赖于变量foo的词法作用域。
另一种方法是强制this指向foo函数对象:
function foo(num){
console.log("foo:" + num);
// 记录foo被调用的次数
// 注意,在当前的调用方式下,this确实指向foo
this.count++;
}
foo.count = 0;
var i;
for(i = 0; i < 10; i++){
if (i > 5){
foo.call(foo,i);
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo被调用了多少次?
console.log(foo.count); // 4
复制代码
2.2 它的作用域
第二种常见的误解是,this指向函数的作用域。这个问题有点复杂,因为在某种情况下它是正确的,但是在其他情况下它却是错误的。
this在任何情况下都不指向函数的词法作用域。在JavaScript内部,作用域确实和对象类似,可见的标识符都是它的属性。但是作用域“对象”无法通过JavaScript代码访问,它存在于引擎内部。
function foo(){
var a = 2;
this.bar();
}
function bar(){
console.log(this.a);
}
foo(); // ReferenceError: a is not defined
复制代码
首先,这段代码试图通过this.bar()来引用bar()函数。这样调用能成功纯属意外,我们之后会解释原因。调用bar()最自然的方法是省略前面的this,直接使用词法引用标识符。
此外,编写这段代码的开发者还试图使用this联通foo()和bar()的词法作用域,从而让bar()可以访问foo()作用域里的变量a。这是不可能实现的,使用this不可能在词法作用域中查到什么。
每当你想要把this和词法作用域的查找混合使用时,一定要提醒自己,这是无法实现的。
3 this到底是什么
this是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。
当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方式、传入的参数等信息。this就是这个记录的一个属性,会在函数执行的过程中用到。
总结
this既不指向自身也不指向函数的词法作用域。
this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用。
巴拉巴拉
关于懒
我本来想写的是关于习惯,后来想想还是不要美化自己了,其实就是懒,也没必要找借口,这个的起因是提交代码时不做确认,其实很多次我都做了,但是一遇到忙,或者提交的文件确实多的时候,我就懒得去检查了,这样就自然而然会导致很多问题,比如,之前就犯过API文档的接口名和实际的接口名不一致而被怼的情况,被教育一番,自己也很是羞愧,写了纸条提醒一定不要再犯,但是吧,还是那句话,忙起来就忘了,这也是我想把它归到习惯的原因,这次又是同样的问题,直接把代码粘贴过来改了一下,也没有检查,就提交了,自然又被批评了一番,心中的懊悔自不必说,意识到了自己需要改正的两个地方,1.提交的东西要严谨,2.尽量不粘贴代码,这次应该肯定不会因为什么就忘了,因为教训是惨痛的!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 《你不知道的JavaScript》-- 精读(四)
- 精读《React 性能调试》
- 精读《Typescript 4》
- 精读《正则 ES2018》
- AIStats 2017文章精读(四)
- 精读《如何比较 Object 对象》
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Data Mining
Bing Liu / Springer / 2011-6-26 / CAD 61.50
Web mining aims to discover useful information and knowledge from Web hyperlinks, page contents, and usage data. Although Web mining uses many conventional data mining techniques, it is not purely an ......一起来看看 《Web Data Mining》 这本书的介绍吧!