【笔试题👋】分享一道有意思的arguments笔试题

主宰稳场 提交于 2020-03-23 19:26:11

3 月,跳不动了?>>>

前言

你盼世界,我盼望你无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时,tempthis的指向是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 或者扫一扫下面的二维码👇👇👇.

我会不定时的更新一些前端方面的知识内容以及自己的原创文章🎉

你的鼓励就是我持续创作的主要动力 😊.

相关推荐:

《全网最详bpmn.js教材》

《建议改成: 读完这篇你还不懂Babel我给你寄口罩》

《你的掘金文章本可以这么炫(博客美化工具一波带走)》

《【建议星星】要就来45道Promise面试题一次爽到底(1.1w字用心整理)》

本文使用 mdnice 排版

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!