前言
你盼世界,我盼望你无bug。Hello 大家好!我是霖呆呆!
这篇文章很短...但绝对不是一篇水文...
主要是在评论区看到了,觉得是我们平常会忽略的一个小知识点而且笔试也有可能碰到,所以单独作为一篇文章来写,还请花个2分钟来看看吧,万一真给碰上了呢 😁。
(题目来源:掘友Lazzw,感谢该小伙伴的提出)
正题
题目是这样的:
var obj = { 
age: 18, 
foo: function (func) { 
    func()
arguments[0]()
 }
} 
var age = 10 
function temp () {
console.log(this.age)
}
obj.foo(temp)
复制代码
 
不卖关子,咱先上答案:
10
undefined
复制代码
 
之前我们一直只在意函数中最常用的隐藏参数this,而这道题其实就考到了函数中隐藏的另一个参数arguments。
先简单说明一下arguments的作用再来看这道题吧。
arguments参数是传递给函数的所有参数的集合(类数组结构),例如下面这两个例子:
function test1 () {
console.log(arguments)
}
function test2 (a) {
console.log(a)
console.log(arguments)
}
test1(1, 2)
test2(1, 2)
复制代码
 
执行结果为:
[1, 2]
1
[1, 2]
复制代码
 
可以看到,不管你的函数中有没有形参,arguments都会获取到你调用函数时传递的所有实参。
(而且arguments只存在于普通函数中,window全局下和箭头函数中都不存在)
另外我们知道,传递给函数的参数也可以是一个函数,那么只要是参数,arguments就可以捕获到,就算你是一个函数也逃不了,比如这样:
function foo () {
arguments[0]()
}
function temp () {
console.log(this)
}
foo(temp) // Arguments [ƒ temp()]
复制代码
 
如上题,向foo()中传递了temp函数,并且使用arguments[0]()调用它是可以执行的。
比较有意思的就是这里了,如果你是将temp当参数传递进去并且调用的话,就会发生隐式绑定丢失问题(类似《【建议👍】再来40道this面试题酸爽继续(1.2w字用手整理)》中的题目3.3),从而使函数内的this指向window:
function foo (fn) {
  fn()
}
function temp () {
console.log(this)
}
foo(temp) // Window
复制代码
 
但是这里我们是用arguments[0]()这样的形式调用它,它里面的this指向的就不是window而是arguments本身了。
所以回到原题中:
var obj = { 
age: 18, 
foo: function (func) { 
    func()
arguments[0]()
 }
} 
var age = 10 
function temp () {
console.log(this.age)
}
obj.foo(temp)
复制代码
 
题目解析:
-  在使用 
obj.foo(temp)时,将temp函数当成了参数传递到foo中,这里我们知道func是发生了隐式绑定丢失的,所以导致第一次调用temp函数(也就是执行func()这段代码)的时候,temp内的this是指向window的,因此会打印出10。 -  而传入进去的 
temp会被arguments所搜集,所以可以使用arguments[0]()这样的形式调用。但是此时temp内的this就是arguments了,而在arguments内是没有age这个属性的,所以会打印出undefined。 
为了验证这个想法💡,我们可以将题目改造一下:
var obj = { 
age: 18, 
foo: function (func) { 
    func()
arguments.age = 66 // 新增代码1
arguments[0]()
 }
} 
var age = 10 
function temp () {
console.log(this) // 新增代码2
console.log(this.age)
}
obj.foo(temp)
复制代码
 
我在题目中加了2行代码,一行是给arguments中添加了一个age属性,一行是将temp中的this打印出来。
现在来看看答案:
Window
10
Arguments [ƒ temp(), age: 66]
66
复制代码
 
果然执行结果和我们设想的一样,第二次调用temp时,temp内this的指向是arguments,并且我们给arguments里塞了个age,它也可以成功打印出来。
附加题
OK👌,霖呆呆最喜欢的事就是...
抢答时间!开始!
"买一送一"
没错啦,碰上了这道有意思的题你难道不想把它改造一下,增加增加难度吗?
[阴笑~]
上题!
var obj = {
age: 10,
foo: function (fn) {
    fn.call(this)()
arguments[0]()()
arguments[0].call(this)()
arguments[0]().call(this)
 }
}
var age = 20
function temp () {
return function () {
console.log(this.age)
 }
}
obj.foo(temp)
复制代码
 
我在temp中返回了一个匿名函数,并且将foo()接收到的参数用不同的方式调用它。
题目解析:
-  
fn.call(this)()是最简单的了,看过呆呆this那篇文章的小伙伴应该都知道,fn.call(this)()使用.call(this)改变的是temp第一层函数中的this,但是最终调用那个匿名函数的还是window,所以会打印出20。(类似于this篇中的题目4.9) -  
arguments[0]()(),通过上面👆的正题我们知道arguments[0]()中,也就是temp函数的第一层指向的是arguments对象,而调用temp返回的那个匿名函数的也还是window,就像是fn.call(this)()一样,所以打印出的也还是20。(做这类题你就想着一个函数中返回另一个函数,如果没用call/apply进行显式绑定的话,调用它的都是window) -  
arguments[0].call(this)()和第二个一样,它使用.call(this)改变的是temp函数的第一层this指向,而调用匿名函数的也还是window,因此还是打印出20。 -  
arguments[0]().call(this),这里使用.call(this)改变的就是匿名函数内的this指向了,将它绑定为foo函数内的this,而我们知道,此时foo函数内的this是指向的obj,因为调用foo的是obj,所以会打印出10。 
(以上👆提到的this篇链接为:《【建议👍】再来40道this面试题酸爽继续(1.2w字用手整理)》)
后语
知识无价,支持原创。
参考文章:
你盼世界,我盼望你无bug。这篇文章就介绍到这里。
好像没什么问题嘛~
都是之前看到过的知识点 😁。
不过如果第一眼看着感觉做不来的小伙伴也别觉得自己不行🙅♂️,实话实话,就算是我自己写的文章不回头看的话也会忘掉 😂,所以我这不是经常搞搞有意思的题来帮我们一起巩固巩固嘛 😁,如果你都做的来的话,那很棒棒哦 👍。
(这个时间点写文章别和我老大举报我啊,我这是为了提高全中国前端工程师的JS水平)
"呸!臭不要脸!"
喜欢霖呆呆的小伙还希望可以关注霖呆呆的公众号 LinDaiDai 或者扫一扫下面的二维码👇👇👇.
我会不定时的更新一些前端方面的知识内容以及自己的原创文章🎉
你的鼓励就是我持续创作的主要动力 😊.
相关推荐:
《【建议星星】要就来45道Promise面试题一次爽到底(1.1w字用心整理)》
本文使用 mdnice 排版
来源:oschina
链接:https://my.oschina.net/u/4414726/blog/3209277
