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

面向对象程序设计


创建对象

工厂模式

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 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值