千家信息网

JS面向对象,创建,继承

发表于:2025-02-23 作者:千家信息网编辑
千家信息网最后更新 2025年02月23日,1 创建一个面向对象var obj = new Object(); //创建一个空对象obj.name = 'haha';obj.showName = function(){ alert(
千家信息网最后更新 2025年02月23日JS面向对象,创建,继承

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 构造函数模式

我们要通过这二个方面来改变:1 函数名首字母大写 2 New 关键字调用

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有什么区别?再来看下面的例子

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 res = {};  //声明一个空对象res  res._proto_= CreatePerson.prototype;//这个对象的_proto_属性指向构造函数的原型对象,这样res就可以调用CreatePerson原型对象下的所有方法  CreatePerson.apply(res);//把this指向改为res对象  this.name = name;  //res对象添加属性,方法  this.showName = function(){     alert(this.name);   };  return res;//返回这个对象}

关于New做时候都是内部的行为,看不到但确实存在,关于上面原型可以先大概知道结论,下面会说原型,接着看就懂了。

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

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属性,无需从原型对象继承。

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

.name ==  p1 = CreatePerson('haha'console.log(CreatePerson.prototype.__proto__===Object.prototype);console.log(CreatePerson.prototype.__proto__===Object);console.log(CreatePerson.constructor); console.log(CreatePerson.prototype  CreatePerson )

字面量法定义原型

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

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

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

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


对象 原型 函数 属性 方法 实例 模式 指向 时候 就是 也就是 代码 地址 方式 面的 两个 也就是说 内存 只是 实际 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 数据库减负系统 长沙薪水2018软件开发 网络安全海报大赛 郑州富士康 软件开发 服务器我的世界网易版 高速公路计算机网络安全 地下城与勇士是什么软件开发的 杨浦区品牌软件开发业务流程 轻量服务器能搭设服务端吗 2022年春季网络安全课 如何防范网络安全800字 陕西松毅软件开发年终奖 数据库设计课程表 地下城新服务器什么时候上线 如东什么是网络技术排名靠前 天府杯网络安全大赛主页 加强自然灾害风险基础数据库建设 企业服务器可以重启吗 海淀区技术软件开发包括什么 求生之路双人服务器 监控远程服务器 深圳吉通网络技术有限公司 服务器机柜工厂直发 怎样防止网络安全的手抄报 服务器拒绝登录是什么意思 wep服务器架设教程 浙江服务器租用 db2命令窗口连接数据库 腾讯云内容管理数据库使用教程 浙江工商学院网络技术工资
0