js基礎-八種建立對象方法

建立對象方法

  1. Object構造函數
  2. 對象字面量表示
  3. 工廠模式
  4. 構造函數模式
  5. 原型模式
  6. 構造函數模式與原型模式結合
  7. 動態原型模式
  8. 寄生構造函數模式

1、Object實例建立

var person1 = new Object();
person1.name = "bob";
person1.age = '22';
person1.job = 'frontend';

person1.sayName = function () {
    console.log(this.name);
}

person1.sayName(); // bob
console.log(person1.age); // 22

2、對象字面量表示

var person2 = {
    name: 'bob',
    age: 22,
    job: 'frontend',
    sayName: function () {
        console.log(this.name);
    }
}
person2.sayName(); // bob

3、工廠模式

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

var person1 = createPerson('bob', 22, 'frontend');
var person2 = createPerson('lynn', 22, 'doctor');

console.log(person1.name); // bob
console.log(person2.name); // lynn
  • 優勢:函數封裝建立對象,無需寫重複建立對象的代碼
  • 缺點:沒有解決對象識別的問題(怎麼樣知道一個對象類型)

4、構造函數模式

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function () {
        console.log(this.name);
    }
    
    /**
     * 與聲明函數在邏輯上是等價的
       this.sayName = new Function("console.log(this.name)"); 
    */
}

var person1 = new Person('bob', 22, 'frontend');
var person2 = new Person('lynn', 22, 'doctor');

console.log(person1.name); // bob
console.log(person2.name); // lynn
優勢:
  • 沒有顯式地建立對象
  • 直接將屬性和方法賦給了this對象
  • 沒有return語句
缺點:
  • 每一個方法都要在每一個實例上從新建立一遍
實現過程:
  • 建立新的對象
  • 將構造函數的做用域賦給新對象,所以this就指向了這個對象
  • 執行構造函數的代碼,爲這個對象添加對象屬性和方法
  • 返回新的對象

person1person2分別保存着Person的一個不一樣的實例。這兩個對象都有一個constructor(構造函數)屬性,該屬性指向Personfrontend

console.log(person1.constructor === Person); // true
console.log(person2.constructor === Person); // true

對象的constructor屬性最初是用來標識對象類型的。可是,提到檢測對象類型,仍是instanceof操做符要更可靠一些函數

console.log(person1 instanceof Object); // true
console.log(person1 instanceof Person); // true
console.log(person2 instanceof Object); // true
console.log(person2 instanceof Person); // true

咱們在這個例子中建立的全部對象既是Object的實例,同時也是Person的實例,這一點經過instanceof操做符能夠獲得驗證,建立自定義的構造函數意味着未來能夠將它的實例標識爲一種特定的類型優化

能夠將構造函數看成函數
// 看成構造函數使用
var person = new Person("bob", 22, "frontend");
person.sayName(); //"Nicholas"

// 做爲普通函數調用
Person("lynn", 22, "doctor"); // 添加到window
window.sayName(); //"Greg"

// 在另外一個對象的做用域中調用
var o = new Object();
Person.call(o, "Kristen", 25, "Nurse");
o.sayName(); //"Kristen"
缺點優化

構造函數建立的對象方法,實際上執行屢次函數建立,會致使不一樣的做用域鏈和標識符解析,如:this

console.log(person1.sayName == person2.sayName);  //false

建立兩個完成一樣任務的Function實例的確沒有必要;何況有this對象在,根本不用在執行代碼前就把函數綁定到特定對象上面。所以,大可像下面這樣,經過把函數定義轉移到構造函數外部來解決這個問題。prototype

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

// 把sayName函數抽離出外部函數
function sayName() {
    console.log(this.name);
}

存在問題:指針

  • 全部被新建立出來的對象,都會指向全局做用域的sayName函數,若是定義N個方法,那麼就要定義N個全局的方法,這就形成了封裝性的瓶頸,不過可使用原型模式來解決

5、原型模式

function Person() {
}

Person.prototype.name = 'bob';
Person.prototype.age = 22;
Person.prototype.job = 'frontend';
Person.prototype.sayName = function () {
    return this.name
}

var person1 = new Person();

console.log(person1.name); // bob
console.log(person1.age); // 22
console.log(person1.job); // frontend
console.log(person1.sayName()); // bob
console.log(person1.sayName === person2.sayName); // true

咱們建立的每一個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含能夠由特定類型的全部實例共享的屬性和方法。若是按照字面意思來理解,那麼prototype就是經過調用構造函數而建立的那個對象實例的原型對象。使用原型對象的好處是可讓全部對象實例共享它所包含的屬性和方法。code

6、組合使用構造函數模式和原型模式

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

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

var person1 = new Person('bob', 22, 'frontend');
var person2 = new Person('lynn', 22, 'doctor');

console.log(person1.name); // bob
console.log(person2.name); // lynn
console.log(person1.sayName === person2.sayName); // true

7、動態原型模式

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

    console.log('typeof this.sayName: ', typeof this.sayName);
    // 檢測sayName 是否是一個函數
    // 實際上只在當前第一次時候沒有建立的時候在原型上添加sayName方法
    if (typeof this.sayName != 'function') {
        Person.prototype.sayName = function () {
            return this.name;
        }
    }
}

var person1 = new Person('bob', 22, 'frontend');
var person2 = new Person('lynn', 22, 'doctor');

console.log(person1.name); // bob
console.log(person2.name); // lynn
console.log(person1.sayName()); // bob
console.log(person2.sayName()); // lynn
console.log(person1.sayName === person2.sayName); // true

8、寄生構造函數模式

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

var person1 = new createPerson('bob', 22, 'frontend');
var person2 = new createPerson('lynn', 22, 'doctor');

console.log(person1.name); // bob
console.log(person2.name); // lynn
相關文章
相關標籤/搜索