數(shù)據(jù)類型
根據(jù)變量類型傳遞方式,可以分為基本數(shù)據(jù)類型和引用數(shù)據(jù)類型
- 基本數(shù)據(jù)類型:Number、Boolean、String、Undefined、Null、Symbol(es6)
- Null表示空對象指針
- Undefined表示未定義
- 引用類型:Object是所有引用類型的父對象
- Object、Function、Arguments、Date、Math、Error、RegExp、自定義對象等
傳參方式
- 基本數(shù)據(jù)類型和引用類型都是按值傳遞
- 按值傳遞,傳遞的是變量里的內(nèi)容,不管盒子里面存的是基本類型值還是引用類型的地址
//不影響
var obj = {
value: 1
};
function foo(o) {
o = 2;
console.log(o); //2
}
foo(obj);
console.log(obj.value) // 1
//影響
var obj = {
value: 1
};
function foo(o) {
o.value = 2;
console.log(o.value); //2
}
foo(obj);
console.log(obj.value) // 2
存儲空間
基本數(shù)據(jù)類型存儲在內(nèi)存棧中,引用類型的數(shù)據(jù)存儲在堆中(引用存儲在內(nèi)存棧)

image
類型檢測
typeof
- 不要用typeof做類型檢測
- typeof null會錯(cuò)誤的返回Object
- 在 JavaScript 最初的實(shí)現(xiàn)中,JavaScript 中的值是由一個(gè)表示類型的標(biāo)簽和實(shí)際數(shù)據(jù)值表示的。對象的類型標(biāo)簽是 0。由于 null 代表的是空指針(大多數(shù)平臺下值為 0x00),因此,null 的類型標(biāo)簽是 0,typeof null 也因此返回 "object"
- typeof Function會返回function
- typeof 無法區(qū)別基本數(shù)據(jù)類型和引用類型
// 下面的例子令人迷惑,非常危險(xiǎn),沒有用處。避免使用它們。
typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String('abc') === 'object';
類型檢測的通用方法
使用Object.prototype.toString()可以獲取對象的[[Class]]內(nèi)部屬性。[[Class]]內(nèi)部屬性根據(jù)標(biāo)準(zhǔn),只可能是下面字符串中的一個(gè):
Arguments, Array, Boolean, Date, Error, Function, JSON, Math, Number, Object, RegExp, String.
function isType(obj,type){
//[object xxx]
let classProperty = Object.prototype.toString.call(obj).slice(8,-1)
return classProperty === type
}
//true
is(new String("a"),"String")
//true
is("a","String")
instanceof
object instanceof constructor用來檢測一個(gè)對象是否為某個(gè)構(gòu)造函數(shù)的實(shí)例
function A() {
}
function B() {
}
B.prototype = new A()
let b = new B()
b instanceof B // true
b instanceof A // true
instanceof原理:
//判斷當(dāng)前構(gòu)造函數(shù)的prototype是否在原型鏈上
function new_instance_of(leftVaule, rightVaule) {
let rightProto = rightVaule.prototype; // 取右表達(dá)式的 prototype 值
leftVaule = leftVaule.__proto__; // 取左表達(dá)式的__proto__值
while (true) {
if (leftVaule === null) {
return false;
}
if (leftVaule === rightProto) {
return true;
}
leftVaule = leftVaule.__proto__
}
}
加深原型鏈理解:

image
- 可以知道prototype是構(gòu)造函數(shù)獨(dú)有屬性,proto是任意對象都有的(不管當(dāng)前對象是作為構(gòu)造函數(shù)還是原型,)并且指向其構(gòu)造函數(shù)的prototype,constructor的是原型獨(dú)有的屬性
- Function對象是任意構(gòu)造函數(shù)的構(gòu)造函數(shù)(包括function Object),所以任意構(gòu)造函數(shù)的proto指向Function.prototype
- 任意對象最終繼承自O(shè)bject.prototype(最終proto指向Object.prototype),Object.prototype.proto按規(guī)定是null
- Function的prototype和proto都指向Function.prototype
function Foo() {
}
//因?yàn)镺bject作為函數(shù)則Object.__proto__等于Function.prototype,而Function.prototype是對象,所以Function.prototype.__proto__為Object.prototype
Object instanceof Object // true
Function instanceof Function // true
Function instanceof Object // true
Foo instanceof Foo // false
Foo instanceof Object // true
Foo instanceof Function // true
賦值、淺拷貝和深拷貝

image
賦值和淺拷貝的區(qū)別
- 如果將一個(gè)對象賦值給新變量,賦的是對象在棧中的地址,不是堆中的數(shù)據(jù)。也就是新的變量和賦值的對象指向同一個(gè)存儲空間。
- 淺拷貝是按位拷貝,會創(chuàng)建一個(gè)新的對象,對原始對象的屬性進(jìn)行拷貝,如果屬性是基本類型,則拷貝的是基本類型的值,如果屬性是引用類型,則拷貝的是引用類型的內(nèi)存地址。
//對象賦值
var obj = {
name:'johe',
age:'18',
arr:[1,2]
}
var obj2 = obj
obj2.name = 'johe-test'
//受影響
obj.name
//淺拷貝
var obj = {
name:'johe',
age:'18',
arr:[1,2]
}
function shallowCopy(obj){
var cloneObj = {}
for(let property in obj){
// for in 會訪問原型鏈上的屬性,所以需要加判斷
if(obj.hasOwnProperty(property)){
cloneObj[property] = obj[property]
}
}
return cloneObj
}
var obj2 = shallowCopy(obj)
obj2.name="johe-test"
//不受影響,輸出johe
obj.name
obj2.arr[1] = 3
//受影響,輸出[1,3]
obj.arr
淺拷貝實(shí)現(xiàn)方式
- Object.assign:把任意多個(gè)源對象的可枚舉屬性拷貝給目標(biāo)對象,然后返回目標(biāo)對象。當(dāng)被拷貝對象只有一層(一層全是基本數(shù)據(jù)類型)時(shí),是深拷貝
var obj = {
arr:[1,2]
}
var cloneObj = Object.assign({},obj)
cloneObj.arr = [1,3]
//受影響,輸出[1,3]
obj.arr
- Array.prototype.concat()
let arr = [1,2,{name:'johe'}]
let arr2 = arr.concat[]
arr2[2].name = "johe-test"
//受影響輸出johe-test
arr[2].name
- Array.prototype.slice()
淺拷貝和深拷貝的區(qū)別

image
淺拷貝和深拷貝都會返回一個(gè)新對象,淺拷貝在拷貝對象屬性時(shí),如果是基本數(shù)據(jù)類型,則拷貝值,如果是引用類型,則拷貝引用(指向同一地址)。
深拷貝在拷貝對象屬性時(shí),如果是基本數(shù)據(jù)類型,則拷貝值,如果是引用類型,則生成新對象遞歸拷貝。
深拷貝實(shí)現(xiàn)
- JSON.parse(JSON.stringify()):最常用的深拷貝方法,但不能處理函數(shù)和正則
- 手寫遞歸方法:
function isType(type,obj){
return Object.prototype.toString.call(obj).slice(8,-1) === type
}
function deepClone(target){
let result
if(isType('Object',target)){
result = {}
}else if(isType('Array',target)){
result = []
}else{
return target
}
for(let i in target){
let value = target[i]
result[i] = deepClone(value)
}
return result
}