《JavaScript面向對象精要》之一:基本類型和引用類型

這裏有一份簡潔的前端知識體系等待你查收,看看吧,會有驚喜哦~若是以爲不錯,懇求star哈~前端


1.1 什麼是類型

原始類型 保存爲簡單數據值。 引用類型 保存爲對象,其本質是指向內存位置的引用。git

爲了讓開發者可以把原始類型和引用類型按相同的方式處理,JavaScript 花費了很大的努力來保證語言的一致性。github

其餘編程語言用棧存原始類型,用對存儲引用類型。正則表達式

而 JavaScript 則徹底不一樣:它使用一個變量對象追蹤變量的生存期。編程

原始值被直接保存在變量對象內,而引用值則做爲一個指針保存在變量對象內,該指針指向實際對象在內存中的存儲位置。數組

1.2 原始類型

原始類型表明照原樣保存的一些簡單數據。app

JavaScript 共有5種原始類型:框架

  • boolean 布爾,值爲 true or false
  • number 數字,值爲任何整型或浮點數值
  • string 字符串,值爲由單引號或雙引號括住的單個字符或連續字符
  • null 空類型,僅有一個值:null
  • undefined 未定義,只有一個值:undefined(undefined 會被賦給一個尚未初始化的變量)

JavaScript 和許多其餘語言同樣,原始類型的變量直接保存原始值(而不是一個指向對象的指針)。編程語言

var color1 = "red";
var color2 = color1;

console.log(color1); // "red"
console.log(color2); // "red"

color1 = "blue";

console.log(color1); // "blue"
console.log(color2); // "red"
複製代碼

鑑別原始類型

鑑別原始類型的最佳方式是使用 typeof 操做符。函數

console.log(typeof "Nicholas"); // "string"
console.log(typeof 10);         // "number"
console.log(typeof true);       // "boolean"
console.log(typeof undefined);  // "undefined"
複製代碼

至於空類型(null)則有些棘手。

console.log(typeof null); // "object"
複製代碼

對於 typeof null,結果是"object"。(其實這已被設計和維護 JavaScript 的委員會 TC39 認定是一個錯誤。在邏輯上,你能夠認爲 null 是一個空的對象指針,因此結果爲"object",但這仍是很使人困惑。)

判斷一個值是否爲空類型(null)的最佳方式是直接和 null 比較:

console.log(value === null); // true or false
複製代碼

注意:以上這段代碼使用了三等號(全等 ===),由於三等號(全等)不會將變量強制轉換爲另外一種類型。

console.log("5" == 5); // true
console.log("5" === 5); // false

console.log(undefined == null); // true
console.log(undefined === null); // false
複製代碼

原始方法

雖然字符串、數字和布爾值是原始類型,可是它們也擁有方法(null 和 undefined 沒有方法)。

var name = "Nicholas";
var lowercaseName = name.toLowerCase(); // 轉爲小寫

var count = 10;
var fixedCount = count.toFixed(2); // 轉爲10.00

var flag = true;
var stringFlag = flag.toString(); // 轉爲"true"

console.log("YIBU".charAt(0)); // 輸出"Y"
複製代碼

儘管原始類型擁有方法,但它們不是對象。JavaScript 使它們看上去像對象同樣,以此來提升語言上的一致性體驗。

1.3 引用類型

引用類型是指 JavaScript 中的對象,同時也是你在該語言中能找到最接近類的東西。

引用值是引用類型的實例,也是對象的同義詞(後面將用對象指代引用值)。

對象是屬性的無序列表。屬性包含鍵(始終是字符串)和值。若是一個屬性的值是函數,它就被稱爲方法。

除了函數能夠運行之外,一個包含數組的屬性和一個包含函數的屬性沒有什麼區別。

建立對象

有時候,把 JavaScript 對象想象成哈希表能夠幫助你更好地理解對象結構。

JavaScript 有好幾種方法能夠建立對象,或者說實例化對象。第一種是使用 new 操做符和構造函數。

構造函數就是經過 new 操做符來建立對象的函數——任何函數均可以是構造函數。根據命名規範,JavaScript 中的構造函數用首字母大寫來跟非構造函數進行區分。

var object = new Object();
複製代碼

由於引用類型再也不變量中直接保存對象,因此本例中的 object 變量實際上並不包含對象的實例,而是一個指向內存中實際對象所在位置的指針(或者說引用)。這是對象和原始值之間的一個基本差異,原始值是直接保存在變量中。

當你將一個對象賦值給變量時,實際是賦值給這個變量一個指針。這意味着,將一個變量賦值給另一個變量時,兩個變量各得到了一份指針的拷貝,指向內存中的同一個對象。

var obj1 = new Object();
var obj2 = obj1;
複製代碼

對象引用解除

JavaScript 語言有垃圾收集的功能,所以當你使用引用類型時無需擔憂內存分配。但最好在不使用對象時將其引用解除,讓垃圾收集器對那塊內存進行釋放。解除引用的最佳手段是將對象變量設置爲 null

var obj1 = new Object();
// dosomething
obj1 = null; // dereference
複製代碼

添加刪除屬性

在 JavaScript 中,你能夠隨時添加和刪除其屬性。

var obj1 = new Object();
var obj2 = obj1;

obj1.myCustomProperty = "Awsome!";
console.log(obj2.myCustomProperty); // "Awsome!" 由於 obj1 和 obj2 指向同一個對象。
複製代碼

1.4 內建類型實例化

