How is 'Function' (not 'function') defined in Javascript? - javascript

I happened to notice Javascript also supports the Function keyword just as in ActionScript. Since both are derived from ECMA Script, existence of such similarities is a common knowledge. But I was curious on what Function represents in case of Javascript, if not a Class(as in as3).
In JS,
var func = new Function(); or var func = new Function;
Assigns a function called 'anonymous' to the variable 'func'.
Could it be simply a method to implement the actual 'function' in an Object oriented way..
Since most browsers(ff, ie & chrome) seem to implement it in the same way, is it addressed in the spec?

Function is the "class" all function extend from. All functions are really Function objects.
(function(){}) instanceof Function === true
You can also use new Function to make a function from a string (like eval).
var func = new Function('x,y', 'return x+y;')

"Every function in JavaScript is actually a Function object." MDN Documentation.
function myFunc(a, b) {
console.log( 'test' );
}
is essentially equal to
var myFunc = new Function('a', 'b', 'console.log( "test" )');
There are however some differences between to two ways of declaring a function. Read the doc!

1 way:
var Person = function() {
this.name;
this.age;
}
var p1 = new Person();
2nd way:
function Person() {
this.name;
this.age;
}
var p1 = new Person();

Related

how does "new" work with classes in javascript?

How does the new work differently in the 2 examples below? I see that the 2nd example is replacing the annoymous funciton with a variable, but in the second one, the function/class "Person" is actually being called. Does it make any difference if it's being called or not? I tried it without the calling and it still worked. So that led me to believe that new is actually calling the function and setting up this to be assigned to the instance variable.
var person = new function() {
this.setName = function(name) {
this.name = name;
}
this.sayHi = function() {
return "Hi, my name is " + this.name;
}
}
person.setName("Rafael");
console.log(person.sayHi()); // Hi, my name is Rafael
var Person = function() {
this.setName = function(name) {
this.name = name;
}
this.sayHi = function() {
return "Hi, my name is " + this.name;
}
}
var personTwo = new Person()
personTwo.setName("Rafael");
console.log(personTwo.sayHi()); // Hi, my name is Rafael
There would be almost no difference between these two examples, if it was a simple function like this:
(function() { console.log("IIFE"); })();
// or
var f = function() { console.log("Function"); };
f();
You just store your function in a variable, and then call it.
However, it makes a little difference, since it is related to JS OOP mechanisms. In the first case you get Object instance, and in the second you get Person instance. This makes difference in OOP sense.
var person = new function() { };
console.log("Is instance of: " + person.constructor.name);
console.log("There is no way to check instanceof in this case");
var Person = function() { };
var person = new Person();
console.log("Is instance of: " + person.constructor.name);
console.log(person instanceof Person);
In general, new and classes are supposed to be used as in the second case in order to enable the full functionality of JS OOP. There is absolutely no sense or/and advantage in using anonymous class constructor.
Whether or not it is assigned into a variable: does not matter. It is completely parallel to this example:
var x = 1;
console.log(x);
and
console.log(1);
Whether it needs to be called or not: A function with the new operator is always being called, but with new, parentheses are optional when no parameters are passed: new Person() is equivalent to new Person, but new Person("Joe") cannot be done differently.
In the second example, you are passing to the new operator the exact same function. You simply are using a reference (logically stored in a variable) instead of writing literal function just in place.
So, your second example is the same as:
var personTwo = new (function() {
[...]
})()
[...]
Which, in fact, is much the same as the first one:
var person = new (function() {
[...]
})
[...]
NOTE that the parentheses surrounding the function are absolutely optional in this case. You could be placed there seven if you like: (((((((function(){[...]}))))))).
The point here is that when you say «in the second one, the function/class "Person" is actually being called» you are WRONG there: That function, which acts as a constructor isn't being called by you. You are simply passing it as a parameter (the constructor function) of the new operator which is, in fact, who is actually calling the constructor with the rest of parameters you provided, if any.
See new syntax documentation:
new constructor[([arguments])]
The constructor is the function you pass to the new operator and the parameters are specified between parentheses. But they are fully optional (including the parentheses itself).
This is why new constructor; without parentheses works.
To be clear: What you thought happens (but not) would be written as:
var person = new ((function(){...})()) ();
...or, more verbosely:
var person = new (
(function(){ // Constructor builder.
[...]
return function(){...}; // Actual constructor.
})() // Constructor builder call
//v-- Parentheses to force builder to be called.
) (); // <-- Parameters (if any) passed to the constructor.

