new目的
- 实例可以访问到构造函数原型中的属性(实例对象的隐式原型__proto__指向构造函数的原型prototype)
- 实例可以访问到构造函数中的属性(使用 apply,改变构造函数 this 的指向到新建的对象,也就是新对象继承了构造函数)
new核心行为:创建一个新对象,设置其原型,然后调用构造函数并返回结果。
在《JavaScript模式》这本书中,new的过程说的比较直白,当我们new一个构造器,主要有三步:
- 首先创建一个空的对象
- 空对象的__proto__属性指向构造函数的原型对象prototype
- 改变构造函数 this 的指向到新建的对象
- 如果构造函数返回一个非基本类型的值,则返回这个值,否则返回上面创建的对象
实现new方法
方法一
function objectFactory() {
const Constructor = Array.prototype.shift.call(arguments);
const obj = {};
obj.__proto__ = Constructor.prototype;
const result = Constructor.apply(obj, arguments);
return result instanceof Object ? result : obj;
}
//const Constructor = Array.prototype.shift.call(arguments);
//取出第一个参数,就是我们要传入的构造函数。
//此外因为 shift 会修改原数组,所以 arguments 会被去除第一个参数
方法二
function _new(fn, ...arg) {
var obj = Object.create(fn.prototype);
const result = fn.apply(obj, arg);
return result instanceof Object ? result : obj;
}
例子:
function Otaku(name, age) {
this.name = name;
this.age = age;
this.habit = "Games";
}
Otaku.prototype.strength = 60;
Otaku.prototype.sayYourName = function () {
console.log("I am " + this.name);
};
function objectFactory() {
var obj = new Object(),
Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
Constructor.apply(obj, arguments);
return obj;
}
var person = objectFactory(Otaku, "Kevin", "18");
console.log(person.name); // Kevin
console.log(person.habit); // Games
console.log(person.strength); // 60
person.sayYourName(); // I am Kevin
比较纠结的问题:为什么实例B里边没有b属性?
function A() {
this.a = "111";
b = "222";
console.log(this.a);
console.log(this.b);
}
A(); //111 //222
const B = new A();
B; // {a: '111'}
可以这么想,A是构造函数,在执行new操作的时候,A的this指向B,
然后给B添加了this上边的属性a。所以B实例里边没有b属性。
Object.create()
是 JavaScript 中的一个内置方法,用于创建一个新对象,并指定其原型对象和属性。语法如下:
Object.create(proto, [propertiesObject]);
prototype:这将作为新对象的原型的对象。如果 prototype 是 null,那么新创建的对象的原型将会是 null。
propertiesObject(可选):一个描述要添加到新对象的一个或多个属性的对象字面量。(包含value、writable、configurabble等字段)
new Object() 通过构造函数来创建对象, 添加的属性是在自身实例下。
Object.create() es6创建对象的另一种方式,可以理解为继承一个对象, 添加的属性是在原型下。
Object.create的基本实现原理
思路:将传入的对象作为原型
function create(obj) {
function F() {}
F.prototype = obj;
return new F();
}