Не стандартно
Эта возможность не является стандартной и стандартизировать её пока никто не собирается. Не используйте её на сайтах, смотрящих во внешний мир: она будет работать не у всех пользователей. Также могут присутствовать большие несовместимости между реализациями и её поведение может в будущем измениться.
__noSuchMethod__
и нестандартно, спецификация ECMAScript Harmony (ES6) содержит объект Proxy
, с помощью которого вы можете сделать всё тоже самое, что и при использовании этого свойством (и даже больше).Сводка
Свойство __noSuchMethod__
ссылается на функцию, выполняющуюся каждый раз при вызове на объекте несуществующего метода.
Синтаксис
obj.__noSuchMethod__ = fun
Параметры
fun
- Функция, имеющая вид
-
function(id, args) { . . . }
id
- Имя вызванного несуществующего метода
args
- Массив аргументов, переданный в метод
Описание
По умолчанию, при попытке вызвать не существующий в объекте метод, будет выброшено исключение TypeError
. Это поведение можно обойти, определив функцию __noSuchMethod__
в качестве члена объекта. Функция принимает два аргумента, первый является именем метода, который попытались вызвать, а второй — массивом аргументов, которые были переданы в метод при его вызове. Второй аргумент является настойщим массивом (то есть, он наследуется через цепочку прототипов от Array.prototype
), а не массивоподобным объектом arguments.
Если данный метод не может быть вызван, либо по причине того, что он установлен в undefined
по умолчанию, либо удалён, либо вручную установлен в не-функцию, движок JavaScript вернётся к выбрасыванию исключения TypeError
.
Примеры
Пример: простая проверка свойства __noSuchMethod__
var o = {
__noSuchMethod__: function(id, args) { console.log(id, '(' + args.join(', ') + ')'); }
};
o.foo(1, 2, 3);
o.bar(4, 5);
o.baz();
// Вывод
// foo (1, 2, 3)
// bar (4, 5)
// baz ()
Пример: использование свойства __noSuchMethod__
для симуляции множественного наследования
Ниже показан пример кода, реализующего примитивную форму множественного наследования.
// Не работает с множественным наследованием объектов в качестве родителей
function noMethod(name, args) {
var parents = this.__parents_;
// Пройдёмся по всем родителям
for (var i = 0; i < parents.length; i++) {
// Если нашли функцию в родителе, вызовем её
if (typeof parents[i][name] == 'function') {
return parents[i][name].apply(this, args);
}
}
// Если мы здесь, метод не был найден
throw new TypeError;
}
// Используется для добавления родителя при множественном наследовании
function addParent(obj, parent) {
// Если объект ещё не инициализирован, инициализируем его
if (!obj.__parents_) {
obj.__parents_ = [];
obj.__noSuchMethod__ = noMethod;
}
// Добавляем родителя
obj.__parents_.push(parent);
}
Ниже показан пример использования этой идеи.
// Пример первого базового класса
function NamedThing(name) {
this.name = name;
}
NamedThing.prototype = {
getName: function() { return this.name; },
setName: function(newName) { this.name = newName; }
}
// Пример второго базового класса
function AgedThing(age){
this.age = age;
}
AgedThing.prototype = {
getAge: function() { return this.age; },
setAge: function(age) { this.age = age; }
}
// Дочерний класс. Наследуется от NamedThing и AgedThing, а также определяет свойство address
function Person(name, age, address) {
addParent(this, NamedThing.prototype);
NamedThing.call(this, name);
addParent(this, AgedThing.prototype);
AgedThing.call(this, age);
this.address = address;
}
Person.prototype = {
getAddr: function() { return this.address; },
setAddr: function(addr) { this.address = addr; }
}
var bob = new Person('Боб', 25, 'Нью-Йорк');
console.log('getAge лежит ' + (('getAge' in bob) ? 'в' : 'не в') + ' объекте bob');
console.log('возраст Боба: ' + bob.getAge());
console.log('getName лежит ' + (('getName' in bob) ? 'в' : 'не в') + ' объекте bob');
console.log('имя Боба: ' + bob.getName());
console.log('getAddr лежит ' + (('getAddr' in bob) ? 'в' : 'не в') + ' объекте bob');
console.log('адрес Боба: ' + bob.getAddr());
Вывод примера будет следующим:
getAge лежит не в объекте bob возраст Боба: 25 getName лежит не в объекте bob имя Боба: Боб getAddr лежит в объекте bob адрес Боба: Нью-Йорк
Спецификации
Не является частью какой-либо спецификации.
Совместимость с браузерами
Возможность | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
Базовая поддержка | Нет | 1.0 (1.7 или ранее) | Нет | Нет | Нет |
Возможность | Android | Chrome для Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|
Базовая поддержка | Нет | Нет | 1.0 (1.0) | Нет | Нет | Нет |