本文介绍JavaScript 语言中 new 关键字调用构造函数的内部执行细节和模拟实现。

在 JavaScript 语言中,我们通过 new 关键字来调用构造函数以创建实例对象,或者是通过 new关键字来调用类以实例化,class是ES6新增的特性,可以理解为它和构造函数是一样的。

在下面的代码中,我们先提供了构造函数Person,然后设置原型对象并创建了实例对象 p。

/* 01-提供构造函数 */
function Person(name, age) {
this.age = age;
this.name = name;
this.showName = function() {
console.log("姓名:" + this.name);
}
this.showAge = function() {
console.log("年龄:" + this.age);
}
} /* 02-设置原型对象 */
Person.prototype.showInfo = function() {
this.showName();
this.showAge();
} /* 03-创建实例对象 */
let p = new Person("Yong", 16); /* 04-测试代码 */
console.log(p);
p.showInfo(); /* 打印输出结果:
Person {
age: 16,
name: 'Yong',
showName: [Function],
showAge: [Function]
}
姓名:Yong
年龄:16
*/

构造函数的代码如果换成是Class,那结果也是一样的。这里我们需要关注下当使用 new 关键字 来调用构造函数或者类的时候都做了些什么,也就是内部的实现细节,下面通过代码注释的方式来对这些细节进行说明。

/* 01-提供构造函数 */
function Person(name, age) {
/* [1] 创建空对象 */
/* 模拟:let o = {} */ /* [2] 设置原型对象访问 */
/* 模拟:o.__proto__ = Person.prototype; */ /* [3] 修改 this 指向空对象 */
/* 模拟:this = o */ /* [4] 通过 this 来设置实例属性 */
this.age = age;
this.name = name; /* [5] 通过 this 来设置实例方法 */
this.showName = function() {
console.log("姓名:" + this.name);
}
this.showAge = function() {
console.log("年龄:" + this.age);
} /* [6] 默认总是返回内部新创建的对象(this) */
/* 如果主动 return , 若跟的是引用类型则直接返回,值类型则忽略 */
/* 模拟:return this */
} /* 02-设置原型对象 */
Person.prototype.showInfo = function() {
this.showName();
this.showAge();
} /* 03-创建实例对象 */
let p = new Person("Yong", 16);

最后,再花点时间来封装个函数以模拟new 关键字的功能,列出给定代码和测试数据。

/* 01-模拟 new 关键字 */
function mockNew() {
/* [1]-获取构造器 */
/* 说明:arguments类数组执行删除操作,接收删除后的元素 */
let Constructor = [].shift.call(arguments); /* [2]-创建空对象 */
let o = {}; /* [3]-设置新对象的原型指向构造函数的原型对象 */
/* 注意:默认 o.__proto__ 指向的是 Object.prototype */
o.__proto__ = Constructor.prototype; /* [4] 把剩余的参数传递给构造函数(class) */
/* 关键:执行函数Constructor(arguments),并绑定内部的 this */
let instance = Constructor.apply(o, arguments); /* [5] 处理返回值 */
/* 说明:如果是引用类型的数据那么就直接返回,否则总是返回内部新创建的对象 o */
return instance instanceof Object ? instance : o;
} /* 02-提供构造函数(首字母大写区分) */
function Person(name, age) {
this.age = age;
this.name = name;
this.showName = function() {
console.log("姓名:" + this.name);
}
this.showAge = function() {
console.log("年龄:" + this.age);
}
} /* 03-设置原型对象 */
Person.prototype.showInfo = function() {
this.showName();
this.showAge();
} /* 04-测试代码 */
let p1 = mockNew(Person, "Yong", 16);
let p2 = mockNew(Person, "Yi", 18);
console.log(p1, p2);
// Person { age: 16, name: 'Yong', showName: [Function], showAge: [Function] }
// Person { age: 18, name: 'Yi', showName: [Function], showAge: [Function] } p1.showInfo();
/* 姓名:Yong 年龄:16 */

