一、資料類型
基本資料類型
基本類型存儲的值
- Boolean (布爾類型)
- Undefined (為定義)
- Number (數字類型)
- Null (空)
- String (字元串類型)
- Symbol (符号類型)
對象類型/引用類型
對象在邏輯上是屬性的無序集合,是存放各種值的容器。對象值存儲的是引用位址,是以和基本類型值不可變的特性不同,對象值是可變的。
- Object
- Function
- Array
例:
var foo = 1;
var bar = 2;
var obj = {foo: 1, bar: 2}
這裡聲明的三個屬性,基本類型存儲在棧中,引用類型存在堆中,我們常用的var、let和const實際上是指針關系,指向棧和堆中的資料集
但是const指向最外層的指針(例:0x0203),切不允許修改指針的指向關系,是以object可以修改内部的屬性值,但是不能修改最外層的對象(會導緻修改指向關系),其他基本資料本身就一層資料接口,是以更加不可修改

二、深拷貝和淺拷貝
1.淺拷貝
淺拷貝是将對象第一層的每個屬性進行依次複制,但是當對象的屬性是引用類型時,實質複制的是其引用,當引用對象指向的值改變時也會跟着變化
2.深拷貝
深拷貝複制變量值,對于非基本類型的變量,則遞歸至基本類型的變量後,再複制。深拷貝的對象與原來的對象是完全隔離的,互不影響,對一個對象的修改并不會影響另一個對象。
實際執行:
var objBase = {
name: '小明',
age: 12,
like: {
work: '程式設計',
sport: '跑步'
},
say: function() {
return `${this.name}說:我喜歡${this.like.work}`
}
}
// 1.0 JSON序列化和反序列化
var objNew1 = JSON.parse(JSON.stringify(objBase))
// 2.0 遞歸拷貝
function deepClone(obj, hash = new WeakMap()) {
if (obj instanceof RegExp) return new RegExp(obj)
if (obj instanceof Date) return new Date(obj)
if (obj === null || typeof obj !== 'object') {
// 不是複雜類型,直接傳回
return obj
}
if (hash.has(obj)) {
return hash.get(obj)
}
/**
* 如果obj是數組,那麼 obj.constructor 是 [Function: Array]
* 如果obj是對象,那麼 obj.constructor 是 [Function: Object]
*/
let t = new obj.construtor()
hash.set(obj, t)
for (let key in obj) {
// 遞歸
if (obj.hasOwnProperty(key)) { //是否是自身的屬性
t[key] = deepClone(obj[key], hash)
}
}
return t
}
var objNew2 = deepClone(objBase)
三、資料類型判斷
1. typeof
這個方法是多數開發者最熟知的,對于基本資料類型判斷很友善準确,但是對于複雜的資料類型是有缺點的,比如:
typeof 'seymoe' // 'string'
typeof true // 'boolean'
typeof 10 // 'number'
typeof Symbol() // 'symbol'
typeof null // 'object' 無法判定是否為 null
typeof undefined // 'undefined'
typeof {} // 'object'
typeof [] // 'object'
typeof(() => {}) // 'function'
對于數組和對象的判斷,實際上是不準确的,統一識别成' object '類型
2.instanceof
這個方法是依據原型鍊去做判斷,但是實際上也是有問題的,比如:
[] instanceof Array // true
({}) instanceof Object // true
(()=>{}) instanceof Function // true
let arr = []
let obj = {}
arr instanceof Array // true
arr instanceof Object // true
obj instanceof Object // true
arr
數組相當于
new Array()
出的一個執行個體,是以
arr.__proto__ === Array.prototype
,又因為
Array
屬于
Object
子類型,即
Array.prototype.__proto__ === Object.prototype
,是以
Object
構造函數在
arr
的原型鍊上。是以
instanceof
仍然無法準确判斷一個值到底屬于數組還是普通對象
3.Object.prototype.toString()
Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call([]) // '[object Array]'
Object.prototype.toString.call(() => {}) // '[object Function]'
Object.prototype.toString.call('hello world') // '[object String]'
Object.prototype.toString.call(1) // '[object Number]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(Symbol()) // '[object Symbol]'
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
Object.prototype.toString.call(new Date()) // '[object Date]'
Object.prototype.toString.call(Math) // '[object Math]'
Object.prototype.toString.call(new Set()) // '[object Set]'
Object.prototype.toString.call(new WeakSet()) // '[object WeakSet]'
Object.prototype.toString.call(new Map()) // '[object Map]'
Object.prototype.toString.call(new WeakMap()) // '[object WeakMap]'
這個方法雖然最準确,但是實際上還是需要注意:
- 該方法本質是通過
方法得到對象内部屬性Object.prototype.toString()
[[Class]]
- 傳入原始類型卻能夠判定出結果是因為對值進行了包裝
-
和null
能夠輸出結果是内部實作有做處理undefined
四、資料類型轉
1. Number、String、Boolean
這三個是我們最常用的,對幾種基本資料類型做轉化的方式
2.toString - Object.prototype.toString()
toString()
方法傳回一個表示該對象的字元串。每個對象都有一個
toString()
方法,當對象被表示為文本值時或者當以期望字元串的方式引用對象時,該方法被自動調用,
**** valueOf()
和
toString()
在特定的場合下會自行調用。* * * *
3.valueOf - Object.prototype.valueOf()
Object.prototype.valueOf()
valueOf()
方法傳回指定對象的原始值。
JS
調用
valueOf()
方法用來把對象轉換成原始類型的值(數值、字元串和布爾值)。但是我們很少需要自己調用此函數,
valueOf
方法一般都會被
JS
自行調用。不同對象的
valueOf
實作:
- String => 傳回字元串值
- Number => 傳回數字值
- Date => 傳回一個數字,即時間值,字元串中内容是依賴于具體實作的
- Boolean => 傳回Boolean的this值
- Object => 傳回this
4.隐式類型轉換(這個有機會我再補下)
最後留下一題:
var a = ?;
if(a == 1 && a == 2 && a == 3){
console.log(1);
}
// 當a在什麼情況下,能列印出來 1
答案