详解JavaScript中new操作符的解析和实现


Posted in Javascript onSeptember 04, 2020

前言

new 运算符是我们在用构造函数创建实例的时候使用的,本文来说一下 new 运算符的执行过程和如何自己实现一个类似 new 运算符的函数。

new 运算符的运行过程

new 运算符的主要目的就是为我们创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例(比如箭头函数就没有构造函数,所以是不能 new 的)。new 操作符的执行大概有以下几个步骤:

  1. 创建一个新的空对象
  2. 把新对象的 __proto__ 链接到构造函数的 prototype 对象(每一个用户定义函数都有一个 prototype 属性指向一个对象,该对象有一个 constructor 属性指向该函数),让我们的公共属性和方法可以从原型上继承,不用每个实例都创建一次。
  3. 将第一步创建的新的对象作为构造函数的 this 的上下文,执行构造函数,构造函数的执行让我们配置对象的私有属性和方法。
  4. 执行构造函数,如果构造函数没有返回值或者返回值不是一个对象,则返回 this

我么可以用代码简单表示上面的逻辑:

function new_ (constr, ...rests) {
 var obj = {};
 obj.__proto__ = constr.prototype;
 var ret = constr.apply(obj, rests);
 return isPrimitive(ret) ? obj : ret; //判断构造函数的返回值是否为对象,不是则直接返回创建的obj对象
}

new 的实现

上面讲了 new 运算符的执行过程,下面我们来自己动手实现一个 new 运算符。

function new_(constr, ...rests) {
 if (typeof constr !== "function") {
 throw "the first param must be a function";
 }
 new_.target = constr;
 var obj = Object.create(constr.prototype);
 var ret = constr.apply(obj, rests);
 var isObj = typeof ret !== null && typeof ret === "object";
 var isFun = typeof ret === "function";
 //var isObj = typeof ret === "function" || typeof ret === "object" && !!ret;
 if (isObj || isFun) {
 return ret;
 }
 return obj;
}

function Person(name, age) {
 this.name = name;
 this.age = age;
}
Person.prototype.say = function () {
 console.log(this.name);
};
var p1 = new_(Person, 'clloz', '28')
var p2 = new_(Person, 'csx', '31')
console.log(p1); //Person {name: "clloz", age: "28"}
p1.say(); //clloz
console.log(p2); //Person {name: "csx", age: "31"}
p2.say(); //csx

console.log(p1.__proto__ === Person.prototype); //true
console.log(p2.__proto__ === Person.prototype); //true

以上就是一个简单的 new 实现,判断是否为对象那里可能不是很严谨,不过没有想到更好的方法。

一个小补充,在 mdnFunction.prototype.apply() 词条中看到的直接把方法写到 Function.prototype 上,也是个不错的思路,Function.prototype 在所以函数的原型链上,所以这个方法可以在每个函数上调用,方法内部的 this 也是指向调用方法的函数的。

Function.prototype.construct = function (aArgs) {
 var oNew = Object.create(this.prototype);
 this.apply(oNew, aArgs);
 return oNew;
};

强制用 new 调用构造函数

function Clloz(...arguments) {
 if (!(this instanceof Clloz)) {
 return new Clloz(...arguments)
 }
}

Tips

补充两个关于 new 运算符的知识点。

  1. 上面提到 new 的执行过程的最后一步,如果构造函数没有返回值或者返回值不是一个对象,则返回 this。但是如果返回的是一个 null 的话,依然返回 this,虽然 null 也算是 object
  2. new 操作符后面的构造函数可以带括号也可以不带括号,除了带括号可以传递参数以外,还有一个重要的点是两种用法的运算符优先级不一样,在JS运算符优先级这篇文章中有提到,带参数的 new 操作符的优先级是比不带参数的要高的,new Foo() > Foo() > new Foo

一般不太会遇到,可能有些题目会问这些问题。

