JavaScript平常会跳的坑系列(一)

function Foo() {          //定义foo函数
    getName = function () { console.log('1');};
    console.log(this);
    return this;
}
Foo.getName = function () { console.log('2');};   //Foo创建了一个叫getName的静态属性存储了一个匿名函数
Foo.prototype.getName = function () { console.log('3');};  //Foo的原型对象新创建了一个叫getName的匿名函数
var getName = function () { console.log('4');};       //函数变量表达式创建了一个getName的函数
function getName() { console.log('5');}      //声明一个叫getName函数

//由于变量定义提升,该段JavaScript实际上的解析顺序如下
/*
function Foo() {          //定义foo函数
    getName = function () { console.log('1');};
    console.log(this);
    return this;
}
var getName;
function getName() { console.log('5');}
Foo.getName = function () { console.log('2');};   //声明foo的getName静态属性
Foo.prototype.getName = function () { console.log('3');};  //以foo为原型再声明一个getName静态属性
getName = function () { console.log('4');}; 
 */


Foo.getName(); //2  
//析:访问Foo函数上存储的静态属性      
getName(); //4
//由于变量定义提升,所有声明变量或声明函数都会被提升到当前函数的顶部,真正的执行顺序如下
/*var getName;
function getName() { console.log('5');}
getName = function () { console.log('4');}; */
Foo().getName(); //1
//析:考察变量作用域问题,this指向问题;
//先执行了Foo函数,然后调用Foo函数的返回值对象的getName属性函数
//此时foo的返回值为Window对象
//Foo函数的第一句  getName = function () { alert (1); };  是一句函数赋值语句,注意它没有var声明,所以先向当前Foo函数作用域内寻找getName变量,没有。再向当前函数作用域上层,即外层作用域内寻找是否含有getName变量,找到了,也就是第二问中的alert(4)函数,将此变量的值赋值为 function(){alert(1)}。 
//此处实际上是将外层作用域内的getName函数修改了。
//注意:此处若依然没有找到会一直向上查找到window对象,若window对象中也没有getName属性,就在window对象中创建一个getName变量。
getName(); //1
//getName函数,相当于 window.getName() ,因为这个变量已经被Foo函数执行时修改了,遂结果与第三问相同,为1
new Foo.getName(); //2
//点(.)的优先级高于new操作,遂相当于是:new (Foo.getName)(); 
//所以实际上将getName函数作为了构造函数来执行,遂弹出2。

new Foo().getName(); //3
//析:Foo()返回的this是foo()对象,调用getName()匿名函数打印3
new new Foo().getName(); //3
//析:
/*第七问, new new Foo().getName(); 同样是运算符优先级问题。
 
最终实际执行为:
 
new ((new Foo()).getName)(); 
先初始化Foo的实例化对象,然后将其原型上的getName函数作为构造函数再次new。
 
遂最终结果为3*/

  

你可能感兴趣的:(JavaScript平常会跳的坑系列(一))