深入理解new运算符
在 JavaScript 中,new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。创建一个对象很简单,为什么我们还要多此一举使用 new 运算符呢?它到底有什么样的魔力?
认识 new 运算符
通过下面的例子理解 new 运算符:
function Person (name) {
this.name = name
}
Person.prototype.getName = function () {
console.log(this.name)
}
var joe = new Person('joe')
joe.sayHello = function () {
console.log('Hello!')
}
joe.getName() // joe
joe.sayHello() // Hello!
Person.sayHello() // Uncaught TypeError: Person.sayHello is not a function
Person 是一个普通的函数,当它与 new 运算符一起使用时,Person 就是一个构造函数。通过 new Person('joe') 得到的新对象 joe 继承了 Person 的属性,同时,this 也指向 joe 实例。为 joe 添加的属性 sayHello 不会影响 Person,即 joe 是区别与 Person 的一个新对象。
因此,通过 new 创建的实例对象和构造函数之间建立了一条原型链,并通过原型链赋予实例对象继承属性的能力。
new 的原理和实现
通过上面的分析,new 运算符内部做了如下四个操作:
- 创建一个空的简单 JavaScript 对象(即{});
- 链接新对象(即设置该新对象的构造函数)到函数对象;
- 将新创建的对象作为 this 的上下文;
- 如果该函数没有返回对象,返回新创建的对象。
new 的实现如下:
function newOperator (ctor, ...args) {
var obj = {};
obj.__proto__ = ctor.prototype
var res = ctor.apply(obj, args)
return res || obj;
}
优化一下代码:
function newOperator (ctor, ...args) {
var o = Object.create(ctor.prototype) // 合并第一和第二步:创建一个空的简单 JavaScript 对象(即{}),链接新对象(即设置该新对象的构造函数)到函数对象
return fn.apply(o, args) || o
}
使用 newOperator 函数测试上面 Person 的例子:
function Person(name) {
this.name = name
}
Person.prototype.getName = function () {
console.log(this.name)
}
var joe = newOperator(Person, 'joe')
joe.sayHello = function () {
console.log('Hello!')
}
joe.getName() // joe
joe.sayHello() // Hello!
Person.sayHello() // Uncaught TypeError: Person.sayHello is not a function
结果是一致的。
更好的检查方式是:
function Person(name) {
this.name = name
}
console.log(new Person('joe')) // @1
console.log(newOperator(Person, 'joe')) // @2
@1 和 @2 在控制台的显示信息是一模一样的。
判断是否使用 new 关键字
在 JavaScript 中,一个实例对象的创建必须使用 new 关键字。但是限于 JavaScript 的语法特征,实际上构造函数同样可以像普通函数那样直接执行。那么构造函数内部如何判断是否使用了 new 关键字?
使用 instanceof 检测
通过理解 new 操作符的原理,可知,在执行 new 操作时,构造函数的 prototype 赋值给了实例的 proto 属性。在 JavaScript 中 instanceof 可以用来检测对象的原型链,如:a instanceof A 用来检测 a 是否是 A 的实例(即 a 的原型链中存在原型对象 A)。
function Person () {
if (this instanceof Person) {
console.log('new 调用')
} else {
console.log('普通函数调用')
}
}
const foo = new Person() // new 调用
const bar = Person() // 普通函数调用
使用 new.target 属性
在 ES6 中引入了 new.target 属性,new.target 属性允许你检测函数或构造方法是否是通过 new 运算符被调用的。在通过 new 运算符被初始化的函数或构造方法中,new.target 返回一个指向构造方法或函数的引用。在普通的函数调用中,new.target 的值是 undefined。
function Person () {
console.log(new.target)
}
const foo = new Person() // ƒ Person () { console.log(new.target) }
const bar = Person() // undefined
深入理解new运算符的更多相关文章
- 理解spread运算符与rest参数
理解spread运算符与rest参数 spread运算符与rest参数 是ES6的新语法.它们的作用是什么?能做什么事情? 1. rest运算符用于获取函数调用时传入的参数. function tes ...
- [.net 面向对象编程基础] (6) 基础中的基础——运算符和表达式
[.net 面向对象编程基础] (6) 基础中的基础——运算符和表达式 说起C#运算符和表达式,小伙伴们肯定以为很简单,其实要用好表达式,不是一件容易的事.一个好的表达式可以让你做事半功倍的效果,比如 ...
- JavaScript instanceof 运算符深入剖析
简介: 随着 web 的发展,越来越多的产品功能都放在前端进行实现,增强用户体验.而前端开发的主要语言则是 JavaScript.学好 JavaScript 对开发前端应用已经越来越重要.在开发复杂产 ...
- java中关于移位运算符的demo与总结
首先,移位运算符有三种,其操作类型只支持:byte / short / char / int和long五种. << 左移运算符,表示将左边的操作数的二进制数据向左移动*位,移动后空缺位以0 ...
- JavaScript instanceof 运算符深入剖析【转载】
http://www.ibm.com/developerworks/cn/web/1306_jiangjj_jsinstanceof/ instanceof 运算符简介 在 JavaScript ...
- 一分钟掌握位运算符—与(&)、非(~)、或(|)、异或(^)
第一个版本: 位运算符的计算主要用在二进制中. 实际开发中也经常会遇到需要用到这些运算符的时候,同时这些运算符也被作为基础的面试笔试题. 所以了解这些运算符对程序员来说是十分必要的. 于此,记录下 ...
- JavaScript instanceof 运算符
instanceof运算符简介 在 JavaScript 中 判断一个变量的类型常常会用 typeof 运算符 判断一个实例是否属于某种类型会使用instanceof 与 typeof 方法不同的是, ...
- 对象扩展运算符(…)与rest运算符
对象扩展运算符(…) 当编写一个方法时,我们允许它传入的参数是不确定的.这时候可以使用对象扩展运算符来作参数,看一个简单的列子: function xzdemo(...arg){ console.lo ...
- JavaScript 扩展运算符
扩展运算符格式扩展运算符格式很简单,就是三个点(...) 扩展运算符作用???扩展运算符允许一个表达式在期望多个参数(用于函数调用)或多个元素(用于数组字面量)或多个变量(用于解构赋值)的位置扩展. ...
随机推荐
- Linux网络学习笔记(二):域名解析(DNS)——以 CoreDNS 为例
个人笔记,观点不一定正确. 适合对 Kubernetes 有一定了解的同学. 前言 最近一直在学习 Kubernetes,但是手头没有个自有域名,要测试 ingress 就比较麻烦,每次都是手动改 h ...
- 题解 P4325 【[COCI2006-2007#1] Modulo】
第\(1\)种方法 也是最暴力的一种 我们熟知,\(c++\)中的\(set\)可以既去重,有排序,这题,我们可以用set来搞,虽然我们不需要排序的功能,但毕竟方便,一共是\(10\)个数,所以暴力一 ...
- centos7 LVM扩容案例
测试数据 cd / && dd if=/dev/zero of=file bs=1M count=10000 将磁盘变大的测试命令. 生产环境不要用. 这只是用于测试扩容后的效果 LV ...
- Manjaro更新后 搜狗拼音输入法突然无法正常使用
之前Manjaro已经用了很久了,很多该配置的都已经配置好了,但是搜狗拼音在系统更新后突然无法使用 1检查 如下依赖 2.检查配置文件 3.发现一切配置没问题,此时输入 sogou-qimpanel ...
- 超越Mask-RCNN:谷歌大脑的AI,自己写了个目标检测AI
这是一只AI生出的小AI. 谷歌大脑的Quoc Le团队,用神经网络架构搜索 (NAS) ,发现了一个目标检测模型.长这样: △ 看不清请把手机横过来 它的准确率和速度都超过了大前辈Mask-RCNN ...
- 2020 | 可替代Selenium的测试框架Top15
本文首发于 微信公众号: 软测小生 Selenium是一种开源自动测试工具.它可以跨不同的浏览器和平台在Web应用程序上执行功能,回归,负载测试.Slenium是最好的工具之一,但确实有一些缺点. 业 ...
- Centos 8 安装 Consul-Template
1. 下载安装包( consul-template_0.23.0_linux_amd64.zip 文件 ) 下载地址: https://releases.hashicorp.com/consul-te ...
- IC设计流程概述
芯片设计分为前端设计和后端设计,前端设计(也称逻辑设计)和后端设计(也称物理设计)并没有统一严格的界限,涉及到与工艺有关的设计就是后端设计. Front-end design flow 1. 规格制定 ...
- yum,rpm等失效,使用系统安装包ISO文件降级程序恢复系统
linux平台:REHL6.7 故障原因:由于不小心使用命令yum update nss误升级了工作平台中nss系列工具包导致系统中yum 和 rpm命令执行都报错. 由于yum rpm命令都不好用使 ...
- Java实现3次找到假球
前言 之前老师让写一个程序,就写了写. 正文 题目要求 程序要求 10个铅球中有一个假球(比其他铅球的重量要轻),用天平三次称出假球. 程序设计思路 第一次使用天平分别称5个球,判断轻的一边有假球:拿 ...