以上就是详解JavaScript中new操作符的解析和实现的详细内容,更多关于JavaScript new解析和实现的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
用函数式编程技术编写优美的 JavaScript_ibm
May 16 Javascript
Textarea与懒惰渲染实现代码
Jan 04 Javascript
JavaScript的Module模式编程深入分析
Aug 13 Javascript
让input框实现类似百度的搜索提示(基于jquery事件监听)
Jan 31 Javascript
使用命令对象代替switch语句的写法示例
Feb 28 Javascript
JavaScript SHA512&SHA256加密算法详解
Aug 11 Javascript
JS实现可关闭的对联广告效果代码
Sep 14 Javascript
jQuery监听文件上传实现进度条效果的方法
Oct 16 Javascript
jQuery中图片展示插件highslide.js的简单dom
Apr 22 jQuery
Vue中的混入的使用(vue mixins)
Jun 01 Javascript
微信小程序倒计时功能实例代码
Jul 17 Javascript
Vue实现boradcast和dispatch的示例
Nov 13 Javascript
我所理解的JavaScript中的this指向
Sep 04 #Javascript
JS运算符优先级与表达式示例详解
Sep 04 #Javascript
vue中的循环对象属性和属性值用法
Sep 04 #Javascript
JavaScript逻辑运算符相关总结
Sep 04 #Javascript
浅析JavaScript预编译和暗示全局变量
Sep 03 #Javascript
详解JavaScript作用域、作用域链和闭包的用法
Sep 03 #Javascript
JS变量提升及函数提升实例解析
Sep 03 #Javascript
You might like
《PHP边学边教》(01.开篇――准备工作)
2006/12/13 PHP
超级好用的一个php上传图片类(随机名,缩略图,加水印)
2010/06/30 PHP
php excel reader读取excel内容存入数据库实现代码
2012/12/06 PHP
codeigniter框架批量插入数据
2014/01/09 PHP
PHP URL参数获取方式的四种例子
2014/02/28 PHP
php通过function_exists检测函数是否存在的方法
2015/03/18 PHP
PHP连接MSSQL方法汇总
2016/02/05 PHP
laravel实现批量更新多条记录的方法示例
2017/10/22 PHP
thinkphp5实现微信扫码支付
2019/12/23 PHP
js实现的网站首页随机公告随机公告
2007/03/14 Javascript
jquery实现的超出屏幕时把固定层变为定位层的代码
2010/02/23 Javascript
jQuery UI Datepicker length为空或不是对象错误的解决方法
2010/12/19 Javascript
actionscript与javascript的区别
2011/05/25 Javascript
Javascript 页面模板化很多人没有使用过的方法
2012/06/05 Javascript
javascript实现客户端兼容各浏览器创建csv并下载的方法
2015/03/23 Javascript
Jquery实现跨域异步上传文件总结
2017/02/03 Javascript
浅谈react.js 之 批量添加与删除功能
2017/04/17 Javascript
详解vue2.0的Element UI的表格table列时间戳格式化
2017/06/13 Javascript
使用axios请求时,发送formData请求的示例
2019/10/29 Javascript
[03:22]DAC最前线(第二期)—DOTA2亚洲邀请赛主赛场周边及线路探访
2015/01/24 DOTA
[00:59]PWL开团时刻DAY7——我在赶
2020/11/06 DOTA
在Python中使用成员运算符的示例
2015/05/13 Python
Python图像处理之图像的读取、显示与保存操作【测试可用】
2019/01/04 Python
Python实现密码薄文件读写操作
2019/12/16 Python
pytorch 修改预训练model实例
2020/01/18 Python
从零开始的TensorFlow+VScode开发环境搭建的步骤(图文)
2020/08/31 Python
一站式跨境收款解决方案:Payoneer(派安盈)
2018/09/06 全球购物
Farfetch巴西官网:奢侈品牌时尚购物平台
2020/10/19 全球购物
教师研修随笔感言
2014/01/23 职场文书
求职信内容怎么写
2014/05/26 职场文书
雷人标语集锦
2014/06/19 职场文书
实验室的标语
2014/06/20 职场文书
公司股份合作协议书
2014/12/07 职场文书
青年岗位能手事迹材料
2014/12/23 职场文书
公司行政助理岗位职责
2015/04/11 职场文书
正则表达式基础与常用验证表达式
2022/06/16 Javascript