你知道new做了什么?模拟new

121 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情

new做了什么

// 创建构造函数
function Play() {
    this.name = name
    this.type = type
}

// new一个实例对象
var play = new Play('LOL','game')

typeof Play === 'function' // true

console.log(play) // { name: 'LOL',type: 'game' }
console.log(Object.prototype.toString.call(play)); // [object Object]

上面的代码再熟悉不过了,new是我们常见的一个关键词,那有没有思考过new了之后内部到底干了些什么事情?

这个例子可以看到Play是一个构造函数,一个函数用new操作符来调用后,生成了一个全新的对象。接下来看下控制台输出

console.log(play) // {}

image.png

与普通对象相比,play中间还多了一层[[Prototype]],它的constructorPlay这个函数,通过new创建的实例对象最终被[[Prototype]]__proto__)链接到构造函数的Prototype对象上。

play.__proto__ === Play.prototype; // true

再来看看this

function Hero(name){
    console.log('赋值前-this', this); // 赋值前-this {}
    this.name = name;
    console.log('赋值后-this', this); // 赋值后-this {name: '韩信'}
}
var hero = new Hero('韩信');
console.log(hero); // {name: '韩信'}

image.png

可以看出Hero函数中的this指向实例hero

如果函数有返回值怎么处理?

创建实例会返回一个对象,当构造函数内部有返回值的情况还会是对象吗?

function Play(name){
    this.name = name;
    this.type = type
    
    // 基本类型
    // return Null
    // return Undefined
    // return Number
    // return String
    // return Boolean
    // return Symbol(符号)
    
    返回以上基本类型都会正常返回实例对象 
    {name:'bsball',type:'sport'}
    
    // 引用类型
    // return Object 返回 {}
    // return Function
    // return Array
    // return Date
    // return RegExp
    // return Error
    
    以上这些值会直接返回这些值
}
var play = new Play('bsball','sport');
console.log(play) // ???

小结

  1. 通过new操作符,会创建生成一个全新的对象。
  2. 通过new创建的实例对象会被执行[[Prototype]](也就是__proto__)链接到构造函数的Prototype对象上。
  3. 通过new创建的实例对象会绑定到函数调用的this
  4. 如果函数没有返回引用类型(ObjectFunctoinArrayDateRegExgError),那么new表达式中的函数调用会自动返回这个新创建的对象。

手写new

function rewriteNew(constructor) {
  if (typeof constructor !== "function") return

  // 基于constructor的原型创建一个全新的对象
  let newObj = Object.create(constructor.prototype);

  // 获取传入的参数
  let args = Array.from(arguments).slice(1);

  // 执行constructor函数,获取结果,并将属性添加到新对象newObj上
  let result = constructor.apply(newObj, args); // 将this指向newObj

  // 判断result类型,如果是object或者function类型,则直接返回结果
  let originType = Object.prototype.toString.call(result); // 获取内部属性值
  let isObject = originType === '[object Object]';
  let isFunction = originType === '[object Function]';
  if (isObject || isFunction) {
    return result;
  } else {
    // 如果函数没有返回引用类型,那么`new`表达式中的函数调用会自动返回这个新的对象。
    return newObj;
  }
}
function Play(name, type){
    this.name = name;
    this.type = type;
}
Play.prototype.rule = function() {
    return this.type
};

var play = rewriteNew(Play, '篮球', 'sport');
console.log(play, play.rule()); // {name: '篮球', type: 'sport'} 'sport'

image.png

end

image.png