yuan
yuan

Reputation: 2534

How does the "new" keyword work as described in ECMAScript 5 standard

I want to know how the new operator work and not just learn how to use it.I looked in the ECMAScript 5 standard and find the algorithm describe how it work but am a little confused about the meanning of it.

The production NewExpression : new NewExpressionis evaluated as follows:

  1. Let ref be the result of evaluating NewExpression.
  2. Let constructor be GetValue(ref).
  3. If Type(constructor) is not Object, throw a TypeError exception.
  4. If constructor does not implement the [[Construct]] internal method, throw a TypeError exception.
  5. Return the result of calling the [[Construct]] internal method on constructor, providing no arguments (that is, an empty list of arguments).

I try to understand the algorithm above using this example:

var f = function() {};    
var h = new f();

Particularly I don't understand the first step and therefore cannot follow the other steps.

  1. Let ref be the result of evaluating NewExpression.
var h = new f();
        ~~~ ~~~~
         |    \_________ NewExpression 
     new operator

Does that mean ref is the value of f()? But It's undefined.

3 . If Type(constructor) is not Object, throw a TypeError exception.

But the type of f is function, will it throw a TypeError exception?

5 . Return the result of calling the [[Construct]] internal method on constructor, providing no arguments (that is, an empty list of arguments).

[[Construct]] internal property of function, What's the meaning of calling it on constructor?

Upvotes: 1

Views: 372

Answers (2)

Felix Kling
Felix Kling

Reputation: 816442

First we have to clarify what new NewExpression and especially NewExpression are. This can be found in Annex A. The most common situation where this rule applies is when you don't pass arguments to the constructor. I.e.

var obj = new F;

where F refers to a function. So this is the rule that lets you omit the parenthesis.

In your example (var h = new f();), you have parenthesis though, i.e. you are passing an empty list of arguments, so this algorithm does not apply. f() is not NewExpression.

Instead this algorithm applies: new MemberExpression Arguments. It is evaluated in pretty much the same way and the algorithm can found in §11.2.2 as well, just after the algorithm you quoted.

With this in mind, lets go through that algorithm step by step:

1. Let ref be the result of evaluating MemberExpression.

In your example, MemberExpression, is f, i.e. it is a variable. The result of the evaluation is a special Reference object. It's not important here what exactly it is. Just know that it holds information about how to actually get the value from the variable.
So now ref refers to that reference.

2. Let constructor be GetValue(ref).

This is were the value of the variable is actually retrieved and constructor will refer to the function that f refers to.

3. Let argList be the result of evaluating Arguments, producing an internal list of argument values (11.2.4).

In your case, Arguments is () and therefore it is an empty list.

4. If Type(constructor) is not Object, throw a TypeError exception.

It is important to know that functions are objects too! So this step will throw the error if primitive values are being used in the new expression.

5. If constructor does not implement the [[Construct]] internal method, throw a TypeError exception.

All functions (and potentially other objects) implement an internal [[Construct]] property which does the actual instantiation of the new object. If the object does not have such a property, it cannot be used as constructor. How it works for functions is defined in §13.2.2.

6. Return the result of calling the [[Construct]] internal method on constructor, providing the list argList as the argument values.

This is were the actual construction happens. [[Construct]] is itself function and is defined in §13.2.2. The method is the same of every function and is responsible for creating a new object, call the function on that new object and return it or whatever the function returns.

Here is an example of what it would look in JavaScript (partly pseudo-code):

[[Construct]] = function(F, argList) {
    // Create new object that in inherits from F.prototype or Object.prototype
    var proto = F.prototype;
    var obj = Object.create(typeof proto === 'object' ? proto : Object.prototype);

    // Call F with this set to obj and pass the argument list
    var result = F.apply(obj, argList);

    // If result is not an object, return the generated object
    return typeof result === 'object' ? result : obj;
};

Upvotes: 3

user123444555621
user123444555621

Reputation: 152986

Let's go through this step by step

  1. Resolve things like new window['foo' + 1 + 'bar'] -> new window.foo1bar
  2. determine what object is actually referenced: What is window? Local variable or property of the global object?
  3. This is obvious.
  4. Not so obvious, but the point is: every Function is a constructor, but not every constructor is a Function. This point makes sure that new is only called on constructors.
  5. Run the constructor. Note that the spec also provides MemberExpression : new MemberExpression Arguments for the case new foo(...)

Upvotes: 2

Related Questions