undefined result using prototype [javascript] - javascript

So I'm learning prototype using javascript, and tried some code :
function Employee(name) { this.name= name; }
var m = new Employee("Bob");
var working= { isWorking: true };
Employee.prototype = working;
alert(m.isWorking);
Unfortunately, I get an undefined message, instead of the true value. Is there a reason to this result?
I have made several tests. I've concluded that reassigning the prototype object causes any previously created instances of the Employee class to be unable to access any properties found inside the newly assigned prototype. Is this accurate?

Changing the prototype will not affect an already created object. It will only affect the objects created based on that object.
There is a property __proto__ which could be used to change the prototype, but its implementation is not required. ES6 does define setPrototypeOf method to change the prototype, but since it's only in ES6 the support may vary.

First off, you have created an instance of Employee before you set the prototype, so that object will not have inherited the new prototype values.
Next, any objects created after you have set the prototype will inherit the new prototype object.
Lastly, the object will have the isWorking property, rather than a working property.
So to redo your example:
function Employee(name) { this.name= name; };
var m1 = new Employee("Bob");
var working= { isWorking: true };
Employee.prototype = working;
var m2 = new Employee("Sam");
alert(m1.isWorking); // undefined
alert(m2.isWorking); // true

Simple fix is to properly assign it.
function Employee(name) {
this.name = name;
}
var m = new Employee("Bob");
var working = {
isWorking: true
};
Employee.prototype.working = working;
alert(m.working.isWorking);
A better fix for MULTIPLE employees is to make a class, then create instances of that: play around with it here: http://jsfiddle.net/MarkSchultheiss/p6jyqbgv/1/
"use strict";
function makeClassStrict() {
var isInternal, instance;
var constructor = function(args) {
if (this instanceof constructor) {
if (typeof this.init == "function") {
this.init.apply(this, isInternal ? args : arguments);
}
} else {
isInternal = true;
instance = new constructor(arguments);
isInternal = false;
return instance;
}
};
return constructor;
}
var EmployeeClass = makeClassStrict();
EmployeeClass.prototype.init = function(employeeName, isWorking) {
var defaultName = 'notbob';
this.name = employeeName ? employeeName : defaultName;
this.working = !!isWorking;
};
// call this to get the name property
EmployeeClass.prototype.getName = function() {
return this.name
};
//note no "new" needed due to the makeClassStrict that does that
var m = EmployeeClass("Bob");
alert(m.working +":"+ m.name);
m.working = true;
alert(m.working +":"+ m.name);
var notbob = EmployeeClass("Charlie",false);
alert(notbob.working +":"+ notbob.name);
alert(notbob.getName()+ m.getName());

You cannot override the entire prototype property and expect already existing instances to work. JavaScript doesn't work that way. But you can loop through the prototype object and unset anything already set, then loop through your new object, and set it to something else.
function Employee(name) { this.name= name; }
var m = new Employee("Bob");
var working= { isWorking: true };
for(var j in Employee.prototype){delete Employee.prototype[j];}//unset all properties, the same as setting to {}
for(j in working){Employee.prototype[j]=working[j];}//set the properties
alert(m.isWorking);

Related

What is the difference between members on prototype object and on constructor function?

