JavaScrpt的面向对象全面解析

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

每次说到javascript的面向对象,总感觉自己心里懂,但是却不知道该怎么说,这就是似懂非懂到表现,于是乎,每次一说,就要到处去查找资料,零零碎碎到看了一些,感觉有懂了,但是过段时间,好像又不知道是怎么回事了,于是乎,又到处找资料,然道是我本来就缺对象?才不理解对象是啥,以至于现实中找找对象,javascript中也在找对象!哎,好尴尬啊!直到我看到了一个妹纸写到“不可不知的javascript面向对象”,我才明白面向对象是什么,这是不是说我要找到对象就是这个妹纸呢😄,先记录一下备忘吧,下面是妹纸写到主要内容:

对象的创建:

1 创建一个面向对象

var obj = new Object(); 
obj.name = 'haha';
obj.showName = function(){ 
 alert(obj.name);
}
obj.showName();

缺点:当我们想创建多个面向对象的时候,重复代码过多,需要封装,所以有了工厂方法。

2 工厂方式

function CreatePerson(name){ 
 var obj = new Object(); //原料
 obj.name = name;   //加工
 obj.showName = function(){
  alert(this.name);
 } 
 return obj;//出厂
}
var p1 = CreatePerson('haha');
p1.showName();
var p2 = CreatePerson('hehe');
p2.showName();
//其实就是简单的封装函数,整个过程像工厂的流水线,所以叫工厂方式

缺点:无法识别创建的对象的类型。因为全部都是Object,没有区分度,不像Date、Array等,因此出现了构造函数模式。

3 构造函数模式

function CreatePerson(name){ 
 this.name = name; 
 this.showName = function(){ 
  alert(this.name);
 } 
} 
var p1 =new CreatePerson('haha'); 
p1.showName();
var p2 = new CreatePerson('hehe'); 
p2.showName(); 

我们通过这二个方面来改变:

1 函数名首字母大写

这是为了区别于普通的函数,构造函数本身其实就是普通的函数,只是我们专门用它来实现了构造的功能,所以专门起了一个名字叫构造函数,任何函数都可以成为构造函数,这取决于你调用函数的方式,当使用了New的方式调用就成了构造函数。

2 New 关键字调用

调用函数的时候用了 New关键字,那么New到底做了什么?用不用New有什么区别?再来看下面的例子

function CreatePerson(name){
 this.name = name;
 this.showName = function(){
  alert(this.name); 
 }; 
 console.log(this);
} 
new CreatePerson('haha'); //CreatePerson
CreatePerson('haha'); //window

我们会发现当用New去调用一个函数的时候,this的指向会不一样。其实New主要做了下面这些事,不过下面写的只是大概的行为,并不是内部源码。

function CreatePerson(name){ 
 var obj = {}; //声明一个空对象obj 
 obj._proto_= CreatePerson.prototype;
 //把这个对象的_proto_属性指向构造函数的原型对象,这样obj就可以调用CreatePerson原型对象下的所有方法 ,这里原型先知道结论,下面会讲。
 CreatePerson.apply(obj); //用apply方法让this指向obj对象
 this.name = name; //obj对象添加属性,方法
 this.showName = function(){ 
  alert(this.name);
  }; 
 return obj;//返回这个对象
}

函数构造模式存在的问题:

alert(p1.showName==p2.showName);//false

缺点:可见这两个对象并不是共用一个方法,每new一次,系统都会新创建一个内存,这两个对象各自有各自的地盘,但他们具有相同的功能,还不共用,肯定不是我们所希望的。所以就有了下一种方法,原型+构造模式

4 原型+构造模式

原型:每个函数都有一个prototype属性,它是一个对象,也称作原型对象,我们可以把方法和属性写在它上面(不过原型对象不仅仅有我们写的属性和方法,还有别的,下面会介绍),而通过这个函数创建出来的实例对象,都能共享这个原型对象下的方法和属性。所以我们只需要把想要共享的东西放在函数的prototype下,不想共享的东西通过构造函数来创建就可以了。
看个栗子(原型+构造)

function CreatePerson(name){ 
 this.name = name;
}
CreatePerson.prototype.showName = function(){ 
 alert(this.name);
}
var p1 =new CreatePerson('haha');
p1.showName();
var p2 = new CreatePerson('hehe');
p2.showName();
alert(p1.showName==p2.showName);//true

