不得不看之JavaScript构造函数及new运算符


Posted in Javascript onAugust 21, 2017

JS中的函数即可以是构造函数又可以当作普通函数来调用,当使用new来创建对象时,对应的函数就是构造函数,通过对象来调用时就是普通函数。

普通函数的创建有:显式声明、匿名定义、new Function() 等三种方式。

当通过new来创建一个新对象时,JS底层将新对象的原型链指向了构造函数的原型对象,于是就在新对象和函数对象之间建立了一条原型链,通过新对象可以访问到函数对象原型prototype中的方法和属性。

和其他高级语言一样 Javascript 中也有构造函数和 new 运算符,我们知道 new 是用来实例化一个类,从而在内存中分配一个实例对象。 但在 Javascript 中,万物皆对象,为什么还要通过 new 来产生对象? 本文将带你一起来探索 Javascript 中 new 的奥秘…

1、认识new运算符

function Animal(name){
this.name = name;
}
 Animal.color = "black";
 Animal.prototype.say = function(){
console.log("I'm " + this.name);
 };
 var cat = new Animal("cat");

 console.log(
 cat.name, //cat
 cat.color //undefined
 );
 cat.say(); //I'm cat

 console.log(
 Animal.name, //Animal
 Animal.color //back
 );
 Animal.say(); //Animal.say is not a function

2、代码解读

1-3行创建了一个函数Animal,并在其this上定义了属性:name,name的值是函数被执行时的形参。

第4行在Animal对象(Animal本身是一个函数对象)上定义了一个静态属性:color,并赋值“black”

5-7行在Animal函数的原型对象prototype上定义了一个say()方法,say方法输出了this的name值。

第8行通过new关键字创建了一个新对象cat

10-14行cat对象尝试访问name和color属性,并调用say方法。

16-20行Animal对象尝试访问name和color属性,并调用say方法。

3、重点解析

第8行代码是关键:

var cat = new Animal("cat");

Animal 本身是一个普通函数,但当通过new来创建对象时,Animal就是构造函数。

JS引擎执行这句代码时,在内部做了很多工作,用伪代码模拟其工作流程如下:

new Animal("cat") = {

var obj = {};

obj.__proto__ = Animal.prototype;

var result = Animal.call(obj,"cat");

return typeof result === 'object'? result : obj;
}

(1)创建一个空对象obj;

(2)把obj的proto指向构造函数Animal的原型对象prototype,此时便建立了obj对象的原型链:obj->Animal.prototype->Object.prototype->null

(3)在obj对象的执行环境调用Animal 函数并传递参数“cat”。 相当于var result = obj.Animal(“cat”)。

(4)考察第3步返回的返回值,如果无返回值或者返回一个非对象值,则将obj返回作为新对象;否则会将返回值作为新对象返回。

理解了其运行机制以后,我们知道cat其实就是过程(4)的返回值,因此我们对cat对象的认知就多了一些:

cat的原型链是:cat->Animal.prototype->Object.prototype->null

cat上新增了一个属性:name

分析完了cat的产生过程,我们再看看输出结果:

cat.name -> 在过程(3)中,obj对象就产生了name属性。因此cat.name就是这里的obj.name

cat.color -> cat会先查找自身的color,没有找到便会沿着原型链查找,在上述例子中,我们仅在Animal对象上定义了color,并没有在其原型链上定义,因此找不到。

cat.say -> cat会先查找自身的say方法,没有找到便会沿着原型链查找,在上述例子中,我们在Animal的prototype上定义了say,因此在原型链上找到了say方法。

另外,在say方法中还访问this.name,这里的this指的是其调用者obj,因此输出的是obj.name的值。

对于Animal来说,它本身也是一个对象,因此,它在访问属性和方法时也遵守上述查找规则,所以:

Animal.color -> “black”

Animal.name -> “Animal” , Animal先查找自身的name,找到了name, 但这个name不是我们定义的name,而是函数对象内置的属性。

一般情况下,函数对象在产生时会内置name属性并将函数名作为赋值(仅函数对象)。

Animal.say -> Animal在自身没有找到say方法,也会沿着其原型链查找,话说Animal的原型链是什么呢?

从测试结果看:Animal的原型链是这样的:

Animal->Function.prototype->Object.prototype->null

因此Animal的原型链上没有定义say方法!

4、new存在的意义

认识了new运算符之后,我们再回到开篇提到的问题:JS中万物皆对象,为什么还要通过new来产生对象?

要弄明白这个问题,我们首先要搞清楚cat和Animal的关系:

通过上面的分析,我们发现cat继承了Animal中的部分属性,因此我们可以简单的理解:Animal和cat是继承关系。

另一方面,cat是通过new产生的对象,那么cat到底是不是Animal的实例对象? 我们先来了解一下JS是如何来定义“实例对象”的?

A instanceof B
如果上述表达式为true,JS认为A是B的实例对象,我们用这个方法来判断一下cat和Animal

cat instanceof Animal; //true
从执行结果看:cat确实是Animal实例,要想证实这个结果,我们再来了解一下JS中instanceof的判断规则:

