Making a function constructor function in Javascript - javascript

How, if possible, do I create a function constructor function?..a constructor that also has prototype methods.
I know how to create an object constructor function i.e.
Function Thing(val) { this.prop1 = val }
Thing.prototype.action = function()...
But to make create a new function with prototype prop and methods, the best I can come up with is, for example:
Function Func(val) {
var func = function(x) {return val*x};
func.val = val;
func.__proto__ = proto;
return func;
}
const proto = {
product: function(x) { return this.val*x },
};
For the sake of code hygiene, is there a more elegant solution?

try...
function Person(name) {
this.name = name;
}
// create a new instance
var person = new Person('codechimp');
console.log('person.constructor is ' + person.constructor);

Related

Trying to emulate 'new' operator

How can I emulate 'new' operator with function myNew? Tried everything but I can't get it work.
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name;
}
function myNew(){
var obj = Object.create(Object.prototype);
var instance = this.apply(obj, arguments);
return instance;
}
var person = myNew(Person, 'Test');
console.log(person instanceof Person); // true
person.getName(); // Test
If you want an emulation without Reflect.construct, try this:
function myNew(constructor) {
var instance = Object.create(constructor.prototype)
var args = Array.from(arguments)
args.shift()
constructor.apply(instance, args)
return instance
}
If you support ES6, you can write it shorter as:
function myNew(constructor, ...args) {
var instance = Object.create(constructor.prototype)
constructor.apply(instance, args)
return instance
}
Edit: Just noticed Array.from is available in ES6 but if you want to support ES5, you can easily simulate it
Edit 2:
Looking to the MDN page of the new operator, I noticed that I forgot an important step in object creation from a constructor. The algorithm I used is almost identical to the one explained on the page except for the crucial part that, there are constructors that actually return something (not all constructors return undefined). In this case, the returned object is the evaluation of the new expression. So the final form (I hope) of the function will be
function myNew(constructor, ...args) {
var instance = Object.create(constructor.prototype)
var obj = constructor.apply(instance, args)
if(obj instanceof Object) return obj
return instance
}
You can use Reflect.construct.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/construct
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name;
}
var person = Reflect.construct(Person, ['Test']);
console.log(person instanceof Person); // true
console.log(person.getName()); // Test

Interesting JavaScript inheritance pattern

I have recently watched a video where Douglas Crockford was explaining inheritance patterns of Javascript. The video itself is pretty old - it was filmed 6 years ago - but still useful. In that video he showed one inheritance pattern he kinda invented (although I am not sure who the author is). This is the code using his approach:
// imitation of new operator
function objectConstructor(obj, initializer, methods) {
// create prototype
var func, prototype = Object.create(obj && obj.prototype);
// add methods to the prototype
if(methods) Object.keys(methods).forEach(function(key) {
prototype[key] = methods[key];
});
// function that will create objects with prototype defined above
func = function() {
var that = Object.create(prototype);
if(typeof initializer === 'function') initializer.apply(that, arguments);
return that;
}
func.prototype = prototype;
prototype.constructor = func;
return func;
}
var person = objectConstructor(Object, function(name) {
this.name = name;
}, {
showName: function() {
console.log(this.name);
}
});
var employee = objectConstructor(person, function(name, profession) {
this.name = name;
this.profession = profession;
}, {
showProfession: function() {
console.log(this.profession);
}
});
var employeeInfo = employee('Mike', 'Driver');
employeeInfo.showName(); // Mike
employeeInfo.showProfession(); // Driver
Unfortanately, he didn't show the invocation. So, this part
var employeeInfo = employee('Mike', 'Driver');
employeeInfo.showName();
employeeInfo.showProfession();
is mine. It generally works, but it turns out that I repeat this.name = name; for both "classes" - person and employee. I played around but I didn't manage to make it work properly without that repetition. Seems I cannot get name because such a property isn't contained in the prototypal chain for employee. I didn't succeed either in mixing in stuff like person.call(this, arguments). So, apart from whether it is cool/nice/smart/sensible etc. or not in 2017, how could I remove this.name = name; from employee and get the same result? Or everything is ok and this approach doesn't suppose it?
Here is your snippet with 2 small modifications so that you can do a super(name) type of call.
I've placed comments were I've made the modifications.. with prefix keith:
// imitation of new operator
function objectConstructor(obj, initializer, methods) {
// create prototype
var func, prototype = Object.create(obj && obj.prototype);
// add methods to the prototype
if(methods) Object.keys(methods).forEach(function(key) {
prototype[key] = methods[key];
});
// function that will create objects with prototype defined above
func = function() {
var that = Object.create(prototype);
if(typeof initializer === 'function') initializer.apply(that, arguments);
return that;
}
func.prototype = prototype;
//keith: store the initialization in constructor,
//keith: as func is already creating the object..
prototype.constructor = initializer;
return func;
}
var person = objectConstructor(Object, function(name) {
this.name = name;
}, {
showName: function() {
console.log(this.name);
}
});
var employee = objectConstructor(person, function(name, profession) {
//keith: call our super person(name)
person.prototype.constructor.call(this, name);
this.profession = profession;
}, {
showProfession: function() {
console.log(this.profession);
}
});
var employeeInfo = employee('Mike', 'Driver');
employeeInfo.showName(); // Mike
employeeInfo.showProfession(); // Driver
Since the func constructor completely disregards this, passing any context to it via call or apply will not work. Creating a way to copy over the super class' properties after creating an object is one of the ways you could accomplish your task.
// imitation of new operator
function objectConstructor(obj, initializer, methods) {
// create prototype
var func, prototype = Object.create(obj && obj.prototype);
// add methods to the prototype
if(methods) Object.keys(methods).forEach(function(key) {
prototype[key] = methods[key];
});
// function that will create objects with prototype defined above
func = function() {
var that = Object.create(prototype);
if(typeof initializer === 'function') initializer.apply(that, arguments);
return that;
}
func.prototype = prototype;
prototype.constructor = func;
return func;
}
function copyProperties(source, target) {
for (var prop in source) {
if (source.hasOwnProperty(prop)) {
target[prop] = source[prop];
}
}
}
var person = objectConstructor(Object, function(name) {
this.name = name;
}, {
showName: function() {
console.log(this.name);
}
});
var employee = objectConstructor(person, function(name, profession) {
copyProperties(person.apply(null, arguments), this);
this.profession = profession;
}, {
showProfession: function() {
console.log(this.profession);
}
});
var employeeInfo = employee('Mike', 'Driver');
employeeInfo.showName(); // Mike
employeeInfo.showProfession(); // Driver

