提高你的javascript代码逼格系列之函数与数组

时间:2022-09-10 07:39:07

不知道大家有没有一种感觉,那就是自己写的javascript代码虽然能完全解决工作上的需要,但是,一眼望去,too simple!!!简直就是一个*都能看懂的水平,于是,在工作之余,我开始去收集一些几乎在日常开发中未曾用过的javascript写法/有价值的javascript知识点,借此来提高自身javascript水平。

一、函数式编程与面向对象编程

<script>
/*函数式编程*/
function f1(){
    var n=999;
    nAdd=function(){
n+=1;
};
    var f2 = function(){
      console.log(n);
    };
    return f2;
  }
  var result=f1();
  result(); //
  nAdd();
  result(); // /*面向对象编程1之json写法*/
var obj1 = {
n:999,
nAdd:function(){
this.n += 1;
},
getN:function(){
console.log(this.n);
}
};
obj1.getN();//
obj1.nAdd();
obj1.getN();// /*面向对象编程2之工厂模式*/
var obj2 = function(){
var obj = new Object;
obj.n = 999;
obj.nAdd = function(){
this.n += 1;
};
obj.getN = function(){
console.log(this.n);
}
return obj;
};
var objins = new obj2();
objins.getN();//
objins.nAdd();
objins.getN();// /*面向对象编程3之原型prototype*/
function obj3(n) {
this.n = n;
}
obj3.prototype.nAdd = function() {
this.n+=1;
};
obj3.prototype.getN = function() {
console.log(this.n);
}
var objins2 = new obj3(999);
objins2.getN();//
objins2.nAdd();
objins2.getN();//
</script>

针对上面所示的函数式编程,涉及了作用域和闭包的知识,这里简要提一下;

里面的nAdd没有用var关键字声明,所以他是全局的,后面可以全局调用,其次利用闭包访问和修改了函数作用域内的n值。

二、纯函数和非纯函数

1.此函数在相同的输入值时,总是产生相同的输出。函数的输出和当前运行环境的上下文状态无关。

2.此函数运行过程不影响运行环境,也就是无副作用(如触发事件、发起http请求、打印/log等)。

简单来说,也就是当一个函数的输出不受外部环境影响,同时也不影响外部环境时,该函数就是纯函数,也就是它只关注逻辑运算和数学运算,同一个输入总得到同一个输出。

var xs = [1,2,3,4,5];
// 纯的
xs.slice(0,3);
//=> [1,2,3]
xs.slice(0,3);
//=> [1,2,3]
xs.slice(0,3);
//=> [1,2,3] // 不纯的
xs.splice(0,3);
//=> [1,2,3]
xs.splice(0,3);
//=> [4,5]
xs.splice(0,3);
//=> []

纯函数相对于非纯函数来说,在可缓存性、可移植性、可测试性以及并行计算方面都有着巨大的优势。

三、函数的柯里化

curry 的概念很简单:将一个低阶函数转换为高阶函数的过程就叫柯里化。

函数柯里化是一种“预加载”函数的能力,通过传递一到两个参数调用函数,就能得到一个记住了这些参数的新函数。从某种意义上来讲,这是一种对参数的缓存,是一种非常高效的编写函数的方法:

                /*一般写法:两数相加*/
var add = function(x,y){
return x + y;
}
/*2+1和2+10*/
add(2,1);//
add(2,10);// /*柯里化写法*/
//es5
var add = function(x) {
return function(y) {
return x + y;
};
};
//es6
var add = x => (y => x + y); //定义+1和+10函数
var increment = add(1);//柯里化后得到的+1函数
var addTen = add(10);//柯里化后得到的+10函数
increment(2); //
addTen(2); //

四、Array.reduce/Array.reduceRight(数组迭代)

先不看标题,来个题目:如何求数组[1,2,3,4,5]的各项累加的和?

大多数人恐怕会立即说出for循环、while循环,的确,for循环和while循环是可以解决上述问题,但是,这个答案显然脱离了此篇博客的主题:逼格!!!

并且,实验表明,将上述求和方法循环1W次,用for循环和while循环耗时大概在50~55ms,但是,用Array.reduce/Array.reduceRight仅仅耗时0.4ms!!!

关于该方法的详解,请猛戳→https://www.w3cplus.com/javascript/array-part-8.html;这里给个demo:

