前言
this指向是js中基础中的基础,当然也是大厂面试的时候常考的。下面我这题是阿里前端面试时出现的一道题,大家看题目的时候,思考一下,看你能否答得出来
var name = 222
var a = {
name:111,
say:function(){
console.log(this.name)
}
}
var fun = a.say
fun()
a.say()
var b = {
name: 333,
say: function(fn) {
fn()
}
}
b.say(a.say)
b.say = a.say
b.say()
现在我们先不着急着写答案。我们先来说说this的概念
概念
this指向在函数定义的时候是无法确定的,只有在函数执行的时候我们才能最终确定它指向谁。 this永远指向的都是最后调用它的对象,也就是看它执行的时候是谁调用的
this执行的几个场景
- 在函数中直接使用,指向的是window
function sayHi(str){
console.log(str)
}
sayHi('hello')
// sayHi('hello') ===sayHi.call(window,'hello')
- 函数作为对象的方法被调用(谁调用我,我就指向谁)
var person = {
name:'Cynthia',
gender:'female',
say:function(str){
console.log(`我的英文名字是${this.name},中文名${str}`)
}
}
person.say('...哈哈哈,不告诉你')
// person.say()相当于 person.say.call(person,'...哈哈哈,不告诉你')
- 作为构造函数执行
function Foo(name){
this.name = name
console.log(this) // 指向构造函数 Foo
}
var f = new Foo('Cynthia')
- call、apply、bind改变this的指向
function fn(name,age){
console.log(name)
console.log(this) //
}
fn.call({x:100},'lily',20) // this-->{x:100}
fn.apply({b:1023},['礼拜',30]) // this-->{y:1023}
var fn2 = function(name,age){
console.log(name) // 张三
console.log(this) // {y:100}
}.bind({y:200})
fn2('张三',30)
了解完上面的,我们就开始讲解一下开篇的那道题目吧
var name = 222
var a = {
name:111,
say:function(){
console.log(this.name)
}
}
var fun =a.say // fun.call(window) 函数的直接调用都是指向window
fun() // this指向是window,所以是222
a.say() // a.say.call(a) 111
var b ={
name:333,
say:function(fn){
fn()
}
}
b.say(a.say) // 这里相当于是函数的直接调用 函数直接调用的话是指向window的,所以是222
b.say = a.say // 把a.say方法直接复制给b.say,相当于b.say=function(){console.log(this.name)}
b.say() // b/.say.call(b) 输出是333
- fun()的结果讲解:
a.say赋值给fun的时候,只是把这个a.say函数赋值了fun,此时的fun就相当于是一个函数,那么函数的this只要你不修改它的指向,它默认的指向就是指向window的。所以fun的写法就相当于是fun.call(window),输出结果是 222 - a.say()的结果讲解: 这个不用多说,就是函数作为对象的方法被调用,
a调用say方法,所以this指向是a,相当于a.say.call(a),输出结果是 111 - b.say(a.say)的结果讲解: 这里是直接把a.say传进去,然后直接调用,函数直接调用的话,指向是window,所以输出结果是 222
- b.say()的结果讲解: 把
a.say方法直接复制给b.say,相当于b.say=function(){console.log(this.name)},那么b.say相当于b.say.call(b), 输出结果是333
箭头函数中的this指向
- 箭头函数中的this是在定义函数的时候绑定,而不是在执行函数的时候绑定
- 箭头函数中,this指向的固定化,并不是因为箭头函数内部有绑定的this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数
下面我们用两道题来讲解
第一道题
// 箭头函数中的this
var x = 11
var obj = {
x:22,
say: ()=>{
console.log(this.x)
}
}
obj.say() // 11
说明:所谓的定义时候绑定,就是this是继承自父执行上下文中的this,比如这里的箭头函数中的this.x,箭头函数say与obj中的x是以平级的key:value形式存在的,也就是箭头函数say本身所在的对象就是obj,而obj的父执行上下文就是window,因此这里的this.x实际上表示的是window.x,所以输出的是11
第二道题
var address = {
country:'China',
getCity:function(){
var country = this.country
var fn = ()=> console.log(this.country + 'GZ')
return fn()
}
}
address.getCity()
说明:例子中的箭头函数本身是在getCity方法中的,getCity的父执行上下文是address,因此这里的this指向是address
注意点:箭头函数的this是不会被修改的
var name = 'Cynthia'
var person = {
name:'Aria'
}
var fn = ()=>{
console.log(this.name)
}
fn.call(person) // Cynthia