call parent ctor from ctor of inheriting class

Is it valid to instead of doing this
function Animal(name, numLegs) {
this.name = name;
this.numLegs = numLegs;
}
Animal.prototype.sayName = function() {
console.log("Hi my name is " + this.name);
};
function Penguin(name) {
this.name = name;
this.numLegs = 2;
}
Penguin.prototype = new Animal();
var penguin = new Penguin("Tux");
penguin.sayName();
do that?
function Animal(name, numLegs) {
this.name = name;
this.numLegs = numLegs;
}
Animal.prototype.sayName = function() {
console.log("Hi my name is " + this.name);
};
function Penguin(name) {
return new Animal(name, 2);
}
Penguin.prototype = new Animal();
var penguin = new Penguin("Tux");
penguin.sayName();
I find the second version more elegant and hoped both version were equivalent in their results, but for the second one codeacademy tells me
Oops, try again. Make sure to create a new Penguin instance called penguin!
while the first one is accepted.
This is not the correct way to call the parent constructor:
function Penguin(name) {
return new Animal(name, 2);
}
The correct way is as follows:
function Penguin(name) {
Animal.call(this, name, 2);
}
The reason is because of the way new works:
Let's say you have a function called ABC.
When you execute new ABC JavaScript creates an instance of ABC.prototype and binds it to this inside of the function ABC which is why you can add properties to this inside ABC.
The constructor function returns this by default unless you return another object explicitly.
The reason Codecademy complains about your code is because you're returning a new Animal(name, 2) which is not an instanceof Penguin.
As I said before the correct way to call the parent constructor is to use ParentConstructor.call(this, arg1, arg2, ...). In this case we are setting the this inside the parent constructor to the same value as this inside the current constructor (which is the instance created by new).
If you want to write elegant code then try this on for size:
function defclass(prototype) {
var constructor = prototype.constructor;
var instance = prototype.instance = function () {};
constructor.prototype = instance.prototype = prototype;
return constructor;
}
function extend(parent, keys) {
var supertype = keys.super = parent.prototype;
var prototype = new supertype.instance;
for (var key in keys) prototype[key] = keys[key];
return defclass(prototype);
}
Using defclass and extend you could rewrite your code as follows:
var Animal = defclass({
constructor: function (name, numLegs) {
this.name = name;
this.numLegs = numLegs;
},
sayName: function () {
console.log("Hi my name is " + this.name);
}
});
var Penguin = extend(Animal, {
constructor: function (name) {
this.super.constructor.call(this, name, 2);
}
});
var penguin = new Penguin("Tux");
penguin.sayName();
How cool is that?
I think the difference is that constructor functions don't return a value. So if you call
new Penguin('bla')
it is not the function Penguin that returns the new Object, it is the new that returns the new Object. So if you let Penguin() return a new Object this will conflict with the new-keyword.
If you want to call the parent-constructor, you can do that as follows:
function Penguin(name) {
Animal.call(this, name, 2);
}
Just additionally: When you assign the prototype of Animal to its sub-prototype Penguin, you call the Function in your example without its paramers. There is a cleaner way to do that:
Penguin.prototype = Object.create(Animal.prototype);
After that you have lost the constructor function of Penguin so you need to reassign it like this:
Penguin.prototype.constructor = Animal;
This is explained in detail here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript
and
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
In the second example you are NOT returning an instance of Penguin but an instance of Animal. if you want to add more functionality to penguin you need to decorate the Animal class with extra functionality.
function Penguin(name) {
var self = new Animal(name, 2);
self.penguinFunction = function (){
//do something here
}
return self;
}

