持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
首先我们来解决一个问题,记录某个函数的调用次数
这里我们采用了再函数中使用this来试图指向自身的count,并且让自身的count自增。
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); }
}
console.log( foo.count )// 0
//foo: 6
//foo: 7
//foo: 8
//foo: 9
这里的foo.count最后的调用结果是0,原因是在for循环中执行的foo(i)中,这里需要理解this的指向,函数是在全局环境中执行的,this指向的是全局的count,foo中的属性count仍然是0,同时this指向的全局作用域中会出现一个count并且值为NaN
console.log(count)//NaN
console.log(foo)//[Function: foo] { count: 0 }
采取另外一种方法来进行实现
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); }
}
}
console.log( data.count ); // 4
这种方法属于借腹生子的办法虽然能够解决问题,但是没有很好的利用到this来进行解决问题
匿名和具名函数
function foo(num) {
console.log("foo: " + num); // 记录 foo 被调用的次数 foo.count++; }
function foo() { foo.count = 4; // foo 指向它自身 }setTimeout( function(){ // 匿名(没有名字的)函数无法指向自身 }, 10 );
可以看出如果使用了匿名函数,我们无法再函数内通过自己去调用自身,因为它本身没有实际的名字可以使用。
function foo(num){
console.log("foo: " + num);
foo.count++
}
foo.count = 0
var i;
for (i = 0; i < 10; i++) {
if (i > 5) { foo(i); }
}
console.log(foo.count)//4
通过具名函数将次数绑定到自身的方法也能解决该问题,但还是没有用到this来解决
使用call来解决this指向问题(显式绑定)
function foo(num){
console.log("foo: " + num);
this.count++
}
foo.count = 0
var i;
for (i = 0; i < 10; i++) {
if (i > 5) {
foo(i).call(foo,i)
}
}
console.log(foo.count)//4
第一个列子中foo的this指向是全局,当你熟悉了this的多种指向方式后,你会发现这里的call可以强制将函数的执行作用域进行改变,指向foo本身,那么在foo中调用的this则是call传入的内容,这是用到了this的显式绑定。
试图联通作用域
function foo() {
var a = 2;
this.bar();
}
function bar() { console.log(this.a); } foo(); // ReferenceError: a is not defined
表面上看上去没有什么问题,但是其实写这段代码的目的可能是想让bar在foo的内部进行执行,这样bar就能和a处在同一个词法作用域中,从而拿到a的值,也就是一下的部分
function foo() {
var a = 2;
console.log(this.a);
}
但是在《你不知道的JavaScript》一书中指出,调用 bar() 最自然的方法是省略前面的 this,不能使用 this 来引用一个词法作用域内部的东西。每当你想要把 this 和词法作用域的查找混合使用时,一定要提醒自己,这是无法实现的。