您现在的位置是:主页 > news > 万网做网站如何下载模板/全球网站流量查询

万网做网站如何下载模板/全球网站流量查询

admin2025/6/24 16:59:45news

简介万网做网站如何下载模板,全球网站流量查询,深圳建筑业协会,怎么做外贸网站优化纯函数 引言 对于函数,大家都不陌生,但是对于纯函数可能有些生疏。我们在写函数的时候,会肆无忌惮,充分的利用js的一些特性,比如使用作用域去修改外部变量,对象属性,数据结构等。这样写如果稍…

万网做网站如何下载模板,全球网站流量查询,深圳建筑业协会,怎么做外贸网站优化纯函数 引言 对于函数,大家都不陌生,但是对于纯函数可能有些生疏。我们在写函数的时候,会肆无忌惮,充分的利用js的一些特性,比如使用作用域去修改外部变量,对象属性,数据结构等。这样写如果稍…

纯函数

引言

  • 对于函数,大家都不陌生,但是对于纯函数可能有些生疏。我们在写函数的时候,会肆无忌惮,充分的利用js的一些特性,比如使用作用域去修改外部变量,对象属性,数据结构等。这样写如果稍不注意,可能会出现隐藏的bug,使我们的函数,不再是一个可信赖的函数。而纯函数正是一个可以保证数据信赖的函数方式,他也是一个函数,只不过有他特有的要求规范,下面就让我们从函数的副作用开始,来学习纯函数的优缺点

什么是纯函数?

  • 纯函数是这样一种函数,相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用

比如常用的slicesplice,这两个函数的作用别二致。但是slice符合纯函数的定义,因为对于相同的输入,他能保证相同的输出。而splice却会嚼烂调用他的那个数组,然后吐出来;这样就会产生观察到的副作用

let arr = [1,2,3]
// 纯的
arr.slice(0, 3) // (3) [1, 2, 3]
arr.slice(0, 3) // (3) [1, 2, 3]
arr.slice(0, 3) // (3) [1, 2, 3]// 不纯的
arr.splice(0, 3) // (3) [1, 2, 3]
arr.splice(0, 3) // []

在函数式编程中,我们讨厌这种会改变数据的笨函数。我们追求的是那种可靠的,每次都能返回同样结果的函数,而不是像 splice 这样每次调用后都把数据弄得一团糟的函数,这不是我们想要的。

来看另外一个例子

// 不纯的
let immutableState = 21
const checkAge = (age) => {return age >=immutableState
}// 纯的
const checkAge = (age) => {let immutableState = 21return age >=immutableState
}

在不纯的版本中,checkAge的结果取决于immutableState这个变量是不是一个可变的值。 如果是可变的,那么对于immutableState的追踪,将会是一件棘手的事。我们可以通过参数的形式传递immutableState,也可以通过作用域的方式,限制变量的访问范围,当然我们也可以通过一些手段,使immutableState成为一个不可变(immutable) 对象.要实现这个效果,必须得创建一个对象,然后调用 Object.freeze 方法:

let immutableState = Object.freeze({immutableState: 21
})

什么是函数的副作用

如果函数与外部可变状态进行交互,则他是有副作用的

  • 任何修改外部的变量,对象属性,数据结构
  • 控制台(屏幕)输入输出的交互
  • 文件操作,网络操作
  • 抛出异常或错误终止
  • …不止于此

站在纯函数的角度来说,以上均是非纯函数的副作用。我们也不必太刻意使用纯函数,因为有很多功能,还是得依赖非纯函数来实现,毕竟你要和这个世界打交道,而不是只活在自己的世界里。

函数副作用demo - 输出最大数

let arrScore = [1, 3, 2, 5, 4];
const getMaxScore = () => {arrScore = arrScore.sort((a, b) => {return b - a;});return arrScore[0];
};
console.log('getMaxScore', getMaxScore()); // 5
console.log('arrScore', arrScore); //  [ 5, 4, 3, 2, 1 ]

问题分析

  1. 在函数内,直接使用了外部变量,并且sort会改变源数据。下次再使用源数据,数据处于不可知状态