Javascript Private/Public Inheritence Syntax

I am having trouble combining private/public methods along with inheritance in Javascript. I think it is just a misunderstanding on my part and hopefully an easy resolution.
Here is what I have:
RB = {};
RB.Fruit = function() {
// Public
this.getType = function() {
return "FRUIT";
}
}
RB.Orange = function() {
// Private
function makeOrangeJuice() {
console.log("Orange has been squeezed.");
}
// Public
return {
getName : function() {
return "Orange";
}
}
}
RB.Orange.prototype = new RB.Fruit();
var o = new RB.Orange();
console.log(o.getType());
When I run this code I receive the error "Uncaught TypeError: Object # has no method 'getType'". I know that it has to do with using the "return" within the class functions (since moving the getName method out of the "return" block allows it to work), but I'd like to continue to be able to declare private/public methods within classes.
How do I modify this to allow RB.Orange to access the RB.Fruit.getType function?
Thanks!
In JavaScript, a constructor call implicitly returns the newly-constructed instance, but the constructor can override that default behavior by explicitly returning a different object. For example, if you define a "constructor" Foo like this:
function Foo() {
return new Date();
}
then the statement foo = new Foo() will set foo to a new Date, not a new Foo.
If I understand correctly what you want, you just need to change this:
return {
getName : function() {
return "Orange";
}
}
(whereby your "constructor" returns a completely fresh object, with only a getName method, and no relation to the object under construction) to this:
this.getName = function() {
return "Orange";
};
(whereby it adds a getName method to the object under construction, and still allows that object to be returned).
The main problem
When you return a non-primitive value from a constructor function, that non-primitive value is returned rather than the default returned instance you would expect when invoking it with the new keyword.
E.g.
function A() { return {}; }
new A() instanceof A; //false
Therefore you could simply change your code to something like:
RB.Orange = function() {
// Private
function makeOrangeJuice() {
console.log("Orange has been squeezed.");
}
this.getName = function () {
return 'Orange';
};
//priviledged function which uses a private member
this.someOtherFunction = function () {
makeOrangeJuice();
};
};
Some inefficiencies in your code
Why not using the prototype?
Functions that aren't priviledged should not be declared within the constructor function. In other words, functions that do not access private variables should not be created in the constructor function because they do not have to and it's extremely inefficient to do so. Why? Because a new function is being created everytime the constructor is called.
Instead you should make use of the Constructor.prototype to share your public functions between all instances.
E.g.
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function () {
console.log('My name is ' + this.name);
};
new Person('Foo Bar').sayName();
Use Object.create rather than new for inheritance when possible.
Most inheritance patterns using the new keyword were done this way because the language was lacking another way of setting up the prototype chain of an object, but now that we have Object.create, your should use it. Using the new keyword for inheritance the way you did has some undesired side-effects like running the constructor function. There are ways to avoid these side effects by using an intermediate empty function but why not simply use Object.create?
E.g. (based on the above example)
function BadPerson(name) {
//call parent constructor
Person.call(this, name + ' the bad');
}
BadPerson.prototype = Object.create(Person.prototype);
BadPerson.prototype.constructor = BadPerson; //fix constructor
Private functions can also be shared!
Note that private functions that do not access private variables can also be shared. You can make use of the module pattern to create a scope for them.
E.g.
var Person = (function () {
//private function used in a functionnal style
function _validateName(name) {
console.log('Validating the name in functionnal style');
}
//private function used in an OO style
function _validateNameOO() {
console.log('Validating the name in a OO style');
}
function Person(name) {
this.name = name;
}
Person.prototype.validateNameBothWays = function () {
_validateName(this.name);
_validateNameOO.call(this);
};
return Person;
})();
new Person().validateNameBothWays();
The following shows how you could implement shared private members and where to put the priviliged methods (methods that can access the shared privates);
I never found much use for this pattern and usually indicate a private being private with the name _aPrivate as Phillip already explained in his answer.
For an introduction on constructor functions, prototype, inheritance and the value of this click here.
RB = {};
RB.Fruit = function() {
}
// Public
RB.Fruit.prototype.getType = function() {
return "FRUIT";
};
RB.Orange = function() {
//inherit instance specific values of Fruit (there are none but there might be)
RB.Fruit.apply(this,arguments);
};
//inherit shared members from the prototype of Fruit
RB.Orange.prototype = Object.create(RB.Fruit.prototype);
//repair constructor to be Orange instead of Fruit
RB.Orange.prototype.constructor = RB.Orange;
//shared privates and privileged methods (methods that can access the privates)
// go in the following IIFE function body.
(function(){
//private version of makeOrangeJuice
var makeOrangeJuice = function () {
//the value of 'this' here isn't the Orange instance
//if you need it then pass it with the public version of
//makeOrangeJuice or use makeOrangeJuice.call(this) in the
//public version
console.log("Orange has been squeezed.");
};
//public version of makeOrangeJuice
RB.Orange.prototype.makeOrangeJuice=function(){
//call private makeOrangeJuice function
makeOrangeJuice();
}
}());
//non privileged member, in getName the private version of makeOrangeJuice
//doesn't exist you can call the public version with this.makeOrangeJuice
RB.Orange.prototype.getName = function() {
return "Orange";
};
var o = new RB.Orange();
console.log(o.getType());
o.makeOrangeJuice();
You need to assign the functions to the prototype of your objects, if you want them to be inherited.
RB = {};
RB.Fruit = function() {};
RB.Fruit.prototype.getType = function() {
return 'Fruit';
};
RB.Orange = function() {};
RB.Orange.prototype = new RB.Fruit();
RB.Orange.prototype.getName = function() {
return 'Orange';
};
If you really need to use privates, and can't just label things as private using conventions like the _name, then you'll need to move the functions that will use the privates into the constructor with the private members.
If they're not instance specific, you can (and should) wrap this whole thing with an immediate function.
(function() {
// All previous code here
window.RB = RB;
}());
Here is one way that you could do it:
var RB = {};
RB.Fruit = function() {
// Public
this.getType = function() {
return "FRUIT";
}
}
RB.Orange = function() {
// Private variable
var fruit = new RB.Fruit();
// Private function
function makeOrangeJuice() {
console.log("Orange has been squeezed.");
}
// Public object with accessor
return {
getName : function() {
return "Orange";
},
getType: fruit.getType
}
}
var o = new RB.Orange();
console.log(o.getType());
try this code.
RB = {};
RB.Fruit = function() {
// Public
this.getType = function() {
return "FRUIT";
}
}
RB.Fruit.prototype.getType = function() {
return "FRUIT";
};
RB.Orange = function() {
RB.Fruit.call(this);
// Private
function makeOrangeJuice() {
console.log("Orange has been squeezed.");
}
this.getName = function() {
return "Orange";
};
this.getJuice = function(){
makeOrangeJuice();
};
};
var o = new RB.Orange();
//calling the super-call's function
console.log(o.getType());
//public function
o.getJuice();
//trying to access private function
o.makeOrangeJuice();
For more detail on the code ojbect oriented javscript plz check below link
http://mckoss.com/jscript/object.htm

