资讯专栏INFORMATION COLUMN

说清楚javascript面向对象、原型、继承

MartinDai / 1200人阅读

摘要:使用调用构造函数,将构造函数的作用域赋给新对象指向新对象构造函数模式的特点使用构造函数创建的对象实例有特定的类型。说明是的原型属性。

这是两年前写的笔记,自己都有遗忘,相信也会有人不明白,贴在这里。
都是红宝书上的内容,在比较难理解的地方加了一些示例和说明。

es中定义对象为:无需属性的集合、其属性可以包含基本值、对象或者函数。

创建对象 Object实例

创建对象最简单的方法是创建一个Object的实例。

var person =new Object();
person.name="Mike";
person.age=12;
person.job="student";
person.sayName=function(){
};
对象字面量
var person={
      name:"mike",
      age:10,
      job:"student",
      sayName:function(){
        alert(this.name);
      }
 };

Object实例和对象字面量都可以用来创建单个对象,
但是当要创建多个对象就会产生大量重复的代码,由此产生了工厂模式。

工厂模式

工厂模式的特点是用函数来封装创建对象的细节,对外以接口的方式调用。

 function createPerson(name,age,job){
      var obj = new Object();
      obj.name=name;
      obj.age=age;
      obj.job=job;
      obj.sayName=function(){
        alert(this.name);
      }
      return obj;
 }
 var person1=createPerson("Mike",12,"student");

工厂模式虽然解决了创建相似对象重复代码的问题,
但同时还存在一个问题:如何知道对象的类别?由此产生构造函数模式

构造函数模式
  function CreatePerson(name,age,job){
      this.name=name;
      this.age=age;
      this.job=job;
      this.sayName=function(){
        alert(this.name);
      }
 }
  var person1= new CreatePerson("Mi",13,"student");
  var person2= new CreatePerson("Mike",12,"student");
  alert(person2.constructor==CreatePerson);//true
  alert(person1 instanceof CreatePerson);//true
  alert(person2 instanceof CreatePerson);//true
  alert(person2 instanceof Object);//true  使用instanceof来检测对象的类型

构造函数没有返回值,没有显示地创建对象。
使用new调用构造函数,将构造函数的作用域赋给新对象(this指向新对象)
构造函数模式的特点:使用构造函数创建的对象(实例)有特定的类型。这也是构造函数模式胜过工厂模式的地方

构造函数模式的问题:构造函数中方法,在不同的实例中是不同的funciton实例,也就是说不同实例中有不同function(虽然他们的功能相同),
但是这并不是我们希望看到的,更何况function中还有this(指向实例的作用域),所以完全没有必要把功能相同function绑定到特定的实例上。
由此产生了原型模式!
大boss来了,接着说下去

原型模式

关于原型的定义,摘自红宝书:每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
好长一句话!有点晕?直接上代码:

function Person(){
  }
Person.prototype.name="mike";
Person.prototype.age=12;
Person.prototype.job="Software Engneer";
Person.prototype.sayName=function(){
      alert(this.name);
}

var person1=new Person();
alert(Person1.prototype.isPrototypeOf(person5));//true检验实例与原型之间的关系
person1.sayName();//mike
var person2=new Person();
alert(person1.sayName()==person2.sayName());//true


var person6=new Person();
person6.name="ssss";
alert(person6.hasOwnProperty("ssss"));//true


原型链查找属性或方法:

首先查找实例属性:即定义在子类构造函数中或直接添加在实例上的属性
然后查找子类原型属性:包括子类自有的原型属性和,父类的实例属性(子类的原型是父类的实例)(这也就是原型链继承的缺点,父类的实例属性全变成子类的原型属性,那就是所有子类实例共享的,如果又是引用类型,就出大事了。所以很少多带带使用原型链)
最后查找父类的原型属性

