1 | function Foo(){ |
尝试说出输出结果?
结果: 2 4 1 1 2 3 3
这道题考察了全局对象、函数声明提升、变量提升、this指针、原型、构造函数、new运算符与点运算符的优先级。
个人理解:
加载代码
var存在变量提升,即会把声明提到第一行,而定义位置不变,函数声明同样,执行代码之前会先读取函数声明,所以相当于:
1 | var getName |
函数的优先级高于变量,相同名称的函数,后面的会覆盖前面的,所以代码加载解析后定义在全局上的getName方法输出为4
执行代码
- 第一行
Foo.getName()
函数也可以理解为特殊的对象,所以可以为它添加属性,输出2;
- 第二行
getName()
执行全局上的getName方法,输出4
- 第三行
Foo().getName()
指定Foo方法,方法返回this,此时this指向window对象,但之前又对getName重新赋值,所以全局getName方法改为输出1
- 第四行
getName()
全局方法getName,上面已经将输出改为1,所以输出1
- 第五行
new Foo.getName()
考察运算符优先级问题,是以Foo.getName当作构造方法还是Foo.getName()返回结果当作构造方法。
上图显示无参数new方法的优先级(18)低于取值运算(19),所以之际执行是new (Foo.getName)()
,即会以Foo.getName当作构造方法,输出2
- 第六行
new Foo().getName()
有参数new方法的优先级与取值运算相同(都是19),所以从左向右执行,(new Foo()).getName()
,Foo作为构造方法返回实例,再对实例取getName方法,实例取值在原型链上获取,所以执行Foo.prototype.getName方法,输出3
比如经常写的new Set(…arr).size也是这样的运算规则
- 第七行
new new Foo().getName()
多个一元运算符存在时,执行顺序为从右到左,所以执行方式为new (new Foo().getName)()
,而new Foo().getName
的执行结果与第六行相同,返回Foo原型上的getName方法,以该方法作为构造方法生成实例,输出为3