1. 程式人生 > >JavaScript高階程式設計學習筆記——建立物件的幾種方式

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

建立的物件都是object型別

建構函式模式

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");

與工廠模式相比:

  • 沒有顯示的建立物件
  • 直接將屬性和方法賦給this物件
  • 沒有return語句
  • 建立例項需要用new

    如果不使用new建立例項,建構函式就是一個普通的函式,this指向全域性

Person("Greg", 27, "Doctor"); // 新增到window
window.sayName(); //"Greg"

可以使用call或apply在另一個物件的作用域呼叫

var o = new Object();
Person.call(o, "Kristen", 25, "Nurse");
o.sayName(); //"Kristen"

建構函式的問題: 建構函式中的方法,在每個例項中都會重新建立一遍 做同一件事情的方法被建立多次,是沒有必要的。

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

可以將方法定義到建構函式的外部

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

如果有多個方法還得建立多個全域性的函式?

原型模式

每個函式都有一個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();
person2.sayName(); //"Nicholas"
alert(person1.sayName == person2.sayName); //true

原型物件

建立一個新的函式,就會為該函式生成一個prototype屬性,這個屬性指向函式的原型物件。 原型物件會自動獲取一個constructor(建構函式)屬性,這個屬性包含一個指向prototype屬性所在函式的指標。 這裡寫圖片描述

從圖中可以看到三種關係: person1,person2:例項 Person: 建構函式 Person Prototype: 原型物件

例項與建構函式: 雖然例項是通過new 建構函式建立,但例項和建構函式之間沒有關係。

例項與原型物件: 每個例項中包含一個[[Prototype]]的屬性,指向原型物件,但卻無法直接訪問[[Prototype]]。 可以通過isPrototypeOf()方法來確定物件之間是否存在這種關係。 Object.getPrototypeOf(),這個方法返回可以[[Prototype]]的值。

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

建構函式與原型物件: 建構函式的prototype指向原型物件,原型物件的constructor 又指回了建構函式。

hasOwnProperty() 和 in

hasOwnProperty()

hasOwnProperty()可以檢測一個屬性是存在例項中,還是存在原型中, 在例項中返回true,在原型中返回false。

in

in 操作符會在通過物件能夠訪問給定屬性時返回true,無論該屬性存在於例項中還是原型中。

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();
alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true
person1.name = "Greg";
alert(person1.name); //"Greg" ——來自例項
alert(person1.hasOwnProperty("name")); //true
alert("name" in person1); //true
alert(person2.name); //"Nicholas" ——來自原型
alert(person2.hasOwnProperty("name")); //false
alert("name" in person2); //true
delete person1.name;
alert(person1.name); //"Nicholas" ——來自原型
alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true

組合使用建構函式模式和原型模式

建構函式模式用於定義例項屬性,而原型模式用於定義方法和共享的屬性。 每個例項都會有自己的一份例項屬性的副本,但同時又共享著對方法的引用。

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