this是什么,取决于被呼叫的呼叫地点。
昨天有提到说,呼叫函式时候会传递隐含参数:arguments和this并讲解了arguments,今天我们就来探讨this吧!
什么是this
我们都会呼叫函式来使用,但有想过到底是从哪里呼叫到这个函式吗?
this通常被称作函式背景空间(function context),也就是说透过this我们可以知道到底是由谁呼叫这支函式(yjssqsdg)。我们无法在一开始定义它,只有函式呼叫时候才能确定。
函式的呼叫有四种方式:
作为函式呼叫
作为一个(物件)的方法呼叫
作为一个建构式函式呼叫
透过apply、call呼叫
apply、call我们会在下一篇中介绍,我们今天主要介绍上述三种呼叫方式。
作为函式呼叫
function funA(){
console.log(this);
}
funA();//Window
由于是在全局环境呼叫funA,所以这时候的this就会是window。
所以很多刚学习的人都会遇到这个问题:
function funA(){
this.count ++;
}
funA.count = 0;
funA();
console.log(funA.count);//0
明明已经声明funA.count = 0怎么会没有加到呢?这就是因为funA是被全局环境也就是window呼叫,所以this并不是你预期的funA。
那到底加了谁的count呢?你可以尝试印出window.count会发现是NaN,是因为你赋予window一个count属性且一开始没有给定初始值,
所以会变成undefined+ 1 = NaN。
或许你认为这样就可以解决问题:
function funA(val){
val.count ++;
}
var dart = {
count:0
};
funA(dart);
console.log(dart.count);//1
但这样你只是在逃避this这个问题而已!!
要透过this解决方案有两种,一个是等下提到的作为物件的方法;一个是明天会说的call及apply。
作为方法呼叫
函式可以透过写在物件里面去呼叫,这个呼叫方式称作作为方法(method),相信大家都知道,但你知道在这时候的this是什么吗?
var obj = {
funA:function(){
console.log(this);
console.log(this===obj);
}
}
obj.funA();
//{funA:ƒ}
//true
可以看到这时候的this是obj物件,也是是说我们是透过obj去呼叫的。
但是要注意一个小地方:
function funA(){
console.log(this);
console.log(this===obj);
}
var obj = {
a:funA
}
funA();
//Window
//false
虽然你认为我已经让obj参照funA了,但是当你直接执行funA时,还是由全局环境去呼叫,这也呼应了我们开头所说的「我们无法在一开始定义它,只有函式呼叫时候才能确定」。
我们可以利用作为方法呼叫来解决作为函式呼叫的问题:
function funA(){
this.count ++;
}
var obj = {
count:0,
sum:funA
};
obj.sum();
console.log(obj.count);//1
作为建构式呼叫
建构式的函式声明就跟任何函式一样,也可以用声明和表达来建立新物件。
要作为建构式函式来呼叫函式,必须要在函式呼叫前加上new:
function myConstructor(){
this.count = 0;
this.sum = function(){
return this.count ++
}
}
var a = new myConstructor();
a.sum();
console.log(a.count);
也许有人会觉得,这跟作为方法呼叫很像,那用物件去写就好何必这么麻烦还要学建构式,用奇怪的new去呼叫函式。
这边就来说明一下,使用new呼叫函式时,会发生什么事:
建立一个新物件。
此物件被当成this参数传递给建构式,因此成为建构式的函式背景空间(swrebar)。
回传新建立的物件。
如果我们今天需要两个相同的物件,如果用作为物件方法呼叫的话就必须建立两个不同的物件,否则会参照到同样的物件并修改。
但是建构式就不需要,因为每一个都是一个新的物件:
function myConstructor(){
this.count = 0;
this.sum = function(){
return this.count ++
}
}
var a = new myConstructor();
var b = new myConstructor();
a.sum();
console.log(b.count);//0
以上就是this的基本三种呼叫方式,若有错误及参考资料未附上劳请留言。
明天我们会介绍this的稍微进阶应用call及apply。
参考资料:
忍者JavaScript开发技巧探秘
你所不知道的JS - this
彻底理解js中this的指向,不必硬背。