構造函數一定要通過new調用嗎?

構造函數
//構造函數
function Point(x,y){
    this.x = x;
    this.y = y;
}
var point = new Point(1,2);
console.log(point);// Point {x: 1, y: 2}
console.log(point.x,point.y);//輸出 1 2

我們知道,構造函數和普通函數一樣,唯一的區別是,構造函數是通過操作符new來調用。
如果一不小心沒有new,直接當普通函數用了呢?

//普通函數
function Point(x,y){
    this.x = x;
    this.y = y;
}
var p = Point(3,4);
console.log(p);//輸出 undefined
console.log(window.x,window.y);//輸出 3 4

可以看到,Point(3,4)返回的是undefined,並不是預期的Point實例,而且xy被誤添加到window對象上了。

作用域安全的構造函數

呃,那有啥辦法能避免這種不小心麼?
有的,作用域安全的構造函數,它能保證:不論你new抑或不new,都會返回一個新實例。

呃,作用域安全的構造函數 長啥樣?
其實,我們有很多機會與它相遇。比如,new Vue(options),函數Vue就是 作用域安全的構造函數。

  function Vue (options) {
    if (!(this instanceof Vue)
    ) {
      warn('Vue is a constructor and should be called with the `new` keyword');
    }
    //...
  }

又比如,http.createServer(options),函數Server也是 作用域安全的構造函數。

function createServer(opts, requestListener) {
  return new Server(opts, requestListener);
}
function Server(options, requestListener) {
  if (!(this instanceof Server)) return new Server(options, requestListener);
  //...
}

這種構造函數首先會甄別this是不是當前類的一個實例,是,OK,繼續往下走;不是,Sorry,先new一個吧,然後才往下走。

照葫蘆畫瓢,我們把之前的例子改造一下。

function Point(x,y){
    if(!(this instanceof Point)){
        return new Point(x,y);
    }
    this.x = x;
    this.y = y;
}
var point = new Point(1,2);
console.log(point);// 輸出 Point {x: 1, y: 2}
console.log(point.x,point.y);// 輸出 1 2

var p = Point(3,4);
console.log(p);// 輸出 Point {x: 3, y: 4}
console.log(p.x,p.y);//輸出 3 4

可以看到,不論是通過new來調用,還是當作普通函數來使用,最後都會返回一個Point實例

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章