Classes in JavaScript - javascript

I am defining a class in JavaScript
function Pen(parent){
this.color = "#0000ff";
this.stroke = 3;
this.oldPt;
this.oldMidPt;
this.isActive = false;
this.parent = parent; //app that owns this pen
this.points = [];
this.curShape;
console.log(this);
return(this);
}
In the console.log statement I am getting way more than just this class, I am getting all kinds of information about basically everything else going on. Why is that?

the keyword this is dependent on the caller, so if you are initializing the function without the "new" keyword "this" might very well be referencing the window and not the object.
Try:
function Pen(parent){
var context = this;
this.color = "#0000ff";
this.stroke = 3;
this.oldPt;
this.oldMidPt;
this.isActive = false;
this.parent = parent; //app that owns this pen
this.points = [];
this.curShape;
console.log(context);
return(this);
}
var pen = new Pen();

Because your "class" inherits (transparently, in your case) from other javascript base classes. If you want to introspect only the properties you've created on your object, use hasOwnProperty(keyName) to filter those out.

Javascript is prototype based and not class based. Every new custom object as default
has pre built functionlity provided by the base object called Object.
So everytime you ask if a property or method belongs to a given object, in the worst
case it will fall until the Object object, and if that property/method is not there
then it will throw an error. Therefore when you are using the log function it is
printing all the object structure including properties and method of its "base" class.

Related

Does it matter if my Object returns the wrong constructor, JavaScript?

Alright, just looking at the question, it seems like it would matter, but lets look at a test I did.
So I created 3 constructor functions. I did the usual Car, then a Mazda, then a MX8 constructor. All of them inherit based on the code in the JSFiddle. Here is a shell of what I did, more detail can be found in the JSFiddle.
By the way I'm a big fan of Object.create which doesn't need any babysitting of anything.
var Car = function () {
//code here
}
var Mazda = function (type) {
this.type = type;
//more code here including a simple method test
}
var MX8 = function () {
//more code here
}
Mazda.prototype = new Car();
MX8.prototype = new Mazda("MX8");
var z = new MX8();
//refer to my JSFiddle
z.interior; // got correct interior
z.type; // got correct type ie model
z.warrantyInfo(); // method was correctly inherited
z.speed; // got correct speed
z.constructor === MX8; // false (unless I specify the constructor in the code of which is commented out in my JSFiddle)
short answer:
You need to explicitly set the constructor.
function Base() {}
function Derived() {}
// old prototype object is gone, including constructor property
// it will get however all the properties attached by Base constructor
Derived.prototype = new Base();
Derived.prototype.constructor = Derived;
Does it matter if my Object returns the wrong constructor?
Well, it depends on whether you're using that property or not. I'd say it's a good practice to keep the correct constructor.
Possible use case:
function getType (target) {
// name is empty unless you use the function declaration syntax
// (read-only property)
return target.constructor.name;
}
getType(new Derived()) // "Derived"
getType(new Base()) // "Base"
side note:
There are better ways of implementing inheritance in JS.
My favorite pattern is the following:
function Base (x) { this.x = x; }
function Derived (x, y) { Base.call(this, x); this.y = y; }
// creates an empty object whose internal "[[Prototype]]" property
// points to Base.prototype
Derived.prototype = Object.create(Base.prototype);
Derived.prototype.constructor = Derived;
The ideea behind Object.create is based on:
function create (proto) {
function f () {}
f.prototype = proto;
return new f();
}
The actual function Object.create is better because you can pass null as prototype, which doesn't work using the above code.
Anyway, you should watch this excellent playlist: Crockford on JavaScript.

JavaScript: Adding a Namespace to Prototype Methods

