關於new命令

前言

JS中有一種說法,叫做一切皆爲對象。對象是什麼呢?大話來講,對象是一種容器,裏面封裝了屬性和方法。在每天編程中,最基本的事情也是頻繁的乾的事情就是創建一個對象,然後使用它幹各種各樣的事情。創建對象的方法有構造函數創建、語法糖創建、還有new命令創建。當然,本文的標題已經表明這次的主角是new關鍵字了。

new的基本用法

new命令的作用,就是執行構造函數,返回一個實例對象。

ps:如果忘了使用new命令,構造函數就變成了普通函數,並不會生成實例對象。

// 1、不帶參數情況
var Vehicle = function () {
  this.price = 1000;
};

var v = new Vehicle();
v.price // 1000

// 2、帶參數情況
var Vehicle = function (p) {
  this.price = p;
};

var v = new Vehicle(500);

當然,爲了保證構造函數必須與new命令一起使用兩種方法。

方法一:構造函數內部使用嚴格模式,即第一行加上use strict。這樣的話,一旦忘了使用new命令,直接調用構造函數就會報錯。

function Fubar(foo, bar){
  'use strict';
  this._foo = foo;
  this._bar = bar;
}

Fubar()
// TypeError: Cannot set property '_foo' of undefined

方法二:構造函數內部判斷是否使用new命令,如果發現沒有使用,則直接返回一個實例對象。

function Fubar(foo, bar) {
  if (!(this instanceof Fubar)) {
    return new Fubar(foo, bar);
  }

  this._foo = foo;
  this._bar = bar;
}

Fubar(1, 2)._foo // 1
(new Fubar(1, 2))._foo // 1

new原理詳解

面試的時候常常會問道,使用new命令時,會發生什麼。

1、創建一個空對象,作爲將要返回的對象實例。

2、將這個空對象的原型,指向構造函數的prototype屬性。

3、將這個空對象賦值給函數內部的this關鍵字。

4、開始執行構造函數內部的代碼。

從上面步驟可以看出,其構造函數內部,通過this指的就是新生對象。
如果你對this不是很清楚,可以看我的另一篇文章
關於this、call、applay和bind

注意:如果構造函數內部有return語句,而且return後面跟着一個對象,new命令會返回return語句指定的對象;否則,就會不管return語句,返回this對象。

例子1


var Vehicle = function () {
  this.price = 1000;
  return 1000;
};

(new Vehicle()) === 1000
// false

例子2

var Vehicle = function (){
  this.price = 1000;
  return { price: 2000 };
};

(new Vehicle()).price
// 2000

另一方面,如果對普通函數(內部沒有this關鍵字的函數)使用new命令,則會返回一個空對象。


function getMessage() {
  return 'this is a message';
}

var msg = new getMessage();

msg // {}
typeof msg // "object"

new關鍵字的內部流程


function _new(/* 構造函數 */ constructor, /* 構造函數參數 */ params) {
  // 將 arguments 對象轉爲數組
  var args = [].slice.call(arguments);
  // 取出構造函數
  var constructor = args.shift();
  // 創建一個空對象,繼承構造函數的 prototype 屬性
  var context = Object.create(constructor.prototype);
  // 執行構造函數
  var result = constructor.apply(context, args);
  // 如果返回結果是對象,就直接返回,否則返回 context 對象
  return (typeof result === 'object' && result != null) ? result : context;
}

// 實例
var actor = _new(Person, '張三', 28);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章