Crockford recommends этот вид Object.create
прокладки:
if (typeof Object.create != "function") {
Object.create = function (o) {
function F(){}
F.prototype = o;
return new F;
};
}
Но пожалуйста не делать этого.
Проблема с этим подходом является то, что ES5 Object.create
имеет подпись 2 аргументов: первый - объект наследовать, и второй (по желанию) - объект, представляющий свойства (или, скорее, дескрипторы), чтобы добавить вновь созданный объект.
Object.create(O[, Properties]); // see 15.2.3.5, ECMA-262 5th ed.
Что мы имеем это непоследовательное выполнение с 2 различными поведения. В средах с родным Object.create
метод знает, как обрабатывать второй аргумент; в средах без родной Object.create
, это не так.
Каковы практические последствия?
Ну, если есть некоторый код (скажем, сценарий третьей стороной), который хочет использовать Object.create
, это довольно разумно, что код, чтобы сделать это:
if (Object.create) {
var child = Object.create(parent, properties);
}
- по существу, при условии, что если Object.create
существует, то его должен соответствовать спецификациям - принимать второй аргумент и добавлять соответствующие свойства объекту.
Но, с вышеупомянутой регулировкой, второй аргумент просто игнорируется. Там даже нет указания на то, что происходит неправильно по-разному. Тихий отказ, так сказать, что-то, что довольно болезненно для обнаружения и исправления.
Можем ли мы сделать лучше?
Ну, это на самом деле невозможно создать полностью соответствующую Object.create
прокладку используя только (стандартное) оборудование ES3. Лучшим решением является создание настраиваемого метода обертки.
Там, однако, несколько альтернативных (менее оптимальных) вещей, которые вы можете попробовать:
1) Уведомление пользователя о невозможности работать со вторым аргументом
if (!Object.create) {
Object.create = function (o) {
if (arguments.length > 1) {
throw Error('second argument is not supported');
}
// ... proceed ...
};
}
2) Попробуйте обрабатывать второй аргумент :
if (!Object.create) {
Object.create = function (parent, properties) {
function F(){}
F.prototype = parent;
var obj = new F;
if (properties) {
// ... augment obj ...
}
return obj;
};
}
Обратите внимание, что «свойство» является объектом, представляющим собственности дескрипторы, а не только имена свойств/Val ЕЭС, и это то, что это не очень тривиальная поддержки (некоторые вещи даже не представляется возможным, например, как контроль перечислимость собственности):
Object.create(parent, {
foo: {
value: 'bar',
writable: true
},
baz: {
get: function(){ return 'baz getter'; },
set: function(value){ return 'baz setter'; },
enumerable: true
}
});
Другая несогласованность в оригинальной прокладки является то, что он не заботится от материнский объект null
.
var foo = Object.create(null);
Это создает объект, [[Prototype]] является null
; другими словами, объект, который не наследует ни от чего, даже от Object.prototype
(который наследует все нативные объекты в ECMAScript).
foo.toString; // undefined
foo.constructor; // undefined
// etc.
Это, кстати, полезно для создания «правильных» хэш-таблиц в ECMAScript.
Это можно подражать этому поведению, но только с использованием нестандартных расширений, таких как «магический» __proto__
(так что реализация будет не очень портативной или надежной). Решение этой проблемы аналогично: либо полностью эмулировать реализацию ES5, либо уведомлять о несогласованности/сбое.
См. Также http://stackoverflow.com/questions/1890464/is-there-a-library-which-implements-new-javascript-ecmascript-5-methods-for-older/2916063#2916063 –