I am studying prototypes, classes and modular patterns with Alex MacCaw's Javascript Web Applications. Almost everything is clear and well-explained, however, I can't figure out how empty functions that are used for initialization work. I would be grateful if your explain nuances no matter how complex they are.
Here is the example from the book:
(function($){
var mod = {};
mod.create = function(includes){
var result = function(){
this.init.apply(this, arguments);
};
result.fn = result.prototype;
result.fn.init = function(){};
result.proxy = function(func){ return $.proxy(func, this); };
result.fn.proxy = result.proxy;
result.include = function(ob){ $.extend(this.fn, ob); };
result.extend = function(ob){ $.extend(this, ob); };
if (includes) result.include(includes)
return result;
};
exports.Controller = mod;
})(jQuery);
From the code above I understand that the Immediately Invoked Function Expression (IIFE) is used to protect the scope. Then mod.create construction function is defined that returns result object with all class methods. However, I am confused with how the following works:
this.init.apply(this, arguments);
result.fn.init = function(){};
I guess that we apply empty init function to constructor arguments to allow new objects instantiation or something like that. From the answer below it appears that init function receives undefined number of arguments, but what arguments? Those that are used during instantiation -- includes in the above code? And why this function is empty, what it does when invoked?
this.init.apply(this, arguments);
is basically just
this.init(arguments[0], arguments[1], ..., arguments[N]);
But as soon as we don't know the exact number of arguments - we just use .apply()
Usage example:
var newConstructor = exports.Controller.create();
newConstructor.include({
init: function(a, b, c) { console.log(a, b, c, 'yay!'); }
});
var newInstance = new newConstructor(1, 2, 3);
Complete demo: http://jsfiddle.net/nbq6d/1/
Related
In C++, you have a bind function that allows you to bind parameters to functions. When you call the function, it will be called with those parameters. Similarly, MySQL has an ability to bind parameters to queries where it will substitute question marks with the variable. In Javascript and jQuery, the bind function has a confusingly different meaning. It makes the passed parameter the this variable, which is not at all what I want. Here's an example of what I want to achieve:
var outerVariable;
var callbacks = [
some_object.event,
some_object.differentEvent.bind(outerVariable)
];
// func() will automatically have outerVariable in scope
$.map(callbacks, function(func) { func(); });
I don't think there is an easy way to use bind without playing around with this, if you want to bind arguments only you may be better writing a wrapper
function bindArgs(fn) {
var slice = Array.prototype.slice,
bound_args = slice.call(arguments, 1);
return function () {
var args = slice.call(arguments, 0);
return fn.apply(this, bound_args.concat(args));
}
}
Now
function foo(a, b) {
console.log(this, a, b);
}
var bar = bindArgs(foo, 'bar');
var obj = {baz: bar};
obj.baz('baz'); // logs obj, "bar", "baz"
Do this instead:
var callbacks = [
some_object.event,
some_object.differentEvent.bind(some_object, outerVariable)
];
The only difference between the C++ and JavaScript bind is that the JavaScript bind takes one extra argument: thisArg, which will bind the keyword this for the bound function to whatever you pass in. If you do not want to re-bind the this-argument, then pass null as the first parameter, and the rest should look familiar to the C++ variant you speak of:
function add(a, b) {
return a + b
}
var three = add(1, 2)
var makeThree = add.bind(null, 1, 2)
three = makeThree()
Let's consider simple singleton implementation:
var singleton = function (Constructor) {
var singleton;
return function () {
if (!singleton) {
singleton = new Constructor();
}
return singleton;
};
};
We could move declaration of singleton variable to arguments:
var singleton = function (Constructor, singleton) {
return function () {
if (!singleton) {
singleton = new Constructor();
}
return singleton;
};
};
So I simply curious about side effects.
One more example:
var counter = (function (i) {
return function () {
i = (i || 0) + 1;
return i;
};
}());
We could move declaration of singleton variable to arguments
First, let's make it possible to talk about this without tying outselves up in knots by using the same symbol (singleton) for two completely different things within the same few lines of code.
Here's your seecond example renamed:
var singleton = function (Constructor, instance) {
return function () {
if (!instance) {
instance = new Constructor();
}
return instance;
};
};
If you did that, then calling the singleton function with two arguments would specify instance, making passing Constructor in pointless — Constructor would never be called by singleton (again, if you passed in two args [and the second arg was truthy]). So it would be a bit odd to do that.
But you asked about side-effects. There are no external effects involved if you assign to a formal argument within the function. It doesn't, for instance, have any effect outside the function:
function foo(arg) {
arg = 67;
}
var a = 42;
foo(a);
console.log(a); // Still 42
However, assigning to an argument rather than to a local variable does, in non-strict mode, have a small cost, because there's overhead involved: It relates to the magic arguments pseudo-array. In non-strict mode, there's a link between the formal arguments of a function and the arguments pseudo-array:
function foo(a, b) {
console.log(a);
console.log(b);
b = 42;
console.log(arguments[1]);
}
If we call that like this:
foo(1, 2);
we see
1
2
42
Note the magic: Assigning to the formal argument b updated the pseudo-array arguments. (It works the other way, too.) That link has a small but real runtime cost.
(In strict mode, there is no link, for this very reason.)
As far as closure goes, there is no difference in the two implementations. However, in first example, singleton is not settable by the caller.
I will choose between the two implementation, just based on whether singleton could have been created outside these example functions or not. If it can be, use model 2 otherwise use model 1
First of all, I don't want to add methods to Function.prototype. Doing that would make them available for all functions and that's not what I'm looking for.
In JavaScript you can create objects with custom prototypes like this:
function CustomObj() {}
CustomObj.prototype = {};
CustomObj.prototype.sayFoo = function () { return 'foo' };
var myCustomObj = new CustomObj(); //=> returns an object: {}
myCusomObj.sayFoo(); //=> 'foo'
You can also create array-like objects with custom prototypes like this:
function CustomArr() {}
CustomArr.prototype = [];
CustomObj.prototype.sayFoo = function () { return 'foo' };
var myCustomArr = new CustomArr(); //=> returns an ordered object: []
myCustomArr.sayFoo(); //=> 'foo'
What I'd like to do is use some kind of constructor to create a function with its own custom prototype in the same way. However, the following does not work:
function CustomFn() {}
CustomFn.prototype = function () {};
CustomFn.prototype.sayFoo = function () { return 'foo' };
var myCustomFn = new CustomFn(); //=> PROBLEM! returns an object: {}
myCustomFn.sayFoo(); //=> 'foo'
// ^^ Here, the prototype was applied but the output was not a function.
myCustomFn(); //=> TypeError: object is not a function
So is there any way to accomplish what I'm trying to do?
UPDATE
Maybe there's another way I could be asking this question that would make it a little clearer.
There's a problem with the idea of a closure:
function makeFn() {
var output = function () { /* do some stuff */ };
output.foo = function () { /* do some stuff */ };
return output;
}
var specialFn = makeFn();
Essentially, this technique gives me what I want. However, the problem is that every time I call makeFn, output.foo has to be created as a totally independent function that takes up its own memory. Gross. So I could move that method out of the closure:
var protoMethods = {
"foo" : function () { /* do some stuff */ }
};
function makeFn() {
var output = function () { /* do some stuff */ };
for (var i in protoMethods) {
Object.prototype.hasOwnProperty.call(protoMethods, i) &&
(output[i] = protoMethods[i]);
}
return output;
}
var specialFn = makeFn();
But now I have to manually do an iteration every time I call makeFn which would be less efficient than if I could just assign protoMethods to be the prototype of output. So, with this new update, any ideas?
It is a tricky thing indeed, more complicated than it should be if the language was designed well...
Basically, you just can't do it cleanly in current versions. Objects other than functions can not be callable.
In future Javascript versions, you can do it with a "proxy" object that can define a "call" handler. But it is still way too complicated and contrived in my opinion.
Another way to go about it is to make your object a real function, not a custom object. Then try to set its __proto__, which is non-standard yet but works in most modern browsers, except Opera and IE 8 or less. Also maybe set its constructor property for faking instanceof checks... such hacks are quite tricky though and results will vary a lot with environments.
The following example works fine on my Firefox:
http://jsfiddle.net/Q3422/2/
function MyFun() {
if (!this || this==window) {
return new MyFun();
}
var f = function() {
return "thanks for calling!";
}
f.__proto__ = MyFun.prototype;
f.constructor = MyFun;
return f;
}
MyFun.prototype = {
foo: function() {
return "foo:" + this();
},
__proto__: Function.prototype
};
var f = new MyFun();
alert("proto method:"+f.foo()); // try our prototype methods
alert("function method:"+f.call()); // try standard function methods
alert("function call:"+f()); // try use as a function
alert('typeof:' + typeof f); // "function", not "object". No way around it in current js versions
alert('is MyFun:' + (f instanceof MyFun)); // true
alert('is Function:' + (f instanceof Function)); // true
Just wanted to add that you should not be worried about "copying" functions to each instance of your objects. The function itself is an object, so is never really copied, nor is it recompiled or anything. It does not waste memory, except for the function object reference itself and any closure variables.
Iterating over the prototype to copy it should not concern you as well, I guess you will not have a gazillion methods.
So your own last solution is probably the best if you need to support environments where proto is not settable, and you are not worried that your prototype might get extended after some objects already got created and they may not pick up the changes.
You're at the heart of what inheritance in JavaScript is all about. Yes, since prototypes are objects, you'll want to set the prototype of CustomFn to an object instead of a function.
But that object can come from another function:
function ParentFn() {}
function CustomFn() {}
CustomFn.prototype = Object.create(ParentFn.prototype);
CustomFn.prototype.sayFoo = fun ...
If you don't have ES5 or a polyfill:
CustomFn.prototype = (function() {
function F(){}
F.prototype = ParentFn.prototype;
return new F();
}());
Some may tell you just to do the following but the above way is better:
CustomFn.prototype = new ParentFn();
I tried that too, when working on V library. I wanted to override the Function constructor to enforce a restricted syntax of constructor functions, that I'm calling "class functions" (and I'm confident to do so).
Answer is no, using the new operator you can only create new "object"s, but not new "function object"s.
However you can use a constructor function both as a constructor and as a function!
var CustomFn = function () {
if (this instanceof CustomFn) {
// here we are 'new CustomFn()'
}
else {
// here we are 'CustomFn()' or 'CustomFn.call()'
}
};
Or as I believe is the better concept, to do the function in first place and then let the constructor go:
var CustomFn = function () {
if (!(this instanceof CustomFn)) { // functioning
// here we are 'CustomFn()' or 'CustomFn.call()'
return new CustomFn(); // or return undefined or throw
}
// constructing
// here we are 'new CustomFn()'
// BaseCustomFn.call(this);
};
How to write chainable functions but do not pollute $.fn ? Write functions only for using inside my plugin. Is it possible?
$('.myclass').makeSomething().andOneMoreFunction().andLast();
It is correct approach?
UPD.
The best solution in my case is extension method:
String.prototype.getMyLength = function(){return this.length;}
And now I can apply this function to any string like this:
var mystring = "test";
mystring.getMyLength();
Or
"teststring".getMyLength()
And make it chainable:
String.prototype.getMe = function(){return this;}
"string".getMe().getMe().getMe().getMe().getMe();
Thanks for answers!
You can chain all you want. If you define a $.fn yourself it is important that you return this at the end of you function.
If you want to write some javascript yourself you can also chain! It just depends on what you return. So if you return some other object, you can chain on from that object. The return value is used for this.
Example
var obj = {
test : function(){
alert("Y");
return this;
},
test2 : function(){
alert("2");
return this;
}
}
obj.test().test2(); // And so on since it returns this
jQuery Plugin API
$.fn.test = function(){
var methods = {
method0 : function(){
alert("method0");
return this;
}
};
return methods;
}
var api = $("obj").test(); // Returns methods
api.method0(); // Calling a function from the returned methods.
// OR
$("obj").test().method0();
Above function is not jQuery chainable anymore. So you can't use the $("obj").test().addClass("test") because you return your own API!
You can avoid pollution by using the first parameter of your plugin's function to specify the method of choice; for instance
(function () {
var o = { // object holding your methods
'bar': function () {console.log('bar', this); return this;},
'foobar': function () {console.log('foobar', this); return this;}
};
$.fn.foo = function (method /*, args*/) {
return o[method].apply(
this,
Array.prototype.slice.call(arguments, 1) // pass your args
);
};
}());
and then
$('something').foo('bar').foo('foobar');
/*
bar, thisobj
foobar, thisobj
*/
This way you keep access to the jQuery object as normal, too.
When you call a.foo(), the function foo is invoked with this set to a. You can use this to your advantage.
Also recall that the expression a.foo() evaluates to whatever you returnd from within the function.
So, just return this.
Then a.foo() evaluates back to a, and (a.foo()).bar() becomes equivalent to calling a.foo() then calling a.bar()... i.e. chained operations on a!
$.fn is not particularly magical — it simply uses the above logic in the same way that you are about to.
I thought I understood the concept of the JavaScript prototype object, as well as [[proto]] until I saw a few posts regarding class inheritance.
Firstly, "JavaScript OOP - the smart way" at http://amix.dk/blog/viewEntry/19038
See the implementation section:
var parent = new this('no_init');
And also "Simple JavaScript Inheritance" on John Resig's great blog.
var prototype = new this();
What does new this(); actually mean?
This statement makes no sense to me because my understand has been that this points to an object and not a constructor function. I've also tried testing statements in Firebug to figure this one out and all I receive is syntax errors.
My head has gone off into a complete spin.
Could someone please explain this in detail?
In a javascript static function, you can call new this() like so,
var Class = function(){}; // constructor
Class.foo = function(){return this;} // will return the Class function which is also an object
Therefore,
Class.foo = function(){ return new this();} // Will invoke the global Class func as a constructor
This way you get a static factory method. The moral of the story is, not to forget functions are just like any other objects when you are not calling them.
What is confusing you, I think, is just where "this" is really coming from. So bear with me-- here is a very brief explanation that I hope will make it quite clear.
In JavaScript, what "this" refers to within a function is always determined at the time the function is called. When you do:
jimmy.nap();
The nap function (method) runs and receives jimmy as "this".
What objects have references to nap is irrelevant. For example:
var jimmy = {}, billy = {};
jimmy.nap = function(){ alert("zzz"); };
var jimmy_nap = jimmy.nap;
jimmy_nap(); // during this function's execution, this is *NOT* jimmy!
// it is the global object ("window" in browsers), which is given as the
// context ("this") to all functions which are not given another context.
billy.sleep = jimmy.nap;
billy.sleep(); // during this function's excution, this is billy, *NOT* jimmy
jimmy.nap(); //okay, this time, this is jimmy!
In other words, whenever you have:
var some_func = function(arg1, arg2){ /*....*/ };
// let's say obj and other_obj are some objects that came from somewhere or another
obj.some_meth = some_func;
other_obj.some_meth = some_func;
obj.some_meth(2, 3);
other_obj.some_meth(2, 3);
What it's getting "translated" into (not literally-- this is pedagogical, not about how javascript interpreters actually work at all) is something like:
var some_func = function(this, arg1, arg2){ /* ...*/ };
// let's say obj and other_obj are some objects that came from somewhere or another
obj.some_meth = some_func;
other_obj.some_meth = some_func;
obj.some_meth(obj, 2, 3);
other_obj.some_meth(other_obj, 2, 3);
So, notice how extend is used in the example on that page:
UniversityPerson = Person.extend({ /* ... */ });
Pop quiz: When extend runs, what does it think "this" refers to?
Answer: That's right. "Person".
So the puzzling code above really is the same as (in that particular case):
var prototype = new Person('no_init');
Not so mysterious anymore, eh? This is possible because unlike in some languages,
a JavaScript variable-- including "this"-- can hold any value, including a function such as Person.
(There is nothing that makes Person specifically a constructor. Any function can be invoked with the new keyword. If I recall the exact semantics, I think they are that when a function is called with the new keyword, it is automatically given an empty object ({}) as its context ("this") and when the function returns, the return value is that same object unless (maybe?) the function returns something else)
This is a cool question because it speaks to a pretty essential part of JavaScript's neatness or oddness (depending on how you see it).
Does that answer your question? I can clarify if necessary.
AJS.Class effectively* translates this:
var Person = new AJS.Class({
init: function(name) {
this.name = name;
Person.count++;
},
getName: function() {
return this.name;
}
});
Person.count = 0;
into this:
var Person = function (name) {
this.name = name;
Person.count++;
};
Person.prototype = {
getName: function() {
return this.name;
}
};
Person.extend = AJS.Class.prototype.extend;
Person.implement = AJS.Class.prototype.implement;
Person.count = 0;
Therefore, in this case, this in AJS.Class.prototype.extend refers to Person, because:
Person.extend(...);
// is the same as
Person.extend.call(Person, ...);
// is the same as
AJS.Class.prototype.extend.call(Person, ...);
* There are a lot of cases I don't go over; this rewrite is for simplicity in understanding the problem.
Imagine the following situation :
var inner = function () {
var obj = new this;
console.log(obj.myProperty);
};
var f1 = function () {
this.myProperty = "my Property"
}
f1.f2 = inner;
f1.f2();
Here the calling object is itself a function, so this will return a function, and we can instantiate it.
In order to use this()(not this) the outer function(the context) must itself return smth that can be instantiated(another function):
var inner = function () {
var obj = new this();
console.log(obj.myProperty);
};
var f1 = function () {
var func = function () {};
func.myProperty = 'my property';
return func;
};
f1.f2 = inner;
f1.f2();
A simpler code explaination:
class User {
constructor() {
this.name = '';
this.age = '';
}
static getInfo() {
let user = new this();
console.log(user);
}
}
User.getInfo()
Output:
Object {
age: "",
name: ""
}
see this link http://www.quirksmode.org/js/this.html It will tell you about the this keyword, but I am not sure what this() is, may be its some kind of user defined function...... that you are not aware of...
"this" means the context of the function currently running.
The code you are posting surely appears in a function that act as a method for an object.
So the object is the context of the function.
"new this()" will return a clone of the current object after running its constructor function with the passed arguments.
this() refers to the the function that the code is in, but this() would have to be within that function. Calling new this(); within a function would create a never ending loop. Calling it outside of a function would be redundant because there is no function/class set as this().