详解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 相关文章推荐
Jquery 在页面加载后执行的几种方式
Mar 14 Javascript
利用javascript实现全部删或清空所选的操作
May 27 Javascript
jQuery将多条数据插入模态框的示例代码
Sep 25 Javascript
jQuery判断当前点击的是第几个li的代码
Sep 26 Javascript
javaScript的函数对象的声明详解
Feb 06 Javascript
js实现ifram取父窗口URL地址的方法
Feb 09 Javascript
javascript运算符——逻辑运算符全面解析
Jun 27 Javascript
老生常谈js中0到底是 true 还是 false
Mar 08 Javascript
jQuery事件对象的属性和方法详解
Sep 09 jQuery
JavaScript面试技巧之数组的一些不low操作
Mar 22 Javascript
jquery.pager.js实现分页效果
Jul 29 jQuery
在vue中使用防抖和节流,防止重复点击或重复上拉加载实例
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
Codeigniter实现智能裁剪图片的方法
2014/06/12 PHP
phplot生成图片类用法详解
2015/01/06 PHP
CI框架表单验证实例详解
2016/11/21 PHP
js静态作用域的功能。
2006/12/25 Javascript
jQuery EasyUI 中文API Layout(Tabs)
2010/04/27 Javascript
兼容IE和Firefox的javascript获取iframe文档内容的函数
2011/08/15 Javascript
JS实现兼容性好,带缓冲的动感网页右键菜单效果
2015/09/18 Javascript
使用jQuery给input标签设置默认值
2016/06/20 Javascript
如何使用jquery实现文字上下滚动效果
2016/10/12 Javascript
Vue.js一个文件对应一个组件实践
2016/10/27 Javascript
ie下js不执行的几种可能
2017/02/28 Javascript
JS常用正则表达式总结【经典】
2017/05/12 Javascript
基于JS实现网页中的选项卡(两种方法)
2017/06/16 Javascript
深入浅析Nodejs的Http模块
2017/06/20 NodeJs
JS实现碰撞检测的方法分析
2018/01/19 Javascript
Ionic学习日记实现验证码倒计时
2018/02/08 Javascript
axios使用拦截器统一处理所有的http请求的方法
2018/11/02 Javascript
vue + typescript + 极验登录验证的实现方法
2019/06/27 Javascript
Python随机生成彩票号码的方法
2015/03/05 Python
Python之py2exe打包工具详解
2017/06/14 Python
Python对象属性自动更新操作示例
2018/06/15 Python
python中dict字典的查询键值对 遍历 排序 创建 访问 更新 删除基础操作方法
2018/09/13 Python
python实现桌面气泡提示功能
2019/07/29 Python
python 递归调用返回None的问题及解决方法
2020/03/16 Python
澳大利亚手表品牌:Time IV Change
2018/10/06 全球购物
Michael Kors英国官网:美国奢侈品品牌
2019/11/13 全球购物
PHP经典面试题
2016/09/03 面试题
库房保管员岗位职责
2014/04/07 职场文书
开学寄语大全
2014/04/08 职场文书
绿色出行口号
2014/06/18 职场文书
践行三严三实心得体会
2014/10/13 职场文书
2014年创卫工作总结
2014/11/24 职场文书
技术股东合作协议书
2014/12/02 职场文书
检讨书范文2000字
2015/01/28 职场文书
Mysql 用户权限管理实现
2021/05/25 MySQL
MYSQL优化之数据表碎片整理详解
2022/04/03 MySQL