一道经典综合面试题解析
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();
这道题的经典之处在于它综合考察了面试者的 JavaScript 的综合能力,包含了变量定义提升、this 指针指向、运算符优先级、原型、继承、全局变量污染、对象属性及原型属性优先级等知识,此题在网上也有部分相关的解释,当然我觉得有部分解释还欠妥,不够清晰,特地重头到尾来分析一次,当然我们会把最终答案放在后面,并把此题再改高一点点难度,改进版也放在最后,方便面试官在出题的时候有个参考。
第一问
先看此题的上半部分做了什么,首先定义了一个叫 Foo 的函数,之后为 Foo 创建了一个叫 getName 的静态属性存储了一个匿名函数,之后为 Foo 的原型对象新创建了一个叫 getName 的匿名函数。之后又通过函数变量表达式创建了一个 getName 的函数,最后再声明一个叫 getName 函数。
第一问的 Foo.getName 自然是访问 Foo 函数上存储的静态属性,答案自然是 2,这里就不需要解释太多的,一般来说第一问对于稍微懂 JS 基础的同学来说应该是没问题的,当然我们可以用下面的代码来回顾一下基础,先加深一下了解
function User(name) {
var name = name; //私有属性
this.name = name; //公有属性
function getName() {
//私有方法
return name;
}
}
User.prototype.getName = function() {
//公有方法
return this.name;
};
User.name = "Wscats"; //静态属性
User.getName = function() {
//静态方法
return this.name;
};
var Wscat = new User("Wscats"); //实例化
注意下面这几点:
- 调用公有方法,公有属性,我们必需先实例化对象,也就是用 new 操作符实化对象,就可构造函数实例化对象的方法和属性,并且公有方法是不能调用私有方法和静态方法的
- 静态方法和静态属性就是我们无需实例化就可以调用
- 而对象的私有方法和属性,外部是不可以访问的
第二问
第二问,直接调用 getName 函数。既然是直接调用那么就是访问当前上文作用域内的叫 getName 的函数,所以这里应该直接把关注点放在 4 和 5 上,跟 1 2 3 都没什么关系。当然后来我问了我的几个同事他们大多数回答了 5。此处其实有两个坑,一是变量声明提升,二是函数表达式和函数声明的区别。
函数声明
// 函数声明
function wscat(type) {
return type === "wscat";
}
函数表达式
// 函数表达式
var oaoafly = function(type) {
return type === "oaoafly";
};