mozilla

Compare Revisions

Object.prototype.__noSuchMethod__

Change Revisions

Revision 72090:

Revision 72090 by evilpie on

Revision 72091:

Revision 72091 by tmim on

Title:
__noSuchMethod__
__noSuchMethod__
Slug:
JavaScript/Reference/Global_Objects/Object/noSuchMethod
JavaScript/Reference/Global_Objects/Object/noSuchMethod
Tags:
JavaScript, "JavaScript Reference"
JavaScript, "JavaScript Reference"
Content:

Revision 72090
Revision 72091
n81      By default, an attempt to call a method that doesn't exist n81      By default, an attempt to call a method that doesn't exist 
>on an object results in a <a href="/en/Core_JavaScript_1.5_Refere>on an object results in a <a href="/En/Core_JavaScript_1.5_Refere
>nce/Global_Objects/TypeError" title="en/Core_JavaScript_1.5_Refer>nce/Global_Objects/TypeError" title="en/Core_JavaScript_1.5_Refer
>ence/Global_Objects/TypeError">TypeError</a> being thrown. This b>ence/Global_Objects/TypeError">TypeError</a> being thrown. This b
>ehavior can be circumvented by defining a function at that object>ehavior can be circumvented by defining a function at that object
>'s <code>__noSuchMethod__</code> member. The function takes two a>'s <code>__noSuchMethod__</code> member. The function takes two a
>rguments, the first is the name of the method attempted and the s>rguments, the first is the name of the method attempted and the s
>econd is an array of the arguments that were passed in the method>econd is an array of the arguments that were passed in the method
> call. The second argument is an actual array (that is, it inheri> call. The second argument is an actual array (that is, it inheri
>ts through the <a href="/en/Core_JavaScript_1.5_Reference/Global_>ts through the <a href="/en/JavaScript/Reference/Global_Objects/A
>Objects/Array/prototype" title="en/Core_JavaScript_1.5_Reference/>rray/prototype" title="en/Core_JavaScript_1.5_Reference/Global_Ob
>Global_Objects/Array/prototype">Array prototype</a> chain) and no>jects/Array/prototype">Array prototype</a> chain) and not the arr
>t the array-like <a href="/En/Core_JavaScript_1.5_Reference/Funct>ay-like <a href="/en/JavaScript/Reference/Functions_and_function_
>ions_and_function_scope/arguments" title="en/Core_JavaScript_1.5_>scope/arguments" title="en/Core_JavaScript_1.5_Reference/Function
>Reference/Functions/arguments">arguments object</a>.>s/arguments">arguments object</a>.
n90      {{ note("If you have a better example, (like a shim that men90      __noSuchMethod__ can be used to simulate multiple inheritan
>diates method calls, to simulate vanilla prototypal inheritance, >ce.
>but with conditions that can affect the return type or auxiliary  
>behavior of the method), please feel free to replace this one."); 
> }} 
n93      Suppose you have a project which has deprecated the use of n93      The code that can implement a primitive form of multiple in
>an <code>errorize</code> method , both because <code>errorize</co>heritance is shown below.
>de> is poorly-named and because your new <code>log</code> method  
>handles the severity of the occurrence, such as an error versus a 
> simple warning. Using <code>__noSuchMethod__, y</code>ou could r 
>eplace the functionality of the old <code>errorize</code>&nbsp; b 
>y substituting a call to <code>log</code>: 
n96wittyProjectName.__noSuchMethod__ = function __noSuchMethod__ (idn96//Doesn't work with multiple inheritance objects as parents
>, args) { 
97  if (id == 'errorize') {97function noMethod(name, args){
98    wittyProjectName.log("wittyProjectName.errorize has been depr98    var parents=this.__parents_;
>ecated.\n" + 
99                         "Use wittyProjectName.log(message, " +99    //Go through all parents
100                         "wittyProjectName.LOGTYPE_ERROR) instead100    for(var i=0;i&lt;parents.length;i++){
>.", 
101                         this.LOGTYPE_LOG);101        //If we find a function on the parent, we call it
102    // just act as a wrapper for the newer log method102        if(typeof parents[i][name] =="function") return parents[i
 >][name].apply(this, args);
103    args.push(this.LOGTYPE_ERROR);
104    this.log.apply(this, args);
105  }103    }
104    //If we get here, the method hasn't been found
105    throw new TypeError;
106}
107//Used to add a parent for multiple inheritance
108function addParent(obj, parent){
109    //If object isn't initialised, initialize it
110    if(!obj.__parents_){
111        obj.__parents_=[];
112        obj.__noSuchMethod__=noMethod;
113    }
114    //Add the parent
115    obj.__parents_.push(parent);
n109      Do note, however, that this is merely a demonstration of <cn119      An example of using this idea is shown below.
>ode>__noSuchMethod__</code>, and there are simpler ways to achiev 
>e the effect here, like changing the function body of the old <co 
>de>errorize</code> method to call <code>log</code> directly. The  
>key difference between that approach and this one is that in this 
> one, the <code>errorize</code> method will remain completely hid 
>den on the <code>wittyProjectName</code> object. It will not be e 
>numerable using <a href="/en/Core_JavaScript_1.5_Reference/Statem 
>ents/for...in" title="en/Core_JavaScript_1.5_Reference/Statements 
>/for...in">for...in</a>, and any references to it besides those c 
>alling it as a function would get <code>undefined</code>, as if i 
>t's not there—because it really isn't: 
n112wittyProjectName.errorize; // returns undefinedn122//Example base class 1
113wittyProjectName.hasOwnProperty("errorize"); // returns false123function NamedThing(name){
114"errorize" in wittyProjectName; // returns false124    this.name=name;
115// this will print "__noSuchMethod__", "log", "LOGTYPE_ERROR", an
>d 
116// "LOGTYPE_LOG" (if the three lattermost ones have been defined)
117for (propname in wittyProjectName) {
118  println(propname);
tt126NamedThing.prototype={
127    getName: function(){return this.name;},
128    setName: function(newName){this.name=newName;}
129}
130 
131//Example base class 2
132function AgedThing(age){
133    this.age=age;
134}
135AgedThing.prototype={
136    getAge: function(){return this.age;},
137    setAge: function(age){this.age=age;}
138}
139 
140//Child class. inherits from NamedThing and AgedThing as well as 
 >defining address
141function Person(name, age, address){
142    addParent(this, NamedThing.prototype);
143    NamedThing.call(this, name);
144    addParent(this, AgedThing.prototype);
145    AgedThing.call(this, age);
146    this.address=address;
147}
148Person.prototype={
149    getAddr: function(){return this.address;},
150    setAddr: function(addr){this.address=addr;}
151}
152 
153var bob=new Person("bob", 25, "New York");
154console.log("getAge is "+(("getAge" in bob)?"in":"not in")+" bob"
 >);
155console.log("bob's age is: "+bob.getAge());
156console.log("getName is "+(("getName" in bob)?"in":"not in")+" bo
 >b");
157console.log("bob's name is: "+bob.getName());
158console.log("getAddr is "+(("getAddr" in bob)?"in":"not in")+" bo
 >b");
159console.log("bob's address is: "+bob.getAddr());

Back to History