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

相关文章
相关标签/搜索