手动实现new操作符

    <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.prototype
            const ret = Constructor.apply(obj, arguments) //4.要将构造函数的作用域指到我们的obj的空对象作用域中来,arguements顺带捎上人家的参数
            //return obj //2. 返回一个参数
            return typeof ret === 'object' ? ret : obj

        }
        console.log(objectFactory(Foo, 18));
    </script>

运行之后如图:
手动实现new操作符_第1张图片

你可能感兴趣的:(原型模式,javascript,开发语言)