最近学习了《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");

工厂模式一目了然,但它的缺点是,我们无法得知我们创建的person1person2究竟属于什么类型,我们只知道它们都是object, 但我们希望更加具体。因为它们有相同的行为,我们希望person1person2都属于一个叫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. 返回这个新对象

现在,我们可以看一下person1person2的类型,

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'

在这里,可以看到设置了person1name属性后,该属性即存在于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. linux网络编程之TCP/IP基础

    (一):TCP/IP协议栈与数据包封装 一.ISO/OSI参考模型 OSI(open system interconnection)开放系统互联模型是由ISO(International Organi ...

  2. hdu 5288 OO’s Sequence(计数)

    Problem Description OO has got a array A of size n ,defined a function f(l,r) represent the number o ...

  3. 苹果拒绝App内部使用版本检测功能

    10.6 - Apple and our customers place a high value on simple, refined, creative, well thought through ...

  4. UVA 536 (13.08.17)

     Tree Recovery  Little Valentine liked playing with binary trees very much. Her favoritegame was con ...

  5. HDU 4362 Dragon Ball 线段树

    #include <cstdio> #include <cstring> #include <cmath> #include <queue> #incl ...

  6. MFC读写配置文件

    void CFileTextDoc::OnIniread() { // TODO: Add your command handler code here CString strStudName;   ...

  7. Android 控件 -------- AutoCompleteTextView 动态匹配内容,例如 百度搜索提示下拉列表功能

    AutoCompleteTextView 支持基本的自动完成功能,适用在各种搜索功能中,并且可以根据自己的需求设置他的默认显示数据.两个控件都可以很灵活的预置匹配的那些数据,并且可以设置输入多少值时开 ...

  8. Code Complete阅读笔记(三)

    2015-05-26   628   Code-Tuning Techniques    ——Even though a particular technique generally represen ...

  9. react基于webpack和babel以及es6的项目搭建

    项目demo地址https://github.com/aushion/webpack_reac_config 1.打开命令提示窗口,输入 mkdir react_test cd react_test ...

  10. 关于取数组地址的识记(&s+1,s+1,&s[0]+1)

    #include <stdio.h> #include <malloc.h> int main() { ', 'o'}; ); printf(]); ]+); printf(] ...