javascript判斷對象的實例

在JavaScript中函數做爲對象的屬性使用時,咱們稱其爲方法調用;若是函數使用new操做符來調用時,咱們稱其爲構造函數javascript

在涉及到構造函數時,一般繞不開關於this的討論。由於構造函數調用會將一個全新的對象做爲this變量的值,並隱式返回這個新對象做爲調用的結果。java

在使用構造函數時,若是調用者忘記使用new關健字,那麼函數的接收者將是全局對象。segmentfault

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

// 使用`new`調用
var jenemy = new Person('jenemy', 18);
console.log(window.age); // undefined

// 不使用
var jenemy = Person('jenemy', 18);
console.log(window.age); // 18

不使用new調用構造函數的結果是咱們無心間建立了全局變量nameage,若是這些全局變量已經存在則會被修改。數組

一個開發者熟知的解決方案是,在調用函數前先判斷函數的接收者是否爲當前函數的實例。函數

function Person(name, age) {
  if (!(this instanceof Person)) {
    return new Person(name, age);
  }
  this.name = name;
  this.age = age;
}

這種模式的一個缺點是須要額外的函數調用,在性能上代價有點高。一種更爲有效的方式是使用ES5的Object.create()函數。性能

function Person(name, age) {
  var self = this instanceof Person ? this : Object.create(Person.prototype);
  self.name = name;
  self.age = age;

  return self;
}

注意,上面二種解決方案都使用了instance操做符來判斷對象的實例。若是看過我寫的《javascript判斷一個對象是否爲數組》文章,會發現instanceof操做符並不可靠。上面的示例,稍做修改:this

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

Object.defineProperty(Person, Symbol.hasInstance, {
  value(v) {
    return false;
  }
})

var wu = new Person('jenemy', 18);
console.log(wu instanceof Person); // false

若是沒有修改Person對象內建的Symbol.hasInstance方法,上面的結果很顯然應該在控制檯輸出true。爲了解決函數調用這種模棱兩可的問題,ES6提供了元屬性new.target,當調用函數的[[Construct]]方法時,new.target被賦值爲new操做的目標,一般爲新建立對象的實例。prototype

function Person(name, age) {
  if (!new.target) {
    throw 'Peron must called with new';
  }
  this.name = name;
  this.age = age;
}

var wu = Person('jenemy', 18); // Uncaught Peron must called with new

須要注意的是在函數外使用new.target會報語法錯誤。同時,它不受對象的Symbol.hasInstance方法被修改的影響。因此若是是在ES6環境,使用new.target是最可靠的解決方案。code

相關文章
相關標籤/搜索