Object.getOwnPropertyNames при использовании объекта, созданного функцией генератора? [Дубликат]

Раньше я думал, что создание объектов во время выполнения будет лучшим подходом. Теперь я менее уверен, так как вы теряете некоторые полезные функции, хотя это может стоить того, что было бы просто для предотвращения путаницы новичков. Недостатками этого являются:

1. Производительность

def foo(arg=something_expensive_to_compute())):
    ...

Если используется оценка времени вызова, тогда дорогая функция вызывается каждый раз, когда ваша функция используется без аргумента. Вы либо заплатили бы дорогостоящую цену за каждый вызов, либо должны вручную кэшировать значение извне, загрязняя пространство имен и добавляя многословие.

2. Принудительные связанные параметры

Полезный трюк заключается в привязке параметров лямбда к привязке current переменной при создании лямбда. Например:

funcs = [ lambda i=i: i for i in range(10)]

Возвращает список функций, возвращающих 0,1,2,3 ... соответственно. Если поведение изменено, они вместо этого привяжут i к значению времени вызова для i, поэтому вы получите список функций, которые все вернули 9.

Единственным способом реализации этого в противном случае было бы создать дальнейшее закрытие с привязкой i, то есть:

def make_func(i): return lambda: i
funcs = [make_func(i) for i in range(10)]

3. Introspection

Рассмотрим код:

def foo(a='test', b=100, c=[]):
   print a,b,c

Мы можем получить информацию о аргументах и ​​значениях по умолчанию с помощью модуля inspect, который

>>> inspect.getargspec(foo)
(['a', 'b', 'c'], None, None, ('test', 100, []))

информация очень полезна для таких вещей, как создание документов, метапрограммирование, декораторы и т. д.

Теперь предположим, что поведение по умолчанию может быть изменено так, что это эквивалентно:

_undefined = object()  # sentinel value

def foo(a=_undefined, b=_undefined, c=_undefined)
    if a is _undefined: a='test'
    if b is _undefined: b=100
    if c is _undefined: c=[]

Однако мы потеряли способность интроспекции и посмотрим, какие аргументы по умолчанию равны . Поскольку объекты не были построены, мы никогда не сможем их захватить, не называя функцию. Самое лучшее, что мы могли бы сделать, это сохранить исходный код и вернуть его как строку.

78
задан Šime Vidas 6 November 2011 в 05:17
поделиться

6 ответов

Поскольку 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
}

Я тестировал это на Safari 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;
}

И просто получить все .. ( enum / nonenum, self / inherited .. Пожалуйста, подтвердите ..

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

    do {
        props= props.concat(Object.getOwnPropertyNames( obj ));
    } while ( obj = Object.getPrototypeOf( obj ) );

    return props;
}
90
ответ дан Muhammad Umer 21 August 2018 в 09:56
поделиться
  • 1
    Спасибо, одна вещь, которую я не понимаю, это строка: while(curr = Object.getPrototypeOf(cure)), поскольку условный оператор использует оператор присваивания вместо оператора сравнения, не всегда ли это возвращает true? Либо эта линия, по существу, проверяет, является ли "curr" имеет прототип? – dkugappi 6 November 2011 в 03:05
  • 2
    @AlexNabokov вернет false, если результат будет ложным, что произойдет, когда Object.getPrototypeOf(cure) вернет null в верхней части прототипа. Я предполагаю, что это не предполагает круговых цепочек прототипов! – Domenic 6 November 2011 в 05:07
  • 3
    @Alex Function.prototype никогда не может быть "root" прототип, поскольку это прототип ссылок указывает на Object.prototype. Функция Object.getPrototypeOf( obj ) возвращает самый верхний объект в цепочке прототипов obj. Он позволяет вам следовать цепочке прототипов obj, пока вы не достигнете ее конца (значение null). Я не уверен, что ваша проблема с этим ... – Šime Vidas 7 November 2011 в 16:01
  • 4
    @Alex Нет, это не undefined. Object.getPrototypeOf(John) возвращает объект Boy.prototype (как он должен) - см. здесь: jsfiddle.net/aeGLA/1 . Обратите внимание, что конструктор Boy является не в цепочке прототипов John. Цепочка прототипа John выглядит следующим образом: Boy.prototype -> Object.prototype -> null. – Šime Vidas 7 November 2011 в 16:13
  • 5
    « Я думал, что Object.getPrototypeOf (obj) вернет прототип конструктора obj & quot; - Да. В случае John его конструктор Boy, а свойство prototype для Boy - Boy.prototype. Поэтому Object.getPrototypeOf(John) возвращает Boy.prototype. – Šime Vidas 7 November 2011 в 16:18
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
ответ дан Dmitry Ragozin 21 August 2018 в 09:56
поделиться

Вот решение, которое я придумал при изучении предмета. Чтобы получить все неперечислимые несобственные свойства объекта obj do 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
ответ дан golem 21 August 2018 в 09:56
поделиться

Чтобы получить все унаследованные свойства или методы для некоторого экземпляра, вы можете использовать что-то вроде этого

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
ответ дан Milan Jaric 21 August 2018 в 09:56
поделиться
  • 1
    Лучше использовать Object.getInherited, а не Object.prototype.getInherited. Это также устраняет необходимость в уродливой проверке !(name == 'getInherited'). Кроме того, в вашей реализации массив props может содержать повторяющиеся свойства. И наконец, в чем цель игнорирования свойства constructor? – Pauan 17 July 2013 в 13:35
  • 2
    Я с тобой согласен. – Milan Jaric 18 July 2013 в 14:35
  • 3
    Когда объект object.getInherited станет правдой? Пожалуйста, проверьте ниже вопрос, поскольку я застрял в наследовании: stackoverflow.com/questions/31718345/… – Ravindra babu 31 July 2015 в 08:26

, если вы пытаетесь зарегистрировать неперечислимые свойства родительского объекта ex. по умолчанию методы, определенные внутри класса в es6, устанавливаются на прототипе, но устанавливаются как неперечислимые.

Object.getOwnPropertyNames(Object.getPrototypeOf(obj));
0
ответ дан Rahil Ahmad 21 August 2018 в 09:56
поделиться

Использование наборов приводит к несколько более чистому решению, 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);
}
0
ответ дан rich remer 21 August 2018 в 09:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: