Hot For Coding
JavaScript作用域安全构造函数

通常我们定义的构造函数需要new操作符实例调用构造函数,因为只有使用new的时候构造函数内用到的this对象会指向新创建的对象实例,如代码:

/**
 * 作用域安全构造函数
 * Nicholas Lee www.qttc.net
 */
 
// 定义构造函数
function cus (name,age) {
  this.name = name;
  this.age = age;
}
 
var obj = new cus('Nicholas Lee', 2);
 
console.log(obj.name); // Output: Nicholas Lee
console.log(obj.age);  // Output: 2

因为使用new定义实例了cus构造函数,所以this对象指向新创建的obj对象。最后obj.nameobj.age分别都接受到构造函数赋予的值,结果可以正常弹出值。

但是,在没有使用new操作符来调用构造函数的情况下,情况就不一样了,我们都知道this默认指的是window,所以name与age都被赋予到window对象上。如代码:

/**
 * 作用域安全构造函数
 * Nicholas Lee www.qttc.net
 */
 
// 定义构造函数
function cus(name,age){
  this.name = name;
  this.age = age;
}
 
// 没有使用new操作符构造函数
var obj = cus('Nicholas Lee', 2);
 
console.log(obj.name); // Output: undefined
console.log(obj.age);  // Output: undefined
 
console.log(window.name) // Output: Nicholas Lee
console.log(window.age) // Output: 2

这里原本是要把两个变量name与age赋予给obj变量的,但由于没有使用new操作符,所以直接赋予到window下了。结果导致obj.name与obj.age都是undefined,而window.name与window.age才可以正确弹出被赋予的值。

为了解决这个问题,我们可以先确认this对象是正确类型的实例,如果是就直接赋予值,如果不是就会创建一个实例并返回。

/**
 * 作用域安全构造函数
 * Nicholas Lee www.qttc.net
 */
 
// 定义构造函数
function cus(name,age){
  // 判断是不是使用new实例
  if(this instanceof cus){
    this.name = name;
    this.age = age;     
  }else{
    // 否则使用new实例并返回
    return new cus(name,age);   
  }
}
 
// 没有使用new操作符构造函数
var obj = cus('Nicholas Lee', 2);
 
console.log(obj.name); // Output: Nicholas Lee
console.log(obj.age);  // Output: 2

这样,无论是否使用new操作符都能当作构造函数来使用了,不要难过担心被赋予到window对象下。

TITLE: JavaScript作用域安全构造函数

LINK: https://www.qttc.net/183_javascript_safe_constructors.html

NOTE: 转载内容请注明出处