setPrototypeOf 与 Object.create区别

6,834 阅读2分钟

前言

设置原型的目的是进行对象间的委托,可以让一个对象获得另一个对象的一些属性或者方法。关于设置一个对象的原型,JS提供了俩种方式。一种是通过setPrototypeOf,另一种是Object.create,通过了解二者的区别可以让我们能够根据情况去选择适合的方式。

用法

若存在A和B俩个函数,让A的原型指向B

1.setPrototypeOf

Object.setPrototypeOf(A.prototype,B.prototype)

2.Create

A.prototype = Object.create(B.prototype)

俩者都可以达到设置对象原型的功能,但是具体表现上有一些区别。

比较

假设有Animal和Plants俩个函数用于生成对象,并在原型上具备一些方法。 然后我们让Animal的原型指向Plants

初始代码如下

    function Animal (name,sound) {
        this.name = name
        this.sound = sound
    }
    
    Animal.prototype.shout = function () {
        console.log(this.name + this.sound)
    }
    
    let dog = new Animal('pipi','wang!wang!')
    
    // 定义Plants
    function Plants (name) {
        this.name = name
        this.sound = null
    }
    
    // 函数接收参数用于区分
    Plants.prototype.shout = function (xssss) {
        console.log(this.name + this.sound +'plants tag')
    }
    
    Plants.prototype.genO2 = function () {
        console.log(this.name + '生成氧气。')
    }

使用create

    Animal.prototype = Object.create(Plants.prototype)
    console.log(Animal.prototype)
    /*
    Plants {}
        __proto__:
            shout: ƒ (xssss)
            genO2: ƒ ()
            constructor: ƒ Plants()
            __proto__: Object
    */
    let cat = new Animal('mimi','miao~miao~')
    
    dog.shout() // pipi wang!wang!
    cat.shout() // mimi miao~miao~ plants tag
    cat.genO2() // mimi 生成氧气。

使用setPrototypeOf

    Object.setPrototypeOf(Animal.prototype,Plants.prototype)
    console.log(Animal.prototype)
    /*
    Plants {shout: ƒ, constructor: ƒ}
        shout: ƒ (xssss)
        constructor: ƒ Animal(name,sound)
        __proto__:
        shout: ƒ ()
        genO2: ƒ ()
        constructor: ƒ Plants()
        __proto__: Object
    */
    let cat = new Animal('mimi','miao~miao~')
    dog.shout() // pipi wang!wang!
    cat.shout() // mimi miao~miao~
    cat.genO2() // mimi 生成氧气。

总结

使用Object.create,Animal.prototype将会指向一个空对象,空对象的原型属性指向Plants的prototytpe。所以我们不能再访问Animal的原有prototypoe中的属性。Object.create的使用方式也凸显了直接重新赋值。

使用Object.setPrototypeOf则会将Animal.prototype将会指向Animal原有的prototype,然后这个prototype的prototype再指向Plants的prototytpe。所以我们优先访问的Animal,然后再是plants。

在进行俩个原型之间的委托时使用setPrototypeOf更好,Object.create更适和直接对一个无原生原型的对象快速进行委托。

执行的时候分开执行才能看到差异,你把它们俩全放到一段执行,已经create过了,那肯定结果是一样的啊。。。。。 这篇文章写了快3年了吧,我现在已经记不清当时怎么写的了,不过得出一个结论肯定经过反复的验证才敢发出来,你觉得不对,也要做多次的验证去证明才行啊,不是简单的把代码执行了就行了的事情。