Understanding behavior of prototype - JavaScript - javascript

I don't understand why the following is happening:
I have the following code:
singleton = (function() {
somePrivFunction = function() {
return new B();
}
A = function() {};
B = function() {};
C = function() {};
A.prototype.a = function() { console.log("a"); };
B.prototype = A.prototype;
B.constructor = B;
B.prototype.b = function() { console.log("b"); };
C.prototype = A.prototype;
C.constructor = C;
C.prototype.c = function() { console.log("c"); };
return {
someFunction: function() {
return somePrivFunction();
}
}
})();
When I call singleton.someFunction() it returns me an instance of B. However all of the following work:
singleton.someFunction().b(); // Prints "b"
singleton.someFunction().a(); // Prints "a"
singleton.someFunction().c(); // Prints "c", but why? Shouldn't it be undefined?

B.prototype has a reference to the same object as A.prototype (line 12). On line 16 you stored a reference of this same object to C.prototype. This means all three prototypes point to the same object, therefore all changes made to A.prototype, B.prototype or C.prototype will actually change the same object. At the end of your code, this object has three methods: a, b and c.

Related

Multiple inheritance console output

I am using below code. I'm getting wrong output console with my code. Right now i am getting "this is aB" but i required constructor related output on my output console. Like "this is aA" for first, "this is aB" for second, "this is aC" for third console.
function A () {
this.name = "A";
}
A.prototype.a = function () {
console.log("this is a"+this.name);
}
function B () {
this.name = "B";
}
B.prototype.b = function () {
console.log("this is b"+this.name);
}
function C() {
this.name = "C";
A.call(this);
B.call(this);
}
C.prototype = Object.assign({}, A.prototype, B.prototype);
C.prototype.constructor = C;
C.prototype.c = function () {
console.log("this is c"+this.name);
}
var x = new C();
x.a(); //this is aB
x.b(); //this is bB
x.c(); //this is cB
this in all three constructors refers to the same object: The one created by the new operator. That one object can only have one name property. So whichever constructor you call last will "win" and the name will be assigned by that. Thus, you're seeing B all the time because even with new C, first C writes C, then A writes A (overwriting C), and finally B writes B (overwriting A).
If you want the code related to each level in the hierarchy to have its own name property, you cannot literally do that, but you can get close by having each one use its own property (e.g., nameA, nameB, and nameC). You can do this in a way that doesn't require you to remember which level you're writing the code at by using brackets notation and a variable shared by all the code for each level.
I'm not recommending that. Whatever the actual problem you're trying to solve is, there's probably a better solution.
But here's how you'd do it:
var A = (function() {
var name = "nameA"; // <== We declare a variable and put this level's property name in it
function A() {
this[name] = "A"; // <== Note we're using brackets notation here
}
A.prototype.a = function() {
console.log("this is a: " + this[name]); // <== Brackets again here
};
return A;
})();
var B = (function() {
var name = "nameB"; // <== Same again for B
function B () {
A.call(this);
this[name] = "B";
}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
B.prototype.b = function() {
console.log("this is b: " + this[name]);
};
return B;
})();
var C = (function() {
var name = "nameC";
function C() {
B.call(this);
this[name] = "C";
}
C.prototype = Object.create(B.prototype);
C.prototype.constructor = C;
C.prototype.c = function() {
console.log("this is c: " + this[name]);
};
return C;
})();
var x = new C();
x.a(); //this is aA
x.b(); //this is bB
x.c(); //this is cC
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
The one object all three constructors work with will end up with three properties: nameA, nameB, and nameC.
Again, I'm not recommending that, just pointing out that it's possible, and can suit some problems, although it's unclear whether it suits yours.
That was 2016. Here in 2020, you'd probably solve this with private fields. You can use them with a transpiler now and support is being actively added to JavaScript engines:
// NOTE: Only works in environments that support private fields (such as
// modern Chromium-based browsers)
class A {
#name; // <== Private field, only accessible to A's code
constructor() {
this.#name = "A";
}
a() {
console.log("this is a: " + this.#name);
}
}
class B extends A {
#name; // <=== Private field, only accessible to B's code
constructor() {
super();
this.#name = "B";
}
b() {
console.log("this is b: " + this.#name);
}
}
class C extends B {
#name; // <=== Private field, only accessible to C's code
constructor() {
super();
this.#name = "C";
}
c() {
console.log("this is c: " + this.#name);
}
}
const x = new C();
x.a(); // tthis is a: A
x.b(); // tthis is b: B
x.c(); // tthis is c: C
The one object created by new C will have a different private #name field for each class.

JavaScript - why must we return a function from a self-invoking function?

This code has a runtime error:
var person = (function(){
var Person = {
init: function() {
},
};
return new Person();
/*return function(){
new Person();
}*/
})();
console.log(person);
it says I have to return a function instead of a plain Object.
Why is that I can't return an object from the self-invoking/anonymous outer function? Why must I return a function?
likewise, this altered code also gives me a similar error:
var person = function(){
var Person = {
init: function() {
},
};
return new Person();
/*return function(){
new Person();
}*/
};
console.log(person());
Why is that I can't return an object from the self-invoking/anonymous outer function?
You can return an object, that is not what's wrong with your code.
The problem with your code is that Person is an object, not a function. Calling new Person() is invalid.
var person = (function () {
return {
name: 'bob'
};
}());
console.log(person.name);
The problem here is that you have declared Person as an object, and you can't use new Person() with an object. To create a "class" in ES5 you create a function instead.
var person = (function(){
var Person = function() {
this.init = function() {
console.log('Initing!')
}
};
return new Person();
})();
console.log(person);
http://jsfiddle.net/758zL8v3/
The alternative is the following Object constructor:
var person = function(){
var Person = function(){
this.init = function() {
};
};
return new Person();
};
You can read more about Object Oriented programming here.
Why must I return a function?
Because the new operator creates an instance of a Javascript Object. And to create it, it needs a constructor function. And that is that function you're asking about.
It's almost like calling a typical function
function add() {
return 1 + 1;
}
add();
// 2
but when you call it with the new operator, you create a new instance of this function object (functions are objects too, in Javascript).
function myAdder() {
this.a = 1;
this.b = 1;
this.add = function () {
return this.a + this.b;
};
return this;
}
myObject = new myAdder();
myObject.b = 2;
myObject.add();
// 3
And the object notation of myAdder would be:
function myAdder() {
return {
a: 1,
b: 1,
add: function () {
return this.a + this.b;
}
};
}

Override this.method = function() inside of a var x = function()

I have a Javascript Object:
var Dog = function() {
this.speak = function() {
return 'woof'
}
this.trick = function() {
return 'sitting'
}
}
I want to make a new object, Cat, that is based on Dog but has a different speak method:
var Cat = ???
...
this.speak = function() {
return 'meow'
}
...
So I can ultimately do this:
var tabby = new Cat();
tabby.speak() //returns 'meow'
tabby.trick() //returns 'sitting'
I have little experience with 'object-oriented Javascript' and can't seem to find an example online that reflects what I want to do, nor do I know what keywords to search for.
I thought it would be something similar to how I override functions in Backbone, but this seems different:
var Cat = Dog.extend({
//the speak function below would override the one that returns 'woof'
speak: function() {
return 'meow'
}
});
Any help is appreciated!
(Above is the simplified version of my ultimate goal - I want to override the render method inside of Rickshaw.Graph.Axis.X)
Usually in JavaScript, we'll define methods on a prototype, instead on the instance:
function Dog() {}
Dog.prototype.speak = function () {
return 'woof';
};
Dog.prototype.trick = function () {
return 'sitting';
};
The difference between defining a method on a prototype and on the instance is that prototypes allow you to share properties between all objects that have their prototype set to the same object. This object is where you define what properties are shared, and a prototype object can also have its own prototype, creating a prototype chain.
To create a simple example, let's take a look at a simple example:
var foo = { bar: 1 };
// create a new object with its prototype set to `foo`
var baz = Object.create(foo);
console.log(foo.bar); // 1
console.log(baz.bar); // 1
// prototype properties and values are shared
foo.bar = 2;
console.log(foo.bar); // 2
console.log(baz.bar); // 2
// this is an instance property, so the property is no longer shared
baz.bar = 3;
console.log(foo.bar); // 2
console.log(baz.bar); // 3
If you have a prototypal-inheritance system in place, this is what you'd do:
function Dog() {}
Dog.prototype.speak = function () {
return 'woof';
};
Dog.prototype.trick = function () {
return 'sitting';
};
function Cat() {}
Cat.prototype = Object.create(Dog.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.speak = function () {
return 'meow';
};
Remember that if you define a property on an instance, it will override the property set on the prototype, the prototype's prototype, and so on.
If you're looking for an answer to your specific situation where you have the methods defined on an instance (and it isn't a built-in constructor -- some have special behaviour), you need to do something a bit different:
function Cat() {
Dog.call(this);
this.speak = function () {
return 'meow';
};
}
What this does is it gives the Dog function the current object of the instance of Cat, on which it can set properties on. This is done by setting the value of this in Dog to the instance of Cat, just for that call using func.call(/* value of this */);.
Given your current approach, you could do this:
var Dog = function() {
this.speak = function() {
return 'woof'
}
this.trick = function() {
return 'sitting'
}
}
var Cat = function() {
Dog.call(this)
this.speak = function() {
return 'meow'
}
}
Though we're not using prototypal inheritance here. We're just assigning own properties directly to the objects. This is less efficient than using shared, inherited methods. Not to mention that the Cat creates the speak method on the Dog, then overwrites it immediately.
var tabby = new Cat();
tabby.speak() //returns 'meow'
tabby.trick() //returns 'sitting'
function Dog() {}
Dog.prototype.speak = function() {
return 'woof';
};
Dog.prototype.trick = function() {
return 'sitting';
};
function Cat(){}
Cat.prototype = Object.create(Dog.prototype);
Cat.prototype.speak = function() {
return 'meow';
};
var fluffy = new Cat();
fluffy.speak(); // 'meow'
fluffy.trick(); // 'sitting'
Basically, you want to do some Googling for "prototypal inheritance".
Same concept as the other answers but here is the javascript secret inherits function slightly simplified from google closure - https://code.google.com/p/closure-library/source/browse/closure/goog/base.js#1578
var inherits = function(child, parent) {
function tmp () {};
tmp.prototype = parent.prototype;
child.superClass_ = parent.prototype;
child.prototype = new tmp;
child.prototype.constructor = child;
};
Now you can
var Dog = function() {};
Dog.prototype.speak = function(){
return 'woof';
}
Dog.prototype.trick = function(){
return 'sitting';
}
var Cat = function(){};
inherits(Cat, Dog); //weird
Cat.prototype.speak = function(){
return "meow";
};
var HouseCat = function(){};
inherits(HouseCat, Cat);
HouseCat.prototype.speak = function(){
return "purr";
};
var dog = new Dog();
var cat = new Cat();
var houseCat = new HouseCat();
console.log(dog.speak()); //woof
console.log(cat.speak()); //meow
console.log(houseCat.speak()); //purr
console.log(houseCat.trick()); //sitting
console.log(cat instanceof Dog); //true
console.log(houseCat instanceof Cat); //true
console.log(houseCat instanceof Dog); //true
console.log(dog instanceof Cat); //false
console.log(cat instanceof HouseCat); //false

Javascript prototypal inheritance and OOP

I'm creating an application that allows a user to create widgets. There are several different types of widgets, and I have defined them using protypal inheritance. i.e.
//the base widget that all widgets inherit from
var Widget = function(){}
Widget.prototype.someFunction = function(){}
//widget type A
var A = function(){}
A.prototype = new Widget();
//widget type B
var B = function(){}
B.prototype = new Widget();
I have discovered that it will be convenient to add a method on the base class that can create a new widget instance of the same type. i.e.
//the base widget
var Widget = function(){};
Widget.prototype.clone = function(){
switch(this.type){
case 'A':
return new A();
break;
case 'B':
return new B();
break;
default:
break;
}
};
Which would allow me to get a new widget of the same type using the following code:
var widgetTypeA = new A();
var cloneOfWidgetTypeA = widgetTypeA.clone();
My concern is that the base widget now has to be explicitly aware of each of the types of widgets that inherit from it. Does this violate any principles of good OOP?
Widget.prototype.clone = function() {
var constructor = window[this.type];
return new constructor();
};
Assuming that all your subclasses are declared as globals of course.
But honestly I would out those sub classes in the Widget namespace, and access them through it rather than making everything global.
Widget.A = function(){};
Widget.A.prototype = new Widget();
Widget.prototype.clone = function() {
var constructor = Widget[this.type];
return new constructor();
};
Given that your constructors are globals, you could do something like:
var global = this;
Widget.prototype.clone = function() {
if (global[this.type])
return new global[this.type]();
};
Provided each instance has a type property whose value is the name of the constructor. Or you could fix the constructor property of constructor's prototype and do:
Widget.prototype.clone = function() {
return new this.constructor();
};
function A() { };
A.prototype = new Widget();
A.prototype.constructor = A;
var a = new A();
var aa = a.clone();
However, that assumes that you don't have any parameters to pass. If you do have parameters to pass, then you likely have to know which type you are making and so can call the correct constructor anyway.
If ECMA5 is supported:
use Object.create(Object.getPrototypeOf(this));
If ECMA5 is not supported:
create an anonymous function
set the prototype of the anonymous function to the non-standard attribute this.__proto__
Example:
var Widget = function() { };
Widget.prototype.clone = function() {
/*
Non-ECMA5:
var newClone = function() {};
newClone.prototype = this.__proto__;
return new newClone();
*/
// ECMA5
return Object.create(Object.getPrototypeOf(this));
}
var A = function() { };
A.prototype = new Widget();
A.prototype.name = "I'm an A";
var B = function() { };
B.prototype = new Widget();
B.prototype.name = "I'm a B";
var x1 = new A();
var y1 = x1.clone();
console.log("y1 should be A: %s", y1.name);
var x2 = new B();
var y2 = x2.clone();
console.log("y2 should be B: %s", y2.name);
The information you need is already available in the constructor property. However, overwriting prototype will lose it as I recently explained here.
Using my own class implementation for ECMAScript version 3 or version 5, your example would look like this:
var Widget = Class.extend({
someFunction : function() {
alert('someFunction executed');
},
clone : function() {
return new this.constructor;
}
});
var A = Widget.extend();
var B = Widget.extend({
constructor : function(arg) {
Widget.call(this); // call parent constructor
this.arg = arg;
},
// override someFunction()
someFunction : function() {
alert('someFunction executed, arg is ' + this.arg)
},
// clone() needs to be overriden as well:
// Widget's clone() doesn't know how to deal with constructor arguments
clone : function() {
return new this.constructor(this.arg);
}
});
var a = new A;
var a2 = a.clone();
a2.someFunction();
var b = new B(42);
var b2 = b.clone();
b2.someFunction();

sub object functions in javascript

I know you can create literal objects with subobjects and functions:
var obj = {
val : 1,
level1 : {
val : 2,
val2 : 3,
func : function(){
return this.val2
}
}
}
console.log(obj.val);
console.log(obj.level1.val);
console.log(obj.level1.func());
outputs:
1
2
3
What I would like to do is do the same thing with methods in a object, something similar to:
function objType() {
this.val = 1;
this.func = function(){
return this.val;
}
this.level1 = function(){
this.val = 2;
this.func = function(){
return this.val;
}
this.level2 = function(){
this.val = 3;
this.func = function(){
return this.val;
}
}
};
};
then i would expect:
var obj = new objType();
console.log(obj.func());
console.log(obj.level1.func());
console.log(obj.level1.level.func());
to output:
1
2
3
However, only the first console.log outputs before the script throws an error.
Is there any way to have sub methods in Javascript?
--edit--
My goal is to create a class i can use for showing a box in the middle of the screen, for displaying messages, questions(to get a yes/no response), and forms. I was thinking a good way to structure it would be with sub methods, so that it could then be referenced with:
function box() {
this.show = function(){
//multiple sub methods here
}
this.hide = function(){
//code to hide window here
}
}
var aBox = new box();
aBox.show.message('the message');
aBox.hide();
aBox.show.question('the question');
aBox.hide();
--edit--
thanks #Sean Vieira
For completeness I'll put the modified version of my code here using his solution:
function objType() {
this.val = 1;
this.func = function(){
return this.val;
}
this.level1 = {
val : 2,
func : function(){
return this.val;
},
level2 : {
val : 3,
func : function(){
return this.val;
}
}
}
var obj = new objType();
console.log(obj.func());
console.log(obj.level1.func());
console.log(obj.level1.level.func());
that outputs
1
2
3
you can do this easily with chaining
function Box() {
this.show = function(){
//your code goes here
return this;
},
this.message = function(message){
//code goes here
return this;
}
}
var aBox = new Box();
aBox.message('the message').show()
Your issue is that this in JavaScript refers to the containing scope -- which in the case of a function invoked with the new operator is a new Object and this applies everywhere within the scope of that function (unless you create a new scope in some way.)
So in your code we can replace this with an imaginary "new" object ... let's call it that.
function objType() {
var that = {}; // This is what `new` does behind the scenes
// (Along with a few other things we won't replicate here).
that.val = 1;
that.func = function(){
return that.val;
}
// Do additional things with `that` here
return that;
}
However, whenever you deal with a function that you are not calling as a "class" (as in a free-standing function or a "method" of an object) then this is set dynamically at runtime.
This means that:
function log_this() {
console.log(this,
"Type:", typeof this,
"IsObject:", this instanceof Object,
"IsFunction:", this instanceof Function);
}
log_this() // window (i.e. global scope)
log_this.apply({"some":"object"}) // {"some":"object"}
log_this.apply(function(){}) // Anonymous function function(){}
var test_object = { fun: log_this };
test_object.log_this() // test_object
This might work for level1:
var obj2 = new obj.level1();
console.log(obj2.func());

Categories

Resources