一、函数
1.1 什么是函数?
在JavaScript中,函数是基础语法之一,作用域、变量对象、闭包、this等知识点都是围绕着函数展开的。从代码上看,被 function
关键词所声明的称之为函数;从实际应用上看,常见的函数形式有函数声明、函数表达式、匿名函数和自执行函数。
1.2 函数声明
fn(); // 函数声明
function fn() {
console.log('函数声明');
}
在变量对象创建的过程中,function
声明的函数比var
声明的变量更优先执行。因此在同一执行上下文中,无论什么位置声明了函数,都可以直接使用。
1.3 函数表达式
函数表达式指的是将函数体赋值给一个变量。
fn(); // TypeError: fn is not function
var fn = function() {
console.log('函数表达式');
}
执行过程可以参考变量,先变量提升为undefined然后再执行过程中赋值。在使用函数表达式时要注意执行顺序问题,这是与函数声明所不同的地方。
1.4 匿名函数
匿名函数一般作为一个参数或者返回值来使用,他没有名字,不易被控制台调试捕获到。
/* 匿名函数作为参数使用 */
var timer = setTimeout(function(){
console.log('匿名函数');
},1000)
/* 匿名函数作为返回值使用 */
function fn(message) {
var name = 'coco';
return function() {
return name + ' ' + message
}
}
fn('ball')();
1.5 函数自执行
自执行函数会产生独立的作用域,因此自执行函数常常用来模仿块级作用域,并进一步在此基础上实现模块化的应用。自执行函数也是匿名函数常见的执行场景之一。
在实际应用中,我们进一步通过自执行实现模块化的运用。
(function(){
// 私有变量
var name = 'coco';
var message = 'frist at all';
var flag = false;
// 私有方法
function getName() {
return `hello ` + name;
}
// 公有方法
function getMessage() {
return flag ? 'sorry I can not' : message
}
window.getMessage = getMessage;
})();
当我们使用自执行创建一个模块时,就意味着,外界已经无法访问该模块内部的任何属性和方法了。我们又通过闭包技术,搭起了模块之间能相互交流的桥梁,让模块能够在我们的控制之下,选择性的对外开放属性和方法。
二、函数式编程
2.1 函数是一等公民
函数在javascript中是一等公民,函数可以作为函数参数,可以作为函数返回值,也可以赋值给变量。
例如: 字符串是在大多数语言中都是一等公民,字符串可以做为函数参数,字符串可以作为函数返回值,字符串也可以赋值给变量。
2.2 声明式编程、命令式编程、函数式编程
-
声明式编程:专注于”做什么”而不是”如何去做”。在更高层面写代码,更关心的是目标,而不是底层算法实现的过程。如:css, 正则表达式,sql 语句,html, xml…
-
命令式编程(过程式编程) : 专注于”如何去做”,这样不管”做什么”,都会按照你的命令去做。解决某一问题的具体算法实现。
-
函数式编程:把运算过程尽量写成一系列嵌套的函数调用,这种函数封装思维叫做编程式思维。相比于命令式编程关心解决问题的步骤,函数式编程是面向数学的抽象,关心数据(代数结构)之间的映射关系。函数式编程将计算描述为一种表达式求值。在狭义上,函数式编程意味着没有可变变量,赋值,循环和其他的命令式控制结构。
2.3 纯函数
纯函数是一种函数特殊的函数,即相同的输入永远会得到相同的输出,而且没有任何可观察的副作用。即:不依赖外部状态,不改变外部状态,外部状态指的就是耦合度。
function fn(num) {
if(parseFloat(num) <= 0) return 'request error'
return num * 1.5 + 2300;
}
2.4 高阶函数
高阶函数其实是一个封装公共逻辑的过程。在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:
- 接受一个或多个函数作为输入
- 输出一个函数
var arr1 = [1, 2, 3, 4];
var arr2 = arr1.map(num => num * 2);
console.log(arr1); // [1, 2, 3, 4]
console.log(arr2); // [2, 4, 6, 8]
很多函数式编程语言都支持这个方法 map 表达式将 func 函数作用于 array 的每一个元素,并返回一个新的 array。
函数式语言通常提供非常强大的集合类(Collection),提供很多高阶函数,因此使用非常方便。
2.5 偏函数
偏函数,也叫部分应用函数,就是固化函数的一个或一些参数,只传入函数的部分参数,从而产生一个新的函数。
换言之,偏函数就是固定一个函数的一个或者多个参数,返回一个新的函数,这个函数用于接受剩余的参数。
function add(a + b) {
return a + b;
}
var add2 = add.bind(number, 5);
console.log(add(2, 5)); // 2 + 5 = 7
console.log(add2(7)); // 5 + 7 = 12
创建一个新函数,具有相同的函数体,调用时的参数被提供给模拟函数
2.6 函数柯里化
函数柯里化的概念很简单:把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数。
此外,柯里化函数有内置的迭代器机制:柯里化函数每次应用一个参数,不会做超出一个参数外的工作。调用返回的函数也就是告诉函数来进行下一步处理。
//柯里化前
function add(a, b, c) { return a + b + c;}
//柯里化后
function _add(a) {
return function(b) {
return function(c) {
return a + b + c;
}
}
}
console.log(add(1)(2)(3)) // 6
柯里化的作用:不断的柯里化,累积传入的参数,最后执行,当在多次调用同一个函数,并且传递的参数绝大多数是相同的,那么该函数就可以使用柯里化。
/* 柯里化前 */
function userLogin1(transNo, data, func) {
axiosPost(testUrl, {
transNo: transNo,
param: data
}, func,function(error) {
console.log(error);
})
}
/* 柯里化后 */
function userLogin2(tranNo) {
if(!tranNo) return alert('未指定交易号');
return function(data) {
let request = {
transNo: transNo,
param: data
}
return function(func) {
axiosPost(testUrl, request, func, function(error) {
console.log(error);
})
}
}
}
userLogin1('T200000050', {
/* 参数体 */
}, function(response) {
/* 方法体 */
});
userLogin2('T200000050')({ /* 参数体 */ })(function(response) { /* 方法体 */ });
函数可以作为参数传递,函数能够作为函数的返回值。
我们平时接触的函数大多都是偏函数,经过柯里化概念认知后:柯里化函数每次应用一个参数,不会做超出一个参数外的工作。调用返回的函数也就是告诉函数来进行下一步处理。
总结 : 本篇内容简单梳理了函数和函数式编程部分知识,函数式编程部分内容大都是停留在概念一级,概念扫盲不能透彻的理解一些事情,但是千里之行始于足下,我认可知识体系是不断丰富建设的,对于熟练应用掌握的那一天当是水到渠成。下一篇扫盲面向对象相关知识,其中包括构造函数与原型,原型链和经典的jQuery封装拆解。
上一篇文章: Javascript 知识扫盲(二)
下一篇文章: 预留,本店打烊