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 相关文章推荐
优化网页之快速的呈现我们的网页
Jun 29 Javascript
JS按位非(~)运算符与~~运算符的理解分析
Jul 31 Javascript
JS实现商品倒计时实现代码
May 03 Javascript
JavaScript第一篇之实现按钮全选、功能
Aug 21 Javascript
jQuery实现手势解锁密码特效
Aug 14 jQuery
vue2.0 自定义 饼状图 (Echarts)组件的方法
Mar 02 Javascript
Vue+axios实现统一接口管理的方法
Jul 23 Javascript
Angular5中状态管理的实现
Sep 03 Javascript
BootStrap模态框闪退问题实例代码详解
Dec 10 Javascript
浅谈Layui的eleTree树式选择器使用方法
Sep 25 Javascript
vue项目中在可编辑div光标位置插入内容的实现代码
Jan 07 Javascript
如何使用RoughViz可视化Vue.js中的草绘图表
Jan 30 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
PHP session常见问题集锦及解决办法总结
2007/03/18 PHP
PHP中集成PayPal标准支付的实现方法分享
2012/02/06 PHP
php daddslashes()和 saddslashes()有哪些区别分析
2012/10/26 PHP
ThinkPHP整合百度Ueditor图文教程
2014/10/21 PHP
ztree获取选中节点时不能进入可视区域出现BUG如何解决
2015/12/03 Javascript
AngularJS下对数组的对比分析
2016/08/24 Javascript
AngularJS中的JSONP实例解析
2016/12/01 Javascript
Vue.js鼠标悬浮更换图片功能
2017/05/17 Javascript
jQuery length 和 size()区别总结
2018/04/26 jQuery
详解各版本React路由的跳转的方法
2018/05/10 Javascript
Vue实现微信支付功能遇到的坑
2019/06/05 Javascript
javascript中的数据类型检测方法详解
2019/08/07 Javascript
简单分析js中的this的原理
2019/08/31 Javascript
Vue.js下拉菜单组件使用方法详解
2019/10/19 Javascript
vue 导出文件,携带请求头token操作
2020/09/10 Javascript
js实现圆形菜单选择器
2020/12/03 Javascript
[02:46]完美世界DOTA2联赛PWL DAY4集锦
2020/11/03 DOTA
python 环境变量和import模块导入方法(详解)
2017/07/11 Python
python运行其他程序的实现方法
2017/07/14 Python
python判断一个数是否能被另一个整数整除的实例
2018/12/12 Python
Python简单实现区域生长方式
2020/01/16 Python
Python如何获取文件路径/目录
2020/09/22 Python
css3 2D图片转动样式可以扩充到Js当中
2014/04/29 HTML / CSS
css3实现平移效果(transfrom:translate)的示例
2020/11/13 HTML / CSS
Vans(范斯)德国官网:美国南加州的原创极限运动潮牌
2017/05/02 全球购物
建筑设计师岗位职责
2013/11/18 职场文书
国税会议欢迎词
2014/01/16 职场文书
客户服务经理岗位职责
2014/01/29 职场文书
外国人聘用意向书
2014/04/01 职场文书
学雷锋活动总结报告
2014/06/26 职场文书
工地门卫岗位职责范本
2014/07/01 职场文书
学习党代会心得体会
2014/09/05 职场文书
2014国庆节幼儿园亲子活动方案
2014/09/16 职场文书
法定代表人授权委托书范文
2014/09/22 职场文书
如何有效防止sql注入的方法
2021/05/25 SQL Server