javascript中的this指向是在函数调用时确定的。
(1)、this指向全局对象window的情况
1、全局作用域中或普通函数中
//全局作用域
console.log(this); //非严格模式window,严格模式undefined
//普通函数
function bar(){
console.log(this); //非严格模式window,严格模式undefined
}
bar(); //相当于bar.call(window)
2、 匿名函数和自执行函数
匿名函数的执行环境具有全局性,因此其this对象指向window,闭包中this指向window,可以将全局变量常驻内存。(javascript高级程序设计第2版148页)
//自执行函数
(function(){
console.log(this); //window
})();
var name = "the window";
var object = {
name:"My Object",
getNameFunc:function(){
return function(){ //这里形成一个闭包
return this.name; //this指向window
}
}
};
console.log(object.getNameFunc()()); //输出the window
3、嵌套函数和回调函数中
和变量不同,关键字this没有作用域的限制,嵌套的函数不会从调用它的函数中继承this;如果嵌套函数作为方法调用,其this的值指向调用它的对象;如果嵌套函数作为函数调用,其this值是全局对象(非严格模式)或undefined(严格模式下)。调用嵌套函数时this并不是指向调用外层函数的上下文。(javascript权威指南第6版171页)
var o={
m:function(){
var self=this; //将this保存到变量self中
console.log(this); //this指向调用它的对象o
f();
function f(){ //定义一个嵌套函数f
console.log(this); //非严格模式下,this指向window
console.log(self); //self保存的是外层函数的this
}
}
};
o.m();
(2)、函数作为对象的方法调用,this指向那个对象
var obj = {
name:"123",
getName:function(){
console.log(this);//this指向obj
console.log(this.name); //输出123
}
};
obj.getName(); //相当于obj.getName.call(obj)
(3)、构造函数调用
1、若构造函数无return或return 一个原始值或null(即数字、字符串、布尔、undefined、null),this指向new出来的那个对象,返回值类型,有原型方法;
//无返回值的构造函数
function Super1(a){
this.a = a;
//return 123; //返回原始值或null有同样的效果
}
//定义两个原型方法
Super1.prototype.sayHello=function(){
console.log("Hello");
};
Super1.prototype.age = 18;
var newsup1 = new Super1(1);//实例化对象
console.log(newsup1); // Super1 { a=1, age=18, sayHello=function()}
console.log(newsup1.a); //1
console.log(newsup1.age); //18
newsup1.sayHello(); //Hello
2、若构造函数return 一个引用类型(即数组、函数、对象),this指向返回的那个引用类型,返回引用类型,没有原型方法;
//返回值为引用类型的构造函数
function Super2(a){
this.a = a;
return {a:2}; //返回原始值或null有同样的效果
}
//定义两个原型方法,在这里没有用
Super2.prototype.sayHello=function(){
console.log("Hello");
};
Super2.prototype.age = 18;
var newsup2 = new Super2(1);//实例化对象
console.log(newsup2); // Object { a=2}
console.log(newsup2.a); //2
console.log(newsup2.age); //undefined
newsup2.sayHello(); //出错,TypeError: newsup2.sayHello is not a function
(4)、事件中this指向
W3C事件处理程序中,this指向触发这个事件的对象;但IE中,attachEvent中的this总是指向全局对象window,这是两者的主要区别。
(5)、综合应用
第一个例子
var o={
a:10,
b:{
a:12,
fn:function(){
console.log(this);
console.log(this.a);
}
}
};
//(1)
o.b.fn(); //输出b和12
//(2)
var j=o.b.fn;
j(); //输出window和undefined
//(3)
var j=o.b;
j.fn(); //输出b和12
上例中(1)相当于o.b.fn.call(b),this永远指向的是最后调用它的对象,所以this指向b;
上例(2)相当于j.call(window),this指向window;
上例(3)相当于j.fn.call(j),实则j.fn.call(o.b),this指向最后调用它的对象b。
第2个例子
var name = "222";
var a={
name:"111",
say:function(){
console.log(this.name);//这个this指向对象a
return function(){
console.log(this.name);//这个this指向window
};
}
}
var fun = a.say;
fun(); //222,相当于fun.call(window)
a.say();//111,a.say.call(a);
a.say()(); //111,222
var b={
name:"333",
say:function(fun){
fun();//嵌套函数里的this指向window
}
};
b.say(a.say);//222,因为嵌套函数里的this指向window
b.say=a.say;//b.say和a.say指向同一个函数
b.say();//333
(5)关于构造函数的new
new的过程
1、创建一个新对象;
2、将构造函数的作用域赋给新对象,即this指向新对象,同时继承该构造函数的原型;
3、执行构造函数中的代码、属性和方法添加到this指向的新对象中;
4、返回新创建的对象
(6)、ES6中箭头函数的指向
箭头函数没有自己的this,它的this是继承而来的,默认指向是在定义它时所处的对象(宿主对象)而不是执行时的对象,定义它时可能环境是window;
箭头函数可以方便地让我们在setTimeout,setInterval中方便的使用this;
箭头函数中的this是固定的,会绑定定义时所在的作用域,而不是指向运行时所在的作用域;
普通函数和箭头函数比较
普通函数
function foo1(){
var that = this;//将this存放在变量that中
setTimeout(function(){
console.log(this); //回调函数中的this指向window,输出window
console.log(this.b);//undefined
console.log(that);//obj1
console.log(that.b); //2
},1000);
}
var obj1={
b:2
};
foo1.call(obj1);
箭头函数
function foo2(){
var that = this;
setTimeout(()=>{
console.log(this); //obj2,这个this指向函数定义时所在的对象
console.log(this.b); //2
},1000);
}
var obj2={
b:2
};
foo2.call(obj2);
箭头函数的注意事项:
- 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象;
- 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出错误;
- 不可以使用arguments对象,该对象在函数体内不存在,若要用,可以用Rest参数代替;
- 不可以使用yield命令,因此箭头函数不能用作Generator函数。