Object.create介绍

104 阅读2分钟

Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__

语法

js
复制代码
 // 返回一个新对象,带着指定的原型对象和属性。
Object.create(proto,[propertiesObject])
  • proto:新创建对象的原型对象,必须为null或者原始包装对象,否则会抛出异常
  • propertiesObject:可选参数,需要是一个对象,该传入对象的自有可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符

不传递propertiesObject

js
复制代码
const obj = {
  name: 'nordon'
};

const newObj = Object.create(obj);

此时打印newObj只是一个{},传递的obj会当作newObj的原型,此时name属性属于newObj.prototype上的属性,并不是obj.name

传递propertiesObject

js
复制代码
const obj = {
    name: "nordon",
};

const newObj = Object.create(obj, {
    name: {
        value: "wy",
        writable: true,
        configurable: true,    
        enumerable: true
    },
    age: {
        value: 12,
        writable: true,
        configurable: true,
        enumerable: true
    },
});

此时newObj

js
复制代码
{
  name: 'wy',
  age: 12
}

优势

为何要使用Object.create创建对象,而不直接使用对象字面量的形式或者使用Object创建对象呢?

js
复制代码
const obj = {
    name: "nordon",
};

const newObj = Object.create(obj);
const nweObj2 = Object(obj);

objnewObjnewObj2依次打印

image-20211106142103881.png

通过输出可以看到通过字面量和使用Object创建的对象是一致的,且其引用地址是一致的:obj === newObj2true

通过Object.create创建的对象会在objnewObj之间增加一层,这个时候引用地址是解耦的:obj === newObj为false,这样的好处可以保证新创建的对象和原有对象解耦,当我们操作newObj时并不会影响原有数据

应用

利用Object.create实现继承

js
复制代码
function Person(name) {
  this.name = name;
  this.permission = ["user", "salary", "vacation"];
}

Person.prototype.say = function () {
  console.log(`${this.name} 说话了`);
};

function Staff(name, age) {
  Person.call(this, name);
  this.age = age;
}

Staff.prototype = Object.create(Person.prototype, {
  constructor: {
      // 若是不将Staff constructor指回到Staff, 此时的Staff实例zs.constructor则指向Person
      value: Staff,
  },
});

Staff.prototype.eat = function () {
  console.log("吃东西啦~~~");
};

创建一个干净的对象,第一个参数传递null即可实现

js
复制代码
const obj = Object.create(null);

通过控制台输出可以看到obj非常干净

image-20211106143010589.png

prototype上不会存在很多通过继承的属性和方法,非常的简洁

实现

js
复制代码
const create = function (proto) {
    if (typeof proto !== "object" && typeof proto !== "function") {
        // 类型校验
        throw new TypeError("proto必须为对象或者函数");
    } else if (proto === null) {
        // null 特殊处理
        throw new Error("在浏览器中暂不支持传递null");
    }

    // 创建一个构造函数
    function F() {}
    // 更改其 prototype
    F.prototype = proto;

    // 返回构造的实例, 这个时候返回的实例和传入的 proto中间多了一层 F
    return new F();
};

通过实现一个简易版本的Object.create,可以更清晰的看到其和object创建对象的差异

文章出处:juejin.cn/post/702770…