this的指向
关于this的指向,除去原型链以及call、apply、bind这些我还没学懂的之外,主要有以下几点:
1. 全局环境下
2. 函数内
3. 对象内(方法内)
4. 箭头函数
5. 构造函数
一、全局环境下的this指向
在全局作用域下,this始终指向全局对象window
console.log(this); //window
//相当于:
window.console.log(this); //这是window下的console方法
console.log()的完整写法是window.console.log(),window可以被省略所以在这里this是指向了window
二、函数内的this指向
普通函数内的this分为两种情况,严格模式下和非严格模式下
1. 严格模式 — ‘use strict’
对代码的的调用必须严格的写出被调用的函数的对象,不可以有省略或者说简写。
function test(){
'use strict'
console.log(this);
}
test(); //undefined
window.test(); //window
this不知道指向谁,所以打印undefined
虽在严格模式,但window调用test函数,所以指向window
2. 正常模式
function test(){
console.log(this);
}
test();
window.test();
在正常模式中,直接调用test()和window.test()性质一样,所以this都指向window
三、对象中(方法中)的this指向
对象内部方法的this指向调用这些方法的对象,就是谁调用就指向谁(有点暴躁哈∩_∩ ),在这里分为两种情况:
1. 单层对象:
var obj = {
name : '张三',
skillone : function(){
name : "李四",
console.log(this.name);
}
}
obj.skillone(); //张三
此时this指向obj,因为skill是被obj调用的。
2. 多层对象(对象里还有对象)
var obj = {
name : '张三',
skillone : function(){
name : "李四",
console.log(this.name);
},
xobj : {
name : "王五",
skilltwo : function(){
name : "张六",
console.log(this.name);
}
}
}
obj.skillone(); //张三
obj.xobj.skilltwo(); //王五
此时因为在调用skilltwo()时的顺序为obj.xobj.skilltwo,所以skilltwo是被xobj调用,所以此时this指向xobj
3. 小结一下
a.函数的定义位置不影响其this指向,this指向只和调用函数的对象有关。
b.多层嵌套的对象,内部方法的this指向离被调用函数最近的对象
四、箭头函数中的this
在谈讨this的话题中,箭头函数是个例外,他没有this,是真的没有this!,但是为什么要在这里提他呢,是因为箭头函数比较努力,会自己寻找this并且绑定,他会一级一级的向上寻找,直到寻找到this的指向!换句话说:它会绑定最近的非箭头函数作用域中的this。首先从它的父级作用域找,如果父级作用域还是箭头函数,就再往上找,直到找到。
var show = () => {
console.log(this);
}
var obj = {
show : () => {
console.log(this);
}
}
window.obj.show();
//----------
show(); //window
window.show(); //window
obj.show(); //window
window.obj.show(); //window
1. 在第一个函数中,自身是箭头函数,没有this,所以向上寻找:window.show(),所以绑定在window上
2. 在后面的对象中,obj是对象不是箭头函数,所以他寻找到这里就结束了,但是此时的obj被window调用,所以箭头函数刚刚绑定的this指向了window。
五、构造函数中的this
在构造函数中的this指向实例化的对象
但是,在JS中是没有类的,而构造函数是个函数,this指向的永远是个对象,如果不搞点小动作,this就算踏破天也指不到构造函数里面去。下面我们就来浅谈一下所谓小动作是什么。
1. 构造函数在写法上首字母大写(区分普通函数,没人定义,只是约定俗成而已)
2. 构造函数被调用时必须用new,这也是区分普通函数的根本区别,那么new创建对象时都干了些什么?
一、 创建一个Object对象实例;
二、 将构造函数的执行对象赋给新生成的对象的这个实例;
三、执行构造函数中的代码;
四、返回新生成的对象实例;
function Gzfun(a,b,c){
this.name = a;
this.age = b;
this.sex = c;
}
var ren = new Gzfun('zhangsan',18,'nan')
console.log(ren); //Gzfun {name: 'zhangsan', age: 18, sex: 'nan'}
console.log(ren.name); //zhangsan
console.log(ren.a); //undefined
用new的ren调用GZfun中的name可以得到传入的nama:zhangsan,可以得出构造函数中的this指向构造函数下创建的实例。
function GZfun(){
this.name = 'wangshi';
var age = 22;
window.age = 22;
}
var ren = new GZfun();
console.log(ren.name); //Tiny Colder;
console.log(ren.age); //undefined;
console.log(window.age); //22;
小结:在构造函数中,this指向new操作符实例化出来的对象
六、几种容易出错的this指向:
1.定时器:
定时器里的函数是回调函数,所有的回调函数中的this都是指向window,因为this指向引用正在调用当前方法的"."前的对象。当没有明确的执行时的当前对象时,this指向全局对象window。
setTimeout(function(){
console.log(this) //Window
},5000)
2.自调用函数(立即执行的函数)
说白了还是普通函数,在前面提到的严格模式中是undefined;非严格模式指向window
//严格模式
(function(){
'use strict'
console.log(this) //undefined
})();
//非严格模式
(function(){
console.log(this) //window
})();
3.绑定事件方法中的this
// javascript
var anniu = document.querySelector('button');
btn.onclick = function() {
console.log(this) //指向<button>按钮</button>这个元素
}
总结:
1. 全局环境下的this
- 在全局作用域下,this始终指向全局对象window
2. 普通函数中的this
- 在非严格模式中,this指向window;
- 在严格模式中,this指向undefined;
3.对象中(方法中)的this
- 对象内部方法的this指向调用这些方法的对象
- 函数的定义位置不影响其this指向,this指向只和调用函数的对象有关。
- 多层嵌套的对象,内部方法的this指向离被调用函数最近的对象
- 总之就是所调用,指向谁
4.箭头函数中的this
- 箭头函数没有this
- 他的this是绑定最近的非箭头函数作用域中的this
- 构造函数中箭头函数的作用域是这个构造函数,所以this指向的是这个构造函数实例出来的新的对象
5.构造函数中的this
- 构造函数中的this指向构造函数下创建的实例。