JS面向对象,创建,继承

网友投稿 229 2022-10-26


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主要做了下面这些事,不过下面写的只是大概的行为,并不是内部源码。

关于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。

所以我们在构造对象的时候,一般是原型模式和构造模式组合使用,变化的用构造模式 不变的公用的用原型模式,就像上面的这个栗子,属性用的构造函数,因为一般不同对象属性都不同,方法用原型模式。

原型链: 每个函数都可以成为构造函数,每个函数都有原型对象,每个原型对象也可以是一个实例化对象,比如,你创建了一个函数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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:有利于SEO的DIV+CSS的命名规则小结
下一篇:Java基础之Object类详解
相关文章

 发表评论

暂时没有评论,来抢沙发吧~