How can "new new Something" produce valid results in JavaScript?

I'm currently developing a JavaScript parser and study the ECMAScript 5.1 specification. Here's a question which puzzles me at the moment.
§ 11.2 Left-Hand-Side Expressions defines the following NewExpression production:
NewExpression :
MemberExpression
new NewExpression
If I read it correctly, then the NewExpression may be something like
new new Something
(Actually, any amount of news.)
This puzzles me completely. How could new Something potentialy return anything you could once again new? Is it possible at all?
It is not common at all, but it is possible; a function that returns a function:
function baz(){}
function foo(){return baz}
new new foo() instanceof baz // true
Take a look at section 13.2.2 [[Construct]] in the specification. More precisely, step 9 of the algorithm.
If Type(result) is Object then return result.
Functions are objects, so if you return a function from a function and try to instantiate the latter function using new, you'll get back the former function, not a new object. But functions are also constructors, so you can new the returned function.
function bar() {}
function foo() { return bar; }
new foo === bar; // true
I had to use new new when using an object as namespace. Though there will be a nicer way:
Instead of:
var Namespace = function() {
var ClassFirst = this.ClassFirst = function() {
this.abc = 123;
}
var ClassSecond = this.ClassSecond = function() {
console.log("Cluttered way to access another class in namespace: ", new new Namespace().ClassFirst().abc);
console.log("Nicer way to access a class in same namespace: ", new ClassFirst().abc);
}
}
new new Namespace().ClassSecond()
Do this:
var Namespace = new function() {
var ClassFirst = this.ClassFirst = function() {
this.abc = 123;
}
var ClassSecond = this.ClassSecond = function() {
console.log("Cluttered way to access another class in namespace: ", new Namespace.ClassFirst().abc);
console.log("Nicer way to access a class in same namespace: ", new ClassFirst().abc);
}
}
new Namespace.ClassSecond()
Not directly related to the question, but I was googling new new javascript, because it looked pretty ugly and wrong. This post can help to avoid this unneeded object creation for fellow new new Google'ers.

Dynamically control arguments while creating objects in javascript

