前言
你盼世界,我盼望你无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