详解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加ASP二级域名转向的代码
May 17 Javascript
IE和Firefox下event事件杂谈
Dec 18 Javascript
使用dynatrace-ajax跟踪JavaScript的性能
Apr 12 Javascript
js滚动条回到顶部的代码
Dec 06 Javascript
js不完美解决click和dblclick事件冲突问题
Jul 16 Javascript
Boostrap基础教程之JavaScript插件篇
Sep 08 Javascript
微信小程序 图片绝对定位(背景图片)
Apr 05 Javascript
详解AngularJS跨页面传值(ui-router)
Aug 23 Javascript
jQuery图片加载失败替换默认图片方法汇总
Nov 29 jQuery
vue+element加入签名效果(移动端可用)
Jun 17 Javascript
ES6函数实现排它两种写法解析
May 13 Javascript
区分vue-router的hash和history模式
Oct 03 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 Token(令牌)设计
2008/03/15 PHP
php 前一天或后一天的日期
2008/06/28 PHP
php生成固定长度纯数字编码的方法
2015/07/09 PHP
PHP中include()与require()的区别说明
2017/02/14 PHP
javascript静态的url如何传递
2007/05/03 Javascript
jQuery 数据缓存模块进化史详细介绍
2012/11/19 Javascript
百度地图API之本地搜索与范围搜索
2015/07/30 Javascript
jQuery实现横向带缓冲的水平运动效果(附demo源码下载)
2016/01/29 Javascript
js仿QQ中对联系人向左滑动、滑出删除按钮的操作
2016/04/07 Javascript
JavaScript构建自己的对象示例
2016/11/29 Javascript
微信小程序 页面跳转及数据传递详解
2017/03/14 Javascript
vue基于Vue2.0和高德地图的地图组件实例
2017/04/28 Javascript
Javascript 一些需要注意的细节(必看篇)
2017/07/08 Javascript
Angularjs中ng-repeat的简单实例
2017/08/25 Javascript
vue.js实现简单轮播图效果
2017/10/10 Javascript
使用clipboard.js实现复制功能的示例代码
2017/10/16 Javascript
Vue源码学习之初始化模块init.js解析
2017/11/02 Javascript
JavaScript中使用import 和require打包后实现原理分析
2018/03/07 Javascript
使用 vue-i18n 切换中英文效果
2018/05/23 Javascript
微信小程序接入腾讯云验证码的方法步骤
2020/01/07 Javascript
微信小程序实现手指拖动选项排序
2020/04/22 Javascript
vue-quill-editor 自定义工具栏和自定义图片上传路径操作
2020/08/03 Javascript
[45:16]完美世界DOTA2联赛PWL S3 Magma vs Phoenix 第一场 12.12
2020/12/16 DOTA
Python对象的深拷贝和浅拷贝详解
2014/08/25 Python
Python实现Const详解
2015/01/27 Python
简单谈谈Python流程控制语句
2016/12/04 Python
Ubuntu+python将nii图像保存成png格式
2019/07/18 Python
Win10环境python3.7安装dlib模块趟过的坑
2019/08/01 Python
python 实现两个npy档案合并
2020/07/01 Python
canvas里面如何基于随机点绘制一个多边形的方法
2018/06/13 HTML / CSS
标记环介质访问控制协议
2016/03/27 面试题
企业党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
个人求职自荐信范文
2015/03/06 职场文书
关于React Native使用axios进行网络请求的方法
2021/08/02 Javascript
《传颂之物 虚伪的假面》BD发售宣传CM公开
2022/04/04 日漫
《火纹风花雪月无双》预告“神秘雇佣兵” 紫发剑客
2022/04/13 其他游戏