There is such a function from a third-party library:
(function($) {
window.NestedFormEvents = function() {
this.addFields = $.proxy(this.addFields, this);
this.removeFields = $.proxy(this.removeFields, this);
};
//......
NestedFormEvents.prototype = {
addFields: function(e) { .....
});
Is there any way to call addFields() from a client? typeof window.NestedFormEvents returns "function", but window.NestedFormEvents.addFields returns undefined as well as window.NestedFormEvents.addFields().
The source code is here: https://github.com/ryanb/nested_form/blob/master/vendor/assets/javascripts/jquery_nested_form.js
This is constructor function. When called with new keyword it returns new object which has methods defined in constructor's prototype:
var nestedFormEvent = new NestedFormEvents();
nestedFormEvent.addFields();
Now if you check console.log(nestedFormEvent) object you will see all necessary methods in it.
You're calling addFields as though it were a static method of NestedFormEvents.
Rather, it is a method of its prototype. So:
var instance = new NestedFormEvents;
alert(NestedFormEvents.addFields); //undefined
alert(instance.addFields); //finds function
In short, any time you're trying to use methods declared on a function's prototype, you need to instantiate it, with new.
Related
I try to override a method and script is:
function wrapper(target) {
target.doABC = function () {
alert('in wrapper');
};
return target;
}
function Model() {
wrapper(this);
}
Model.prototype.doABC = function () {
alert('in Model');
};
var a = new Model();
a.doABC();
The result is 'in wrapper'. I don't know why?
Any JavaScript object has own and inherited properties. Own are those defined directly on the instance and inherited are taken from the prototype object.
When using a property accessor, JavaScript first searches in object's own properties list. If the property is not found, it searches in object's prototype chain.
In your example, the wrapper() method defines on object instance an own property doABC, which is a function that alerts 'in wrapper'. Even if the object has a prototype with the same property doAbc that alerts 'in Model', JavaScript anyway will use the own property.
function wrapper(target) {
// Define an own property "doABC"
target.doABC = function () {
alert('in wrapper');
};
return target;
}
function Model() {
wrapper(this);
}
// Define an inherited property "doABC"
Model.prototype.doABC = function () {
alert('in Model');
};
var a = new Model();
//Use the own property "doABC". The inherited "doABC" is ignored.
a.doABC();
As an addition, the own property can be removed using delete operator. After deletion, the object will use the inherited property.
// delete the own property "doABC"
delete a['doABC'];
// the inherited "doABC" will be used. Alerts "in Model"
a.doABC();
Check the complete working demo.
Let me see if I can explain:
You have two separate versions of doABC here.
Your target.doABC creates a function specific to that instance of your Model and each Model get its own doABC.
Because Model has a doABC, the JavaScript engine has no need to look 'up the chain' for something else, hence it will never look for the Model.prototype.doABC version.
You can see this by adding these lines:
Model.prototype.doXYZ = function () {
alert('in Model');
};
and calling
a.doXYZ();
Since a doesn't have its own doXYZ then, and only then, will it look up the chain and see the method in the prototype.
I've read the similar questions on SO and can't figure out what I'm doing wrong. I can't call the prototype method from within the constructor method.
I get: Uncaught TypeError: Object # has no method 'afterLoad'
var FiltersByDivision = function () {
$(document).on('afterLoad', this.afterLoad());
};
FiltersByDivision.prototype.afterLoad = function (){
console.log('afterLoad');
}
function OpenOrders() {
Widget.call(this);
FiltersByDivision.call(this);
this.widgetEndpoint = '/xxxxx';
}
OpenOrders.prototype = Object.create(Widget.prototype);
OpenOrders.prototype.constructor = OpenOrders;
There are a number of problems with this code:
You aren't inheriting from FiltersByDivision so thus an OpenOrders object does not have any FiltersByDivision methods. That's the reason why there is no afterLoad method.
$(document).on('afterLoad', this.afterLoad()); will execute this.afterLoad() immediately and pass it's return result as the event handler (which is not what you want). After you fix item 1, perhaps, you want $(document).on('afterLoad', this.afterLoad.bind(this));
There are many possible structures here. If FiltersByDivision is a separate object, then perhaps OpenOrders should just have one of those objects in its instance data like this (though if all it is doing is setting up an event handler, I'm not sure why it is a separate type of object):
var FiltersByDivision = function () {
$(document).on('afterLoad', this.afterLoad.bind(this));
};
FiltersByDivision.prototype.afterLoad = function (){
console.log('afterLoad');
}
function OpenOrders() {
Widget.call(this);
this.filter = new FiltersByDivision();
this.widgetEndpoint = '/xxxxx';
}
OpenOrders.prototype = Object.create(Widget.prototype);
OpenOrders.prototype.constructor = OpenOrders;
As jsfriend already pointed out is that afterLoad is not on ObjectOrders prototype. Doing a OtherConstructor.call does not inherit that constuctors prototype but initializes instance variables.
The value of this is the invoking object so the declaration of the function doesn't define its value but how you invoke it. You could use closures:
var FiltersByDivision = function ()
var me = this;
$(document).on('afterLoad', function(){
me.afterLoad();
});
};
More info on this, prototype and closures can be found here: https://stackoverflow.com/a/16063711/1641941
What is the difference between this two codes and which one should I use?
function Test() {}
Test.method = function() {};
With Prototype:
function Test() {}
Test.prototype.method = function() {};
1st case : static method.
function Test() {}
Test.method = function () { alert(1); };
var t = new Test;
Test.method(); // alerts "1"
t.method(); // TypeError: Object #<Test> has no method 'method'
2nd case : instance method.
function Test() {}
Test.prototype.method = function () { alert(1); };
var t1 = new Test;
var t2 = new Test;
t1.method(); // alerts "1"
t2.method(); // alerts "1"
Test.method(); // TypeError: Object function Test() {} has no method 'method'
The first example merely assigns a function to a new property of Test called method. There is nothing special or magic about it (by which I mean, the language does not do anything interesting with it). You might call this a static method, because it's shared across all instances, but it's really just a normal property. (Functions are objects and objects have properties.)
In the second case, a new method is added to Test's prototype, which makes it available to all instances of Test. This is special behavior. Every object in JavaScript has an internal link to another object, which is called its prototype. This link is established using the prototype of the constructor that created the object, so any instance created by Test will have the new property in its prototype chain.
For example:
function Test() {}
Test.method = function() {};
var a = new Test();
console.log(a.method); // => undefined
But:
function Test() {}
Test.prototype.method = function() {};
var a = new Test();
console.log(a.method); // => function
The prototype method is shared between all instances of Test.
The difference goes back to how the prototype chaining works. If you create instances of Test then they will be able to access the methods that are defined on the prototype.
The first code, simply adds a "static" method on the constructor; You won't be able to access that method doing something like this:
var testInst = new Test();
testInst.method() // Error Undefined is not a function
The only way to invoke that method is via the constructor reference i.e.
Test.method();
As i mentioned, the above is feasible if you add the method to the prototype of the constructor.
If you define a method in the prototype, any instances will be able to use that method. If you define the method as simply a part of the original object, it allows you to simply use that in a manner that one could reasonably refer to as a static method.
For example:
Array.isArray( [] ) //true
[].isArray() //throws a TypeError
The second example throws a TypeError because isArray() is not in the Array.prototype (remember, instances only access methods defined in that instance, or in that instance's prototype or __proto__ chain).
In short:
* A method defined in the original object can be accessed by that object, but not instances of that object.
* A method defined in the original object's prototype can be accessed by any instance of the original object.
Will NOT Work (for an instance)
function Test() {}
Test.method = function() {};
Will Work (for an instance)
function Test() {}
Test.prototype.method = function() {};
Why?
Assuming that you create an instance of Test:
t = new Test()
On calling a method:
t.method()
JavaScript will first look within Test, for example the 3 properties and methods will be recognized below:
function Test() {} {
this.a = "hello";
this.b = "world";
this.c = function() { alert( this.a + this.b) }
}
and then the second, the look up will be done on prototype:
Test.prototype.method = function() { console.log('prototype defined method') }
In JavaScript the below does not register to the instance t but instead Test:
Test.method = function() { console.log('something unsual') };
therefore
Test.method() // works
t.method() // no works
When trying to test prototype functionality, I got this odd result:
Here is my first test:
<script>
function Hello() {
}
var a = new Hello();
Hello.prototype.name = "Fred";
alert(a.name);
</script>
And, here's the second one:
<script>
function Hello() {
}
var a = new Hello();
Hello.prototype = {
name : "Fred",
}
alert(a.name);
</script>
I can't understand why the first will return a alert with "Fred" and the second is "undefined" though these mean the same thing?
Could you help me with it?
Thank you.
When you define a function in JavaScript, the interpreter makes a special prototype property available on the function, which points to an object, in case you use that function as a constructor. The [[Prototype]] internal property points to this object when you create a new object using the constructor.
When you replace the prototype property with a new one, you are replacing that reference, and if you do it after you instantiate an object, you will find the prototype object appears to be stale (that object's [[Prototype]] is pointing to the original object that prototype pointed to).
Solutions
Only assign new properties directly on the prototype property.
var constructor = function() { };
constructor.prototype.someMethod = function() { };
Use an extend type function to extend the existing prototype property with your new object (in this example, I used Underscore's extend() function).
var constructor = function() { };
_.extend(constructor.prototype, { someMethod: function() { } });
Make sure after the constructor, assigning the prototype property is the very next step in your program (generally not recommended).
var constructor = function() { };
constructor.prototype = { someMethod: function() { } };
Your ordering is messed up. You need assign the object to the prototype before using the new operator:
function Hello() {
}
Hello.prototype = {
name : "Fred",
}
var a = new Hello();
alert(a.name);
Demo.
The two code snippets are not actually equal.
In the first script you only override Hello.prototype.name, while in the second script you override the whole content of Hello.prototype.
If I create a Class with two method like following:
var Car = function() {}
Car.prototype = {
run: function() {
alert('run');
},
stop: function() {
alert('stop');
}
}
And when the DOM is ready will call test() method,
and this test() method will create a instance of Car and call the method of Car
$(document).ready(function() {
test("run");
});
function test(method) {
var instance = new Car();
// call instance.run()
}
I know I have to use apply() method,
but I have tried lots of times and failed
So, how can I use apply() method in Object?
An object in javascript is an associative array, so you can use the [] operator to address by string any member of the object, functions as well.
function test(method) {
var instance = new Car();
instance[method]();
}
this will allow to call a function by name over the object Car.
See it working on JsFiddle.
The context inside the called method will properly point to the newly created Car instance without any additional effort, that I guess is what you want. Using apply or call is generally used when you need to change the default 'this' value to something else.
I know I have to use apply() method,
You don't. Uncomment the instance.run() code, call the test() method and it works.
demo: http://jsfiddle.net/JkAnb/
how can I use apply() method in Object
It depends on what you want to achieve. There is documentation at MDN.
perhaps you want to call
instance.method()
call dynamically i.e. based on value passed run/stop. You can try this -
instance[method].call(instance)
or
instance[method].apply(instance)
where instance is passed as scope param which is scope of the function to be called (value of "this" inside function).
Why do You need classes in an (object based) functional language?
Your intent is bit unclear. What is the implied type of the argument 'method' in Your test function?
I assume it is a method name. In any case code bellow might help.
/* prefer this class pattern */
var Car = (function () {
"use strict";
Car.prototype = {
name : undefined ,
run: function () {
return name_ + ":: run";
},
stop: function () {
return name_ + ":: stop";
}
};
/* constructor */
function Car(name) {
name_ = name;
}
return Car;
})();
function printer(msg_) {
document.body.innerHTML += msg_ + "<br/>";
}
function test(car_, method_name_1, method_name_2) {
printer(car_[method_name_1]());
printer(car_[method_name_2]());
}
test( new Car("BMW"), "run", "stop");
test( new Car("Lada"), "run", "stop")
in addition, you could also use the eval function:
var instance = new Car();
eval('instance.'+method+'();');
though Felice Pollano's way is far neater imo.
http://jsfiddle.net/VZdXb/