var arr = [1,2,3,4,5];
/*ES6写法*/
var reducer = (prevalue,curvalue)=>prevalue + curvalue;
console.log(arr.reduce(reducer));//
/*ES5写法*/
var reducer = function(prevalue,curvalue){
return prevalue + curvalue;
};
console.log(arr.reduce(reducer));//
/*解析*/
数组的reduce方法有两个参数:callback,prevalue;
对于第一个参数callback,里面有4个参数prevalue、curvalue、index、array;
index是当前迭代时的curvalue的索引(数组中的索引),array当然是操作的数组了;
着重看另外两个参数,prevalue和curvalue(上一个值和当前值);
如果reduce方法没有第二个参数的话,那么callback回调将数组第一个值作为prevalue,第二个值作为curvalue;
如果reduce方法有第二个参数,那么将第二个参数值作为prevalue,将数组第一个值作为curvalue;
每一次的操作结果将变为下一次操作的prevalue,而curvalue的值教上一次往后推一位;
/*实例解析*/
针对上述数组相加;
没有第二个参数,只有一个回调callback,那么他的过程是这样的;
第一次运算:prevalue为1,curvalue为2,运算结果为1+2=3,并将结果作为下次运算的prevalue;
第二次运算:prevalue为3(上一次运算的结果),curvalue为3,运算结果为3+3=4,以此类推; 如果有第二个参数,假设为5,arr.reduce(reducer,5),那么将是这么计算的;
第一次运算:prevalue为5(第二个参数),curvalue为1,运算结果为5+1=6,并将结果作为下次运算的prevalue;
第二次运算:prevalue为6(上一次运算的结果),curvalue为2,运算结果为6+2=8,以此类推; reduceRight和reduce类似,只不过他是从右边开始迭代的。

 五、函数组合(reduce高级用法)

假想一下,要将字符串“my name is echo”进行如下操作,你会怎么做?转大写、然后末尾加一个感叹号;

我想你大概会定义一个函数operate,对于形参str,先toUpperCase(),然后+ '!',ok这样做没错,但是现在我需求改了,我不要求转大写了,你是不是得删除那行代码?

可能你会说了,我定义两个函数一个是转大写,一个是加叹号,需要哪个用哪个,其实无论你用几个函数来写,还是直接用prototype或者链式调用的方法去写,都只是大众化的写法,且不易维护,so,请看下面的写法:

        var compose = (...args) => x => args.reduceRight((prevalue, curvalue) => curvalue(prevalue), x);
var toUpperCase = x => x.toUpperCase();
var exclaim = x => x + '!';
var shout = compose(exclaim, toUpperCase);
console.log(shout("my name is echo"));

一眼望去,是不是两眼懵逼?!!不怕,我们用ES5还原一下,请看:

        var compose = function (...args){
return function (x){
return args.reduceRight(function(prevalue, curvalue){
return curvalue(prevalue);
},x)
}
};
var toUpperCase = function(x){
return x.toUpperCase();
};
var exclaim = function(x){
return x + '!';
};
var shout = compose(exclaim, toUpperCase);
console.log(shout("my name is echo"));

结合上述第四例所讲到的reduce,我希望此时你已经看懂了,没看懂也没关系,接着往下看,继续解析:

        var shout == compose(exclaim, toUpperCase)
== function (x) {
return [exclaim, toUpperCase].reduceRight(function(prevalue, curvalue){
return curvalue(prevalue);
},x)
};
shout("my name is echo") == [exclaim, toUpperCase].reduceRight(function(prevalue, curvalue){
return curvalue(prevalue);
},"my name is echo");
/*前面说过,如果reduce/reduceRight传了第二个参数,那么该第二个参数将作为prevalue给callback调用。*/
/*运算过程如下(reduceRight从右往左)curvalue(prevalue):*/
1.toUpperCase("my name is echo");并将结果作为prevalue供下次调用;
2.exclaim(toUpperCase("my name is echo"));如此实现了先转大写再加感叹号。

提高你的javascript代码逼格系列之函数与数组的更多相关文章

  1. JS函数 编程练习 使用javascript代码写出一个函数:实现传入两个整数后弹出较大的整数。

    编程练习 使用javascript代码写出一个函数:实现传入两个整数后弹出较大的整数. 任务 第一步: 编写代码完成一个函数的定义吧. 第二步: 我们来补充函数体中的控制语句,完成函数功能吧. 提示: ...

  2. JavaScript代码段整理笔记系列(二)

    上篇介绍了15个常用代码段,本篇将把剩余的15个补齐,希望对大家有所帮助!!! 16.检测Shift.Alt.Ctrl键: event.shiftKey; //检测Shift event.altKey ...

  3. 深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点

    深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点 2011-12-28 23:00 by 汤姆大叔, 139489 阅读, 119 评论, 收藏, 编辑 才华横溢的 ...

  4. Selenium3 &plus; Python3自动化测试系列十——调用JavaScript代码

    调用JavaScript代码 一.调用JavaScript代码方法 Selenium在对浏览器操作时会有自动化代码中不稳定的部分,经常出错的部分,可以将这部分对网页元素进行操作的代码换成对应的Java ...

  5. JavaScript代码段整理笔记系列(一)

    30段JavaScript代码——上篇 1.如何区分IE及非IE浏览器: if(!+[1,]){ //IE 11 不支持 alert("这是 IE 浏览器"): }else{ al ...

  6. C&num; 代码中调用 Javascript 代码段以提高应用程序的配置灵活性&lpar;使用 Javascript &period;NET 与 Jint&rpar;

    一般来说,我们需要在开发应用软件的配置文件中,添加一些参数,用于后续用户根据实际情况,自行调整. 配置参数,可以放在配置文件中.环境变量中.或数据库表中(如果使用了数据库的话).通常,配置数据,以 k ...

  7. 如何提高JavaScript代码质量

    如何编写可维护的JavaScript代码 代码风格及规范 构建检查工具 jshint配置 http://jshint.com/docs/options/ http://www.cnblogs.com/ ...

  8. 巧妙利用函数的惰性载入提高javascript 代码性能

    在 javascript 代码中,因为各浏览器之间的行为的差异,我们经常会在函数中包含了大量的 if 语句,以检查浏览器特性,解决不同浏览器的兼容问题. 例如,我们最常见的为 dom 节点添加事件的函 ...

  9. 利用函数的惰性载入提高 javascript 代码性能

    在 javascript 代码中,因为各浏览器之间的行为的差异,我们经常会在函数中包含了大量的 if 语句,以检查浏览器特性,解决不同浏览器的兼容问题.例如,我们最常见的为 dom 节点添加事件的函数 ...

随机推荐

  1. table布局, td内部元素溢出边界问题。 (已解决)

    今天,我尝试用table布局有多个输入需要提交的页面, 为了使输入元素占满td,我对其宽度设置为100%, 结果text输入元素溢出td, 具体情况如下: 解决办法是对td样式设置为overflow: ...

  2. HttpClient 3&period;X 4&period;3 4&period;x超时设置

    HttpClient 4.3.HttpClient这货和Lucene一样,每个版本的API都变化很大,这有点让人头疼.就好比创建一个HttpClient对象吧,每一个版本的都不一样, 3.X是这样的 ...

  3. Java-基础练习3

    1.编写一个Java程序,计算半径为3.0的圆周长和面积并输出结果.把圆周率π定义为常量,半径定义为变量,然后进行计算并输出结果. package com.java; public class zm ...

  4. java中的this与super的区别

    java中的this与super的区别 1. 子类的构造函数如果要引用super的话,必须把super放在函数的首位 代码如下: class Base { Base() { System.out.pr ...

  5. 排版字号对应多少pt

    各字号对应多少pt?初号= 42pt: 小初号= 36pt: 一号= 26pt: 二号= 22pt: 小二号= 18pt: 三号= 16pt: 四号= 14pt: 小四号= 12pt: 五号= 10. ...

  6. 【C&num;设计模式——创建型模式】简单工场模式

    进入码农行列也有一年半载了,仍然感觉自己混混沌沌,无所事事,无所作为,,,想想都下气,下气归下气,仍要奋起潜行,像愤怒的小鸟一边又一遍的冲向猪头也好,像蜗牛一样往前蹭也罢,总之要有蚂蚁啃骨头的精神!! ...

  7. iframe自适应高度代码

    var adjustIframe = function (id) { var iframe = document.getElementById(id) var idoc = iframe.conten ...

  8. QReadWriteLock上锁容忍的等待时间是多久?

    非递归上锁情况下,同一个锁,已经被锁过一次,那么另外一个线程尝试上锁,会被挡在外面,但是会被挡多久呢?挡一分钟会被崩溃,还十分钟,还是永久等待而不崩溃(希望如此)?还是会立刻崩溃?因为不可以重复上锁. ...

  9. 利用vertical-align&colon;middle垂直居中

    以前总是以为vertical-align与text-align是同样的道理,一个是垂直居中,一个是水平居中,结果在这里一点效果也没有.事实上vertical-align与text-align完全不一样 ...

  10. Algorithm --&gt&semi; 全排列

    1.算法简述 简单地说:全排列就是从第一个数字起每个数分别与它后面的数字交换. E.g:E = (a , b , c),则 prem(E)= a.perm(b,c)+ b.perm(a,c)+ c.p ...