My question is not about the difference between object's members and prototype members. I understand that. I think it is similar like C# object members and static members on the class.
My question is about difference between members on constructor function and on prototype object. Comparing to C# they both are "static". So what is the difference? I only observed, that prototype members can be called the same way on instances directly, or on Constructor.prototype. The constructor function members can be called only on constructor function.
When to use which approach?
To illustrate this, imagine I need count of Persons.
Example using constructor function members:
function Person () {
Person.countOfCreatedPersons = (Person.countOfCreatedPersons || 0) + 1;
}
Person.Count = function () {
return Person.countOfCreatedPersons;
}
var p = new Person();
alert(Person.Count());
Example using prototype members:
function Person () {
Person.prototype.countOfCreatedPersons = (Person.prototype.countOfCreatedPersons || 0) + 1;
}
Person.prototype = {
Count: function () {
return this.countOfCreatedPersons;
}
}
var p = new Person();
alert(Person.prototype.Count()); // or p.Count()
When you add a property to the prototype of an object, every object that inherits from that prototype has the property:
function Ob(){};
Ob.prototype.initialised = true;
var ob1 = new Ob();
alert(ob1.initialised); //true!
alert(Ob.initialised); //undefined;
If you add it to the constructor, is like a static property. Instances won't have acces to them.
function Ob2(){};
Ob2.initialised = true;
var ob2 = new Ob2();
alert(ob2.initialised); //undefined
alert(Ob2.initialised); //true
Besides, if you add a method to the prototype, the this variable inside the method will point to your object (the instance of the class you've created with new). This is not true for class methods:
function Obj() {
this.value = 1;
}
Obj.prototype.getValue = function() {
return this.value;
};
Obj.getValue = function() {
return this.value;
};
var ob3 = new Obj();
alert(ob3.getValue()); //'1'!
alert(Obj.getValue()); //undefined!
Hope this explains.

Static/shared property and method in JavaScript

I'm trying to have a 'class' in JS which tracks how many instances of itself have been instantiated. I am attempting to do so like this...
var myNamespace = {};
myNamespace.myClass = function () {
//fails here as .getNetInstanceNo() not recognised...
var instanceNumber = myNamespace.myClass.getNextInstanceNo();
return {
instanceNo : function() { return instanceNumber; }
}
};
myNamespace.myClass.InstanceNo = 0; //static property?
//should the class itself have this method added to it...
myNamespace.myClass.prototype.getNextInstanceNo = function () { //static method?
return myNamespace.myClass.InstanceNo++;
};
var class1 = new myNamespace.myClass();
alert('class 1 has instance of ' + class1.instanceNo() );
However this fails as the getNextInstanceNo function is not recognised. Even though I think I'm adding it through the myClass.prototype.
What am I doing wrong?
prototype is an object from which other objects inherit properties, as in when you create an instance of an object and that object doesn't have a property/method, when called, the prototype of the class in which the object belongs to is searched for that property/method, here's a simple example:
function Animal(){};
Animal.prototype.Breathe = true;
var kitty= new Animal();
kitty.Breathe; // true (the prototype of kitty breathes)
var deadCat = new Animal();
deadCat.Breathe = false;
deadCat.Breathe; // false (the deadCat itself doesn't breath, even though the prototype does have breath
As you said yourself, you don't need to define getNextInstanceNo on prototype, since that's not how static methods are defined on JavaScript, leave it right right there on the class itself, instead you can define the instanceNo method on prototype, here's how:
var myNamespace = {};
myNamespace.myClass = function () {
this.instanceNumber = myNamespace.myClass.getNextInstanceNo();
};
myNamespace.myClass.prototype.instanceNo = function () {
return this.instanceNumber;
};
myNamespace.myClass.InstanceNo = 0;
myNamespace.myClass.getNextInstanceNo = function () {
return myNamespace.myClass.InstanceNo++;
};
var class1 = new myNamespace.myClass();
alert('class 1 has instance of ' + class1.instanceNo());

javascript class inherit from Function class

I like that in javascript, I can create a function, and then add further methods and attributes to that function
myInstance = function() {return 5}
myInstance.attr = 10
I would like to create a class to generate these objects. I assume I have to inherit from the Function base class.
In other words, I would like to:
var myInstance = new myFunctionClass()
var x = myInstance()
// x == 5
But I don't know how to create the myFunctionClass. I have tried the following, but it does not work:
var myFunctionClass = function() {Function.call(this, "return 5")}
myFunctionClass.prototype = new Function()
myInstance = new myFunctionClass()
myInstance()
// I would hope this would return 5, but instead I get
// TypeError: Property 'myInstance' of object #<Object> is not a function
I also tried the more complicated (and more proper?) inheritance method found here: How to "properly" create a custom object in JavaScript?, with no more luck. I have also tried using the util.inherits(myFunctionClass, Function) found in node.js. Still no luck
I have exhausted Google, and therefore feel that I must be missing something fundamental or obvious. Help would be greatly appreciated.
Your trying to inherit from Function. This is a right pain to do. I suggest you do the following instead
Live Example
var Proto = Object.create(Function.prototype);
Object.extend(Proto, {
constructor: function (d) {
console.log("construct, argument : ", d);
this.d = d;
// this is your constructor logic
},
call: function () {
console.log("call", this.d);
// this get's called when you invoke the "function" that is the instance
return "from call";
},
method: function () {
console.log("method");
// some method
return "return from method";
},
// some attr
attr: 42
});
You want to create a prototype object that forms the basis of your "class". It has your generic methods/attributes. It also has a constructor that gets invoked on object construction and a call method that gets invoked when you call the function
var functionFactory = function (proto) {
return function () {
var f = function () {
return f.call.apply(f, arguments);
};
Object.keys(proto).forEach(function (key) {
f[key] = proto[key];
});
f.constructor.apply(f, arguments);
return f;
}
}
A function factory takes a prototype object and returns a factory for it. The returned function when called will give you a new function object that "inherits" from your prototype object.
var protoFactory = functionFactory(proto);
var instance = protoFactory();
Here you create your factory and then create your instance.
However this isn't proper prototypical OO. we are just shallow copying properties of a prototype into a new object. So changes to the prototype will not reflect back to the original object.
If you want real prototypical OO then you need to use a hack.
var f = function () {
// your logic here
};
f.__proto__ = Proto;
Notice how we use the non-standard deprecated .__proto__ and we are mutating the value of [[Prototype]] at run-time which is considered evil.
JS does not allow a constructor to return a function, even though functions are objects. So you cant have an instantiation of a prototype that is itself executable. (Am I right in this? please correct if I'm not, it's an interesting question).
Though you could do a factory function:
var makeCoolFunc = function() {
var f = function() { return 5 };
f.a = 123;
f.b = 'hell yes!'
return f;
};
var func = makeCoolFunc();
var x = func();
You can extend Function and pass the wanted function body as String to the super constructor. The context of the function can be accessed with arguments.callee.
Example for an observable Attribute class:
export default class Attribute extends Function {
constructor(defaultValue){
super("value", "return arguments.callee.apply(arguments);");
this.value = defaultValue;
this.defaultValue = defaultValue;
this.changeListeners = [];
}
apply([value]){
if(value!==undefined){
if(value!==this.value){
var oldValue = this.value;
this.value=value;
this.changeListeners.every((changeListener)=>changeListener(oldValue, value));
}
}
return this.value;
}
clear(){
this.value=undefined;
}
reset(){
this.value=this.defaultValue;
}
addChangeListener(listener){
this.changeListeners.push(listener);
}
removeChangeListener(listener){
this.changeListeners.remove(listener);
}
clearChangeListeners(){
this.changeListeners = [];
}
}
Example usage:
import Attribute from './attribute.js';
var name= new Attribute();
name('foo'); //set value of name to 'foo'
name.addChangeListener((oldValue, newValue)=>{
alert('value changed from ' +oldValue+ ' to ' +newValue);
});
alert(name()); //show value of name: 'foo'
name('baa'); //set value of name to new value 'baa' and trigger change listener

Getting the type of an object in Javascript when its prototype is assigned an instance of another object

I must have some sort of fundamental misunderstanding of how objects work in Javascript because I am unable to figure out why the following outputs what it does. You can see the jsfiddle of the following code here: http://jsfiddle.net/VivekVish/8Qvkn/1/
Note that is uses the getName function defined here: How do I get the name of an object's type in JavaScript?
Object.prototype.getName = function()
{
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec((this).constructor.toString());
return (results && results.length > 1) ? results[1] : "";
};
function ContentProvider()
{
}
function LessonProvider()
{
console.log(this.getName());
}
lessonProvider1 = new LessonProvider();
LessonProvider.prototype = new ContentProvider();
lessonProvider2 = new LessonProvider();
The above code outputs the following to the console:
LessonProvider
ContentProvider
But why isn't it LessonProvider in both cases and how can one make it LessonProvider in both cases?
If you don't reset the pointer to the constructor, the all the children will report that the parent object is their constructor.
LessonProvider.prototype.constructor = LessonProvider;
You may want to try using a function like below for inheritance:
function inherit(C, P) {
//empty function used as a proxy
var F = function() {};
//set F's prototype equal to P's prototype
F.prototype = P.prototype;
//C will only inherit properties from the F's prototype
C.prototype = new F();
//set access to the parents (P's) prototype if needed
C.uber = P.prototype;
//Set the constructor back to C
C.prototype.constructor = C;
}
inherit(LessonProvider, ContentProvider);
if you insist-
LessonProvider.prototype = new ContentProvider()
LessonProvider.prototype.constructor=LessonProvider;

Copying Javascript getters/setters to another prototype object

// Base class
var Base = function() {
this._value = 'base';
};
Base.prototype = {
constructor: Base,
// By function
getValue: function() {
return this._value;
},
// By getter
get value() {
return this._value;
}
};
// Sub class extends Base
var Sub = function() {
this._value = 'sub';
};
Sub.prototype = {
constructor: Sub
};
// Pass over methods
Sub.prototype.getValue = Base.prototype.getValue;
Sub.prototype.value = Base.prototype.value;
// ---
var mySub = new Sub();
alert(mySub.getValue()); // Returns 'sub'
alert(mySub.value); // Returns 'undefined'
At first glance it seems that mySub.value should return the same as mySub.getValue(), but as you can see it instead returns undefined. Obviously the getter is not finding the parent scope as the Sub instance (mySub), but rather a non-existent Base instance.
Is there any way around this other than having to assign the same getters onto the new prototype?
A more modern solution is to use the Object.defineProperty since it allows getters and setters to be handled without breaking them.
Only problem is that it takes a descriptor object, so instead of manually making one, use the Object.getOwnPropertyDescriptor function to just get it for you.
var BazValue = Object.getOwnPropertyDescriptor(Base.prototype,'value');
Object.defineProperty(Sub.prototype, 'value', BazValue);
Sub.prototype.__defineGetter__('value', Base.prototype.__lookupGetter__('value'));
Try that.
I think it would work if you assigned
Sub.prototype = new Base()
The issue is that the constructor is never run when you assign it directly from the Base.prototype.value. That value won't exist until you have an instance of the Base class (via new)
This is my typical method for extending Function to achieve inheritance:
Function.prototype.Extend = function(superClass) {
this.prototype = new superClass();
this.prototype.getSuperClass = function() {
return superClass;
};
this.getSuperClass = this.prototype.getSuperClass;
return this;
};
This will properly assign all of the parent classes methods and properties to the child 'class'.
Usage looks like
var Sub = function() {}
Sub.Extend(Base)
In addition to Alex Mcp's answer you could add new getters/setters to Sub after extending it using:
Function.prototype.addGetter = function(val,fn){
this.prototype.__defineGetter__(val,fn);
return this;
}
Function.prototype.addSetter = function(val,fn){
this.prototype.__defineSetter__(val,fn);
return this;
}
//example;
Sub.Extend(Base);
Sub.addGetter('date',function(){return +new Date;});
And to add to tylermwashburns answer: you could extend the Function prototype for that:
Function.prototype.copyGetterFrom = function(val,fromConstructor){
this.prototype.__defineGetter__(
val
,fromConstructor.prototype.__lookupGetter__(val));
return this;
}
//usage example.:
Sub.copyGetterFrom('value',Base);

Categories

Resources