I have a commercial application that has an existing JavaScript object structure using prototype chains. I have had success extending this API by adding more methods to the prototypes of objects. However, I realize that it would be best to add a namespace in front of my methods in case the application vendor decides to name a new method the same as one of my methods in a future release.
If I have an existing object called State, I would add a method called getPop like so:
State.prototype.getPop = function(){return this.pop;};
var Washington = new State('Washington',7000000);
Washington.getPop(); //returns 7000000
What I want to do is add a namespace called 'cjl' before my custom method to avoid name collision so that I can call it like so:
Washington.cjl.getPop();
I tried:
State.prototype.cjl = {};
State.prototype.cjl.getPop = function(){return this.pop;};
The problem is this. It doesn't point to the instance but instead points to the 'cjl' object.
I tried various methods, including using .bind() but none of them seemed to work. I finally found an answer here: Is it possible to organise methods on an object's prototype into namespaces? This works using the Object.defineProperty() method. The problem is the commercial application only works in compatibility mode in IE which doesn't support the Object.defineProperty() method for non-DOM elements.
Is there another way to accomplish this? I don't want to have to call multiple functions, which is the result of some techniques, e.g.:
Washington.cjl().getPop();
You could namespace in the following way, reading your comments I see that you can't change the original constructor so you'll have to replace the original with your own and save the original in a closure.
Every state instance will have it's own cjl instance but that only has a reference to current State instance, all the cjl functions are shared as they exist only once:
[UPDATE]
Forgot to get State.prototype in myState's prototype chain.
//the original constructor
function State(name, pop){
this.name=name;this.pop=pop;
}
State.org="original constructor";
//original constructor is available through
// closure and window.State is replaced with
// your constructor having the cjl namespace
(function(State){
//cjl namespace
function cjl(stateInstance){
this.stateInstance=stateInstance;
};
//cjl functions
cjl.prototype.getPopInThousands=function(){
//do not use this, instead use this.stateInstance
return this.stateInstance.pop/1000;
}
function myState(){
//apply State constructor
State.apply(this,arguments);
//create a clj instance, all methods
// are on cjl.prototype so they're shared
this.cjl = new cjl(this);
}
//inherit from State (use polyfil for older browsers)
myState.prototype = Object.create(State.prototype);
//replace window.State with your constructor
window.State=myState;
}(State))
var s = new State("Wasington", 7000000);
console.log(s.cjl.getPopInThousands());
//non standard, name
console.log("constructor name",s.constructor.name);
console.log("constructor tostring",s.constructor.toString());
More on constructor functions and prototype can be found here: https://stackoverflow.com/a/16063711/1641941
I have to agree with friend and cookie that pre fixing the function names may be the better solution but if you want to use the same methods for an object named Country then you may think of using the previous code as you can re use the cjl object.
Instead of defining State.prototype.cjl outside of the function, try to set the cjl "namespace" inside the constructor function.
function State(){
var thisObject = this;
this.cjl = {
getPop: function(){
return thisObject.pop;
}
};
}
Then you can do Washington.cjl.getPop();.
Try:
var State = function(name, pop) {
this.name = name;
this.pop = pop;
};
State.prototype.cjl = function(method) {
return this.cjlDefs[method].apply(this, Array.prototype.slice.call(arguments, 1) );
};
State.prototype.cjlDefs = {
getPop: function() {return this.pop;}
};
var Washington = new State('Washington', 80000);
console.log( Washington.cjl('getPop') );
https://jsfiddle.net/ghbjhxyh/
Or another shape if you prefer:
var State = function(name, pop) {
this.name = name;
this.pop = pop;
};
State.prototype.cjl = function(method) {
this.cjlDefs.obj = this;
return this.cjlDefs;
};
State.prototype.cjlDefs = {
assertObj: function() { /* Make sensible assertion */ },
getPop: function() { this.assertObj(); return this.obj.pop; }
};
var Washington = new State('Washington', 75000);
console.log( Washington.cjl().getPop() ); // 75000
https://jsfiddle.net/7vjrz2mn/

Pseudo-classical inheritance with privacy?

