前言
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);