迅雷面试题:深拷贝对象,除了原型上的属性?
来源:互联网 发布:node readfilesync 编辑:程序博客网 时间:2024/05/16 19:16
第一种:深拷贝原型上的属性
function clone(Obj) { var buf; if (Obj instanceof Array) { buf = []; // 创建一个空的数组 var i = Obj.length; while (i--) { buf[i] = clone(Obj[i]); } return buf; } else if (Obj instanceof Object){ buf = {}; // 创建一个空对象 for (var k in Obj) { // 为这个对象添加新的属性 buf[k] = clone(Obj[k]); } return buf; }else{ return Obj; }}//测试function O() { this.yyy = 'yyy';}function X() { this.xxx = 'xxx';}X.prototype = new O();x = new X();var obj = { a : {k1:'a'}, b : 'b',x:x};var obj2 = clone(obj);obj.x.yyy = 'zzz'console.log(obj2);console.log(obj2.x.yyy);
以上对吗,对象x具有原型上的属性,通过函数clone也深拷贝了原型上的属性;测试可知
改变对象obj上的原型属性,obj2不变。
obj.x.yyy = 'zzz'
第二种:不深拷贝原型上的属性(以及构造函数非和构造函数非Object的对象)
$ = function() { var copyIsArray, hasOwn = Object.prototype.hasOwnProperty, isPlainObject = function(obj) { if (obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) { return false; } var key; for (key in obj) { } return key === undefined || hasOwn.call(obj, key); }, extend = function(deep, target, options) { var name,copy,clone; for (name in options) { src = target[name]; copy = options[name]; if (target === copy) { continue; } //为了避免无限循环 if (deep && copy && (isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { if (copyIsArray) {//如果copy是数组 copyIsArray = false;//回归初始值 clone = src && Array.isArray(src) ? src : [];//因为这是对象合并,所以可能target[name]是存在的,存在则不需要拷贝。 } else { clone = src && isPlainObject(src) ? src : {}; } target[name] = extend(deep, clone, copy); } else if (copy !== undefined) { target[name] = copy; } } return target; }; return { extend : extend };}();obj1 = { a : 'a', b : 'b', y : '1' };obj2 = { x : { xxx : 'xxx', yyy : 'yyy' }, y : 'y' };var combineObj = $.extend(true,obj1,obj2);console.log(combineObj);
注意:(1)关键代码是
isPlainObject = function(obj) { if (obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) { return false; } var key; for (key in obj) { } return key === undefined || hasOwn.call(obj, key); },
(2)把递归的写法搞清楚
第三种:不深拷贝原型上的属性(本题答案)
//判断是对象var isObject = function(obj){ return Object.prototype.toString.call(obj) === '[object Object]'}//判断是数组var isArray = Array.isArray || function(obj){ return Object.prototype.toString.call(obj) === '[object Array]'}//获取对象不在原型上的键var get_keys = function(obj){ var keys = []; for(key in obj){ if(hasOwnProperty.call(obj,key)){ keys.push(key); } } return keys;}//实现深拷贝var deepCopy = function(obj){ var temp ; if(isArray(obj)){ temp = []; for(var i = 0 ; i < obj.length ; i++){ if(isArray(obj[i])||isObject(obj[i])){ //当前项是数组或者对象,递归调用 temp.push(deepCopy(obj[i])); }else{ temp.push(obj[i]); } } }else if(isObject(obj)){ temp = {}; var keys = get_keys(obj); var length = keys.length ; for(var i = 0 ; i < length ; i++){ //将对象值递归,结果赋值到新创建的temp对象的key[i]属性。 temp[keys[i]] = deepCopy(obj[keys[i]]) } }else{ //传入其他类型直接返回。 return obj; } return temp ;}
注意:(1)主要是hasOwnProperty的用法:该方法可以检测一个属性是存在于实例中,还是存在于原型中。这个方法只有在只在给定属性存在于对象实例中时,才会返回true。
(2)第2种和第3种的区别:第2种是只要对象的构造函数不是object,则不进行深拷贝,而第3种是对象的构造函数可以是非Object,不深拷贝对象原型上的属性,只拷贝实例上的属性。
举例如下:
function O() { this.yyy = 'yyy';}function X() { this.xxx = 'xxx';}X.prototype = new O();x = new X();//var obj = { a : {k1:'a'}, b : 'b',x:x };var obj = { a : {k1:'a'}, b : 'b',x:x};var obj2 = deepCopy(obj);obj.x.xxx = 'zzz'obj.x.yyy = 'zzz'console.log("obj ",obj); //{ a: { k1: 'a' }, b: 'b', x: O { xxx: 'zzz', yyy: 'zzz' } }console.log("obj2 ",obj2); //{ a: { k1: 'a' }, b: 'b', x: { xxx: 'xxx' } }console.log(obj2.x.xxx); //xxx 已经深拷贝,值不变console.log(obj2.x.yyy); //undefinedconsole.log(x.hasOwnProperty("xxx"));//true
(3)deepCopy 函数是直接不拷贝(跳过)相关对象,而$.extend对于不满足isPlainObject
的对象,则执行浅拷贝(即 target[name] = copy;
)。
第四种:不深拷贝原型上的属性($.extend()的完整实现)
$ = function() { var copyIsArray, toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty, class2type = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Object]' : 'object' }, //对type的注释:如果obj=null,则返回String(obj),即null, type = function(obj) { return obj == null ? String(obj) : class2type[toString.call(obj)] || "object"; }, isWindow = function(obj) { return obj && typeof obj === "object" && "setInterval" in obj; }, //如果浏览器有内置的Array.isArray 实现,就使用浏览器自身的实现方式,否则将对象转为String,看是否为"[object Array]"。(1.这里所说的将对象转为String即toString.call(obj) 2.考虑了兼容性 ) isArray = Array.isArray || function(obj) { return type(obj) === "array"; }, isPlainObject = function(obj) { if (!obj || type(obj) !== "object" || obj.nodeType || isWindow(obj)) { return false; } if (obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) { return false; } var key; for (key in obj) { } return key === undefined || hasOwn.call(obj, key); }, extend = function(deep, target, options) { var name,copy,clone; for (name in options) { src = target[name]; copy = options[name]; if (target === copy) { continue; } //为了避免无限循环 //以下if将copy是对象和数组合并在一起 if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) { if (copyIsArray) {//如果copy是数组 copyIsArray = false;//回归初始值 clone = src && isArray(src) ? src : [];//因为这是对象合并,所以可能target[name]是存在的,存在则不需要拷贝。 } else { clone = src && isPlainObject(src) ? src : {}; } target[name] = extend(deep, clone, copy); } else if (copy !== undefined) {//说明copy既不是对象,也不是数组,是基本类型, 直接赋值 target[name] = copy; } } return target; }; return { extend : extend };}();//测试function O() { this.yyy = 'yyy';}function X() { this.xxx = 'xxx';}X.prototype = new O();x = new X();obj1 = { a : 'a', b : 'b', y : '1' };obj2 = { x : { xxx : 'xxx', yyy : 'yyy' }, y : 'y' };var combineObj = $.extend(true,obj1,obj2);console.log(combineObj);
阅读全文
0 0
- 迅雷面试题:深拷贝对象,除了原型上的属性?
- 多线程的面试题迅雷
- 迅雷面试题---学习的方向
- 练习迅雷面试题
- 迅雷面试题
- 迅雷面试题
- 迅雷面试题练习
- 迅雷笔试面试题
- 迅雷面试题
- 迅雷面试题
- 迅雷面试题
- 迅雷校园面试题
- 迅雷多线程面试题
- 迅雷面试题
- Java深拷贝除了通过实现Cloneable接口,另外还可以通过序列化实现对象的拷贝。
- 前端一道面试题,考察变量定义提升、this指针指向、运算符优先级、原型、继承、全局变量污染、对象属性及原型属性优先级
- 面试题:String类的浅拷贝、深拷贝、写时拷贝
- 原型模式 -- 拷贝当前对象的副本
- 基础练习 数列排序
- 032 参数方程确定的函数导数
- ThinkPHP M()函数和D()函数的区别
- EasyUI动态加载button按钮
- My first HTML5 game in Construct 2
- 迅雷面试题:深拷贝对象,除了原型上的属性?
- 什么是Rup?什么是xp?什么是敏捷过程?
- android wifi 开发相关资料汇总
- druid连接池的简单使用
- JZOJ 5395. 【NOIP2017提高A组模拟10.6】Count
- 51nod 1287 加农炮(二分/线段树)
- *TEST 1 for NOIP
- 安卓studio 超级汉化
- #HDU1560#DNA sequence(IDA*_搜索)