最近学习了《Javascript高级程序设计》面向对象部分,结合书中的例子总结一下原型链和继承部分的内容。

创建对象


在Js当中没有类这个概念,当我们想要创建具有相同属性的对象的时候,有如下解决方法:

  • 工厂模式
  • 构造函数模式
  • 原型模式

其中,原型模式在Js中应用更加广泛,下面逐一对上述模式进行介绍。

工厂模式

在ECMAScript中,所谓的工厂模式其实就用一个函数进行封装,创建对象时传入相应的参数即可。

function createPerson(name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.sayName = function() {
alert(this.name);
}
return o;
} var person1 = createPerson("Nick", 20, "Teacher");
var person2 = createPerson("Nancy", 21, "Doctor");

工厂模式一目了然,但它的缺点是,我们无法得知我们创建的person1和person2究竟属于什么类型,我们只知道它们都是object, 但我们希望更加具体。因为它们有相同的行为,我们希望person1和person2都属于一个叫Person的“类”。构造函数模式可以满足这个要求。

构造函数模式

直接上代码:

function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() {
alert(this.name);
}
} var person1 = new Person("Nick", 20, "Teacher");
var person2 = new Person("Nancy", 21, "Doctor");

下面解释一下对象创建的过程,

  1. 首先,new新建一个对象
  2. this指向这个新对象
  3. 执行Person函数中的代码
  4. 返回这个新对象

现在,我们可以看一下person1和person2的类型,

alert(person1 instanceof Object); // true
alert(person1 instanceof Person) // true

用构造函数创建对象也很方便,但有个缺点,注意上面例子中this.sayName方法,这种创建方式意味着我们每创建一个新的Person实例,该实例内部都会新建一个sayName方法。而实际上,这些方法的作用都相同,没有重复创建的必要。如果把这个函数放在构造函数之外,作为全局函数的话,可以解决重复的问题,但却牺牲了Person的封装性,因此我们推荐下一种模式,原型模式。

原型模式

我们需要一个“仓库”存储同一类型的对象的共有的属性和方法,在js里面,这个“仓库”是prototype指向的对象(即__原型对象__)。

我们创建的每一个函数都有一个prototype(原型)属性,这个属性指向“仓库”(prototype本身是一个指针)。只要把所需的函数、属性添加到“仓库”中,便可在该类型对象的实例中共用。

举例如下:

function Person() {
} Person.prototype.name = 'Nicholas';
Person.prototype.age = 29;
Person.prototype.job = 'Software Engineer';
Person.prototype.sayName = function() {
alert(this.name);
} var person1 = new Person();
person1.sayName(); //'Nicholas' var person2 = new Person();
peron2.sayName(); //'Nicholas' alert(person1.sayName() == peron2.sayName()); //true

原型对象

原型对象是一个很重要的概念,它就是我们上面提到的“仓库”(可能比喻不是很恰当),先来理解一下它:

结合刚才的代码,有下图:

有:

  1. 构造函数Person的prototype属性指向Person prototype对象;Person Prototype的constructor又指向Person构造函数;
  2. 实例Person1和Person2的[[prototype]]指针也指向Person prototype对象;

在调用person1.sayName()的时候,解析器会先询问person1中是否有sayName方法,发现没有,就会查找person1的原型;在person1原型中发现有,就会使用原型中的sayName方法;

来看另外一个例子:

function Person() {
} Person.prototype.name = 'Nicholas';
Person.prototype.age = 29;
Person.prototype.job = 'Software Engineer';
Person.prototype.sayName = function() {
alert(this.name);
} var person1 = new Person();
var person2 = new Person(); person1.name = "Gerg"; person1.sayName(); //'Gerg'
person2.sayName(); //'Nicholas'

在这里,可以看到设置了person1的name属性后,该属性即存在于person1实例中,无需再从原型中查找,在person1中,相当于将原型的name属性覆盖。

而person2不受影响。

语法简化:

上面的代码有点冗长,可以用对象字面量来重写原型对象,代码如下:

function Person() {
} Person.prototype = {
constructor : Person,
name : "Nicholas",
age : 29,
job : "software Engineer",
sayName : function() {
alert(this.name);
}
}

原型的动态性:

  1. 对原型的修改会直接反映到每个实例,因为实例的[[prototype]] 实际上是指向原型对象的指针;
  2. 如果直接重写原型对象,原来的原型没有被直接覆盖,而是将构造函数的prototype指向新的原型对象。在此之前所建的实例的[[prototype]]不指向重写后的原型对象。上代码:
function Person() {
} var friend = new Person(); Person.prototype = {
constructor : Person,
name : "Nicholas",
age : 29,
job : "software Engineer",
sayName : function() {
alert(this.name);
}
}
friend.sayName(); //error

从图中可以看出之前生成的实例的原型并没有改变。

构造函数模式和原型模式结合

我们通过构造函数的方式生成每个实例独自享有的属性和方法,通过原型生成共享的属性和方法:

function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.friend = [shelby', 'Court'];
} Person.prototype = {
constructor : Person,
sayName : function() {
alert(this.name);
}
} var person1 = new Person('Nicholas', 29, 'software engineer');
var person2 = new Person('Gerg', 27, 'doctor'); person1.friends.push('Van');
alert(person1.friends); //'shelby, Count, Van'
alert(person2.friends); //'shelby, Count'
alert(person1.friends === person2.friends); // false
alert(person1.sayName === person2.sayName); // true

