前端内功提升:面向切面编程

139 阅读3分钟

什么是面向切面编程?

说到面向切面编程,这个一直都是高级工程师必须掌握的一项知识点

生动形象一点的解释就是,写代码就像切面包,如果要你切三刀,最好的保持面包完成度的方法就是;从两头切,而不是一开始就从中间一刀切:

而在编程上的思想就是面向切面编程:其最终目的就是增加的业务逻辑(例如打埋点)的同时降低业务间的耦合度。

场景一: 统计所有函数谁的耗时最长:

// 常用的方案:
function test(){
	var startTime = ....// 业务侵入严重,统计效率低下
	alert(2)
	var endTime = ....
}

下面是面向切面编程的写法:

fucntion test(){
  	alert(2);
}
Function.prototype.before = fn=>{
  var _self = this;
  fn();
  _self.apply(this,arguments);
};
Function.prototype.after = fn=>{
  var _self = this;
  _self.apply(this,arguments);
  fn();
};
test.before(function(){
  alert(1)
})
test.after(function(){
  alert(1)
})
//输出: 1 2 2 3

这样写的好处就是孤立了test方法,回调中申明的任何变量也都不会污染你以前的业务逻辑代码;这就是面向切面编程的优雅之处。

如输出所示,2被输出了两次,这肯定是个bug,所以如下进行优化:

因为默认函数会被执行两次: 解决方案如上所示: 把test作为中转

before回调和before一起送到after去;

同理:假如after写在了前面,自然就是after回调和after一起送到before去

fucntion test(){
  	alert(2);
}
Function.prototype.before = fn=>{
  var _self = this;
  return function(){// return回去
  // 此时this作为闭包被送到外部: 所以此处的this指向了window对象
  	fn.apply(_self,arguments);// 此时就保住了this指向
  	_self.apply(_self,arguments);//此时的this指向还是test Function
  }
  
};
Function.prototype.after = fn=>{
  var _self = this;
  // 同理改造:
  return function(){
  	 _self.apply(_self,arguments);
  	fn.apply(_self,arguments);
  }
 
};
test.before(function(){
  alert(1)
}).after(function(){
  alert(3)
})()
//输出 1 2 3
//或者
//test.after(function(){// return function => return 2 3(这一步一开始都是不会执行的)
//  alert(3)
//}).before(function(){// 执行 1 fucntion() => 1 2 3
//  alert(1)
//})()
//输出 1 2 3 

说明:

执行顺序: 执行before中的before回调=>before中的test方法=>执行了after中的回调;

而之所以after的方法中的本身方法会跳过,世界是因为before返回的匿名函数致使this对象发生了改变

拓展: 假如: test方法中有return 的话此时如果按上面的写法, 值就会在挂在的过程中消失:

方案: 你既然执行了人家方法,就要好好将人家送回去:

在after中改造: 因为既然是抛出当然要放在最后

fucntion test(){
  	alert(2);
  	return 'colorssk';
}
Function.prototype.before = fn=>{
  var _self = this;
  return function(){// return回去
  	if(fn.apply(_self,arguments)== false){
  		return false
	}
  	return _self.apply(_self,arguments);
  }
  
};
Function.prototype.after = fn=>{
  var _self = this;
  return function(){
  	 var result = _self.apply(_self,arguments);
  	 if(reslult == false){
  		return false;
	}
  	fn.apply(_self,arguments);
  	return result;
  }
 
};
test.after(function(){ 
alert(3)
}).before(function(){// 执行 1 fucntion() => 2 3
  alert(1)
 //return fasle//还有一个好处是当此时抛出异常的时候只需要return false就会停止接下来的链式操作
})()
输出 1 2 3
colorssk

以上是面向切面编程的一种思想,这种解耦的思想,也是抽象思维的一种表现,当埋点或者临时插入业务逻辑代码的时候,可以方便于后期的维护