前端面試題積累

建立對象的方式

一、工廠模式javascript

在函數裏,new 一個 Object,而後根據傳入的參數給該對象添加屬性,最後返回該對象。問題:沒法知道一個對象的類型。java

二、構造函數模式數組

問題:每一個方法都要在每一個實例上從新建立一遍。解決:在全局做用域中定義全局函數。固然,這會致使封裝性不好。app

三、原型模式函數

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

缺點:原型中全部屬性是被不少實例共享的,這種共享對於函數很是合適。可是對於包含引用類型值的屬性問題就突出了spa

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

構造函數模式用於定義實例屬性,而原型模式用於定義方法和共享的屬性。
結果,每一個實例都會有本身的一份實例屬性的副本,但同時又共享着對方法的引用,最大限度地節省了內存。另外,這種混成模式還支持向構造函數傳遞參數;可謂是集兩種模式之長。指針

五、動態原型模式code

在構造函數中這麼寫共享的方法和屬性:

// 方法
if (typeof this.sayName != 'function') {
  Person.prototype.sayName = function() {
    alert(this.name);
  };
}

六、寄生構造函數模式

基本思想:建立一個函數,該函數的做用僅僅是封裝建立對象的代碼,而後再返回新建立的對象。

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('Amy', 18, 'student');
friend.sayName();    // Amy

構造函數在不返回值的狀況下,默認會返回新對象實例。而經過在構造函數的末尾添加一個 return 語句,能夠重寫調用構造函數時返回的值。

用法:這個模式能夠在特殊的狀況下用來爲對象建立構造函數。假設咱們想建立一個具備額外方法的特殊數組。因爲不能直接修改 Array 構造函數,所以可使用這個模式。

function SpecialArray() {
  // 建立數組
  var values = new Array();
  // 添加值
  values.push.apply(values, arguments);
  // 添加方法
  values.toPipedString = function() {
    return this.join('|');
  };
  // 返回數組
  return values;
}

var colors = new SpecialArray('red', 'green', 'blue');
alert(colors.toPipedString());    // red|green|blue

關於寄生構造函數模式,有一點須要說明:
首先,返回的對象與構造函數或者與構造函數的原型屬性之間沒有關係;也就是說,構造函數返回的對象與在構造函數外部建立的對象沒有什麼不一樣。爲此,不能依賴 instanceof 操做符來肯定對象類型。

用 new 調用構造函數實際經歷了4個步驟

  • 1 建立一個新對象;
  • 2 將構造函數的做用域賦給新對象(所以 this 就指向了這個新對象);
  • 3 執行構造函數中的代碼(爲這個新對象添加屬性);
  • 4 返回新對象。

理解原型對象

全部函數都有一個 prototype 屬性,這個屬性指向函數的原型對象

在默認狀況下,全部原型對象都會自動得到一個 constructor (構造函數)屬性,這個屬性是一個指向 prototype 屬性所在函數的指針
eg. Person.prototype.constructor => Person。

當調用構造函數建立一個新實例後,該實例的內部將包含一個指針(內部屬性[[Prototype]]),指向構造函數的原型對象。注意:這個鏈接存在於實例與構造函數的原型對象之間,而不是存在於實例與構造函數之間。實例 => 構造函數的原型對象

原型對象

判斷某個實例的原型指針是否指向某個函數的原型對象:

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

hasOwnProperty() 方法:檢測一個屬性是存在於實例中,仍是存在於原型中。只有存在於實例中時,才返回 true。
in 操做符:實例和原型中的屬性都能訪問到。
同時使用 hasOwnProperty() 方法和 in 操做符,就能夠肯定該屬性究竟是存在於對象中,仍是存在於原型中。

Object.keys() 方法:取得對象上全部可枚舉的實例屬性。
Object.getOwnPropertyNames() 方法:獲得全部實例屬性(包括不可枚舉屬性)。

重寫原型會怎麼樣?

Person.prototype = {…}:
咱們將 Person.prototype 設置爲等於一個以對象字面量形式建立的新對象。 最終結果相同,但有一個例外:constructor 屬性再也不指向 Person 了。前面曾經介紹過,每建立一個函數,就會同時建立它的 prototype 對象,這個對象也會自動得到 constructor 屬性。而咱們在這裏使用的語法,本質上徹底重寫了默認的 prototype 對象,所以 constructor 屬性也就變成了新對象的 constructor 屬性(指向 Object 構造函數),再也不指向 Person 函數。此時,儘管 instanceof 操做符還能返回正確的結果,但經過 constructor 已經沒法肯定對象的類型了。

重寫原型對象

實現繼承的方式

一、原型鏈繼承

相關文章
相關標籤/搜索