详解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 相关文章推荐
文本链接逐个出现的js脚本
Dec 12 Javascript
JavaScript高级程序设计 读书笔记之八 Function类及闭包
Feb 27 Javascript
JS字符串处理实例代码
Aug 05 Javascript
JavaScript中this的使用详解
Nov 08 Javascript
js 操作select与option(示例讲解)
Dec 20 Javascript
jQuery trigger()方法用法介绍
Jan 13 Javascript
实例详解jQuery结合GridView控件的使用方法
Jan 04 Javascript
JS动态修改网页body的背景色实例代码
Oct 07 Javascript
AngularJS实现controller控制器间共享数据的方法示例
Oct 30 Javascript
koa2使用ejs和nunjucks作为模板引擎的使用
Nov 27 Javascript
Node.js折腾记一:读指定文件夹,输出该文件夹的文件树详解
Apr 20 Javascript
详解在IDEA中将Echarts引入web两种方式(使用js文件和maven的依赖导入)
Jul 11 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实现 上一篇、下一篇的代码
2012/09/29 PHP
浅析十款PHP开发框架的对比
2013/07/05 PHP
php判断当前用户已在别处登录的方法
2015/01/06 PHP
php遍历树的常用方法汇总
2015/06/18 PHP
浅析Yii2 GridView实现下拉搜索教程
2016/04/22 PHP
PHP 以POST方式提交XML、获取XML,解析XML详解及实例
2016/10/26 PHP
javascript的内存管理详解
2013/08/07 Javascript
学习Bootstrap组件之下拉菜单
2015/07/28 Javascript
jquery实现简单的二级导航下拉菜单效果
2015/09/07 Javascript
Angularjs中UI Router全攻略
2016/01/29 Javascript
JS实现支持Ajax验证的表单插件
2016/03/24 Javascript
js不间断滚动的简单实现
2016/06/03 Javascript
Bootstrap文件上传组件之bootstrap fileinput
2016/11/25 Javascript
JS实现的数字格式化功能示例
2017/02/10 Javascript
JavaScript数据结构中串的表示与应用实例
2017/04/12 Javascript
微信小程序 本地数据存储实例详解
2017/04/13 Javascript
详解node中创建服务进程
2017/05/09 Javascript
js 两个日期比较相差多少天的实例
2017/10/19 Javascript
JavaScript的数据类型转换原则(干货)
2018/03/15 Javascript
vuedraggable+element ui实现页面控件拖拽排序效果
2020/07/29 Javascript
[01:00:53]OG vs IG 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
[01:00] DOTA2英雄背景故事第五期之重力引力法则谜团
2020/07/16 DOTA
python学习之第三方包安装方法(两种方法)
2015/07/30 Python
Python+Socket实现基于TCP协议的客户与服务端中文自动回复聊天功能示例
2017/08/31 Python
Python处理菜单消息操作示例【基于win32ui模块】
2018/05/09 Python
Python实现Dijkstra算法
2018/10/17 Python
解决pyinstaller打包exe文件出现命令窗口一闪而过的问题
2018/10/31 Python
学习python可以干什么
2019/02/26 Python
Python 识别12306图片验证码物品的实现示例
2020/01/20 Python
CSS3 Notes: -webkit-box-reflect实现倒影的实例
2016/12/08 HTML / CSS
HTML5 Canvas中绘制矩形实例
2015/01/01 HTML / CSS
Kipling凯浦林美国官网:世界著名时尚休闲包袋品牌
2016/08/24 全球购物
AOP的定义以及作用
2013/09/08 面试题
作风建设年度心得体会
2014/10/29 职场文书
JavaScript中document.activeELement焦点元素介绍
2021/11/27 Javascript
CSS SandBox应用场景及常见问题
2022/06/25 HTML / CSS