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的理解
附参考链接:
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);
。
call
,而不确定的时候,用 apply
,然后把参数push
进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments
这个数组来便利所有的参数。 注: 另外,当apply
的参数为空时,this
是指向window
的。