不得不看之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数据缓存系统实现代码
Oct 24 Javascript
各浏览器中querySelector和querySelectorAll的实现差异分析
May 23 Javascript
js实现点击链接后延迟3秒再跳转的方法
Jun 05 Javascript
javascript数组随机排序实例分析
Jul 22 Javascript
jQuery实现浮动层随浏览器滚动条滚动的方法
Sep 22 Javascript
jQuery插件echarts去掉垂直网格线用法示例
Mar 03 Javascript
js/jq仿window文件夹框选操作插件
Mar 08 Javascript
js+html制作简单日历的方法
Jun 27 Javascript
微信小程序如何获取用户信息
Jan 26 Javascript
Vue拖拽组件开发实例详解
May 11 Javascript
基于vue循环列表时点击跳转页面的方法
Aug 31 Javascript
vue中封装axios并实现api接口的统一管理
Dec 25 Vue.js
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
改造一台复古桌面收音机
2021/03/02 无线电
PHP图片上传类带图片显示
2006/11/25 PHP
php一句话cmdshell新型 (非一句话木马)
2009/04/18 PHP
PHP基础学习之流程控制的实现分析
2013/04/28 PHP
PHP实现在线阅读PDF文件的方法
2015/06/23 PHP
php记录搜索引擎爬行记录的实现代码
2018/03/02 PHP
javascript Object与Function使用
2010/01/11 Javascript
javascript中substr,substring,slice.splice的区别说明
2010/11/25 Javascript
高效率JavaScript编写技巧整理
2013/08/23 Javascript
javascript实现多级联动下拉菜单的方法
2015/02/06 Javascript
jQuery选择器源码解读(二):select方法
2015/03/31 Javascript
jquery+CSS3模拟Path2.0动画菜单效果代码
2015/08/31 Javascript
Web前端框架bootstrap实战【第一次接触使用】
2016/12/28 Javascript
jQuery插件autocomplete使用详解
2017/02/04 Javascript
Axios学习笔记之使用方法教程
2017/07/21 Javascript
OkHttp踩坑随笔为何 response.body().string() 只能调用一次
2018/01/08 Javascript
JavaScript轮播停留效果的实现思路
2018/05/24 Javascript
vue中当图片地址无效的时候,显示默认图片的方法
2018/09/18 Javascript
如何用RxJS实现Redux Form
2018/12/29 Javascript
[01:14:30]TNC vs VG 2019国际邀请赛淘汰赛 胜者组赛BO3 第二场 8.20.mp4
2019/08/22 DOTA
python3新特性函数注释Function Annotations用法分析
2016/07/28 Python
利用ctypes提高Python的执行速度
2016/09/09 Python
Python整型运算之布尔型、标准整型、长整型操作示例
2017/07/21 Python
Django rstful登陆认证并检查session是否过期代码实例
2019/08/13 Python
利用pytorch实现对CIFAR-10数据集的分类
2020/01/14 Python
解决pytorch 模型复制的一些问题
2021/03/03 Python
基于DOM+CSS3实现OrgChart组织结构图插件
2016/03/02 HTML / CSS
HTML5实现表单自动验证功能实例代码
2017/01/11 HTML / CSS
Etam艾格英国官网:法国著名女装品牌
2019/04/15 全球购物
经销商培训邀请函
2014/01/21 职场文书
实现中国梦思想汇报2014
2014/09/13 职场文书
道德模范事迹材料
2014/12/20 职场文书
2015纪念九一八事变84周年演讲稿
2015/03/19 职场文书
2015年全民国防教育日活动总结
2015/03/23 职场文书
数据结构课程设计心得体会
2016/01/15 职场文书
【2·13】一图读懂中国无线电发展
2022/02/18 无线电