详解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 函数调用规则
Sep 14 Javascript
javascript利用初始化数据装配模版的实现代码
Nov 17 Javascript
Jquery.addClass始终无效原因分析
Sep 08 Javascript
解决json日期格式问题的3种方法
Feb 02 Javascript
用原生js做个简单的滑动效果的回到顶部
Oct 15 Javascript
JavaScript实现三阶幻方算法谜题解答
Dec 29 Javascript
jquery插件qrcode在线生成二维码
Apr 26 Javascript
星期几的不同脚本写法(推荐)
Jun 01 Javascript
JS实用的带停顿的逐行文本循环滚动效果实例
Nov 23 Javascript
Vue.js 2.0学习教程之从基础到组件详解
Apr 24 Javascript
JS弹窗 JS弹出DIV并使整个页面背景变暗功能的实现代码
Apr 21 Javascript
Angular8 Http拦截器简单使用教程
Aug 20 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 接口类与抽象类的实际作用
2009/11/26 PHP
gd库图片下载类实现下载网页所有图片的php代码
2012/08/20 PHP
浅谈web上存漏洞及原理分析、防范方法(文件名检测漏洞)
2013/06/29 PHP
php断点续传之如何分割合并文件
2014/03/22 PHP
php模拟post上传图片实现代码
2016/06/24 PHP
PHP cURL获取微信公众号access_token的实例
2018/04/28 PHP
javascript下4个跨浏览器必备的函数
2010/03/07 Javascript
js封装的textarea操作方法集合(兼容很好)
2010/11/16 Javascript
利用javascript实现web页面中指定区域打印
2013/10/30 Javascript
JavaScript删除指定子元素代码实例
2015/01/13 Javascript
javascript表格隔行变色加鼠标移入移出及点击效果的方法
2015/04/10 Javascript
基于Angularjs+mybatis实现二级评论系统(仿简书)
2017/02/13 Javascript
jQuery插件之validation插件
2017/03/29 jQuery
nodejs利用ajax实现网页无刷新上传图片实例代码
2017/06/06 NodeJs
利用JavaScript将Excel转换为JSON示例代码
2019/06/14 Javascript
layui实现tab的添加拒绝重复的方法
2019/09/04 Javascript
js实现图片跟随鼠标移动效果
2019/10/16 Javascript
详细介绍解决vue和jsp结合的方法
2020/02/06 Javascript
vue iview实现动态新增和删除
2020/06/17 Javascript
[01:03:41]DOTA2-DPC中国联赛 正赛 Dynasty vs XG BO3 第三场 2月2日
2021/03/11 DOTA
Windows 7下Python Web环境搭建图文教程
2018/03/20 Python
numpy判断数值类型、过滤出数值型数据的方法
2018/06/09 Python
关于python中plt.hist参数的使用详解
2019/11/28 Python
python tqdm 实现滚动条不上下滚动代码(保持一行内滚动)
2020/02/19 Python
记一次Django响应超慢的解决过程
2020/09/17 Python
瑞士国际航空官网:SWISS
2016/07/21 全球购物
伦敦剧院门票:From The Box Office
2018/06/30 全球购物
英国最大的汽车配件在线商店:Euro Car Parts
2019/09/30 全球购物
大学生水果店创业计划书
2014/01/28 职场文书
中介业务员岗位职责
2014/04/09 职场文书
学习型党组织建设经验材料
2014/05/26 职场文书
2014办公室副主任四风对照检查材料思想汇报
2014/09/20 职场文书
2015年世界无烟日活动总结
2015/02/10 职场文书
开票员岗位职责
2015/02/12 职场文书
2019年年中工作总结讲话稿模板
2019/03/25 职场文书
idea以任意顺序debug多线程程序的具体用法
2021/08/30 Java/Android