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);
Related
I'm trying to get my head around Javascript OO, using the IIFE module pattern to mimic a class:
var MyClass = (function() {
// Constructor
return function() {
return {
foo: 'foo'
}
}
}());
I'm passing arguments with something like:
var MyClass = (function() {
// Constructor
return function(arg) {
return {
foo: function() {
return 'foo'+arg
}
}
}
}());
To mimic classical inheritance I am using the pattern suggested here:
function inherit(base, child, obj) {
child.prototype = Object.create(base.prototype);
child.prototype.constructor = child;
obj&&Object.keys(obj).forEach(function(key){
child.prototype[key] = obj[key];
})
}
var Base = (function() {
var init = function() {};
init.prototype = {
foo: function() {
return "foo";
}
};
return init;
}());
var Child = (function() {
var init = function() {
Base.call(this);
};
inherit(Base, init, {
bar: function() {
return 'bar';
}
});
return init;
}());
So far so good. My only problem is in understanding how to pass parameters to my class constructor when I'm doing inheritance in the above way. I like the fact that in the 'pure' IIFE module I can simply refer to the constructor parameter in any functions defined within it, so that they become closures. But how do I access constructor params when I'm adding these subsequent functions using the constructor variable, as in the inheritance example above? I suppose I could do something like:
var init = function(arg) {
this.theArg = arg;
};
Then I can access it within anything subsequent:
init.prototype = {
foo: function() {
return "foo"+this.theArg;
}
};
And for the child:
var init = function(arg) {
Base.call(this, arg);
};
This makes arg available to the outside world, so to make it read-only I suppose a getter would work:
var init = function(arg) {
var theArg = arg;
this.getArg = function() { return theArg };
};
On the face of it I can't see anything wrong with that, and I can't think of a better alternative. Is there one? Am I missing something obvious?
I can't think of a better alternative. Is there one?
No. Not in your example.
I like the fact that in the 'pure' IIFE module I can simply refer to the constructor parameter in any functions defined within it, so that they become closures.
You can access args in each function because, in your first example, you are defining foo on each object instance separately. Therefore each definition of foo has a separate closure containing the args passed when it was defined.
This is also only possible, because foo is defined within the scope containing your args.
But how do I access constructor params when I'm adding these subsequent functions ... in the inheritance example above?
By using the classical inheritance patten you found, you are now defining the foo function on the constructor prototype. This means that only a single foo definition exists which is inherited by all instances created using your constructor. So foo can not be made specific to each instance anymore.
As you have figured, it also means foo is no longer defined inside the scope containing args and has no direct access.
You are therefore correct by assigning args to this.thisArgs which allows foo to access thisArgs on each instance. You have made foo a general case function that can handle any instance it is applied to.
Passing arguments to the IIFE constructor: The IIFE itself is not the constructor, it simply builds the constructor object. The IIFE's scope has long since been returned by the time the constructor itself is invoked.
Am I missing something obvious?
Yes. Javascript is a prototypical language. It was never meant to be like "classical" languages. Just let it be Javascript. :)
JavaScript uses a Prototype system, which is fundamentally different than a Class system. This is my first serious encounter with the language. I had fooled around with it previously, but this is the first time I built a system with proper OO, inheritance, polymorphism, etc.
From what I read there seems to be a few common methods to do member function inheritance in Javascript. Assuming you have a parent foo as following
foo = function(){ this.one = 1; }
foo.prototype.func1 = function(){return this.one;}
The MDN Introduction to JavaScript Inheritance suggests the naive approach of invoking the parent's method in the context of the child, as shown below.
bar = function(){ foo.call(this); }
bar.prototype = Object.create(foo.prototype);
bar.prototype.func1 = function(){ return this.one + foo.prototype.func1();}
This has the advantage of being simple to understand, but can become cumbersome as pointed out in this Salsify Blog post. The blog post outlines an alternate method where a super property is defined in the child prototype, and the name of each member function is attached as a property to the method. This method, however, relies on the caller property of a method, which the article points out will soon be deprecated. Rather than duplicate the entire post, I believe a summary of the important points are these
Object.defineProperty(bar.prototype, "super", {
get: function get() {
...
// methodName is set as a property on each method in an omitted code segment
methodName = get.caller.methodName;
...
Object.getPrototypeOf(this.prototype)[methodName]
}
}
Which is to say that you find the method with the same name in your prototype's prototype. I was wondering if this can be done in a simpler manner, without having to attach the method name as a parameter and without the Function.caller.
foo.prototype.super = function(method) {
superMethod = Object.getPrototypeOf(this.constructor.prototype)[method];
return superMethod.call(this, Array.prototype.slice.call(arguments, 1));
}
bar.prototype.func1 = function(){ return this.one + super('func1'); }
I'm making a number of assumptions in the above, I'd like to verify some assumptions.
new bar().constructor.prototype === Object.getPrototypeOf(new bar())
If the above is always true, is one preferable over the other?
The Parent's member function will always live in the child's prototype's prototype (assuming that neither of the prototypes were mutated after object creation)
That Object.getPrototypeOf() is not the "language support for accessing super methods" that the blog refers to as being added in ES6
If Object.getPrototypeOf() isn't that language support, what is?
After seeing the error of using this, which does not change throughout the execution and always refers to the instance of the subclass, I've revisited and am thinking I need something like this
Grandfather = function(){};
Grandfather.prototype.function1 = function(){console.log("I am the Grandfather");};
Father = function(){Grandfather.apply(this);};
Father.prototype = Object.create(Grandfather.prototype);
Father.prototype.function1 = function f(){ f.super(); console.log("I am the Father");};
Father.prototype.function1.super = Grandfather.prototype.function1;
Child = function(){Father.apply(this);}
Child.prototype = Object.create(Father.prototype);
Child.prototype.function1 = function f(){ f.super(); console.log("I am the Child");};
Child.prototype.function1.super = Father.prototype.function1;
c = new Child();
c.function1();
// I am the Grandfather
// I am the Father
// I am the Child
And so the question becomes, how to set the super property on to each function in some automatic way?
One such way to do this is shown below, it has the benefit that functions added to the prototype after objects are instantiated still receive the benefit of being able to call superFunc, whereas an approach that sets a super property at class extension time would not set such a property if functions are added to the prototype later.
The downsides of this approach are that it only works in single threaded environment and that it requires functionality inherited from a common base class. It is not threadsafe since some state is held in a what is effectively a static variable of the function. This is fine for my purposes since browsers still have single threaded JavaScript. The requirement that all classes inherit from some base class containing this method isn't a huge blocker (especially if you do a "bad thing" and insert this into Object's prototype).
Grandfather.prototype.superFunc = function f(funcName){
currentPrototype = Object.getPrototypeOf(f.startingPrototype || Object.getPrototypeOf(this));
f.startingPrototype = currentPrototype;
return currentPrototype[funcName]();
}
Child.prototype.function2 = function(){this.superFunc('function2'); console.log("Still in the Child");};
Father.prototype.function2 = function(){this.superFunc('function2'); console.log("Still in the Father");};
GrandFather.prototype.function2 = function(){console.log("Still in the Grandfather");};
c = new Child();
c.function2();
// Still in the Grandfather
// Still in the Father
// Still in the Child
Question 1
new Bar().constructor.prototype should equal Object.getPrototypeOf(new Bar()), provided you haven't overrided Bar.prototype.constructor or Bar.prototype, or return a different object in the Bar constructor. Here's an example:
function Bar() {}
var foo = new Bar();
foo.constructor.prototype === Object.getPrototypeOf(foo); // true
function Bar2() {}
var foo2 = new Bar2();
Bar2.prototype = {};
foo2.constructor.prototype === Object.getPrototypeOf(foo2); // false
function Bar3() {}
var foo3 = new Bar3();
Bar3.prototype.constructor = function NotBar3() {};
foo3.constructor.prototype === Object.getPrototypeOf(foo3); // false
Question 2
If you're looking to get the actual prototype of an object, use Object.getPrototypeOf, as that's unaffected by any of the changes shown above.
Question 3
No, you will not be able to access Foo from new Bar(). In your example, new Bar() would not inherit from Foo.prototype and as a result, there's no way to access Foo unless you make it inherit from Foo.prototype or assign Foo to a property of new Bar() or Bar.prototype.
Question 4/5
No, that's not what they're referring to. ES6 will introduce a separate class contruct, where super takes on a special meaning (similar to how super works in other languages with classes). Here's an example of how classes work in ES6:
class Foo {
constructor() {
this.one = 1;
}
func1() {
return this.one;
}
}
class Bar extends Foo {
func1() {
return this.one + super();
}
}
When you use super in the way you do it'll break when inheritance is more than 2 levels.
Assuming you'd use it the following way:
//changed super to this.super since super is not shown to exist in global scope
bar.prototype.func1(){ return this.one + this.super('func1'); }
See the following example:
function GrandFather(){
this.i = 0;
};
GrandFather.prototype.test = function(){
console.log('test in GrandFather');
};
function Father(){
GrandFather.call(this);
};
Father.prototype = Object.create(GrandFather.prototype);
Father.prototype.constructor = Father;
Father.prototype.super = GrandFather.prototype;
Father.prototype.test = function(){
console.log('test in Father');
//prevent too many recursions
this.i++;
if(this.i>5){
return;
}
this.super.test.call(this);//because test in child was called
// with Child instance as invoking object this will be Child
// and this.super will be Father.prototype
};
function Child(){
Father.call(this);
}
Child.prototype = Object.create(Father.prototype);
Child.prototype.constructor = Child;
Child.prototype.super = Father.prototype;
Child.prototype.test = function(){
console.log('test in Child');
this.super.test.call(this);//because invoking object is Child
//this.super in Father is Child
};
var c = new Child();
c.test();
It's also common practice to start a constructor function with a capital so it's better to use Foo and Bar for constructor function names.
If you want to go through all the trouble of simulating super in JavaScript then the following way would be slightly more robust: http://ejohn.org/blog/simple-javascript-inheritance/
JavaScript can create a object in many ways.
I try the following code to avoid new keyword to create a new Object of Class A.
My question is that A.prototype.init() here is whether equals new A()? is this good for practice, and why?
function A(){
}
A.prototype.init=function(){
return this;
}
var a = A.prototype.init();
console.log(a);
var a1=new A();
console.log(a1);
jsfiddle
All you're doing is returning the A.prototype object. You're not really initializing anything, and you're not using the result.
console.log(A.prototype === A.prototype.init()); // true
So unless you have a particular use in mind, I'd say, no it's not a good practice.
Not sure exactly why you want to avoid new, but in any case, you can change your constructor so that it can be called with or without new and still behave like a constructor.
function A() {
var ths = Object.create(A.prototype);
ths.foo = "bar";
return ths;
}
Now it won't matter if you use new. You're going to get a new object that inherits from A.prototype no matter what.
You can still use an .init() method, but you might as well just put the logic in the constructor.
Furthermore, you can easily create a factory that takes care of that little bit of boilerplate code.
function Ctor(fn) {
return function() {
var ths = Object.create(fn.prototype);
fn.apply(ths, arguments);
return ths;
};
}
So now you'd create your constructor like this:
var A = Ctor(function() {
this.foo = "bar";
});
You can avoid new by encapsulating your code with the module pattern and returning a function that calls the constructor, in other words:
var A = (function ClassA() {
// Constructor
function A(prop) {
this.prop = prop; // instance property
this._init();
}
// Public methods
A.prototype = {
_init: function() {
}
};
// Mini factory to create new instances
return function(prop) {
return new A(prop); // well, only one `new`
};
}());
Now you can create new instances without new:
var a = A('foo'); //=> A { prop: "foo", init: function }
Usually you catch direct function calls with instanceof:
function MyConstructor (a, b, c) {
if (!(this instanceof MyConstructor)) {
return new MyConstructor(a, b, c);
}
// ...
}
but there is no good reason to avoid using new. Object.create and other alternatives can have a significant performance impact.
I'm trying to create some kind of inheritance between objects:
var foo = (function(){
function doFooStuff(){
console.log(arguments.callee.name);
}
return {
doFooStuff: doFooStuff
}
})();
var bar = (function(){
$.extend(this, foo);
function doBarStuff(){
console.log(arguments.callee.name);
doFooStuff();
}
return {
doBarStuff: doBarStuff,
}
})();
bar.doBarStuff();
bar.doFooStuff(); //<-- Uncaught TypeError:
//Object #<Object> has no method 'doFooStuff'
http://jsfiddle.net/wRXTv/
Why isn't doFooStuff accessible here? Would you recommend another approach than using $.extend?
$.extend(this, foo);
this is not the object which you return from the function below (in fact it cannot be since it's created after this call), but the global object - check MDN's introduction to the this keyword.
For what you want to do, there are two ways:
Copy all properties from foo onto your bar object after it is created:
var bar = (function() {
…
return {…};
})();
$.extend(bar, foo);
You can do that as well directly on the returned object:
return $.extend({…}, foo);
A variant of this pattern allows you to overwrite foo properties. Copy foo into an empty object, then write your bar properties to it:
return $.extend({}, foo, {…});
Use prototypical inheritance. Create an object that inherits its properties from foo, and then write your bar properties to it:
return $.extend(Object.create(foo), {…});
Now when foo changes afterward, you still can access those new properties on bar (unless they're shadowed by own properties). Notice that Object.create might not be supported in legacy environments, but you can easily shim it.
As noted by #raina77ow, your doBarStuff function is flawed too. The doFooStuff function is not in the scope of your function, and you cannot change that. You never will be able to access the private declared functions and variables from the foo module, only those that are public - if you did need them, consider a different pattern or app design. However, doFooStuff is a property on the exported (public) foo object, from which bar inherits (regardless in which of the above demonstrated ways). Therefore, you can access it as a method of bar as well, usually by using this.doFooStuff().
You attempt to work with revealing module as if it were a constructor. Hence an attempt to extend this, wrong for many reasons. The most glaring, I suppose, is that neither the function is used as a constructor (no new) nor its context is changed. In plain words, this just points to a global object here.
But that's not the only problem. Consider that part of your code:
function doBarStuff(){
console.log(arguments.callee.name);
doFooStuff();
}
Here doFooStuff won't be in the scope even if you somehow manage to extend this. ) Remember, the scope resolution doesn't involve the context object.
So what's the solution? Well, I often use aggregation in similar cases:
var foo = (function(){
function doFooStuff(){
console.log(arguments.callee.name);
}
return {
doFooStuff: doFooStuff
}
})();
var bar = (function(){
var _super = foo;
function doBarStuff(){
console.log(arguments.callee.name);
_super.doFooStuff();
}
// static parent: further changes on `foo` won't affect `bar`,
// as $.extend takes the parent's current state
return $.extend({}, _super, {
doBarStuff: doBarStuff,
});
// dynamic parent: further changes on `foo` will affect `bar`,
// as extended object now has `foo` in its prototype chain
return $.extend(Object.create(_super), {
doBarStuff: doBarStuff,
});
})();
JS Fiddle.
Yes, it's aggregation, not inheritance. But so what? I'm still able to get the main prize - removing code duplication AND I'm able to control the usage of parent functions within the child module.
The problem with your code is that this in $.extend(this,foo) refers to the window object and not foo. Anonymous function are run in window's context.
I would recommend using a John Resig implementation of classical inheritance in javascript.
http://ejohn.org/blog/simple-javascript-inheritance/.
Extract:
var Person = Class.extend({
init: function(isDancing){
this.dancing = isDancing;
},
dance: function(){
return this.dancing;
}
});
var Ninja = Person.extend({
init: function(){
this._super( false );
},
dance: function(){
// Call the inherited version of dance()
return this._super();
},
swingSword: function(){
return true;
}
});
var p = new Person(true);
p.dance(); // => true
var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true
// Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class
It is because this is an anonymous function. This part of your function deceleration:
var foo = (function(){
function doFooStuff(){
console.log(arguments.callee.name);
}
return {
doFooStuff: doFooStuff
}
})();
Do you see that you are immediately invoking this function call and ultimately do not have access to doFooStuff within your return statement.
If you remove the anonymous function deceleration, it will work.
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"