Using apply() to chain constructors in JavaScript? - javascript

I'm learning apply() in MDN, there's an example I can't figure out:
// Create constructor method for array of args
Function.prototype.construct = function(aArgs) {
var oNew = Object.create(this.prototype);
this.apply(oNew, aArgs);
return oNew;
};
what does this.apply(oNew, aArgs) do?

First: what would be the aim of this function?
The aim
This prototype function constructor is defined to provide an alternative to new. Where new Person(a,b) will need the arguments as such, this function provides a way to pass those arguments as array.
As a side note: it should be said that the spread syntax makes such a feature unnecessary, as we can pass such an array like so: new Person(...[a,b]). But OK...
Example use
Let's say we have a constructor:
function Person(name, gender) {
this.name = name;
this.gender = gender;
}
And I have an array with the arguments:
var args = ["Helen", "F"];
Then we could do:
var person = new Person(args[0], args[1]);
But we want to pass args as single argument. Now this prototype function will help us with that. We can now do:
var person = Person.construct(args);
// Create constructor method for array of args
Function.prototype.construct = function(aArgs) {
var oNew = Object.create(this.prototype);
this.apply(oNew, aArgs);
return oNew;
};
function Person(name, gender) {
this.name = name;
this.gender = gender;
}
var args = ["Helen", "F"];
var person = Person.construct(args);
console.log(person);
How does it work
When calling Person.construct(args) the this object will be Person, i.e. our constructor function.
Then the following is done:
var oNew = Object.create(this.prototype);
This will create a Person object, but without actually calling the constructor function Person, so the object is not initialised. It is just an empty object that is an instance of Person.
So we need somehow to call Person with the arguments we have. We can use apply for that:
this.apply(oNew, aArgs);
Recall that this is Person, so we call Person here via apply. apply makes it possible to call a function with a specific this object value (our newly created instance of Person) and the arguments as an array -- exactly what we need.
So the above will initialise our empty object with the name and gender arguments, completing the full creation and initialisation that you would normally have with new.

This function is works like the operator new in Javascript.
You can figure out how new works in MDN
For example, if you define an constructor function like below
function Foo(name, age) {
this.name = name
this.age = age
}
Foo.prototype.hello = function() {
console.log('hello' + this.name + this.age)
}
If you already define the Function.prototype.construct like the example you show.
Then you can use either const a = new Foo('a', 1) or const a = Foo.construct('a', 1) to create the same object
And this.apply(oNew, aArgs) is used for call the constructor function to initiate the instance just created

Related

why do i not return anything from my constructor function?

function Person (name, eyeColor, age) {
this.name = name;
this.eyeColor = eyeColor;
this.age = age;
this.updateAge = function () {
return ++this.age;
};
}
let person1 = new Person("kevin", "blue", 34); // normalli would have to return something but as im
creating a new object
let person2 = new Person("tom", "brown", 64);
console.log(person1);
Normally if i wanted let person1 to equal something from inside the function i would have to return something to it. Why do i not have to do that when creating a new object constructor. if i console.log person 1, it returns person 1 to me. Whereas if i were normally calling a function i would need it have to return something to me for that to be the assignment value of the variable. Also why are we returning from the method? But we dont return from inside the constructor function
thanks all
Please refer below document
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
The new keyword does the following things:
Creates a blank, plain JavaScript object;
Links (sets the constructor of) this object to another object;
Passes the newly created object from Step 1 as the this context;
Returns this if the function doesn't return an object.

Javascript - How to create new instance of functions

I know that, we can create the new instance of functions by the following approach. But my question is there any other way to achieve the same?
var Person = function (firstName) {
this.firstName = firstName;
console.log('Person instantiated');
};
var person1 = new Person('Alice');
var person2 = new Person('Bob');
// Show the firstName properties of the objects
console.log('person1 is ' + person1.firstName); // logs "person1 is Alice"
console.log('person2 is ' + person2.firstName); // logs "person2 is Bob"
Since, some time in case of new declaration fails, i am not getting the error too..
Especially, in javascript oops concept requires the different approach.
Some times, I am confusing without even calling the new key words it all works fine.. what is the different between using the new keyword and without using that?
example :
var setColor = function (color) {
return color;
}
var x = setColor('red');
var y = setColor('blue');
console.log(y);
console.log(x);
The new [Function] keyword does many things, but the main things it does are:
Creates a new object
Uses [Function]'s prototype as the parent prototype for the new object
Executes the contents of [Function], using this as a reference to the new object
If you call such a function without new, the this reference will be determined the way it would usually be determined when calling a function, and quite often this would be the global object.
One thing you can do to help catch these mistakes more easily is to use strict mode:
"use strict";
var Person = function (firstName) {
this.firstName = firstName;
console.log('Person instantiated');
};
var person1 = Person('Alice');
If the above code were executed, this would be null instead of the global object, and you would get an error right away instead of having the properties assigned to the global object (and having hard-to-catch bugs).
A way to avoid these kinds of mistakes with new altogether is to simply have the function return a new object instead of being a constructor:
var person = function (firstName) {
console.log('person instantiated');
return {
firstName: firstName
};
};
var person1 = person('Alice');
var person2 = person('Bob');
If you do this, it doesn't matter whether you use new or not, because the function doesn't use this.
Edit There was a question below about prototypes. If you are unfamiliar with prototypes, this is a feature that allows you to specify properties and methods that will be shared between all instances of an object:
"use strict";
var Person = function (firstName) {
this.firstName = firstName;
console.log('Person instantiated');
};
Person.prototype.getMyName = function () {
return this.firstName;
};
var person1 = new Person('Alice');
console.log(person1.getMyName());
If you do this, then all instances created with new Person() will share the getMyName method.
The new-less option I detailed later on does not provide this automatic prototype extension, but there are alternatives:
Option 1 - don't use a prototype:
var person = function (firstName) {
console.log('person instantiated');
return {
firstName: firstName,
getMyName: function () {
return this.firstName;
}
};
};
Option 2 - Use Object.create() to extend the prototype:
var person = function (firstName) {
console.log('person instantiated');
var person = Object.create(person.prototype);
person.firstName = firstName;
return person;
};
Option 3 - Use Object.assign() method to copy the contents of the prototype to a new object:
var person = function (firstName) {
console.log('person instantiated');
return Object.assign({
firstName: firstName
}, person.prototype);
};
Using the new keyword when you call a function sets the context (this) inside the function to be a newly instantiated object, rather than window or some other context, which is why you can assign to this.firstName inside the function, and then refer to it as person1.firstName.
Without using the new keyword, the value of this WONT be a blank object, so you will be assigning to window instead. In this case, you want to use new since you are using the function as a constructor. If you aren't planning to use the function as a constructor, you don't want to call it with new.
Another possible structure using closures and not objects at all
This structure also can be nested creating private static variables
It has no use of the word this
var thing = function(private_var){
function get(){
console.log(private_var)
}
function set(z){
private_var = z
}
return {
get:get,
set:set
}
}
var x = thing(0)
var y = thing(1)
Please note :
This makes certain types of programmers freak out and panic
&& importantly x.say !== y.say
I think you need a bit better understanding of how objects and prototyping work in Javascript.
Consider you have a use case where you want an object that represents a user, and stores their first_name.
Without using any functions, you can simply create an object with your desired properties:
var person = {
first_name: 'joel'
};
This is a standard javascript object - nothing special at all, and no usage of the new keyword to construct it. An alternate syntax to accomplish the same thing would be:
var person = new Object();
person.first_name = 'joel';
Again - this is just a standard object - nothing special at all.
The main reason for creating new instances of a function, is to use javascript's prototyping system. This is similar to a class in other languages. Let's say you wanted all instances of a person to have a method called getName(). You could either make sure you create that method on every person you have...
var person = {
first_name: 'joel',
getName: function() {
return this.first_name;
}
};
or...
var person = new Object();
person.first_name = 'joel';
person.getName = function() {
return this.first_name;
};
However a better approach for this kind of thing, where you're always going to want this method defined for every user, is to create a new instance of a person object, and define the getName method on the prototype property of the Person function:
function Person() {}
Person.prototype.getName = function() {
return this.first_name;
}
var user = new Person();
user.first_name = 'joel';
console.log(user.getName());
... Or as per your example, you can use a parameter to the Person constructor function to set the first name property:
function Person(first_name) {
this.first_name = first_name;
}
Person.prototype.getName = function() {
return this.first_name;
};
var user = new Person('joel');
console.log(user.getName());
Note that using this method you would always use the new keyword when creating a Person instance. The reason for this becomes clear when you consider the followng:
function Person() {this.first_name = 'joel'; return 'test';}
console.log(window.first_name); // Undefined, as expected
console.log(Person()); // Shows "test";
console.log(window.first_name); // shows "joel".
console.log(new Person()); // Shows "{first_name: 'joel'}"
Note that on line 4 above, you can see that by omitting the new keyword on a function call that expects you to be using it, you've accidentally modified a property on the window object, instead of setting it on a new regular object.
Effectively - you can consider usage of the new keyword to cause the return value of the Person function to be disrecarded, and instead you'll be given back a new instance of the Person Object.
Also note that you can reduce the risk of accidental modifying of the window object by omitting the new keyword from inside your function, by checking if this is equal to window and returning a new instance of your function instead:
function Person() {
if (this === window) return new Person();
this.first_name = 'joel';
}
With the above, you can instantiate your person object using either of the following methods and both will have the same effect:
var user1 = new Person();
var user2 = Person();
For some more information on how javascript functions and prototype objects work, I suggest reading http://www.w3schools.com/js/js_object_prototypes.asp

Why include .prototype in the function?

I am reading John Resig's slideshow http://ejohn.org/apps/learn/#78
Its not clear to me why i need to include .prototype in the line Me.prototype = new Person();
function Person(){}
Person.prototype.getName = function(){
return this.name;
};
function Me(){
this.name = "John Resig";
}
Me.prototype = new Person();
var me = new Me();
assert( me.getName(), "A name was set." );
Think of it this way, if every person is going to have a name, it's easier to assign the getName function to it's prototype.
In this case, you have a Person that has a prototype function to get a name, and a few lines below you have a Me function that assigns a name by default. Since we want to incorporate the getName function, we use the Person which already has that function object built-in. When you construct Me() and assign to me you can call getName() and use that to return the name, which by default is "John Resig"
The same thing can be achieved without prototype, like this
function Me(){
this.name = "John Resig";
this.getName = function () {
return this.name;
}
}
var me = new Me();
...BUT by using prototype, it helps create objects a lot faster, you can refer to this answer as well.

javascript functions and objects using keyword 'this' does not work

my question here is about functions and objects in javascript. I have three questions that stems from one to other. In the below example, I try to access the value of 'a' in test, but I get undefined. but I create a new object of test, then I am able to access the 'a' value and change it.
//create a function called test
var test=function() {
this.a=2
this.b=3 };
test.a//undefined
//create a object called test1 using 'new'
test1 = new test();
test1.a//2
//change the value of a in test1
test1.a=4
test1 //Object { a=4, b=3}
while trying to find why this happens, I came across this javascript functions are objects? and another question popped out of this.
The accepted solution for that SO question is below
var addn = function func(a) {
return func.n + a;
};
addn['n'] = 3;
addn(3);
I changed the 'func.n' to 'this' and it no longer works
var addn=function func(a) {
return this.n+a;
};
addn['n']=3;
addn(3); //NaN
making anonymous function with 'this' also did not help
//anonymous function
var addn=function(a) {
return this.n+a;
};
addn['n']=3;
addn(3); //NaN
why using 'this' did not work?
one final question, what is the difference in using keyword 'new' and 'createObject'. Douglas Crokford suggests using 'CreateObject' in his book, but I fail to understand why. Thanks all for your comments
1. Functions are constructors for new objects
When you call new FuncName, the function acts as a constructor, and the value of this inside points to the object being constructed (not the function itself). When you remove new, this becomes undefined, falling back to the global object (unless you're in strict mode).
2. Functions are also objects
Every function is an instance of Function, so the functions themselves are objects and can have have their own properties. Those properties cannot be accessed with this.propName inside the function body, only with funcName.propName. That's because this inside a function is never the function object itself (unless you forced it to be, with bind, call, or apply).
I hope both topics above help you understand how functions work. As for your final question: Crockford's createObject is a different way to implement inheritance, doing basically what Object.create does in ES5-compliant browsers. It allows an object to inherit straight from another object, without requiring you to manually create a new constructor, set its prototype property (which is an example of a property on a function object), and create an instance with new. Crockford prefers that, and said he stopped using new in favor of this approach.
In response to the questions you asked in chat, here is an attempt to explain what functions are and what they do, with examples.
Functions can be just... functions
You call them, they do something:
function alertThis(what) {
alert(what)
}
alertThis("alerting something");
You can also pass them values, and have them return values
function timesTwo(num) {
return num * 2;
}
timesTwo(2); // 4
They can be passed and return anything, including objects...
function createPerson(firstName, lastName) {
return {
firstName : firstName,
lastName : lastName
}
}
var john = createPerson('John', 'Doe');
john.lastName; // "Doe"
...and other functions:
function timesN(n) {
return function(num) {
return n * num;
}
}
var timesThree = timesN(3);
timesThree(5); // 15
Functions are objects
Functions can be passed around and returned like any ordinary object. That's because they are objects. Like any object, they can have properties:
function countCalls() {
countCalls.timesCalled++;
}
countCalls.timesCalled = 0;
countCalls();
countCalls();
countCalls.timesCalled; // 2
One very important default property of functions is prototype. It's a special property, and we'll see why.
Functions can act as constructors for new objects
Functions can behave like class constructors do in regular OO languages. When called with new, they create a new object of a certain "class". This new object is called this inside the function, and is automatically returned:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
var john = new Person('John', 'Doe');
john.firstName; // "John"
john instanceof Person; // true
... unless you deliberately return something else:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
var fakePerson = {
firstName : firstName,
lastName : lastName
};
return fakePerson;
}
var notPerson = new Person('John', 'Doe');
notPerson.firstName; // "John"
notPerson instanceof Person; // false
// Note: the object called 'this' inside the function is created, but
// after the function is called there is no outside reference to it.
Objects created by constructors know who created them, and can see their prototype property
Back to a real person:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// Add something to the Person prototype
Person.prototype.sayHi = function() {
return "hi, I'm " + this.firstName;
}
var john = new Person('John', 'Doe');
john.sayHi(); // "Hi, I'm John"
john.constructor; // Person
The object john can sayHi() because it has access to everything inside its constructor's prototype property. But it cannot see other properties of Person directly (only through their own constructor property):
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
Person.timesCalled++;
// There is no 'this.timesCalled', only Person.timesCalled
}
Person.timesCalled = 0;
var john = new Person('John', 'Doe');
john.timesCalled; // undefined - john cannot be called, Person can
john.constructor.timesCalled; // 1
1.
addn['n'] = 3; //Means you add static property n to the function(object) addn.
so addn.n also work.
2
this.n means property n of the instance.
this.n === undefined so it returns NaN.
3 var addn=function func(a) means you give a second name to func.
var addn=function(a) is better format in most case.
4 createObject is not a native javaScript code. 'New' is.

prototype chain in javascript

Suppose I have two constructor function:
var Person = function(xx,xx,xxx,xxxxxxx) {
//Person initialization
}
var Man = function(xx,xx,xxx,xxx) {
//Man initialization
}
And I want Man extends from Person.
The following is what I thought:
Given a created Man object:
var m=new Man("xx",....);
1) when a property of m is accessed,it will search it in Man.prototype.
2) If not find, It should find it in Man.prototype.__prop__.
So what I have do is make the Man.prototype.__prop__ linked to Person.prototype.
I know this is the common way:
function inherit(superClass) {
function F() {}
F.prototype = superClass.prototype;
return new F;
}
Man.prototype=inherit(Person);
But when I try this:
Man.prototype.prototype=Person.prototype.
Why it does not work?
It sounds like you actually want to link instances of Man to an instance of Person that retains any properties added in its constructor, in which case you might really want something like this:
function Person(a, b) {
this.a = a;
this.b = b;
}
function Man() {}
Man.prototype = new Person("val1", "val2");
var m = new Man();
console.log(m.a);
...which prints val1.
Additional Ramblings
The purpose of inherit is to create an object from a function whose prototype is that of the given super class (without explicitly using new), which is exactly what it does. Therefore, the following prints string:
function Person() {}
Person.prototype.test = "string";
function Man() {}
function inherit(superClass) {
function F() {}
F.prototype = superClass.prototype;
return new F;
}
var t = inherit(Person);
console.log(t.test);
But you generally want to assign the returned object to another function's prototype:
Man.prototype = inherit(Person);
var m = new Man();
console.log(m.test);
...so that m.test also prints string, which means that objects created using Man are linked to Person's prototype).
Note that Man.prototype.prototype is undefined and -- this is the important part -- also meaningless. Functions have prototypes. Other objects (such as Man.prototype) do not. The prototype property is not magical in any other context. Assigning a value to a random object's prototype property doesn't do anything special. It's just another property.
Note also that the thing we returned from inherit is linked to Person by way of its prototype and has no access to any properties added to instances of Person.
How I do it (in regards to your example):
var Person = function () {
}
// Define "Person" methods
var Man = function () {
}
Man.prototype = new Person();
// Define "Man" methods
UPDATE
Regarding constructors with parameters: just found this SO question that can really help you figure it out (second answer, first part): JavaScript inheritance: when constructor has arguments.
There are quite a few generic methods to do that. I will provide three of them:
1.) Using Function object as a constructor and as a prototype object for inherited new objects. The implementation should look like as the following:
var person = {
toString : function() {
return this.firstName + ' ' + this.lastName;
}
}
function extend(constructor, obj) {
var newObj = Object.create(constructor);
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
newObj[prop] = obj[prop];
}
}
return newObj;
}
var man = extend(person,
{
sex: "male",
age: "22"
});
var name = extend(man,
{
firstName: "Simo",
lastName: "Endre"
});
name.man;
name.toString();
2.) In this case we'll use the Function object as the constructor for simulating the classical inheritance in a language like C# or Java. The prototype property of an object will be used in the role of a constructor and the the newly created object will inherit all the properties from the object prototype root. In this case the object's prototype has only one kind of augmentation role, the effective implementation is done in the function method.
var Person = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.toString = function() {
return this.firstName + ' ' + this.lastName;
}
function inherit(func) {
// passing function arguments into an array except the first one which is the function object itself
var args = Array.prototype.slice.call(arguments, 1);
// invoke the constructor passing the new Object and the rest of the arguments
var obj = Object.create(func.prototype);
func.apply(obj, args);
//return the new object
return obj;
}
var man = inherit(Person, "Simo", "Endre");
man.toString();
3.) The well known inheritance model:
function extend(o) {
function F() {}
// We'll set the newly created function prototype property to the object.
//This act as a constructor.
F.prototype = o;
// Using the `new` operator we'll get a new object whose prototype is o.
return new F();
};

Categories

Resources