var L = A.__proto__;
var R = B.prototype;
if(L === R)
return true;

如果A的proto 等价于 B的prototype,就返回true

在new的执行过程(2)中,cat的proto指向了Animal的prototype,所以cat和Animal符合instanceof的判断结果。

因此,我们认为:cat 是Animal的实例对象。

5、总结

在Javascript中, 通过new可以产生原对象的一个实例对象,而这个实例对象继承了原对象的属性和方法。因此,new存在的意义在于它实现了Javascript中的继承,而不仅仅是实例化了一个对象!

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助~如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持!

Javascript 相关文章推荐
Javascript 中文字符串处理额外注意事项
Nov 15 Javascript
下载网站打开页面后间隔多少时间才显示下载链接地址的代码
Apr 25 Javascript
js加强的经典分页实例
Mar 15 Javascript
js数字转换为float,取N位小数
Feb 08 Javascript
jQuery实现ajax调用WCF服务的方法(附带demo下载)
Dec 04 Javascript
js获取当前日期时间及其它日期操作汇总
Mar 08 Javascript
AngularJS 作用域详解及示例代码
Aug 17 Javascript
微信小程序(应用号)简单实例应用及实例详解
Sep 26 Javascript
jquery实现弹窗功能(窗口居中显示)
Feb 27 Javascript
从零开始学习Node.js系列教程三:图片上传和显示方法示例
Apr 13 Javascript
微信小程序实现自定义picker选择器弹窗内容
May 26 Javascript
vue-cli脚手架build目录下utils.js工具配置文件详解
Sep 14 Javascript
JavaScript实现简单图片轮播效果
Aug 21 #Javascript
Javascript中 toFixed四舍六入方法
Aug 21 #Javascript
webpack使用 babel-loader 转换 ES6代码示例
Aug 21 #Javascript
JavaScript创建对象的七种方式全面总结
Aug 21 #Javascript
webpack处理 css\less\sass 样式的方法
Aug 21 #Javascript
Vue中建立全局引用或者全局命令的方法
Aug 21 #Javascript
JS实现身份证输入框的输入效果
Aug 21 #Javascript
You might like
需要使用php模板的朋友必看的很多个顶级PHP模板引擎比较分析
2008/05/26 PHP
PHP实现更新中间关联表数据的两种方法
2014/09/01 PHP
PHP的拦截器实例分析
2014/11/03 PHP
Ajax+PHP实现的模拟进度条功能示例
2019/02/11 PHP
PHP实现的权重算法示例【可用于游戏根据权限来随机物品】
2019/02/15 PHP
用js 让图片在 div或dl里 居中,底部对齐
2008/01/21 Javascript
validator验证控件使用代码
2010/11/23 Javascript
web前端开发也需要日志
2010/12/09 Javascript
javascript实现rgb颜色转换成16进制格式
2015/07/10 Javascript
基于JavaScript实现右键菜单和拖拽功能
2016/11/28 Javascript
基于JavaScript实现复选框的全选和取消全选
2017/02/09 Javascript
js使用generator函数同步执行ajax任务
2017/09/05 Javascript
React Native中的RefreshContorl下拉刷新使用
2017/10/09 Javascript
手把手教你使用TypeScript开发Node.js应用
2019/05/06 Javascript
完美解决vue 中多个echarts图表自适应的问题
2020/07/19 Javascript
[05:13]2018DOTA2亚洲邀请赛主赛事第二日战况回顾 LGD、VG双雄携手晋级
2018/04/05 DOTA
简单讲解Python中的数字类型及基本的数学计算
2016/03/11 Python
使用XML库的方式,实现RPC通信的方法(推荐)
2017/06/14 Python
Python简单实现两个任意字符串乘积的方法示例
2018/04/12 Python
详解python读取image
2019/04/03 Python
python对象转字典的两种实现方式示例
2019/11/07 Python
使用CSS3的appearance属性改变任何元素的浏览器默认风格
2012/12/24 HTML / CSS
使用HTML5的File实现base64和图片的互转
2013/08/01 HTML / CSS
Html5页面点击遮罩层背景关闭遮罩层
2020/11/30 HTML / CSS
英国独特的时尚和生活方式品牌:JOY
2018/03/17 全球购物
什么是Smarty变量操作符?如何使用Smarty变量操作符
2014/07/18 面试题
new修饰符是起什么作用
2015/06/28 面试题
百度JavaScript笔试题
2015/01/15 面试题
2014年消防工作总结
2014/11/21 职场文书
工作自我推荐信范文
2015/03/25 职场文书
七年级作文之《我和我的祖国》观后感作文
2019/10/18 职场文书
PyTorch dropout设置训练和测试模式的实现
2021/05/27 Python
数据库之SQL技巧整理案例
2021/07/07 SQL Server
JMeter对MySQL数据库进行压力测试的实现步骤
2022/01/22 MySQL
为自由献出你的心脏!「进击的巨人展 FINAL」2022年6月在台开展
2022/04/13 日漫
vue3种table表格选项个数的控制方法
2022/04/14 Vue.js