New方法

213 阅读2分钟

new目的

  1. 实例可以访问到构造函数原型中的属性(实例对象的隐式原型__proto__指向构造函数的原型prototype)
  2. 实例可以访问到构造函数中的属性(使用 apply,改变构造函数 this 的指向到新建的对象,也就是新对象继承了构造函数)

new核心行为:创建一个新对象,设置其原型,然后调用构造函数并返回结果。

在《JavaScript模式》这本书中,new的过程说的比较直白,当我们new一个构造器,主要有三步:

  1. 首先创建一个空的对象
  2. 空对象的__proto__属性指向构造函数的原型对象prototype
  3. 改变构造函数 this 的指向到新建的对象
  4. 如果构造函数返回一个非基本类型的值,则返回这个值,否则返回上面创建的对象

实现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();
}