码迷,mamicode.com
首页 > 编程语言 > 详细

javascript高级程序设计笔记(第6章 面向对象的程序设计)

时间:2014-09-10 23:47:21      阅读:266      评论:0      收藏:0      [点我收藏+]

标签:style   blog   color   io   os   使用   java   ar   for   

1、访问器属性:

var book = {
  _year: 2004,
  edition: 1
};
Object.defineProperty(book, "year", {
  get: function(){
    return this._year;
    },
  set: function(newValue){
    if (newValue > 2004) {
      this._year = newValue;
      this.edition += newValue - 2004;
    }
}
});
book.year = 2005;
alert(book.edition); //2

非标准方法:

var book = {
    _year : 2004,
    edition : 1
};
//定义访问器的旧有方法
book.__defineGetter__("year", function () {
    return this._year;
});
book.__defineSetter__("year", function (newValue) {
    if (newValue > 2004) {
        this._year = newValue;
        this.edition += newValue - 2004;
    }
});
book.year = 2005;
alert(book.edition); //2

 


 

2、创建对象

  2.1 工厂模式(没有解决对象识别的问题(即怎样知道一个对象的类型))

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("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");

 

2.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("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

alert(person1.constructor == Person); //true
alert(person2.constructor == Person); //true

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

 

把上面的构造函数当做函数

// 当作构造函数使用
var person = new Person("Nicholas", 29, "Software Engineer");
person.sayName(); //"Nicholas"
// 作为普通函数调用
Person("Greg", 27, "Doctor"); // 添加到window
window.sayName(); //"Greg"
// 在另一个对象的作用域中调用
var o = new Object();
Person.call(o, "Kristen", 25, "Nurse");
o.sayName(); //"Kristen"

 

构造函数的问题:就是每个方法都要在每个实例上重新创建一遍。在前面的例子中,person1 和person2 都有一个名为sayName()的方法,但那两个方法不是同一个Function 的实例

可以把函数定义转移到构造函数外部来解决这个问题:

        function Person(name, age, job){
            this.name = name;
            this.age = age;
            this.job = job;
            this.sayName = sayName;
        }
        
        function sayName(){
            alert(this.name);
        }
        
        var person1 = new Person("Nicholas", 29, "Software Engineer");
        var person2 = new Person("Greg", 27, "Doctor");
        
        person1.sayName();   //"Nicholas"
        person2.sayName();   //"Greg"
        
        alert(person1 instanceof Object);  //true
        alert(person1 instanceof Person);  //true
        alert(person2 instanceof Object);  //true
        alert(person2 instanceof Person);  //true
        
        alert(person1.constructor == Person);  //true
        alert(person2.constructor == Person);  //true
        
        alert(person1.sayName == person2.sayName);  //true 

 

但是新的问题又来了:在全局作用域中定义的函数实际上只能被某个对象调用,这让全局作用域有点名不副实。而更让人无法接受的是:如果对象需要定义很多方法,那么就要定义很多个全局函数,于是我们这个自定义的引用类型就丝毫没有封装性可言了。好在,这些问题可以通过使用原型模式来解决。

2.3 原型模式

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();
person2.sayName(); //"Nicholas"
alert(person1.sayName == person2.sayName); //true

 

可以通过画图分析:非常重要图见书中

下面这个函数可以用于断属性到底是存在对象中还是存在于原型中

function hasPrototypeProperty(object, name) {
    return !object.hasOwnProperty(name) && (name in object);
}

 

 

ie BUG :ie不会枚举默认不可枚举的所有属性和方法包括:hasOwnProperty()、propertyIsEnumerable()、toLocaleString()、toString()和valueOf()。

var o = {
    toString : function () {
        return "My Object";
    }
};
for (var prop in o) {
    if (prop == "toString") {
        alert("Found toString"); //在IE 中不会显示
    }
}

 

 

枚举对象上的可枚举属性:keys/Object.getOwnPropertyNames

function Person() {}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function () {
    alert(this.name);
};
var keys = Object.keys(Person.prototype);
alert(keys);     //"name,age,job,sayName"
var p1 = new Person();
p1.name = "Rob";
p1.age = 31;
var p1keys = Object.keys(p1);
alert(p1keys);       //"name,age"
var keys = Object.getOwnPropertyNames(Person.prototype);
alert(keys);       //"constructor,name,age,job,sayName"

 

 

使用对象直接量,不用每次都打一遍Person.prototype

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

 

但是这样上面的代码constructor 属性不再指向Person 了。

 

解决方法:

function Person() {}
Person.prototype = {
    constructor : Person,
    name : "Nicholas",
    age : 29,
    job : "Software Engineer",
    sayName : function () {
        alert(this.name);
    }
};
----------------------------------------------------------------------------------------------------------------------------------------------------
function Person() {}
Person.prototype = {
    name : "Nicholas",
    age : 29,
    job : "Software Engineer",
    sayName : function () {
        alert(this.name);
    }
};
Object.defineProperty(Person.prototype, "constructor", {
    enumerable : false,
    value : Person
});

 

 

 

原型的动态性:

比较下面两段代码的不同:图表分析见书中

var friend = new Person();
Person.prototype.sayHi = function(){
alert("hi");
};
friend.sayHi(); //"hi"(没有问题!)

//注意这里的顺序:

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() {}
Person.prototype = {
    constructor : Person,
    name : "Nicholas",
    age : 29,
    job : "Software Engineer",
    friends : ["Shelby", "Court"],
    sayName : function () {
        alert(this.name);
    }
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Court,Van"
alert(person2.friends); //"Shelby,Court,Van"
alert(person1.friends === person2.friends); //true

 

 

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

构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,

最大限度地节省了内存。另外,这种混成模式还支持向构造函数传递参数;可谓是集两种模式之长。下面的代码重写了前面的例子

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Shelby", "Court"];
}
Person.prototype = {
    constructor : Person,
    sayName : function () {
        alert(this.name);
    }
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 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

 

 

 

2.5 动态原型模式

可以通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型。来看一个例子。

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("Nicholas", 29, "Software Engineer");
friend.sayName();


这里只在sayName()方法不存在的情况下,才会将它添加到原型中。这段代码只会在初次调用构造函数时才会执行。此后,原型已经完成初始化,不需要再做什么修
改了。不过要记住,这里对原型所做的修改,能够立即在所有实例中得到反映。因此,这种方法确实可以说非常完美。其中,if 语句检查的可以是初始化之后应该存在的任何属性或方法——不必用一大堆if 语句检查每个属性和每个方法;只要检查其中一个即可。对于采用这种模式创建的对象,还可以使用instanceof 操作符确定它的类型。但是记住,使用动态原型模式时,不能使用对象字面量,

 

 

2.6 寄生构造函数模式

 

 

2.7 稳妥构造函数模式

 

javascript高级程序设计笔记(第6章 面向对象的程序设计)

标签:style   blog   color   io   os   使用   java   ar   for   

原文地址:http://www.cnblogs.com/liguwe/p/3965473.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!