题目以下:node
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
// 4
// 1
// 1
// 2
// 3
// 3
复制代码
下面对输出值进行分析:函数
Foo.getName()
输出为 2, 访问的是函数 Foo 上的静态属性,输出为 2。优化
如今,尝试在函数内定义 getName 函数和在 Foo 原型上绑定 getName 函数, 都没法成功执行 Foo.getName()
, 而以字面量建立对象的方式建立对象后,则能正常的执行 getName()
函数。ui
经过建立对象运行 getName()
定义在函数内部没法正常执行,即便它是全局变量。this
结论: 因为函数自己是对象,经过函数绑定属性和方法属于静态方法 ,能够直接调用。绑定在原型上的属性和方法要建立对象后才能调用,在构造函数对象内部定义的方法没法经过对象调用。spa
getName();
结果输出为 4,而不是输出 5。这是由于JS 存在变量声明提高(全部声明的变量或声明的函数都会被提高到当前函数的顶部)。prototype
故代码执行顺序为:code
var getName;
function getName() { alert(5); }
// ... 省略代码
getName = function () { alert(4) }
复制代码
最终执行 getName
输出为 4cdn
延伸题目:对象
console.log( Foo )
function Foo() {
console.log(1);
}
var Foo = 1
复制代码
Foo 的输出结果为?
Foo().getName();
输出值为1, 先执行 Foo() 函数,定义全局变量 getName, 以后调用全局对象的 getName()
方法, 返回 1。
注意, Foo()
函数返回的 this
指向的是全局对象 window,因此调用的是全局对象 getName()
。 函数里的 getName 绑定的是全局对象,经过 Foo 调用会报错。
Node 下执行这条语句会报错,由于 node 没有全局对象 window, 因此没法调用 getName
getName()
调用全局函数, 由于执行 Foo()
, 更新了 getName 的值,因此返回 1。
new Foo.getName()
考察了运算符的优先级。 .
的优先级高于 new, 至关于执行 new (Foo.getName)()
, 至关于执行 getName 的构造函数,返回 2
new Foo().getName()
执行方式为 (new Foo()).getName()
先生成 Foo 对象, 再执行 getName()
函数。 在 new Foo()
返回的是新建立的空对象,因为对象这时还没绑定属性 getName, 因此这时调用的是原型上的 getName, 结果返回3
注意: 构造函数
return this
,在执行 new 的时候,返回的是新建立的对象。
延伸题目:
function A() {
this.a = 2;
function B() {
this.a = 1;
}
return B();
}
console.log(new A());
复制代码
a的值是? 若是 return new B();
a的值是?
new new Foo().getName()
能够改写为 new ((new Foo()).getName)()
先初始化实例,而后将原型对象上的 getName() 做为构造函数执行,结果返回 3
最终代码能够优化为
var getName;
function getName() { alert(5); }
function Foo() {
getName = function() { alert(1); }
return this
}
Foo.getName = function() { alert(2); }
Foo.prototype.getName = function() { alert(3); }
getName = function () { alert(4); }
Foo.getName(); // 2
getName(); // 4
Foo();
getName(); // 1
getName(); // 1
Foo.getName(); // 2
(new Foo()).getName(); // 3
(new Foo()).getName(); // 3
复制代码