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

发布时间 - 2026-01-11 02:54:01    点击率:

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中的继承,而不仅仅是实例化了一个对象!

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


# JS  # 构造函数  # new运算符  # 关于Js中new操作符的作用详解  # Javascript模拟实现new原理解析  # 浅析JS中NEW的实现原理及重写  # JS使用new操作符创建对象的方法分析  # JavaScript中的 new 命令  # JS重学系列之聊聊new操作符  # 原生JS封装_new函数实现new关键字的功能  # JavaScript new对象的四个过程实例浅析  # 如何自己实现JavaScript的new操作符  # 返回值  # 是一个  # 没有找到  # 运算符  # 便会  # 创建一个  # 会先  # 的是  # 建立了  # 找到了  # 也有  # 就在  # 也会  # 是这样  # 找不到  # 但在  # 继承了  # 并在  # 这个问题  # 我们可以 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 北京的网站制作公司有哪些,哪个视频网站最好?  网站视频制作书签怎么做,ie浏览器怎么将网站固定在书签工具栏?  阿里云高弹*务器配置方案|支持分布式架构与多节点部署  想要更高端的建设网站,这些原则一定要坚持!  JavaScript中如何操作剪贴板_ClipboardAPI怎么用  Laravel如何生成PDF或Excel文件_Laravel文档导出工具与使用教程  如何破解联通资金短缺导致的基站建设难题?  如何快速搭建个人网站并优化SEO?  如何在阿里云服务器自主搭建网站?  焦点电影公司作品,电影焦点结局是什么?  Laravel怎么设置路由分组Prefix_Laravel多级路由嵌套与命名空间隔离【步骤】  laravel怎么用DB facade执行原生SQL查询_laravel DB facade原生SQL执行方法  Laravel如何实现本地化和多语言支持_Laravel多语言配置与翻译文件管理  laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程  浅述节点的创建及常见功能的实现  Laravel如何集成第三方登录_Laravel Socialite实现微信QQ微博登录  高防服务器租用指南:配置选择与快速部署攻略  Laravel API资源类怎么用_Laravel API Resource数据转换  JavaScript如何实现类型判断_typeof和instanceof有什么区别  php中::能调用final静态方法吗_final修饰静态方法调用规则【解答】  如何正确下载安装西数主机建站助手?  Laravel如何使用查询构建器?(Query Builder高级用法)  JavaScript中的标签模板是什么_它如何扩展字符串功能  Laravel如何实现本地化和多语言支持?(i18n教程)  移动端脚本框架Hammer.js  Laravel怎么定时执行任务_Laravel任务调度器Schedule配置与Cron设置【教程】  Laravel Artisan命令怎么自定义_创建自己的Laravel命令行工具完全指南  Laravel如何设置自定义的日志文件名_Laravel根据日期或用户ID生成动态日志【技巧】  Laravel如何使用Service Container和依赖注入?(代码示例)  标题:Vue + Vuex + JWT 身份认证的正确实践与常见误区解析  Laravel如何处理跨站请求伪造(CSRF)保护_Laravel表单安全机制与令牌校验  微信小程序 input输入框控件详解及实例(多种示例)  装修招标网站设计制作流程,装修招标流程?  哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?  HTML5打空格有哪些误区_新手常犯的空格使用错误【技巧】  Laravel Seeder怎么填充数据_Laravel数据库填充器的使用方法与技巧  Laravel如何使用模型观察者?(Observer代码示例)  Laravel控制器是什么_Laravel MVC架构中Controller的作用与实践  Laravel Eloquent关联是什么_Laravel模型一对一与一对多关系精讲  如何在腾讯云服务器快速搭建个人网站?  MySQL查询结果复制到新表的方法(更新、插入)  敲碗10年!Mac系列传将迎来「触控与联网」双革新  bootstrap日历插件datetimepicker使用方法  成都网站制作公司哪家好,四川省职工服务网是做什么用?  php结合redis实现高并发下的抢购、秒杀功能的实例  长沙企业网站制作哪家好,长沙水业集团官方网站?  如何挑选最适合建站的高性能VPS主机?  如何快速上传自定义模板至建站之星?  详解CentOS6.5 安装 MySQL5.1.71的方法  Midjourney怎么调整光影效果_Midjourney光影调整方法【指南】