This is a topic that I like to give anyone interviewing for a JS position at my company. It's a bit of a brain-twister, and unless you really understand how prototypal inheritance works in JS, there's a pretty good chance you'll get it wrong.
What's the difference between:
1. var objB = Object.create(objA);
and
2. var objB = new objA();
When we write #1, objB's internal [[proto]] property points to the object that is objA. That means that when we execute something like:
var objA = {
a:42;
}
var objB = Object.create(objA); //objB.__proto__ === objA
console.log(objB.a);
However, when we have the following scenario, invoking a function as a constructor:
function objA(){
this.a = 42;
}
objA.prototype.b = 43;
var objB = new objA(); //objB.__proto__ === objA.prototype
console.log(objB.a); //42
console.log(objB.b); //43
console.log(objB.__proto__); //objA.prototype
So we see that when when use the new keyword with a function, the object that is created (objB) has it's internal [[proto]] pointing to the function's prototype property (objA.prototype).
A blog about Javascript. For topics on security and hacking, please see my security blog at http://guerresanslarmes.blogspot.com/
Showing posts with label prototype. Show all posts
Showing posts with label prototype. Show all posts
Saturday, June 4, 2016
Thursday, March 26, 2015
Polyfilling Object.create in pre-ES5 Environments
As you might be aware, there are two primary ways of creating a [[prototype]] link between two objects in Javascript:
Using Object.create()
var obj1 = {
a:2
};
var obj2 = Object.create(obj1);
console.log(obj2.a); //2
Using a function as a constructor
function Obj1(){
this.a = 2;
}
var obj2 = new Obj1();
console.log(obj2.a); //2
In both cases, obj2.a will return a value of 2, although in the first case the property 'a' actually lives on obj1 and is found through [[prototype]] delegation, whereas in the second, "constructed" case, the property 'a' actually lives on obj2.
Generally speaking, it is somewhat cleaner to use Object.create() to link an object to another as opposed to making a function call as a construction (imagine if Obj1() had some sort of side effects in addition to just returning an object). However, in some older environments it is necessary to create a partial polyfill of Object.create(), which can be accomplished very easily with the following code snippet:
if( !Object.create ){
Object.create = function(o){
function F(){};
F.prototype = o;
return new F();
};
}
In line one we check to see if the function already exists, if not, we begin defining it in line two by creating the 'create' property on Object and assigning it a function that takes an object as its argument. in line three, we create a throw-away function called F, and set its prototype object to the parameter 'o'. We then return a new instance of F(), which will be linked to 'o', since that is what we reassigned F's prototype object to reference.
Pretty simple polyfill hack. Some developers argue that this isn't a best practice since we haven't technically completely polyfilled Object.create. Object.create an also take an option object of arguments that will be assigned to the object that it creates, such as:
var obj2 = Object.create(obj1, { b:{},c:{} });
In this case, we have to define each of these properties by hand, such as setting b's enumerable, writable, configurable descriptors, etc. This is not supported in pre ES5 browsers, but this form is very rarely used, so most developers are okay with the partial polyfill, but if it bothers you, it's okay to simply create a different function that handles the partial polyfill, such as:
function object_create_link(o){
function F(){};
F.prototype = o;
return new F();
}
var obj1 = {
a:2
};
var obj2 = object_create_link(obj1);
obj2.a; //2
That's a wrap. I like this example because it provides a nice discussion of how Object.create() and functions as constructors differ in creating an object.
Thanks for reading!
-nate
Subscribe to:
Posts (Atom)