今天聊一下clone這個前端面試高頻問題,由此引出typeof、instanceof、Object.prototype.toString這些javascript Api。
下面我們先詳細的聊一下,完了解決下面試官的問題。
typeof
typeof能獲取一個變量或表達式的類型。
-
原始類型
- Boolean
- Null
- Undefined
- String
- Symbol
- Number
- Symbol
- 和 引用類型 Object,Function
下面看一些栗子
//基礎類型也可以說非引用類型
let str = 'hello word!'
console.log(typeof str) //string
let num = 12
console.log(typeof num) //number
let udf = undefined
console.log(typeof udf) //undefined
let bl = true
console.log(typeof bl) //boolean
let nl = null
console.log(nl) //null
let sl = Symbol()
console.log(typeof sl) //symbol
//複合類型也可以說是引用類型,
let obj = {
a: 1
}
console.log(typeof obj) //object
let arr = [1, 2, 3]
console.log(typeof arr) //object
//函數也屬於引用類型,不過typeof卻能準確的返回類型
function fn() {}
console.log(typeof fn) //function
從以上的執行結果可以看出,typeof不能夠準確分返回所有類型
instenceof
我們從instenceof的實現來了解下instenceof是幹什麼的
// 模擬instenceof實現
// 1、instenceof接收兩個參數
// 2、返回true或false
function myInstenceof(X, Y) {
let L = X._proto_
let R = Y.prototype
if (L !== R) {
return false
}
return true
}
// test
function Fn() {
}
let newFn = new Fn()
console.log(newFn)
console.log(new Fn())
console.log(myInstenceof(newFn, new Fn())) //true
console.log(myInstenceof([], new Array())) //true
console.log(myInstenceof([], new Object())) //true
以上demo我們就能看出,instenceof也不夠靠譜,模擬實現就是判斷X的原型知否在Y的原型鏈上。
數組之所以instenceof Object爲true是因爲 [].prototype->new Array->new Object->null
上邊說了typeof和instenceof其實就是想說這兩個對於深度clone的實現來說不夠嚴謹要不就是多層判斷。
Object.prototype.toString.call()
接下里我們說個靠譜的
Object.prototype.toString.call(''); // [object String]
Object.prototype.toString.call(1); // [object Number]
Object.prototype.toString.call(true); // [object Boolean]
Object.prototype.toString.call(undefined); // [object Undefined]
Object.prototype.toString.call(null); // [object Null]
Object.prototype.toString.call(new Function()); // [object Function]
Object.prototype.toString.call(new Date()); // [object Date]
Object.prototype.toString.call([]); // [object Array]
Object.prototype.toString.call(new RegExp()); // [object RegExp]
Object.prototype.toString.call(new Error()); // [object Error]
Object.prototype.toString.call(document); // [object HTMLDocument]
Object.prototype.toString.call(window); //[object Window]
靠譜!
接下來我們就用Object.prototype.toString.call()來解答一下面試題
function clone(obj, o) {
//Object.prototype.toString.call(obj)返回類似[Object Array] 利用slice來截取我們需要的字符串
let type = Object.prototype.toString.call(obj).slice(8, -1)
// 如果是Object
if (type === 'Object') {
o = {}
for (let k in obj) {
o[k] = clone(obj[k]);
}
// 如果是對象
} else if (type === 'Array') {
o = []
for (let i = 0; i < obj.length; i++) {
o.push(clone(obj[i]));
}
} else {
// 非引用類型
o = obj
}
return o
}
let obj1 = {
a: [1, 2, 3, 4, 5, 6],
b: {
c: 2
},
d: 1,
f: function() {
return 1
}
}
let obj2 = clone(obj1)
obj2.f = function() {
return 2
}
obj2.a = 1
console.log(obj1)
console.log(obj2)
測試打印結果,obj2的改變不會影響到obj1。
歡迎吐槽!