首页 文章

Object.create原型链

提问于
浏览
4

初步问题

昨天我读到了ECMAScript 5 Object.create()我想用这个方法开始在我的代码中构建原型链,而不是设置原型及其构造函数,我喜欢你可以直接设置可写的可配置等 .

我试过这样的

function printobject(msg, obj) {
    if (msg) {
        document.write("<b>" + msg + "</b><br>");
        document.write("<hr><br>");
    }
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) {
            if (obj[prop].toString() !== "[object Object]") {
                document.write(prop + " : " + obj[prop] + "<br>");
            }
            else {
                document.write("<b>" + prop + " : " + obj[prop] + "</b><br>");
                printobject("", obj[prop]);
            }
        }
    }
    if (msg) {
        document.write("<br><hr><br>");
    }
};
var base = {
    extend: function () { //extend this Object
        var args = Array.prototype.slice.call(arguments);
        printobject("Arguments to Extend", args)
        var that = Object.create(this, (args ? args.shift() : {}));
        var arg = args.shift() || {};
        printobject("Copy Properties to New Object", arg);
        for (var prop in arg) {
            that[prop] = arg[prop];
        }
        // Object.freeze(that);       
        return that;
    },
    create: function () { //Creates new instances of the Object
        var that = Object.create(this, {
            extend: {
                value: null,
                writable: false,
                configurable: false
            }, //sets extend and create to null so you cant create a new instance when used create ( use extend instead);
            create: {
                value: null,
                writable: false,
                configurable: false
            }
        });
        that.init.apply(that, arguments); //call init function for the new created object; 
        return that;
    },
    init: function () {
        printobject("No Initfunction supplied for New Object", this);
    } // Empty init function for fallback
}
var Human = base.extend({
    name: {
        value: "test"
    }
}, {
    init: function (name) {
        alert(name + " has been created");
        this.name = name;
    },
    walk: function () {
        alert(this.name + " walks");
    }
});
var Human1 = Human.create("test2");
//alert("Human1 - Name:" + Human1.name);
Human1.walk();
Human.walk = function () {
    alert("Walk has been overwritten")
}; //Object freezed 
Human1.walk();
Human1.create = function () {
    alert("Overwrite create");
}; //Doesnt exist in created     Object
Human1.create(); ?
  • Human 中给出的方法只在ram中存在一次吗?和 Human1.walk() 指向它?

  • 我想知道这是否是这样做的正确方法?我是JavaScript的新手 .

这是jsfiddle上的代码 .

答案

首先,很多东西让事情变得清晰了=)但是,1:当我这样做时,实例继承自构造函数的原型(?)

Nothing = {};
function base() {
this.inherit = function(constructor) {
    alert("inherit");
    var obj = constructor;
    obj.constructor = constructor;
    obj.prototype = this;
   return obj ;  
 }
 ;}
base.prototype = Nothing;
base.constructor = base;
var Top = new base();       
var Human = Top.inherit(function(name) {
        this.name = name;
});
var Paul = new Human("Paul");
alert(Paul.name);
alert(Paul instanceof Human); //true `

2:所以instanceof运算符不会破坏这个代码,(它对函数起作用只对我来说很明显)

但是这样编写,Paul仍然从Top的原型继承了inherit()方法,我需要覆盖它但是如果我不想让Human的实例继承该方法,我该怎么做呢?

除了使用Objkect.defineproperty(?)之外,我无法设置像wrtable这样的属性描述符

那么使用Object.create()从Objects继承和设置原型和构造函数的主要好处是什么? =)

3:哦thx,是的,那就是defs那不是基础对象的扩展=)thx的建议=)

感谢所有的努力=)

答案

好吧,当我这样做

Nothing = {} base.prototype = Nothing;

这不会阻止s.o上传原型链直到Object.prototype?如果没有,有没有办法做到这一点? =)将(Object.create(null);)执行此操作,

我以为我必须设置

base.prototype.constructor = base;

因为否则,原型的构造函数

var Top = new base();

如果原型被设置为Nothing,Nothings'或者不会从原型链的某个地方继承构造函数 - >

Top instanceof base // false

更新

