题
function Foo(){
getName = function () {alert(1);}
return this;
}
Foo.getName = function() {alert(2);};
Foo.prototype.getName = function(){alert(3);};
var getName = function(){alert(4);};
function getName(){alert(5)};
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
答
2 ----Foo.getName();
4 ----getName();
1 ----Foo().getName();
1 ----getName();
2 ----new Foo.getName();
3 ----new Foo().getName();
3 ----new new Foo().getName();
概念
为了阅读效益最大化,请先了解执行环境
和变量对象
的文字性
概念。
执行环境
挺常见的,它是长这样的。它的特性是先进后出(stack)。
上述图片是来源于代码执行到Foo( ).getName( )。
(anonymous function) 其实就是global context
表示方法:
ECStack = [
functionContext(Foo), /*这不是函数*/
GlobalContext
]
变量对象
也挺常见,在Chrome中长这样。
表示方法通常是:
//以上述代码尚未执行时为例
VO = {
Foo: {
<reference to function>,
return this
}
getName: <reference to function>
}
分析
代码执行有两个阶段
进入环境(代码未执行,已编译)
代码执行
现在一起来看看每一行代码的执行
上述代码未执行时,变量对象是这样的。
VO = {
Foo: {
<reference to function>,
return this
}
getName: <reference to function(){alert(5)}>
}
执行"第一行"代码
该行代码执行后VO会变成这样。
VO = {
Foo: {
<reference to function>,
getName: <reference to function() {alert(2)},
return this
}
getName: <reference to function(){alert(5)}>
}
VO的Foo图示是这样的
执行"第二行"代码
该行代码执行后VO会变成这样。
VO = {
Foo: {
<reference to function>,
getName: <reference to function() {alert(2)},
prototype: {
getName: <reference to function(){alert(3)}
},
return this,
}
getName: <reference to function(){alert(5)}>
}
VO的Foo图示是这样
执行"第三行"代码
该行代码执行后VO会变成这样。
VO = {
Foo: {
<reference to function>,
getName: <reference to function() {alert(2)},
prototype: {
getName: <reference to function(){alert(3)}
},
return this
}
getName: <reference to function(){alert(4)}>
}
执行"第四行"代码(第一问)
直接去VO里寻找结果发现alert 2。
执行"第五行"代码(第二问)
getName() //等于
window.getName();
同样直接在VO里可以直接找到答案 alert 4。
执行"第六行"代码(第三问)
这里比上述多了一个函数调用,Foo()调用返回this(指向window),所以此时
Foo().getName(); //等于
window.getName()
同时注意:
由于Foo()调用,导致VO发生了变化。最后alert 1.
VO = {
Foo: {
<reference to function>,
getName: <reference to function() {alert(2)},
prototype: {
getName: <reference to function(){alert(3)}
},
return this
}
getName: <reference to function(){alert(1)}>
}
执行"第七行"代码(第四问)
结果同上
执行"最后三行"代码(第五、六、七问)
最后三问考察了new、属性访问符、及函数调用优先顺序和new运算符的作用。
优先顺序
参考如下,或点这
无论是用哪种属性访问表达式,在"."和"[]"之前的表达式总是会先计算的。
对于new Foo.getName()
来说,点运算级最高,所以先进行计算表达式
Foo的值。如果先运算new的话,就证明了new优先级高于点号,与规范不和。
而对于new Foo().getName()
来说,Foo()与new Foo()相比,new优先级更高,所以先算new Foo(),new出来的新对象继承
了Foo.prototype属性,因此新对象访问getName时会弹出3.
此处要明白new的作用
创建新的空对象
将新对象继承构造函数的prototype属性,并调用构造函数初始化
将构造函数的this指针指向新建对象。
最后一个问题同理倒数第二个。
谢谢ID:李卫
的提醒。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。