1. 前言
最近打算充实一下自己,所以打算复习一下js基础,与之前不同的是这次复习打算把内容都整理成文章发布出来。因为我发现自己的遗忘速度越来越快了,既然脑子不好使了,就靠我的烂笔头吧。 言归正传,今天在复习new的时候发现了
关于new构造函数内返回值的问题,在探讨这个问题之前,先复习一下new内部的过程,熟悉这一部分的大佬可以直接跳到3.2 关键字new的返回值
2. new的过程
new关键字会进行如下的操作:
- 创建一个空的简单JavaScript对象(即
{}); - 为步骤1新创建的对象添加属性 proto ,将该属性链接至构造函数的原型对象 ;
- 将步骤1新创建的对象作为
this的上下文 ; - 如果该函数没有返回对象,则返回
this。
这里的第四句中的
对象我认为是非空的内容,既除去null和undefined
3. 手写new
按照上述描述我们很容易的便写出下面的代码
function selfNew(fun, ...args) {
// 创建一个空的简单JavaScript对象(即{}
let obj = {};
// 为步骤1新创建的对象添加属性__proto__,将该属性链接至构造函数的原型对象
obj.__proto__ = fun.prototype;
// 将步骤1新创建的对象作为this的上下文
let result = fun.apply(obj, args);
// 如果该函数没有返回对象,则返回this(obj)
return result === undefined || result === null ? obj : result;
}
3.1 验证代码:
// 构造函数
function Person(name) {
this.name = name;
return null;
// return 1;
// return '1';
// return true;
// return Symbol('1');
// return BigInt(1);
// return [1];
// return { x: 1 };
// return function () {};
}
// 正常的new
let p1 = new Person('HuLu');
console.log(p1);
console.log(p1.__proto__.constructor);
// 自己写的new
let p2 = selfNew(Person, 'HuLu');
console.log(p2);
console.log(p2.__proto__.constructor);
发现问题,当返回类型为非null和undefined的基本数据类型时,正常的new仍然返回的是“this”,而我们的new则返回了基础数据类型!
- return 1 或 retun '1':
- return true:
3.2 关键字new的返回值
经过上述代码运行发现构造函数中return类型不同,实例对象的结果见下表。
运行环境为node@14.17.3 |构造函数中return的内容|构造函数中return的数据类型|实例对象的结果|实例对象的类型| |-|-|-|-| |undefined|undefined|Person { name: 'HuLu' }|object| |null|null|Person { name: 'HuLu' }|object| |1|number|Person { name: 'HuLu' }|object| |'1'|string|Person { name: 'HuLu' }|object| |true|boolean|Person { name: 'HuLu' }|object| |Symbol(1)|symbol|Person { name: 'HuLu' }|object| |BigInt(1)|bigInt|Person { name: 'HuLu' }|object| |{x: 1}|object|{x: 1}|object |[1]|array|[ 1 ]|array |function() {}|function|[Function (anonymous)]|function|
由此可见,当构造函数中的返回值为引用数据类型时,实例对象才是其返回值,否则为“新创建的obj”
3.3 新的手写new:
function selfNew(fun, ...args) {
let obj = {};
obj.__proto__ = fun.prototype;
let result = fun.apply(obj, args);
// null的typeof也是object
return ['object', 'function'].includes(typeof result) && result !== null ? result : obj;
}
可以使用Object.create指定原型链
function selfNew2(fun, ...args) {
let obj = Object.create(fun.prototype);
let result = fun.apply(obj, args);
return ['object', 'function'].includes(typeof result) && result !== null ? result : obj;
}
4. MDN的描述有误?
很不解为什么MDN的描述有误,查了一些资料也没找到原因,直到我翻看的英文版本的MDN
这个案例在解释new执行的时候提到
由构造函数返回的对象(非null、false、3.1415或其他基本类型)成为整个新表达式的结果,而我们的中文版却没有这句翻译。。。
所以呢,自身条件允许的话,我们还是直接查阅原版英文文档吧(本人是个英语渣渣)。