前言:
this指向
问题一直是js中最容易犯的错误之一。
今天就写下这篇博文,谈一下我对this的理解。
若是你们以为有帮助,请点个赞
或关注
我吧。
若是有不对的地方,欢迎你们指正!面试
先来看个思惟导图吧: 数组
1、ES5中funciton的this指向:bash
function Person() {
console.log(this, '1') //Person
this.say = function (){
console.log( this, '2'); //Person
}
}
// 在构造函数中,this指向的是new出来的实例,因此两处this都指向Person
var per = new Person()
per.say()
复制代码
2. 由于构造函数自己是没法访问其自身的值,实例化对象能够。 这里为了比较,作了如下的写法:微信
function Person() {
console.log(this, '1') //Window
this.say = function (){
console.log( this, '2'); //Window
this.eat = function () {
console.log(this, '3'); //Window
}
eat()
}
say()
}
Person()
复制代码
解析:用函数名()
调用时,不管嵌套多少层,this默认指向的也是window。闭包
3. 在对象中建立的函数this指向是:this 永远指向最后调用它的那个对象!this 永远指向最后调用它的那个对象!this 永远指向最后调用它的那个对象!
(重要的话说3次)牢记这条就不会出错。app
//eg1:
var a = 2
var obj = {
a: 1,
b: function() {
console.log(this.a) //1 这里是obj调用的,因此this指向obj
}
}
obj.b()
复制代码
假如咱们假如了setTimeout呢,状况会是什么样的呢?函数
//eg2:
var a = 2
var obj = {
a: 1,
b: function() {
window.setTimeout(function() {
console.log(this.a) //2
})
console.log(this.a) //1
}
}
obj.b()
复制代码
解析:setTimeout的执行环境是Window
,因此会把this指向改变到Window上。ui
4. 那假如在对象中嵌套多层呢?状况会是怎么样的呢?this
const obj = {
a: function() { console.log(this) },
b: {
c: function() {console.log(this)}
}
}
obj.a() // obj, obj调用的a()方法
obj.b.c() //obj.b, obj.b调用的a()方法
复制代码
解析:仍是那句话:this 永远指向最后调用它的那个对象!
,这下记住了吧。spa
5. 还有一个状况就是闭包中的this指向,这里也讲解一下。 (面试的时候可能会出这种变形题。)
//eg1:
var name = '张'
function Person() {
this.name = '柳';
let say = function (){
console.log( this.name + ' do Something');//张 do Something
}
say()
}
var per = new Person()
复制代码
咱们能够把这道题换种写法:
//eg2:
var name = '张'
function Person() {
this.name = '柳';
return function (){ //本质都是匿名函数的自执行
console.log( this.name + ' do Something');//张 do Something
}
}
var per = new Person()
per()
复制代码
解析:看到这就明白了,其实这是一道闭包题。闭包函数具备匿名函数自执行的特性,默认this指向是挂在Window下的。
2、 ES6箭头函数中的this
《深刻浅出ES6》(65页)中关于箭头函数this的解释:
箭头函数中没有this绑定,必须经过查找做用域链来决定其值。
若是箭头函数被非箭头函数包围,那么this绑定的是最近一层非箭头函数的this;
不然,this的值会被设置为undefined。
复制代码
个人理解:
若是箭头函数被非箭头函数包围,那么this绑定的是最近一层非箭头函数的this
,我理解的这句话是说,若是箭头函数的父级是function,那么箭头函数的this指向会与funciton中的this指向保持一致。
若是上面的听不太明白,那么能够参考你们的理解方式:为箭头函数的this是在定义的时候绑定的。那么问题来了:
1.何为定义时绑定?
//eg1:
var x=11;
var obj={
x:22,
say:function(){
console.log(this.x)
}
}
obj.say();
//console.log输出的是2
复制代码
解析:通常的定义函数跟咱们的理解是同样的,运行的时候决定this的指向,咱们能够知道当运行obj.say()时候,this指向的是obj这个对象。
//eg2:
var x=11;
var obj={
x:22,
say:()=>{
console.log(this.x);
}
}
obj.say();
//输出的值为11
复制代码
解析:
这样就很是奇怪了若是按照以前function定义应该输出的是22,而此时输出了11,那么如何解释ES6中箭头函数中的this是定义时的绑定呢?
所谓的定义时候绑定,this绑定的是最近一层非箭头函数的this;由于箭头函数是在obj中运行的,obj的执行环境就是window,所以这里的this.x实际上表示的是window.x,所以输出的是11。
2. 理解了对象中的this定义后,还有几点要提一下:
对象中箭头函数的this指向的是window。且没法改变其指向。
缘由:函数的this能够用call方法来手动指定,是为了减小this的复杂性,箭头函数没法用call等方法来指定this。
//eg3:
var a = 2
const obj = {
a: 1,
b: () => {
console.log(this.a)
}
}
obj.b()//2 默认绑定外层this
obj.b.call(obj.a)//2 不能用call方法修改里面的this
复制代码
//eg4:
const obj = {
a: function() {
console.log(this)
window.setTimeout(() => {
console.log(this)
}, 100)
}
}
obj.a() //第一个this是obj对象,第二个this仍是obj对象
复制代码
解析:函数obj.a没有使用箭头函数,由于它的this仍是obj;
而setTimeout里的函数使用了箭头函数,因此它会和外层的this保持一致,也是obj;
若是setTimeout里的函数没有使用箭头函数,那么它打印出来的应该是window对象。
const obj = {
a: function() { console.log(this) },
b: {
c: () => {console.log(this)}
}
}
obj.a() //没有使用箭头函数打出的是obj
obj.b.c() //打出的是window对象!!
复制代码
解析:obj.a调用后打出来的是obj对象,而obj.b.c调用后打出的是window对象而非obj, 这表示多层对象嵌套里箭头函数里this是和最最外层保持一致的。
3、改变this指向的办法
//eg1:
const obj = {
log: function() {
console.log(this)
}
}
//1.不用变量接收:this默认指向为obj
obj.log() //obj
obj.log.call(window) //window call和apply都会返回一个新函数
obj.log.apply(window) //window
obj.log.bind(window)() //window bind则是返回改变了上下文后的一个函数,要想执行的话,还须要加个括号调用。
//2.用变量接收:用变量接收的话,this的默认指向就变成全局了
var objName = obj.log
objName() //王
// call、apply、bind的用法还和上面的同样,这里就不重复了。
复制代码
eg2:
var _this = this
const obj = {
log: function() {
console.log(_this)
}
}
obj.log()//此时this的当前指向再也不是obj,而是window了。
复制代码
小结: 3种改变this指向方法的区别
一、call和apply改变了函数的this上下文后便执行该函数,而bind则是返回改变了上下文后的一个函数。
二、call、apply的区别: 他们俩之间的差异在于参数的区别,
call和aplly的第一个参数都是要改变上下文的对象,而call从第二个参数开始以参数列表的形式展示,
apply则是把除了改变上下文对象的参数放在一个数组里面做为它的第二个参数
复制代码
let arr1 = [1, 2, 19, 6];
//例子:求数组中的最值
console.log(Math.max.call(null, 1,2,19,6)); // 19
console.log(Math.max.call(null, arr1)); // NaN
console.log(Math.max.apply(null, arr1)); // 19 直接能够用arr1传递进去
复制代码
合并数组:
var arr1=[1,2,3];
var arr2=[4,5,6];
arr1.push.apply(arr1,arr2);
alert(arr1)//1,2,3,4,5,6
alert(arr2)//4,5,6
复制代码
解析:同理,apply将数组装换为参数列表的集合。
结尾: 以上就是对js中的this指向,和call()、apply()方法一些须要知道的小技巧。
若是以为对你有帮助,请给做者一点小小的鼓励,点个赞或者收藏
吧。
有须要沟通的请联系我:微信( wx9456d ) 邮箱( allan_liu986@163.com )