Раньше я думал, что создание объектов во время выполнения будет лучшим подходом. Теперь я менее уверен, так как вы теряете некоторые полезные функции, хотя это может стоить того, что было бы просто для предотвращения путаницы новичков. Недостатками этого являются:
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=[]
Однако мы потеряли способность интроспекции и посмотрим, какие аргументы по умолчанию равны . Поскольку объекты не были построены, мы никогда не сможем их захватить, не называя функцию. Самое лучшее, что мы могли бы сделать, это сохранить исходный код и вернуть его как строку.
Поскольку 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;
}
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);
Вот решение, которое я придумал при изучении предмета. Чтобы получить все неперечислимые несобственные свойства объекта 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);
}
Чтобы получить все унаследованные свойства или методы для некоторого экземпляра, вы можете использовать что-то вроде этого
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(","));
Object.getInherited
, а не Object.prototype.getInherited
. Это также устраняет необходимость в уродливой проверке !(name == 'getInherited')
. Кроме того, в вашей реализации массив props
может содержать повторяющиеся свойства. И наконец, в чем цель игнорирования свойства constructor
?
– Pauan
17 July 2013 в 13:35
, если вы пытаетесь зарегистрировать неперечислимые свойства родительского объекта ex. по умолчанию методы, определенные внутри класса в es6, устанавливаются на прототипе, но устанавливаются как неперечислимые.
Object.getOwnPropertyNames(Object.getPrototypeOf(obj));
Использование наборов приводит к несколько более чистому решению, 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);
}
while(curr = Object.getPrototypeOf(cure))
, поскольку условный оператор использует оператор присваивания вместо оператора сравнения, не всегда ли это возвращает true? Либо эта линия, по существу, проверяет, является ли "curr" имеет прототип? – dkugappi 6 November 2011 в 03:05Object.getPrototypeOf(cure)
вернетnull
в верхней части прототипа. Я предполагаю, что это не предполагает круговых цепочек прототипов! – Domenic 6 November 2011 в 05:07Function.prototype
никогда не может быть "root" прототип, поскольку это прототип ссылок указывает наObject.prototype
. ФункцияObject.getPrototypeOf( obj )
возвращает самый верхний объект в цепочке прототиповobj
. Он позволяет вам следовать цепочке прототиповobj
, пока вы не достигнете ее конца (значениеnull
). Я не уверен, что ваша проблема с этим ... – Šime Vidas 7 November 2011 в 16:01undefined
.Object.getPrototypeOf(John)
возвращает объектBoy.prototype
(как он должен) - см. здесь: jsfiddle.net/aeGLA/1 . Обратите внимание, что конструкторBoy
является не в цепочке прототиповJohn
. Цепочка прототипаJohn
выглядит следующим образом:Boy.prototype -> Object.prototype -> null
. – Šime Vidas 7 November 2011 в 16:13John
его конструкторBoy
, а свойствоprototype
дляBoy
-Boy.prototype
. ПоэтомуObject.getPrototypeOf(John)
возвращаетBoy.prototype
. – Šime Vidas 7 November 2011 в 16:18