Calling method using JavaScript prototype

Is it possible to call the base method from a prototype method in JavaScript if it's been overridden?
MyClass = function(name){
this.name = name;
this.do = function() {
//do somthing
}
};
MyClass.prototype.do = function() {
if (this.name === 'something') {
//do something new
} else {
//CALL BASE METHOD
}
};
I did not understand what exactly you're trying to do, but normally implementing object-specific behaviour is done along these lines:
function MyClass(name) {
this.name = name;
}
MyClass.prototype.doStuff = function() {
// generic behaviour
}
var myObj = new MyClass('foo');
var myObjSpecial = new MyClass('bar');
myObjSpecial.doStuff = function() {
// do specialised stuff
// how to call the generic implementation:
MyClass.prototype.doStuff.call(this /*, args...*/);
}
Well one way to do it would be saving the base method and then calling it from the overriden method, like so
MyClass.prototype._do_base = MyClass.prototype.do;
MyClass.prototype.do = function(){
if (this.name === 'something'){
//do something new
}else{
return this._do_base();
}
};
I'm afraid your example does not work the way you think. This part:
this.do = function(){ /*do something*/ };
overwrites the definition of
MyClass.prototype.do = function(){ /*do something else*/ };
Since the newly created object already has a "do" property, it does not look up the prototypal chain.
The classical form of inheritance in Javascript is awkard, and hard to grasp. I would suggest using Douglas Crockfords simple inheritance pattern instead. Like this:
function my_class(name) {
return {
name: name,
do: function () { /* do something */ }
};
}
function my_child(name) {
var me = my_class(name);
var base_do = me.do;
me.do = function () {
if (this.name === 'something'){
//do something new
} else {
base_do.call(me);
}
}
return me;
}
var o = my_child("something");
o.do(); // does something new
var u = my_child("something else");
u.do(); // uses base function
In my opinion a much clearer way of handling objects, constructors and inheritance in javascript. You can read more in Crockfords Javascript: The good parts.
I know this post is from 4 years ago, but because of my C# background I was looking for a way to call the base class without having to specify the class name but rather obtain it by a property on the subclass. So my only change to Christoph's answer would be
From this:
MyClass.prototype.doStuff.call(this /*, args...*/);
To this:
this.constructor.prototype.doStuff.call(this /*, args...*/);
if you define a function like this (using OOP)
function Person(){};
Person.prototype.say = function(message){
console.log(message);
}
there is two ways to call a prototype function: 1) make an instance and call the object function:
var person = new Person();
person.say('hello!');
and the other way is... 2) is calling the function directly from the prototype:
Person.prototype.say('hello there!');
This solution uses Object.getPrototypeOf
TestA is super that has getName
TestB is a child that overrides getName but, also has
getBothNames that calls the super version of getName as well as the child version
function TestA() {
this.count = 1;
}
TestA.prototype.constructor = TestA;
TestA.prototype.getName = function ta_gn() {
this.count = 2;
return ' TestA.prototype.getName is called **';
};
function TestB() {
this.idx = 30;
this.count = 10;
}
TestB.prototype = new TestA();
TestB.prototype.constructor = TestB;
TestB.prototype.getName = function tb_gn() {
return ' TestB.prototype.getName is called ** ';
};
TestB.prototype.getBothNames = function tb_gbn() {
return Object.getPrototypeOf(TestB.prototype).getName.call(this) + this.getName() + ' this object is : ' + JSON.stringify(this);
};
var tb = new TestB();
console.log(tb.getBothNames());
function NewClass() {
var self = this;
BaseClass.call(self); // Set base class
var baseModify = self.modify; // Get base function
self.modify = function () {
// Override code here
baseModify();
};
}
An alternative :
// shape
var shape = function(type){
this.type = type;
}
shape.prototype.display = function(){
console.log(this.type);
}
// circle
var circle = new shape('circle');
// override
circle.display = function(a,b){
// call implementation of the super class
this.__proto__.display.apply(this,arguments);
}
If I understand correctly, you want Base functionality to always be performed, while a piece of it should be left to implementations.
You might get helped by the 'template method' design pattern.
Base = function() {}
Base.prototype.do = function() {
// .. prologue code
this.impldo();
// epilogue code
}
// note: no impldo implementation for Base!
derived = new Base();
derived.impldo = function() { /* do derived things here safely */ }
If you know your super class by name, you can do something like this:
function Base() {
}
Base.prototype.foo = function() {
console.log('called foo in Base');
}
function Sub() {
}
Sub.prototype = new Base();
Sub.prototype.foo = function() {
console.log('called foo in Sub');
Base.prototype.foo.call(this);
}
var base = new Base();
base.foo();
var sub = new Sub();
sub.foo();
This will print
called foo in Base
called foo in Sub
called foo in Base
as expected.
Another way with ES5 is to explicitely traverse the prototype chain using Object.getPrototypeOf(this)
const speaker = {
speak: () => console.log('the speaker has spoken')
}
const announcingSpeaker = Object.create(speaker, {
speak: {
value: function() {
console.log('Attention please!')
Object.getPrototypeOf(this).speak()
}
}
})
announcingSpeaker.speak()
No, you would need to give the do function in the constructor and the do function in the prototype different names.
In addition, if you want to override all instances and not just that one special instance, this one might help.
function MyClass() {}
MyClass.prototype.myMethod = function() {
alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
MyClass.prototype.myMethod_original.call( this );
alert( "doing override");
};
myObj = new MyClass();
myObj.myMethod();
result:
doing original
doing override
function MyClass() {}
MyClass.prototype.myMethod = function() {
alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
MyClass.prototype.myMethod_original.call( this );
alert( "doing override");
};
myObj = new MyClass();
myObj.myMethod();

Categories

Resources