function SuperType(){
      this.name="super";
      this.job="student";
}
SuperType.prototype.getSuperValue=function(){
      alert(this.name);
}
SuperType.prototype.sex="man";
function SubType(){
      this.age=12;
}
SubType.prototype=new SuperType();
SubType.prototype.getSubValue=function(){
      alert(this.age);
}
//var person=new SubType();
var instance1=new SubType
alert(instance1 instanceof SubType);//true
alert(instance1 instanceof SuperType);//true
alert(SubType.prototype.isPrototypeOf(instance1));//true
alert(SuperType.prototype.isPrototypeOf(instance1));//true  
person.getSuperValue();
alert(person.constructor==SubType);//false子类的实例的原型对象没有constructor属性
alert(person instanceof SubType);
alert(person instanceof SuperType);
alert(person.job);
alert(person.constructor);//sub的原型指向super的原型,super的原型的constuctor是superType,所以person的
alert(person.hasOwnProperty("name"));//false
alert("name" in person);//true 说明name是sub的原型属性。
alert(person.hasOwnProperty("sex"));//false
alert("sex" in person);//true 说明name是sub的原型属性。,父类中的全部属性都是子类的原型属性
var person1=new SuperType();;
alert(person1.constructor);//

解决原型链缺点的方法:借用构造函数

借用构造函数
function SuperType(name){
  this.colors=["red","yellow","green"];
  this.name=name;
}
function SubType(){
      SuperType.call(this,"Mike");
      this.age=10;
}
var instance1=new SubType();
instance1.colors.push("aa");
alert(instance1.colors);
alert(instance1 instanceof SubType);//true
alert(instance1 instanceof SuperType);//false
alert(SubType.prototype.isPrototypeOf(instance1));//true
alert(SuperType.prototype.isPrototypeOf(instance1));//false
var instance2=new SubType();
alert(instance2.colors);//["red","yellow","green"];

在新实例的环境中调用Super构造函数

var instance3=new SubType();
alert(instance3.hasOwnProperty("name"));
alert(instance3.hasOwnProperty("age"));

在子类中call(借调)父类的构造函数实际上就是为子类添加了实例属性(原来在父类中的实例属性)
即父类的实例属性变成了子类的实例属性(原型链继承中,父类的实例属性变成了子类的原型属性)

组合继承
function SuperType(name){
  this.colors=["red","yellow","green"];
  this.name=name;
}
SuperType.prototype.sayName=function(){
  alert(this.name);
}

function SubType(name,age){
     SuperType.call(this,"Kiko");
      this.age=age;
}
SubType.prototype=new SuperType();
SubType.prototype.constructor=SubType;
SubType.prototype.sayAge=function(){
      alert(this.age);
}
var instance1=new SubType("Kiko",12);
//instance1.sayName();
//instance1.colors.push("ss");
//alert("colors" in instance1);//有属性
//alert(instance1.hasOwnProperty("colors"))
//实例属性 没有这句话的时候//SuperType.call(this,"Kiko");,,是原型属性
//有了这句话变成了实例属性
//alert(instance1.colors);
//instance1.sayAge();
alert(instance1 instanceof SubType);//true
alert(instance1 instanceof SuperType);//true
alert(SubType.prototype.isPrototypeOf(instance1));//true
alert(SuperType.prototype.isPrototypeOf(instance1));//true
alert(Object.keys(SubType.prototype));//colors,name,constructor,sayAge
alert(Object.keys(instance1));//colors,name,age

这两句说明第一:SubType.prototype=new SuperType();父类的所有属性都变成了子类的原型属性
第二:SuperType.call(this,"Kiko");,在子类的构造函数中重写了父类的实例属性,即父类的实例属性变成了子类的实例属性
第三:p149:每当代码读取对象中的某个属性时,都会执行一次搜索,先查找实例属性,再查找原型属性
第四:因此,组合继承中父类中的实例属性既是子类的实例属性也是子类的原型属性,但是在每次使用对象时,查找到实例属性就截止了,
所以表现为父类中的实例属性变成了子类中的实例属性(实例属性覆盖了原型对象上的同名属性)

var instance2=new SubType("hihi",13);
//alert(instance2.colors);

原型式继承
function object(o){
     function F(){}
      F.prototype=o;
      return new F();
}

var person={
      name:"Mike",
      friends:["kiko","Court","Van"]
};
var anotherPerson=object(person);
alert(anotherPerson.name);//
anotherPerson.friends.push("ss");

