JS是一種面向對象的語言。除了基本數據類型number, string, boolean(true, false), null, undefined,其餘的都是對象。對象就是一個"name-value"對集合。javascript
JS有三種建立對象的方式:字面量,Object.create,new構造方式。java
嚴格來講調用Object.create方法是建立JS對象的惟一方式(其餘兩種方式內部實現都是基於該方法的)。該方法功能是建立一個對象,而且該對象的原型指向create的參數對象。
參數:必須是null或者對象,不然報錯。null表示建立一個沒有原型的空對象。segmentfault
var p = { a: 1}; // 對象字面量 var c1 = Object.create(p); // 對象c1的原型指向p var c2 = Object.create(null);// 對象c2沒有原型
對象字面量是一種建立對象的便捷方式,見上例。其中對象p的建立方式就是對象字面量。JS解釋器會對它進行處理的,等價於:數組
var p = Object.create(Object.prototype); p.a = 1;
因此說對象字面量內部也是經過Object.create方式建立對象的,而且全部對象字面量方式建立的對象的原型都執行Object.prototype(如上圖)。app
思考:JS解釋器如何區分語句塊花括號{}
和空對象花括號{}
的?
先看看這兩條語句執行的結果?函數
{} + [] // 0 [] + {} // "[object Object]"
當{}
做爲右值(賦值表達式右側),實參,在運算符的右側,被括號()
包裹則做爲對象,其餘則視爲語句塊:
下面輸出都是:"[object Object]"this
console.log({} + []) // 做爲實參了 ({}) + [] // 被括號包裹 var a = {} + [] //做爲右值 console.log(a)
咱們知道當ES6箭頭函數的函數體只有一條語句時能夠省略語句塊花括號,可是若是箭頭函數返回的是一個對象該如何書寫呢?spa
var func1 = () => {age: 12} // 本意是想返回對象{age:12},顯然這樣寫就不對了,花括號會被做爲語句塊解析 var func2 = () => ({age: 12}) // 能夠用括號包裹下 var func3 = () => { return {age: 12}} // 或顯示的寫全
JS的做者爲了討好類語言的開發者,引入了第三者建立對象方式,即new構造方式。這使得JS對象的建立有點像類語言的對象建立。prototype
new關鍵字 + 空格 + 函數名字 + [(參數)]
其中參數是可選的,當沒有參數傳遞時,能夠省略括號。如:code
function Func(){} var c1 = new Func(); var c2 = new Func; // 若是沒有參數傳遞,能夠省略括號。
function Func(name){ this.name = name; } Func.prototype.say = function(){ }; var c = new Func('q');
這種方式的內部也是經過Object.create方式構建的。new方式建立對象大體分爲三步:
Step1:建立一個對象A,而且對象A的原型指向構造函數的prototype屬性
Step2:以對象A綁定到構造函數上調用構造函數
Step3:若是構造函數返回值不是個非null的對象,則返回構造函數的返回值做爲new表達式的值,不然以對象A做爲new表達式的值。
function Func(name){ this.name = name; } Func.prototype.say = function(){ }; function create(){ // 模擬new操做符 var func = arguments[0]; var args = Array.prototype.slice.call(arguments, 1); var other = Object.create(func.prototype); // Step 1 var result = func.apply(other, args); // Step 2 return typeof result === 'object' && result ? result: other; // Step3 注意返回值 } var c = create(Func, 'q');
訪問方式也就是get/set/delete。在get訪問中會涉及原型鏈,set/delete訪問不會。
var Obj = { name: 'john' }; // Get操做 var n = Obj.name; // 等價var n = Obj["name"]; // Set操做 Obj.age = 12;
能夠經過delete操做符刪除對象的屬性,只能刪除對象自己的屬性。
var p = { age: 26 } var obj = Object.create(p); obj.name = 'john'; console.log(obj.name); // john console.log(obj.age); // 26 delete obj.name; // 刪除屬性 delete obj.age; // 刪除屬性 console.log(obj.name); // undefined console.log(obj.age); // undefined
JS中對象是引用類型的。對象在做爲值時,是做爲引用傳遞的。
var a={}, b={}; // a,b分別指向不一樣的對象 var c = d = {}; // c,d指向同一個對象
肯定對象的類型有時頗有必要。
經過typeof操做符能夠獲取值的類型:
console.log(typeof 1); // number console.log(typeof ''); // string console.log(typeof null); // object console.log(typeof undefined); // undefined console.log(typeof true); // boolean console.log(typeof {}); // object console.log(typeof []); // object console.log(typeof function(){}); // function
可是發現這種方式中null, 數組也都是返回「object」。緣由是JS中沒有原生數組類型,數組是經過對象模擬的,因此數組也是對象。可是如何區分數組和對象呢???
typeof是有缺陷的,在實際應用中常經過Object.prototype.toString方法肯定對象類型的。
console.log(Object.prototype.toString.call(1)); // [object Number] console.log(Object.prototype.toString.call('')); // [object String] console.log(Object.prototype.toString.call(null)); // [object Null] console.log(Object.prototype.toString.call(undefined)); // [object Undefined] console.log(Object.prototype.toString.call(true)); // [object Boolean] console.log(Object.prototype.toString.call( {})); // [object Object] console.log(Object.prototype.toString.call([])); // [object Array] console.log(Object.prototype.toString.call(function(){})); // [object Function]
看例子中輸出結果中發現不一樣之處了吧。假如判斷對象是否爲數組:
var isArray = function(val){ return Object.prototype.toString.call(val) === '[object Array]'; }
目前的不少庫zeptojs,underscorejs中都是這樣實現的。