I have multiple eatable classes in javascript eg: food, drinks, snacks.
Each of this class requires a different set of parameters. I have another factory class which creates an instance of the eatable item that is sent to it.
I am not able to figure out how can we dynamically select the eatable item and pass the arguments (which are in an array form) using this factory?
I have come up with two solutions -
Solution 1:
var factory = function(eatable, argumentList){
var obj = new eatable(argumentList);
return obj
};
This is a problem because argumentList is an array.
Solution 2
var factory = function(eatable, argumentList){
var obj = eatable.apply({}, argumentList);
return obj
};
this does not really create an object of the eatable type.
The effect that I really want
Say I am able to convert the argumentList into a js argument type object then -
var obj = new eatable(argumentList.toArguments());
obj instanceOf eatable; // should return true
Please help!
Ah, yes. I've encountered this problem before - you can't use new and apply together in JavaScript. A similar question has been asked before: Use of .apply() with 'new' operator. Is this possible?
The problem is quite apparent - new is a keyword, not a function; and apply can only be used on a function. If new was a function instead of a keyword then we could use it in conjuction with apply.
To understand how to do so let's create a function called new which does exactly what the keyword new does:
Function.prototype.new = (function () {
function Factory(constructor, args) {
return constructor.apply(this, args);
}
return function() {
Factory.prototype = this.prototype;
return new Factory(this, arguments);
};
}());
Now instead of calling a constructor as follows:
var object = new constructor(arg1, ...);
You can call a constructor as follows:
var object = constructor.new(arg1, ...);
What's the advantage of doing so you ask? Well it's simple really. Because new is now a function instead of a keyword you can use it in conjunction with apply as follows:
var object = Function.new.apply(constructor, [arg1, ...]);
Hence your eatable factory function now becomes:
var factory = function(eatable, argumentList) {
var obj = Function.new.apply(eatable, argumentList);
return obj;
};
Edit: If all your factory function does is take an eatable constructor and an argumentList and return new.apply(eatable, argumentList) then as Bergi pointed out in his comment you could define factory as follows instead:
var factory = Function.apply.bind(Function.new);
Hope this helped.
You can use Object.create to set up the prototype chain correctly:
function factory(eatable, argumentList){
var obj = Object.create(eatable.prototyope);
return eatable.apply(obj, argumentList) || obj;
}
This is basically what the new operator does.
You can define a function init to initialize the object .
function Eatable(){
}
Eatable.prototype.init = function(/** arg1, arg2, arg3 **/){
// initialize object
}
In factory function
var eatable = new Eatable();
eatable.init.apply(eatable, /** pass arguments array here **/);
return eatable;
You have to provide context to apply, The context is the object you are trying to apply the arguments to. The context you are currently passing {} is of type Object
var factory = function(eatable, argumentList){
var obj = eatable.apply(new Eatable(), argumentList);
return obj
};
I can not use factories with out polymorphism so if you didn't create those eatables in way they extend an Eatalbe object you will not be able to do it.
One more way to achieve this is as follows -
var _bind = Function.prototype.bind;
var factory = function(_constructor, _argumentList){
var obj = _bind.apply(_constructor, [null].concat(_argumentList));
return obj
};

Beget function in JavaScript: The Good Parts

