new 原理我们可以在 ES5 官方文档中看到其对 new 创建对象过程的定义与约束:
13.2.2 [[Construct]] When the [[Construct]] internal method for a Function object F is called with a possibly empty list of arguments, the following steps are taken:
"Object"."prototype".若执行 new Foo() ,其过程可简单描述为:
o ;[[Prototype]] 属性赋值,构造原型链。若构造函数的原型为 Object 类型,则指向构造函数的原型,否则执行 Object 对象的原型;this 指向 o ,执行构造函数;o 。new 实现根据上两节的内容,我们可以尝试自己实现 new :
function my_new() {
// 创建一个空的对象
let o = {};
// 获得构造函数
let constructor = [].shift.call(arguments);
// 链接到原型
let prototype =
typeof constructor.prototype === "object"
? constructor.prototype
: Object.prototype;
o.__proto__ = prototype;
// 绑定 this,执行构造函数
let result = constructor.apply(o, arguments);
// 确保 new 出来的是个对象
return typeof result === "object" ? result : o;
}
function Foo(name) {
this.name = name;
}
const obj = my_new(Foo, "Jiahonzheng");
console.log(obj); // {name: "Jiahonzheng"}instanceof 原理我们可以通过 instanceof 判断某个对象的类型,其内部机制是通过判断对象的原型链中是否能找到类型的 prototype 。
值得注意的是,null instanceof Object 返回 false ,所以 null 不是 Object 类型,尽管 typeof null 返回 "Object" 。
PS:typeof null 返回 "Object" 情况的出现是因为:在 JS 的最初版本中,使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000 开头代表的是对象,而 null 所有数据位为零,故 typeof 错误地将它判断为 object 。虽然现在内部类型判断代码已经改变,但是这个 Bug 仍在流传。
instanceof 实现function instanceOf(left, right) {
// 获得类型的原型
let prototype = right.prototype;
// 获得对象的原型
left = left.__proto__;
// 判断对象的类型是否等于类型的原型
while (true) {
if (left === null) return false;
if (prototype === left) return true;
left = left.__proto__;
}
}
const Foo = function() {};
const o = new Foo();
console.log(instanceOf(o, Foo)); // true
// 重写 Foo 原型
Foo.prototype = {};
console.log(instanceOf(o, Foo)); // falsenew 调用,原因是箭头函数无 [[Construct]] 方法。new 生成的。new Object() 的方式创建对象,需要通过作用域链层层查找到 Object ,而在使用字面量时,则无此问题。new 运算符优先级问题:
function Foo() { return this; } Foo.func = function() { console.log("1"); }; Foo.prototype.func = function() { console.log("2"); }; new Foo.func(); // new (Foo.func()); -> 1 new Foo().func(); // (new Foo()).func(); -> 2