深入理解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 扩展运算符
扩展运算符格式扩展运算符格式很简单,就是三个点(...) 扩展运算符作用???扩展运算符允许一个表达式在期望多个参数(用于函数调用)或多个元素(用于数组字面量)或多个变量(用于解构赋值)的位置扩展. ...
随机推荐
- 重定向 CORS 跨域请求
TL;DR 非简单请求不可重定向,包括第一个preflight请求和第二个真正的请求都不行. 简单请求可以重定向任意多次,但如需兼容多数浏览器,只可进行一次重定向. 中间服务器应当同样配置相关 COR ...
- VirtualBox 安装 Centos8 使用 Xshell 连接
1.下载CentOS CentOS下载地址:https://wiki.centos.org/Download 这里选择本地安装包,网络安装包在安装时需要在线下载资源比较慢 2.安装VirtualBox ...
- 阿里云服务器Ubuntu系统搭建LNMP环境
目录 一.Nginx 安装 二.MySQL安装 三.PHP安装 四.配置Nginx 五.环境测试 六.服务器常用路径 一.Nginx 安装 更新软件源 sudo apt-get update 安装 N ...
- 动态规划(Dynamic Programming)算法与LC实例的理解
动态规划(Dynamic Programming)算法与LC实例的理解 希望通过写下来自己学习历程的方式帮助自己加深对知识的理解,也帮助其他人更好地学习,少走弯路.也欢迎大家来给我的Github的Le ...
- "xaml+cs"桌面客户端跨平台初体验
"Xaml+C#"桌面客户端跨平台初体验 前言 随着 .Net 5的到来,微软在 .Net 跨平台路上又开始了一个更高的起点.回顾.Net Core近几年的成果,可谓是让.Ne ...
- tensorflow 控制流操作,条件判断和循环操作
Control flow operations: conditionals and loops When building complex models such as recurrent neura ...
- 推荐|近期热点机器学习git项目
No1: InterpretML by Microsoft--Machine Learning Interpretability github地址:https://github.com/microso ...
- BZOJ 4472 salesman 题解
题目 某售货员小T要到若干城镇去推销商品,由于该地区是交通不便的山区,任意两个城镇之间都只有唯一的可能经过其它城镇的路线.小T可以准确地估计出在每个城镇停留的净收益.这些净收益可能是负数,即推销商品的 ...
- MySql查询当天、本周、本月、本季度、本年的数据
1.今天 SELECT * FROM 表名 WHERE TO_DAYS(时间字段名) = TO_DAYS(NOW()); 2.昨天 ; 3.本周 SELECT * FROM 表名 WHERE YEAR ...
- CentOS下的Docker离线安装
Linux下离线安装Docker 一.基础环境 1.操作系统:CentOS 7.3 2.Docker版本:18.06.1 官方下载地址(打不开可能很慢) 3.百度云Docker 18.06.1地址:h ...