我最终以这样的方式做到了:

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(extension,desc) {
        // instances inherit from the proto objects
        var newInst = Object.create(this.proto, desc);
        if(this.proto.childExtendable) //if Subclass allows its Children to be Extendible, do so
            newInst.extend(extension);
        if(newInst.init||this.proto.init) //4
            newInst.init()                          
        return newInst
    },
    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);
        props.protect = this.protect;
        if(props.childExtendable)
            props.extend = this.extend;
        this.extend.call(sub.proto, props);
        return sub;
    }, 
    extend: function (props) {
        for (var prop in props) {
            var propmatch = prop.match(/(.*?)__(.{1,5}?)__(.*)/)||["",prop,"",""];
            this[propmatch[1]+propmatch[3]] = props[prop];
            if(propmatch[2])
                this.protect(propmatch[1]+propmatch[3],propmatch[2]);           
        }
    },
    protect: function(prop,flags) { //with each call it toggles the given flags,  so you can protect funcitons given to the inherit function ;; //This should be available to all childs, but adding it to the base.proto, it changes Object.prototyppe ( therefore not a good idea)
        var d  = Object.getOwnPropertyDescriptor(this, prop);
        if (flags.match(/w/)){
             Ti.API.info("Setting writable for propertie " + prop + " in Object " + this + " to " + !d.writable);
             Object.defineProperty(this, prop, {writable:!d.writable});};
        if (flags.match(/c/)){
            Ti.API.info("Setting configurable for propertie " + prop + "in Object " + this);
            Object.defineProperty(this, prop, {configurable:!d.configurable});};
        if (flags.match(/e/)){
            Ti.API.info("Setting enumerable for propertie " + prop + "in Object " + this);
            Object.defineProperty(this, prop, {configurable:!d.enumerable});};
        if (flags.match(/a/)){
            Ti.API.info("Setting enumerable for propertie " + prop + "in Object " + this);
            Object.preventExtensions(this);};
   },
    init: function() {},
    proto: Object.prototype // or null, if you want
};

var Human = base.inherit({ //will be put in Human.proto
    childExtendable:true,
    init:function() {alert("Humans Init for all Instances")},
    say:function() { alert("Hi, I'm "+this.name); }
});
Human.proto.name = "default"; // You could use an argument to the inherit function
                              // I just want to make clear what happens
Ti.API.info(Object.getPrototypeOf(Function) + "a");
var paul = Human.create({ //extends this object
    name: "Paul",
    test: function() {alert("test")},
    init__wce__: function() {alert("Pauls Own Init")},
    say__w__ : function() { alert("Hi, I'm" + this.name + "s Own Function")}
});
paul.name = "Paul";           // and again, the create function might do it for you
paul.say = function() {alert("Pauls say is overwritten")} // define init without __wce__ and it will be overwritten
paul.say(); // -> "Hi, I'm Paul"

只要有人关心
但是,jsfiddle不会运行这个,Titanium会按预期执行每个可能的某些严格模式(??)

1 回答

  • 4

    Human中给出的方法只在ram中存在一次吗?

    是 .

    和Human1.walk()指向它?

    是 . 更正确的是, Human1Human 的原型有一个指向它的属性"walk" .

    我想知道这是否是这样做的正确方法?我是JavaScript的新手 .

    我会说不,因为它过于复杂,而且有些错误 .

    • Human实例的原型链包括 base . 多数民众多,你需要为每个实例覆盖create和extend方法 . 通常的方法是"classes"包含一个"prototype"属性,其实例继承该属性 .

    • 您的模式打破了 instanceof 运算符,尽管这可能是一个小问题 .

    • extend方法令人困惑 . 它不会扩展对象本身,而是创建一个从它继承的新对象,并在其上设置属性和属性描述符 . 更好地实现同样的事情:

    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;
    };
    

    对于扩展的问题:

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

    很没用 . 首先,默认情况下,任何函数的"prototype"属性都是(几乎)空对象,直到您覆盖它为止 . 无需将其设置为 nothing :-)

    而“构造函数”属性通常是一个原型属性 . 它将被所有实例继承,指向thei构造函数 . 您只需要在覆盖函数的“prototype”属性时显式设置它 - 并且您不应该在函数本身上设置“构造函数”属性 .

    (继续:)我虽然更多关于这样的解决方案:

    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"
    

    这样, paul 继承自 Human.proto 继承自 base.proto ,即 Object.prototypenull . 并且 Human 继承自 base ,即您可以使用 Human.inherit() 轻松构建"subclass" .

    是否要使用属性描述符绝对是您的选择 . 无论你在哪里创建并扩展它,你都可以使用 Object.defineProperties (或 Object.create 的第二个参数)以及 Object.extend (通常的复制方法) .

    使用Object.create()从Objects继承和设置原型和构造函数有什么主要好处?

    这是一个设计选择 . Object.create 不会在构建对象上调用[构造函数]函数 . 有关详细信息,请参阅Using "Object.create" instead of "new"Understanding the difference between Object.create() and new SomeFunction() .

    base.prototype = {};不会阻止s.o上传原型链直到Object.prototype?

    是 . 一个空对象(由您的文字创建)在其链中仍然有 Object.prototype . 唯一的方法是使用 Object.create(null) (不能使用 new 进行填充) .

    我认为我必须设置base.prototype.constructor = base;

    不是在这种情况下 . 拥有 function base(){...} ,将其"prototype"属性设置为 {constructor: base} 绝对没有任何变化(除了现在可枚举的"constructor") - 每个函数都有这样一个默认的proto对象,包括"constructor" .

    所以只有在你需要的时候用一个新对象覆盖"prototype"属性,就像它让它从另一个函数的原型继承一样,你可以添加这个方便属性: MySubClass.prototype = Object.create(MyClass.prototype, {constructor:{value:MySubClass}});

    否则......

    什么都不会发生 . 没有语言功能(如 instanceof ),原型对象上的"constructor"属性是必需的,很少使用 . 没有什么能打破 .

相关问题