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 Javascript. Show all posts
Showing posts with label Javascript. Show all posts
Saturday, June 4, 2016
Talking DOMball...
Hello all you baseball fans and JS wahoos, it's time for another season of baseball!!
It's also time for us to discuss the differences between two similar sounding words in Javascript, document, and window.
window is the global object in Javascript. It holds everything, like global variables, global functions, history, location, etc. Global functions, such as setTimeout and console, live on the window as well. Even document lives on the window.
console.log(window.setTimeout === setTimeout); // true
console.log(window.document === document); //true
window can also be thought of as the default scope or this keybinding in browser-based JS (environments like nodejs do not have a window object).
var x = 5; //x in global/window scope
console.log(this.x === window.x); //true
console.log(this === window); //true
document is the DOM. The DOM is a tree of nodes (html tags, like h1, div, span, etc), and may be thought of as an object-oriented representation of the HTML that makes up the page. For an example of what this tree looks like, check out this site:
https://gojs.net/latest/samples/DOMTree.html
document is immensely useful because it allows us to query and manipulate the DOM using Javascript. For example, to grab all h1 elements in the DOM, we would write:
var headers = document.getElementsByTagName('h1');
Check back later, when we'll continue our exploration of window and document.
It's also time for us to discuss the differences between two similar sounding words in Javascript, document, and window.
window is the global object in Javascript. It holds everything, like global variables, global functions, history, location, etc. Global functions, such as setTimeout and console, live on the window as well. Even document lives on the window.
console.log(window.setTimeout === setTimeout); // true
console.log(window.document === document); //true
window can also be thought of as the default scope or this keybinding in browser-based JS (environments like nodejs do not have a window object).
var x = 5; //x in global/window scope
console.log(this.x === window.x); //true
console.log(this === window); //true
document is the DOM. The DOM is a tree of nodes (html tags, like h1, div, span, etc), and may be thought of as an object-oriented representation of the HTML that makes up the page. For an example of what this tree looks like, check out this site:
https://gojs.net/latest/samples/DOMTree.html
document is immensely useful because it allows us to query and manipulate the DOM using Javascript. For example, to grab all h1 elements in the DOM, we would write:
var headers = document.getElementsByTagName('h1');
Check back later, when we'll continue our exploration of window and document.
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
Monday, November 3, 2014
A Taste of Java...script. Hoisting
Javascript has been getting some popularity lately, and it's not really a secret. I've posted some links to my Twitter feed of recent articles that I've read detailing node.js and using Javascript for full-stack dev. I'll post them here as well:
http://www.toptal.com/nodejs/why-the-hell-would-i-use-node-js
http://www.toptal.com/javascript/guide-to-full-stack-javascript-initjs
Interesting stuff. This just means that now - more than ever - we as software engineers need to know how Javascript works, and we need to know it well if we want to use it for full-stack development.
The strange thing about Javascript is that it's well...strange. Devs coming from a background in C++ or Java, or even Python will be surprised at some of the things Javascript takes for granted, like hoisting...
This should break, right?
Example 1:
console.log(square(2));
function square(x){
return x*x;
}
but it doesn't. It produces 4 just like if you had written:
function square(x){
return x*x;
}
console.log(square(2));
hmm....okay. So this works too then?
Example 2:
console.log(square(2));
var square = function(x){
return x*x;
}
well...no, not at all. Example 1 runs perfectly, example 2 will generate an undefined reference error. So, what exactly is going on here?
In Javascript, there is something called variable hoisting, which applies to variables and functions, and basically moves them to the top of their enclosing scope (remember, in Javascript, functions define scope, not braces). This is because the Javascript compiler runs through the program first, allocates variables and references, and then the execution engine runs through and actually runs stuff. So in example 1, the compiler sees the function declaration, handles it, and then when the execution engine runs, it calls console.log(...) and finds the reference to the square function no problem.
Cool, so why does example 2 fail?
Well, to answer that, here's example 3:
console.log(x);
var x = 3;
Works, right? Nah, it's an undefined reference error too.
The deal is that variable declarations are hoisted, but assignments are not, so in example 3, the compiler more or less produces:
var x;
console.log(x);
x = 3;
So it's obvious why it's an undefined reference. It's basically the same for example 2. The Javascript compiler will generate the following code for the execution engine:
var square;
console.log(square(2));
square = function(x){
return x*x;
}
So, hoisting can come in handy in many situations, but be wary of the fact that it can catch you off guard sometimes.
Subscribe to:
Posts (Atom)