new 实例化的重写
在 JavaScript 中,我们通常使用new
关键字来创建一个构造函数的实例对象。但是,你知道吗?我们可以通过重写Function.prototype.new
方法来自定义new
的实现过程。下面我就来讲解一下如何重写new
方法。
首先,我们在Function
的原型对象上添加一个new
方法:
Function.prototype.new = function () {
// this指向调用new方法的构造函数对象
var fn = this;
// 为obj添加原型
var obj = Object.create(fn.prototype);
// 修改this指向,指向obj,传入arguments
// 构造函数执行,把传入的参数赋值到obj上,成为obj的属性
var res = fn.apply(obj, arguments);
// 判断res是否继承于Object
return res instanceof Object ? res : obj;
};
我们来一步步分析上面的代码:
-
首先获取到调用
new
方法的构造函数对象,赋值给变量fn
。 -
然后使用
Object.create
方法创建一个新对象obj
,并将构造函数的原型对象赋值给obj
的原型。这样obj
就继承了构造函数的原型属性和方法。 -
接着使用
apply
方法修改构造函数内部this
的指向,让它指向新创建的对象obj
,并把arguments
参数传递进去。这样构造函数内部的this
就指向了obj
,所以构造函数内部的属性都会被赋值到obj
上,成为obj
的属性。 -
构造函数执行完后会返回一个对象
res
,我们判断它是否继承于Object
,如果是则直接返回res
,否则返回obj
。
这样我们就实现了new
操作符的内部逻辑。下面我们来测试一下:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function () {
console.log('hello');
};
var p = Person.new('zhangsan', 18);
console.log(p); // Person {name: "zhangsan", age: 18}
p.say(); // hello