Object.create和new创建对象

Object.createnew

先看一个例子:

 function Animal(name,sex) { 
        this.name = name;
        this.sex = sex;
     }
     Animal.prototype.getName = function (){
         return this.name;
     }
    let obj1 = new Animal("zyy","male");
    let obj2 = Object.create(Animal.prototype);
    console.log(obj1)
    console.log(obj2)
    console.log(obj1 instanceof Animal)//true
    console.log(obj2 instanceof Animal)//true
    console.log(obj1.__proto__ === Animal.prototype)//true
    console.log(obj2.__proto__ === Animal.prototype)//true

在这里插入图片描述

分析:obj1obj2都为Animal的对象。实际上obj1就是Animal的对象,obj2F的对象(怎么出来了一个F???),具体Object.createnew怎么实现的?接下来再看

1. new操作符做的事情
  • 创建一个空对象
  • 给该对象的__proto__赋值为fn.prototype,即设置原型链
  • 执行fn,并将obj作为内部this
  • 如果fn有返回值,则将其作为new操作返回内容,否则返回obj
 function test(a,b) { 
        this.a = a;
        this.b = b;
     }
     //new操作符做的事情
    function myNew(fn,args){
        let obj = new Object();
        obj.__proto__ = fn.prototype;
        let result = fn.apply(obj,args);
        if(typeof(result) === "object") return result;//如果fn执行返回的为一个对象时返回该对象
        return obj;
    }
    console.log(myNew(test,[1,2]))
    console.log(new test(1,2))

2. Object.create做的事情
  • 各种出错判断
  • 创建一个在外部被隐藏的F函数
  • 创建并返回该F函数的对象

搬来官网的Polyfill方法

  if (typeof Object.create !== "function") {
        Object.create = function(proto, propertiesObject) {
            if (typeof proto !== "function" || typeof proto !== "object") {
                throw new TypeError('Object prototype may only be an Object: ' + proto);
            } else if (proto === null) {
                throw new TypeError('Object prototype may only be an Object: ' + proto);
            }
            if (typeof propertiesObject != 'undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");
            function F() {}
            F.__proto__ = proto;
            return new F();
        }
    }

搬来官网的例子(曾经让我无法理解的例子

// Shape - 父类(superclass)
function Shape() {
  this.x = 0;
  this.y = 0;
}

// 父类的方法
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  console.info('Shape moved.');
};

// Rectangle - 子类(subclass)
function Rectangle() {
  Shape.call(this); // call super constructor.
}

// 子类续承父类
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?',
  rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
  rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.'

输出:
在这里插入图片描述

理解:Rectangle.prototype实际上为Object.create返回的F函数的一个实例,而该实例的__proto__Shape.prototype,所以该实例实际上也为Shape的一个实例,从而rect.__proto__Shape的一个实例且rect继承了Shape类。

下图为它们之间的关系:
在这里插入图片描述

然后我们又回到第一个例子:
在这里插入图片描述
我们可以很容易发现,使用Object.create方式创建的对象并没有继承其父类Animal内部的的属性,这是因为,使用Object.create创建出来的对象的构造函数为F,且其被隐藏,在创建时并没有将其创建的实例与Animal函数进行绑定,故无法访问到Animal函数中的内部属性,但是可以访问到其原型链上的属性与方法。

既然已经知道了其原理,那么难道通过Object.create方法不能创建自己的内部属性吗?当然不是

Object.create创建自己的属性

该方法的第二个参数便是可以传入创建对象的属性配置集合。其中的具体配置与Object.defineProperties中属性的配置相同,可参考 Object.defineProperties

let o = Object.create(Object.prototype, {
  // foo会成为所创建对象的数据属性
  foo: { 
    writable:true,
    configurable:true,
    value: "hello" 
  },
  // bar会成为所创建对象的访问器属性
  bar: {
    configurable: false,
    get: function() { return 10 },
    set: function(value) {
      console.log("Setting `o.bar` to", value);
    }
  }
});

打印输出:
在这里插入图片描述

Object.create多继承

由于Object.create方法无法将父元素的属性/方法继承,只能继承其原型上的属性和方法。故我们需要先采用构造继承的方式将父元素的属性/方法继承,然后再通过Object.create的方式继承父元素原型上的属性和方法。由于一个对象不能从属于两个父类,故如果要实现多继承,只能将另一个父类的原型方法以及原型属性添加到My的原型上,另一个父类的方法和属性可以通过构造继承的方式将其继承。

function Person(name, age) { 
    this.name = name;
    this.age = age;
 }
 function Animal(height, weight) {
    this.height = height;
    this.weight = weight;
 }

 function My() {
     Person.call(this, "zyy", 21);
     Animal.call(this, 160, 110);
 }

 My.prototype = Object.create(Animal.prototype);
 Object.assign(My.prototype, Person.prototype);
 My.prototype.constructor = My;
 console.log("myObject=====", new My())

在这里插入图片描述

使用Object.create继承有什么好处呢?

猜你喜欢

转载自blog.csdn.net/weixin_43314846/article/details/106817408