<script>//前置知识// 每一个函数在创建之初就会有一个prototype属性,这个属性指向函数的原型对象// function abc(){// }// abc.prototype--> {constructor: f}// 在JS中任意的对象都有内置的属性叫做[[prototype]]这是一个私有属性,这个私有属性通过__proto__的方法来访问。// 隐式原型指向这个对象函数的显式原型// function Abc(){// this.name='wn'// }// let test = new Abc()// test.__proto__=Abc.prototype//实例的隐式原型等于它构造函数的显式原型function Foo(e) {this.name = 'wn'this.age = e//如果构造函数有个return,return出来的值会影响到我们的返回结果,如果return出来的是个对象的话 那我们的作用域会出现一些微妙的结果,return不是对象的话没什么影响 但是如果是对象的话return出来的值就会受到影响 是它本身return {}}//手动实现new操作符function objectFactory() {// 1. 定义一个对象出来 console.log(new Foo(18)) new Foo一定是一个对象 实例对象实例对象const obj = {}//3. 构造函数可以接收参数的,但是要先拿到这个构造函数,shift删除数组的第一项并且返回该项值,把shift方法里面的作用域修改到arguments里面去,call方法改变this指向//[].shift.call(arguments) 的目的是将 arguments 对象转换成数组,并调用数组对象的 shift 方法来取出第一个参数(构造函数)。由于 arguments 是类数组对象而不是真正的数组对象,所以不能直接调用 shift 方法。因此,我们借助 call 方法来显式指定调用 shift 方法时的上下文对象,也就是将 shift 方法中的 this 指向 arguments 对象,从而实现从 arguments 中取出第一个参数的目的。const Constructor = [].shift.call(arguments)//或者是下面这样的方法,解构赋值 ...arguments这里面可能有很多参数 但是第一个指定是constructor,这里传进来的参数其实是console.log(objectFactory(Foo,18))第一个传进来的肯定是Foo//const [Constructor, ...args] = [...arguments]//现在拿到了我们的构造函数需要调用一下,因为new的时候的实例对象会继承函数的属性和方法,所以接下来是要实现要将函数的属性或者方法添加到构造函数上去//5. 执行我们的原型连接 ,obj.__proto__ = Constructor.prototypeconst ret = Constructor.apply(obj, arguments) //4.要将构造函数的作用域指到我们的obj的空对象作用域中来,arguements顺带捎上人家的参数//return obj //2. 返回一个参数return typeof ret === 'object' ? ret : obj}console.log(objectFactory(Foo, 18));</script>
运行之后如图(构造函数没有return的时候):