this的值是什么

324 阅读2分钟

经典面试题:

var obj = {
  foo: function(){
    console.log(this)
  }
}
var bar = obj.foo
obj.foo() // 打印出的 this 是 obj
bar() // 打印出的 this 是 window

请解释最后两行函数的值为什么不一样。

函数调用

js(ES5)里面有三种函数调用方式:

function(a1,a2)
obj.child.method(a1,a2)
function.call(context,a1,a2)

一般大家都知道前两种的形式,认为前两种优于第三种形式,但其实第三种才是正常的调用的形式。

function.call(context,a1,a2)

其它两种都是语法糖,可以变换成第三种形式:

function(a1,a2) 等价于
function.call(undefined,a1,a2)


obj.child.method(a1,a2) 等价于
obj.child.method.call(obj.child,a1,a2)

所以函数调用的最终形式:

fn.call(context,a1,a2)

this解释

通过以上对函数调用方式的解析,this就是上面代码中的context.

this是你call一个函数时传的context.

代码转换帮助理解

function fn(){
	console.log(this)
}
fn()

转化成下面这样

function fn(){
	console.log(this)
}
fn.call(undefined) //简写为fn.call()

转化后可能认为打印出的this就是undefined,但是浏览器中有一条规则:

如果你传的context是null或undefined,那么window对象就是默认的context(严格模式下默认的context是undefined)

所以上面的打印结果不是undefined而是window

如果你希望打印的this不是window,就很简单了

function.call(obj) //这样this就是obj对象了

回到题目

var obj = {
  foo: function(){
    console.log(this)
  }
}
var bar = obj.foo
obj.foo()
//  转换为obj.foo.call(obj), this就是 obj
bar() 
// 转换为:bar.call()
// 由于没有传context,所以this就是undefined,最后浏览器给你默认的this-window对象

[ ]语法

function fn (){ console.log(this) }
var arr = [fn, fn2]
arr[0]() // 这里面的 this 又是什么呢

我们可以把 arr0 想象为arr.0( ),虽然后者的语法是错误的,但是形式与转换代码里的 obj.child.method(a1, a2) 对应上了,于是就可以愉快的转换了:

        arr[0]() 
假想为    arr.0()
然后转换为 arr.0.call(arr)
那么里面的 this 就是 arr 了 :)

箭头函数

箭头函数里面并没有this,如果箭头里面看到this,可以直接把他当作箭头外面的this即可,外面的this是什么箭头里面的this就是什么。

总结

this就是你call一个函数时传入的第一个参数