Skip to main content

Javascript’s "new" Keyword Explained as Simply as Possible

Javascript’s “new” Keyword Explained as Simply as Possible

Normal Function Call

To explain what new does, let’s start with just a normal function, called without new. We want to write a function that will create “person” objects. It’ll give these objects name and age properties based on parameters that it takes in.

function personFn(name, age) {
var personObj = {};
personObj.name = name;
personObj.age = age;

return personObj;
}
var alex = personFn('Alex', 30);
// -> { name: 'Alex', age: 30 }

Simple enough. We create an object, add the properties to it, and return it at the end.

new

Let’s create a function that does the same thing, but we want it to be invoked using new. This function will create the same object as the one above. Common practice is to make functions that are meant to be invoked with new start with a capital letter. These functions are also referred to as constructors.

function PersonConstructor(name, age) {
this.name = name;
this.age = age;
}
var alex = new PersonConstructor('Alex', 30);
// -> { name: 'Alex', age: 30 }

Invoking personFn normally and invoking PersonConstructor with new both result in the same object being created. What’s going on?

The new keyword invokes a function in a special way. It adds some implicit code that we don’t see. Let’s expand the above function to show everything that’s happening. The commented lines are pseudocode representing functionality that is implicitly added by the JS engine when using new.

function PersonConstructor(name, age) {
// this = {};
// this.__proto__ = PersonConstructor.prototype;
// Set up logic such that: if
// there is a return statement
// in the function body that
// returns anything EXCEPT an
// object, array, or function:
// return 'this' (the newly
// constructed object)
// instead of that item at
// the return statement;
this.name = name;
this.age = age;
// return this;
}

Let’s break it down. new:

  1. Creates a new object and binds it to the this keyword.
  2. Sets the object’s internal [[Prototype]] property, __proto__, to be the prototype of the constructing function. This also makes it so the constructor of the new object is prototypically inherited.
  3. Sets up logic such that if a variable of any type other than objectarray, or function is returned in the function body, return this, the newly constructed object, instead of what the function says to return.
  4. At the end of the function, returns this if there is no return statement in the function body.

Let’s show that these statements are valid, one by one.

function Demo() {
console.log(this);
this.value = 5;
return 10;
}
/*1*/ var demo = new Demo(); // -> {}
/*2*/ console.log(demo.__proto__ === Demo.prototype); // -> true
console.log(demo.constructor === Demo); // -> true
/*3*/ console.log(demo); // -> { value: 5 }
function SecondDemo() {
this.val = '2nd demo';
}
/*4*/ console.log(new SecondDemo()); // -> { val: '2nd demo' }

If you aren’t familiar with constructors or prototypes, don’t worry about it too much. You’ll run into them as you continue to learn Javascript. For now, just understand that the new object implicitly returned by the constructor function will be able to inherit properties and methods.

Calling a non-constructor with new

What happens if we invoke a normal function like personFn using new? Nothing special. The same rules apply. in the case of personFn, we see nothing explicitly happening.

var alex = new personFn('Alex', 30);
// -> { name: 'Alex', age: 30 }

Why? Let’s add our implicit code in to personFn.

function personFn(name, age) {
// this = {};
// this.constructor = PersonConstructor;
// this.__proto__ = PersonConstructor.prototype;
// Set up logic such that: if
// there is a return statement
// in the function body that
// returns anything EXCEPT an
// object, array, or function:
// return this (the newly
// constructed object)
// instead of that item at
// the return statement;
var personObj = {}; personObj.name = name;
personObj.age = age;

return personObj;

// return this;
}

The implicit code is still added in:

  • It binds this to a new object and sets its constructor and prototype.
  • It adds logic that will return this instead of a non-object.
  • It adds an implicit return this statement at the end.

This doesn’t affect our code, since we don’t use the this keyword in our code. We also explicitly return an object, personObj, so the returning logic and the return this line have no use. Effectively, using new to invoke our function here has no effect on the output. If we were using this or if we weren’t returning an object, the function would have different effects when invoked with and without new.

Comments

Popular Posts

Reloading UITableView while Animating Scroll in iOS 11

Reloading UITableView while Animating Scroll Calling  reloadData  on  UITableView  may not be the most efficient way to update your cells, but sometimes it’s easier to ensure the data you are storing is in sync with what your  UITableView  is showing. In iOS 10  reloadData  could be called at any time and it would not affect the scrolling UI of  UITableView . However, in iOS 11 calling  reloadData  while your  UITableView  is animating scrolling causes the  UITableView  to stop its scroll animation and not complete. We noticed this is only true for scroll animations triggered via one of the  UITableView  methods (such as  scrollToRow(at:at:animated:) ) and not for scroll animations caused by user interaction. This can be an issue when server responses trigger a  reloadData  call since they can happen at any moment, possibly when scroll animation is occurring. Example of s...

What are the Alternatives of device UDID in iOS? - iOS7 / iOS 6 / iOS 5 – Get Device Unique Identifier UDID

Get Device Unique Identifier UDID Following code will help you to get the unique-device-identifier known as UDID. No matter what iOS user is using, you can get the UDID of the current iOS device by following code. - ( NSString *)UDID { NSString *uuidString = nil ; // get os version NSUInteger currentOSVersion = [[[[[UIDevice currentDevice ] systemVersion ] componentsSeparatedByString: @" . " ] objectAtIndex: 0 ] integerValue ]; if (currentOSVersion <= 5 ) { if ([[ NSUserDefaults standardUserDefaults ] valueForKey: @" udid " ]) { uuidString = [[ NSUserDefaults standardDefaults ] valueForKey: @" udid " ]; } else { CFUUIDRef uuidRef = CFUUIDCreate ( kCFAllocatorDefault ); uuidString = ( NSString *) CFBridgingRelease ( CFUUIDCreateString ( NULL ,uuidRef)); CFRelease (uuidRef); [[ NSUserDefaults standardUserDefaults ] setObject: uuidString ForKey: @" udid " ]; [[ NSUserDefaults standardUserDefaults ] synchro...

Xcode & Instruments: Measuring Launch time, CPU Usage, Memory Leaks, Energy Impact and Frame Rate

When you’re developing applications for modern mobile devices, it’s vital that you consider the performance footprint that it has on older devices and in less than ideal network conditions. Fortunately Apple provides several powerful tools that enable Engineers to measure, investigate and understand the different performance characteristics of an application running on an iOS device. Recently I spent some time with these tools working to better understand the performance characteristics of an eCommerce application and finding ways that we can optimise the experience for our users. We realised that applications that are increasingly performance intensive, consume excessive amounts of memory, drain battery life and feel uncomfortably slow are less likely to retain users. With the release of iOS 12.0 it’s easier than ever for users to find applications that are consuming the most of their device’s finite amount of resources. Users can now make informed decisions abou...