以函数为参数的函数,返回一个函数的函数
const filter = (predicate, xs) => xs.filter(predicate)
const is = (type) => (x) => Object(x) instanceof type
filter(is(Number), [0, '1', 2, null]) // [0, 2]
函数所需的参数个数。来自于单词 unary, binary, ternary 等等。这个单词是由 -ary 与 -ity 两个后缀组成。例如,一个带有两个参数的函数被称为二元函数或者它的 arity 是2。它也被那些更喜欢希腊词根而非拉丁词根的人称为 dyadic。同样地,带有可变数量参数的函数被称为 variadic,而二元函数必须给出两个且只有两个参数,见下文,柯里化(Currying) 和 偏应用函数(Partial Application) 。
const sum = (a, b) => a + b
const arity = sum.length
console.log(arity) // 2
// The arity of sum is 2
// 设置一个随机数,需要时,才会计算,每次计算都是一个不同的值
const rand = function*() {
while (1 < 2) {
yield Math.random()
}
}
const randIter = rand()
randIter.next() // 每个执行都给出一个随机值,表达式按需求值。
function add(a, b,c) {
return a + b+c;
}
//也可以
var addOne = add.bind(null, 1,2);
console.log(addOne(2));
//也可以
var addTwo = add.bind(null, 1);
console.log(addTwo(3,4));
const sum = (a, b) => a + b
const curriedSum = (a) => (b) => a + b
curriedSum(40)(2) // 42.
const add2 = curriedSum(2) // (b) => 2 + b
add2(10) // 12
const add = (x, y) => x + y
const curriedAdd = _.curry(add)
curriedAdd(1, 2) // 3
curriedAdd(1) // (y) => 1 + y
curriedAdd(1)(2) // 3
var compose = function(fun1,fun2){
return function(val){
return fun1(fun2(val));
}
}
var add = function(val){
return val + "111";
}
var upperCase = function(val){
return val.toUpperCase();
}
var double = function(val){
return val += val;
}
// 无限组合,才是compose的威力所在
var upperCaseThenAdd = compose(add,upperCase);
var doubleThenAdd = compose(double,add);
var addThenAdd = compose(add,add);
var addThenAddThenUpperCase = compose(upperCase,addThenAdd);//注意这个函数,以组合函数addThenAdd作为其参数,很强大,有没有!
console.log(upperCaseThenAdd("china"));//CHINA111
console.log(doubleThenAdd("china"));//china111china111
console.log(addThenAdd("china"));//china111111
console.log(addThenAddThenUpperCase("china"));//CHINA111111
//改进compose,支持2个以上参数
var compose1 = function(){
var args = arguments;
return function(initVal){
var val = initVal;
for(key in args){
val = args[key](val);
}
return val;
}
}
var doubleThenUpperCaseThenAddThenAdd = compose1(double,upperCase,add,add);
console.log(doubleThenUpperCaseThenAddThenAdd("china"));//CHINACHINA111111
//continueFun函数就称为一个Continuation
var addOneAndContinue = function(val,continueFun){
var val = val + 1;
return continueFun(val);
}
var mutiply = function(val){
return val * 5;
}
console.log(addOneAndContinue(100,mutiply));//505
如果返回值仅由其输入值决定,并且不产生副作用,那么这个函数就是纯函数。
const greet = (name) => `Hi, ${name}`
greet('Brianne') // 'Hi, Brianne'
以下代码不是纯函数:
window.name = 'Brianne'
const greet = () => `Hi, ${window.name}`
greet() // "Hi, Brianne"
上述示例的输出基于存储在函数外部的数据…
let greeting
const greet = (name) => {
greeting = `Hi, ${name}`
}
greet('Brianne')
greeting // "Hi, Brianne"
… 而这个示例则是修改了函数外部的状态。
如果函数与外部可变状态进行交互,则它是有副作用的.函数或表达式如果被认为具有副作用,那么除了返回值之外,它可以与外部可变状态(读取或写入)进行交互。
const differentEveryTime = new Date()
console.log('IO is a side effect!')
数学中的幂等性
接口的幂等性
GET /pageX HTTP/1.1是幂等的。连续调用多次,客户端接收到的结果都是一样的:
GET /pageX HTTP/1.1
GET /pageX HTTP/1.1
GET /pageX HTTP/1.1
GET /pageX HTTP/1.1
POST /add_row HTTP/1.1不是幂等的。如果调用多次,就会增加多行记录:
POST /add_row HTTP/1.1
POST /add_row HTTP/1.1 -> Adds a 2nd row
POST /add_row HTTP/1.1 -> Adds a 3rd row
DELETE /idX/delete HTTP/1.1是幂等的,即便是不同请求之间接收到的状态码不一样:
DELETE /idX/delete HTTP/1.1 -> Returns 200 if idX exists
DELETE /idX/delete HTTP/1.1 -> Returns 404 as it just got deleted
DELETE /idX/delete HTTP/1.1 -> Returns 404
程序的幂等性
//虽然是一个面向对象的例子,但是可以说明问题
var Student = function(name,age){
this.name = name;
this.age = age;
};
Student.prototype.delName = function(){
var response = this.name ? this.name + "已被删除":"name不存在";
this.name = null;
return response;
}
//对内部的影响是一样的,但是返回值可以不同
var lilei = new Student("lilei",19);
console.log(lilei.delName());//lilei已被删除
console.log(lilei.delName());//name不存在
console.log(lilei.delName());//name不存在
定义函数时,不显式地指出函数所带参数。这种风格通常需要柯里化或者高阶函数。也叫 Tacit programming
// 给定
const map = (fn) => (list) => list.map(fn)
const add = (a) => (b) => a + b
// 然后
// 非 points-free - `numbers` 是一个明确的参数
const incrementAll = (numbers) => map(add(1))(numbers)
// Points-free - `list` 显式地标识
const incrementAll2 = map(add(1))
incrementAll 明确的使用了参数 numbers,所以它是非 points-free 风格。 incrementAll2 连接函数与值,并不提及它的参数。所以 是 points-free 风格. Point-Free 风格的函数就像平常的赋值,不使用 function 或者 =>。
const morethenTwo = (a) => a > 2;
;[1, 2, 3, 4].filter(morethenTwo);
const contract = (input) => {
if (typeof input === 'number') return true
throw new Error('Contract Violated: expected int -> int')
}
const addOne = (num) => contract(num) && num + 1
addOne(2)
addOne('hello') // Error
【不好理解】
【一个范畴遵从三个原则】
//一致性
object.map(x => x) ? object
//组合性
var fun1 = function(x){
return x+1;
}
var fun2 = function(x){
return x*x;
}
var res1 = [1,2,3].map(fun1).map(fun2);
var res2 = [1,2,3].map(function(x){
return fun2(fun1(x));
});
console.log(res1,res2);
Array.of(1) // [1]
Object.freeze({name: 'John', age: 30}) // `freeze` 强制实现不可变性。
const name="haha"
一个匿名函数,被当作一个值来对待。
;(function (a) {
return a + 1
})
;(a) => a + 1
匿名函数通常作为高阶函数的参数
;[1, 2].map((a) => a + 1) // [2, 3]
可以把 Lambda 赋值给一个变量
const add1 = (a) => a + 1
//of
Array.of(1,2,3);//[ 1, 2, 3 ]
//chain方法的实现
Array.prototype.chain = function (f) {
return this.reduce((acc, it) => acc.concat(f(it)), [])
};
Array.of('cat,dog', 'fish,bird').chain(s => s.split(','));//[ "cat", "dog", "fish", "bird" ]
拥有 extract 与 extend 函数的对象。
const CoIdentity = (v) => ({
val: v,
extract () {
return this.val
},
extend (f) {
return CoIdentity(f(this))
}
})
从函子中 extract (提取) 出一个值。
CoIdentity(1).extract() // 1
Extend 在 comonad 上运行一个函数。函数应该返回与 comonad 相同的类型。
CoIdentity(1).extend((co) => co.extract() + 1) // CoIdentity(2)
// uppercase :: String -> String
const uppercase = (str) => str.toUpperCase()
// decrement :: Number -> Number
const decrement = (x) => x - 1
应用函子是具有ap函数的对象。 ap将对象中的函数应用于同一类型的另一个对象中的值。
// 实现
Array.prototype.ap = function (xs) {
return this.reduce((acc, f) => acc.concat(xs.map(f)), [])
}
// 使用示例
;[(a) => a + 1].ap([1]) // [2]
如果你有两个对象,并需要对他们的元素执行一个二元函数
// 你想合成的数组
const arg1 = [1, 3]
const arg2 = [4, 5]
// 合成函数 - 必须为此 curried 柯里化 才能工作
const add = (x) => (y) => x + y
const partiallyAppliedAdds = [add].ap(arg1) // [(y) => 1 + y, (y) => 3 + y]
由此得到了一个函数数组,并且可以调用 ap 函数得到结果:
partiallyAppliedAdds.ap(arg2) // [5, 6, 7, 8]
// 提供函数在两种类型间互相转换
const pairToCoords = (pair) => ({x: pair[0], y: pair[1]})
const coordsToPair = (coords) => [coords.x, coords.y]
console.log(pairToCoords([1, 2]));//{ "x": 1, "y": 2 }
console.log(coordsToPair({x: 1, y: 2}));//[ 1, 2 ]
Array.prototype.equals = function (arr) {
const len = this.length
if (len !== arr.length) {
return false
}
for (let i = 0; i < len; i++) {
if (this[i] !== arr[i]) {
return false
}
}
return true
}
;[1, 2].equals([1, 2]) // true
;[1, 2].equals([3, 4]) // false
;[1].concat([2]) // [1, 2]
var sum = [1,2,3,4].reduce(function(total,val){
return total += val;
})
console.log(sum);
//通常 js 会在注释中指出参数与返回值的类型
// functionName :: firstArgType -> secondArgType -> returnType
// add :: Number -> Number -> Number
const add = (x) => (y) => x + y
// increment :: Number -> Number
const increment = (x) => x + 1
//如果函数的参数也是函数,那么这个函数需要用括号括起来。
// call :: (a -> b) -> a -> b
const call = (f) => (x) => f(x)
//字符 a, b, c, d 表明参数可以是任意类型。以下版本的 map 的参数 f,把一种类型 a 的数组转化为另一种类型 b 的数组。
// map :: (a -> b) -> [a] -> [b]
const map = (f) => (list) => list.map(f)
// add :: (NumOrString, NumOrString) -> NumOrString
const add = (a, b) => a + b
add(1, 2) // Returns number 3
add('Foo', 2) // Returns string "Foo2"
add('Foo', 'Bar') // Returns string "FooBar"
// point :: (Number, Number) -> {x: Number, y: Number}
const point = (x, y) => ({x: x, y: y})
// 想象一下,在这里我们不能设置只能具有这些值的类型
const bools = new Set([true, false])
const halfTrue = new Set(['half-true'])
// 弱逻辑类型包含 bools 和 halfTrue 值的总和
const weakLogicValues = new Set([...bools, ...halfTrue])
闭包是访问其作用域之外的变量的一种方法。正式一点的解释,闭包是一种用于实现词法作用域的命名绑定的技术。它是一种用环境存储函数的方法。
闭包是一个作用域,在这个作用域能够捕获访问函数的局部变量,即使执行已经从定义它的块中移出。即,它们允许在声明变量的块执行完成之后保持对作用域的引用。
const addTo = x => y => x + y
var addToFive = addTo(5)
addToFive(3) // returns 8
函数 addTo() 返回一个函数(内部调用 add() ),将它存储在一个名为 addToFive 的变量中,并柯里化(Curried)调用,参数为 5 。 通常,当函数 addTo 完成执行时,其作用域与局部变量 add,x,y 不可访问。但是,它在调用 addToFive() 时返回 8。这意味着即使代码块执行完成后,函数 addTo 的状态也被保存,否则无法知道 addTo 被调用为 addTo(5),x 的值设置为 5。
词法作用域是能够找到 x 和 add 的值的原因 – 已完成执行的父级私有变量。这就称为 Closure(闭包) 。
堆栈伴随着函数的词法作用域存储在父对象的引用形式中。这样可以防止闭包和底层变量被当做垃圾回收(因为至少有一个实时引用)。
Lambda Vs Closure(闭包) :lambda 本质上是一个内联定义的函数,而不是声明函数的标准方法。lambda 经常可以作为对象传递。
闭合是一个函数,通过引用其函数体外部的字段来保持对外部变量的引用。
计算机专业、互联网专业术语大全,值得大家收藏备用熟记的IT常用术语。这篇文章从不同的方式讲解IT行业常见技术及专业术语,为刚进入IT行业或对IT行业毫不了解的人群快速普及常见IT技术
JavaScript常见术语解释总结,这里是javascript经常用到的各种专业名词,在此整理一下分享给大家,比如:直接量、变量、原始值、引用值、保留字与关键字 等
函数式编程有许多优势,由此越来越受欢迎。然而每个编程范式 (paradigm) 都有自己唯一的术语,函数式编程也不例外。我们提供一张术语表,希望使你学习函数式编程变得容易些。
API应用程序接口(英语:Application Programming Interface,简称:API),又称为应用编程接口,就是软件系统不同组成部分衔接的约定。由于近年来软件的规模日益庞大,常常需要把复杂的系统划分成小的组成部分,编程接口的设计十分重要
变量,指值可以变的量。变量以非数字的符号来表达,一般用拉丁字母。变量的用处在于能一般化描述指令的方式。结果只能使用真实的值,指令只能应用于某些情况下。变量能够作为某特定种类的值中任何一个的保留器。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!