I am reading JavaScript: The Good Parts. In the book, a beget function is defined. Its purpose is to create and return a new object, which uses the other object as its prototype. Why does the beget function instantiate a new function instead of an object?
if( typeof Object.beget !== 'function' ){
Object.beget = function(o){
var F =new Function(){}; // this line, why it cannot be var F = new Object();
F.prototype = o;
return new F();
}
}
This has everything to do with the new keyword. In JavaScript, new only works with functions (which are a special type of object).
If you use new on just about any function, you will get an object back.
alert(typeof console.log); // function
var dumb = new console.log(); // dumb is an object
The type of object you get back depends on that function's prototype object.
alert(typeof console.log.prototype); // object, any new objects created by the new keyword will be of this type.
alert(typeof Function.prototype); // function, new objects are functions.
alert(typeof new Function()); // function, see?
alert(typeof (function(){})); // function, using literal syntax, equivalent
You may have noticed from above that Function itself is a function. In fact, all of the built-in constructors are functions (Function, Object, Number, Array, etc). Capitalization is just a convention to distinguish how you use a function.
So to get back to your question, the author uses an empty Function object simply because it can be used as a constructor. Objects cannot.
He then changes the constructor's prototype, so that it will return objects of that type.
Object.beget = function(o) {
var F = new Function(); // now F can be used as a constructor.
F.prototype = o; // All new objects F creates will be based on o.
return new F();
};
To add on to previous answers and avoid some confusion, this beget() function was replaced with create() via an errata, so different books seem to have different version of the code. The book on Safari Books Online has it printed like this:
if (typeof Object.create !== 'function') {
Object.create = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
Note that it no longer encourages the use of the new keyword on line 3.
In my opinion,as the MDN said
The new operator creates an instance of a user-defined object type or of one of the built-in object types that has a constructor function.
Syntax
new constructor[([arguments])]
Parameters
constructor
A function that specifies the type of the object instance.
arguments
A list of values that the constructor will be called with.
So,wo have to use a function to create a new instance.
For example:
var list = new Array();
typeof Array;//"function"
This Array is not a object,but a constructor function.
For one thing, you can't use () on a generic object nor on anything else that isn't a function. You'll get an error something like "TypeError: F is not a function."
// create a temporary function
var F =new Function(){};
// set the prototype of the function to be o
F.prototype = o;
// create a new object from the function
return new F();
Because that's how new works. new creates a new object and places F.prototype in the prototype chain.
new F() === Object.create(F.prototype)
My books is
if (typeof Object.beget !== 'function') {
Object.beget = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
your answer is in the book only. The beget method created a new object and that object is used as its prototype.
Below line is used to check if beget method is already used or not !
if( typeof Object.beget !== 'function' )
And then..
A constructor, F, is defined, its prototype is set to the passed in object and then a new instance is returned.

Using "Object.create" instead of "new"

Javascript 1.9.3 / ECMAScript 5 introduces Object.create, which Douglas Crockford amongst others has been advocating for a long time. How do I replace new in the code below with Object.create?
var UserA = function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
}
UserA.prototype.sayHello = function() {
console.log('Hello '+ this.name);
}
var bob = new UserA('bob');
bob.sayHello();
(Assume MY_GLOBAL.nextId exists).
The best I can come up with is:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB);
bob.init('Bob');
bob.sayHello();
There doesn't seem to be any advantage, so I think I'm not getting it. I'm probably being too neo-classical. How should I use Object.create to create user 'bob'?
With only one level of inheritance, your example may not let you see the real benefits of Object.create.
This methods allows you to easily implement differential inheritance, where objects can directly inherit from other objects.
On your userB example, I don't think that your init method should be public or even exist, if you call again this method on an existing object instance, the id and name properties will change.
Object.create lets you initialize object properties using its second argument, e.g.:
var userB = {
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB, {
'id' : {
value: MY_GLOBAL.nextId(),
enumerable:true // writable:false, configurable(deletable):false by default
},
'name': {
value: 'Bob',
enumerable: true
}
});
As you can see, the properties can be initialized on the second argument of Object.create, with an object literal using a syntax similar to the used by the Object.defineProperties and Object.defineProperty methods.
It lets you set the property attributes (enumerable, writable, or configurable), which can be really useful.
There is really no advantage in using Object.create(...) over new object.
Those advocating this method generally state rather ambiguous advantages: "scalability", or "more natural to JavaScript" etc.
However, I have yet to see a concrete example that shows that Object.create has any advantages over using new. On the contrary there are known problems with it. Sam Elsamman describes what happens when there are nested objects and Object.create(...) is used:
var Animal = {
traits: {},
}
var lion = Object.create(Animal);
lion.traits.legs = 4;
var bird = Object.create(Animal);
bird.traits.legs = 2;
alert(lion.traits.legs) // shows 2!!!
This occurs because Object.create(...) advocates a practice where data is used to create new objects; here the Animal datum becomes part of the prototype of lion and bird, and causes problems as it is shared. When using new the prototypal inheritance is explicit:
function Animal() {
this.traits = {};
}
function Lion() { }
Lion.prototype = new Animal();
function Bird() { }
Bird.prototype = new Animal();
var lion = new Lion();
lion.traits.legs = 4;
var bird = new Bird();
bird.traits.legs = 2;
alert(lion.traits.legs) // now shows 4
Regarding, the optional property attributes that are passed into Object.create(...), these can be added using Object.defineProperties(...).
Object.create is not yet standard on several browsers, for example IE8, Opera v11.5, Konq 4.3 do not have it. You can use Douglas Crockford's version of Object.create for those browsers but this doesn't include the second 'initialisation object' parameter used in CMS's answer.
For cross browser code one way to get object initialisation in the meantime is to customise Crockford's Object.create. Here is one method:-
Object.build = function(o) {
var initArgs = Array.prototype.slice.call(arguments,1)
function F() {
if((typeof o.init === 'function') && initArgs.length) {
o.init.apply(this,initArgs)
}
}
F.prototype = o
return new F()
}
This maintains Crockford prototypal inheritance, and also checks for any init method in the object, then runs it with your parameter(s), like say new man('John','Smith'). Your code then becomes:-
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}} // For example
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.build(userB, 'Bob'); // Different from your code
bob.sayHello();
So bob inherits the sayHello method and now has own properties id=1 and name='Bob'. These properties are both writable and enumerable of course. This is also a much simpler way to initialise than for ECMA Object.create especially if you aren't concerned about the writable, enumerable and configurable attributes.
For initialisation without an init method the following Crockford mod could be used:-
Object.gen = function(o) {
var makeArgs = arguments
function F() {
var prop, i=1, arg, val
for(prop in o) {
if(!o.hasOwnProperty(prop)) continue
val = o[prop]
arg = makeArgs[i++]
if(typeof arg === 'undefined') break
this[prop] = arg
}
}
F.prototype = o
return new F()
}
This fills the userB own properties, in the order they are defined, using the Object.gen parameters from left to right after the userB parameter. It uses the for(prop in o) loop so, by ECMA standards, the order of property enumeration cannot be guaranteed the same as the order of property definition. However, several code examples tested on (4) major browsers show they are the same, provided the hasOwnProperty filter is used, and sometimes even if not.
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}}; // For example
var userB = {
name: null,
id: null,
sayHello: function() {
console.log('Hello '+ this.name);
}
}
var bob = Object.gen(userB, 'Bob', MY_GLOBAL.nextId());
Somewhat simpler I would say than Object.build since userB does not need an init method. Also userB is not specifically a constructor but looks like a normal singleton object. So with this method you can construct and initialise from normal plain objects.
TL;DR:
new Computer() will invoke the constructor function Computer(){} for one time, while Object.create(Computer.prototype) won't.
All the advantages are based on this point.
Sidenote about performance: Constructor invoking like new Computer() is heavily optimized by the engine, so it may be even faster than Object.create.
You could make the init method return this, and then chain the calls together, like this:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
return this;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB).init('Bob');
Another possible usage of Object.create is to clone immutable objects in a cheap and effective way.
var anObj = {
a: "test",
b: "jest"
};
var bObj = Object.create(anObj);
bObj.b = "gone"; // replace an existing (by masking prototype)
bObj.c = "brand"; // add a new to demonstrate it is actually a new obj
// now bObj is {a: test, b: gone, c: brand}
Notes: The above snippet creates a clone of an source object (aka not a reference, as in cObj = aObj). It benefits over the copy-properties method (see 1), in that it does not copy object member properties. Rather it creates another -destination- object with it's prototype set on the source object. Moreover when properties are modified on the dest object, they are created "on the fly", masking the prototype's (src's) properties.This constitutes a fast an effective way of cloning immutable objects.
The caveat here is that this applies to source objects that should not be modified after creation (immutable). If the source object is modified after creation, all the clone's unmasked properties will be modified, too.
Fiddle here(http://jsfiddle.net/y5b5q/1/) (needs Object.create capable browser).
I think the main point in question - is to understand difference between new and Object.create approaches. Accordingly to this answer and to this video new keyword does next things:
Creates new object.
Links new object to constructor function (prototype).
Makes this variable point to the new object.
Executes constructor function using the new object and implicit perform return this;
Assigns constructor function name to new object's property constructor.
Object.create performs only 1st and 2nd steps!!!
In code example provided in question it isn't big deal, but in next example it is:
var onlineUsers = [];
function SiteMember(name) {
this.name = name;
onlineUsers.push(name);
}
SiteMember.prototype.getName = function() {
return this.name;
}
function Guest(name) {
SiteMember.call(this, name);
}
Guest.prototype = new SiteMember();
var g = new Guest('James');
console.log(onlineUsers);
As side effect result will be:
[ undefined, 'James' ]
because of Guest.prototype = new SiteMember();
But we don't need to execute parent constructor method, we need only make method getName to be available in Guest.
Hence we have to use Object.create.
If replace Guest.prototype = new SiteMember();
to Guest.prototype = Object.create(SiteMember.prototype); result be:
[ 'James' ]
Sometimes you cannot create an object with NEW but are still able to invoke the CREATE method.
For example: if you want to define a Custom Element it must derive from HTMLElement.
proto = new HTMLElement //fail :(
proto = Object.create( HTMLElement.prototype ) //OK :)
document.registerElement( "custom-element", { prototype: proto } )
The advantage is that Object.create is typically slower than new on most browsers
In this jsperf example, in a Chromium, browser new is 30 times as fast as Object.create(obj) although both are pretty fast. This is all pretty strange because new does more things (like invoking a constructor) where Object.create should be just creating a new Object with the passed in object as a prototype (secret link in Crockford-speak)
Perhaps the browsers have not caught up in making Object.create more efficient (perhaps they are basing it on new under the covers ... even in native code)
Summary:
Object.create() is a Javascript function which takes 2 arguments and returns a new object.
The first argument is an object which will be the prototype of the newly created object
The second argument is an object which will be the properties of the newly created object
Example:
const proto = {
talk : () => console.log('hi')
}
const props = {
age: {
writable: true,
configurable: true,
value: 26
}
}
let Person = Object.create(proto, props)
console.log(Person.age);
Person.talk();
Practical applications:
The main advantage of creating an object in this manner is that the prototype can be explicitly defined. When using an object literal, or the new keyword you have no control over this (however, you can overwrite them of course).
If we want to have a prototype The new keyword invokes a constructor function. With Object.create() there is no need for invoking or even declaring a constructor function.
It can Basically be a helpful tool when you want create objects in a very dynamic manner. We can make an object factory function which creates objects with different prototypes depending on the arguments received.
You have to make a custom Object.create() function. One that addresses Crockfords concerns and also calls your init function.
This will work:
var userBPrototype = {
init: function(nameParam) {
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
function UserB(name) {
function F() {};
F.prototype = userBPrototype;
var f = new F;
f.init(name);
return f;
}
var bob = UserB('bob');
bob.sayHello();
Here UserB is like Object.create, but adjusted for our needs.
If you want, you can also call:
var bob = new UserB('bob');
While Douglas Crockford used to be a zealous advocate of Object.create() and he is basically the reason why this construct actually is in javascript, he no longer has this opinion.
He stopped using Object.create, because he stopped using this keyword altogether as it causes too much trouble. For example, if you are not careful it can easily point to the global object, which can have really bad consequences. And he claims that without using this Object.create does not make sense anymore.
You can check this video from 2014 where he talks at Nordic.js:
https://www.youtube.com/watch?v=PSGEjv3Tqo0
new and Object.create serve different purposes. new is intended to create a new instance of an object type. Object.create is intended to simply create a new object and set its prototype. Why is this useful? To implement inheritance without accessing the __proto__ property. An object instance's prototype referred to as [[Prototype]] is an internal property of the virtual machine and is not intended to be directly accessed. The only reason it is actually possible to directly access [[Prototype]] as the __proto__ property is because it has always been a de-facto standard of every major virtual machine's implementation of ECMAScript, and at this point removing it would break a lot of existing code.
In response to the answer above by 7ochem, objects should absolutely never have their prototype set to the result of a new statement, not only because there's no point calling the same prototype constructor multiple times but also because two instances of the same class can end up with different behavior if one's prototype is modified after being created. Both examples are simply bad code as a result of misunderstanding and breaking the intended behavior of the prototype inheritance chain.
Instead of accessing __proto__, an instance's prototype should be written to when an it is created with Object.create or afterward with Object.setPrototypeOf, and read with Object.getPrototypeOf or Object.isPrototypeOf.
Also, as the Mozilla documentation of Object.setPrototypeOf points out, it is a bad idea to modify the prototype of an object after it is created for performance reasons, in addition to the fact that modifying an object's prototype after it is created can cause undefined behavior if a given piece of code that accesses it can be executed before OR after the prototype is modified, unless that code is very careful to check the current prototype or not access any property that differs between the two.
Given
const X = function (v) { this.v = v };
X.prototype.whatAmI = 'X';
X.prototype.getWhatIAm = () => this.whatAmI;
X.prototype.getV = () => this.v;
the following VM pseudo-code is equivalent to the statement const x0 = new X(1);:
const x0 = {};
x0.[[Prototype]] = X.prototype;
X.prototype.constructor.call(x0, 1);
Note although the constructor can return any value, the new statement always ignores its return value and returns a reference to the newly created object.
And the following pseudo-code is equivalent to the statement const x1 = Object.create(X.prototype);:
const x0 = {};
x0.[[Prototype]] = X.prototype;
As you can see, the only difference between the two is that Object.create does not execute the constructor, which can actually return any value but simply returns the new object reference this if not otherwise specified.
Now, if we wanted to create a subclass Y with the following definition:
const Y = function(u) { this.u = u; }
Y.prototype.whatAmI = 'Y';
Y.prototype.getU = () => this.u;
Then we can make it inherit from X like this by writing to __proto__:
Y.prototype.__proto__ = X.prototype;
While the same thing could be accomplished without ever writing to __proto__ with:
Y.prototype = Object.create(X.prototype);
Y.prototype.constructor = Y;
In the latter case, it is necessary to set the constructor property of the prototype so that the correct constructor is called by the new Y statement, otherwise new Y will call the function X. If the programmer does want new Y to call X, it would be more properly done in Y's constructor with X.call(this, u)
new Operator
This is used to create object from a constructor function
The new keywords also executes the constructor function
function Car() {
console.log(this) // this points to myCar
this.name = "Honda";
}
var myCar = new Car()
console.log(myCar) // Car {name: "Honda", constructor: Object}
console.log(myCar.name) // Honda
console.log(myCar instanceof Car) // true
console.log(myCar.constructor) // function Car() {}
console.log(myCar.constructor === Car) // true
console.log(typeof myCar) // object
Object.create
You can also use Object.create to create a new object
But, it does not execute the constructor function
Object.create is used to create an object from another object
const Car = {
name: "Honda"
}
var myCar = Object.create(Car)
console.log(myCar) // Object {}
console.log(myCar.name) // Honda
console.log(myCar instanceof Car) // ERROR
console.log(myCar.constructor) // Anonymous function object
console.log(myCar.constructor === Car) // false
console.log(typeof myCar) // object
I prefer a closure approach.
I still use new.
I don't use Object.create.
I don't use this.
I still use new as I like the declarative nature of it.
Consider this for simple inheritance.
window.Quad = (function() {
function Quad() {
const wheels = 4;
const drivingWheels = 2;
let motorSize = 0;
function setMotorSize(_) {
motorSize = _;
}
function getMotorSize() {
return motorSize;
}
function getWheelCount() {
return wheels;
}
function getDrivingWheelCount() {
return drivingWheels;
}
return Object.freeze({
getWheelCount,
getDrivingWheelCount,
getMotorSize,
setMotorSize
});
}
return Object.freeze(Quad);
})();
window.Car4wd = (function() {
function Car4wd() {
const quad = new Quad();
const spareWheels = 1;
const extraDrivingWheels = 2;
function getSpareWheelCount() {
return spareWheels;
}
function getDrivingWheelCount() {
return quad.getDrivingWheelCount() + extraDrivingWheels;
}
return Object.freeze(Object.assign({}, quad, {
getSpareWheelCount,
getDrivingWheelCount
}));
}
return Object.freeze(Car4wd);
})();
let myQuad = new Quad();
let myCar = new Car4wd();
console.log(myQuad.getWheelCount()); // 4
console.log(myQuad.getDrivingWheelCount()); // 2
console.log(myCar.getWheelCount()); // 4
console.log(myCar.getDrivingWheelCount()); // 4 - The overridden method is called
console.log(myCar.getSpareWheelCount()); // 1
Feedback encouraged.

Categories

Resources