What is the difference between these 2 types of structures
var bar = {
something : value,
execute : function() { /* Whatever */ }
}
function foo() {
this.something = value;
this.execute = function() { /* Whatever */ };
}
My reasoning is that bar is a static object, and foo is a regular object that has to be created calling the new constructor
Is that correct ? Or not really
I assume you mean what's the difference between bar (as you declared it) and
var bar2 = new foo();
There's not a lot of difference between bar and bar2, other than that the prototype for bar will always be the prototype property of Object (as if you had written var bar = new Object(); bar.something = value; bar.execute = function() {...}), while the prototype for bar2 will be whatever is assigned to the prototype property of foo (or the prototype property of Object by default).
Other than the issue of prototypes, writing a constructor function is mostly a matter of convenience.
Note that with the constructor approach, you can use the prototype to advantage:
function foo() {
this.something = value;
}
foo.prototype.execute = function() { /* Whatever */ };
Then all instances of foo share the same execute function. This is much more space efficient than having a new function object for each foo object. (Of course, if you're only creating one of these, there's not much advantage.)
Related
According to http://js4py.readthedocs.org/en/latest/object-tree.html,
All JavaScript objects are part of an inheritance tree. Each object in
the tree has a parent object, which is also called the prototype
object (of the child).
I was playing around to make sure I understand it correctly. Shouldn't the following print "lakdas" since myOtherObj inherits the field x from its parent myObj? Why does it instead log undefined?
var myObj = { x:"lakdas" };
var myOtherObj = { y:"lkjaas" };
myOtherObj.prototype = myObj;
console.log(myOtherObj.x); /* Should print "lakdas", right? */
You can't change an object's prototype by assigning to a prototype property. In many engines you can't change the prototype at all after the object is created. You can set the prototype at object creation time:
var myObj = { x:"lakdas" };
var myOtherObj = Object.create(myObj); // sets prototype
myOtherObj.y = "lkjaas";
console.log(myOtherObj.x); // prints "lakdas"
Functions have a prototype property - when you use a function as a constructor, the object stored in the function's prototype property becomes the prototype of the constructed object:
var myObj = { x:"lakdas" };
function foo() {
this.y = "lkjaas";
}
foo.prototype = myObj;
var myOtherObj = new foo();
console.log(myOtherObj.x); // prints "lakdas"
I noticed that the Function.prototype has a toMethod() method in experimental JavaScript, but what does that actually do? And how do I use it?
Update: the toMethod method was experimental only and did not make it into the standard. The home object is essentially static now, the only way to manipulate super is to change the [[prototype]]:
var base = {…}; // as below
var obj = Object.setPrototypeOf({
foo() { // needs to use method definition syntax
super.foo();
}
}, base);
obj.foo();
It's very similar to the bind method of function objects. However, instead of creating a new function with a bound this value, it creates a new function with a bound [[HomeObject]], which is the reference that is used for super calls:
[[HomeObject]] (Object): If the function uses super, this is the object whose [[GetPrototypeOf]] provides the object where super property lookups begin.
Consider this example (not using any class syntax):
var base = {
foo: function() {
console.log("base foo called on", this);
}
};
base.foo(); // base foo called on base
var obj = Object.create(base);
obj.foo(); // base foo called on obj
obj.foo = function() {
super.foo();
};
obj.foo(); // ReferenceError: this method has no home
obj.bar = obj.foo.toMethod(obj);
obj.bar(); // base foo called on obj
obj.baz = function() {
super();
};
obj.baz(); // ReferenceError: this constructor has no parent class
Reflect.setPrototypeOf(obj.baz, base.foo);
obj.baz(); // base foo called on obj
My understanding is that .toMethod is like cloning a function. Consider the example in the source I posted,
class P { }
class C extends P {
foo() {
console.log("f");
super();
}
}
P.prototype.foo=C.prototype.foo;
(new C).foo();
Here you reference a subclass method .foo in the superclass, so when you call .foo, it will reference P's .foo which is C's .foo and you have just created a loop.
It seems like to solve this issue, you can use .toMethod which "clones" the function and give it a different super/"home" that you specifed:
P.prototype.foo = C.prototype.foo.toMethod(P.prototype);
now calling (new C).foo() would not go on forever.
I am creating an AJAX API for a web service and I want to be able to call jQuery-like accessors.
jQuery seems to be able to execute 'jQuery' as a function, but also use it to directly access the object that is the result of the function EG:
jQuery();
jQuery.each({});
This is the trick that I can't seem to pull off:
myAPI('foo'); //output: 'foo'
myAPI('foo').changeBar(); //output: 'foo' 1
myAPI.changeBar(); //Error: not a function
I have seen the answers to similar questions, which are helpful, but don't really answer my question.
#8734115 - Really interesting, but you can't access the methods that were set by f.prototype.
#2953314 - Uses Multiple operations to create object instead of a single function.
here is my code:
(function(window) {
var h = function(foo) {
// The h object is actually just the init constructor 'enhanced'
return new h.fn.init(foo);
};
/**
* Methods defined at protoype.
*/
h.fn = h.prototype = {
constructor: h,
init: function(foo) {
console.log(foo);
return this;
},
splice : function () {},
length : 0,
bar : 0,
changeBar : function() {
this.bar++;
return this.bar;
}
};
h.fn.init.prototype = h.fn;
//Publish
window.myAPI =h;
}( window));
I'm sure I'm missing something simple :(
What jQuery is doing there is using jQuery as both a function and as a pseudo-namespace. That is, you can call jQuery: var divs = jQuery("div"); and you can use properties on it, e.g.: jQuery.each(...);.
This is possible because in JavaScript, functions are first-class objects, and so you can add arbitrary properties to them:
function foo() {
alert("Foo!");
}
foo.bar = function() {
alert("Bar!");
};
foo(); // "Foo!"
foo.bar(); // "Bar!"
That's literally all there is to it.
Within the call to bar, this will be the foo function (because this is determined entirely by how a function is called, not where it's defined). jQuery doesn't use this to refer to itself (usually it uses this to refer to DOM elements, sometimes to other things like array elements; when referring to itself, since it's a single thing, it just uses jQuery).
Now, you might want to ensure that your functions have proper names (whereas the function I assigned to bar above is anonymous — the property has a name, but the function does not). In that case, you might get into the module pattern:
var foo = (function() {
function foo() {
alert("Foo!");
}
function foo_bar() {
alert("Bar!");
}
foo.bar = foo_bar;
return foo;
})();
foo(); // "Foo!"
foo.bar(); // "Bar!"
That pattern also has the advantage that you can have private data and functions held within the scoping function (the big anonymous function that wraps everything else) that only your code can use.
var foo = (function() {
function foo() {
reallyPrivate("Foo!");
}
function foo_bar() {
reallyPrivate("Bar!");
}
function reallyPrivate(msg) {
alert(msg);
}
foo.bar = foo_bar;
return foo;
})();
foo(); // "Foo!"
foo.bar(); // "Bar!"
reallyPrivate("Hi"); // Error, `reallyPrivate` is undefined outside of the scoping function
In your code, you're assigning things to the prototype property of the function. That only comes into play when the function is called as a constructor function (e.g., via new). When you do that, the object created by new receives the function's prototype property as its underlying prototype. But that's a completely different thing, unrelated to what jQuery does where it's both a function and a pseudo-namespace.
You do not need any of that weirdness, to use stuff like $.each
you just attach functions to the function object instead
of the prototype object:
function Constructor() {
if (!(this instanceof Constructor)) {
return new Constructor();
}
}
Constructor.prototype = {
each: function() {
return "instance method";
}
};
Constructor.each = function() {
return "static method";
};
var a = Constructor();
a.each(); //"instance method"
Constructor.each(); //"static method"
When I run this code:
function foo() {
console.log("foo");
var self = this;
this.a = function() {
return arguments.length == 0 ? self.b : (self.b = arguments[0]);
};
};
function bar() {
};
bar.prototype = new foo();
var a = new bar();
var b = new bar();
console.log(a.a());
b.a(true);
console.log(a.a());
I get the following output: foo, undefined, true
What I do not understand is how the object returned by the constructor function foo somehow manages to allocate a new memory location for b. I was totally expecting the last output to be true because I only get 1 foo output.
That this works is great, but it feels too much like magic.
My problem really here is that I'd like to setup an initialization order (or chain). What I've realized is that foo cannot take any arguments, because it's only called once, to provide a base (or template of sorts).
I'd like to devise a really simple schema where foo has parameters that has to be passed from bar to foo (because bar inherits foo). I'm fine with something like calling foo.apply(this, arguments) from bar but the call to set the prototype has to be done without arguments, what I need is a fluent way to somehow tell the two apart.
But I really don't want to build an entire service around creating objects that allow some kind of inheritance, the only thing I really care about is constructing the objects, correctly...
On a side note, you're sometimes using self and sometimes using this... personally, I'd be more consistent. I like to use that because this can be confusing and self is part of the BOM, but it's just a matter of taste.
Try parasitic inheritance:
function foo(arg) {
var that = this;
that.a = function() {
return arguments.length == 0 ? that.b : (that.b = arguments[0]);
};
}
function bar(arg) {
return new foo(arg);
}
bar.prototype = new foo();
var a = new bar(); // the `new` is now optional. Personally I'd remove it...
var b = bar(); // ... like I did here!
console.log(a.a());
b.a(true);
console.log(a.a());
console.log(b.a());
... here the inheritance behaves in a more classically, explicitly invoking a parent constructor when the constructor is called.
Well, this is one of the weak spots (and yet, strong spots) of JS. You're running into a pattern issue here. I'd suggest taking a look at http://ejohn.org/blog/simple-javascript-inheritance/ - there's a free 'class' you can use to help straighten up what one would expect with a more 'classical' inheritance.
Just as a quick example, most patterns I've seen have a base 'object' (which is more or less a customized class) and the constructor (which is more or less 'how the object gets built') calls something like "this.init.apply(this, arguments)". That calls an 'init' method on the object with all the arguments that have been passed. So the init can then be set, extended, re-set, etc., and the constructor always calls the one that is 'local' to itself with the arguments that have been passed. Pretty neat.
Hope that helps, or at least doesn't confuse.
The last output is true. You are being deceived by your JavaScript console. That last undefined is the return value from your expression. Make your console.log() calls more descriptive to shine a light on what's happening:
function foo() {
console.log("foo constructor called");
var self = this;
this.a = function() {
return arguments.length == 0 ? self.b : (self.b = arguments[0]);
};
}
function bar() {
}
bar.prototype = new foo();
var a = new bar();
var b = new bar();
console.log("value from a.a(): " + a.a());
b.a(true);
console.log("value from a.a(): " + a.a());
console.log("done logging");
This yields the following output in the console:
foo constructor called
value from a.a(): undefined
value from a.a(): true
done logging
undefined
It's not magic, it's prototypal inheritance. I think what you're trying to achieve is combining two constructor functions to get called automagically. You're probably mixing up constructors and prototypes.
But I really don't want to build an entire service around creating
objects that allow some kind of inheritance, the only thing I really
care about is constructing the objects, correctly...
I don't know what you mean by "service". But as in any other object-oriented programming language, superclass method calls need to be done manually. So either you hard-code the "superclass" like this:
function foo() {
console.log("foo");
var self = this;
this.a = function() {
return arguments.length == 0 ? self.b : (self.b = arguments[0]);
};
}
function bar() {
foo.apply(this, arguments); // <- ugly
}
//bar.prototype = new foo(); // this is not neccessary
...or you build some wrapper stuff to connect your "classes". Something like:
function inherit(superconstructor) {
return function () {
superconstructor.apply(this, arguments);
};
}
function foo() {...}
bar = inherit(foo);
I use the following function for creating new objects.
function newObj(o) {
var params = Array.prototype.slice.call(arguments,1);
function F() {}
F.prototype = o;
var obj = new F();
if(params.length) {
obj.init.apply(obj,params);
}
return obj;
}
And it works well most of the time. However one of my base "classes" is now defined as inheriting from another base class
SPZ.EditablePuzzle = function () {
// function and variable definitions
return {
///some methods and properties
}
}();
SPZ.EditablePuzzle.prototype = SPZ.Puzzle;
Now when I use newObj() to create a new SPZ.EditablePuzzle the init function is not defined even though it is defined in SPZ.Puzzle and I make sure EditablePuzzle runs after Puzzle
Why won't my newObj function find the init function? Shouldn't it automatically look in the prototype as soon as it fails to find it in the object itself?
I suspect the inheritance is not well set. try doing
SPZ.EditablePuzzle.prototype = new SPZ.Puzzle;
Might solve this problem, though I am not sure.
Concerning the problem:
function Foo() {
}
Foo.prototype.init = function() {
console.log('bla');
};
function FooBar() {
}
FooBar.prototype = Foo; // looks fishy...
var kitten = new FooBar();
console.log(kitten.init); // yields undefined, uh what?
The problem is, that in this case Foo itself gets assigned to the prototype property, when in fact you wanted to do:
FooBar.prototype = Foo.prototype
See the difference? Foo has no init property as it is defined on the prototype object.