继承

未完待续...

JavaScript原型链与继承的更多相关文章

  1. JavaScript原型链和继承

    1.概念 JavaScript并不提供一个class的实现,在ES6中提供class关键字,但是这个只是一个语法糖,JavaScript仍然是基于原型的.JavaScript只有一种结构:对象.每个对 ...

  2. [转]深入javascript——原型链和继承

    在上一篇post中,介绍了原型的概念,了解到在javascript中构造函数.原型对象.实例三个好基友之间的关系:每一个构造函数都有一个“守护神”——原型对象,原型对象心里面也存着一个构造函数的“位置 ...

  3. JavaScript原型链及继承

    在JavaScript中,所有的东西都是对象,但是JavaScript中的面向对象并不是面向类,而是面向原型的,这是与C++.Java等面向对象语言的区别,比较容易混淆,因此把我自己学习的过程记录下来 ...

  4. 白话JavaScript原型链和继承

    原型基础 每个函数都有一个prototype属性,指向函数的原型对象 每个对象都一个私有属性 __proto__, 默认指向其构造函数的prototype 在JS中所有函数都是Function构造出来 ...

  5. javascript原型链继承

    一.关于javascript原型的基本概念: prototype属性:每个函数都一个prototype属性,这个属性指向函数的原型对象.原型对象主要用于共享实例中所包含的的属性和方法. constru ...

  6. 《JAVASCRIPT高级程序设计》根植于原型链的继承

    继承是面向对象的语言中,一个最为津津乐道并乐此不疲的话题之一.JAVASCRIPT中的继承,主要是依靠原型链来实现的.上一篇文章介绍过,JAVASCRIPT中,每一个对象都有一个prototype属性 ...

  7. 对Javascript 类、原型链、继承的理解

    一.序言   和其他面向对象的语言(如Java)不同,Javascript语言对类的实现和继承的实现没有标准的定义,而是将这些交给了程序员,让程序员更加灵活地(当然刚开始也更加头疼)去定义类,实现继承 ...

  8. JavaScript中的原型链和继承

    理解原型链 在 JavaScript 的世界中,函数是一等公民. 上面这句话在很多地方都看到过.用我自己的话来理解就是:函数既当爹又当妈."当爹"是因为我们用函数去处理各种&quo ...

  9. 三张图搞懂JavaScript的原型对象与原型链 / js继承,各种继承的优缺点(原型链继承,组合继承,寄生组合继承)

    摘自:https://www.cnblogs.com/shuiyi/p/5305435.html 对于新人来说,JavaScript的原型是一个很让人头疼的事情,一来prototype容易与__pro ...

随机推荐

  1. java.lang.IllegalArgumentException: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]

    此方法为Timestamp的 转换方法. 这几天做到excel导入功能,其中里面有几个时间时段,所以用了这个类来将导入的字符串格式转换Timestamp格式. 不慎出现了 java.lang.Ille ...

  2. 简单的Dao设计模式

    简单的DAO设计模式 这两天学习到了DAO(Data Access Object 数据存取对象)设计模式.想谈谈自己的感受,刚开始接触是感觉有点难,觉得自己逻辑理不清,主要是以前学的知识比较零散没有很 ...

  3. java时间格式转换

    package org.shineway.com; import java.text.ParseException; import java.text.SimpleDateFormat; import ...

  4. TCP/IP远程访问操作:rwho,rlogin,rcp和rsh

    TCP/IP网络通信 软件 包使用远程访问 的 命令 ,这些命令首先是由UC Berkely为Arpanet开发的.它允许您远程注册到另一个 系统 中,并从一个系统复制文件到另一个系统.您能取得关于一 ...

  5. Android控件TextView的实现原理分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8636153 在前面一个系列的文章中,我们以窗口 ...

  6. 又一道软通动力7K月薪面试题——银行业务调度系统

    后期补充:网友对我诟病最多的就是我帮学生做面试题,说这是小偷和骗子行为,在此,我对自己给学员做面试题做出例如以下解释:  (1)学员拿着面试题来找老师,学生也事先思考和尝试后实在没有办法,又求职心切才 ...

  7. nodejs之简介及安装(一)

    @[nodejs|个人学习笔记] nodejs简介 什么是node.js Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境. 参考网站 一.nodejs.cn 二 ...

  8. 涂抹Oracle笔记2:数据库的连接-启动-关闭

    一.数据库的连接sqlplus <username>[/<password>][@<connect_idertifier>]|/[as sysdba| as sys ...

  9. 密码算法详解——AES

    0 AES简介 1997年1月2号,美国国家标准技术研究所宣布希望征集一个安全性能更高的加密算法(AES)[3],用以取代DES.我们知道DES的密钥长度是64 bits,但实际加解密中使用的有效长度 ...

  10. Android5.0+(CollapsingToolbarLayout)

    CollapsingToolbarLayout作用是提供了一个可以折叠的Toolbar,它继承至FrameLayout,给它设置layout_scrollFlags,它可以控制包含在Collapsin ...