क्या किसी वस्तु के गैर-प्रवर्तनीय विरासत में मिली संपत्ति के नाम प्राप्त करना संभव है?


99

जावास्क्रिप्ट में हमारे पास किसी वस्तु के गुण प्राप्त करने के कुछ तरीके हैं, जो इस बात पर निर्भर करता है कि हम क्या पाना चाहते हैं।

1) Object.keys(), जो एक वस्तु, एक ECMA5 विधि के सभी, अपने स्वयं के अनगिनत गुणों को लौटाता है।

2) एक for...inलूप, जो किसी वस्तु के सभी प्रवर्तनीय गुणों को लौटाता है, भले ही वे स्वयं के गुण हों, या प्रोटोटाइप श्रृंखला से विरासत में मिले हों।

3) Object.getOwnPropertyNames(obj)जो किसी वस्तु के सभी गुणों को वापस लाता है, प्रगणनीय है या नहीं।

हमारे पास ऐसे तरीके भी हैं hasOwnProperty(prop)जो हमें यह जांचने देते हैं कि क्या कोई संपत्ति विरासत में मिली है या वास्तव में उस वस्तु से संबंधित है, और propertyIsEnumerable(prop)जैसा कि नाम से पता चलता है, हमें यह जांचने देता है कि क्या कोई संपत्ति नाममात्र है।

इन सभी विकल्पों के साथ, किसी वस्तु की गैर-गणना योग्य, गैर-स्वयं की संपत्ति प्राप्त करने का कोई तरीका नहीं है , जो कि मैं करना चाहता हूं। क्या इसे करने का कोई तरीका है? दूसरे शब्दों में, क्या मुझे किसी तरह विरासत में मिली गैर-संपत्ति की सूची मिल सकती है?

धन्यवाद।


4
आपके प्रश्न का उत्तर उस प्रश्न से मिलता है, जो मैं पूछने जा रहा था: गैर-गुणांक गुणों का निरीक्षण कैसे करें (केवल यह पता लगाने के लिए कि पूर्वनिर्धारित वस्तुओं में क्या उपलब्ध है)। अंत में मैंने getOwnPropertyNames पाया! :-)
मार्कस

1
@marcus :-) यही तो सब के बारे में है!
dkugappi

जवाबों:


115

चूँकि getOwnPropertyNamesआप गैर-गुणकारी गुण प्राप्त कर सकते हैं, आप इसका उपयोग कर सकते हैं और इसे प्रोटोटाइप श्रृंखला में चलने के साथ जोड़ सकते हैं।

function getAllProperties(obj){
    var allProps = []
      , curr = obj
    do{
        var props = Object.getOwnPropertyNames(curr)
        props.forEach(function(prop){
            if (allProps.indexOf(prop) === -1)
                allProps.push(prop)
        })
    }while(curr = Object.getPrototypeOf(curr))
    return allProps
}

मैंने सफारी 5.1 पर परीक्षण किया और प्राप्त किया

> getAllProperties([1,2,3])
["0", "1", "2", "length", "constructor", "push", "slice", "indexOf", "sort", "splice", "concat", "pop", "unshift", "shift", "join", "toString", "forEach", "reduceRight", "toLocaleString", "some", "map", "lastIndexOf", "reduce", "filter", "reverse", "every", "hasOwnProperty", "isPrototypeOf", "valueOf", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "propertyIsEnumerable", "__lookupSetter__"]

अद्यतन: कोड को थोड़ा सा जोड़ा (रिक्त स्थान, और घुंघराले ब्रेसिज़, और फ़ंक्शन नाम में सुधार)

function getAllPropertyNames( obj ) {
    var props = [];

    do {
        Object.getOwnPropertyNames( obj ).forEach(function ( prop ) {
            if ( props.indexOf( prop ) === -1 ) {
                props.push( prop );
            }
        });
    } while ( obj = Object.getPrototypeOf( obj ) );

    return props;
}

1
धन्यवाद toby, एक बात जो मुझे समझ में नहीं आती है वह है रेखा: while(curr = Object.getPrototypeOf(cure))जैसा कि सशर्त कथन एक तुलना ऑपरेटर के बजाय एक असाइनमेंट ऑपरेटर का उपयोग करता है, क्या यह हमेशा सही नहीं होगा? या क्या यह रेखा अनिवार्य रूप से जाँच रही है कि क्या "वक्र" में एक प्रोटोटाइप है?
dkugappi

2
@AlexNabokov यह गलत होगा अगर परिणाम गलत है, जो तब होगा जब प्रोटोटाइप श्रृंखला के शीर्ष पर Object.getPrototypeOf(cure)वापस आ जाएगा null। मुझे लगता है कि यह कोई परिपत्र प्रोटोटाइप श्रृंखला नहीं है!
डोमिनिक

2
@ एलेक्स Function.prototypeकभी भी "मूल" प्रोटोटाइप नहीं हो सकता, क्योंकि यह प्रोटोटाइप लिंक पॉइंट है Object.prototype। फ़ंक्शन Object.getPrototypeOf( obj )प्रोटोटाइप श्रृंखला में सबसे ऊपरी ऑब्जेक्ट देता है obj। यह आपको प्रोटोटाइप श्रृंखला का पालन करने में सक्षम बनाता है objजब तक कि आप इसके अंत ( nullमूल्य) तक नहीं पहुंचते । मुझे यकीन नहीं है कि इस बारे में आपका मुद्दा क्या है ...
टाइम विधा

2
@ एलेक्स नहीं, यह नहीं है undefined। ऑब्जेक्ट Object.getPrototypeOf(John)लौटाता है Boy.prototype(जैसा कि यह होना चाहिए) - यहां देखें: jsfiddle.net/aeGLA/1 । ध्यान दें कि निर्माता Boyहै नहीं के प्रोटोटाइप श्रृंखला में John। की प्रोटोटाइप श्रृंखला Johnइस प्रकार है Boy.prototype -> Object.prototype -> null:।
13इमे विद्या

3
" मुझे लगा कि Object.getPrototypOf (obj) ओब्जेक्ट के निर्माता के प्रोटोटाइप को वापस कर देगा " - हाँ। के मामले में John, उसका निर्माता है Boy, और की prototypeसंपत्ति Boyहै Boy.prototype। तो Object.getPrototypeOf(John)लौट आता है Boy.prototype
18इमे विद

9

पुनरावर्तन का उपयोग कर एक क्लीनर समाधान:

function getAllPropertyNames (obj) {
    const proto     = Object.getPrototypeOf(obj);
    const inherited = (proto) ? getAllPropertyNames(proto) : [];
    return [...new Set(Object.getOwnPropertyNames(obj).concat(inherited))];
}

संपादित करें

अधिक सामान्य कार्य:

function walkProtoChain (obj, callback) {
    const proto     = Object.getPrototypeOf(obj);
    const inherited = (proto) ? walkProtoChain(proto, callback) : [];
    return [...new Set(callback(obj).concat(inherited))];
}

function getOwnNonEnumPropertyNames (obj) {
    return Object.getOwnPropertyNames(obj)
        .filter(p => !obj.propertyIsEnumerable(p));
}

function getAllPropertyNames (obj) {
    return walkProtoChain(obj, Object.getOwnPropertyNames);
}

function getAllEnumPropertyNames (obj) {
    return walkProtoChain(obj, Object.keys);
}

function getAllNonEnumPropertyNames (obj) {
    return walkProtoChain(obj, getOwnNonEnumPropertyNames);
}

इसी टेम्पलेट का उपयोग करके लागू किया जा सकता है Object.getOwnPropertySymbols, आदि।


4

सेट का लाभ उठाकर कुछ हद तक क्लीनर समाधान, IMO होता है।

const own = Object.getOwnPropertyNames;
const proto = Object.getPrototypeOf;

function getAllPropertyNames(obj) {
    const props = new Set();
    do own(obj).forEach(p => props.add(p)); while (obj = proto(obj));
    return Array.from(props);
}

2

ES6 में सीधे आगे पुनरावृत्ति:

function getAllPropertyNames(obj) {
    let result = new Set();
    while (obj) {
        Object.getOwnPropertyNames(obj).forEach(p => result.add(p));
        obj = Object.getPrototypeOf(obj);
    }
    return [...result];
}

उदाहरण रन:


1

कुछ उदाहरणों के लिए सभी विरासत में दिए गए गुणों या विधियों को प्राप्त करने के लिए आप कुछ इस तरह का उपयोग कर सकते हैं

var BaseType = function () {
    this.baseAttribute = "base attribute";
    this.baseMethod = function() {
        return "base method";
    };
};

var SomeType = function() {
    BaseType();
    this.someAttribute = "some attribute";
    this.someMethod = function (){
        return "some method";
    };
};

SomeType.prototype = new BaseType();
SomeType.prototype.constructor = SomeType;

var instance = new SomeType();

Object.prototype.getInherited = function(){
    var props = []
    for (var name in this) {  
        if (!this.hasOwnProperty(name) && !(name == 'constructor' || name == 'getInherited')) {  
            props.push(name);
        }  
    }
    return props;
};

alert(instance.getInherited().join(","));

1
के Object.getInheritedबजाय उपयोग करने के लिए बेहतर है Object.prototype.getInherited। ऐसा करना बदसूरत !(name == 'getInherited')जांच की आवश्यकता को भी दूर करता है । इसके अलावा, आपके कार्यान्वयन में, propsसरणी में डुप्लिकेट गुण हो सकते हैं। अंत में, constructorसंपत्ति की अनदेखी करने का उद्देश्य क्या है?
पौआन

