今天看到一道面试题,如下,问: 实例化 Person
过程中,Person
返回什么(或者 p
等于什么)?
function Person(name) {
this.name = name
return name;
}
let p = new Person('Tom');
说实话,第一反应我以为值为 'Tom'
,等到我把代码丢到控制台一输出,才明白我错了。天呐,new
运算符给无视掉了吗???
撇开 new
的存在,我们修改下代码
function Person(name) {
this.name = name
return name;
}
let p = Person('Tom');
console.log(p);
很显然,输出的结果是 'Tom'
, 但是有 new
存在呢?接下去,我们来捋一捋。
首先,我先去 MDN上搜索了 new 的定义
new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。
emmmm,相当晦涩难懂。
那我们试着写几个栗子看看结果吧
function Person1(name) {
this.name = name;
// 没有返回值
}
function Person2(name) {
this.name = name;
return name;
// 返回非对象
}
function Person3(name) {
this.name = name;
return { a: 1 };
// 返回对象
}
function Person4(name) {
this.name = name;
return null;
// 返回null
}
var p1 = new Person1("aa");
var p2 = new Person2("bb");
var p3 = new Person3("cc");
var p4 = new Person4("dd");
console.log(p1); // Person1 {name: "aa"}
console.log(p2); // Person2 {name: "bb"}
console.log(p3); // {a: 1}
console.log(p4); // Person4 {name: "dd"}
根据上面几个栗子,我们能得出结论:当使用 new 来创建对象||调用构造函数时,如果函数没有返回值|| 返回值是非对象,那么返回的就是构造函数实例后的对象;如果函数return对象,那么返回这个对象(特例:return null
,返回的也是构造函数实例后的对象而非null
)
我们接着看 MDN 文档的解释,毕竟光光看这几个demo没有说服力。
一起来理解下 new
到底做了什么工作吧~
就拿下面这个 demo
分析
function Person(name) {
this.name = name;
return {a: 1}
}
var p = new Person('fefeng')
当调用 new Person(...)
时,会进行以下几步:
- 首先是 继承自
Person.prototype
的新对象会被创建 - 使用参数
'fefeng'
调用构造函数Person
, 并将this
绑定到新创建的对象 - 由
Person
返回的对象就是new
表达式的结果 =》Person
返回的对象是{a: 1}
所以new
表达式的结果为{a:1}
; 如果Person
没有返回值(一般构造函数都不返回值)那么使用步骤1创建的对象,即==》 继承自Person.prototype
的新对象
貌似照着文档能够些许理解了,倘若模拟实现 new
运算符更能深入理解 new
以下是 new 的模拟实现,代码来源 : JavaScript深入之new的模拟实现
function objectFactory() {
var obj = new Object(),
cons = [].shift.call(arguments)
obj.__proto__ = cons.prototype
var ret = cons.apply(obj, arguments)
return typeof ret === 'object' ? ret|| obj : obj
}
function Person(name) {
this.name = name;
return {a: 1}
}
var p = objectFactory(Person, 'fefeng')
当然了,学习别人的代码不能仅仅只是照搬过来,起码得理解这个代码吧。
使用
- 首先是创建一个对象,
-
cons
是调用objectFactory
方法的第一个参数,即构造函数; 因为shift
会改变原数组,所以改变后的argument
即为调用构造函数的参数 (这里补充说明下: arguments 是一个对应于传递给函数的参数的类数组对象。) - 将
obj
的原型指向构造函数, 这样 obj 就能访问到构造函数原型上的属性 - 将构造函数
cons
的this
指向obj
,这样obj
能访问构造函数里的属性 - 判断返回的值是不是一个对象,如果是对象即返回它(当然这里要处理
return null
的特例);如果不是对象就返回obj
(注意:这里的obj
已经不是一个空对象)
如果你耐心看到了这里,那么十分感谢。如文章有错误,望给予指正~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。