js实现new 的问题

这里const result = obj.apply(newObj,reset)不知道为什么要有这一步。
我的理解是第一步把建立出来新对象的proto = 构造函数的prototype,那此时构造函数的实例newObj不就应该有构造函数中的所有属性与方法了吗,求解释,感谢各位

    //自己理解的写法
  function myNew(obj,...reset) { 
          let newObj = Object.create(obj.prototype);
          return newObj
         }


 function Person(name) {
         this.name = name;
         this.say = function () {
           console.log('我是person构造函数的say方法'+name)
          }

        }
        let tempObj = myNew(Person);
        console.log(tempObj)
        tempObj.say()  //打印出来is not a function
    //正确写法
 function myNew(obj,...reset) { 
          let newObj = Object.create(obj.prototype);
          const result = obj.apply(newObj,reset);
          return result === Object ? result : newObj;
         }
阅读 1.9k
4 个回答

这样可能好理解一点, 一步一步来:

1.function Person本身只是1个普通的函数,因为我可以像下面这样直接调用对吧:

var name = '123';
var say = function() {
    console.log('hhh');
}
function Person(name) {
    this.name = name;
    this.say = function () {
       console.log('我是person构造函数的say方法'+name)
    }
}

Person('名字');

这样一来,这个函数只是改变了全局作用域上的name和say而已。

2.当你执行new Person(name)的时候,却是不一样的效果:

function Person(name) {
    this.name = name;
    this.say = function () {
       console.log('我是person构造函数的say方法'+name)
    }
}

// 全局作用域的name和say不会受影响,b会生成一个新的对象。
const b = new Person('名字');

那么这个new操作到底干了什么呢?
1.创建构造函数,任何使用new操作符的函数都会创建1个新的构造函数。
2.创建构造函数的过程中,虽然你直接使用this.name = xxx赋值了,但实际上隐性的创建了一个新的对象new Object()。所以this的属性都是挂载在这个新的对象上的。

知道了new的操作会执行一遍创建对象即new Obejct的操作,然后再执行一遍给这个对象赋值的操作即this.name = xxx。你就能理解,其实new是进行了两个操作,一是创建新对象,二是给这个对象的属性进行赋值。

结论:
1.所以你的Object.crate操作只是完成了第一步,创建了1个新的对象,但是并没有执行给对象添加属性这一步。因为即使你是创建的Object.create(Person.prototype),也只是继承了Person方法而已,但是本身Person就没有被new过啊,也就并没有创建新的对象,而且没有指定这个对象的this是指向谁,没有赋值。所以你继承的只是一个空壳函数的呢。
2.而apply方法会绑定作用域,即this指向。同时执行这个函数,也就是执行this.name = xxx赋值的操作。所以当你执行了apply操作后,才算是给了这个对象一个完整的生命。

代码里的obj是构造函数,构造函数被new的时候是会执行里面代码的,apply就是执行构造函数,而构造函数的运行结果如果是一个对象(这里的对象不单指object类型的数据,可以理解为非基础数据)的话,则返回这个对象,所以下面正确写法其实也不对

class 的属性会被加到 prototype 里。

普通函数里对 this.say 的赋值并不影响 prototype ,就是说 prototype 中并没有 say 函数。需要执行这个构造函数的时候,this.say 才被赋值。所以,要在 obj.apply (执行构造函数) 之后,才可以使用 say

// obj 意义不够准确,改为 cstr,表示 constructor,也就是构造函数
// 注意,它是一个函数
// 另外,参数列表应该叫 rest,或者叫 args。reset 是重置的意思,不是剩余/其它的意思
function myNew(cstr, ...rest) {
    // 先从 cstr 的原形创建一个对象,newObj
    let newObj = Object.create(cstr.prototype);
    // 然后需要把这个 newObj 作为 cstr 中的 this 来调用 cstr
    // 所以用 apply,这表示调用 cstr,但里面的 this 是 newObj,
    // 后面是 rest 参数数组,作为 cstr 的参数传递进去
    // 如果改用 call,就是 cstr.call(newObj, ...rest)
    // 做这一步是为了初始化 this 对象(也就是构造函数本身的作用)
    const result = cstr.apply(newObj, rest);
    return result === Object ? result : newObj;
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题