方式1:一个构造函数,里面有个全局变量getName 指向一个匿名函数
function Foo(){
getName = function (){
console.log(1);
}
return this;
}
方式2:构造函数的一个属性getName 指向一个匿名函数
Foo.getName = function(){
console.log(2);
}
方式3:构造函数的原型上有个getName方法
Foo.prototype.getName = function (){
console.log(3);
}
方式4:定义一个变量指向一个匿名函数
var getName = function (){
console.log(4);
}
方式5:声明一个叫getName的函数
function getName(){
console.log(5);
}
//请写出下面输出的结果
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.getName()
此句为函数Foo的静态方法,输出结果为2.
----->2. getName()
单独看此句首先想到的是一般会有个全局声明的函数方法,方式5"function getName(){}",但要放在这个上下文环境中,那肯定不一样了,因为还有个方式4"var getName = function(){}",这里要考察一个知识点,当定义的变量和声明的函数重名了怎么办?答:它们都会预解析,函数声明提前于变量声明,但是最终会被后者变量覆盖,so输出结果为4.
----->3. Foo().getName()
此句有个执行顺序的,先执行方式1的Foo(),其相当于window.Foo(),故此this指向window,另外Foo()函数的第一句是getName = function(){}是一句函数赋值语句,注意它没有var声明,是一个全局变量,如果先执行window.getName()结果是4,如果先执行Foo()会返回一个window,那此时
此时方式4已经被覆盖了,所以下面再执行全局getName()就都是结果为1了。
----->4. getName()
此处跟执行的Foo().getName()有关,因为这个变量已经被Foo函数执行时修改了,所以结果为1
----->5. new Foo. getName()
此句首先还是看下运算符的优先级吧,结果大概就是(new Foo()> Foo() > new Foo)相当于new (Foo.getName)();
先运算方式函数调用Foo.getName(),静态调用,回到方式1的执行语句了,结果为2,再new一个Foo实例对象,实际上将getName函数作为了构造函数来执行,结果为2
----->6. new Foo(). getName()
此句先看运算符相当于(new Foo()).getName(),先指向Foo函数,而此时Foo作为构造函数却有返回值,所以这里需要说明下js中的构造函数返回值问题
构造函数返回值
在传统语言中,构造函数不应该有返回值,实际执行的返回值就是此构造函数的实例化对象。
而在js中构造函数可以有返回值也可以没有
1.没有返回值则按照其他语言一样返回实例化对象
2.若有返回值则检查其返回值是否为引用类型,如果是非引用类型,如基本类型(string,number,boolean,null,undefined)则与无返回值相同,实际返回其实例化对象
3.若返回值是引用类型,则实际返回值为这个引用类型
原题中返回的是this,而this在构造函数中本来就代表当前实例化对象,所以Foo函数返回实例化对象。
之后调用实例化对象的getName函数,因为在Foo()构造函数中没有为实例化对象添加任何属性,所以到当前对象的原型对象(prototype)中寻找getName,所以找到了,结果为3.
----->7. new new Foo(). getName()
同样先运用优先级问题,实际相当于new ((new Foo()).getName)();
先初始化Foo的实例化对象,然后将其原型上的getName函数作为构造函数再次被new,结果为3