JS手撕(五) new、Object.create()、Object.assign()

2023-01-01 16:12:58 浏览数 (1)

JS手撕(五)    new、Object.create()、Object.assign()

new关键字

实现new关键字,首先得了解一下new关键字究竟干了什么。

new关键字主要干了四件事:

  1. 创建一个新对象
  2. 设置该对象的原型为构造函数的原型(保留原有原型链)
  3. 执行构造函数,this指向新对象
  4. 如果构造函数返回值是对象,返回该对象。否则,返回1创建的对象
代码语言:javascript复制
function myNew(Func, ...args) {
  // 1. 创建一个新对象
  const obj = Object.create(null);

  // 2. 设置该对象的原型为构造函数的原型(保留原有原型链)
  Object.setPrototypeOf(obj, Func.prototype);

  // 3. 执行构造函数,`this`指向新对象
  const result = Func.apply(obj, args);

  // 如果构造函数返回值是对象,返回该对象。否则,返回`1`创建的对象
  return (typeof result === 'object' && result !== null)
    ? result
    : obj;
}

因为Object.create()可以使用现有的对象来作为新建对象的原型,所以第12步是可以合在一起的。

即:

代码语言:javascript复制
const obj = Object.create(Func.prototype);

测试:

代码语言:javascript复制
function Person(name, age) {
  this.name = name;
  this.age = age;

  // return { test: 'test' }
}

const person = myNew(Person, 'clz', 21);
console.log(person);                      // Person {name: 'clz', age: 21}

Object.create()

Object.create()方法用于创建一个新对象,使用现有的对象来作为新建对象的原型。

实现一个低配版的,不考虑第二个参数。

核心就是一种实现继承的方法。(道格拉斯·克罗克福德在一篇文章中介绍的一种实现继承的方法)

代码语言:javascript复制
function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

完整代码:

代码语言:javascript复制
function object(o) {
  function F() { }
  F.prototype = o;
  return new F();
}


Object.myCreate = function (proto) {
  const obj = object(proto);
  return obj;
}

测试:

代码语言:javascript复制
function Animal(type) {
  this.type = type;
}

const pig = Object.myCreate(Animal);
pig.type = 'pig';
console.log(pig);     // F {type: 'pig'}

还有一个问题:我们有时候会使用Object.create(null)创建一个没有原型的对象,但是现在是有问题的。

代码语言:javascript复制
const obj = Object.myCreate(null);
console.log(obj);     

所以还需要判断参数是null的时候,设置原型为null来实现能够创建一个没有原型的对象。

代码语言:javascript复制
Object.myCreate = function (proto) {
  const obj = object(proto);

  if (proto === null) {
    Object.setPrototypeOf(obj, null);
  }

  return obj;
}

Object.assign()

Object.assign()将所有可枚举并且是自身属性从一个或多个源对象复制到目标对象,返回修改后的对象。

代码语言:javascript复制
Object.myAssign = function (target, ...sources) {
  sources.forEach(source => {
    for (const key in source) {
      // 可枚举

      if (source.hasOwnProperty(key)) {
        // 自身属性
        target[key] = source[key];
      }
    }
  })

  return target;
}

测试:

代码语言:javascript复制
const target = {
  name: 'clz'
};

const source1 = {
  name: '赤蓝紫'
};
const source2 = {
  age: 21
};
const source3 = {
  age: 999
};

const result = Object.myAssign(target, source1, source2, source3);
console.log(result);              // {name: '赤蓝紫', age: 999}
console.log(target === result);   // true 

参考

GitHub - qianlongo/fe-handwriting: 手写各种js Promise、apply、call、bind、new、deepClone….

JavaScript之手撕new_战场小包的博客-CSDN博客

0 人点赞