• 【JavaScript进阶之旅 函数式编程篇 第三十三章】JS函数、特点、函数式编程、纯函数


    一、JS函数

    1、 函数的一等公民

    JavaScript世界当中的 「一等公民」 -> 函数

    • JavaScript一等公民:声明、调用、赋值、传参、返回、构造函数、类实例、立即执行
    1. 第一级函数:First-class Function
    function test() {}
    
    var test = function() {}
    
    • 1
    • 2
    • 3

    2、计算函数的不同实现

    • 方法一
    	function add(a, b) {
    		return a + b;
    	}
    
    	function minus(a, b) {
    		return a - b;
    	}
    
    	function compute(a, b, fn) {
    		return fn(a, b);
    	}
    
    	console.log(compute(1, 2, add)); // 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 方法二
    	function Compute(a, b) {
    		this.a = a;
    		this.b = b;
    
    		this.add = function() {
    			return this.a + this.b;
    		}
    
    		this.minus = function() {
    			return this.a - this.b;
    		}
    	}
    
    	var computed = new Compute(1, 3);
    	console.log(computed.add()); // 4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 方法三
    	var test = (function() {
    		function Compute(a, b) {
    			this.a = a;
    			this.b = b;
    
    			this.add = function() {
    				return this.a + this.b;
    			}
    
    			this.minus = function() {
    				return this.a - this.b;
    			}
    		}
    
    		return new Compute(10, 1);
    
    	})();
    
    	console.log(test.add()) // 11
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3、JS编程特点

    • 函数式编程和面向对象编程的混编语言
    • 可扩展性强

    优点:编程灵活、易学
    缺点:不可控

    4、面向对象与函数式编程关系

    • 面向对象中存在复杂的this指向,面向对象是需要大量的使用、大量的复用才有必要使用
    • 函数式编程:易读、易维护

    二、函数式编程

    • 概念:函数是第一类对象,不依赖任何其他对象独立存在

    1、纯函数

    • 相同的输入得到相同的输出,不依赖且不影响外部环境也不产生任何副作用

    输出完全取决于输入

    var a = 1;
    
    function test(num) {
    	console.log(num);
    }
    
    test(a); // 纯函数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 副作用:
      1. 只要跟函数外部环境发生了交互就是副作用
      2. 发送数据请求
      3. 改变数据
      4. console.log() 是Javascript引擎 控制台的方法
      5. DOM操作
      6. 数据的存取:cookie、storage
    
    	function add(obj) {
    		return obj.a + obj.b;
    	}
    
    	function minus(obj) {
    		return obj.a - obj.b;
    	}
    
    	function compute(num) {
    		return {
    			add: add(num),
    			minus: minus(num)
    		}
    	}
    
    	var nums = {
    		a: 1,
    		b: 2
    	}
    
    	console.log(compute(nums).add);
    	console.log(compute(nums).minus);
    
    // 请问compute是纯函数吗?
    // 他不是,因为compute依赖了外部函数,一旦外部函数发生错误,就影响到了compute
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • splice与slice
    • splice:改变原数组,不是纯函数
    • slice:返回新数组,不改变原数组,是纯函数
    	var arr1 = [1, 2, 3, 4, 5],
    			arr2 = [1, 2, 3, 4, 5];
    
    	var spArr = arr1.splice(0, 3),
    			slArr = arr2.slice(0, 3);
    
    	console.log('arr1', arr1);
    	console.log('arr2', arr2);
    
    	console.log('spArr', spArr);
    	console.log('slArr', slArr)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2、手写第一个纯函数

    	var obj = {
    		a: 1, 
    		b: 2,
    		c: 3
    	}
    
    
    	// 改变了原对象obj -> 所以他不是纯函数
    	function test(obj) {
    		obj.d = 4;
    		return obj;
    	}
    	
    	console.log(test(obj));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 深拷贝obj,那么test就是纯函数
    // 函数test不可以影响obj
    
    	var obj = {
    		a: 1, 
    		b: 2,
    		c: 3
    	}
    
    
    	// 改变了原对象obj -> 所以他不是纯函数
    	function test(obj) {
    		// 深拷贝obj
    		var newObj = deepClone(obj, {});
    		console.log(newObj);
    
    		newObj.d = 4;
    
    
    		function deepClone(obj,cloneObj) {
    			debugger
          var cloneObj = cloneObj || {},
              toStr = Object.prototype.toString,
              objArr = '[object Array]'
    
          for(var i in obj) {
            // console.log(obj[i]);
            // 判断i是不是自己的属性
            if(!obj.hasOwnProperty[i]) {
            	// i有可能在自己的原型上面
    					if(typeof obj[i] === 'object' && obj[i] !== null){
    			          // cloneObj[i] = Array.isArray(obj[i]) ? [] : {};
    			          // cloneObj[i] = obj[i] instanceof Array ? [] : {};
    			
    			          cloneObj[i] = toStr.call(obj[i]) === Object ? [] : {}
    			
    			          deepClone(obj[i], cloneObj[i])
    			          
    	        }else {
    	          cloneObj[i] = obj[i]
    	        }
    				} 
    
          }
          return cloneObj
        }
    
    
    		return newObj;
    	}
    
    	console.log(test(obj));
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    3、纯函数的特点

    可移植性

    • 拿到哪里都可以用
    	function compute(a, b, type) {
    		if(typeof(a) === 'number' && typeof(b) === 'number') {
    			switch(type) {
    				case 'add':
    					return a + b;
    					break;
    				case 'minus':
    					return a - b;
    					break;
    				default: 
    					return a + b;
    
    			}
    		}else {
    			return 'a跟b必须是数字';
    		}
    	}
    
    	console.log(compute(1, 3, 'add'));
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    引用合理,透明性

    function add(a, b) {
    	return a + b;
    }
    
    // 或者
    
    function add() {
    	var a = 1,
    			b =2;
    	return a + b;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    可缓存性

    	function test(fn) {
    		var cache = {}; // 缓冲池
    
    		return function() {
    			var args = JSON.stringify(arguments);
    
    			cache[args] = cache[args]
    				? cache[args] + '(来自缓冲池)'
    				// : fn(arguments);
    				: fn.apply(fn, arguments);
    
    			return cache[args];
    		}
    	}
    
    	// var add = test(function(arguments) {
    	var add = test(function() {
    		var argLen = arguments.length,
    				item,
    				res = 0;
    
    		for(var i = 0; i < argLen; i ++) {
    			item = arguments[i];
    			res += item;
    		}
    
    		return res;
    	});
    
    	console.log(add(1, 3)); // 4
    	console.log(add(1, 3)); // 4(来自缓冲池)
    	console.log(add(1, 3)); // 4(来自缓冲池)(来自缓冲池)
    	console.log(add(1, 4));	// 5
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
  • 相关阅读:
    人工智能数学课高等数学线性微积分数学教程笔记(3. 线性代数基础)
    从0搭建Vue3组件库:button组件
    第9章 Mybatis
    自己动手写编译器:GoLex程序的基本情况介绍
    利用Linux socat快速搭建TCP服务器
    不同实验样品在实时荧光定量PCR检测中要求有哪些?
    【论文解读】CP-SLAM: Collaborative Neural Point-based SLAM System_神经点云协同SLAM系统(上)
    框架中实现 小堆顶高性能定时器 10W计时器耗时1.9ms
    promise使用与源码封装(二)
    关于打印输出
  • 原文地址:https://blog.csdn.net/Lyb__/article/details/125884657