开开森森学前端

566 阅读3分钟

前言

大家好,来掘金有3个多月了,决定跟随前端大佬们的步伐,故决定记录自己的成长轨迹,由于水平有限,对于文章中出现的理解等有问题还请大佬们指正。

先来瞄一眼题目

var length = 10;
function fn() {
    console.log(this.length);
}
var obj = {
  length: 5,
  method: function(fn) {
    fn();
    arguments[0]();
  }
};
obj.method(fn, 1);

可以看到本题考查的知识点考察了以下知识点

  • this指向(不过好在算是this里最简单的)
  • 作用域
  • arguments伪数组(伪数组就是里面操作数组的各种方法都没有,但它有length属性
  • 其实这里还考察了函数的参数是按值传递的这个概念。

1.在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(即命名参数,或者用 ECMAScript 的概念来说,就是 arguments 对象中的一个元素)。

2.在向参数传递引用类型的值时,会把 这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部。

题目分析与解析

程序第一句:执行了obj.method(fn,1);

  1. 可以看到第一句中第一个参数传了fn函数的引用,第二个参数传了数字1
  2. 因为第一句调用了obj对象中的method方法,所以刚刚传的参数也是传到了method中,method函数接收fn函数引用且在里面执行了fn();,我们可以去看fn函数里有一个console.log输出语句,输出this.length,那我们只需要搞清楚this是谁就可以得到输出结果。
  3. 重点来了!
  4. 接着上面的分析我们现在想知道this,大家可能会想了,一般情况下this不就是谁最终调用的this就是谁吗,那这里是obj调用的method,那么this肯定是obj,obj里面不是刚好有length属性吗,那输出结果不就是5吗?(很不幸的告诉大家,如果你这样想那就掉进陷阱了)
  5. 实际上因为fn是作为形参传递进来的,且fn函数是声明在全局作用域的,所以即使在obj的method方法中调用,那么他的this依旧是window,所以method方法中的fn函数执行后输出结果是10
  6. 为了大家阅读方便我再把原题贴一遍,顺便把刚刚分析过的代码的执行结果加上
var length = 10;
function fn() {
   console.log(this.length);
}
var obj = {
 length: 5,
 method: function(fn) {
   fn();//10
   arguments[0]();
 }
};
obj.method(fn, 1);
  1. 这里第二句我们看到是这样的一行代码:arguments[0]();
  2. 我们知道arguments是个数组,里面存放的是所在函数接收到的所有形参集合,那么这么存放的肯定是fn函数的引用和1,它访问了arguments[0],那么很明显还是调用了fn函数,那么又遇到了fn函数中的console.log(this.length)这条输出语句。
  3. 那么我们继续探索一波this指向,在这里我们需要知道作为arguments成员之一调用的时候,其作用域就绑定到了arguments上,换句话说也就是this指向了arguments数组对象,刚刚说过arguments是有length属性的,因为method方法的形参总共传了2个(fn和1),那么arguments的length就是2,既然fn里的this指向arguments对象,所以this.length就等于是arguments.length,所以最后输出2。 而不是10或5

最终得到的答案

依次输出10和2

总结

想要做对这道题只需要基本掌握this指向和arguments是什么就可以轻松应对啦

大佬们如果发现了文中的错误,及时在评论区指出,我会及时修改!

如果觉得对您有用请点个赞,谢谢大佬!