JavaScript 浅复制、深复制、面向切面(重构函数)

一个老生常谈的问题,关于JavaScript的浅复制、深复制,这次还带来了面向切面。本文中将会举例来说明这两种区别,最后将会演示面向切面的作用。

源代码

直接上代码,给出的是一个工具类,就不一一解释代码了,足够演示以及生产使用。

/**
 * 对象操作工具类
 * */
function Utils() {
	let __this__ = this;
  /**
   * 是否是Object
   * @param {object} obj
   * @returns {Boolean}
   */
  this.isObject = function(obj) {
    return obj && (typeof obj === 'object');
  }
  /**
   * 是否不是Object
   * @param {object} obj
   * @returns {Boolean}
   */
  this.isNotObject = function(obj) {
    return !__this__.isObject(obj);
  }
  /**
   * 是否是数组
   * @param {object} obj || Array
   * @returns {Boolean}
   */
  this.isArray = function(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
  }
  /** 浅复制
   * @param {object} source  源对象
   * @param {object} target  目标对象
   */
  this.reflection = function(source, target) {
    //如果不是对象将抛出异常
    if (__this__.isNotObject(source) || __this__.isNotObject(target)) {
      throw new Error('There are parameters that are not objects in the given parameters.');
    }
    let arrSource = Object.keys(source);
    for (let i = 0; i < arrSource.length; i++) {
      let key = arrSource[i];
      target[key] = source[key]
    }
  }
  /** 深复制
   * @param {object} source 源对象
   * @param {object} target 目标对象
   */
  this.copy = function(source, target) {
    //如果不是对象将抛出异常
    if (__this__.isNotObject(source) || __this__.isNotObject(target)) {
      throw new Error('There are parameters that are not objects in the given parameters.');
    }
    let arrSource = Object.keys(source);
    for (let i = 0; i < arrSource.length; i++) {
      let key = arrSource[i];
	  //如果这个属性是对象则迭代
	  if(__this__.isObject(source[key])){
		target[key] = __this__.isArray(source[key]) ? [] : {};
	  	__this__.copy(source[key],target[key]);
	  }else{
	  	target[key] = source[key]
	  }
    }
  }
  /**
   * 切面
   * 重构目标函数,提供函数执行之前执行之后的钩子函数
   * @param {object} source 目标对象
   * @param {string} attribute 目标函数,属于目标对象的需要代理的属性,必须是函数,否则将抛出异常
   * @param {function} before 目标函数执行之前执行,接收一个参数args(目标函数中arguments转变的数组),可改变目标函数的参数值
   * @param {function} after 目标函数执行之后执行,接收一个参数args(目标函数中arguments转变的数组),可改变目标函数的参数值
   */
  this.aspect = function(source, attribute, before, after) {
    if (typeof source[attribute] === "function") {
      let temporary = source[attribute];
      source[attribute] = function(){
        let parameter = Array.prototype.slice.call(arguments);
        if(typeof before !== 'undefined' && before instanceof Function){
          before.call(source,parameter);
        }
        temporary.apply(source,parameter);
        if(typeof after !== 'undefined' && after instanceof Function){
          after.call(source,parameter);
        }
      }
    } else {
      throw new Error('The property is not an executable function type.');
    }
  }
}

export default ObjectUtils;

验证

const ObjectUtils = new Utils();

let source = {
	"name":"杰克",
	"age":21,
	"relatives":[
		{
			"name":"父亲",
			"age":46,
		},
		{
			"name":"母亲",
			"age":46,
		}
	],
	"data":{
		"gender":"男",
		"hobby":"女"
	}
}
let target1 = {}
let target2 = {}
ObjectUtils.reflection(source,target1);
ObjectUtils.copy(source,target2);
console.log(target1)
console.log(target2)
target1.relatives[0].age = 50;
console.log(target1.relatives[0].age)  // 50
console.log(target2.relatives[0].age)  // 48
console.log(source.relatives[0].age)   // 50

从代码中看到,深复制与浅复制的区别在于深复制在循环中进行了判断,如果属性是Object则创建一个空Object或者Array进行递归复制。

从演示中看到,深复制与浅复制的区别在于深复制与源对象没有任何关联,改变源对象不会影响复制后的对象,而浅复制相反。

总结:实现上深复制进行了类型判断并递归复制,浅复制复制基本类型以及对象引用。使用上深复制是一个全新的对象与源对象没有关联,浅复制(可能)存在相同引用的内容。

面向切面演示

const ObjectUtils = new Utils();

let source = {
	"run":function(){
		console.log(2)
	},
}
ObjectUtils.aspect(source,"run",function(){
	console.log(1)
},function(){
	console.log(3)
});

source.run();

// 1
// 2
// 3

由代码中可知切面函数有四个参数,前两个必须,后两个可选,分别是源对象、目标函数在源对象中的key,前置函数,后置函数。

从演示中看到,在经过切面函数处理之后,执行源函数会按照顺序执行前置函数、目标函数、后置函数。在其他语言中面向切面编程,可以为代码省去一些重复的步骤,或是进行集中处理。当然这里只能算是一个另类实现,重构函数,远算不上面向切面,具体的使用场景就自行摸索吧~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值