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 に 1 回しか存在しませんか? そして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 演算子はこの Code で壊れません (関数に対してのみ機能することは私には明らかです)

しかし、このように書いても、Paul は依然として Top のプロトタイプから inherit() メソッドを継承しており、それを上書きする必要があります。

そして、Objkect.defineproperty (?) を使用しない限り、wrtable のようなプロパティ記述子を設定できません。

Object.create() を使用して Objects から継承することと、プロトタイプとコンストラクターを設定することの主な利点は何ですか? =)

3: ああ thx、はい、それは基本オブジェクトの拡張ではありません =) 提案のための thx =)

すべての努力のためのThx =)

答え

わかりましたので、私がそうするとき

なし = {}

base.prototype = なし;

これは Object.prototype までプロトタイプチェーンを上ることを妨げませんか? そうでない場合、これを行う方法はありますか? =) ( Object.create(null); ) はこれを行いますか?

そして、私は設定しなければならないと思った

base.prototype.constructor = ベース;

そうでなければ、のプロトタイプコンストラクター

var Top = new base();

プロトタイプが Nothing に設定されている場合、Nothings になるか、プロトタイプ チェーンのどこかからコンストラクターを基本継承しません ->

baseof のトップ インスタンス // 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 は、おそらくいくつかの厳密なモード (??) を期待どおりに実行します。

4

1 に答える 1

4

Human で指定されたメソッドは、ram で一度だけ存在しますか?

はい。

Human1.walk() はそれを指していますか?

はい。より正確には、 、 、 のプロトタイプにはHuman1Humanそれを指すプロパティ "walk" があります。

これは、このようにする正しいアプローチなのだろうか?私はJavaScriptに比較的慣れていません。

それは非常に複雑で、部分的に間違っているので、私はノーと言います。

  • Human インスタンスのプロトタイプ チェーンには が含まれますbase。これは奇妙で、すべてのインスタンスの create メソッドと extend メソッドを上書きする必要があります。通常の方法では、「クラス」に「プロトタイプ」プロパティが含まれ、そこからインスタンスが継承されます。
  • あなたのパターンはinstanceofオペレーターを壊しますが、それは小さな問題かもしれません。
  • 拡張メソッドは紛らわしいです。オブジェクト自体を拡張するのではなく、オブジェクトから継承し、プロパティとプロパティ記述子を設定する新しいオブジェクトを作成します。同じことのより良い実装:

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:-)

また、「コンストラクター」プロパティは通常、プロトタイプ プロパティです。コンストラクター関数を指して、すべてのインスタンスに継承されます。関数の「プロトタイプ」プロパティを上書きするときにのみ明示的に設定する必要があります。関数自体に「コンストラクタ」プロパティを設定しないでください。

(継続:)私はこのような解決策についてもっと考えています:

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"

このように、paulinherits from Human.protoinherits from base.protowhich isObject.prototypeまたはnull. Humanから継承します。つまり、baseを使用して「サブクラス」を簡単に構築できますHuman.inherit()

プロパティ記述子を使用するかどうかは、完全にあなたの選択です。何かを作成して拡張する場合はどこでも、Object.defineProperties(または の 2 番目の引数Object.create) とObject.extend(通常の for-in-copy-method) を使用できます。

Object.create() を使用してオブジェクトから継承することと、プロトタイプとコンストラクターを設定することの主な利点は何ですか?

デザイン選びです。Object.create構築されたオブジェクトで [constructor] 関数を呼び出しません。詳細については、「new」の代わりに「Object.create」を使用する、Object.create() と new SomeFunction() の違いを理解するを参照してください。

base.prototype = {};Object.prototypeまでプロトタイプチェーンを上ることを妨げませんか?

はい。空のオブジェクト(リテラルによって作成されたもの)はまだObject.prototypeチェーンにあります。これを行う唯一の方法はObject.create(null)( でシム可能ではないnew) です。

設定しなければならないと思ったbase.prototype.constructor = base;

この場合ではありません。を持ち、function base(){...}その「プロトタイプ」プロパティを に設定しても、{constructor: base}何も変更されません (「コンストラクター」が現在列挙可能であることを除いて) - すべての関数には、「コンストラクター」を含むそのようなデフォルトのプロト オブジェクトがあります。

したがって、別の関数のプロトタイプから継承させるときに発生するように、「prototype」プロパティを新しいオブジェクトで上書きする必要がある場合にのみ、次の便利なプロパティを追加できます。MySubClass.prototype = Object.create(MyClass.prototype, {constructor:{value:MySubClass}});

それ以外は...

何も起こりません。プロトタイプ オブジェクトの「コンストラクター」プロパティは、言語機能 ( などinstanceof) には必要なく、めったに使用されません。何も壊れていない可能性があります。

于 2012-06-28T11:24:32.933 に答える