函数是javascript中非常重要的一部分,用途也非常的多,可作为参数、返回值、回调等等,下面有一些函数式编程的重要概念和定义
纯函数
纯函数属于程序设计的名词,其它语言中也是存在的,而在javascript中,符合以下规则即为纯函数。
- 函数有相同的输入,必定有相同的输出
- 函数的输出仅与输入有关,与其他隐藏信息无关
- 不得产生任何的副作用,如 触发事件等
副作用:除了返回函数值以外,还对调用函数产生了其他的影响,如修改全局变量、修改参数或者改变外部存储。
以下几个示例来区分一下纯函数和非纯函数
1、数组方法
var arr1 = [1, 2, 3, 4]
var arr2 = [10, 20, 30, 40]
const newArr1 = arr1.splice(1, 3)
const newArr2 = arr2.slice(1, 3)
console.log(arr1, newArr1)
console.log(arr2, newArr2)
splice 通过下标值和长度操作原数组本身,修改了入参,所以不是纯函数。 slice 通过下标值截取数组,返回一个新的数组,没有副作用,是纯函数。
2、修改入参
var obj = { name: 'alice' }
function foo(info) {
info.name = 'kiki'
return info
}
foo(obj)
function bar(info) {
return {
...info,
name: 'kiki'
}
}
bar(obj)
上面两个函数的作用都是返回一个新的对象,但foo修改了入参,所以foo不是纯函数,bar没有产生任何副作用,满足纯函数的定义。
使用纯函数在开发当中具有一些优点
- 不用考虑传入的参数是否已经发生了变化
- 不用考虑函数的操作是否会修改全局、外部的一些变量
这样函数的功能就更加的单一和纯净,可以放心的编写和使用
柯里化
通过函数返回函数的方式,实现多次接收参数并进行统一处理的函数编码形式
function sum(a, b, c) {
return a + b + c
}
function add(a) {
return function (b) {
return function (c) {
return a + b + c
}
}
}
sum(1, 2, 3)
add(1)(2)(3)
以上两个函数的执行结果相同,但是调用方式不同,使用柯里化的优点在于使每一个函数的功能更加单一,及逻辑复用
function foo(type, time, message){
console.log(`${type}:${[time]}:${message}`)
}
foo('error', '2021/10/24', '接口返回数据异常')
foo('error', new Date(), '页面显示错误')
function log(type) {
return function (time) {
return function (message) {
console.log(`${type}:${[time]}:${message}`)
}
}
}
var error = log('error')
error('2021/10/24')('接口返回数据异常')
error(new Date())('页面显示错误')
如以上柯里化代码,复用了【获取类型】部分的函数
组合函数
组合函数不是一种函数类型,只是创建一个新函数将多种功能的函数合并起来
function mul(m) {
return m * 2
}
function square(n) {
return n * n
}
function compose(m, n) {
return function (i) {
return m(n(i))
}
}
var fn = compose(mul, square)
console.log(fn(5))
通过组合函数,就可以将不同功能的函数组合使用
with语句
with语句可以创建一个独立的作用域
with语句的语法是 with(){},with小括号内需要传递一个值,一般为对象,with语句内的变量会从这个小括号里先查找
var message = 'global'
var obj = { name: 'alice', message: 'obj' }
function foo() {
console.log(message)
with (obj) {
console.log(message)
}
}
foo()
以上代码的执行结果如下
目前with语句已经不推荐使用了
eval
eval用于解析字符串及执行代码
var str = "var message = 'global'; console.log(message)"
eval(str)
以上代码执行完成会在控制台上输出 global
目前已经不推荐使用eval,从上述代码,我们可以看出它存在的问题
- 可读性非常差,也不便于维护
- eval字符串很可能会在执行的过程中被篡改,容易遭到攻击
- js代码在解析的过程中可以经过js引擎优化,如果是字符串,就没办法优化
严格模式
在全局或者函数中通过 “use strict” 来开启严格模式,严格模式下,不允许编写一些松散的代码,浏览器会对代码进行更严格的检测
严格模式对javascript语义做了一些限制
1、严格模式通过【抛出错误】来消除一些原有的【静默】错误 静默错误:比如定义变量没有关键字声明,如 num = 1
2、严格模式在js引擎在执行代码的时候可以进行更多的优化(不需要对特殊的语法进行处理) 如以下代码,通过属性描述符定义name属性为不可修改
var obj = {}
Object.defineProperty(obj, "name", { writable: false })
obj.name = "alice"
非严格模式直接忽略赋值,严格模式下会报错
3、严格模式禁用了在ECMAScript未来版本可能会定义的一些语法 如: 关键字 function var new 保留字 class let const (ES5以前) 保留字在未来有可能升级为关键字
非严格模式下以前可以使用保留字作为变量如var let = “abc” 严格模式下会报错
具体来说,严格模式做了以下限制 1、无法意外的创建全局变量 在非严格模式下,没有通过关键字定义的变量会被添加到全局 严格模式下这样的代码执行会抛出异常 message is not defined
message = "hello"
2、严格模式会使引起静默失败的赋值操作抛出异常 静默失败:silently fail,不报错也没有任何效果 非严格模式下不报错,严格模式下直接抛出异常 Cannot create property ‘message’ on boolean ‘true’
true.name = "alice"
3、严格模式下删除不可删除的属性会抛出异常 非严格模式下不报错,忽略删除操作,严格模式下直接抛出异常 Cannot delete property ‘address’ of #
var user = { name: 'alice' }
Object.defineProperty(user, 'address', {
value: '上海'
})
delete user.address
4、严格模式不允许函数参数有相同的名称 非严格模式下执行函数,最终输出3,2,3,严格模式下抛出异常 SyntaxError: Duplicate parameter name not allowed in this context
"use strict"
function foo(a, b, a) {
console.log(a, b, a)
}
foo(1, 2, 3)
5、不允许0的八进制语法 非严格模式下,0开头的数字可代表八进制,严格模式下,定义0开头的数字会抛出异常。Octal literals are not allowed in strict mode. 严格模式下可以别的方式定义进制,如 0o(八进制)、0x(十六进制),0b(二进制)
var num = 0212
console.log(num)
6、严格模式下,不允许使用with 非严格模式下,输出gloabl,严格模式下,直接抛出异常 Strict mode code may not include a with statement
var message = 'global'
var obj = { name: 'alice' }
with (obj) {
console.log(message)
}
7、在严格模式下,eval不再为上层引用变量 非严格模式下,eval执行的字符串中定义变量,变量将被添加到全局,而严格模式下,不会被添加。 以下代码非严格模式下,会输出两次global,严格模式下,输出一个global,外加抛出异常 message is not defined
var str = "var message = 'global'; console.log(message)"
eval(str)
console.log(message)
8、严格模式下,this绑定不会默认转成对象 独立函数调用时,非严格模式下,this指向window,严格模式下,this为不会默认指向window。 以下代码在非严格模式下,输出window对象,严格模式下,输出undefined
function foo(){
console.log(this)
}
foo()
以上纯函数、柯里化、组合函数、with语句、eval、严格模式都是函数式编程中的概念,关于js高级,还有很多需要开发者掌握的地方,可以看看我写的其他博文,持续更新中~
|