最近在看曾探老师写的 JavaScript设计模式与开发实践这本书,其中讲到new过程的时候,给了一个这样的例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>new过程</title>
</head>
<body>
<script>
function Person(name) {
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
};
var objectFactory = function (constructor) {
var obj = new Object(); //从Object.prototype上克隆一个空的对象
Constructor = [].shift.call(arguments); //取得外部传入的构造器,此例是Person
obj.__proto__ = Constructor.prototype; //指向正确原型
var ret = Constructor.apply(obj, arguments); //借用外部传入的构造器给obj设置属性
return typeof ret === "object" ? ret : obj; //确保构造器总是返回一个对象
};
var a = objectFactory(Person, "sven");
console.log(a);
console.log(a.name);
console.log(a.getName());
console.log(Object.getPrototypeOf(a) === Person.prototype);
</script>
</body>
</html>
感觉理解起来还是比较麻烦的,我也曾记得在面试题中new过程还是问到的次数比较多的,经过看别人写的文章以及mdn上的一些解释,自己按照一个比较简便的方法来记new过程,
这是自己封装的一个简易的new对象的过程:
let _new = function(constructor,...args) {
//首先传入两个参数,一个就是new的函数,另一个就是arguments参数,这样就不用[].shift.call这个方法了
let obj = new Object() //创建一个新的对象
obj.__proto__ = constructor.prototype //新对象的__proto__指向构造函数的原型
let ret = constructor.apply(obj,args) //用apply,执行构造函数中的代码,并且改变this指向,第二个参数用来传参,为obj
添加新属性
return typeof ret === "object" ? ret : obj; //判断构造函数有没有显示返回一个对象,如果没有,就返回新的创建的新的空的
对象
}
var a = _new(Person, "sven");
console.log(a);
console.log(a.name);
console.log(a.getName());
console.log(Object.getPrototypeOf(a) === Person.prototype);
简单总结一下new的过程:
1.创建一个新的对象,新对象的隐式原型__proto__指向new的构造函数的显示原型proptotype
2.改变this指向,将构造函数的作用域赋给新的对象,并且执行构造函数的代码,为新的对象添加属性
3.返回新的对象
mdn给出的解释是这样的:
当代码 new Foo(...) 执行时,会发生以下事情:
一个继承自 Foo.prototype 的新对象被创建。
使用指定的参数调用构造函数 Foo,并将 this 绑定到新创建的对象。new Foo 等同于 new Foo(),也就是没有指定参数列表,Foo 不带任何参数调用的情况。
由构造函数返回的对象就是 new 表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1创建的对象。(一般情况下,构造函数不返回值,但是用户可以选择主动返回对象,来覆盖正常的对象创建步骤)