Javascript模拟实现new原理解析


Posted in Javascript onMarch 03, 2020

new是JS中的一个关键字,用来将构造函数实例化的一个运算符。例子:

function Animal(name) {
  this.name = name;
}
Animal.prototype.sayName = function() {
  console.log("I'm " + this.name);
}
var cat = new Animal('Tom');
console.log(cat.name); // Tom
console.log(cat.__proto__ === Animal.prototype); // true
cat.sayName(); // I'm Tom

从上面的例子可以得出两点结论:

  • new操作符实例化了一个对象;
  • 这个对象可以访问构造函数的属性;
  • 这个对象可以访问构造函数原型上的属性;
  • 对象的**__proto__**属性指向了构造函数的原型;

由于new是关键字,我们只能去声明一个函数去实现new的功能,首先实现上面的三个特性,第一版代码如下:

附:对原型原型链不熟悉的可以先看理解Javascript的原型和原型链。

// construct: 构造函数
function newFunction() {
 var res = {};
 // 排除第一个构造函数参数
 var construct = Array.prototype.shift.call(arguments);
 res.__proto__ = construct.prototype;
 // 使用apply执行构造函数,将构造函数的属性挂载在res上面
 construct.apply(res, arguments);
 return res;
}

我们测试下:

function newFunction() {
 var res = {};
 var construct = Array.prototype.shift.call(arguments);
 res.__proto__ = construct.prototype;
 construct.apply(res, arguments);
 return res;
}
function Animal(name) {
  this.name = name;
}
Animal.prototype.sayName = function() {
  console.log("I'm " + this.name);
}
var cat = newFunction(Animal, 'Tom');
console.log(cat.name); // Tom
console.log(cat.__proto__ === Animal.prototype); // true
cat.sayName(); // I'm Tom

一切正常。new的特性实现已经80%,但new还有一个特性:

function Animal(name) {
  this.name = name;
  return {
    prop: 'test'
  };
}
var cat = new Animal('Tom');
console.log(cat.prop); // test
console.log(cat.name); // undefined
console.log(cat.__proto__ === Object.prototype); // true
console.log(cat.__proto__ === Animal.prototype); // false

如上,如果构造函数return了一个对象,那么new操作后返回的是构造函数return的对象。让我们来实现下这个特性,最终版代码如下:

// construct: 构造函数
function newFunction() {
 var res = {};
 // 排除第一个构造函数参数
 var construct = Array.prototype.shift.call(arguments);
 res.__proto__ = construct.prototype;
 // 使用apply执行构造函数,将构造函数的属性挂载在res上面
 var conRes = construct.apply(res, arguments);
 // 判断返回类型
 return conRes instanceof Object ? conRes : res;
}

测试下:

function Animal(name) {
  this.name = name;
 return {
  prop: 'test'
  };
}
var cat = newFunction(Animal, 'Tom');
console.log(cat.prop); // test
console.log(cat.name); // undefined
console.log(cat.__proto__ === Object.prototype); // true
console.log(cat.__proto__ === Animal.prototype); // false

以上代码就是我们最终对new操作符的模拟实现。我们再来看下官方对new的解释

引用MDN对new运算符的定义:

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。

new操作符会干下面这些事:

  • 创建一个空的简单JavaScript对象(即{});
  • 链接该对象(即设置该对象的构造函数)到另一个对象 ;
  • 将步骤1新创建的对象作为this的上下文 ;
  • 如果该函数没有返回对象,则返回this。

4条都已经实现。还有一个更好的实现,就是通过Object.create去创建一个空的对象:

// construct: 构造函数
function newFunction() {
 // 通过Object.create创建一个空对象;
 var res = Object.create(null);
 // 排除第一个构造函数参数
 var construct = Array.prototype.shift.call(arguments);
 res.__proto__ = construct.prototype;
 // 使用apply执行构造函数,将构造函数的属性挂载在res上面
 var conRes = construct.apply(res, arguments);
 // 判断返回类型
 return conRes instanceof Object ? conRes : res;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
最新的10款jQuery内容滑块插件分享
Sep 18 Javascript
基于JS判断iframe是否加载成功的方法(多种浏览器)
May 13 Javascript
深入理解JavaScript内置函数
Jun 03 Javascript
angularjs 源码解析之injector
Aug 22 Javascript
Dropzone.js实现文件拖拽上传功能(附源码下载)
Nov 22 Javascript
JS实现的全排列组合算法示例
Oct 09 Javascript
vue 利用路由守卫判断是否登录的方法
Sep 29 Javascript
微信小程序bindinput与bindsubmit的区别实例分析
Apr 17 Javascript
VUEX-action可以修改state吗
Nov 19 Javascript
微信小程序实现文件预览
Oct 22 Javascript
如何使用RoughViz可视化Vue.js中的草绘图表
Jan 30 Vue.js
Vue实现下拉加载更多
May 09 Vue.js
JS面向对象编程——ES6 中class的继承用法详解
Mar 03 #Javascript
JS面向对象编程实现的拖拽功能案例详解
Mar 03 #Javascript
序列化模块json代码实例详解
Mar 03 #Javascript
JS常用排序方法实例代码解析
Mar 03 #Javascript
JS面向对象编程实现的Tab选项卡案例详解
Mar 03 #Javascript
JS面向对象编程基础篇(三) 继承操作实例详解
Mar 03 #Javascript
小程序接入腾讯位置服务的详细流程
Mar 03 #Javascript
You might like
我的论坛源代码(五)
2006/10/09 PHP
ThinkPHP访问不存在的模块跳转到404页面的方法
2014/06/19 PHP
php按字符无乱码截取中文的方法
2015/03/27 PHP
Laravel 微信小程序后端实现用户登录的示例代码
2019/11/26 PHP
封装好的省市地区联动控件附下载
2007/08/13 Javascript
模仿jQuery each函数的链式调用
2009/07/22 Javascript
jQuery入门问答 整理的几个常见的初学者问题
2010/02/22 Javascript
jquery.post用法之type设置问题
2014/02/24 Javascript
js特殊字符过滤的示例代码
2014/03/05 Javascript
jQuery封装的屏幕居中提示信息代码
2016/06/08 Javascript
轻松实现js选项卡切换效果
2016/09/24 Javascript
JavaScript给每一个li节点绑定点击事件的实现方法
2016/12/01 Javascript
BootStrap table删除指定行的注意事项(笔记整理)
2017/02/05 Javascript
详解在React中跨组件分发状态的三种方法
2018/08/09 Javascript
layui对工具条进行选择性的显示方法
2019/09/19 Javascript
如何将Node.js中的回调转换为Promise
2020/11/10 Javascript
jQuery冲突问题解决方法
2021/01/19 jQuery
[01:21]DOTA2新纪元-7.0新版本即将开启!
2016/12/11 DOTA
python中日志logging模块的性能及多进程详解
2017/07/18 Python
python实现linux下抓包并存库功能
2018/07/18 Python
Python代理IP爬虫的新手使用教程
2019/09/05 Python
python二进制读写及特殊码同步实现详解
2019/10/11 Python
numpy创建单位矩阵和对角矩阵的实例
2019/11/29 Python
python 类之间的参数传递方式
2019/12/20 Python
使用pytorch实现可视化中间层的结果
2019/12/30 Python
opencv python如何实现图像二值化
2020/02/03 Python
Python如何输出整数
2020/06/07 Python
Python中对象的比较操作==和is区别详析
2021/02/12 Python
CSS3实现王者荣耀匹配人员加载页面的方法
2019/04/16 HTML / CSS
解释一下抽象方法和抽象类
2016/08/27 面试题
商务英语专业应届毕业生求职信
2013/10/28 职场文书
反腐倡廉警示教育活动心得体会
2014/09/04 职场文书
九一八事变演讲稿
2014/09/05 职场文书
保险公司岗前培训工作总结
2015/10/24 职场文书
HTML5页面音频自动播放的实现方式
2021/06/21 HTML / CSS
分析ZooKeeper分布式锁的实现
2021/06/30 Java/Android