this关键字的指向
this关键字的理解是在很多前端面试题中出现的题目,实际开发中用到的地方也非常多,这里写一下自己的理解~
在一个方法内部,this是一个特殊变量,它始终指向当前对象。this是动态的,可以改变的。
eg:
var n = {
name: 'abc',
getName: function () {
return this.name;
}
};
n.getName; // function n.getName()
n.getName(); // abc
在上面这段代码中,age function
中的this
指向的就是n
。
换种方法写:
function getName() {
return this.name;
}
var n= {
name: 'abc',
gName: getName
};
n.gName(); // abc, 正常结果
getName(); // NaN
在这段代码中,n.gName()
执行时,getName()
中的this
是指向n
的,但是直接调用getName()
时,this
是指向全局变量window
的。
如果把n.gName()
赋给一个变量,像这样:
var name = n.gName;
name();
这个时候,function getName
中的this
却是指向window
的,这是因为,在JS中,要保证this
指向正确,必须用obj.xxx()
的形式调用。
有的时候,在函数内部又写了一个函数,像这样:
var n= {
name: 'abc',
getName: function () {
function getNewname() {
return this.name;
}
return getNewname();
}
};
n.getName();
这个时候,在getNewname()
中的this,指向的就不是n
了,而是window
。原因是this
指针只在getName
方法的函数内指向n
,在函数内部定义的函数getNewname()
,this
又指向window
了!
怎么解决这个问题呢?
在getName
函数中,用that
变量获取到this
,然后getNewname
函数就可以使用这个that了,就像这样:
var n= {
name: 'abc',
getName: function () {
var that = this; // 在方法内部一开始就捕获this
function getNewname() {
return that.name; // 用that而不是this
}
return getNewname();
}
};
n.getName();
这样,就可以放心地在函数内部使用this了。
另外JS中还有几种调用函数的方式:
- 在标签内用
onclick="show()"
的方式调用show
函数,这时由于是直接调用了show
函数,因此show
函数内部的this是指向window的,而如果是onclick="show(this);"
这样写,就可以改变this的指向了。 - 用
addEventListener
注册的函数,像这样:
name = 'window';
var a = document.getElementsByTagName('body');
a.addEventListener('click',show());
function show(){
alert(this.name);
}
这时在屏幕上点击一下,alert
出来的结果是'window'
,说明this
指的是window
。
- 作为构造方法调用,像这样:
function test(){
this.x = 1;
}
var o = new test();
alert(o.x); // 1
这里this
指对象o
,所谓构造函数,就是通过这个函数生成一个新对象(object)。这时,this
就指这个新对象。
如果再通过test函数
构造出一个对象p
,像这样:
var p = new test();
alert(p.x);
这个时候,this
指的p
。
call、apply的理解
附参考链接:https://www.zhihu.com/question/20289071
call和apply的存在,就是为了改变函数的调用对象,改变某个函数运行时的 context 即上下文,也就是改变this的指向。
二者的作用是一样的,只是传递参数的方式不一样。
call----把参数顺序传递进去,用,
隔开
apply----把参数作为一个数组传递进去
eg:
func.call(this, arg1, arg2,arg3);
func.apply(this, [arg1, arg2,arg3]);
call和apply的应用场景:
在javascript OOP中,我们经常会这样定义:
function cat(){}
cat.prototype={
food:"fish",
say: function(){
alert("I love "+this.food);
}
}
var blackCat = new cat;
blackCat.say();
但是如果我们有一个对象whiteDog = {food:"bone"}
,我们不想对它重新定义say方法
,那么我们可以通过call
或apply
用blackCat
的say
方法:blackCat.say.call(whiteDog);
。
当一个object没有某个方法,但是其他的有,我们可以借助call或apply用其它对象的方法来操作。
另外,当你的参数是明确知道数量时,用 call
,而不确定的时候,用 apply
,然后把参数push
进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments
这个数组来便利所有的参数。
注:
另外,当apply
的参数为空时,this
是指向window
的。