模拟 JS new 运算符

242 阅读2分钟

模拟 JS new 运算符

1. JS new 运算符做了什么

  • 操作对象仅能为函数
  • 创建一个新对象
  • 新对象的原型链指向函数的 prototype 属性
  • 新对象绑定到函数的 this
  • 若函数返回一个对象类型的值,则返回,反之返回新对象

操作对象仅能为函数

var arr = [1,2,3];
new arr;
// Uncaught TypeError: arr is not a constructor
// 大家可以试试别的类型
var fun = function () {};
new fun;

创建一个新对象

function fun() {}
var f = new fun;
console.log(typeof f);
// object

新对象的原型链指向函数的 prototype 属性

function fun() {}
var f = new fun;
console.log(f.__proto__ === fun.prototype);
console.log(Object.getPrototypeOf(f) === fun.prototype);

新对象绑定到操作函数的 this

function fun() { this.name = 'n'; }
var f = new fun;
console.log(f);
function fun1(name) { this.name = name; }
var f1 = new fun1('cheng');
console.log(f1);

若函数返回一个对象类型的值,则返回,反之返回新对象

function fun() { this.name = 'n'; return 123; }
var f = new fun;
console.log(f);
function fun0() { this.name = 'n0'; return null; }
var f0 = new fun0;
console.log(f0);
// 大家可以试试别的类型
function fun1() { this.name = 'n1'; return [123]; }
var f1 = new fun1;
console.log(f1);

2. 模拟 JS new 操作符

function myNew() {
    var fun = arguments[0];
    var arrParams = [].slice.call(arguments, 1);
    // 操作对象仅能为函数
    if (typeof fun !== 'function') {
        throw new Error('first parameter must be a function')
    }
    // 创建一个新对象
    // 新对象的原型链指向函数的 prototype 属性
    var newObject = Object.create(fun.prototype);
    // 新对象绑定到函数的 this
    var result = fun.apply(newObject, arrParams);
    // 若函数返回一个对象类型的值,则返回,反之返回新对象
    if (result !== null &&
    (typeof result === 'object') || (typeof result === 'function')){
        return result;
    }
    else {
        return newObject;
    }
}

3. 测试所写的方法

操作对象仅能为函数

var arr = [1,2,3];
// new arr;
myNew(arr);
var fun = function () {};
// new fun;
myNew(fun);

创建一个新对象

function fun() {}
// var f = new fun;
// console.log(typeof f);
var f = myNew(fun);
console.log(typeof f);
// object

新对象的原型链指向函数的 prototype 属性

function fun() {}
// var f = new fun;
var f = myNew(fun);
console.log(f.__proto__ === fun.prototype);
console.log(Object.getPrototypeOf(f) === fun.prototype);

新对象绑定到操作函数的 this

function fun() { this.name = 'n'; }
// var f = new fun;
var f = myNew(fun);
console.log(f);
function fun1(name) { this.name = name; }
// var f1 = new fun1('cheng');
var f1 = myNew(fun1, 'cheng');
console.log(f1);

若函数返回一个对象类型的值,则返回,反之返回新对象

function fun() { this.name = 'n'; return 123; }
// var f = new fun;
var f = myNew(fun);
console.log(f);
function fun0() { this.name = 'n0'; return null; }
// var f0 = new fun0;
var f0 = myNew(fun0);
console.log(f0);
// 大家可以试试别的类型
function fun1() { this.name = 'n1'; return [123]; }
// var f1 = new fun1;
var f1 = myNew(fun1);
console.log(f1);

4. 总结

  • 操作对象仅能为函数
  • 创建一个新对象
  • 新对象的原型链指向函数的 prototype 属性
  • 新对象绑定到函数的 this
  • 若函数返回一个对象类型的值,则返回,反之返回新对象

没注释的模拟方法

function myNew() {
    var fun = arguments[0];
    var arrParams = [].slice.call(arguments, 1);
    if (typeof fun !== 'function') {
        throw new Error('first parameter must be a function')
    }
    var newObject = Object.create(fun.prototype);
    var result = fun.apply(newObject, arrParams);
    if (result !== null &&
    (typeof result === 'object') || (typeof result === 'function')){
        return result;
    }
    else {
        return newObject;
    }
}