经典面试题:
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一个函数时传入的第一个参数