前端开发系列038-基础篇之new关键字的更多相关文章

  1. 从0到1用react+antd+redux搭建一个开箱即用的企业级管理后台系列(基础篇)

    背景 ​ 最近因为要做一个新的管理后台项目,新公司大部分是用vue写的,技术栈这块也是想切到react上面来,所以,这次从0到1重新搭建一个react项目架子,需要考虑的东西的很多,包括目录结构.代码 ...

  2. 前端开发:css基础知识之盒模型以及浮动布局。

    前端开发:css基础知识之盒模型以及浮动布局 前言 楼主的蛮多朋友最近都在学习html5,他们都会问到同一个问题 浮动是什么东西?  为什么这个浮动没有效果?  这个问题楼主已经回答了n遍.今天则是把 ...

  3. ESP8266开发之旅 基础篇① 走进ESP8266的世界

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  4. ESP8266开发之旅 基础篇② 如何安装ESP8266的Arduino开发环境

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  5. ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  6. openlayers5-webpack 入门开发系列一初探篇(附源码下载)

    前言 openlayers5-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载 ...

  7. leaflet-webpack 入门开发系列一初探篇(附源码下载)

    前言 leaflet-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 w ...

  8. 【Windows10 IoT开发系列】配置篇

    原文:[Windows10 IoT开发系列]配置篇 Windows10 For IoT是Windows 10家族的一个新星,其针对不同平台拥有不同的版本.而其最重要的一个版本是运行在Raspberry ...

  9. ESP8266开发之旅 基础篇④ ESP8266与EEPROM

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  10. ESP8266开发之旅 基础篇⑥ Ticker——ESP8266定时库

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

随机推荐

  1. Mybatis的原始的执行方式

    一.通过SqlSessionFactory创建sqlsession,再由Sqlsession获取session对象,然后通过session中的执行器Executor,去执行MapperStatemen ...

  2. firebase studio硬刚cursor,送免费云服务可跑23b大模型

    谷歌IDX提供免费高配云服务器(16核CPU,64G内存,300G硬盘),无需绑卡,只需一个能正常使用的谷歌账号.这是一个非常强大的开发环境,特别适合运行大型AI模型和开发工作. 一.Google I ...

  3. 【Linux】Linux内核模块开发

    Linux内核模块开发 零.关于 1.概述 最近在学习Linux相关的东西,学习了U-Boot的编译,Linux的编译,能够在开发板上运行自己编译的U-Boot和Linux了,那么接下来就是在自己编译 ...

  4. windows快速开启【程序和功能】

    程序和功能一般常用的操作是对软件进行卸载. 方式一: 1. Win+R打开运行 2. 输入appwiz.cpl命令 方式二: 1.Win+X打开快捷开关 2. F进去应用和功能 3.点击右侧程序和功能 ...

  5. API测试基础之http协议

    http简介: http(超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP(传输控制协议)之上.它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应.请求和响应消息的头以ASC ...

  6. MySQL 8.0 修改密码 新建用的正确方式

    mysql 更新完密码,总是拒绝连接.登录失败?MySQL8.0 不能通过直接修改 mysql.user 表来更改密码.正确更改密码的方式备注: 清空root密码MySQL8.0 不能通过直接修改 m ...

  7. 制作带sshd功能的centos镜像

    docker run -it --name node1 docker.io/centos bash  创建node1容器 docker exec -it node1 bash 进入node1 yum ...

  8. LSTM 原理

    之前在讨论 RNN (递归神经网络) 的梯度消失 和 梯度爆炸都会对咱的网络结构产生极大的影响. 梯度爆炸, 也是在参数更新这块, 调整步伐太大, 产生 NaN 或 Inf, 代码就搞崩了直解决梯度消 ...

  9. 神经网络-反向传播BP算法推导

    还是用前向算法的图, 然后仔细一看分类输出, 发现好像错了, 这该如何去反向修改权值呢? 因其是网络结构, 改变一点, 必然会引起一连串的改动, 这个过程, 如何来描述呢? 数学推导 声明变量 首先, ...

  10. 1Panel + MaxKB 对接高德地图 MCP Server

    一.场景说明: 通过 1Panel+MaxKB 两个开源工具实现高德地图(Amap) MCP 服务调用. 二.操作说明 步骤一:完成 1Panel 的安装部署 安装说明:在线安装 - 1Panel 文 ...