कब होगा ऑब्जेक्ट.गेट इनहेरिटेड सच हो जाएगा? कृपया नीचे दिए गए प्रश्न की जाँच करें क्योंकि मैं विरासत के साथ फंस गया हूं: stackoverflow.com/questions/31718345/…
रविन्द्र बाबू

IMHO - ये रिफ्लेक्ट के हैं, ऑब्जेक्ट के नहीं। या - वैकल्पिक रूप से - मैं भाषा से अपेक्षा करता हूं Object.keys (src, [सेटिंग्स]) जहां वैकल्पिक सेटिंग्स निर्दिष्ट कर सकती हैं कि क्या गैर-नौन्यूमेबल्स को शामिल किया जाए, यदि विरासत में शामिल करना है, यदि गैर-एन्यूमेरिएबल को शामिल करना है, यदि स्वयं को शामिल करना है। , अगर प्रतीकों को शामिल करना है, और शायद खुदाई करने के लिए अधिकतम विरासत की गहराई क्या है।
रेडगैस्ट ब्राउन ब्राउन

उह ... Object.entries के लिए एक ही। हालांकि Object.values ​​के बारे में निश्चित नहीं है। ...कुंआ। क्यों नहीं।
रेडगैस्ट ब्राउन ब्राउन

0

यहाँ इस बात का हल है कि मैं इस विषय का अध्ययन करते हुए आया हूँ। objऑब्जेक्ट के सभी गैर-एन्यूमरेबल गैर-स्वयं के गुण प्राप्त करने के लिएgetProperties(obj, "nonown", "nonenum");

function getProperties(obj, type, enumerability) {
/**
 * Return array of object properties
 * @param {String} type - Property type. Can be "own", "nonown" or "both"
 * @param {String} enumerability - Property enumerability. Can be "enum", 
 * "nonenum" or "both"
 * @returns {String|Array} Array of properties
 */
    var props = Object.create(null);  // Dictionary

    var firstIteration = true;

    do {
        var allProps = Object.getOwnPropertyNames(obj);
        var enumProps = Object.keys(obj);
        var nonenumProps = allProps.filter(x => !(new Set(enumProps)).has(x));

        enumProps.forEach(function(prop) {
            if (!(prop in props)) {
                props[prop] = { own: firstIteration, enum_: true };
            }           
        });

        nonenumProps.forEach(function(prop) {
            if (!(prop in props)) {
                props[prop] = { own: firstIteration, enum_: false };
            }           
        });

        firstIteration = false;
    } while (obj = Object.getPrototypeOf(obj));

    for (prop in props) {
        if (type == "own" && props[prop]["own"] == false) {
            delete props[prop];
            continue;
        }
        if (type == "nonown" && props[prop]["own"] == true) {
            delete props[prop];
            continue;
        }

        if (enumerability == "enum" && props[prop]["enum_"] == false) {
            delete props[prop];
            continue;
        }
        if (enumerability == "nonenum" && props[prop]["enum_"] == true) {
            delete props[prop];
        }
    }

    return Object.keys(props);
}

0
function getNonEnumerableNonOwnPropertyNames( obj ) {
    var oCurObjPrototype = Object.getPrototypeOf(obj);
    var arReturn = [];
    var arCurObjPropertyNames = [];
    var arCurNonEnumerable = [];
    while (oCurObjPrototype) {
        arCurObjPropertyNames = Object.getOwnPropertyNames(oCurObjPrototype);
        arCurNonEnumerable = arCurObjPropertyNames.filter(function(item, i, arr){
            return !oCurObjPrototype.propertyIsEnumerable(item);
        })
        Array.prototype.push.apply(arReturn,arCurNonEnumerable);
        oCurObjPrototype = Object.getPrototypeOf(oCurObjPrototype);
    }
    return arReturn;
}

उपयोग करने का उदाहरण:

function MakeA(){

}

var a = new MakeA();

var arNonEnumerable = getNonEnumerableNonOwnPropertyNames(a);

0

यदि आप किसी अभिभावक के पूर्व के गैर-गुणकारी गुणों को लॉग इन करने की कोशिश कर रहे हैं। डिफ़ॉल्ट रूप से es6 में एक वर्ग के अंदर परिभाषित तरीकों को प्रोटोटाइप पर सेट किया गया है लेकिन गैर-गणना योग्य के रूप में सेट किया गया है।

Object.getOwnPropertyNames(Object.getPrototypeOf(obj));

0

मेरी व्यक्तिगत प्राथमिकताओं में एक कार्यान्वयन :)

function getAllProperties(In, Out = {}) {
    const keys = Object.getOwnPropertyNames(In);
    keys.forEach(key => Object.defineProperty(In, key, {
        enumerable: true
    }));
    Out = { ...In, ...Out };

    const Prototype = Object.getPrototypeOf(In);
    return Prototype === Object.prototype ? Out : getAllProperties(Proto, Out);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.