JavaScript中new操作符的原理与实现详解
作者:来碗盐焗星球 发布时间:2024-05-22 10:31:07
一、new做了哪些事
先看看new的使用场景:
// 1、创建一个构造函数
function Vehicle(name, price) {
this.name = name
this.price = price
}
?
// 2、new一个实例对象
let truck = new Vehicle()
console.log(truck); //Vehicle { name: undefined, price: undefined }
console.log(Object.prototype.toString.call(truck)); //[object Object]
?
// 传入参数
let car = new Vehicle('car', '¥9999999')
console.log(car);
//Vehicle { name: 'car', price: '¥9999999' }
司空见惯的代码,烂熟于心的写法,那你知道new具体做了哪些事情嘛?从上述代码可以看出,一个构造函数使用new操作符调用的时候,会生成一个具有构造函数相同属性的新对象。是不是很奇怪?明明Vehicle是构造函数:
console.log(typeof Vehicle); //function
然而,经过new的一番操作后,它的实例化是一个对象!!!new到底做了哪些事情呢?对于这个例子,我们可以概括为以下事情:
?
// 第一件:在构造函数内部,创建一个this对象
let this = {
name = name,
price = price
}
?
// 第二件:返回this对象
return this;
?
// 第三件:给this对象的属性赋值
this.name = name
this.price = price
很抽象,看不懂。。。进一步剖析如下:
function Person(name, gender) {
console.log('赋值前的this=', this); //赋值前的this= Person {}
this.name = name
this.gender = gender
console.log('赋值后的this=', this); //赋值后的this= Person { name: '小灰灰', gender: 'boy' }
}
?
let child = new Person('小灰灰', 'boy')//Person { name: '小灰灰', gender: 'boy' }
console.log(child);
由以上代码可以看出,
第一:在构造函数内部有一个空的this对象,通过new操作符,会创建生成一个全新的对象(实例对象)。
第二:实例对象会执行[[Prototype]]( .proto)链接,并且实例对象的this会指向构造函数的this(实例对象会绑定函数调用的this)。通过new创建的实例对象最终被[[Prototype]]( .proto)链接到构造函数的Prototype对象上。也就是说,实例对象的隐式原型===构造函数的显示原型
二、返回不同类型时有哪些表现
创建一个构造函数X,通过new操作符,实例化X得到实例化对象x,打印x,一定会是X{...}这个对象嘛?当构造函数内部有返回值,并且返回的是不同类型的值,打印的结果又会是怎么样呢?
function Student(id, name) {
this.id = id
this.name = name
?
// 返回基本类型的值时:返回的结果依然是对象Student {name:xxx,age:xxx}
// return null //Student { id: '1001', name: 'cat' }
// return undefined //Student { id: '1001', name: 'cat' }
// return 123 //Student { id: '1001', name: 'cat' }
// return 'hello world' //Student { id: '1001', name: 'cat' }
// return true //Student { id: '1001', name: 'cat' }
// return false //Student { id: '1001', name: 'cat' }
//return Symbol('abc') //Student { id: '1001', name: 'cat' }
?
// 返回引用类型时:
//返回空对象时:返回的结果是空对象
// return {} //{}
//返回函数时,返回的结果是函数
return function() {} //[Function (anonymous)]
// return [] //[]
// return new Date() //2022-10-24T04:44:18.581Z
// return new Error() //Error...
}
?
let student = new Student('1001', 'cat')
console.log(student); //构造函数内部返回不同类型的值时,这里的打印结果是一样的吗?
三、手写new的实现原理
思路:new的实现原理核心是new做了哪些事情。
总结:
(1)通过new操作符调用构造函数,会返回一个全新的对象,这个对象的属性是构造函数的参数。
若构造函数内部有返回值,且返回值是基本数据类型(number|string|null|undefined|Symbol|boolean),则实例对象的返回结果是原本的对象;
若返回值是引用数据类型(Object|Array|Function|Date|RegExp|Error),则实例对象的返回的结果就是引用类型对应的值。
(2)通过new操作符创建的实例对象的隐式原型会挂载到构造函数的显示原型上。实例对象.proto==构造函数.prototype。
(3)通过new操作符创建的实例对象的this会绑定调用函数的this 请看如下代码:
// new的实现原理
function newPerson() {
// 先return一个对象
var obj = {};
var constructor = Array.prototype.shift.call(arguments); //把数组的shift方法借给constructor使用
// 实例对象的隐式原型===构造函数的显示原型
obj._proto_ = constructor.prototype;
var result = constructor.apply(obj, arguments);
return typeof result === 'object' && result != 'null' ? result : obj;
}
?
let p = newPerson(Person, 'hunny')
console.log(p); //{ _proto_: {}, name: 'hunny', age: undefined }
来源:https://juejin.cn/post/7158073689408274463


