对于JS的初学者而言,JS当中的this指向很难让人摸准其脉络,经常会给你一种模糊美、朦胧美的感脚!因为this并不是固定不变的,它会根据自身所执行的环境的不同而不同。而且在开发的过程中,经常因为对this的不了解出现这样或那样的错误!所以搞定this的指向是非常非常有必要的!
与其它语言当中的this不同的是,我们JS当中的this总是指向一个对象。而具体是指向哪一个对象,则要看其运行时是基于哪一个函数的执行环境所动态绑定的。
注意:this的指向并不是函数被声明时的环境。
具体到实际开发中,this的指向大致可以分为以下几种:
1、作为普通函数调用
当你的函数不是作为对象的属性来调用时,即是我们经常说的普通函数调用。此时的this为全局对象,而JS当中的全局对象指的是window。 作为普通对象调用:
代码语言:javascript复制//定义一个全局变量age
var age=18;
//声明一个全局函数getAge
function getAge(){
return this.age;
}
//因为是全局环境内调用的getAget函数所以指向的对象为window
console.log(getAge());//18
//你也可以这样写
console.log(window.getAge());//18
以上代码中,getAge方法在全局window下调用,所以getAge方法内的this指向的是window。为了更好的验证这一点,咱们再来对以上代码修改如下:
代码语言:javascript复制//声明一个全局函数getAge
function getAge(){
//由于该函数在全局环境(window)下调用,所以this为window
this.age=81;//为this指向的window对象添加属性age
}
getAge();//全局调用函数getAge()
console.log(age);//81
//也可以这样输出
console.log(window.age);//81
以上代码中声明了一个全局函数getAge。由于该函数在全局环境(window)下调用,所以this为window。然后通过this.age为window对象增加一个age属性。所以在调用完该函数后进行console.log(window.age)输出的结果为81。
2、函数作为对象的属性来调用:
如果函数作为对象的属性来调用,函数内的this为调用函数的对象。
代码语言:javascript复制var obj={
//obj属性age
age:12,
//obj方法getAge
getAge:function(){
return this.age;
}
}
//全局属性age
var age=13;
//全局方法getAge
function getAge(){
return this.age;
}
//在obj对象下调用getAge(),this代表的是obj
console.log(obj.getAge());//12
在全局环境下,this代表的是window。所以调取的方法为全局方法getAge。又因为getAge是在window下调用的,所以内部this指向的是window对象。最终输出结果为13
代码语言:javascript复制var obj={
//obj属性age
age:12,
//obj方法getAge
getAge:function(){
return this.age;
}
}
//全局属性age
var age=13;
//全局方法getAge
function getAge(){
return this.age;
}
//在全局环境下,this代表window,所以下面可以理解为window对象下调用全局getAge
console.log(this.getAge());//13
接下来看种丢失掉this的情况,换言之,this的指向发生改变。我们先来看下面的代码
代码语言:javascript复制var obj={
//obj属性age
age:12,
//obj方法getAge
getAge:function(){
return this.age;
}
}
//全局属性age
var age=13;
//全局方法getAge
function getAge(){
return this.age;
}
//在obj对象下调用getAge(),this代表的是obj
console.log(obj.getAge());//12
//将obj下的函数getAge赋值给fn。
var fn=obj.getAge;
//在全局环境(window) 下调用fn,this代表的是window
console.log(fn());//13
当调用obj.getAge时,getAge方法是作为obj对象的属性来调用的。输出结果为12。当将obj.getAge赋值给一个变量fn时,因为fn的调用是在全局环境下调用的,所以this指向的是window,输出结果为13。 将代码汇总如下,认真看看:
代码语言:javascript复制var obj={
//obj属性age
age:12,
//obj方法getAge
getAge:function(){
return this.age;
}
}
//全局属性age
var age=13;
//全局方法getAge
function getAge(){
return this.age;
}
//在obj对象下调用getAge(),this代表的是obj
console.log(obj.getAge());//12
//在全局环境下,this代表window,所以下面可以理解为window对象下调用全局getAge
console.log(this.getAge());//13
//将obj下的函数getAge赋值给fn。
var fn=obj.getAge;
//在全局环境(window) 下调用fn,this代表的是window
console.log(fn());//13
3、DOM对象的事件函数
DOM对象的事件函数内的this指向的是该DOM对象,看以下代码:
代码语言:javascript复制<body>
<div id="myDiv">点我吧!</div>
</body>
<script>
//为id为"myDiv"增加点击事件
document.getElementById("myDiv").onclick=function(){
//this为div
console.log(this.id);//myDiv
}
</script>
在事件函数内添加一个子函数_fn,该子函数内的this指向的是window:
代码语言:javascript复制<body>
<div id="myDiv">点我吧!</div>
</body>
<script>
var id="window";
document.getElementById("myDiv").onclick=function(){
function _fn(){
console.log(this.id);//window
}
_fn();
}
</script>
但往往我们需要的是让它指向触发事件的DOM对象,此时有一种解决方法可以作为参考:
代码语言:javascript复制<body>
<div id="myDiv">点我吧!</div>
</body>
<script>
var id="window";
document.getElementById("myDiv").onclick=function(){
var _this=this;//保存对myDiv的引用
function _fn(){
console.log(_this.id);//myDiv
}
_fn();
}
</script>
4、构造函数
在JS当中并没有类的概念,但是我们可以通过构造函数来创建对象,而且JS也提供了new操作符,使构造函数看起来更像是一个类! 构造函数与普通函数的异同:构造函数与普通函数的个表是一样的,它们的区别在于调取的方式。当用new操作符调用函数时,该函数为构造函数,否则为普通函数。
代码语言:javascript复制function Box(){
this.age=14;
}
var obj=new Box();
console.log(obj.age);//14
通过new来调用构造函数时的执行流程如下:
- new 构造函数(),隐式执行了new Object();
- 将构造函数的作用域给新对象(即new Object()创建出的对象),函数体内的this就代表这个新对象。
- 执行构造函数的语句。
- 隐式直接返回新对象。 需要注意的是构造函数如果直接返回一个对象,那么执行返回的对象就不是我们所期待的this:
function Box(){
this.age=14;
return {
age:16
}
}
var obj=new Box();
console.log(obj.age);//16
5、通过call与apply改变this的指向
通过call与apply可以动态的改变函数内的this
代码语言:javascript复制//声明一个全局变量color
var color="red";
//声明一个全局对象obj,为 obj添加一个属性color值为yellow
var obj= {
color: "yellow"
}
//添加一个构造函数
function Fn(){
this.color="blue";
}
//普通函数
function getColor(){
console.log(this.color);
}
getColor();//red
getColor.call(window);//red
getColor.call(this);//red
getColor.call(obj);//yellow
getColor.call(new Fn());//blue
以上代码通过call来改变函数体内this的指向,以上代码用apply也是可以实现相同的功能。只需要将call改变apply即可:
代码语言:javascript复制var color="red";
var obj= {
color: "yellow"
}
function Fn(){
this.color="blue";
}
function getColor(){
console.log(this.color);
}
getColor();//red
getColor.apply(window);//red
getColor.apply(this);//red
getColor.apply(obj);//yellow
getColor.apply(new Fn());//blue
call与apply的用法是一样,区别仅在于传入的参数形式不同。
代码语言:javascript复制function fn(num1,num2){
console.log(num1 num2 num);
}
var num=5;
var obj={
num:8
}
fn.call(this,1,2);//8
fn.call(obj,1,2);//8
//apply 传递的参数需要用中括号进行包裹
fn.apply(this,[3,4]);//12
fn.apply(obj,[3,4]);//12
6、通过bind指定函数内部的this
代码语言:javascript复制var age=81;
var obj={
age:18
}
//指定fn函数体内的this指向window
var fn=function(){
console.log(this.age);
}.bind(this);
//指定fn2函数体内的this指向obj
var fn2=function(){
console.log(this.age);
}.bind(obj);
fn();//81
fn2();//18
好了,今天就先到这里吧!