New, Apply, Call, Bind in JavaScript
In JavaScript, apply, call, bind are crucial concepts for development, which all relate closely with this pointer.
I’m gonna start with a few questions:
- What does
newactually do? - Difference among
apply,callandbind? - How to implement an
applyorcall?
Well, let’s get started!
New
The main function of new is to execute constructor functions and return a new instance.
Let’s check out a demo:
1 | function Person(){ |
Easy enough, we call new on constructor Person and get a new instance of Person.
Let’s break down what new had done during the above process:
- Creates a new object
- Assign the scope of the constructor to the new object (or say
thisbinding) - Execute the constructor function
- return the new instance
What happen if we don’t use new for the same process? Let’s try.
1 | function Person(){ |
See? We don’t get a new object back p. Instead, the this during the execution points to the global window object by default, which allows us to call name without explicitly declaring it.
One step further, if the constructor returns a object, how would things change with new?
1 | function Person(){ |
Obviously, new doesn’t create a new object. It returns the object straightly.
But, if the constructor returns non-object value, new works as usual.
1 | function Person(){ |
Therefore, we can conclude that after new we always receive a object, either new instance or object that returned by the constructor.
Apply & Call & Bind
apply, call, bind are three methods of function. Let’s take a look at a demo:
1 | func.call(thisArg, param1, param2, ...) |
The common usage of these three is to change the this of the function, i.e. the execution subject. thisArg refers to the this object you want to call on.
Difference for the second param among them:
applyreceives an param arraycallandbindbypasses param from position 2 to Nbindwould not execute the function immediately, it would return a new function with a changedthis.
What are all these for? Reusage! Say, we don’t have to buy a house for living if we can rent one. Same here, we borrows functions from existing objects, saving spaces and efforts.
Let’s take a deeper look for the usage and everything should be clear:
1 | let a = { |
Classic scenarios
Let’s see what we can do with these three BORROW ablities.
Type Checking
Remember how we use Object.prototype.toString for checking variable types. There it is.
1 | function getType(obj){ |
Array-Like Value
We can have an array-like value if we define our object as:
1 | var arrayLike = { |
But sure it has no array methods. No worry, we can borrow from real Array!
1 | Array.prototype.push.call(arrayLike, 'jack', 'lily'); |
We just pushed a new value into the array-like object by calling Array’s push! Isn’t that magical?
Get max/min of an array
Check this out: we can pass an array and get its max/min value by using Math.max/Math.min:
1 | let arr = [13, 6, 10, 11, 16]; |
Inheritance
Back in the previous article 6 Ways of Inheritance in JavaScript, we use Parent.call(this) inside a child constructor for inheriting the properties from parents.
Can we implement then on our own?
Try new
Let’s do a quick recap about what does new do during execution:
- Allows instances to visit private properties
- Allows instances to visit the properties on constructor’s prototype chain. (
constructor.prototype) - Return a reference type data (either new instance or result of constructor)
Here is our version:
1 | function _new(ctor, ...args) { |
Try apply and call
The principle of apply and call is similar, let’s implement them together!
1 | Function.prototype.call = function (context, ...args) { |
The key is to use eval to execute the function itself in a different context (or say on a different object).
Try bind
The basic principle of bind is also similar, but bind doesn’t execute immediately, so we don’t need eval anymore.
1 | Function.prototypeFunction.prototype.bind = function (context, ...args) { |
The key here is to return a function with a changed context. Also we can’t lose the prototype in the new function.
Sumamry
Let’s do a summary for the three methods:
| Method | call | apply | Bind |
|---|---|---|---|
| params | multiple | one array | multiple |
| function | change this for a function |
change this for a function |
change this for a function |
| result | immediate execution | immediate execution | return a function |
| implementation | call eval |
call eval |
indirectly call apply |