JS 的 this 指向题目是陈词滥调的难点了。我当初从 Java 转过来时极为不适应,花了好长时间才挣脱这个暗影。网上也有许多关于 this 的文章了,本文就简朴说说,再聊点不一样的。
this 主如果在函数中运用,在函数外运用的话,一概指向全局对象
console.log(this) // window
var o = {
global: this // window
}
在函数内运用 this 时,细致指向是由函数的挪用体式格局决议,而不是依据函数定义体式格局决议
1. 函数作为一般函数运转时,能够看作是当作全局对象的要领运转,此时 this 指向全局对象
function hello() {
console.log(this)
}
hello() // window 作为一般函数运转
2. 函数作为对象的要领挪用时,函数内的 this 指向该对象
所以上面一条,一般函数能够看作是全局对象的要领,所以 this 指向全局对象
var name = 'global'
var obj = {
name: 'local',
getName: function () {
console.log(this.name)
},
outer: function () {
function inner() {
console.log(this.name)
}
inner() // 这是第 12 行代码
}
}
obj.getName() // local 作为 obj 的要领挪用,此时 this 指向 obj
obj.outer() // 打印什么?控制台尝尝吧
这里提到了一个人人轻易无视的点: 嵌套函数
还记得上面题目说的吗? this 的指向是由函数的挪用体式格局来决议的
由于大多数嵌套函数是直接被挪用的, 比方:第 12 行代码,挪用 inner()这时刻 inner 是被当作一般函数挪用的
,也能够看作是 window.inner() ,所以此时 inner 内部的 this 指向 window,打印 global
罕见的解决方案以下:
var obj = {
name: 'local',
outer: function () {
var that = this
function inner() {
console.log(that.name)
}
inner()
}
}
// 声明变量 that ,在 inner 内部用 that 替代 this
obj.outer() // local
另有个题目
var name = 'global'
var obj = {
name: 'local',
getName: function () {
console.log(this.name)
}
}
obj.getName() // local
var getName = obj.getName
getName() // ?
直接挪用 getName() 会打印 global
照样前面说的,虽然 obj.getName() 在声明的时刻是作为 obj 的要领
然则把它赋值给 getName, 再挪用 getName() 和 obj.getName() 的挪用体式格局已差别了
3. apply call bind 转变 this 指向
这个没啥还说的,强迫转变 this 的指向,bind 的优先级最高。
var name = 'global'
var obj = {
name: 'local',
getName: function () {
console.log(this.name)
}
}
var obj2 = {
name: 'xiaoming'
}
var obj3 = {
name: 'laowang'
}
obj.getName() // local
obj.getName.call(obj2) // xiaoming
var getName = obj.getName.bind(obj3) // 将 getName 内部的 this 绑定到 obj3
getName() // laowang 不再是 window
getName.call(obj2) // laowang
// bind 不会遭到 apply 和 call 影响
4. 定时器设置的函数,this 会指向全局
var name = 'global'
var obj = {
name: 'local',
getName: function () {
console.log(this.name)
}
}
var obj3 = {
name: 'laowang'
}
setTimeout(obj.getName, 1000) // global
setTimeout(obj.getName.bind(obj3), 2000) // laowang
bind 强迫绑定优先级最高,不受定时器影响
准确挪用体式格局以下:
外面包一层匿名函数
setTimeout(function () {
obj.getName()
}, 1000) // local
5. ES6 箭头函数
ES6 推出了箭头函数,细致教程能够参考阮一峰先生的教程箭头函数没有本身的 this 和 arguments
, 因此在箭头函数内部运用 this 和 argments, 实在运用的是外层的 this 和 arguments
var name = 'global'
var obj = {
name: 'local',
getName: () => console.log(this.name),
outer: function () {
var inner = () => console.log(this.name)
inner()
}
}
obj.getName() // global 由于箭头函数没有本身的 this,所以 getName 内部的 this 实际上是函数外部的 this,指向全局
obj.outer() // local
作为函数的要领,最好不要用箭头函数,由于箭头函数内部的 this 不再指向该对象。
所以箭头函数虽然好用,然则不要滥用哦
箭头函数还常用于数组的 forEach/map/some/every/filter/reduce 等轮回要领中,比方
var arr = [1, 2, 3].map(item => item * 2)