-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
js深拷贝 #30
Comments
ramda 深拷贝的实现 方式/**
* Copies an object. 可以正确处理循环引用
*
* @param {*} value The value to be copied
* @param {Array} refFrom Array containing the source references
* @param {Array} refTo Array containing the copied source references
* @param {Boolean} deep Whether or not to perform deep cloning.
* @return {*} The copied value.
*/
// demo:
// var obj1 = {
// a: {
// b: 1,
// }
// }
// obj1.a.c = obj1
// const nobj = _clone(obj1, [], [], true)
// console.log(nobj)
// refFrom 的作用是 处理循环引用
// 具体来说,refFrom 会 保存每次_clone 传进来的 value 值,再克隆时,会先判断 属性值是否引用了之前的对象,如果是,则返回这个对象, 否则,进行下一步
export default function _clone(value, refFrom, refTo, deep) {
var copy = function copy(copiedValue) {
var len = refFrom.length;
var idx = 0;
while (idx < len) {
if (value === refFrom[idx]) {
return refTo[idx];
// 这里需要注意下:返回的copyedValue 的引用, 而不是 refFrom[idx],不然就是旧对象的引用了
}
idx += 1;
}
// ramda 中写的的是 idx + 1 ,其实应该是 idx 才更合理
refFrom[idx] = value;
refTo[idx] = copiedValue;
for (var key in value) {
copiedValue[key] = deep ?
_clone(value[key], refFrom, refTo, true) : value[key];
}
return copiedValue;
};
switch (type(value)) {
case 'Object': return copy({});
case 'Array': return copy([]);
case 'Date': return new Date(value.valueOf());
case 'RegExp': return _cloneRegExp(value);
default: return value;
}
}
/**
* Gives a single-word string description of the (native) type of a value,
* returning such answers as 'Object', 'Number', 'Array', or 'Null'. Does not
* attempt to distinguish user Object types any further, reporting them all as
* 'Object'.
*
* @func
* @memberOf R
* @since v0.8.0
* @category Type
* @sig (* -> {*}) -> String
* @param {*} val The value to test
* @return {String}
* @example
*
* R.type({}); //=> "Object"
* R.type(1); //=> "Number" "Object.prototype.toString.call(1) => "[object Number]"
* R.type(false); //=> "Boolean"
* R.type('s'); //=> "String"
* R.type(null); //=> "Null"
* R.type([]); //=> "Array"
* R.type(/[A-z]/); //=> "RegExp"
* R.type(() => {}); //=> "Function"
* R.type(undefined); //=> "Undefined"
*/
const type = function type(val) {
// 单独处理 null 和 undefined 向前兼容 ECMAScript 5.1 版本之前的。
return val === null
? 'Null'
: val === undefined
? 'Undefined'
: Object.prototype.toString.call(val).slice(8, -1); // 从第八位开始截取,截取到倒数负一位
}
/**
* @desc clone正则表达式
* @createDate 2019/08/13
* https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp
* new RegExp(pattern [, flags]) -> new RegExp('abc', 'gi') = /abc/gi
* RegExp(pattern [, flags])
* RegExp.prototype.source ->正则对象的源模式文本。
* /\w+abc/.source -> 'w+abc'
*/
const _cloneRegExp = function _cloneRegExp(pattern) {
return new RegExp(pattern.source, (pattern.global ? 'g' : '') +
(pattern.ignoreCase ? 'i' : '') +
(pattern.multiline ? 'm' : '') +
(pattern.sticky ? 'y' : '') +
(pattern.unicode ? 'u' : ''));
}
|
别的深拷贝方法实现来自上面写的那篇博文的底部实现方法: var types = "Array,Object,String,Date,RegExp,Function,Boolean,Number,Null,Undefined".split(",");
var $ = {}
for (let i = types.length; i--; ) {
$["is" + types[i]] = str =>
Object.prototype.toString.call(str).slice(8, -1) === types[i];
}
function copy(obj, deep = false, hash = new WeakMap()) {
// 利用WeakMap 来处理循环引用
if (hash.has(obj)) {
return hash.get(obj);
}
if ($.isFunction(obj)) {
return new Function("return " + obj.toString())();
} else if (obj === null || typeof obj !== "object") {
return obj;
} else {
var name,
target = $.isArray(obj) ? [] : {},
value;
hash.set(obj, target);
for (name in obj) {
value = obj[name];
if (deep) {
if ($.isArray(value) || $.isObject(value)) {
target[name] = copy(value, deep, hash);
} else if ($.isFunction(value)) {
target[name] = new Function("return " + value.toString())();
} else {
target[name] = value;
}
} else {
target[name] = value;
}
}
return target;
}
}
// 上面的代码可以正确处理循环引用,但是,对于方法,感觉不应该克隆,而是应该想ramda 那样,
// 返回函数的引用,原因是 那种克隆方法会丢失函数的属性,闭包变量等。 |
拷贝一个方法function fn(a, b,c) {
return a + b + c;
}
new Function("return " + fn.toString()) // 返回如下的代码:
ƒ anonymous() {
return function fn(a, b, c) {
return a + b + c;
}
}
// 所以,得到真正的方法需要调用这个匿名函数
new Function("return " + fn.toString())() |
lodash 中拷贝 Symbol 的方法/** Used to convert symbols to primitives and strings. */
const symbolValueOf = Symbol.prototype.valueOf
/**
* Creates a clone of the `symbol` object.
*
* @private
* @param {Object} symbol The symbol object to clone.
* @returns {Object} Returns the cloned symbol object.
*/
function cloneSymbol(symbol) {
return Object(symbolValueOf.call(symbol))
}
export default cloneSymbol |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
先附上结论:
此段代码来自
JSON.strigify和JSON.parse 🌰
The text was updated successfully, but these errors were encountered: