new 操作符

参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。以这种方式调用构造函数实际上会经历以下 4 个步骤:

  1. 创建一个新对象, 即{};
  2. 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
  3. 执行构造函数中的代码(为这个新对象添加属性),即使用指定的参数调用构造函数,并将 this 绑定到新创建的对象。new Person 等同于 new Person(),也就是没有指定参数列表,Person 不带任何参数调用的情况。
  4. 如果该函数没有返回对象,则返回this(即新对象)。展开来说,由构造函数返回的对象就是 new 表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1创建的对象。(一般情况下,构造函数不返回值,但是用户可以选择主动返回对象,来覆盖正常的对象创建步骤)

模拟实现一个new操作:

/**
* fn 构造函数
* args 参数,可以是多个
*/
// 实现一
function newOper(fn, ...args) {
  let obj = {};
  Object.setPrototypeOf(obj, fn.prototype); // setPrototypeOf是es6新增方法,之前版本可使用: obj.__proto__ = fn.prototype;
  let result = fn.apply(obj, args);
  return result instanceof Object ? result : obj;
}
// 由于现代 JavaScript 引擎优化属性访问所带来的特性的关系,更改对象的 [[Prototype]]在各个浏览器和 JavaScript 引擎上都是一个很慢的操作。关心性能,你应该避免设置一个对象的 [[Prototype]]。相反,你应该使用 Object.create()来创建带有你想要的[[Prototype]]的新对象。详见:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf
// 实现二
function newOper2 (fn, ...args) {
    let obj = Object.create(fn.prototype);
    let result = fn.apply(obj, args);
    return result instanceof Object ? result : obj;
}
// 对于两种方式的测试
function Person(){}
Person.prototype.name = "xiaoming"
console.time('newOper')
for(let i = 0; i < 10000; i++){
    newOper(Person);
}
console.timeEnd('newOper');
console.time('newOper2');
for(let i = 0; i < 10000; i++){
    newOper2(Person);
}
console.timeEnd('newOper2')
// 测试结果, 显然方法二效率更高
// newOper: 3.765625ms
// newOper2: 2.02294921875ms
posted @ 2020-01-06 22:01  fanlinqiang  阅读(164)  评论(0编辑  收藏  举报