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 相关文章推荐
让 JavaScript 轻松支持函数重载 (Part 2 - 实现)
Aug 04 Javascript
jQuery实现鼠标滑过Div层背景变颜色的方法
Feb 17 Javascript
JavaScript构造函数详解
Dec 27 Javascript
基于javascript实现图片懒加载
Jan 05 Javascript
模仿password输入框的实现代码
Jun 07 Javascript
javascript 定时器工作原理分析
Dec 03 Javascript
JS正则RegExp.test()使用注意事项(不具有重复性)
Dec 28 Javascript
轻松理解JavaScript闭包
Mar 14 Javascript
微信小程序利用co处理异步流程的方法教程
May 20 Javascript
jQuery滑动效果实现方法分析
Sep 05 jQuery
vue 移动端适配方案详解
Nov 15 Javascript
JS/HTML5游戏常用算法之碰撞检测 像素检测算法实例详解
Dec 12 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 注释规范
2012/03/29 PHP
php最简单的删除目录与文件实现方法
2014/11/28 PHP
php+mysqli事务控制实现银行转账实例
2015/01/29 PHP
PHP实现的CURL非阻塞调用类
2018/07/26 PHP
在laravel中实现事务回滚的方法
2019/10/10 PHP
JQuery 常用方法基础教程
2009/02/06 Javascript
IE和firefox浏览器的event事件兼容性汇总
2009/12/06 Javascript
zeroclipboard复制到剪切板的flash
2010/08/04 Javascript
jQuery代码优化 事件委托篇
2011/11/01 Javascript
关于Javascript与iframe的那些事儿
2013/07/04 Javascript
jquery幻灯片插件bxslider样式改进实例
2014/10/15 Javascript
AngularJS 实现按需异步加载实例代码
2015/10/18 Javascript
JavaScript继承学习笔记【新手必看】
2016/05/10 Javascript
JavaScript中object和Object的区别(详解)
2017/02/27 Javascript
node.js操作mongodb简单示例分享
2017/05/25 Javascript
jQuery实现拼图小游戏(实例讲解)
2017/07/24 jQuery
jQuery发请求传输中文参数乱码问题的解决方案
2018/05/22 jQuery
ES6知识点整理之函数对象参数默认值及其解构应用示例
2019/04/17 Javascript
JS前端知识点 运算符优先级,URL编码与解码,String,Math,arguments操作整理总结
2019/06/27 Javascript
Python的Flask框架中web表单的教程
2015/04/20 Python
Python 爬虫爬取指定博客的所有文章
2016/02/17 Python
使用Python中的reduce()函数求积的实例
2019/06/28 Python
python加密解密库cryptography使用openSSL生成的密匙加密解密
2020/02/11 Python
Python基于staticmethod装饰器标示静态方法
2020/10/17 Python
python 用struct模块解决黏包问题
2020/11/07 Python
美国亚马逊旗下男装网站:East Dane(支持中文)
2019/09/25 全球购物
Yahoo的PHP面试题
2014/05/26 面试题
C#软件工程师英语面试题
2015/06/07 面试题
应付会计岗位职责
2013/12/12 职场文书
满月酒答谢词
2014/01/14 职场文书
授权收款委托书范本
2014/10/10 职场文书
2014购房个人委托书范本
2014/10/12 职场文书
2016秋季校长开学典礼致辞
2015/11/26 职场文书
大学生学习十八届五中全会精神心得体会
2016/01/05 职场文书
解决go在函数退出后子协程的退出问题
2021/04/30 Golang
一起来看看Vue的核心原理剖析
2022/03/24 Vue.js