1.此题涉及的知识点众多,包括变量定义提升、this指针指向、运算符优先级、原型、继承、全局变量污染、对象属性及原型属性优先级等等。
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();
答案如下:
Foo.getName();//2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName();//2
new Foo().getName();//3
new new Foo().getName();//3
解析:先看此题,1.首先创建了一个Foo的函数,2.之后又为Foo创建了一个叫getName的静态属性存储了一个匿名函数,3.之后为Foo的原型创建了一个名叫getName的匿名函数。4.之后又通过函数变量表达式创建了一个getName的函数,5.最后再声明一个叫getName函。
第一问:自然是访问Foo上的静态属性,是2.
第二问:此处有两个坑,一是变量声明提升,二是函数表达式。
以上问题代码可以等价于:
function Foo() {
getName = function () { console.log(1) };
return this;
}
function getName() { console.log(5) };//先提升函数声明
var getName;//然后提升变量,不会赋值
Foo.getName = function () { console.log(2) };
Foo.prototype.getName = function () { console.log(3) };
getName = function () { console.log(4) };
最后执行getName()时自然输出的是4.
第三问:先执行Foo(),首先在Foo函数的作用域里寻找变量getName,没有找到就到全局作用域里去寻找,找到了把getName重新赋值了一个匿名函数,最后返回的是window,相当于执行window.getName(),自然结果是1;
第四问:此时已经把变量getName存储了function () { console.log(1) }的匿名函数。所以结果为1;
后面的就牵扯到运算,优先级从高到底排序的,可以参考https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
![](https://images2017.cnblogs.com/blog/1215688/201711/1215688-20171119150849671-819260058.jpg)
第五问:点.的运算符高于new所以相当于new (Foo.getName());访问对象Foo的静态属性getName(),实际上把getName当作构造函数,结果为2;
第六问:
new Foo().getName(),括号()的优先级高于new,
相当于(new Foo()).getName();
构造函数的返回值
在传统语言中,构造函数不应该有返回值,实际执行的返回值就是此构造函数的实例化对象。
而在js中构造函数可以有返回值也可以没有。
1、没有返回值则按照其他语言一样返回实例化对象。
2、若有返回值则检查其返回值是否为引用类型。如果是非引用类型,如基本类型(string,number,boolean,null,undefined)则与无返回值相同,实际返回其实例化对象。
3、若返回值是引用类型,则实际返回值为这个引用类型。
原题中,返回的是this,而this在构造函数中本来就代表当前实例化对象,遂最终Foo函数返回实例化对象。
之后调用实例化对象的getName函数,因为在Foo构造函数中没有为实例化对象添加任何属性,遂到当前对象的原型对象(prototype)中寻找getName,找到了。
遂最终输出3。
第七问:
new new Foo().getName(),相当于new ((new Foo()).getName)();先初始化Foo的实例化对象,然后将其原型上的getName函数作为构造函数再次new;
参考:http://mp.weixin.qq.com/s/eO5hL0pcEHYr7jAbWTWAXg