问题解决

  1. 通过参数的形式,将数据传入
  2. 参数如果是引用类型,提前进行clone
  3. 避免使用修改源数据的api,使用其他方式实现
let arrScore = [1, 3, 2, 5, 4];
const getMaxScore = (arrScore) => {let temp = arrScore.slice();temp = temp.sort((a, b) => {return b - a;});return temp[0];
};
console.log('getMaxScore', getMaxScore(arrScore)); // 5
console.log('arrScore', arrScore); //  [ 1, 3, 2, 5, 4 ]
let arrScore = [1, 3, 2, 5, 4];
const getMaxScore = (arrScore) => {return Math.max(...arrScore);
};
console.log('getMaxScore', getMaxScore(arrScore)); // 5
console.log('arrScore', arrScore); //  [ 1, 3, 2, 5, 4 ]

追求“纯”的理由

可缓存性 (Cacheable)

  • 由于纯函数的输入就决定了输出,就和数学中的函数一样(所以我们也可以像数学公式一样推导),一个确定的输入对应一个确定的输出,

  • 因此我们可以根据传入的参数把结果缓存起来,这样后续以同样的参数调用的时候就可以直接返回结果,而不是重新执行一遍算法.

  • 实现缓存的一种典型方式是memoize技术,

vue 源码

/*** Create a cached version of a pure function.*/function cached(fn) {var cache = Object.create(null);return function cachedFn(str) {var hit = cache[str];return hit || (cache[str] = fn(str));};}/*** Capitalize a string.*/var capitalize = cached(function (str) {return str.charAt(0).toUpperCase() + str.slice(1);});

可移植性,自文档化(Portable / Self-Documenting)

  • 纯函数的依赖很明确,因此更易于观察和理解

  • 因为他们与环境无关,所以可以拷贝到任何地方运行,提高了代码的复用性。

  • 对比面向对象,你从类中拷贝一个方法,就要麻烦得多。

可测试性(Testable)

  • 纯函数让测试更加容易。

  • 只需要给定输入,断言输出就可以了。

  • 甚至有专门的测试工具帮我们自动生成输入,并断言输出。 比如Quickcheck

合理性,引用透明性(Reasonable)

  • 很多人相信使用纯函数最大的好处是引用透明性(referential transparency)。如果一段代码可以替换成它执行所得的结果,而且是在不改变整个程序行为的前提下替换的,那么我们就说这段代码是引用透明的。
var Immutable = require('immutable');var decrementHP = function(player) {return player.set("hp", player.hp-1);
};var isSameTeam = function(player1, player2) {return player1.team === player2.team;
};var punch = function(player, target) {if(isSameTeam(player, target)) {return target;} else {return decrementHP(target);}
};var jobe = Immutable.Map({name:"Jobe", hp:20, team: "red"});
var michael = Immutable.Map({name:"Michael", hp:20, team: "green"});punch(jobe, michael);
//=> Immutable.Map({name:"Michael", hp:19, team: "green"})

在上面的demo中,decrementHPisSameTeampunch都是纯函数,所以是透明引用。我们可以使用一种叫做“等式推到”的技术来分析代码
首先内联isSameTeam

var isSameTeam = function(player1, player2) {return player1.team === player2.team;
};// 因为数据是不可变的,所以我们直接把team 替换为实际的值var punch = function(player, target) {if("red" === "green") {return target;} else {return decrementHP(target);}
};// if 执行的结果是false,所以可以把整个if 语句删掉var punch = function(player, target) {return decrementHP(target);
};
// 然后再内联decrementHP,punch就编程一个让hp的值减1的调用

并行运算

  • 我们可以并行运行任意纯函数。因为纯函数根本不需要访问共享的内存,而且根据其定义,纯函数也不会因副作用而进入竞争态(race condition)。

  • 并行代码在服务端 js 环境以及使用了 web worker 的浏览器那里是非常容易实现的,因为它们使用了线程(thread)。不过出于对非纯函数复杂度的考虑,当前主流观点还是避免使用这种并行。