Javascript高级程序设计 第六章 --- 面向对象程序设计

原创 2015年11月19日 22:03:11

面向对象程序设计


创建对象

工厂模式

function createPerson(name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    };
    return o;
}

var person1 = createPerson("Lyf", 20, "student");

构造函数模式

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    };
}
var person1 = new Person("Lyf", 20, "student");

按照惯例,构造函数始终以大写字母开头,非构造函数以小写字母开头。


原型模式

每个函数都有一个 prototype(原型)的属性,这个属性是一个指针,指向一个对象,这个对象包含所有实例共享的属性和方法。

使用原型对象的好处是:让所有对象实例共享它所包含的属性和方法。

function Person(){
}

Person.prototype.name = "Lyf";
Person.prototype.age = 20;
Person.prototype.job = "student";
Person.prototype.sayName = function(){
    alert(this.name);
}

var person1 = new Person();
person1.sayName();          // "Lyf"

var person2 = new Person();
person2.sayName();          // "Lyf"

alert(person1.sayName == person2.sayName);  // true



在所以实例中都无法访问到 [ Prototype ],但是可以通过 isPrototypeOf()方法确定对象之间是否存在这种关系。

alert(Person.prototype.isPrototypeOf(person1));     // true
alert(Person.prototype.isPrototypeOf(person2));     // true



ECMAScript 5 新增的方法:Object.getPrototypeOf(),这个方法返回 [ Prototype ]

alert(Object.getPrototypeOf(person1) == Person.prototype); 
// true
alert(Object.getPrototypeOf(person1).name);     // "Lyf"



当为对象实例添加属性时,这个属性会 屏蔽 原型对象中保存的同名属性,该属性只会阻止我们访问原型中的那个属性,不会修改那个属性。

delete 操作符可以完全删除实例属性,从而让我们访问原型属性。

使用 hasOwnProperty()方法可以检测一个属性是存在于实例中,还是原型中。

function Person(){
}
Person.prototype.name = "Lyf";
Person.prototype.age = 20;
Person.prototype.job = "student";
Person.prototype.sayName = function(){
    alert(this.name);
};

var person1 = new Person();
var person2 = new Person();

alert(person1.hasOwnProperty("name"));  // false

person1.name = "JackLiu";
alert(person1.name);    // "JackLiu"  ---  来自实例
alert(person2.name);    // "Lyf"  ---  来自原型
alert(person1.hasOwnProperty("name"));  // true 来自实例
alert(person2.hasOwnProperty("name"));  // false 来自原型

delete person1.name;
alert(person1.name);    // "Lyf"  ---  来自原型

更简洁的原型写法

function Person(){
};

Person.prototype = {
    name : "Lyf",
    age : 20,
    jog : "student",
    sayName : function(){
        alert(this.name);
    }
};

原生对象的问题

function Person(){
}

Person.prototype = {
    name : "Lyf",
    age : 20,
    friends : ["老王", "老张"],
    sayName : function(){
        alert(this.name);
    }
};

var person1 = new Person();
var person2 = new Person();

person1.push("老李");

alert(person1.friends);     // "老王,老张,老李";
alert(person2.friends);     // "老王,老张,老李";
alert(person1.friends === person2.friend);  // true

组合使用构造函数模式和原型模式

组合使用构造函数模式和原型模式,是最常见的方式。

  • 构造函数 用于定义实例属性
  • 原型模式 用于定义方法和共享属性
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["老王","老张"];
}

Person.prototype = function(){
    constructor : Person,
    sayName : function(){
        alert(this.name);
    }
}

var person1 = new Person("Lyf", 20, "student");
var person2 = new Person("JackLiu", 20, "student");

person1.friends.push("老李") ;
alert(person1.friends);     // "老王, 老张, 老李"
alert(person2.friends);     // "老王, 老张"
alert(person1.friends === person2.friends);     // false
alert(person1.sayName === person2.sayName);     // true

实例属性都在构造函数中,实例共享的属性 constructor 和 方法 sayName在原型中定义的。


动态原型模式

function Person(name, age, job){
    // 属性
    this.name = name;
    this.age = age;
    this.job = job;

    // 方法
    if( typeOf this.sayName != "function" ){
        Person.prototype.sayName = function(){
            alert(this.name);
        }
    }
}

var friend = new Person("Lyf", 20, "student");
friend.sayName();

寄生构造函数模式

这种模式的基本思想是创建一个函数,该函数的作用是封装创建对象的代码,然后再返回新创建的对象。(不建议使用)

function Person(name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    };
    return o;
}

var friend = new Person("Lyf", 20, "student");
friend.sayName();       // "Lyf"

稳妥构造函数模式

稳妥对象 指的是没有公用属性,而且其方法也不引用 this 的对象。

function Person(name, age, job){
    // 创建要返回的对象
    var o = new Object();
    // 可以再这里定义私有变量和函数
    o.sayName = function(){
        alert(name);
    }

    // 返回对象
    return o ;
}

这种对象创建的对象中,除了使用 sayName()方法之外,没有其他方法访问name的值。

var friend = new Person("Lyf", 20, "student");
friend.sayName();   // "Lyf"

继承

原型链

ECMAScript中,将原型链作为实现继承的主要方法。
其基本思想是:利用原型链让一个引用类型继承另一个引用类型的属性和方法。

原型链的搜索机制:

  • 首先会再实例中搜索该属性
  • 如果没找到,继续搜索实例的原型


确定原型和实例的关系

第一种方法:可以通过 instanceof 操作符,来确认原型和实例之间的关系

alert(instance instanceof Object);      // true

第二种方法:使用 isPrototypeOf()方法

alert(Object.prototype.isPrototypeOf(instance));    // true

谨慎的定义方法

通过原型链实现继承,不能使用对象字面量创建原型方法,这样会重写原型链。

function SuperType(){
    this.property = true;
}

Supertype.prototype.getSuperValue = function(){
    return this.prototype;
}

function SubType(){
    this.subproperty = false;
}

// 继承了 SuperType
SubType.prototype = new SuperType();

// 使用字面量添加新方法,会导致上一行代码无效
SubType.prototype = {
    getSubValue : function(){
        return this.subproperty;
    },
    someOtherMethod : function(){
        return false;
    }
};

var instance = new SubType();
alert(instance.getSuperValue());        // error!

以上代码刚把 SuperType实例赋值给原型,接着原型换成字面量表示,现在的原型相当于 Object对象实例,而非 SuperType实例。


原型链的问题

用原型链来继承时,包含引用类型值的原型属性会被所有实例共享。

function SuperType(){
    this.color = ["red", "blue", "green"];
}

function SubType(){
}

// 继承了SuperType
SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);    // "red,blue,green,black"

var instance2 = new SubType();
alert(intance2.colors);     // "red,blue,green,black" 

借用构造函数

在解决原型中包含引用类型值所带来的问题,开发人员使用借用构造函数的技术(有时也叫伪造对象或经典继承)。即在子类型构造函数的内部调用超类型的构造函数。使用 call()方法和 apply()方法也可以在将来新创建的对象上执行构造函数。

function SuperType(){
    this.colors = ["red", "blue", "green"];
}

function SubType(){
    // 继承了SuperType
    SuperType.call(this);
} 

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);    // "red,blue,green,black"

var instance2 = new SubType();
alert(instance2.colors);    // "red,blue,green"


传递参数

相对于原型链而言,借用构造函数可以在子类型中向超类型构造函数传递参数。

function SuperType(name){
    this.name = name;
}

function SubType(){
    // 继承了SuperType,同时还传递了参数
    SuperType.call(this,"Lyf");

    // 实例属性
    this.age = 20;
}

var instance = new SubType();
alert(instance.name);   // "Lyf"
alert(instance.age);    // 20

组合继承

组合继承也叫伪经典继承,将原型链和借用构造函数的技术组合到一块,从而发挥二者之长的一种继承模式。

使用原型链实现对原型属性和方法的继承,从而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数的复用,又能保证每个实例都有自己的属性。

function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}

SuperType.prototype.sayName = function(){
    alert(this.name);
}

function SubType(name, age){
    // 继承属性
    SuperType.call(this,name);

    this.age = age;
}

// 继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
    alert(this.age);
}

var instance1 = new SubType("Lyf", 20);
instance1.colors.push("black");
alert(instance1.colors);        // "red,blue,green,black"
instance1.sayName();        // "Lyf"
instance1.sayAge();         // 20

var instance2 = new SubType("JackLiu", 20);
alert(instance2.colors);        // "red,blue,green"
instance2.sayName();            // "JackLiu"
instance2.sayAge();             // 20 
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

JavaScript高级编程(二)-面向对象程序设计

js中的面向对象函数表达式

【javascript高级程序设计】读书摘录3 第六章、面向对象

第六章、面向对象的程序设计     这一章应该是Javascript中最抽象的一章,其中原型、原型链、构造函数等多次出现,几乎贯穿了整个章节。而对于创建对象和继承,也都是基于原型和构造函数而来的。因...

[Python学习笔记][第六章Python面向对象程序设计]

1月29日学习内容Python面向对象程序设计类的定义与使用类定义语法 使用class关键词 class Car: def infor(self): print("This...

第六章 面向对象面向对象程序设计

什么是面向对象程序语言 面向对象语言的主要特征 什么是类,对象和成员 声明一个类#include using namespace std;//声明一个类 class Hum...

JavaScript 面向对象程序设计(下)——继承与多态

前面我们讨论了如何在 JavaScript 语言中实现对私有实例成员、公有实例成员、私有静态成员、公有静态成员和静态类的封装。这次我们来讨论一下面向对象程序设计中的另外两个要素:继承与多态。 1 又...
  • ly20wy
  • ly20wy
  • 2013年11月29日 10:06
  • 407

JavaScript面向对象程序设计

1.创建对象 JavaScript 把对象定义为 : 无序属性的集合, 其属性可以包括基本值, 对象或者 函数. 每个对象都是基于一个引用类型创建的.(  引用类型可以是原生的, 也可以是开发人员...

javascript面向对象程序设计——封装(by vczero)

javascript面向对象程序设计——封装 javascript面向对象程序设计——封装 在javascript中,我们宣称是面向对象的程序设计。其实面向对象是js 与生俱来的特性,每...
  • wlh_js
  • wlh_js
  • 2014年08月04日 23:54
  • 297

javascript面向对象程序设计

1、对象数据属性的类型 [Configurable]能否通过delete删除属性,能否修改属性特征,能够将数据属性改为访问器属性,默认值为true,一旦将变为false则不能修改其属性 [Enum...

JavaScript面向对象程序设计——继承

JavaScript面向对象程序设计——继承简介 面向对象程序设计的三个特点是封装性,继承性和多态性,上一篇 已经详述了封装性的实现方法,这一篇博客将会详述继承性的实现方法。ES6中的继承 ES6中通...

JavaScript中的面向对象程序设计

面向对象程序设计主要是有3个特点:封装、继承、多态,这篇文章简单介绍如何在JavaScript实现类,以及如何继承类。类的实现js中没用关键字class,但是提供了关键字new和this。我们可以先声...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Javascript高级程序设计 第六章 --- 面向对象程序设计
举报原因:
原因补充:

(最多只允许输入30个字)