【JavaScript 面向对象编程——《深浅拷贝》】计数器例子

    技术2022-07-11  71

    相关文章导航

    👉【JavaScript 面向对象编程——《深浅拷贝》】计数器例子👈

         【JavaScript 面向对象编程——《设计模式》】计数器例子

         【JavaScript 面向对象编程——《原型继承》】计数器例子


    关于深浅拷贝:

    【JavaScript 浅拷贝】Object.create()、Object.assign()、扩展运算符【JavaScript 深拷贝】$.extend() 方法、自封装函数(进来拿代码套用啦!)赋值、浅拷贝、深拷贝之间的区别:

    文章目录

    🔸浅拷贝🔸(❌慎用)一、【ES5】Object.create()方法优缺点 二、【ES6】Object.assign()方法优缺点 三、【ES6】对象展开运算符 "..."优缺点 🔸深拷贝🔸一、【jQuery】extend()方法优缺点 二、递归算法(1)第一种递归优缺点(2)第二种递归优缺点 三、二叉树遍历算法【DFS】树深度优先遍历(1)第一种 DFS 写法优缺点(2)第二种 DFS 写法优缺点 【BFS】树广度优先遍历(1)第一种 BFS 写法优缺点(2)第二种 BFS 写法优缺点


    🔸浅拷贝🔸(❌慎用)

    一、【ES5】Object.create()方法

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript"> // 定义对象字面量 var makeCounter = { num : 0, changeBy : function(val) { this.num += val; }, add : function() { this.changeBy(1); }, red : function() { this.changeBy(-1); }, value : function() { return this.num; } }; // 封装深拷贝函数 function deepClone(obj) { // 通过调用函数创建一个以指定对象的原型为模板的新对象 var copy = Object.create(Object.getPrototypeOf(obj)); // 利用数组的 “Array.prototype.forEach” 方法进行复制,实现深拷贝 var propNames = Object.getOwnPropertyNames(obj); propNames.forEach(function(name) { // 获取指定对象上一个自有属性对应的属性描述符。 var desc = Object.getOwnPropertyDescriptor(obj, name); // 直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。 Object.defineProperty(copy, name, desc); }); return copy; } // 执行操作 function event(ele, btn1, btn2, obj) { btn1.onclick = function() { obj.add(); ele.innerHTML = obj.value(); } btn2.onclick = function() { obj.red(); ele.innerHTML = obj.value(); } ele.innerHTML = obj.value(); } window.onload = function() { // 计数器 1 var Counter1 = deepClone(makeCounter); var add1 = document.getElementById('add1'); var red1 = document.getElementById('red1'); var demo1 = document.getElementById('demo1'); event(demo1, add1, red1, Counter1); // 计数器 2 var Counter2 = deepClone(makeCounter); var add2 = document.getElementById('add2'); var red2 = document.getElementById('red2'); var demo2 = document.getElementById('demo2'); event(demo2, add2, red2, Counter2); } </script> </head> <body> <h3>【ES5】Object.create()方法</h3> <hr /> <p>计数器 1</p> <input type="button" id="add1" value="自增 (+1)" /> <input type="button" id="red1" value="自减 (-1)" /> <p id="demo1"></p> <hr /> <p>计数器 2</p> <input type="button" id="add2" value="自增 (+1)" /> <input type="button" id="red2" value="自减 (-1)" /> <p id="demo2"></p> </body> </html>

    优缺点

    【优点】:适用于仅有一层嵌套层的对象的拷贝。 【缺点】:无法对多层对象嵌套层实现深拷贝。

    二、【ES6】Object.assign()方法

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript"> // 定义对象字面量 var makeCounter = { num : 0, changeBy : function(val) { this.num += val; }, add : function() { this.changeBy(1); }, red : function() { this.changeBy(-1); }, value : function() { return this.num; } }; // 执行操作 function event(ele, btn1, btn2, obj) { btn1.onclick = function() { obj.add(); ele.innerHTML = obj.value(); } btn2.onclick = function() { obj.red(); ele.innerHTML = obj.value(); } ele.innerHTML = obj.value(); } window.onload = function() { // 计数器 1 var Counter1 = Object.assign({}, makeCounter); var add1 = document.getElementById('add1'); var red1 = document.getElementById('red1'); var demo1 = document.getElementById('demo1'); event(demo1, add1, red1, Counter1); // 计数器 2 var Counter2 = Object.assign({}, makeCounter); var add2 = document.getElementById('add2'); var red2 = document.getElementById('red2'); var demo2 = document.getElementById('demo2'); event(demo2, add2, red2, Counter2); } </script> </head> <body> <h3>【ES6】Object.assign()方法(该方法实际属于浅拷贝)</h3> <hr /> <p>计数器 1</p> <input type="button" id="add1" value="自增 (+1)" /> <input type="button" id="red1" value="自减 (-1)" /> <p id="demo1"></p> <hr /> <p>计数器 2</p> <input type="button" id="add2" value="自增 (+1)" /> <input type="button" id="red2" value="自减 (-1)" /> <p id="demo2"></p> </body> </html>

    优缺点

    【优点】:a)适用于仅有一层嵌套层的对象的拷贝;b)方便简洁快捷,一行代码解决… 【缺点】:无法对多层对象嵌套层实现深拷贝。

    三、【ES6】对象展开运算符 “…”

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript"> // 定义对象字面量 var makeCounter = { num : 0, changeBy : function(val) { this.num += val; }, add : function() { this.changeBy(1); }, red : function() { this.changeBy(-1); }, value : function() { return this.num; } }; // 执行操作 function event(ele, btn1, btn2, obj) { btn1.onclick = function() { obj.add(); ele.innerHTML = obj.value(); } btn2.onclick = function() { obj.red(); ele.innerHTML = obj.value(); } ele.innerHTML = obj.value(); } window.onload = function() { // 计数器 1 var Counter1 = {...makeCounter}; var add1 = document.getElementById('add1'); var red1 = document.getElementById('red1'); var demo1 = document.getElementById('demo1'); event(demo1, add1, red1, Counter1); // 计数器 2 var Counter2 = {...makeCounter}; var add2 = document.getElementById('add2'); var red2 = document.getElementById('red2'); var demo2 = document.getElementById('demo2'); event(demo2, add2, red2, Counter2); } </script> </head> <body> <h3>【ES6】扩展运算符</h3> <hr /> <p>计数器 1</p> <input type="button" id="add1" value="自增 (+1)" /> <input type="button" id="red1" value="自减 (-1)" /> <p id="demo1"></p> <hr /> <p>计数器 2</p> <input type="button" id="add2" value="自增 (+1)" /> <input type="button" id="red2" value="自减 (-1)" /> <p id="demo2"></p> </body> </html>

    优缺点

    【优点】:a)适用于仅有一层嵌套层的对象的拷贝;b)方便简洁快捷,一行代码解决… 【缺点】:无法对多层对象嵌套层实现深拷贝。

    🔸深拷贝🔸

    一、【jQuery】extend()方法

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script> <script type="text/javascript"> // 定义对象字面量 var makeCounter = { num : 0, changeBy : function(val) { this.num += val; }, add : function() { this.changeBy(1); }, red : function() { this.changeBy(-1); }, value : function() { return this.num; } }; // 执行操作 function event(ele, btn1, btn2, obj) { btn1.onclick = function() { obj.add(); ele.innerHTML = obj.value(); } btn2.onclick = function() { obj.red(); ele.innerHTML = obj.value(); } ele.innerHTML = obj.value(); } window.onload = function() { // 计数器 1 var Counter1 = $.extend(true, {}, makeCounter); var add1 = document.getElementById('add1'); var red1 = document.getElementById('red1'); var demo1 = document.getElementById('demo1'); event(demo1, add1, red1, Counter1); // 计数器 2 var Counter2 = $.extend(true, {}, makeCounter); var add2 = document.getElementById('add2'); var red2 = document.getElementById('red2'); var demo2 = document.getElementById('demo2'); event(demo2, add2, red2, Counter2); } </script> </head> <body> <h3>【jQuery】extend()方法</h3> <hr /> <p>计数器 1</p> <input type="button" id="add1" value="自增 (+1)" /> <input type="button" id="red1" value="自减 (-1)" /> <p id="demo1"></p> <hr /> <p>计数器 2</p> <input type="button" id="add2" value="自增 (+1)" /> <input type="button" id="red2" value="自减 (-1)" /> <p id="demo2"></p> </body> </html>

    优缺点

    【优点】:a)方便简单且快捷;b)支持很多层级的数据; 【缺点】:a)无法拷贝对象中值为 ‘undefined’ 的属性;b)鸡肋:为了一个方法引入 jQuery 库…除非项目用 jQuery 开发;

    二、递归算法

    (1)第一种递归

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript"> // 定义对象字面量 var makeCounter = { num : 0, changeBy : function(val) { this.num += val; }, add : function() { this.changeBy(1); }, red : function() { this.changeBy(-1); }, value : function() { return this.num; } }; // 递归封装深拷贝 function deepClone(obj) { if (obj === null) { return null; } else if (typeof obj !== 'object') { // 不再具有下一层次 return obj; } else if (obj.constructor === Date) { return new Date(obj); } // 保持继承链 var objClone = new obj.constructor (); for (var k in obj) { // 不遍历其原型链上的属性 if (obj.hasOwnProperty(k)) { // 判断obj子元素是否为对象,如果是,递归复制 if (obj[k] && typeof obj[k] === 'object') { objClone[k] = deepClone(obj[k]); } else { objClone[k] = obj[k]; } // 简写 // objClone[k] = typeof obj[k] === 'object' ? deepClone(obj[k]) : obj[k]; } } // 返回深度克隆后的对象 return objClone; }; // 执行操作 function event(ele, btn1, btn2, obj) { btn1.onclick = function() { obj.add(); ele.innerHTML = obj.value(); } btn2.onclick = function() { obj.red(); ele.innerHTML = obj.value(); } ele.innerHTML = obj.value(); } window.onload = function() { // 计数器 1 var Counter1 = deepClone(makeCounter); var add1 = document.getElementById('add1'); var red1 = document.getElementById('red1'); var demo1 = document.getElementById('demo1'); event(demo1, add1, red1, Counter1); // 计数器 2 var Counter2 = deepClone(makeCounter); var add2 = document.getElementById('add2'); var red2 = document.getElementById('red2'); var demo2 = document.getElementById('demo2'); event(demo2, add2, red2, Counter2); } </script> </head> <body> <h3>(一)递归算法</h3> <hr /> <p>计数器 1</p> <input type="button" id="add1" value="自增 (+1)" /> <input type="button" id="red1" value="自减 (-1)" /> <p id="demo1"></p> <hr /> <p>计数器 2</p> <input type="button" id="add2" value="自增 (+1)" /> <input type="button" id="red2" value="自减 (-1)" /> <p id="demo2"></p> </body> </html>

    优缺点

    【解释】:a)用 new obj.constructor () 构造函数新建一个空的对象,而不是使用 {} 或者 [],这样可以保持原形链的继承;b)用 obj.hasOwnProperty(key) 来判断属性是否来自原型链上,因为 for…in… 也会遍历其原型链上的可枚举属性;c)对于 function 类型,这里是直接赋值的,还是共享一个内存值。这是因为函数更多的是完成某些功能,有个输入值和返回值,而且对于上层业务而言更多的是完成业务功能,并不需要真正将函数深拷贝。 【优点】:a)常用的递归封装方法,可满足普通对象深拷贝;b)支持很多层级的数据; 【缺点】:a)无法保持引用;b)当数据的层次很深,会栈溢出;

    (2)第二种递归

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript"> // 定义对象字面量 var makeCounter = { num : 0, changeBy : function(val) { this.num += val; }, add : function() { this.changeBy(1); }, red : function() { this.changeBy(-1); }, value : function() { return this.num; } }; // 创建对元素进行类型判断的函数 function getType(obj) { // tostring会返回对应不同的标签的构造函数 var _toString = Object.prototype.toString; var map = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Undefined]' : 'undefined', '[object Null]' : 'null', '[object Object]' : 'object' }; if (obj instanceof Element) { return 'element'; } return map[_toString.call(obj)]; } // 递归封装深拷贝 function deepClone(obj) { var type = getType(obj); var objClone; if (type === 'array') { objClone = []; } else if (type === 'object') { objClone = {}; } else { // 不再具有下一层次 return obj; } // 类型为数组或对象时的递归复制 if (type === 'array') { for (var i = 0, len = obj.length; i < len; i++) { objClone.push(deepClone(obj[i])); } } else if (type === 'object') { for (var k in obj) { objClone[k] = deepClone(obj[k]); } } // 返回深度克隆后的对象 return objClone; } // 执行操作 function event(ele, btn1, btn2, obj) { btn1.onclick = function() { obj.add(); ele.innerHTML = obj.value(); } btn2.onclick = function() { obj.red(); ele.innerHTML = obj.value(); } ele.innerHTML = obj.value(); } window.onload = function() { // 计数器 1 var Counter1 = deepClone(makeCounter); var add1 = document.getElementById('add1'); var red1 = document.getElementById('red1'); var demo1 = document.getElementById('demo1'); event(demo1, add1, red1, Counter1); // 计数器 2 var Counter2 = deepClone(makeCounter); var add2 = document.getElementById('add2'); var red2 = document.getElementById('red2'); var demo2 = document.getElementById('demo2'); event(demo2, add2, red2, Counter2); } </script> </head> <body> <h3>(二)递归算法</h3> <hr /> <p>计数器 1</p> <input type="button" id="add1" value="自增 (+1)" /> <input type="button" id="red1" value="自减 (-1)" /> <p id="demo1"></p> <hr /> <p>计数器 2</p> <input type="button" id="add2" value="自增 (+1)" /> <input type="button" id="red2" value="自减 (-1)" /> <p id="demo2"></p> </body> </html>

    优缺点

    【解释】:对于 function 类型,这里是直接赋值的,还是共享一个内存值。这是因为函数更多的是完成某些功能,有个输入值和返回值,而且对于上层业务而言更多的是完成业务功能,并不需要真正将函数深拷贝。 【优点】:a)可满足普通对象深拷贝;b)支持很多层级的数据; 【缺点】:a)无法保持引用;b)当数据的层次很深,会栈溢出;

    三、二叉树遍历算法

    【DFS】树深度优先遍历

    (1)第一种 DFS 写法

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript"> // 定义对象字面量 var makeCounter = { num : 0, changeBy : function(val) { this.num += val; }, add : function() { this.changeBy(1); }, red : function() { this.changeBy(-1); }, value : function() { return this.num; } }; // 深度优先深度克隆, 利用栈的方式实现 // 防栈溢出 function deepClone(obj) { var objClone = {}; // 栈 var loopList = [{ parent: objClone, key: undefined, data: obj, }]; while (loopList.length) { // 深度优先 var node = loopList.pop(); var parent = node.parent; var key = node.key; var data = node.data; // 初始化赋值目标,key为undefined则拷贝到父元素,否则拷贝到子元素 var res = parent; if (typeof key !== 'undefined') { res = parent[key] = {}; } for (var k in data) { if (data.hasOwnProperty(k)) { if (typeof data[k] === 'object') { // 下一次循环 loopList.push({ parent : res, key : k, data : data[k], }); } else { res[k] = data[k]; } } } } // 返回深度克隆后的对象 return objClone; } // 执行操作 function event(ele, btn1, btn2, obj) { btn1.onclick = function() { obj.add(); ele.innerHTML = obj.value(); } btn2.onclick = function() { obj.red(); ele.innerHTML = obj.value(); } ele.innerHTML = obj.value(); } window.onload = function() { // 计数器 1 var Counter1 = deepClone(makeCounter); var add1 = document.getElementById('add1'); var red1 = document.getElementById('red1'); var demo1 = document.getElementById('demo1'); event(demo1, add1, red1, Counter1); // 计数器 2 var Counter2 = deepClone(makeCounter); var add2 = document.getElementById('add2'); var red2 = document.getElementById('red2'); var demo2 = document.getElementById('demo2'); event(demo2, add2, red2, Counter2); } </script> </head> <body> <h3>【DFS】树深度优先遍历(一)</h3> <hr /> <p>计数器 1</p> <input type="button" id="add1" value="自增 (+1)" /> <input type="button" id="red1" value="自减 (-1)" /> <p id="demo1"></p> <hr /> <p>计数器 2</p> <input type="button" id="add2" value="自增 (+1)" /> <input type="button" id="red2" value="自减 (-1)" /> <p id="demo2"></p> </body> </html>

    优缺点

    【优点】:a)不会栈溢出;b)支持很多层级的数据; 【缺点】:…

    (2)第二种 DFS 写法

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript"> // 定义对象字面量 var makeCounter = { num : 0, changeBy : function(val) { this.num += val; }, add : function() { this.changeBy(1); }, red : function() { this.changeBy(-1); }, value : function() { return this.num; } }; // 创建对元素进行类型判断的函数 function getType(obj) { // tostring会返回对应不同的标签的构造函数 var _toString = Object.prototype.toString; var map = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Undefined]' : 'undefined', '[object Null]' : 'null', '[object Object]' : 'object' }; if (obj instanceof Element) { return 'element'; } return map[_toString.call(obj)]; } // 深度优先深度克隆, 利用栈的方式实现 // 解决【递归、对象环、边界处理(比如函数,Set等)、防栈溢出】问题 function deepClone(obj) { var type = getType(obj); var objClone = {}; // 用于存储复制过程中访问过的对象的队列,避免对象环的问题 var visitQueue = []; if (type === 'array' || type === 'object') { var index = visitQueue.indexOf(obj); if (index > -1){ objClone = visitQueue[index] } else { visitQueue.push(obj); for (var key in obj) { objClone[key] = deepClone(obj[key], visitQueue); } } } else if (type === 'function') { // 处理函数 objClone = eval( '(' + obj.toString() + ')'); } else { // 处理原始值 objClone = obj; } // 返回深度克隆后的对象 return objClone; } // 执行操作 function event(ele, btn1, btn2, obj) { btn1.onclick = function() { obj.add(); ele.innerHTML = obj.value(); } btn2.onclick = function() { obj.red(); ele.innerHTML = obj.value(); } ele.innerHTML = obj.value(); } window.onload = function() { // 计数器 1 var Counter1 = deepClone(makeCounter); var add1 = document.getElementById('add1'); var red1 = document.getElementById('red1'); var demo1 = document.getElementById('demo1'); event(demo1, add1, red1, Counter1); // 计数器 2 var Counter2 = deepClone(makeCounter); var add2 = document.getElementById('add2'); var red2 = document.getElementById('red2'); var demo2 = document.getElementById('demo2'); event(demo2, add2, red2, Counter2); } </script> </head> <body> <h3>【DFS】树深度优先遍历(二)</h3> <hr /> <p>计数器 1</p> <input type="button" id="add1" value="自增 (+1)" /> <input type="button" id="red1" value="自减 (-1)" /> <p id="demo1"></p> <hr /> <p>计数器 2</p> <input type="button" id="add2" value="自增 (+1)" /> <input type="button" id="red2" value="自减 (-1)" /> <p id="demo2"></p> </body> </html>

    优缺点

    【优点】:a)不会栈溢出;b)支持很多层级的数据; 【缺点】:…

    【BFS】树广度优先遍历

    (1)第一种 BFS 写法

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript"> // 定义对象字面量 var makeCounter = { num : 0, changeBy : function(val) { this.num += val; }, add : function() { this.changeBy(1); }, red : function() { this.changeBy(-1); }, value : function() { return this.num; } }; // 广度优先深度克隆, 利用队列的方式实现 // 利用objClone建立一个与原对象相同的数据结构, 遇到可处理的值(比如原始值,函数,就处理后赋值到相应的节点下) function deepClone(obj) { var objClone = {}; // 进队列 var originQueue = [obj]; // 同时objClone也跟着一起进队列 var copyQueue = [objClone]; // 以下两个队列用来保存复制过程中访问过的对象,以此来避免对象环的问题(对象的某个属性值是对象本身) var visitQueue = []; var copyVisitQueue = []; while (originQueue.length > 0) { var _obj = copyQueue.shift(); var _data = originQueue.shift(); copyVisitQueue.push(_obj); visitQueue.push(_data); for (var k in _data) { var _value = _data[k]; if (typeof _value !== 'object') { _obj[k] = _value; } else { // 使用indexOf可以发现数组中是否存在相同的对象(实现indexOf的难点就在于对象比较) var index = visitQueue.indexOf(_value); if (index >= 0) { // 出现环的情况不需要再取出遍历 _obj[k] = copyVisitQueue[index]; } else { originQueue.push(_value); _obj[k] = {}; copyQueue.push(_obj[k]); } } } } // 返回深度克隆后的对象 return objClone; } // 执行操作 function event(ele, btn1, btn2, obj) { btn1.onclick = function() { obj.add(); ele.innerHTML = obj.value(); } btn2.onclick = function() { obj.red(); ele.innerHTML = obj.value(); } ele.innerHTML = obj.value(); } window.onload = function() { // 计数器 1 var Counter1 = deepClone(makeCounter); var add1 = document.getElementById('add1'); var red1 = document.getElementById('red1'); var demo1 = document.getElementById('demo1'); event(demo1, add1, red1, Counter1); // 计数器 2 var Counter2 = deepClone(makeCounter); var add2 = document.getElementById('add2'); var red2 = document.getElementById('red2'); var demo2 = document.getElementById('demo2'); event(demo2, add2, red2, Counter2); } </script> </head> <body> <h3>【BFS】树广度优先遍历(一)</h3> <hr /> <p>计数器 1</p> <input type="button" id="add1" value="自增 (+1)" /> <input type="button" id="red1" value="自减 (-1)" /> <p id="demo1"></p> <hr /> <p>计数器 2</p> <input type="button" id="add2" value="自增 (+1)" /> <input type="button" id="red2" value="自减 (-1)" /> <p id="demo2"></p> </body> </html>

    优缺点

    【优点】:a)不会栈溢出;b)支持很多层级的数据; 【缺点】:…

    (2)第二种 BFS 写法

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript"> // 定义对象字面量 var makeCounter = { num : 0, changeBy : function(val) { this.num += val; }, add : function() { this.changeBy(1); }, red : function() { this.changeBy(-1); }, value : function() { return this.num; } }; // 创建对元素进行类型判断的函数 function getType(obj) { // tostring会返回对应不同的标签的构造函数 var _toString = Object.prototype.toString; var map = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Undefined]' : 'undefined', '[object Null]' : 'null', '[object Object]' : 'object' }; if (obj instanceof Element) { return 'element'; } return map[_toString.call(obj)]; } // 广度优先深度克隆, 利用队列的方式实现 // 利用objClone建立一个与原对象相同的数据结构, 遇到可处理的值(比如原始值,函数,就处理后赋值到相应的节点下) function deepClone(obj) { var objClone = {}; // 进队列 var originQueue = [obj]; // 同时objClone也跟着一起进队列 var copyQueue = [objClone]; // 用于存储复制过程中访问过的对象的队列,避免对象环的问题 var visitQueue = []; while(originQueue.length){ var _obj = originQueue.shift(); var _data = copyQueue.shift(); if (getType(_obj) === 'array' || getType(_obj) === 'object') { for(item in _obj){ var val = _obj[item]; if (getType(val) === 'object') { var index = visitQueue.indexOf(val); if (~index) { // 对象环 _data[item] = visitQueue[index]; } else { // 新的对象,给objClone一个对应属性的空对象 originQueue.push(val); _data[item] = {}; copyQueue.push(_data[item]); visitQueue.push(val); } } else if (getType(val) === 'array') { originQueue.push(val); _data[item] = []; copyQueue.push(_data[item]) } else if (getType(val) === 'function') { // 处理函数 _data[item] = eval( '(' + val.toString() + ')'); } else { // 处理原始值 _data[item] = val; } } } else if (getType(obj) === 'function') { // 处理函数 _data = eval( '(' + _obj.toString() + ')'); } else { // 处理原始值 _data = _obj; } } // 返回深度克隆后的对象 return objClone; } // 执行操作 function event(ele, btn1, btn2, obj) { btn1.onclick = function() { obj.add(); ele.innerHTML = obj.value(); } btn2.onclick = function() { obj.red(); ele.innerHTML = obj.value(); } ele.innerHTML = obj.value(); } window.onload = function() { // 计数器 1 var Counter1 = deepClone(makeCounter); var add1 = document.getElementById('add1'); var red1 = document.getElementById('red1'); var demo1 = document.getElementById('demo1'); event(demo1, add1, red1, Counter1); // 计数器 2 var Counter2 = deepClone(makeCounter); var add2 = document.getElementById('add2'); var red2 = document.getElementById('red2'); var demo2 = document.getElementById('demo2'); event(demo2, add2, red2, Counter2); } </script> </head> <body> <h3>【BFS】树广度优先遍历(二)</h3> <hr /> <p>计数器 1</p> <input type="button" id="add1" value="自增 (+1)" /> <input type="button" id="red1" value="自减 (-1)" /> <p id="demo1"></p> <hr /> <p>计数器 2</p> <input type="button" id="add2" value="自增 (+1)" /> <input type="button" id="red2" value="自减 (-1)" /> <p id="demo2"></p> </body> </html>

    优缺点

    【优点】:a)不会栈溢出;b)支持很多层级的数据; 【缺点】:…
    Processed: 0.017, SQL: 10