簡介
基本上所有的程式員都使用過javascript,我們在web中使用javascript,我們在伺服器端使用nodejs,js給大家的第一映像就是簡單,但是可能并不是所有人都系統的了解過js中的内置對象和資料結構。
今天,一起來看看吧。
基礎類型
js是一種弱類型的動态語言,雖然是弱類型的,但是js本身定義了很多種資料類型。
js中有7種基礎類型:分别是undefined,Boolean,Number,String,BigInt,Symbol和null。
undefined
undefined會自動指派給剛剛聲明的變量。舉個例子:
var x; //create a variable but assign it no value
console.log("x's value is", x) //logs "x's value is undefined"
Boolean和Boolean對象
Boolean的值就是true 或者 false。
除了基礎類型的Boolean值外,還有一個Boolean對象,用來封裝boolean值。
如果是用new Boolean來構造Boolean對象的話,下面的例子中Boolean的初始值都是false:
var bNoParam = new Boolean();
var bZero = new Boolean(0);
var bNull = new Boolean(null);
var bEmptyString = new Boolean('');
var bfalse = new Boolean(false);
下面boolean對象的初始值都是true:
var btrue = new Boolean(true);
var btrueString = new Boolean('true');
var bfalseString = new Boolean('false');
var bSuLin = new Boolean('Su Lin');
var bArrayProto = new Boolean([]);
var bObjProto = new Boolean({});
注意,我們不要使用Boolean對象來進行if條件的判斷,任何Boolean對象,即使是初始值是false的Boolean對象,if條件判斷,都是true:
var x = new Boolean(false);
if (x) {
// this code is executed
}
var x = false;
if (x) {
// this code is not executed
}
如果非要使用if條件判斷,我們可以使用Boolean函數或者!!如下所示:
var x = Boolean(expression); // use this...
var x = !!(expression); // ...or this
var x = new Boolean(expression); // don't use this!
Number和BigInt
Number和BigInt是JS中的兩個數字類型,其中Number表示的雙精度64位二進制格式,其範圍是-(253 − 1) and 253 − 1.
除此之外,Number還有三個值:+Infinity, -Infinity, 和 NaN。
前面兩個表示的是正負最大值。NaN表示的是 Not-A-Number。
我們可以通過isNaN來判斷是否是一個Number:
function sanitise(x) {
if (isNaN(x)) {
return NaN;
}
return x;
}
console.log(sanitise('1'));
// expected output: "1"
console.log(sanitise('NotANumber'));
// expected output: NaN
BigInt表示任意精度的整數,使用BigInt可以進行超出Number精度整數的運算。
我們可以通過在整數後面加上n來表示BigInt。
> const x = 2n ** 53n;
9007199254740992n
> const y = x + 1n;
9007199254740993n
注意,和Boolean一樣,Number和BitInt也有wrapper對象類型。
看下Number的wrapper:
Number('123') // returns the number 123
Number('123') === 123 // true
Number("unicorn") // NaN
Number(undefined) // NaN
看下BitInt的wrapper類型:
const theBiggestInt = 9007199254740991n
const alsoHuge = BigInt(9007199254740991)
// ↪ 9007199254740991n
const hugeString = BigInt("9007199254740991")
// ↪ 9007199254740991n
const hugeHex = BigInt("0x1fffffffffffff")
// ↪ 9007199254740991n
const hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111")
// ↪ 9007199254740991n
String
js中的String是不可變的,同樣的String基礎類型也有和它對應的String wrapper對象。
String基礎類型和不使用new的String函數是一緻的:
const string1 = "A string primitive";
const string2 = String('A string primitive');
上面兩個String是一緻的。但是如果使用new來構造String對象,那麼兩者是不一樣的:
let s_prim = 'foo'
let s_obj = new String(s_prim)
console.log(typeof s_prim) // Logs "string"
console.log(typeof s_obj) // Logs "object"
let s1 = '2 + 2' // creates a string primitive
let s2 = new String('2 + 2') // creates a String object
console.log(eval(s1)) // returns the number 4
console.log(eval(s2)) // returns the string "2 + 2"
我們可以通過String對象的valueOf()方法,獲得其String基礎類型。
Symbol
Symbol是一個唯一的不可變的基礎類型,一般用在對象的key中。
// Here are two symbols with the same description:
let Sym1 = Symbol("Sym")
let Sym2 = Symbol("Sym")
console.log(Sym1 === Sym2) // returns "false"
Symbol是不支援new操作的:
let sym = new Symbol() // TypeError
如果你真的想建立Symbol對象,則可以使用Object():
let sym = Symbol('foo')
typeof sym // "symbol"
let symObj = Object(sym)
typeof symObj // "object"
null
null表示引用的是無效的Object對象或者位址。
雖然null可以看做是primitive,但是null其實是一個Object,所有的對象都來自null:
typeof null === 'object' // true
Object
Object是js中的一種資料類型,幾乎所有的對象都繼承自Object,它存儲的是key-value形式的資料,我們可以通過使用Ojbect()方法或者new Object()或者Object字面量的方式來建立Object。
let o = {}
let o = {a: 'foo', b: 42, c: {}}
let a = 'foo', b = 42, c = {}
let o = {a: a, b: b, c: c}
注意使用Object()或者new Object()是一樣的效果,都會得到一個Object對象。
在ES2015之後,我們還可以使用動态的對象屬性:
let param = 'size'
let config = {
[param]: 12,
['mobile' + param.charAt(0).toUpperCase() + param.slice(1)]: 4
}
console.log(config) // {size: 12, mobileSize: 4}
Function
Function也是一個Object,JS中的所有函數都是Function對象。
(function(){}).constructor === Function
那麼通過Function構造函數和function函數定義建立出來的函數有什麼差別呢?
使用new Function建立的函數,其作用域範圍是global,我們看一下具體的例子:
var x = 10;
function createFunction1() {
var x = 20;
return new Function('return x;'); // this |x| refers global |x|
}
function createFunction2() {
var x = 20;
function f() {
return x; // this |x| refers local |x| above
}
return f;
}
var f1 = createFunction1();
console.log(f1()); // 10
var f2 = createFunction2();
console.log(f2()); // 20
Date
Date是js中用來操作時間的Object。我們看下Date的常用例子:
let today = new Date()
let birthday = new Date('December 17, 1995 03:24:00')
let birthday = new Date('1995-12-17T03:24:00')
let birthday = new Date(1995, 11, 17) // the month is 0-indexed
let birthday = new Date(1995, 11, 17, 3, 24, 0)
let birthday = new Date(628021800000) // passing epoch timestamp
let [month, date, year] = ( new Date() ).toLocaleDateString().split("/")
let [hour, minute, second] = ( new Date() ).toLocaleTimeString().slice(0,7).split(":")
Array
JS内置了很多種不同類型的Array,最常用的就是Array字面量和Array Object。
我們看下怎麼建立一個Array:
let fruits = ['Apple', 'Banana'];
console.log(fruits.length); // 2
console.log(fruits[0]); // "Apple"
let fruits = new Array('Apple', 'Banana');
console.log(fruits.length); // 2
console.log(fruits[0]); // "Apple"
周遊Array:
let fruits = ['Apple', 'Banana']
fruits.forEach(function(item, index, array) {
console.log(item, index)
})
// Apple 0
// Banana 1
添加Item到Array:
let newLength = fruits.push('Orange')
// ["Apple", "Banana", "Orange"]
從最後删除item:
let last = fruits.pop() // remove Orange (from the end)
// ["Apple", "Banana"]
從前面删除item:
let first = fruits.shift() // remove Apple from the front
// ["Banana"]
從前面添加item:
let newLength = fruits.unshift('Strawberry') // add to the front
// ["Strawberry", "Banana"]
删除某個index的item:
let removedItem = fruits.splice(pos, 1) // this is how to remove an item
// ["Strawberry", "Mango"]
删除多個item:
let vegetables = ['Cabbage', 'Turnip', 'Radish', 'Carrot']
console.log(vegetables)
// ["Cabbage", "Turnip", "Radish", "Carrot"]
let pos = 1
let n = 2
let removedItems = vegetables.splice(pos, n)
// this is how to remove items, n defines the number of items to be removed,
// starting at the index position specified by pos and progressing toward the end of array.
console.log(vegetables)
// ["Cabbage", "Carrot"] (the original array is changed)
console.log(removedItems)
// ["Turnip", "Radish"]
拷貝array:
let shallowCopy = fruits.slice() // this is how to make a copy
// ["Strawberry", "Mango"]
除了Array之外,JS還内置了特定類型的Array:
- Int8Array
- Uint8Array
- Uint8ClampedArray
- Int16Array
- Uint16Array
- Int32Array
- Uint32Array
- Float32Array
- Float64Array
- BigInt64Array
- BigUint64Array
這些特定類型的Array中隻能存儲特定類型的值。
Keyed collections
除了數組之外,JS中還有key-value的集合,比如:Map,Set,WeakMap和WeakSet。
對Map來說,我們可以通過使用set,get,has,delete等犯法來對Map進行操作:
let contacts = new Map()
contacts.set('Jessie', {phone: "213-555-1234", address: "123 N 1st Ave"})
contacts.has('Jessie') // true
contacts.get('Hilary') // undefined
contacts.set('Hilary', {phone: "617-555-4321", address: "321 S 2nd St"})
contacts.get('Jessie') // {phone: "213-555-1234", address: "123 N 1st Ave"}
contacts.delete('Raymond') // false
contacts.delete('Jessie') // true
console.log(contacts.size) // 1
周遊Map:
let myMap = new Map()
myMap.set(0, 'zero')
myMap.set(1, 'one')
for (let [key, value] of myMap) {
console.log(key + ' = ' + value)
}
// 0 = zero
// 1 = one
for (let key of myMap.keys()) {
console.log(key)
}
// 0
// 1
for (let value of myMap.values()) {
console.log(value)
}
// zero
// one
for (let [key, value] of myMap.entries()) {
console.log(key + ' = ' + value)
}
// 0 = zero
// 1 = one
使用forEach來周遊map:
myMap.forEach(function(value, key) {
console.log(key + ' = ' + value)
})
// 0 = zero
// 1 = one
Set中存儲的是唯一的對象。
我們看下Set的操作:
let mySet = new Set()
mySet.add(1) // Set [ 1 ]
mySet.add(5) // Set [ 1, 5 ]
mySet.has(1) // true
mySet.delete(1) // removes 1 from the set
set的周遊:
// logs the items in the order: 1, "some text", {"a": 1, "b": 2}, {"a": 1, "b": 2}
for (let item of mySet) console.log(item)
WeakMap,WeakSet和Map于Set的差別在于,WeakMap的key隻能是Object對象,不能是基本類型。
為什麼會有WeakMap呢?
對于JS中的Map來說,通常需要維護兩個數組,第一個數組中存儲key,第二個數組中存儲value。每次添加和删除item的時候,都需要同時操作兩個數組。
這種實作有兩個缺點,第一個缺點是每次查找的時候都需要周遊key的數組,然後找到對應的index,再通過index來從第二個數組中查找value。
第二個缺點就是key和value是強綁定的,即使key不再被使用了,也不會被垃圾回收。
是以引入了WeakMap的概念,在WeakMap中,key和value沒有這樣的強綁定關系,key如果不再被使用的話,可以被垃圾回收器回收。
因為引用關系是weak的,是以weakMap不支援key的周遊,如果你想周遊key的話,請使用Map。
本文作者:flydean程式那些事
本文連結:
http://www.flydean.com/js-built-in-objects-structures/本文來源:flydean的部落格
歡迎關注我的公衆号:「程式那些事」最通俗的解讀,最深刻的幹貨,最簡潔的教程,衆多你不知道的小技巧等你來發現!