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】 JavaScript 中 New 操作符的内部机制 #64

Open
yayxs opened this issue Apr 17, 2021 · 0 comments
Open

【JavaScript】 JavaScript 中 New 操作符的内部机制 #64

yayxs opened this issue Apr 17, 2021 · 0 comments

Comments

@yayxs
Copy link
Owner

yayxs commented Apr 17, 2021


title: 手写实现New操作符

手写实现 JavaScript 中的 New 操作符

延伸的面试题

根据new操作符相关的知识点一般会 延伸出以下的面试题 ,面试官你是否有很多问号

  • 问题一:new 之后都做了些什么??
  • 问题二:能否手写 new 操作符原理??
  • 问题三:通过 new 的方式创建对象和通过字面量创建有什么区别

mdn 关于 new 运算符关键字的描述

  1. 创建一个空的简单 JavaScript 对象(即{});
  2. 链接该对象(即设置该对象的构造函数)到另一个对象 ;
  3. 将步骤 1 新创建的对象作为this的上下文 ;
  4. 如果该函数没有返回对象,则返回this

以上 4 条是MDN 上关于 new 操作符(或者说关键字)的描述,那么当new 的时候 引擎做了几件事呢

  function CreateObj() {
        this.name = `-Create-OBj`
      }

      var myObj = new CreateObj()
  • 首先创建了一个空的对象 tempObj

  • 接着调用CreateObj.call 方法 并将 初始化的空对象tempObj 作为call方法的参数,当CreateObj的执行上下文创建的时候 this 就指向了 `tempObj``

  • 然后执行 CreateObj 函数 此时 函数执行上下文中的this 指向了tempObj 对象

  • 最后把对象tempObj返回

var tempObj = {}
CreateObj.call(tempObj)
return tempObj

构造函数中的this其实就是新对象本身

简单的来体验下利用构造函数来new 一个对象

function Person(name, age) {
  console.log('this', this)
  this.name = name
  this.age = age
}
// 然后在**构造函数添加原型方法**
Person.prototype.height = 180
Person.prototype.sayName = function() {
  console.log(this.name)
}
let p = new Person('yayxs', 20)
console.log(p.name) // yayxs
console.log(p.age)
20
p.sayName() // yayxs
console.log(p.__proto__ === Person.prototype) // 对象p(实例)的原型属性指向构造函数的原型,

既然我们通过自定义,其使用的方式大体跟new 是一样的。

// ------ 使用new的时候

const p = myNew Person('yayxs',20) // 其返回的结果是一个对象

// ---------

第一版的 myNew

大体思路是声明一个对象,取出当前的构造函数,以及参数,让新对象的原型属性指向构造函数的原型,然后调用构造函数,传入对象的参数

function myNew() {
  let obj = new Object(),
    [constructor, ...args] = [...arguments]
  obj.__proto__ = constructor.prototype

  constructor.apply(obj, args)
  return obj
}

第二版的 myNew

经过上文的简单案例我们可以得知,

  • new 一个构造函数得到一个对象,它的原型属性(也就是** proto **)与该构造函数的原型是全等

  • new 通过构造函数 Persion 创建出来的实例可以访问到构造函数中的属性,就像这样

    console.log(xiaoMing.name) // 小明
  • 言简意赅:new 出来的实例对象通过原型链和构造函数联系起来

构造函数说白了也是一个函数,那是函数就可以有返回值

function Person(name) {
  this.name = name
  //   return 1; // 返回内部新创建的对象
  //   return "1"; // 返回内部新创建的对象
  // return null; // 返回内部新创建的对象
  //   return undefined; // 返回内部新创建的对象
  //   return {}; // {} // 直接返回
  return function() {} // 直接返回
  return [1] // [1] // 直接返回
}
let p = new Person('李四')
console.log(p)

有了给构造函数返回一个值得想法,那就通过不同的数据类型 进行测试得出结论

  • 不同的数据类型返回的效果是不一样的,像数字 1 字符串”1“ ,返回的依然是内部创建的对象
  • 那如果返回一个对象({})或者说数组([]) 都会直接返回回去

小结

也就是说,构造函数一般不需要return

  • 返回一般的数据类型吧,不起作用
  • 返回对象吧, new 的意义又何在呢
function myNew(){
  let obj = new Object(),
  [constructor,...args] =  [...arguments]
   obj.__proto__ = constructor.prototype;

  let res =  constructor.apply(obj,args)
  return =  typeof res === 'object' ? res : obj;
}

手写一个自己的 myNew 小结

如果自己实现一个 new 的话,首先要满足它的几点效果

  1. 一个构造函数会返回一个对象,那函数里就应该有对象

    let obj = {}
  2. 并将其__proto__属性指向构造函数的prototype属性

    obj.__proto__ = constructor.prototype
  3. 调用构造函数,绑定 this

    constructor.apply(obj, args)
  4. 返回原始值需要忽略,返回对象需要正常处理

    res instanceof Object ? res : obj

箭头函数使用new

但是 ES6 中介绍了一种无法使用这些规则的特殊函数类型:箭头函数

var Foo = () => {}
var foo = new Foo() // TypeError: Foo is not a constructor
  • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误

this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。

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

No branches or pull requests

1 participant