面向对象的js程序设计

1.工厂方法:没有解决对象识别问题,即怎样知道一个对象的类型

function createPerson(name, age, job) {
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.job = job;
    obj.sayName = function() {
        alert("my name:"+this.name);
    };
    return obj;
}
var person = createPerson("kitty", 18, "font-to-end developer");

2.构造方法

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function() {
        alert(this.name);
    };
}
var person1 = new Person("liLei", 20, "doctor");
var person2 = new Person("hanmeimei", 18, "teacher");

弊端:sayName方法在要在每个实例上重新创建一遍,person1,person2这两个对象的sayName方法不是同一个实例,因为函数即是对象,故每定义一个函数,就是实例化了一个对象
改进策略:

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = sayName; 
}
function sayName() {
    alert(this.name);
}

解决上面问题:包含的是指向全局函数sayName的指针,因此person1和person2对象共享了在全局作用域中定义的同一个sayName函数;
但引来其他问题:在全局作用域上定义的函数实际上只能被某个对象调用,有点名不副实。并且,如果对象需要定义很多个方法,那么,就要定义很多个全局函数,于是我们自定义的引用类型就丝毫没有封装性可言了。此策略依然不行。
3.原型模式
每创建一个函数,就会为该函数创建一个prototype属性,该属性指向函数的原型对象。所有原型对象,对会自动获得一个constructor属性,此属性指向prototype属性所在函数的指针(即开始的函数)。我们还可以继续为原型对象添加属性和方法。
例如:

function Person() {

}
Person.prototype.name = "kitty";
Person.prototype.age = 20;
Person.prototype.sex = "female";
Person.sayName = function() {
    alert(this.name);
}

图解:
这里写图片描述

介绍几个和原型有关的方法:
方法一:isPrototypeOf 检测某个实例是否是某个原型的原型

var person1 = new Person();
var person2 = new Person();
alert(person1.sayName === person2.sayName); // true
Person.prototype.isPrototypeOf(person1); // true
var person3 = new Object();
Person.prototype.isPrototypeOf(person3); //false

方法二:Object.getPrototypeOf 获取某个实例的原型

Object.getPrototypeOf(person1) === Person.prototype // true

方法三: hasOwnProperty 检测某个对象的属性是否来自实例对象

person1.hasOwnProperty("name"); // false
person1.name = "marry";
person1.hasOwnProperty("name"); // true

方法四: propertyName in object :检测属性名称是否存在某个对象中,只要存在该实例对象或者原型对象中,均返回true

"name" in person1 // true

方法五:Object.keys 要取得对象上所有可枚举的实例属性,返回字符串数组

Object.keys(Person.prototype); // ["name", "age", "job", "sayName"]
var person1 = new Person();
person1.name = "kk";
person1.tt = "tt";
Object.keys(person1); // ["name", "tt"]

方法六:Object.getOwnPropertyNames 取得对象上的所有实例属性,无论它是否可枚举

Object.getOwnPropertyNames(Person.prototype) // ["constructor", "name", "age", "job", "sayName"]

说明:方法五、方法六引出的原因:
这里写图片描述

原型模式存在的缺点:
最大问题在于其共享本性所导致的:原型中所有属性是被很多实例共享的,这种共享对于函数是非常合适的,包含基本值的类型也说得过去,但是,对于包含引用类型值得属性来说,问题就比较突出。例如:

function Person() {

}
Person.prototype = {
  constructor: Person,
  name: "kitty",
  fields: ["zhangsan", "lisi", "hanmeimei"], // 引用类型
  sayName: function() {
    alert(this.name);
  }
};
var person1 = new Person();
var person2 = new Person();
person1.fields.push("lucy");
alert(person1.fields===person2.fields); // true

故很少有人看到单独使用原型模式
4.构造函数模式 + 原型模式
思想:构造函数(可传参)模式用于定义实例属性,原型模式用于定义方法和共享的属性

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.fields = ["lily", "lucy"];
}
Person.prototype = {
    constructor: Person,
    sayName: function() {
        alert(this.name);
    }  
};
var person1 = new Person("zhangsan", 10);
var person2 = new Person("lisi", 10);
person1.fields.push("hehe");
alert(person2.fields); // ["lily", "lucy"]

结果:每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用
此种模式是广受欢迎的
5.动态原型模式:
用于解决构造函数和原型分家问题

function Person(name, age) {
    this.name = name;
    this.age = age;

    if (typeof this.sayName !== "function") {
        Person.prototype.sayName = function() {
        alert(this.name);
        };
    }
}

特点:把所有信息都封装在构造函数中,而通过在构造函数中初始化原型,又同时保证了使用构造函数和原型的优点。通过判断原型的条件,可以使sayName方法中只初始化一次。注意:此处不能给原型使用字面量的方式创建(Person.prototype = {sayName: function() {…}}),否则会切断现有实例与新原型的关系。
5.寄生构造函数模式:

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

由于创建的对象与构造函数没有任何关系,故不能用instanceof 检测对象
此种模式能不用,则不用
6.稳妥构造函数模式:没有公共属性,而且其方法也不引用this对象

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

这样,就只有一种方式能够访问name属性,就是通过sayName方法
由于,只有创建的对象与构造函数没有任何关系,故也不能使用instanceof检测对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值