(1) 建立一个新对象;
(2) 将构造函数的做用域赋给新对象(所以 this 就指向了这个新对象) ;
(3) 执行构造函数中的代码(为这个新对象添加属性) ;
(4) 绑定原型;
(4) 返回新对象。
注意:数组
function Test(name) { this.name = name return 1 } const t = new Test('yck') console.log(t.name) // 'yck' function Test(name) { this.name = name console.log(this) // Test { name: 'yck' } return { age: 26 } } const t = new Test('yck') console.log(t) // { age: 26 } console.log(t.name) // 'undefined'
由于 new 是关键字,因此没法直接覆盖,因此咱们写一个函数,命名为 myNew,来模拟 new 的效果。用的时候是这样的:app
function person() { …… } // 使用 new var person = new person(……); // 使用 objectFactory var person = myNew(person, ……)
由于 new 的结果是一个新对象,因此在模拟实现的时候,咱们也要创建一个新对象,假设这个对象叫 obj,由于 obj 会具备 Otaku 构造函数里的属性,想一想经典继承的例子,咱们能够使用 Otaku.apply(obj, arguments)来给 obj 添加新的属性。函数
function myNew() { //用new Object() 的方式新建了一个对象 obj var obj = new Object(), //取出传入的构造函数。此外由于shift会修改原数组,因此arguments会被去除第一个参数 Constructor = [].shift.call(arguments); //将 obj 的原型指向构造函数,这样 obj 就能够访问到构造函数原型中的属性 obj.__proto__ = Constructor.prototype; //使用 apply,改变构造函数 this 的指向到新建的obj对象,并执行了Constructor,这样obj就会被添加属性 var ret = Constructor.apply(obj, arguments); //判断返回的值是否是一个对象,若是是一个对象,咱们就返回这个对象,若是不是,咱们原样返回 return typeof ret === 'object' ? ret : obj; //返回出去 return obj; };
function person(name, age) { this.name = name; this.age = age; this.habit = 'Games'; } person.prototype.strength = 60; person.prototype.sayYourName = function () { console.log('I am ' + this.name); } var person = myNew(person, 'Kevin', '18') console.log(person.name) // Kevin console.log(person.habit) // Games console.log(person.strength) // 60 person.sayYourName(); // I am Kevin
function myNew(Con, ...args) { let obj = {} //等同于 obj.__proto__ = Con.prototype Object.setPrototypeOf(obj, Con.prototype) let result = Con.apply(obj, args) return result instanceof Object ? result : obj }