第十天2019-01-10

碎碎念

最近都没有不同的图片可以贴了,还需要找点图片啊。今天早上看了下怎么实现new操作符,感觉又回到了,原型和原型链的理解,“new”一个函数的时候,到底发生了什么?兜兜转转看来还是这个理解的不到位。说起理解不到位,让我想起了,今天写业务代码的时候,写到Vue渲染先后顺序这个地方,愣是卡了很久。看来这是对于整个的Vue运行机制还掌握的不够。


笔记-new操作符-上

“new” 发生了什么

先来看看MDN上是怎么解释的?2

  • 语法
    new constructor[([arguments])] // constructor:指定对象实例的类型的类或函数
  • 描述

    当代码 new Foo(…) 执行时,会发生以下事情:

  1. 一个继承自 Foo.prototype 的新对象被创建。
  2. 使用指定的参数调用构造函数 Foo ,并将 this 绑定到新创建的对象。new Foo 等同于 new Foo(),也就是没有指定参数列表,Foo 不带任何参数调用的情况。
  3. 由构造函数返回的对象就是 new 表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1创建的对象。(一般情况下,构造函数不返回值,但是用户可以选择主动返回对象,来覆盖正常的对象创建步骤)

网友总结的[1]

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

这个是总结出来的,总觉得有点不科学啊。但目前好像是最好的办法,通过new的功能反推new的实现。

补充

使用 Function.prototype 属性将共享属性添加到以前定义的对象类型

function Car() {}
car1 = new Car()

Car.prototype.color = null
console.log(car1.color) // null

怎么实现new

/**
* 模拟实现 new 操作符
* @param {Function} ctor [构造函数]
* @return {Object|Function|Regex|Date|Error} [返回结果]
*/
function newOperator(ctor){
if(typeof ctor !== 'function'){
throw 'newOperator function the first param must be a function';
}
// ES6 new.target 是指向构造函数
// new.target 后面会补充下
newOperator.target = ctor;
// 1.创建一个全新的对象,
// 2.并且执行[[Prototype]]链接
// 4.通过`new`创建的每个对象将最终被`[[Prototype]]`链接到这个函数的`prototype`对象上。
var newObj = Object.create(ctor.prototype);
// ES5 arguments转成数组 当然也可以用ES6 [...arguments], Aarry.from(arguments);
// 除去ctor构造函数的其余参数
var argsArr = [].slice.call(arguments, 1);
// 3.生成的新对象会绑定到函数调用的`this`。
// 获取到ctor函数返回结果
var ctorReturnResult = ctor.apply(newObj, argsArr);
// 小结4 中这些类型中合并起来只有Object和Function两种类型 typeof null 也是'object'所以要不等于null,排除null
var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult !== null;
var isFunction = typeof ctorReturnResult === 'function';
if(isObject || isFunction){
return ctorReturnResult;
}
// 5.如果函数没有返回对象类型`Object`(包含`Functoin`, `Array`, `Date`, `RegExg`, `Error`),那么`new`表达式中的函数调用会自动返回这个新的对象。
return newObj;
}

这个实现,除去一些排除异常的条件,我理解的就几步,把对象复制过去,然后参数绑定过去,排除边界条件,整个咋一看并不是很难,但是很考验对整个操作符的掌握和熟悉程度。

new.target

在构造方法调用中,new.target指向被new调用的构造函数,所以”new.”成为了一个虚拟上下文[2]

  • 普通函数中
    new.target的值是undefined,可以检测一个函数是否是作为构造函数通过new被调用的。
    function Foo() {
    if (!new.target) throw "Foo() must be called with new";
    console.log("Foo instantiated with new");
    }

    Foo(); // throws "Foo() must be called with new"
    new Foo(); // logs "Foo instantiated with new", 检测到由new调用
  1. 构造函数中
    稍微复杂点,这里暂时不讨论可以到MDN去看。
    今天暂时讨论到这啊!明天还得上线呢!有点晚,早点睡觉吧。
    --end 
    
    参考:
    [1]. 面试官问:能否模拟实现JS的new操作符
    [2]. new运算符
文章作者: lmislm
文章链接: http://lmislm.com/2019/01/10/2019-01-10/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 LMISLMのBlog