var yetAnotherPerson=object(person);
alert(yetAnotherPerson.friends);//["kiko","Court","Van","ss"]
寄生式继承
function createAnother(original){
      var clone=object(original);
      clone.sayHi=function(){
    alert("hi");
  }
  return clone;
}
var anotherPerson1=createAnother(person);
anotherPerson.sayHi();//hi

使用寄生式继承来为对象添加函数,会由于不能复用而降低效率,这一点与构造函数模式很类似(同名的方法是不同的function实例)

寄生组合式继承

组合式的缺点是两次调用超类的构造函数:
一,SubType.prototype=new SuperType();父类的所有属性都变成了子类的原型属性
二:SuperType.call(this,"Kiko");,在子类的构造函数中重写了父类的实例属性,即父类的实例属性变成了子类的实例属性
寄生组合式目的是为了省掉第一步多继承的实例属性,在第一步时只继承父类的原型属性,第二步继承实例属性

function object(o){
      function F(){}
      F.prototype=o;
      return new F();
}

function inheritPrototype(SubType,SuperType){
      var prototype=object(SuperType.prototype);
      prototype.constructor=SubType;
      SubType.prototype=prototype;
}
function SuperType(name){
      this.name=name;
      this.colors=["red","blue","yellow"];
}
SuperType.prototype.sayName=function(){
      alert(this.name);
}
SuperType.prototype.job="student";

function SubType(name,age){
    SuperType.call(this,name);//(2)继承实例属性
      this.age=age;
}
inheritPrototype(SubType,SuperType);//(3)继承原型属性
SubType.prototype=new SuperType();//(1)把父类的原型属性和实例属性都继承为原型属性了
SubType.prototype.sayAge=function(){
      alert(this.age);
}
var instance1=new SubType();
alert("name" in instance1);//有属性true
alert(instance1.hasOwnProperty("name"));//false不是实例属性

这两句话检验是否是原型属性,1true,2false,原型属性,1ture,2true实例属性
寄生组合式,name会是实例属性
组合式,把(3)换成(1)name确实也是实例属性,那是因为(2)重新调用了SuperType,覆盖了原型中的同名属性。
可以把(2)去掉,发现name变成了原型属性。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100766.html

相关文章

  • JavaScript进阶学习(二)—— 基于原型继承的js工具库的实现方法

    摘要:一些额外的全局函数命名空间对象接口和构造函数与没有典型的关联,但却是有效的。最后有几点需要说明的是每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。 文章来源:小青年原创发布时间:2016-07-03关键词:JavaScript,原型链,jQuery类库转载需标注本文原始地址: http://zhaomenghuan.githu...

    陈伟 评论0 收藏0
  • 详解javascript的类

    摘要:原文地址详解的类博主博客地址的个人博客从当初的一个弹窗语言,一步步发展成为现在前后端通吃的庞然大物。那么,的类又该怎么定义呢在面向对象编程中,类是对象的模板,定义了同一组对象又称实例共有的属性和方法。这个等同于的属性现已弃用。。 前言 生活有度,人生添寿。 原文地址:详解javascript的类 博主博客地址:Damonare的个人博客   Javascript从当初的一个弹窗语言,一...

    hufeng 评论0 收藏0
  • 详解javascript的类

    摘要:原文地址详解的类博主博客地址的个人博客从当初的一个弹窗语言,一步步发展成为现在前后端通吃的庞然大物。那么,的类又该怎么定义呢在面向对象编程中,类是对象的模板,定义了同一组对象又称实例共有的属性和方法。这个等同于的属性现已弃用。。 前言 生活有度,人生添寿。 原文地址:详解javascript的类 博主博客地址:Damonare的个人博客   Javascript从当初的一个弹窗语言,一...

    marek 评论0 收藏0
  • JavaScript面向对象编程简明教程

    摘要:这样每个实例独享自己的属性,并和其他同类型的实例共享方法构造函数原型以上这种方式定义的类型,可以通过来判断一个实例是否是类型的实际上是通过实例的原型链来判断一个对象是否某个类型的实例的,具体的细节后面会详细介绍。 JavaScript面向对象编程 如何定义自定义类型 首先需要明确,JavaScript并不是传统意义上的OO语言,它并没有class的概念, 而是包含了另一套异常强大的...

    myeveryheart 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<