<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
</body>
</html>
// Step 1:深拷贝数组和对象
function clone(target) {
if(typeof target == 'object') {
let _target = Array.isArray(target) ? [] : {}
for(let i in target) {
_target[i] = clone(target[i])
}
return _target
} else {
return target
}
}
// Step 2:但是如果循环引用,上面的代码就很会导致栈内存溢出
// 【解决】利用Map,拷贝前检查有无拷贝过
// => Map是强引用类型,内存不会自动释放,会造成非常大的额外消耗(任何值都可以作为一个键或一个值)
// => 使用WeakMap弱引用类型,内存会自动释放(键必须是对象,而值可以是任意的)
function clone(target, map = new WeakMap()) {
if (typeof target === 'object') {
let _target = Array.isArray(target) ? [] : {}
if(map.get(target)) {
return map.get(target)
}
map.set(target, _target)
for(let i in target) {
_target[i] = clone(target[i], map)
}
return _target
} else {
return target
}
}
// Step 3:做一下性能优化
// 【优化点】执行效率:while、for > for in
// 其中for in执行效率是三者中最差的,所以不能用for in
if(false) {
let arr = [new Array(1000000).keys()]
console.time()
// 第 1 种:while 用时:8.023193359375ms
let i = 0
while(i < arr.length) { i++ }
// 第 2 种:for 用时:7.807861328125ms
for(let i = 0; i < arr.length; i++) { }
// 第 3 种:for in 用时:190.059814453125ms
for(let i in arr) { }
// 第 4 种:for in 用时:10.40576171875ms
arr.forEach(() => {})
console.timeEnd()
}
function clone(target, map = new WeakMap()) {
if (typeof target === 'object') {
let isArray = Array.isArray(target);
let _target = isArray ? [] : {}
if(map.get(target)) {
return map.get(target)
}
map.set(target, _target)
let keys = isArray ? undefined : Object.keys(target)
forEach(keys || target, (value, i) => {
if (keys) {
i = value
}
_target[i] = clone(target[i], map)
})
return _target
} else {
return target
}
}
function forEach(array, iteratee) {
let index = -1;
const length = array.length;
while (++index < length) {
iteratee(array[index], index);
}
return array;
}
// Step 4:兼容其他数据类型
// 以上代码只兼容object和array两种数据类型,值如果存在null、function则会报错
// 一个简单的测试
let target = {
a: undefined,
b: 'hello',
c: {
child: 'child'
},
d: [1, 2, 3],
f: { f: { f: { f: { f: { f: { f: { f: { f: { f: { f: { f: {} } } } } } } } } } } },
}
let result = clone(target)
target.target = target // 循环引用
target.c.child = 'new child' // 修改原对象
console.log(result) // 打印拷贝值
Output
This bin was created anonymously and its free preview time has expired (learn why). — Get a free unrestricted account
Dismiss xKeyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |