We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
照例思维导图。
总的来说,按值传递。
var param = 1 function foo(a) { console.log(a); // 1 a = 2; console.log(a); // 2 } foo(param); console.log(param); // 1
这很好理解,当传递给函数参数的值是基本类型值的时候。直接把变量的值复制给函数参数,且变量与参数互不影响。
对于传递引用类型值的时候,其实是共享传递,什么是共享传递?共享传递就是传递对象的引用的副本!
因为拷贝副本也是一种值的拷贝,所以在高程中也直接认为是按值传递了。
你可以理解为:参数如果是基本类型是按值传递,如果是引用类型按共享传递。
举个例子:
var obj = { value: 1 }; function foo(o) { o = 2; console.log(o); //2 } foo(obj); console.log(obj.value) // 1
传递给o的是obj引用的副本。当改变o的值的时候,对obj本身并没有影响。
函数式编程是一种被部分JavaScript程序员推崇的编程风格,更别说 Haskell 和 Scala 这种以函数式为教义的语言。原因是因为其能用较短的代码实现功能,如果掌握得当,能达到代码文档化(代码本身具有很高可读性甚至可以代替文档)的效果,当然,泛滥使用也会使代码可读性变差。
函数式编程以函数作为主要载体的编程方式,用函数去拆解、抽象一般的表达式。其思维建议我们把多次出现的功能封装在一个函数里,可以重复调用。
出道题:
现在有一个数组,array = [1, 3, 'h', 5, 'm', '4'],现在想要找出这个数组中的所有类型为number的子项。你会怎么做?
可能大多数人就这样写,直来直去简单明了(命令式编程):
var array = [1, 3, 'h', 5, 'm', '4']; var res = []; for(var i=0; i<array.length; i++) { if (typeof array[i] === 'number') { res.push(array[i]); } } console.log(res);
这样是可以实现功能,但这样写的坏处是什么呢?假如之后我们要为另一个数组找子项,那又要写重复的逻辑。当出现次数多了,代码就会变得糟糕和难以维护。运用函数式编程的思维来写的话,就可以把相同的功能封装起来。
function getNumbers(arr) { var res = []; arr.forEach((item) => { if (typeof item === 'number') { res.push(item); } }) return res; }
当我们将功能封装之后,我们实现同样的功能时,只需要写一行代码。而如果未来需求变动,或者稍作修改,我们只需要对getNumbers方法进行调整就可以了。而且我们在使用时,只需要关心这个方法能做什么,而不用关心他具体是怎么实现的。
所谓"第一等公民"(first class),指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。这些场景,我们应该见过很多。
"表达式"(expression)是一个单纯的运算过程,总是有返回值(函数式编程期望一个函数有输入,也有输出。);"语句"(statement)是执行某种操作,没有返回值。函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。
比如下面这段代码:
var ele = document.querySelector('.test'); function setBackgroundColor(color) { ele.style.backgroundColor = color; // 这里面封装的仅仅只是一个语句,没有返回值。 } // 多处使用 setBackgroundColor('red'); setBackgroundColor('#ccc');
按照函数式编程的习惯,应该改为如下:
function setBackgroundColor(ele, color) { ele.style.backgroundColor = color; return color; } // 多处使用 var ele = document.querySelector('.test'); setBackgroundColor(ele, 'red'); setBackgroundColor(ele, '#ccc');
纯函数即不产生“副作用”的函数。相同的输入总会得到相同的输出。
怎么理解?可以理解为不要改变输入进去的原对象(可以返回新对象也好)。
举个例子:我们期望封装一个函数,能够得到传入数组的最后一项。那么可以通过下面两种方式来实现。
function getLast(arr) { return arr[arr.length - 1]; } var arr = [1, 2, 3]; getLast(arr); console.log(arr); // [1,2,3] 这种方式没改变原数组,该函数是纯函数
function getLast_(arr) { return arr.pop(); } var arr = [1, 2, 3]; getLast_(arr); // [1,2] 改变了原数组。
getLast与getLast_虽然同样能够获得数组的最后一项值,但是getLast_改变了原数组。而当原始数组被改变,那么当我们再次调用该方法时,得到的结果就会变得不一样。这样不可预测的封装方式,在我们看来是非常糟糕的。它会把我们的数据搞得非常混乱。在JavaScript原生支持的数据方法中,也有许多不纯的方法,我们在使用时需要非常警惕,我们要清晰的知道原始数据的改变是否会留下隐患。
var source = [1, 2, 3, 4, 5]; source.slice(1, 3); // 纯函数 返回[2, 3] source不变 source.splice(1, 3); // 不纯的 返回[2, 3, 4] source被改变 source.pop(); // 不纯的 source.push(6); // 不纯的 source.shift(); // 不纯的 source.unshift(1); // 不纯的 source.reverse(); // 不纯的 // 我也不能短时间知道现在source被改变成了什么样子,干脆重新约定一下 source = [1, 2, 3, 4, 5]; source.concat([6, 7]); // 纯函数 返回[1, 2, 3, 4, 5, 6, 7] source不变 source.join('-'); // 纯函数 返回1-2-3-4-5 source不变
诸如闭包、函数柯里化也是函数式编程的风格。
如果用一句话总结的话,函数式编程是以函数作为主要载体的编程方式。
优点:
本文完。
希望看到各位技术人对这篇文章有不同的有“证据”,符合逻辑的分析、看法~
文章会第一时间更新在GitHub,觉得写得还不错的,可以点个star支持下作者🍪
参考:
The text was updated successfully, but these errors were encountered:
No branches or pull requests
照例思维导图。
提一下函数参数传递方式
总的来说,按值传递。
这很好理解,当传递给函数参数的值是基本类型值的时候。直接把变量的值复制给函数参数,且变量与参数互不影响。
对于传递引用类型值的时候,其实是共享传递,什么是共享传递?共享传递就是传递对象的引用的副本!
因为拷贝副本也是一种值的拷贝,所以在高程中也直接认为是按值传递了。
你可以理解为:参数如果是基本类型是按值传递,如果是引用类型按共享传递。
举个例子:
传递给o的是obj引用的副本。当改变o的值的时候,对obj本身并没有影响。
函数式编程
函数式编程是一种被部分JavaScript程序员推崇的编程风格,更别说 Haskell 和 Scala 这种以函数式为教义的语言。原因是因为其能用较短的代码实现功能,如果掌握得当,能达到代码文档化(代码本身具有很高可读性甚至可以代替文档)的效果,当然,泛滥使用也会使代码可读性变差。
函数式编程以函数作为主要载体的编程方式,用函数去拆解、抽象一般的表达式。其思维建议我们把多次出现的功能封装在一个函数里,可以重复调用。
出道题:
现在有一个数组,array = [1, 3, 'h', 5, 'm', '4'],现在想要找出这个数组中的所有类型为number的子项。你会怎么做?
可能大多数人就这样写,直来直去简单明了(命令式编程):
这样是可以实现功能,但这样写的坏处是什么呢?假如之后我们要为另一个数组找子项,那又要写重复的逻辑。当出现次数多了,代码就会变得糟糕和难以维护。运用函数式编程的思维来写的话,就可以把相同的功能封装起来。
当我们将功能封装之后,我们实现同样的功能时,只需要写一行代码。而如果未来需求变动,或者稍作修改,我们只需要对getNumbers方法进行调整就可以了。而且我们在使用时,只需要关心这个方法能做什么,而不用关心他具体是怎么实现的。
函数是一等公民
所谓"第一等公民"(first class),指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。这些场景,我们应该见过很多。
只用"表达式",不用"语句"
"表达式"(expression)是一个单纯的运算过程,总是有返回值(函数式编程期望一个函数有输入,也有输出。);"语句"(statement)是执行某种操作,没有返回值。函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。
比如下面这段代码:
按照函数式编程的习惯,应该改为如下:
纯函数
纯函数即不产生“副作用”的函数。相同的输入总会得到相同的输出。
怎么理解?可以理解为不要改变输入进去的原对象(可以返回新对象也好)。
举个例子:我们期望封装一个函数,能够得到传入数组的最后一项。那么可以通过下面两种方式来实现。
getLast与getLast_虽然同样能够获得数组的最后一项值,但是getLast_改变了原数组。而当原始数组被改变,那么当我们再次调用该方法时,得到的结果就会变得不一样。这样不可预测的封装方式,在我们看来是非常糟糕的。它会把我们的数据搞得非常混乱。在JavaScript原生支持的数据方法中,也有许多不纯的方法,我们在使用时需要非常警惕,我们要清晰的知道原始数据的改变是否会留下隐患。
诸如闭包、函数柯里化也是函数式编程的风格。
一句话总结
如果用一句话总结的话,函数式编程是以函数作为主要载体的编程方式。
优点:
本文完。
希望看到各位技术人对这篇文章有不同的有“证据”,符合逻辑的分析、看法~
文章会第一时间更新在GitHub,觉得写得还不错的,可以点个star支持下作者🍪
参考:
The text was updated successfully, but these errors were encountered: