JavaScript: ways of constructing a new instance - javascript

According to this MSDN article - scroll to Constructor Functions but No Classes, (and after reading the MDN JS reference) I should be able to construct an object like this:
function Dog(name){
this.name = name;
}
// EXAMPLE 1
var dog = new Dog("Spot");
console.log("Dog using new:");
console.log(dog); // Dog object, awesome!
// EXAMPLE 2
var dog = {};
dog = Dog.call(dog,"Rowdie");
console.log("Dog using call:");
console.log(dog); // Undefined.. why?
However, while the first example (most common way of constructing a new object) returns the expected instance, the second example returns undefined - am I doing something wrong?
Here is the JSFiddle I used to test this: http://jsfiddle.net/wk8JD/1/

Change
dog = Dog.call(dog,"Rowdie");
to
Dog.call(dog,"Rowdie");
When you call a function with new, then this is implicitly returned, i.e. the function behaves as if you had return this; at the end. From the MDN documentation:
The object returned by the constructor function becomes the result of the whole new expression. If the constructor function doesn't explicitly return an object, the object created in step 1 is used instead. (Normally constructors don't return a value, but they can choose to do so if they want to override the normal object creation process.)
But if you call a function "normally" (i.e. without new), it will return undefined if there is no return statement.
(In the article they are not assigning the return value either btw)

Related

Javascript instanceof operator confusion

I've read about Javascript's instanceof operator and wanted to test it out. I've written this code:
function first() {};
first.prototype.hello = function hello() {
console.log("hello");
}
var second = {};
second.prototype = Object.create(first.prototype);
console.log(second instanceof first); //should've output true
second.hello();
This doesn't work as expected (by me). What I thought when writing this fragment:
instanceof takes a function (first in this case) as its right hand operand and an object as its left hand operand. Then it checks whether the given function's prototype appears in any part of the object's prototype chain. first is the function, hello is some function added to first's prototype. second's prototype is assigned a new object which has a prototype link to first.prototype so when second instanceof first is executed, it cannot find link to first.prototype object on second directly so it follows prototype link to second.prototype which has that link.
When I run this in Chrome this is the result:
false
Uncaught TypeError: second.hello is not a function
at main.js:13
Could you please help me out with this?
second's prototype is assigned a new object
No, this part is wrong. You're creating a property called "prototype", but that doesn't mean it is the object's actual prototype.
var second = {};
second.prototype = ...
is equivalent to
var second = { "prototype": ... };
but it's unrelated to inheritance.
Pretty much the only spot where a property called "prototype" is used is on constructor functions (such as your first), and even then it's not used as the prototype of the function itself; it's used as the prototype for any instances created later on from new ThatFunction().
What you can do is
var second = new first;
// What this does:
// - gets the object from first.prototype
// - creates a new derived object, like Object.create(first.prototype)
// - calls first(), passing the new object as 'this',
// like first.call(Object.create(first.prototype))
// - assigns the object returned from first() to second
// (if first doesn't return an object, it automatically uses the new object created in step 2 instead)
or (mostly equivalent, but won't call first)
var second = Object.create(first.prototype);
Instead of second.prototype, use second
I've edited your code.
function first() {};
first.prototype.hello = function hello() {
console.log("hello");
}
var second = Object.create(first.prototype);
console.log(second instanceof first); //should've output true
second.hello();
Object.create () returns the created object which you need to store in second variable, not in second.prototype. It does not return an Object prototype, but the entire Object itself.
var second = {}
second = Object.create (first.prototype)

un expexted behaviour of javascript constructor when called without new keyword

I created a class using function like -
function Person(name) {
this.name = name;
}
var obj = new Person("Ferdinand");
console.log(obj.name);
I am creating an object obj and prints its property name it is working fine and prints "Ferdinand", but if we forget to write new key word like below program -
function Person(name) {
this.name = name;
}
var obj = Person("Ferdinand");
console.log(name);
Here I am not able to understand why name is available in console, it is printing "Ferdinand". But we are using Person as a function and assigning name variable in function itself so why its value is available outside function.
JavaScript does not implement objects in the classical sense. Instead, they are implemented directly:
var thing={}; // new object
Because you typically want multiple objects to follow a common pattern and behaviour, you can use what is called a constructor function to help. In your example, Person is a constructor function.
When using a constructor, you call it indirectly using the new command:
var thing = new Person(…);
In fact, there’s a lot of magic going on here:
JavaScript begins by creating a new object: var thing={};.
Then the this key word is assigned to the new object
Finally the constructor is run, using the this value to assign local values.
If you call a constructor function directly, the first 2 steps do not apply, and the function is left trying to work in its own definition of this which is generally not what you want.
If you really want to call the constructor function without bothering with new, you can try the following:
function Person(data) {
// “new” safe constructor
if(!(this instanceof Person)) {
return new Person(data);
}
This new version checks whether it is being called as a proper constructor, and, if not, calls itself properly.

Why constructor return object with the same name as itself

While creating a new object, why does constructor not return object with the name of the newly created object
In the following, the output is cons{x: "hi"} object, why not myobj {x: "hi"}?
function cons() {
this.x = "hi";
return null;
}
var myobj = new cons();
console.log(myobj);
This article, says that "It returns the newly created object,unless the constructor function returns a non-null object reference." So it should return myobj{x: "hi"} since the above constructor is returning null.
In the following, the output is cons{x: "hi"} object, why not myobj {x: "hi"}?
What you see will vary depending on which console implementation you're using, but some (like Chrome's) will indeed show you that.
The cons there is to tell you what type of object it is,1 not what variable the object's reference is stored in. It's just so you can readily distinguish between the different types of objects in your code when looking at the dev tools.
As for why: Remember that console.log has no idea where the value it got came from; it doesn't know the value came from a variable called myobj. When you do console.log(myobj), the value of myobj is read, and then that value is passed into console.log. So it couldn't print the variable name even if the designers of it wanted it to.
If you want to see the variable name as well, put it in the console.log call:
console.log("myobj", myobj);
Example:
function cons() {
this.x = "hi";
return null;
}
var myobj = new cons();
console.log("myobj", myobj);
This article, says that "It returns the newly created object,unless the constructor function returns a non-null object reference." So it should return myobj{x: "hi"} since the above constructor is returning null.
You're quite understandably confusing two unrelated things. The result of calling a constructor function with new, and the output of passing an object reference into console.log.
In your code, var myobj = new cons(); does indeed result in the new object created by new being stored in myobj (the return null; has no effect on it). What that quote is trying to say is that something like this wouldn't:
function cons() {
this.x = "hi";
return {hey: "I'm a completely different object"};
}
var myobj = new cons();
console.log(myobj);
In that code, cons has overridden the default behavior of new by returning a non-null object reference to something other than this. So the result of new cons is a reference to that other object, not the one new created. It's not something constructors usually need to do, but sometimes (for instance) you want something that looks like a constructor to actually provide a previous instance instead of the new object.
1 Loosely speaking; objects don't really have type in JavaScript, just a prototypical inheritance lineage.
Objects have no name in general. What you are seeing is an implementation-dependent stringification of the object. Firefox console would show
Object { x: "hi" }
Chrome presumably shows the name of the constructor of that object. Functions do have a name.

Javascript scope/this

How come when I do:
function Dog(){
this.firstName = 'scrappy';
}
Dog.firstName is undefined?
However then I can do:
Dog.firstName = 'scrappy';
And now Dog.firstName returns 'scrappy'?
How come when I do ... Dog.firstName is undefined?
Because...
... Dog is never called, so the line this.firstName = 'scrappy'; is never executed and ...
... even if you call the function, this probably won't refer to the function Dog. You can call it in a way that this refers to Dog, but that is rather unusual . How the value of this is determined has been explained extensively.
However then I can do ... And now Dog.firstName returns 'scrappy'?
Functions are just objects, so you can assign any property to it.
The Dog() function is just the constructor, so you're calling firstname on the constructor rather than an instance of it. This isn't defined just by virtue of it being defined on the returned objects, they're totally separate things. However, because you can augment functions with fields, you were able to assign a value to dog.firstName anyway.
First, let me demonstrate the difference between a constructor and an instance:
function Dog() {
this.firstName = 'scrappy';
}
Dog.firstname; // undefined on the constructor
Dog.prototype; // defined on constructor, returns an empty object
var myDog = new Dog();
myDog.firstname; // defined on instance, returns 'scrappy'
myDog.prototype; // undefined on instance
As you can see, a constructor (a function that returns an object) is a totally different thing to the object it returns, and has totally different fields as a result. What you were seeing when you got Dog.firstname to return 'scrappy' was the result of adding a new field to the constructor. This is doable, but remember, adding a field to the constructor will not add the same field to the constructed. Consider:
Dog.someNewProperty = 'whatever';
var myDog = new Dog();
Dog.someNewProperty; // 'whatever'
myDog.someNewProperty; // undefined

javascript subclassing not working as expected when returning methods in constructor function

I'm not understanding why in the following code, obj.BaseMethod doesn't return the method defined in BaseClass constructor. In other words, why is it that
SubClass.prototype.BaseMethod
is defined, but
new SubClass().prototype.BaseMethod
is undefined.
http://jsfiddle.net/HvxJ4/4/
I'm obviously missing something important here.
function BaseClass() {
var privatestuff = "blah";
return {
BaseMethod: function() {
console.log('BaseMethod called');
}
}
}
function SubClass() {
var moreprivates = "stuff";
return {
SubClassMethod: function() {
console.log('SubClassMethod called');
}
}
}
SubClass.prototype = new BaseClass();
var obj = new SubClass();
obj.SubClassMethod(); // SubClassMethod called
obj.BaseMethod(); // Uncaught TypeError: undefined is not a function
UPDATE
I actually understood how to get my code working using
this.method = function() { }
in my constructor function. I just didn't understand why the code above didn't do the same thing.
The answer is that if you return an object in a constructor function, you are no longer using "protoypal" inheritance.
The thing that makes this most clear to me was this answer
https://stackoverflow.com/a/2118831/834770
Quoting Douglas Crockford in Chapter 5, Inheritance, of JavaScript:
(...)
Douglas Crockford then explains how the new operator could be
implemented as a JavaScript function. This function makes use of
several other functions defined in the book, so I rewrote it in a
(somewhat) simpler form below:
function createNew(constructor) {
// a function to explain the new operator:
// var object = createNew(constructor);
// is equivalent to
// var object = new constructor();
//
// param: constructor, a function
// return: a new instance of the "constructor" kind of objects
// step 1. create a new empty object instance
// linked to the prototype of provided constructor
var hiddenLink = function(){};
hiddenLink.prototype = constructor.prototype;
var instance = new hiddenLink(); // cheap trick here: using new to implement new
// step 2. apply the constructor the new instance and get the result
var result = constructor.apply(instance); // make this a reference to instance within constructor
// step 3. check the result, and choose whether to return it or the created instance
if (typeof result === 'object') {
return object;
} else {
return instance;
}
}
So, in short, if you return an object in this function, then the inheritance bit is effectively ignored.
Here's a way to think of the statement
new SubClass().prototype.BaseMethod
First, the new keyword tells JavaScript to create a new, empty object, i.e. {}
Then JavaScript sets the context (this) to be equal to that new object and calls the function after new. So in this case JavaScript will look for a function to call, but your syntax doesn't reference a defined function, so the result is undefined.
Contrast that with a typical approach for defining objects in JavaScript:
function ExampleObject() {
// stuff related to the example object
this.exampleProperty = "value";
}
var exObj = new ExampleOject();
In this case new creates the empty object {} as before, but now there is a defined function to call. When this function is called, the newly created object (set equal to this) will have an exampleProperty set equal to "value". The resulting object is then assigned to the variable exObj.
It may sound strange to those coming from a Java background (or similar), but JavaScript doesn't really support the concept of classes. The language made the unfortunate choice of trying to make it's prototypical inheritance look like classical inheritance, but it's really not the same. If you're going to be spending a lot of time in JavaScript, you might want to stop trying to think in terms of classes and subclasses and learn a bit about prototypes instead.

Categories