非標準
この機能は標準ではなく、標準化の予定もありません。公開されているウェブサイトには使用しないでください。ユーザーによっては使用できないことがあります。実装ごとに大きな差があることもあり、将来は振る舞いが変わるかもしれません。
Gecko 43 で廃止 (Firefox 43 / Thunderbird 43 / SeaMonkey 2.40)
この機能は廃止されました。まだいくつかのブラウザーで動作するかもしれませんが、いつ削除されてもおかしくないので、使わないようにしましょう。
__noSuchMethod__
プロパティは、オブジェクトで存在しないメソッドが呼び出されたときに実行される関数を参照するために使用されていましたが、この機能は利用できなくなりました。
__noSuchMethod__
は廃止されしたが、 ECMAScript 2015 (ES6) 仕様には Proxy
オブジェクトがあり、以下のようなことを (それ以上のことも) 実現できます。
構文
obj.__noSuchMethod__ = fun
引数
fun
- 以下の引数をとる関数
-
function (id, args) { . . . }
id
- 呼び出された未定義のメソッドの名前
args
- そのメソッドへ渡された引数の配列
解説
オブジェクトで定義されていない関数の呼び出しを試みても、標準の挙動では TypeError
例外が投げられるだけです。オブジェクトのメンバー関数として __noSuchMethod__
を定義しておく事でこの挙動を回避できます。 __noSuchMethod__
として定義される関数は 2 つの引数をとります。 1 つ目の引数は呼び出しが試みられたメソッドの名前を表し、 2 つ目の引数はそのメソッドへ渡された引数の配列を表します。この 2 つ目の引数は実配列です。配列を模したオブジェクトである 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__
を使用して多重継承をシミュレートする
多重継承の基本形を実装するコードの例を以下に示します。
// Doesn't work with multiple inheritance objects as parents function noMethod(name, args) { var parents = this.__parents_; // Go through all parents for (var i = 0; i < parents.length; i++) { // If we find a function on the parent, we call it if (typeof parents[i][name] == 'function') { return parents[i][name].apply(this, args); } } // If we get here, the method hasn't been found throw new TypeError; } // Used to add a parent for multiple inheritance function addParent(obj, parent) { // If the object isn't initialized, initialize it if (!obj.__parents_) { obj.__parents_ = []; obj.__noSuchMethod__ = noMethod; } // Add the parent obj.__parents_.push(parent); }
使用例を以下に示します。
// Example base class 1 function NamedThing(name) { this.name = name; } NamedThing.prototype = { getName: function() { return this.name; }, setName: function(newName) { this.name = newName; } } // Example base class 2 function AgedThing(age) { this.age = age; } AgedThing.prototype = { getAge: function() { return this.age; }, setAge: function(age) { this.age = age; } } // Child class. inherits from NamedThing and AgedThing // as well as defining 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('bob', 25, 'New York'); console.log('getAge is ' + (('getAge' in bob) ? 'in' : 'not in') + ' bob'); // getAge is not in bob console.log("bob's age is: " + bob.getAge()); // bob's age is: 25 console.log('getName is ' + (('getName' in bob) ? 'in' : 'not in') + ' bob'); // getName is not in bob console.log("bob's name is: " + bob.getName()); // bob's name is: bob console.log('getAddr is ' + (('getAddr' in bob) ? 'in' : 'not in') + ' bob'); // getAddr is in bob console.log("bob's address is: " + bob.getAddr()); // bob's address is: New York
仕様書
どの仕様にも含まれていません。この機能は削除されました。 バグ 683218 をご覧ください。
ブラウザーの対応
デスクトップ | モバイル | サーバー | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
基本対応 | Chrome 未対応 なし | Edge 未対応 なし | Firefox 未対応 1 — 43 | IE 未対応 なし | Opera 未対応 なし | Safari 未対応 なし | WebView Android 未対応 なし | Chrome Android 未対応 なし | Edge Mobile 未対応 なし | Firefox Android 未対応 4 — 43 | Opera Android 未対応 なし | Safari iOS 未対応 なし | Samsung Internet Android 未対応 なし | nodejs 未対応 なし |
凡例
- 未対応
- 未対応
- 非標準。ブラウザー間の互換性が低い可能性があります。
- 非標準。ブラウザー間の互換性が低い可能性があります。
- 非推奨。新しいウェブサイトでは使用しないでください。
- 非推奨。新しいウェブサイトでは使用しないでください。