Object.create Prototype Chains

六眼飞鱼酱① 提交于 2019-11-29 15:13:59
Bergi

Do the methods given in Human only exist once in the ram?

Yes.

and Human1.walk() points to it?

Yes. To be more correct, the prototype of Human1, Human, has a property "walk" pointing to it.

I wonder if this is the right Approach of doing it like this? I'm relatively new to JavaScript.

I'd say no, because it is overly complicated, and partly wrong.

  • The prototype chain of Human instances includes base. Thats odd, and you need to overwrite the create and extend methods for every instance. The usual method is that "classes" contain a "prototype" property, from which their instances inherit.
  • Your pattern breaks the instanceof operator, although that might be a minor issue.
  • The extend method is confusing. It does not extend the object itself, but create a new object inheriting from it and setting properties and property descriptors on that. Better implementation of the same thing:

base.inherit = function(descs, props) {
    // creates a new object inheriting from this
    var that = Object.create(this, descs); // will even work when undefined
    if (props)
        for (var prop in props)
            that[prop] = props[prop];
    // Object.freeze(that);       
    return that;
};

To the extended question:

base.prototype = Nothing​;
base.constructor = base;

is quite useless. First, the "prototype" property of any function is an (nearly) empty object by default, until you overwrite it. No need to set it to nothing :-)

And the "constructor" property is usually a prototype property. It would be inherited by all instances, pointing to thei constructor function. You only need to set it explicitly when overwriting a function's "prototype" property - and you should not set the the "constructor" property on the function itself.

(continuing:) I though more about a solution like this:

var base = {
// a tiny little selfmade prototypical inheritance system
// you are free to add function arguments for extending the created objects
// neither instanceof nor .constructor is featured, because "classes" are no functions
    create: function([desc]) {
        // instances inherit from the proto objects
        return Object.create(this.proto, [desc]);
    },
    inherit: function([props]) {
        // the "class" inherits static methods from the class
        var sub = Object.create(this);
        // and the proto objects inherits from the parent proto
        sub.proto = Object.create(this.proto);
        [Object.extend(sub.proto, props);]
        return sub;
    },
    proto: Object.prototype // or null, if you want
};

var Human = base.inherit();
Human.proto.name = "default"; // You could use an argument to the inherit function
                              // I just want to make clear what happens
Human.proto.say = function() { alert("Hi, I'm "+this.name); };

var paul = Human.create();
paul.name = "Paul";           // and again, the create function might do it for you
paul.say(); // -> "Hi, I'm Paul"

This way, paul inherits from Human.proto inherits from base.proto which is Object.prototype or null. And Human inherits from base, i.e. you could easily build a "subclass" with Human.inherit().

Whether you want to use property descriptors or not is absolutely your choice. Everywhere you create something and extend it, you might use Object.defineProperties (or the second argument to Object.create) as well as Object.extend (the usual for-in-copy-method).

what are the main benefits from using Object.create() to inherit from Objects vs Setting the prototypes and construcotrs?

It's a design choice. Object.create won't call a [constructor] function on the built object. See Using "Object.create" instead of "new" or Understanding the difference between Object.create() and new SomeFunction() for further information.

base.prototype = {}; doesnt prevent s.o to go up the prototype chain til Object.prototype?

Yes. An empty object (as created by your literal) still has Object.prototype in its chain. The only way to do this is Object.create(null) (not shim-able with new).

i thought that i had to set base.prototype.constructor = base;

Not in this case. Having a function base(){...}, setting its "prototype" property to {constructor: base} changes absolutely nothing (except that "constructor" in enumerable now) - every function has such a default proto object including the "constructor".

So only when you need to overwrite the "prototype" property with a new object, as it happens when letting it inherit from another function's prototype, you might add this convenience property: MySubClass.prototype = Object.create(MyClass.prototype, {constructor:{value:MySubClass}});

otherwise...

Nothing would happen. The "constructor" property on prototype objects is needed for no language features (like instanceof), and is seldom used. It's likely that nothing breaks.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!