new 操作符

【初级】考查 new 操作符,输出结果

function Foo() {
  this.a = 1;
  return {
    a: 4,
    b: 5,
  };
}

Foo.prototype.a = 6;
Foo.prototype.b = 7;
Foo.prototype.c = 8;

var o = new Foo();

console.log(o.a);
console.log(o.b);
console.log(o.c);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

参考答案:

4
5
undefined
1
2
3

追问:

  • 去掉return后,输出结果是?

    • 1 7 8
  • new的过程是怎样的?this指向谁?

    • 创建一个新对象
    • 新对象的__proto__指向fn.prototype
    • 将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
    • 执行构造函数中的代码(为这个新对象添加属性)
    • 返回新对象(如果fn执行后不返回,则默认返回新对象;如果返回了其他对象,则返回值为其他对象)
  • B-能说出new操作符的大概作用

  • A-能比较准备描述new操作符整个工作流程

  • S-能自己实现一个new

【中级】模拟new的实现

(不需要兼容class,因为class在 ECMA 规范中未实现[[Call]]

参考答案:风动之石的博客 - new 操作符open in new window

function newOperator(Constructor){
    if(typeof Constructor !== 'function'){
      throw 'newOperator function the first param must be a function';
    }

    // 使用 new 操作符时,构造函数内的 new.target 会指向操作函数。
    // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new.target
    // 下面这一行其实没啥必要,因为用 newOperator 函数去模拟 new 操作符时,构造函数内部也不会使用 newOperator.target 去替换 new.target
    // newOperator.target = Constructor;


    // 1、创建新对象,修改 __proto__ 指向
    var newObj = {};
    newObj.__proto__ = Constructor.prototype;

    // 2、在新对象上调用 Constructor 函数,绑定 this 为新对象
    var args = [].slice.call(arguments, 1);
    var result = Constructor.apply(newObj, args);

    // 3、判断是返回 Constructor 的执行结果,还是返回新对象
    var isObject = typeof result === 'object' && result !== null;
    var isFunction = typeof result === 'function';
    if(isObject || isFunction){
        return result;
    }

    return newObj;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28