微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

JavaScript中的this使用详解

其实this是一个老生常谈的问题了。关于this的文章非常多,其实我本以为自己早弄明白了它,不过昨天在做项目的过程中,还是出现了一丝疑惑,想到大概之前在JavaScript weekly里收藏待看的一篇详解this的文章(后有链接,也附上了稀土上的中文译文)和另一篇一位前辈推荐的文章,就把它们看了看,对this的认识确实提升了一些。

JavaScript 中的'this‘是动态的,它在函数运行时被确定而非在函数声明时被确定。所有的函数都可以调用'this',这无关于该函数是否属于某个对象。关于this,主要有以下四种情况。

1.被当做对象的方法调用

如果该函数是被当做某一个对象的方法,那么该函数的this指向该对象;

rush:js;"> var john = { firstName: "John" } function func() { alert(this.firstName + ": hi!") } john.sayHi = func john.sayHi() // this = john

这里有一点值得注意,当一个对象的方法被取出来赋值给一个变量时,该方法变为函数触发,this指向window或underfind(严格模式)。

2.函数之内调用

函数中有 this,其实就意味着它被当做方法调用,之间调用相当于把他当做window对象的方法,this指向window,值得注意的是ES5其实是规定这种情况this=undefined的,只浏览器大多还是按照老的方法执行(本人在最新版的Chrome,Safari,Firefox中测试都指向window(201607)),在火狐下使用严格模式指向undefined;

rush:js;"> func() function func() { alert(this) // [object Window] or [object global] or kind of.. }

为了传递this,()之前应该为引用类型,类似于obj.a 或者 obj['a'],不能是别的了。

这里还存在一个小坑,当对象的方法中还存在函数时,该函数其实是当做函数模式触发,所以其this认为window(严格模式下为undefined)解决办法是给该函数绑定this。

true function calculate() { // this is window or undefined in strict mode console.log(this === numbers); // => false return this.numberA + this.numberB; } return calculate(); } }; numbers.sum(); // => NaN or throws TypeError in strict mode var numbers = { numberA: 5,sum: function() { console.log(this === numbers); // => true function calculate() { console.log(this === numbers); // => true return this.numberA + this.numberB; } // use .call() method to modify the context return calculate.call(this); } }; numbers.sum(); // => 15

3.在new中调用

一个引用对象的变量实际上保存了对该对象的引用,也就是说变量实际保存的是对真实数据的一个指针。 使用new关键字时this的改变其实有以下几步:

创建 this = {}. new执行的过程中可能改变this,然后添加属性方法; 返回被改变的this.

rush:js;"> function Animal(name) { this.name = name this.canWalk = true } var animal = new Animal("beastie") alert(animal.name)

需要注意的是如果构造函数返回一个对象,那么this指向返回的那个对象;

rush:js;"> function Animal() { this.name = 'Mousie'; this.age = '18'; return { name: 'Godzilla' } // <-- will be returned }

var animal = new Animal()
console.log(animal.name) // Godzilla
console.log(animal.age)//undefined

这里需要注意的是不要忘记使用new,否则不会创建一个新的函数。而是只是执行了函数,相当于函数调用,this其实指向window

'Car' car.wheelsCount // => 4 car === window // => true

4.明确调用this,使用call和apply

这是最具JavaScript特色的地方。 如下代码

func.call(obj,arg1,arg2,...)

一个参数将作为this的指代对象,之后的参数将被作为函数的参数,解决方法是使用bind。

true console.log('The ' + this.type + ' has ' + this.legs + ' legs'); }; } var myCat = new Animal('Cat',4); // logs "The Cat has 4 legs" setTimeout(myCat.logInfo.bind(myCat),1000); // setTimeout?? var john = { firstName: "John",surname: "Smith" } function func(a,b) { alert( this[a] + ' ' + this[b] ) } func.call(john,'firstName','surname') // "John Smith"

至于apply,其只是以数组的方传入参数,其它部分是一样的,如下:

rush:js;"> func.call(john,'surname') func.apply(john,['firstName','surname'])

它们也可用于在 ES5 中的类继承中,调用父级构造器。

true this.name = name; } function Rabbit(name,countLegs) { console.log(this instanceof Rabbit); // => true // 间接调用调用了父级构造器 Runner.call(this,name); this.countLegs = countLegs; } var myRabbit = new Rabbit('White Rabbit',4); myRabbit; // { name: 'White Rabbit',countLegs: 4 }

5..bind()

对比方法 .apply() 和 .call(),它俩都立即执行了函数,而 .bind() 函数返回了一个方法,绑定了预先指定好的 this ,并可以延后调用

.bind() 方法的作用是创建一个新的函数,执行时的上下文环境为 .bind() 传递的第一个参数,它允许创建预先设置好 this 的函数

[3,10] // Extract method from object var simpleGetNumbers = numbers.getNumbers; simpleGetNumbers(); // => undefined or throws an error in strict mode

使用.bind()时应该注意,.bind() 创建了一个永恒的上下文链并不可修改一个绑定函数即使使用 .call() 或者 .apply()传入其他不同的上下文环境,也不会更改它之前连接的上下文环境,重新绑定也不会起任何作用。

只有在构造器调用时,绑定函数可以改变上下文,然而这并不是特别推荐的做法。

6.箭头函数

箭头函数并不创建它自身执行的上下文,使得 this 取决于它在定义时的外部函数

箭头函数一次绑定上下文后便不可更改,即使使用了上下文更改的方法

{ console.log(this === numbers); // => true return this; }; console.log(this === numbers); // => true get(); // => [1,2] // 箭头函数使用 .apply() 和 .call() get.call([0]); // => [1,2] get.apply([0]); // => [1,2] // Bind get.bind([0])(); // => [1,2] }).call(numbers);

这是因为箭头函数拥有静态的上下文环境,不会因为不同的调用而改变。因此不要使用箭头函数定义方法

{ console.log(this === window); // => true return this.hours + ' hours and ' + this.minutes + ' minutes'; }; var walkPeriod = new Period(2,30); walkPeriod.format(); // => 'undefined hours and undefined minutes'

参考

强烈推荐觉得没弄明白的同学看看上面三篇文章,其中第三篇是第二篇的译文。如果大家对this还有疑问,也欢迎大家一起讨论,交流促进思考,共同进步。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是深拷贝与浅拷贝?深拷贝与浅拷贝是js中处理对象或数据复制操作的两种方式。‌在聊深浅拷贝之前咱得了解一下js中的两种数据类型:
前言 今天复习了一些前端算法题,写到一两道比较有意思的题:重建二叉树、反向输出链表每个节点 题目 重建二叉树: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 {1,2,4,7,3,5,6,8} 和中序遍历序列 {
最近在看回JavaScript的面试题,this 指向问题是入坑前端必须了解的知识点,现在迎来了ES6+的时代,因为箭头函数的出现,所以感觉有必要对 this 问题梳理一下,所以刚好总结一下JavaScript中this指向的问题。
js如何实现弹出form提交表单?(图文+视频)
js怎么获取复选框选中的值
js如何实现倒计时跳转页面
如何用js控制图片放大缩小
JS怎么获取当前时间戳
JS如何判断对象是否为数组
JS怎么获取图片当前宽高