# 写出输出结果并给出分析
# Example_0
function Foo() {
getName = function() {
console.log(1)
}
return this
}
Foo.getName = function() {
console.log(2)
}
Foo.prototype.getName = function() {
console.log(3)
}
var getName = function() {
console.log(4)
}
function getName() {
console.log(5)
}
// 请写出以下输出结果:
Foo.getName()
getName()
Foo().getName()
getName()
new Foo.getName()
new Foo().getName()
new new Foo().getName()
代码执行时,首先进入全局执行上下文,在执行上下文编译阶段:
- 参数处理(无);
- 函数声明:
function Foo() { // ... }
和function getName() { console.log(5) }
; - 变量声明:存在一个
var
声明,由于与上面已经声明的函数同名,所以会被忽略。
然后进入执行文的执行阶段:
赋值:
Foo.getName = function() { console.log(2) }
;Foo.prototype.getName = function() { console.log(3) }
;getName = function() { console.log(4) }
,覆盖之前函数声明的值;
执行:
Foo.getName();
,调用赋值步骤 1 得到的方法,输出 2;getName();
,调用赋值步骤 3 得到的函数,输出 4;Foo().getName();
;- 直接调用
Foo
函数,其内this
在非严格模式下指向window
。 - 内部作用域中不存在
getName
变量,通过原型链找到外层,也就是全局的getName
函数,然后赋值进行覆盖。 - 返回
this
,也就是对象window
。此时Foo().getName();
相当于window.getName();
。 - 执行全局的
getName
方法,也就是 3-2 中改过后的方法,输出 1。
- 直接调用
getName();
,再次调用全局的getName
方法,输出 1。new Foo.getName();
:- 根据执行顺序属性的读取高于无参的
new
关键字,所以这里会先取得Foo
上的getName
方法。 - 通过
new
关键字调用得到的方法,输出 2。
- 根据执行顺序属性的读取高于无参的
new Foo().getName();
- 根据执行顺序
new
(带参数列表) 的优先级高于函数调用,所以这里先执行new Foo()
,此时new Foo().getName();
相当于Foo实例.getName();
。 - 实例上由于不存在
getName
方法,根据原型链将找到Foo.prototype.getName
方法并执行,见赋值步骤 2,输出 3。
- 根据执行顺序
new new Foo().getName();
:- 同上,先执行
new Foo()
得到结果new Foo实例.getName();
;根据原型链找到赋值步骤 2 中的方法。 - 通过关键字
new
调用Foo
原型上的getName
方法,输出 3。
- 同上,先执行