举荐浏览地址
掘金
前言:大家好,我是林一一,这是一篇对于 this 指向的文章。this 是 JS 中一个特地重要的一个知识点,this 难吗?如同挺简略的。看完上面这一篇文章,还不会的话,你别来找我。手动狗头🐕。
思维导图
this 的指向
- 执行函数前有
'.'
点操作符的话,函数体中的this
就指向后面的对象,没有就指向window
,严格模式下指向undefined
。这句话特地的重要,请记住 - 函数没有间接调用者
this
指向全局对象(浏览器中是 window,node 中是 global)。如匿名函数等 - 构造函数的
this
指向实例自身。 - 箭头函数自身没有
this
的,箭头函数的this
指向最近的非箭头函数this
,找不到就指向window
,严格模式下指向undefined
。
再来看一下这句话:执行函数前有
'.'
点操作符的话,函数体中的this
就指向后面的对象,没有就指向window
一、一般函数 this 的热身题
热身题 1
var name = '林一一'
function fn(){
var name = '林二二'
return this.name
}
fn() // 林一一
执行函数
fn()
,后面没有'.'
点操作符吧,那么这里的this
就指向window
。输入的就是全局下的name = '林一一'
。
再来看一下这句话:执行函数前有 '.'
点操作符的话,函数体中的 this
就指向后面的对象,没有就指向 window
热身题 2
var name = '林二二'
var obj = {
name: '林一一',
fn: function () {return this.name}
}
console.log(obj.fn()) // '林一一'
var fo = obj.fn
console.log(fo()) // '林二二' fo() ==> window.fo()
obj.fn()
中函数fn()
后面有'.'
点操作符吧,那么这里的this
就指向obj
这个对象。再看执行函数fo()
,后面没有'.'
点操作符吧,那么这里的this
就指向window
。其实下面的函数fo() ==> window.fo()
,所以执行函数fo()
后面也是能够看作是有'.'
操作符的。
再来看一下这句话:执行函数前有 '.'
点操作符的话,函数体中的 this
就指向后面的对象,没有就指向 window
热身题 3,批改一下热身题 2
var name = '林二二'
var obj = {
name: '林一一',
fn: function () {
var name = '小三'
return function(){return this.name}
}
}
console.log(obj.fn()()) // 林二二
var fo = obj.fn()
console.log(fo()) // 林二二
热身 3 和热身 2 差不多,
obj.fn()()
中obj.fn()
执行完后有一个函数 (这里称为函数A
) 返回,最初相当于执行函数A()
,A()
后面没有'.'
点操作符吧,那么这里的this
就指向window
,输入就是林二二
了。下面的fo()
函数同理。
二、函数没有间接调用者
函数没有间接调用者 this
指向全局对象(浏览器中是 window,node 中是 global)。如匿名函数等
热身题 1
var name = '林一一';
!(function(){console.log(this.name) // 林一一
})()
自执行函数没有间接的调用者输入的
name = '林一一'
。
热身题 2
var name = '林一一'
var obj = {
name : '二二',
callback: function(){console.log(this.name)
}
}
setTimeout(obj.callback,1000)
/* 输入
* 林一一
*/
函数
setTimeout
,obj.callback(这只是一个援用地址)
中并没有间接调用者,this
就指向window
。所以输入的name
就是全局下的林一一
。
三、构造函数中的 this
来读一下这句话:构造函数的 this
指向实例自身
对于构造函数的
this
为什么指向实例是浏览器指定的,详情看new
这个过程产生了什么 面试 | 你不得不懂得 JS 原型和原型链
热身题 1
function Fn(){
var n = 0
this.name = '林一一'
this.age = 18
this.getName = function(){return this.name}
}
Fn.prototype.getAge = function(){return this.age}
Fn.x = '林二二'
var f = new Fn()
console.log(f.name) // 林一一
console.log(f.getName()) // 林一一
console.log(f.getAge()) // 18
console.log(f.n) // undefined
console.log(f.x) // undefined
下面的
Fn
通过new
后就是一个构造函数,this
就指向实例f
。所以下面的 1,2 输入都是林一一
。f.getAge()
是实例f
调用了getAge
输入就是 18,问:实例f
中并没有属性getAge
是怎么输入 18 的,f.x
输入又为什么是undefined
?答:这是原型链的查找机制,属性x
不是在原型prototype
上的就不是实例的属性,能够读一下这篇文章 面试 | 你不得不懂得 JS 原型和原型链;问:为什么f.n
输入的是undefined
。因为变量n
是构造函数的公有变量和new
创立的实例没有关系。
四、箭头函数
- 箭头函数自身没有
this
,箭头函数的this
继承上下文的,外面的this
会指向以后最近的非箭头函数的this
,找不到就是window
(严格模式是 undefined) - 箭头函数的
this
始终指向函数定义时的this
,而非执行时
热身题 1
var name = '林一一'
var obj = {
name: '二二',
a: () => {console.log(this.name)
}
}
obj.a()
/* 输入
* '林一一'
*/
箭头函数的
this
,找不到非箭头函数的this
就间接指向window
。
热身题 2
var name = '林一一'
var obj = {
name: '二二',
fn: function() {return () => {console.log(this.name)
}
}
}
obj.fn()()
/* 输入
* '二二'
*/
很显著箭头函数的
this
来自函数fn
,对象obj
调用了函数fn
,所以fn
的this
指向obj
,输入后果就是二二
。
五、call,apply,bind 扭转 this 的指向
提醒:所有的函数都是基于 Function
这个基类来创立的,同样领有 Function
原型下面的办法
call
,承受this
的对象,和一组列表。apply
和call
一样,惟一不同的是apply
承受的是一个蕴含多个参数的数组。bind
同样也是扭转函数的this
指向,只不过bind
执行后会返回一个新的函数,新函数中参数来源于残余的参数
热身题
var name = '林一一'
var age = 18
function fn(){return this.name}
function p(){
return {
age: this.age,
arg: arguments
}
}
let obj = {
name: '二二',
age: 18
}
let o = {name: '三三'}
fn() // '林一一'
fn.call(obj) // '二二'
fn.call(o) // '三三'
p.call(obj, 12, 23, 45, 67) // {age: 18, arg: Arguments(4)}
fn.apply(obj) // "二二"
p.apply(obj, [1, 2, 3, 4, 5]) // {age: 18, arg: Arguments(5)}
fn.bind(obj)() // "二二"
p.bind(obj, 12, 23, 34)() // {age: 18, arg: Arguments(3)}
以上就是
call
,apply
,bind
, 对于this
的内容,这里不介绍三者的写法,如果介绍能够写另一篇文章了。对这三者不相熟的能够找其余材料看看。
思考题
1. 口试题 this 指向问题
var name = '林一一'
var obj = {
name: '林二二',
show: function (){console.log(this.name)
},
wait: function () {
var fn = this.show
fn()}
}
obj.wait() // 林一一
obj.wait()
中,执行函数wait()
后面有'.'
点操作符吧,那么这里的this
就指向obj
这个对象,所以this.show ==> obj.show
。再看执行函数fn()
后面没有'.'
点操作符吧,那么这里的this
就指向window
,输入就是林一一
。
2. 和闭包无关的 this 指向问题
var n = 2 // -> 4 -> 8
var obj = {
n: 3, // 6
fn: (function(n){
n*=2
this.n+=2 // window 下的 n 变成 4
var n = 5 // 这一步不会再从新申明,因为曾经参数赋值,就不会再申明而是间接赋值 n = 5
console.log("window.n", window.n)
return function (m) {console.log("n:", n, "m", m) // n:5 m:3 这里的 n 向上查找是 5 //
this.n*=2 // fn(3): 2 * 4 =8 // obj.fn(3): 2 * 3 = 6
console.log(m + (++n)) // 3 + (++5) ++n 导致下级作用域的 n 变成了 6 // 3 + (++6)
}
})(n)
}
var fn = obj.fn;
fn(3) // 9
obj.fn(3) // 10
console.log(n, obj.n) // 8 6
/* 输入
* 9
* 10
* 8 6
/
这道题就留给大家思考了,下面有我的剖析步骤,感觉碍眼的话能够去掉 😂。你能够在评论区给出你的剖析过程。
完结
感激浏览早这里,我是林一一,如果这文章能对你有一点启发的话,欢送给个 star, 下次见。