--- title: 变量的定义提升 date: 2017-10-14 00:30:18 tags: - JavaScript - 函数 categories: - JavaScript --- 从一道笔试题说起 ```javascript 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是一个函数对象 , `Foo.getName = … `在其中定义了一个名为getName的属性 , 也是一个函数 所以第一问当中的调用输出的应该是2 #### 第二问 这里涉及到了变量的定义提升问题 , 如果不了解容易误认为答案是5 例如如下语句 ```javascript console.log("x" in window); var x; ``` 虽然变量的定义是在第二个语句 , 但是输出的结果仍然是true 因为代码执行时 JS引擎会把变量的声明语句提升到最上方 但是提升的仅仅是变量声明 , 如果声明变量的时候包含初始化 则会将初始化作为单纯的一条赋值语句保留在原处 例如 ```javascript console.log("x" in window); var x = 10; ``` 在JS引擎处理之后会改变为 ```javascript var x; console.log("x" in window); x = 10; ``` > 补充说明 : 只有显式的变量定义才会被提升 > 隐式的变量定义并不会 > 比如 ``` console.log("x" in window);//false x = 10; ``` > 输出就是false , 因为x未定义 全局函数的定义与全局变量的定义本质是一样的 所以它也会被提升到顶部 但是 `var x = function(){}`与`function x(){}`两种定义方式最终效果相同 执行过程却是不同的 ```javascript console.log(x);//function x(){} function x(){} console.log(x);//function x(){} ``` 或者 ```javascript console.log(x);//undefined var x = function(){} console.log(x);//function x(){} ``` 那么具体到这个题目 代码 ```javascript var getName = function () { console.log (4);}; function getName() { console.log (5);} ``` 会被JS引擎在解析时修改为 ```javascript var getName; function getName() { console.log (5);} getName = function () { console.log (4);}; ``` 显然 , 第三行的赋值会将第二行的定义覆盖掉 最终这个全局的getName函数输出的值是4 #### 第三问 Foo() 是在全局的基础上调用的 , 也就是由window对象调用的 所以return this返回的是window对象 但是在这个函数的内部 , 修改了全局的getName的值 现在名为getName的全局函数输出是1了 所以再调用window.getName() 的输出当然是1 #### 第四问 同样是调用全局的getName函数 , 所以结果和第三问一样 , 也是1 #### 第五问 成员访问的点号( . )优先级高于 new , 所以结果与第一问相同 , 也是2 #### 第六问 括号运算符的优先级高于点号( . ) 实际执行为 `( new Foo( ) ).getName()` 所以调用的是原型对象上的getName函数 , 输出是3