Не стандартно
Эта возможность не является стандартной и стандартизировать её пока никто не собирается. Не используйте её на сайтах, смотрящих во внешний мир: она будет работать не у всех пользователей. Также могут присутствовать большие несовместимости между реализациями и её поведение может в будущем измениться.
__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) | Нет | Нет | Нет |