测试为true,可见showName()方法是共享的,也就是说他们共用一个内存,更进一步的说它们存在引用关系,也就是说你更改了p1的showName也会影响p2的showName。

_proto_属性:

同一个函数造出来的实例对象能共享这个函数的prototype下的方法和属性,但是它是如何做到的呢?这里要出场的就是_proto_属性.

每个实例化对象都有_proto_属性,它是一个指针,指向函数的prototype,也就是保存了它的地址。(JS中任何对象的值都是保存在堆内存中,我们声明的变量只是一个指针,保存了这个对象的实际地址,所以有了地址就能找到对象),
所以总得来说,每个实例化对象都有_proto_属性,保存了构造函数的原型对象的地址,通过这个属性就可以拥有原型对象下的所有属性和方法,_proto_属性实际就是实例化对象和原型对象之间的连接

原型链:

每个函数都可以成为构造函数,每个函数都有原型对象,每个原型对象也可以是一个实例化对象,比如,你创建了一个函数fun,它是构造函数function的实例化对象,而function的原型对象,又是Object的实例对象。所以fun有个_proto_属性可以访问到function的原型对象,function原型对象也是个实例对象,也有个_proto_属性,可以访问到Object的原型对象,所以通过_proto_属性,就形成了一条原型链。每个实例化对象都可以访问到链子上方的方法和属性,所以fun是可以访问Object原型对象下的方法和属性的。实际上所有对象都可以访问到Object的原型对象。

原型链的访问规则:先在自身的下面寻找,再去一级一级的往原型链上找。

如下:

function Aaa(){}
Aaa.prototype.num = 3;
var a1 = new Aaa();
a1.num =10;
alert(a1.num); //10

原型对象:

原型对象下可能有三种属性:

1 原型对象所带方法和属性 2 constructor 3_proto_属性

constructor:构造函数属性,每个函数的原型对象都有的默认属性,指向函数。

每个实例化对象本身是没有constructor属性的,他们下面默认只有一个_proto_属性,用来连接原型对象,而和构造函数本身是没有直接的联系的。所以它的constructor是访问的原型对象上的。所以当原型对象的constructor变化了,实例化对象的constructor也会改变。但是如果这个对象本身既是原型对象,又是实例化对象,那就拥有了constructor属性,无需从原型对象上面访问。**

看下面的例子,来验证我们所说的:

function CreatePerson(name){ 
 this.name = name;
}
CreatePerson.prototype.showName = function(){ 
 console.log(this.name);
 };
var p1 =new CreatePerson('haha');
p1.showName();
console.log(p1.constructor); // CreatePerson 来自CreatePerson.prototype
console.log(CreatePerson.prototype); 
// {showName:{},constructor:CreatePerson,__proto__:Object.prototype}
//可见,原型对象保存了
  1 自身添加的方法,
  2 构造函数constructor 
  3 _proto_(和上一层构造函数原型对象的连接)
console.log(CreatePerson.prototype.__proto__===Object.prototype);
// true 这个原型对象本身又是object的实例化对象,所有_proto_指向Object的原型对象
console.log(CreatePerson.prototype.__proto__===Object);
// false 可见是和构造函数下原型对象的连接,不是构造函数
console.log(CreatePerson.prototype.constructor);
//CreatePerson CreatePerson.prototype是Object实例化对象,也是原型对象,所以自身拥有constructor属性
console.log(Object.prototype.__proto__); 
// null 原型链的终点是null
console.log(CreatePerson.__proto__); //function.prototype
// CreatePerson本身既是构造函数又是function的实例化对象,拥有_proto_属性,指向function的原型对象
console.log(CreatePerson.constructor); 
// function 继承自function.prototype
console.log(CreatePerson.prototype instanceof CreatePerson ) 
//验证是否在一条原型链上 false

字面量法定义原型:

为了创建对象的代码更方便,你一定见过这样的代码,就是字面量法:

function Aaa(){}
Aaa.prototype = { 
 showName:function(){},
 showSex:function(){}
}; 
var a1 = new Aaa();
console.log(Aaa.prototype);
//{showName:function(){},_proto_} 
//你会发现constructor不见了,因为这种方式相当于重新赋值了Aaa.prototype 
console.log(Aaa.prototype.constructor);
//Object 因为自身没有了constructor属性,就去上级原型对象找,找到了Object
console.log(a1.constructor );
//Object 也变了,验证了它是访问的原型对象上的

因此我们在写的时候需要修正一下原型的指向:

function Aaa(){}
Aaa.prototype = { 
constructor:Aaa, 
num1:function(){alert(10);}
}
var a1 = new Aaa();
a1.constructor // Aaa

 以上所述是小编给大家介绍的JavaScrpt的面向对象全面解析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!


# javascript  # 面向对象  # Javascript之面向对象--封装  # JavaScript面向对象分层思维全面解析  # js面向对象实现canvas制作彩虹球喷枪效果  # 归纳下js面向对象的几种常见写法总结  # JavaScript面向对象编写购物车功能  # 它是  # 都有  # 又是  # 存了  # 都是  # 这是  # 也会  # 有个  # 就可以  # 这两个  # 写到  # 创建一个  # 小编  # 是一个  # 也就是说  # 找对象  # 一个函数  # 是个  # 我要 


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


相关推荐: Android仿QQ列表左滑删除操作  Laravel怎么实现微信登录_Laravel Socialite第三方登录集成  JS中对数组元素进行增删改移的方法总结  微信小程序 五星评分(包括半颗星评分)实例代码  打造顶配客厅影院,这份100寸电视推荐名单请查收  JavaScript如何实现倒计时_时间函数如何精确控制  如何使用 jQuery 正确渲染 Instagram 风格的标签列表  Laravel如何清理系统缓存命令_Laravel清除路由配置及视图缓存的方法【总结】  JS碰撞运动实现方法详解  详解阿里云nginx服务器多站点的配置  如何在 Telegram Web View(iOS)中防止键盘遮挡底部输入框  Win11摄像头无法使用怎么办_Win11相机隐私权限开启教程【详解】  Windows10电脑怎么设置虚拟光驱_Win10右键装载ISO镜像文件  Laravel如何自定义错误页面(404, 500)?(代码示例)  如何快速搭建高效简练网站?  Laravel如何使用Livewire构建动态组件?(入门代码)  零基础网站服务器架设实战:轻量应用与域名解析配置指南  如何在建站之星绑定自定义域名?  南京网站制作费用,南京远驱官方网站?  ChatGPT常用指令模板大全 新手快速上手的万能Prompt合集  WordPress 子目录安装中正确处理脚本路径的完整指南  怎么用AI帮你设计一套个性化的手机App图标?  Laravel如何优雅地处理服务层_在Laravel中使用Service层和Repository层  装修招标网站设计制作流程,装修招标流程?  详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)  七夕网站制作视频,七夕大促活动怎么报名?  怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?  javascript中数组(Array)对象和字符串(String)对象的常用方法总结  Laravel如何使用Blade组件和插槽?(Component代码示例)  如何用好域名打造高点击率的自主建站?  Laravel Eloquent访问器与修改器是什么_Laravel Accessors & Mutators数据处理技巧  网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?  湖南网站制作公司,湖南上善若水科技有限公司做什么的?  Laravel如何创建和注册中间件_Laravel中间件编写与应用流程  如何快速生成可下载的建站源码工具?  Laravel怎么创建自己的包(Package)_Laravel扩展包开发入门到发布  UC浏览器如何设置启动页 UC浏览器启动页设置方法  uc浏览器二维码扫描入口_uc浏览器扫码功能使用地址  北京网站制作的公司有哪些,北京白云观官方网站?  如何快速搭建高效服务器建站系统?  如何为不同团队 ID 动态生成多个非值班状态按钮  Laravel如何使用Contracts(契约)进行编程_Laravel契约接口与依赖反转  Laravel如何处理异常和错误?(Handler示例)  百度输入法全感官ai怎么关 百度输入法全感官皮肤关闭  Laravel怎么自定义错误页面_Laravel修改404和500页面模板  实现点击下箭头变上箭头来回切换的两种方法【推荐】  如何正确选择百度移动适配建站域名?  Laravel怎么返回JSON格式数据_Laravel API资源Response响应格式化【技巧】  为什么php本地部署后css不生效_静态资源加载失败修复技巧【技巧】  Laravel怎么集成Log日志记录_Laravel单文件与每日日志配置及自定义通道【详解】