In JavaScript: The Good Parts, Crockford argues that one of the downsides of using the pseudo-classical pattern of inheritance is that it publicly exposes instance variables.
For example:
var Ball = function(width, color) {
this.width = width;
this.color = color;
}
var redBall = new Ball(5, "red");
redBall.width = 12; // Changes width to 12
Now, what if I want the width of the ball to be private?
Here's what I've tried:
var Ball = function(width, color) {
this.getWidth = function() { return width; }
this.color = color;
}
var redBall = new Ball(5, "red");
Problem with that is we can still change this.getWidth and there may be prototype methods that rely on it.
What about ...
var Ball = function(width, color) {
return {
getWidth: function() { return width; },
color: color
}
}
var redBall = new Ball(5, "red");
Problem with that is that the prototype methods no longer have access to the instance variables. It's also closer to the functional pattern of inheritance, but with more indirection using the new operator.
So how do I achieve privacy using the pseudo-classical inheritance pattern? Is this even possible?
To answer your question; the only way to have intace specific private members is to have both the members and privileged functions (functions that can access them) in the same scope. This means they all have to be in the constructor body (var my private...this.myPrivileged=function(){ console.log (myPrivate...) or in a IIFE with a closure object keeping track of instances and their privates.
When returning an object private you already loose privacy because the calling code can mutate your private value. To prevent this you have to deep copy the value and return that.
To have privates on the prototype the privates will be shared. This because the instance is not known when declaring your prototype and private members.
This is because JavaScript doesn't have a private modifier and only simulates them through closures.
One pattern that can use prototype for instance specific protected variables is using Crockford's box example.
All protecteds are put in a box that can only be opened with a key, the key is available through closures to all prototype members defined in the IIFE.
Because the instance isn't known when creating prototype you have to invoke initProtecteds from the instance in order to create instance specific protected members.
Minimal code with an example protected instance member called medicalHistory is used in Animal.
function makeBox(key){
var ret = {};
return {
get : function(pKey){
if(pKey===key){
return ret;
}
return false;
}
}
};
var Person = function(args){
args = args || {};
this.name = args.name || "Nameless Person";
this.initProtecteds();
};
//using IIFE to define some members on Person.prototype
// these members and only these members have access to
// the passed object key (through closures)
// later the key is used to create a box for each instance
// all boxes use the same key so instances of same type
// can access each other's protected members and instances
// inheriting from Person can do so too, extending parent methods
// will be trickier, no example for that is given in this code
(function(key){
//private shared member
var privateBehavior = function(instance,args){
//when you invoke this from public members you can pass
// the instance or use call/apply, when using call/apply
// you can refer to this as the current instance, when
// passing it as an argument then instance will
// be the current instance
console.log("private shared invoked");
};
//set default _protecteds to false so init knows
// it has not been initialised and needs to be shadowed
// with a box
Person.prototype._protecteds=false;
Person.prototype.getMedicalHistory = function(){
//Maybe run some code that will check if you can access
// medical history, invoking a private method
privateBehavior(this,{});
var protectedObject = this._protecteds.get(key);
//if medicalHistory is an object the calling code
// can now mutate it
return protectedObject.medicalHistory;
};
Person.prototype.hasSameDesease = function(person){
//this Person instance should be able to see
// medical history of another Person instance
return person._protecteds.get(key);
};
Person.prototype.getArr = function(){
//Returns protecteds.get(key).arr so we can
// mutate it and see if protecteds are instance
// specific
return this._protecteds.get(key).arr;
};
Person.prototype.initProtecteds = function(){
//only create box if it hasn't been created yet
if(this._protecteds!==false)
return;
//use the same key for all instance boxes, one instance
// can now open another instance's box
this._protecteds=makeBox(key);
//retreive the object held by the box
var protectedObject = this._protecteds.get(key);
//add protected members by mutating the object held
// by the box
protectedObject.medicalHistory = "something";
protectedObject.arr = [];
//protectedObject is no longer needed
protectedObject=null;
};
}({}));
var Animal = function(){
this.initProtecteds();
};
(function(key){
Animal.prototype._protecteds=false;
Animal.prototype.initProtecteds = function(){
if(this._protecteds!==false)
return;
this._protecteds=makeBox(key);
var protectedObject = this._protecteds.get(key);
protectedObject.medicalHistory = "something";
};
}({}));
var Employee = function(args){
//re use Person constructor
Person.call(this,args);
};
//set up prototype part of inheritance
Employee.prototype = Object.create(Person.prototype);
//repair prototype.constructor to point to the right function
Employee.prototype.constructor = Employee;
var ben = new Person({name:"Ben"});
var nameless = new Person();
console.log(ben.getMedicalHistory());//=something
//key is in closure and all privileged methods are in that closure
// since {} !== {} you can't open the box unless you're in the closure
// or modify the code/set a breakpoint and set window.key=key in the closure
console.log(ben._protecteds.get({}));//=false
//One Person instance can access another instance's protecteds
// Objects that inherit from Person are same
console.log(ben.hasSameDesease(nameless));//=Object { medicalHistory="something"}
var lady = new Animal();
//An Animal type object cannot access a Person protected members
console.log(ben.hasSameDesease(lady));//=false
var jon = new Employee({name:"Jon"});
console.log(ben.hasSameDesease(jon));//=Object { medicalHistory="something"}
//making sure that protecteds are instance specific
ben.getArr().push("pushed in ben");
console.log(jon.getArr());
console.log(nameless.getArr());
console.log(ben.getArr());
This is interesting to consider.
To me (and I consider myself a student of js), it looks like only private member functions have access to the object's private variables. This is because it creates a closure around the var:
var Ball = function(width, color) {
var width = width;
this.color = color;
this.getWidth=function(){return width}
this.specialWidthCalc=function(x){ width = width + x;}
}
So programmers can do:
var redBall = new Ball(5, "red");
consoloe.log( redBall.getWidth() );
redBall.specialWidthCalc(3);
consoloe.log( redBall.getWidth() );
I am unable to create a prototype which has access to width.

How to call parent class' method from a subclass in JavaScript so that parent's local variables would be accessible?

I'm using one of the approaches to class inheritance in JavaScript (as used in the code I'm modifying), but do not understand how to attach additional functionality for a method in a subclass to the functionality the respective parent class method already has; in other words, I want to override a parent's method in the child class with a method that besides its own sub-class-specific stuff does also the same the parent's method is doing. So, I'm trying to call the parent's method from the child's method, but is it even possible?
The code is here: http://jsfiddle.net/7zMnW/. Please, open the development console to see the output.
Code also here:
function MakeAsSubclass (parent, child)
{
child.prototype = new parent; // No constructor arguments possible at this point.
child.prototype.baseClass = parent.prototype.constructor;
child.prototype.constructor = child;
child.prototype.parent = child.prototype; // For the 2nd way of calling MethodB.
}
function Parent (inVar)
{
var parentVar = inVar;
this.MethodA = function () {console.log("Parent's MethodA sees parent's local variable:", parentVar);};
this.MethodB = function () {console.log("Parent's MethodB doesn't see parent's local variable:", parentVar);};
}
function Child (inVar)
{
Child.prototype.baseClass.apply(this, arguments);
this.MethodB = function ()
{
console.log("Child's method start");
Child.prototype.MethodB.apply(this, arguments); // 1st way
this.parent.MethodB.apply(this, arguments); // 2 2nd way
console.log("Child's method end");
};
}
MakeAsSubclass(Parent, Child);
var child = new Child(7);
child.MethodA();
child.MethodB();
No you can't see the parents local variables. You inherit the parents prototype chain, not their local state. In your case you're applying the parent function onto the child object which does not hold the state.
apply(this,...)
means that you're binding the function to the current value of this. when you call method b from the child object, its then bound to the child, and therefore is not operating within the closure that contains the parents value.
I would advice agains using private instance value properties like this because it messes up the prototype. Functions that need to access the private instance variable (each instance has it's own private value) can't be put on the prototype so you can't realy use it.
Here is how your code could work (but I would not do it myself):
var Parent = function(){
var private=22;
this.showPrivate=function(){
console.log(private);
}
}
var Child=function(){Parent.call(this)};
// the following is only usefull if you have functions
// on the parent prototype that don't use privates
Child.prototype=Object.create(Parent.prototype);
// Child.prototype.constructor would now point to Parent
// it's not needed most of the time but you can fix that
Child.prototype.constructor=Child;
var c = new Child();
c.showPrivate();
Here is how you could use "private" functions:
var Parent = function(name){
//public instance variable
this.name=name;
}
Parent.prototype=function(){
// privates on the prototype (shared among instances)
var privateFunction=function(me){
console.log("private function called in:"+me.name);
console.log("shared in "+me.name
+" is now:"+shared+" setting it to 'changed'");
shared="Changed";
}
// private shared value
var shared="Parent"
return{
constructor:Parent,
publicFn:function(){
privateFunction(this);
}
};
}();
var Child=function(name){Parent.call(this,name)};
Child.prototype=Object.create(Parent.prototype);
Child.prototype.constructor=Child;
var c = new Child("child1");
var c2 = new Child("child2");
c.publicFn();
c2.publicFn();//shared is already changed by 'child1'
More info on constructor functions here
The variable var parentVar = inVar; is a local and private variable available only in the Parent() function and visible only to functions defined in the same scope (Parent()).
I think that best way here would be to modify the Parent class in such way that the parentVar wouldn't be private, but public:
function Parent(inVar) {
this.parentVar = inVar;
}

javascript prototype

I AM trying to understand js prototype property: my sample code
function Container(param) {
this.member = param;
}
var newc = new Container('abc');
Container.prototype.stamp = function (string) {
return this.member + string;
}
document.write(newc.stamp('def'));
function Box() {
this.color = "red";
this.member = "why";
}
Container.prototype = new Box();
Box.prototype.test = "whatever";
var b = new Box();
document.write(newc.test);
here the last line is undefined - even though Container's prototype is a Box and Box's prototype has a property test, why is the newc which refers to test in Box doesnt work? can any one please explain how the 'Prototype' works in my above context.
Thanks...
You are setting Container prototype to Box() after the newc instance was already created.
Reorder the statements as follows:
function Container(param) {
this.member = param;
}
function Box() {
this.color = "red";
this.member = "why";
}
Container.prototype = new Box();
Box.prototype.test = "whatever";
Container.prototype.stamp = function (string) {
return this.member + string;
}
//Here the containers prototype setup is complete.
var newc = new Container('abc');
document.write(newc.stamp('def'));
document.write(newc.test);
If sounds like you want to know WHY it is behaving the way it is, and not just "fix" the code. So here's what's going on.
As you saw, if you change the prototype of "Container", you will actually change the properties for new objects AND objects already instantiated. So:
function Container(param) {
this.member = param;
}
var newc = new Container('abc');
// setting a new property of the prototype, after newc instantiated.
Container.prototype.stamp = function (string) {
return this.member + string;
}
// This already-instantiated object can access the stamp function
document.write(newc.stamp('123')); // output: abc123
So there's no problem with the above, as long as you don't call the new method before it's defined. Now the next point. Add this to the above:
// Our Box object
function Box() {
this.color = "red";
this.member = "why";
}
Container.prototype = new Box();
var newd = new Container('fgh');
document.write(newd.stamp('456')); // output: ERROR
Error! But that makes sense, right? You totally wiped out the "Container" prototype and replaced it with the one from "Box", which has no "stamp" function.
I am going to assume you want "Box" to inherit from "Container". That would be logical from the naming convention. If you want to do that, replace the previous section with this:
// Our Box object
function Box() {
this.color = "red";
this.member = "why";
}
// This inherits from Container. Note that we can
// do this before or after we declare "Box"
Box.prototype = new Container();
Box.prototype.test = "Whatever";
var b = new Box("jkl"); // note: "jkl" is ignored because "Box" sets "member" to "why"
document.write(b.test); // output: Whatever
document.write("<br>");
document.write(b.stamp("345")); // output: why345
So now we have a "Box" that can call its own methods and parameters, and also call them from its parent "Container".
So the big picture is that an object will look at its own prototype for a method or something, and if it doesn't find it there it will look in the prototype of the thing it inherited from, and so on. The other big point is that setting something in the prototype makes it immediately available in all future AND current instances of that object.
An object does not contain a reference to its constructor which it uses to get at the prototype. If it did, then the code would work as you expected.
Instead, an object contains a reference to its prototype that is set when it is created.
From the language spec section 4.2.1:
Every object created by a constructor has an implicit reference (called the object’s prototype) to the value of its constructor’s “prototype” property. Furthermore, a prototype may have a non-null implicit reference to its prototype, and so on; this is called the prototype chain. When a reference is made to a property in an object, that reference is to the property of that name in the first object in the prototype chain that contains a property of that name. In other words, first the object mentioned directly is examined for such a property; if that object contains the named property, that is the property to which the reference refers; if that object does not contain the named property, the prototype for that object is examined next; and so on.

Categories