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

new关键字解读以及模拟实现 #24

Open
keep-run opened this issue Jun 28, 2020 · 0 comments
Open

new关键字解读以及模拟实现 #24

keep-run opened this issue Jun 28, 2020 · 0 comments

Comments

@keep-run
Copy link
Owner

keep-run commented Jun 28, 2020

new关键字干了什么?

通常使用new关键字是为了创建一个自定义对象类型的实例。使用new的时候,会有以下几个过程:

1、创建一个空的简单JavaScript对象(即{});
2、链接该对象(即设置该对象的构造函数)到另一个对象 ;
3、将步骤1新创建的对象作为this的上下文 ;
4、如果该函数(2中设置的构造函数)没有返回对象,则返回this。
原文(中文):https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new
英文(英文):https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new

以上仅仅是new的过程,如果要创建一个用户自定类型的对象,需要以下两部:

1、写一个函数定义对象类型;
2、通过new关键字来创建对象的实例;

有两点值得注意:
1、如果构造函数没有显示的返回一个对象,则返回this(创建的实例对象)。 如果显示返回一个对象,则返回该对象,且该对象不是构造函数的实例。 如果返回 null string number等,会直接忽略,继续返回this对象。测试一下:

  • 返回 null string number等被忽略的情况
function Demo1(a){
  this.a=a
  return 'test'
}
Demo1.prototype.getA=function(){
  return 'a is :'+this.a
}
const inst1=new Demo1(5)
inst1.getA()
  • 显示返回一个对象:
function Demo2(a){
  this.a=a
  return {
    b:3
  }
}
Demo2.prototype.getB=function(){
  return 'a is :'+this.b
}

const inst2=new Demo2(5)
inst2.a   //undefined
inst2.b   //2
inst2.getB()  // inst2.getB is not a function  显示返回的对象不是Demo2的实例,不能访问原型上的对象。

怎么模拟一个new ?

先实现一个简单的版本。

function _new(constructFunc,...rest){
  let obj={}
  constructFunc.apply(obj,rest)
  obj.__proto__=constructFunc.prototype
  return obj
}
function Test(a){
  this.a=a
}
Test.prototype.getA=function(){
  return this.a
}
const testInst=_new(Test,999)
console.log(testInst.getA())  // 999

注意:定义新对象的时候,以下两种方法是等价的:

let a={}
let a=Object.create({})

如果使用Object.create(null)创建对象,则会丢失原型,只能通过Object.setPrototypeOf()重新设置对象的原型。o.__proto__设置是无效的。

处理异常返回

这里要做一次判断,如果constructFunc函数返回一个对象,则直接返回该对象,否则就返回构造的实例对象。

function _new(constructFunc, ...rest) {
  let obj = {}
  obj.__proto__ = constructFunc.prototype
  let res=constructFunc.apply(obj, rest)
  return (res && typeof res === 'object') ? res : obj
}
function Test(a) {
  this.a = a
  return {b:a}
}
Test.prototype.getA = function () {
  return this.a
}
const testInst = _new(Test, 999)
testInst.getA()   // testInst.getA is not a function  不是实例

参考文章:mqyqingfeng/Blog#13

new.target

new.target是es6新增的指令, 返回new调用的函数的函数名。基于该指令可以辅助实现限制部分函数必须用new调用。比如定义了一个构造函数,必须先实例化才能继续使用。可以写以下函数来容错。

function Person(name){
  if(new.target!==Person){
    return  new Person(name)
  }
  this.name=name
}

let p1=new Person('A')   //Person {name: "A"}
let P2=Person('B')         // Person {name: "B"}

以上写法,不管有没有使用new来调用函数,都可以返回一个Person的实例。增加程序健壮性;

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