Open zhaobinglong opened 4 years ago
纯函数,这里有一个非常严格的定义:
function add(a,b) {
return a+b
}
当我们讨论高阶函数时,通常包括以下几点:
// 自己实现一个map的高阶函数
function myMap(arr, fn) {
let newArr = [];
for(let i in arr) {
newArr.push(
fn(arr[i])
)
}
return newArr;
}
// 用myMap函数实现一下上面的需求
myMap(persons, function(item){return item.age}); // [10, 18, 49]
// 试着把写进Array.prototype原型上
Array.prototype.myMap = function(fn){
let array = this;
let len = array.length;
let newArr = [];
for(let i=0; i<len; i++){
newArr.push(fn(array[i], i, array))
}
return newArr;
}
柯里化,英语:Currying(果然是满满的英译中的既视感),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
将一个带有多个参数的函数转换为一次只传递部分参数的过程。每次调用函数时,它只接受一个或者多个参数,并返回一个函数,直到传递所有参数为止。
// 实现一个工具函数,将普通函数柯里化
function curry(fn) {
// 保存预置参数
const presetArgs = [].slice.call(arguments, 1)
// 返回一个新函数
function curried () {
// 新函数调用时会继续传参
const restArgs = [].slice.call(arguments)
const allArgs = [...presetArgs, ...restArgs]
return curry.call(null, fn, ...allArgs)
}
// 重写toString
curried.toString = function() {
return fn.apply(null, presetArgs)
}
return curried;
}
function dynamicAdd() {
return [...arguments].reduce((prev, curr) => {
return prev + curr
}, 0)
}
var add = curry(dynamicAdd);
add(1)(2)(3)(4) // 10
add(1, 2)(3, 4)(5, 6) // 21
// 正常正则验证字符串 reg.test(txt)
// 函数封装后
function check(reg, txt) {
return reg.test(txt)
}
check(/\d+/g, 'test') //false
check(/[a-z]+/g, 'test') //true
// Currying后
function curryingCheck(reg) {
return function(txt) {
return reg.test(txt)
}
}
var hasNumber = curryingCheck(/\d+/g)
var hasLetter = curryingCheck(/[a-z]+/g)
hasNumber('test1') // true
hasNumber('testtest') // false
hasLetter('21212') // false
//换一种写法可能比较好理解一点,上面就是把isSupport这个参数给先确定下来了
var on = function(isSupport, element, event, handler) {
isSupport = isSupport || document.addEventListener;
if (isSupport) {
return element.addEventListener(event, handler, false);
} else {
return element.attachEvent('on' + event, handler);
}
}
// 像我们js中经常使用的bind,实现的机制就是Currying.
Function.prototype.bind = function (context) {
var _this = this
var args = Array.prototype.slice.call(arguments, 1)
return function() {
return _this.apply(context, args)
}
}
// 实现一个add函数,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;
function add() {
let sum = 0;
sum = Array.prototype.slice.call(arguments).reduce((a,b) => {return a+b;},sum);
var curried = function () {
if (arguments.length == 0) {
return sum;
}else{
sum = Array.prototype.slice.call(arguments).reduce((a,b) => {return a+b;},sum);
return curried;
}
};
curried.toString = function () {
return sum;
}
return curried;
}
console.log(add(1)(2)(3)(4));//10
console.log(add(1,2)(3,4)(1));//10
console.log(add(1,2)(3,4));//10
https://www.jianshu.com/p/2975c25e4d71 https://www.zhangxinxu.com/wordpress/2013/02/js-currying/ https://zhuanlan.zhihu.com/p/31271179 https://juejin.im/post/6864378349512065038#heading-27
[].map(item => {
//
})
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
AOP(面向切面编程)的主要作用就是把一些和核心业务逻辑模块无关的功能抽取出来,然后再通过“动态织入”的方式掺到业务模块种。这些功能一般包括日志统计,安全控制,异常处理等。AOP是Java Spring架构的核心。下面我们就来探索一下再Javascript种如何实现AOP 在JavaScript种实现AOP,都是指把一个函数“动态织入”到另外一个函数中,具体实现的技术有很多,我们使用Function.prototype来做到这一点
/**
* 织入执行前函数
* @param {*} fn
*/
Function.prototype.aopBefore = function(fn){
// 第一步:保存原函数的引用
const _this = this
// 第四步:返回包括原函数和新函数的“代理”函数
return function() {
// 第二步:执行新函数,修正this
fn.apply(this, arguments)
// 第三步 执行原函数
return _this.apply(this, arguments)
}
}
/**
* 织入执行后函数
* @param {*} fn
*/
Function.prototype.aopAfter = function (fn) {
const _this = this
return function () {
let current = _this.apply(this,arguments)// 先保存原函数
fn.apply(this, arguments) // 先执行新函数
return current
}
}
/**
* 使用函数
*/
let aopFunc = function() {
console.log('aop')
}
// 注册切面
aopFunc = aopFunc.aopBefore(() => {
console.log('aop before')
}).aopAfter(() => {
console.log('aop after')
})
// 真正调用
aopFunc()
有时候我们会写一些函数,这些函数是处理业务逻辑的,函数中有很多判断,你会发现函数每次被调用,这些判断都要被执行一次,有没有可能函数只有在第一次调用的时候会执行一次判断,后续就不再执行这个判断呢?实现这种方案的函数就是惰性函数
// 给执行元素点击事件,每次执行addEvent,if都会被执行一次
function addEvent(element, type, handler) {
if (window.addEventListener) {
element.addEventListener(type, handler, false);
} else if (window.attachEvent){
element.attachEvent('on' + type, handler);
} else {
element['on' + type] = handler;
}
}
// if只会被执行一次
function addEvent(element, type, handler) {
if (window.addEventListener) {
addEvent = function(element, type, handler) {
element.addEventListener(type, handler, false);
}
} else if (window.attachEvent){
addEvent = function(element, type, handler) {
element.attachEvent('on' + type, handler);
}
} else {
addEvent = function(element, type, handler) {
element['on' + type] = handler;
}
}
// 有点闭包的味道了
addEvent(element, type, handler);
}
一句话
函数是JavaScript这门语言中的一等公民
构造函数和普通函数的区别
• 构造函数首字母习惯大写 • 构造函数需要new才能使用,普通函数不需要
参考
https://zhuanlan.zhihu.com/p/78513598