猜你喜欢
- 有的时候取出全部数据库记录也许正好满足你的要求,不过,在大多数情况下我们通常只需得到部分记录。这样一来该如何设计查询呢?当然会更费点脑筋了,
- <%MaxPerPage=8 ’定义页面最大的记录数为8<br>
- 如下所示:import numpy as npb = [[1,2,0],[4,5,0],[7,8,1],[4,0,1],[7,11,1] &
- 我正在用 MySQL 客户端的时候,突然想到如果可以给查询结果添加排名该多好啊,然后就找到了一个简单的解决办法。下面是一个示例表
- 不过由于手机的参数多,且不同的手机其参数差异大,所以参数表结构通常是纵表(一个参数是一行),而不是横表(一个参数是一列),此时使用若干参数来
- python 地图经纬度转换、纠偏的代码如下所示:# -*- coding: utf-8 -*-import jsonimport urll
- 在用Pygame写游戏的时候,有人可能会遇到两个Rect对象碰撞但是对象之间还有空间间隔的问题,这里,将教大家用一种方法精准地检测图像碰撞。
- 这是解释器设置问题,在设置里找到interpreter 找到合适的目录就可以了。因为重装了python导致pycharm找不到路径了。另外,
- 网页过渡是指当浏览者进入或离开网页时,页面呈现的不同的刷新效果,比如卷动、百叶窗等。注:通过模板所建网页无法添加网页过渡效果!制作步骤:1、
- Vue实现文本编译详情模板编译在数据劫持中,我们完成了Vue中data选项中数据的初始操作。这之后需要将html字符串编译为render函数
- 本文实例讲述了Sanic框架应用部署方法。分享给大家供大家参考,具体如下:简介Sanic是一个类似Flask的Python 3.5+ Web
- python的try语句有两种风格一是处理异常(try/except/else)二是无论是否发生异常都将执行最后的代码(try/finall
- SqlServer 在事务中获得自增ID实例代码在sqlserver 中插入数据时,如何返回自增的主键ID,方式有很多,这里提
- 今天做一个超简单的无损放大图片的程序,原理很简单JPG原理:读取原图片的像素点的RGB颜色值并保存到文件内,然后将原图进行翻倍放大,在放大的
- 前言ThinkPHP出于安全的考虑增加了表单令牌Token,由于通过Ajax异步更新数据仅仅部分页面刷新数据,就导致了令牌Token不能得到
- 前言defer是golang语言中的关键字,用于资源的释放,会在函数返回之前进行调用。一般采用如下模式:f,err := os.Open(f
- 三种文件操作比较ioutilbufioos.File当文件较小(KB 级别)时,ioutil > bufio > os。当文件大
- 问题描述现有一个有向赋权图。如下图所示:问题:根据每条边的权值,求出从起点s到其他每个顶点的最短路径和最短路径的长度。说明:不考虑权值为负的
- 最近服务器升级到了win2008 r2,数据库也从sql2000升级到了sql2005,不过安装后发现sql server找不到服务器名这样
- 一、什么是模块容器 -> 数据的封装函数 -> 语句的封装类 -> 方法和属性的封装模块 -> 模块就是程序,模块就