【进阶3-5期】深度解析 new 原理及模拟实现(转)
这是我在公众号(高级前端进阶)看到的文章,现在做笔记
https://github.com/yygmind/blog/issues/24
new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。 ——(来自于MDN)
举个例子:
function Car(color) {
this.color = color;
}
Car.prototype.start = function() {
console.log(this.color + " car start");
}
var car = new Car("black");
car.color; // 访问构造函数里的属性
// black
car.start(); // 访问原型里的属性
// black car start
可以看出 new 创建的实例有以下 2 个特性
- 1、访问到构造函数里的属性
- 2、访问到原型里的属性
注意点
ES6新增 symbol 类型,不可以使用 new Symbol(),因为 symbol 是基本数据类型,每个从Symbol()返回的 symbol 值都是唯一的。
Number(""); //
String(); // "123"
Boolean(); // true
Symbol(); // Symbol(123)
new Number(""); // Number {123}
new String(); // String {"123"}
new Boolean(true); // Boolean {true}
new Symbol(); // Symbol is not a constructor
模拟实现
当代码 new Foo(...) 执行时,会发生以下事情:
- 一个继承自
Foo.prototype的新对象被创建。 - 使用指定的参数调用构造函数
Foo,并将this绑定到新创建的对象。new Foo等同于new Foo(),也就是没有指定参数列表,Foo不带任何参数调用的情况。 - 由构造函数返回的对象就是
new表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1创建的对象。
模拟实现第一步
new 是关键词,不可以直接覆盖。这里使用 create 来模拟实现 new 的效果。
new 返回一个新对象,通过 obj.__proto__ = Con.prototype 继承构造函数的原型,同时通过 Con.apply(obj, arguments)调用父构造函数实现继承,获取构造函数上的属性(【进阶3-3期】)。
实现代码如下:
// 第一版
function create() {
// 创建一个空的对象
var obj = new Object(),
// 获得构造函数,arguments中去除第一个参数
Con = [].shift.call(arguments);
// 链接到原型,obj 可以访问到构造函数原型中的属性
obj.__proto__ = Con.prototype;
// 绑定 this 实现继承,obj 可以访问到构造函数中的属性
Con.apply(obj, arguments);
// 返回对象
return obj;
};
测试一下
// 测试用例
function Car(color) {
this.color = color;
}
Car.prototype.start = function() {
console.log(this.color + " car start");
} var car = create(Car, "black");
car.color;
// black car.start();
// black car start
完美!
不熟悉 apply / call 的点击查看:【进阶3-3期】深度解析 call 和 apply 原理、使用场景及实现
不熟悉继承的点击查看:JavaScript常用八种继承方案
模拟实现第二步
上面的代码已经实现了 80%,现在继续优化。
构造函数返回值有如下三种情况:
- 1、返回一个对象
- 2、没有
return,即返回undefined - 3、返回
undefined以外的基本类型
情况1:返回一个对象
function Car(color, name) {
this.color = color;
return {
name: name
}
}
var car = new Car("black", "BMW");
car.color;
// undefined
car.name;
// "BMW"
实例 car 中只能访问到返回对象中的属性。
情况2:没有 return,即返回 undefined
function Car(color, name) {
this.color = color;
}
var car = new Car("black", "BMW");
car.color;
// black
car.name;
// undefined
实例 car 中只能访问到构造函数中的属性,和情况1完全相反。
情况3:返回undefined 以外的基本类型
function Car(color, name) {
this.color = color;
return "new car";
}
var car = new Car("black", "BMW");
car.color;
// black
car.name;
// undefined
实例 car 中只能访问到构造函数中的属性,和情况1完全相反,结果相当于没有返回值。
所以需要判断下返回的值是不是一个对象,如果是对象则返回这个对象,不然返回新创建的 obj对象。
所以实现代码如下:
// 第二版
function create() {
// 创建一个空的对象
var obj = new Object(),
// 获得构造函数,arguments中去除第一个参数
Con = [].shift.call(arguments);
// 链接到原型,obj 可以访问到构造函数原型中的属性
obj.__proto__ = Con.prototype;
// 绑定 this 实现继承,obj 可以访问到构造函数中的属性
var ret = Con.apply(obj, arguments);
// 优先返回构造函数返回的对象
return typeof ret === 'object' ? ret : obj;
};
【进阶3-5期】深度解析 new 原理及模拟实现(转)的更多相关文章
- 【进阶3-4期】深度解析bind原理、使用场景及模拟实现(转)
这是我在公众号(高级前端进阶)看到的文章,现在做笔记 https://github.com/yygmind/blog/issues/23 bind() bind() 方法会创建一个新函数,当这个新函 ...
- 深度解析 Vue 响应式原理
深度解析 Vue 响应式原理 该文章内容节选自团队的开源项目 InterviewMap.项目目前内容包含了 JS.网络.浏览器相关.性能优化.安全.框架.Git.数据结构.算法等内容,无论是基础还是进 ...
- mysql索引原理深度解析
mysql索引原理深度解析 一.总结 一句话总结: mysql索引是b+树,因为b+树在范围查找.节点查找等方面优化 hash索引,完全平衡二叉树,b树等 1.数据库中最常见的慢查询优化方式是什么? ...
- java8Stream原理深度解析
Java8 Stream原理深度解析 Author:Dorae Date:2017年11月2日19:10:39 转载请注明出处 上一篇文章中简要介绍了Java8的函数式编程,而在Java8中另外一个比 ...
- 并发编程(十五)——定时器 ScheduledThreadPoolExecutor 实现原理与源码深度解析
在上一篇线程池的文章<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中从ThreadPoolExecutor源码分析了其运行机制.限于篇幅,留下了Scheduled ...
- 并发编程(十二)—— Java 线程池 实现原理与源码深度解析 之 submit 方法 (二)
在上一篇<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法.这篇文章是接着上一篇文章 ...
- spring5 源码深度解析----- 被面试官给虐懵了,竟然是因为我不懂@Configuration配置类及@Bean的原理
@Configuration注解提供了全新的bean创建方式.最初spring通过xml配置文件初始化bean并完成依赖注入工作.从spring3.0开始,在spring framework模块中提供 ...
- VueRouter 源码深度解析
VueRouter 源码深度解析 该文章内容节选自团队的开源项目 InterviewMap.项目目前内容包含了 JS.网络.浏览器相关.性能优化.安全.框架.Git.数据结构.算法等内容,无论是基础还 ...
- 《SEO深度解析——全面挖掘搜索引擎优化的核心秘密》
<SEO深度解析——全面挖掘搜索引擎优化的核心秘密> 基本信息 作者: 痞子瑞 出版社:电子工业出版社 ISBN:9787121224041 上架时间:2014-2-28 出版日期:201 ...
随机推荐
- 二十一、Linux 进程与信号---进程资源限制
21.1 进程资源限制 在操作系统中,我们能够通过函数getrlimit().setrlimit()分别获得.设置每个进程能够创建的各种系统资源的限制使用量. 21.1.1 函数 #include & ...
- pom样板
<properties> <java.version>1.6</java.version> <project.build.sourceEncoding> ...
- 深度理解PHP中for与foreach两个循环结构遍历数组的区别
遍历一个数组是编程中最常见不过的了,这里讨论下for和foreach两种方法: 首先,我们先准备两个用于遍历的数组: $arr1=array(1=>'a', 3=>22, 5=>'b ...
- Apache的域名配置
配置独立域名有什么好处呢?我们在本地做程序开发,要同时用很多开源程序.CMS.框架,或者自己写的管理系统,那么给他们每一个都配置一个独立的域名,在测试的时候只要在浏览器输入设置好的域名就可以了,非常方 ...
- 前端向服务器请求数据并渲染的方式(ajax/jQuery/axios/vue)
原理: jQuery的ajax请求:complete函数一般无论服务器有无数据返回都会显示(成功或者失败都显示数据): return result
- Shiro入门 - 通过自定义Realm连数数据库进行授权
shiro-realm.ini [main] #自定义Realm myRealm=test.shiro.MyRealm #将myRealm设置到securityManager,相当于Spring中的注 ...
- MySql cmd下的学习笔记 —— 有关多表查询的操作(多表查询练习题及union操作)
先建立一张 m 表 mysql> create table m ( -> mid int, -> hid int, -> gid int, ), -> matime da ...
- springboot中使用过滤器、拦截器、监听器
监听器:listener是servlet规范中定义的一种特殊类.用于监听servletContext.HttpSession和servletRequest等域对象的创建和销毁事件.监听域对象的属性发生 ...
- Vue获取事件源
设置事件源 <label :data-weight="item1.EvaluateWeight" @click='radioClick' :data-id="ite ...
- MySQL常用的sql操作
1.日期时间格式化 2.日期时间格式化 3.查询第11到第15条数据 ,5//落过多少,取出多少. 4.字符串转日期 select str_to_date('2016-01-02', '%Y-%m-% ...