內建類型以下:

  • Array 數組類型,以數字爲索引的一組值的有序列表
  • Date 日期和時間類型
  • Error 運行期錯誤類型
  • Function 函數類型
  • Object 通用對象類型
  • RegExp 正則表達式類型

可以使用 new 來實例化每個內建引用類型:

var items = new Array();
var now = new Date();
var error = new Error("Something bad happened.");
var func = new Function("console.log('HI');");
var object = new Object();
var re = new RegExp();
複製代碼

字面形式

內建引用類型有字面形式。字面形式容許你在不須要使用 new 操做符和構造函數顯示建立對象的狀況下生成引用值。屬性的能夠是標識符或字符串(若含有空格或其餘特殊字符)

var book = {
  name: "Book_name",
  year: 2016
}
複製代碼

上面代碼與下面這段代碼等價:

var book = new Object();
book.name = "Book_name";
book.year = 2016;
複製代碼

雖然使用字面形式並無調用 new Object(),可是 JavaScript 引擎背後作的工做和 new Object() 同樣,除了沒有調用構造函數。其餘引用類型的字面形式也是如此。

1.5 訪問屬性

可經過 .中括號 訪問對象的屬性。 中括號 [] 在須要動態決定訪問哪一個屬性時,特別有用。由於你能夠用變量而不是字符串字面形式來指定訪問的屬性。

1.6 鑑別引用類型

函數是最容易鑑別的引用類型,由於對函數使用 typeof 操做符時,返回"function"。

function reflect(value){
  return value;
}
console.log(typeof reflect); // "function"
複製代碼

對其餘引用類型的鑑別則較爲棘手,由於對於全部非函數的引用類型,typeof 返回 object。爲了更方便地鑑別引用類型,可使用 JavaScript 的 instanceof 操做符。

var items = [];
var obj = {};
function reflect(value){
  return value;
}

console.log(items instanceof Array); // true;
console.log(obj instanceof Object); // true;
console.log(reflect instanceof Function); // true;
複製代碼

instanceof 操做符可鑑別繼承類型。這意味着全部對象都是 Oject 的實例,由於全部引用類型都繼承自 Object

雖然 instanceof 能夠鑑別對象類型(如數組),可是有一個列外。JavaScript 的值能夠在同一個網頁的不用框架之間傳來傳去。因爲每一個網頁擁有它本身的全局上下文—— Object、Array 以及其餘內建類型的版本。因此當你把一個對象(如數組)從一個框架傳到另一個框架時,instanceof 就沒法識別它。

1.8 原始封裝類型

原始封裝類型有 3 種:String、Number 和 Boolean。 當讀取字符串、數字或布爾值時,原始封裝類型將被自動建立。

var name = "Nicholas";
var firstChar = name.charAt(0); // "N"
複製代碼

這在背後發生的事情以下:

var name = "Nichola";
var temp = new String(name);
var firstChar = temp.charAt(0);
temp = null;
複製代碼

因爲第二行把字符串當成對象使用,JavaScript 引擎建立了一個字符串的實體讓 charAt(0) 能夠工做。字符串對象的存在僅用於該語句並在隨後銷燬(一種被稱爲自動打包的過程)。爲了測試這一點,試着給字符串添加一個屬性看看它是否是對象。

var name = "Nicholas";
name.last = "Zakas";

console.log(name.last); // undefined;
複製代碼

下面是在 JavaScript 引擎中實際發生的事情:

var name = "Nicholas";
var temp = new String(name);
temp.last = "Zakas";
temp = null; // temporary object destroyed

var temp = new String(name);
console.log(temp.last);
temp = null;
複製代碼

新屬性 last 其實是在一個馬上就被銷燬的臨時對象上而不是字符串上添加。以後當你試圖訪問該屬性時,另外一個不一樣的臨時對象被建立,而新屬性並不存在。

雖然原始封裝類型會被自動建立,在這些值上進行 instanceof 檢查對應類型的返回值倒是 false。 這是由於臨時對象僅在值被讀取時建立instanceof 操做符並無真的讀取任何東西,也就沒有臨時對象的建立。

固然你也能夠手動建立原始封裝類型。

var str = new String("me");
str.age = 18;

console.log(typeof str); // object
console.log(str.age); // 18
複製代碼

如你所見,手動建立原始封裝類型實際會建立出一個 object。這意味着 typeof 沒法鑑別出你實際保存的數據的類型。

另外,手動建立原始封裝類型和使用原始值是有必定區別的。因此儘可能避免使用。

var found = new Boolean(false);
if(found){
  console.log("Found"); // 執行到了,儘管對象的值爲 false
}
複製代碼

這是由於一個對象(如 {} )在條件判斷語句中總被認爲是 true;

1.9 總結

第一章的東西都是咱們一些比較熟悉的知識。可是也有一些須要注意的地方:

  • 正確區分原始類型和引用類型
  • 對於 5 種原始類型均可以用 typeof 來鑑別,而空類型必須直接跟 null 進行全等比較。
  • 函數也是對象,可用 typeof 鑑別。其它引用類型,可用 instanceof 和一個構造函數來鑑別。(固然能夠用 Object.prototype.toString.call() 鑑別,它會返回 [object Array]之類的)。
  • 爲了讓原始類型看上去更像引用類型,JavaScript提供了 3 種封裝類型。JavaScript會在背後建立這些對象使得你可以像使用普通對象那樣使用原始值。但這些臨時對象在使用它們的語句結束時就馬上被銷燬。雖然可手動建立,但不建議。
相關文章
相關標籤/搜索