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 相关文章推荐
一些技巧性实用js代码小结
Oct 14 Javascript
js实现addClass,removeClass,hasClass的函数代码
Jul 13 Javascript
JS随即打乱数组实现代码
Dec 03 Javascript
使用GruntJS构建Web程序之安装篇
Jun 04 Javascript
浅谈js中的闭包
Mar 16 Javascript
web打印小结
Jan 11 Javascript
jQuery利用FormData上传文件实现批量上传
Dec 04 jQuery
Nuxt.js 数据双向绑定的实现
Feb 17 Javascript
详解package.json版本号规则
Aug 01 Javascript
jQuery 选择器用法基础入门示例
Jan 04 jQuery
JavaScript简单编程实例学习
Feb 14 Javascript
vue 项目软键盘回车触发搜索事件
Sep 09 Javascript
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
解析php中反射的应用
2013/06/18 PHP
php中最简单的字符串匹配算法
2014/12/16 PHP
PHP使用Pear发送邮件(Windows环境)
2016/01/05 PHP
PHP正则匹配反斜杠'\'和美元'$'的方法
2017/02/08 PHP
document.all还是document.getElementsByName?
2006/07/21 Javascript
Javascript在IE和FireFox中的不同表现简析
2012/12/03 Javascript
JS对话框_JS模态对话框showModalDialog用法总结
2014/01/11 Javascript
js查找节点的方法小结
2015/01/13 Javascript
Jquery实现动态切换图片的方法
2015/05/18 Javascript
JS在一定时间内跳转页面及各种刷新页面的实现方法
2016/05/26 Javascript
jquery层级选择器的实现(匹配后代元素div)
2016/09/05 Javascript
微信小程序  checkbox组件详解及简单实例
2017/01/10 Javascript
快速掌握jQuery插件开发
2017/01/19 Javascript
Vue + Webpack + Vue-loader学习教程之功能介绍篇
2017/03/14 Javascript
p5.js绘制旋转的正方形
2019/10/23 Javascript
深入浅析vue全局环境变量和模式
2020/04/28 Javascript
ES6新增的数组知识实例小结
2020/05/23 Javascript
vue.js click点击事件获取当前元素对象的操作
2020/08/07 Javascript
[06:36]吞吞映像top1
2014/06/20 DOTA
在Python中操作字典之fromkeys()方法的使用
2015/05/21 Python
详解Python的Django框架中inclusion_tag的使用
2015/07/21 Python
python的concat等多种用法详解
2018/11/28 Python
对python中矩阵相加函数sum()的使用详解
2019/01/28 Python
Python异常处理例题整理
2019/07/07 Python
Django1.11自带分页器paginator的使用方法
2019/10/31 Python
python with语句的原理与用法详解
2020/03/30 Python
python中for in的用法详解
2020/04/17 Python
html5+css3之动画在webapp中的应用
2014/11/21 HTML / CSS
基于html5 canvas做批改作业的小插件
2020/05/20 HTML / CSS
我有一个char * 型指针正巧指向一些int 型变量, 我想跳过它们。 为什么如下的代码((int *)p)++; 不行?
2013/05/09 面试题
马智宇婚礼主持词
2014/03/22 职场文书
《海底世界》教学反思
2014/04/16 职场文书
反洗钱宣传活动总结
2014/08/26 职场文书
先进基层党组织材料
2014/12/25 职场文书
汽车销售合同文本
2019/08/08 职场文书
Windows11性能真的上涨35%? 桌面酷睿i9实测结果公开
2021/11/21 数码科技