Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【JavaScript】new 原理及实现 #14

Open
Tracked by #6
swiftwind0405 opened this issue Feb 27, 2020 · 2 comments
Open
Tracked by #6

【JavaScript】new 原理及实现 #14

swiftwind0405 opened this issue Feb 27, 2020 · 2 comments

Comments

@swiftwind0405
Copy link
Owner

swiftwind0405 commented Feb 27, 2020

  • new 是一个运算符
  • new 的作用,就是执行构造函数,返回一个实例对象

new 的功能:

  • 访问到 Function 构造函数里的函数
  • 访问到 Function.prototype 中的属性

new做了什么:

  1. 创建了一个全新的对象。
  2. 这个对象会被执行[[Prototype]](也就是__proto__)链接。
  3. 生成的新对象会绑定到函数调用的this。
  4. 通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上。
  5. 如果函数没有返回对象类型Object(包含Functoin, Array, Date, RegExg, Error),那么new表达式中的函数调用会自动返回这个新的对象。

实现原理

使用 new 命令时,它后面的构造函数会执行以下操作:

  1. 创建一个空的简单的 JavaScript 对象
  2. 将空对象的原型,指向构造函数的 prototype 属性
  3. 将当前函数内部的 this 绑定到空对象
  4. 执行构造函数,如果没有返回对象,则返回 this,即新创建的对象

步骤 3 中,将新创建的对象作为了当前函数 this 的上下文,这也是为什么通过 new 创建实例时,构造函数内部的 this 指向创建的实例对象的原因。

手写

function objectFactory() {

    var obj = new Object(),//从Object.prototype上克隆一个对象

    Constructor = [].shift.call(arguments);//取得外部传入的构造器

    var F=function(){};
    F.prototype= Constructor.prototype;
    obj=new F();//指向正确的原型

    var result = Constructor.apply(obj, arguments);//借用外部传入的构造器给obj设置属性

    return typeof result === 'object' ? ret : obj;//确保构造器总是返回一个对象
};
  • new Object() 的方式新建了一个对象 obj
  • 取出第一个参数,就是我们要传入的构造函数。此外因为 shift 会修改原数组,所以 arguments 会被去除第一个参数
  • 将 obj 的原型指向构造函数,这样 obj 就可以访问到构造函数原型中的属性
  • 使用 apply,改变构造函数 this 的指向到新建的对象,这样 obj 就可以访问到构造函数中的属性
  • 如果构造函数返回一个对象,那么我们也返回这个对象;否则,就返回默认值

https://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=2651555993&idx=1&sn=37bb41a7e178083de174bfd51308d369&chksm=80255f58b752d64e3006feb7d14b1e0cf47414f98863dc0ffb46b524f2926ac0dea805210353&mpshare=1&scene=1&srcid=%23rd

campcc/blog#3

https://juejin.im/post/5bde7c926fb9a049f66b8b52

@swiftwind0405 swiftwind0405 changed the title 实现一个 new 操作符 new 原理及实现 Feb 27, 2020
@swiftwind0405
Copy link
Owner Author

swiftwind0405 commented Mar 10, 2020

@swiftwind0405 swiftwind0405 changed the title new 原理及实现 【Day22】new 原理及实现 Mar 16, 2020
@swiftwind0405 swiftwind0405 changed the title 【Day22】new 原理及实现 【Day21】new 原理及实现 Mar 16, 2020
@swiftwind0405 swiftwind0405 changed the title 【Day21】new 原理及实现 【JavaScript】new 原理及实现 Apr 29, 2020
@swiftwind0405
Copy link
Owner Author

首先我们要知道new做了什么

  1. 创建一个新对象,并继承其构造函数的prototype,这一步是为了继承构造函数原型上的属性和方法
  2. 执行构造函数,方法内的this被指定为该新实例,这一步是为了执行构造函数内的赋值操作
  3. 返回新实例(规范规定,如果构造方法返回了一个对象,那么返回该对象,否则返回第一步创建的新对象)
// new是关键字,这里我们用函数来模拟,new Foo(args) <=> myNew(Foo, args)
function myNew(foo, ...args) {
  // 创建新对象,并继承构造方法的prototype属性, 这一步是为了把obj挂原型链上, 相当于obj.__proto__ = Foo.prototype
  let obj = Object.create(foo.prototype)  
  
  // 执行构造方法, 并为其绑定新this, 这一步是为了让构造方法能进行this.name = name之类的操作, args是构造方法的入参, 因为这里用myNew模拟, 所以入参从myNew传入
  let result = foo.apply(obj, args)

  // 如果构造方法已经return了一个对象,那么就返回该对象,否则返回myNew创建的新对象(一般情况下,构造方法不会返回新实例,但使用者可以选择返回新实例来覆盖new创建的对象)
  return Object.prototype.toString.call(result) === '[object Object]' ? result : obj
}

// 测试:
function Foo(name) {
  this.name = name
}
const newObj = myNew(Foo, 'zhangsan')
console.log(newObj)                 // Foo {name: "zhangsan"}
console.log(newObj instanceof Foo)  // true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant