new操作符做了什么 使用new操作符调用函数时,会自动执行下面的操作
创建一个全新的对象
新对象执行[[prototype]]连接,即将新对象的__proto__指向调用函数的prototype
新对象绑定到函数调用的this
如果函数没有返回其他对象,那么new中的函数调用会自动返回新对象。
1 2 3 4 function foo (a ) { this .a = a } var bar = new foo (2 )
使用new调用foo(…)时,会构造一个新对象并把它绑定到foo(…)调用中的this上。
new的模拟实现 基于第一部分分析的四个步骤,很容易构造出以下模拟函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function new2 ( ) { var obj = Object .create (Object .prototype ) var Constructor = [].shift .call (arguments ) obj.__proto__ = Constructor .prototype Constructor .apply (obj, arguments ); return obj }
可以在浏览器中测试一下模拟的结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 function person (name, age ){ this .name = name this .age = age } person.prototype .school = 'njupt' person.prototype .sayName = function ( ) { console .log (`my name is ${this .name} ` ) } var person1 = new2 (person, 'izayoih' , '21' )console .log (person1.name ) console .log (person1.age ) console .log (person1.school ) person1.sayName ()
但这种没有考虑返回值的问题比如返回了一个对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 function person (name,age ) { this .age = age this .hobby = 'Games' return { name : name, school : 'njupt' } } var person1 = new person ('izayoih' , '21' )console .log (person1.name ) console .log (person1.age ) console .log (person1.school ) console .log (person1.hobby )
在实例person1中只能访问返回对象中的属性。
或者只返回基本类型:
1 2 3 4 5 6 7 8 9 10 function person (name,age ) { this .age = age this .hobby = 'Games' return 'njupt' } var person1 = new person ('izayoih' , '21' )console .log (person1.name ) console .log (person1.age ) console .log (person1.school ) console .log (person1.hobby )
这种情况下返回值正确但没有处理返回值。
总结一下就是判断返回值是否是一个对象,如果是一个对象,那么就返回该对象,如果不是或者没有返回值,那么就和正常情况一样,不处理构造函数的返回值。
1 2 3 4 5 6 7 8 9 10 11 function new2 ( ) { var obj = Object .create (Object .prototype ) var Constructor = [].shift .call (arguments ) obj.__proto__ = Constructor .prototype var retVal = Constructor .apply (obj, arguments ) return typeof retVal === 'object' ? retVal : obj }
以上为修改之后的模拟new函数。