使用JavaScript ES6的新特性计算Fibonacci(非波拉契数列)
程序员面试系列
Java面试系列-webapp文件夹和WebContent文件夹的区别?
程序员面试系列:Spring MVC能响应HTTP请求的原因?
Java程序员面试系列-什么是Java Marker Interface(标记接口)
JavaScript面试系列:JavaScript设计模式之桥接模式和懒加载
面试题:用JavaScript开发一个函数,打印非波拉契数列。
我们只要记住非波拉契数列的计算公式,就不难写出来了:
F(0)=1,F(1)=1, F(n)=F(n-1)+F(n-2)
我写的JavaScript代码如下:
var fib = function (a, b) {
var _current = a + b;
return {
current: _current,
next: function () {
return fib(b, _current);
}
}
}
把当前这一轮的计算结果存储到第二行的变量_current里,并通过属性current返回给调用者。返回的json对象除了current属性外,还有另一个属性next,指向一个闭包函数调用。一旦next指向的函数再次被调用,则会再次触发数列的计算。
var generator = fib(1,1);
// 前一行调用fib(1,1)计算1+1的结果为2,将2存储到_current里通过current属性返回,所以打印2
// 同时返回next函数,函数体为return fib(b, _current); 此时b为1,_current为2
console.log(generator.current);
// 一旦执行next函数,则执行其指向的return fib(b, _current); 1 + 2 = 3
var result = generator.next();
console.log(result.current); // 打印3
如果要打印10个非波拉契数列的值,意味着我要重复调用9次fib函数,太麻烦。于是我写了个函数把fib调用包裹起来。
这个包裹函数有两个输入参数,n为希望生成非波拉契数列元素的个数,第二个参数sequence接受一个函数。
var take = function(n, sequence) {
var result = [];
var temp = sequence;
for (var i = 0; i < n; i++) {
result.push(temp.current);
temp = temp.next();
}
return result;
}
现在我只需要一行语句,就能打印10个非波拉契数列的元素出来。
console.log(take(10, fib(1,1)));
采用ES6的GeneratorFunction生成非波拉契数列
ES6提供了原生GeneratorFunction的支持,语法非常有特色,关键字function后面紧跟一个星号。GeneratorFunction的详细介绍参考官网:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
先看如何用GeneratorFunction这个黑科技重新实现非波拉契树立的生成。代码如下:
var fib_generator = function *(){
var current = 0, next = 1;
while(true) {
[next, current] = [next+current, next];
yield current;
}
}
var fib = fib_generator();
for(var i = 0; i < 10; i++){
console.log(fib.next().value);
}
第5行从语义上非常清晰地体现出了非波拉契数列的计算公式:
F(n)=F(n-1)+F(n-2)
然而它是包含在一个while(true)的无限循环内的,所以这段代码是如何工作的呢?
最好的学习办法就是单步调试。
代码第40行到第47行,我们使用了ES6 function*关键字得到了一个"function generator"。在这个generator内部,我们定义了一个无限循环,用于计算非波拉契数列。
第49行,我们用()调用了这个generator,将结果存储在变量fib里。直到此时,function generator的实现体,即代码41~45行还没有得到执行。
实际上,49行的变量lib只是维护了一个指向fib_generator的ITERATOR指针。
这个ITERATOR自带了一个名为next的方法,是ES6的原生实现,大家看上图调试器里的fib.next显示的是native code。Functiongenerator的神奇之处在于,当next方法被调用一次,则generator内部的函数体也只会执行一次。
单步执行,执行一次next方法:
注意调用栈,此时我们已经进入fib_generator函数体内部了:
一旦在FunctionGenerator实现体内部执行到yield关键字,则当前计算结果作为返回值返回给consumer。也就是说,一旦执行遇到yield,则自动从无限循环中退出。
下列简单的循环会打印10个非波拉契数列的元素:
for(var i = 0; i < 10; i++){
var currentResult = fib.next();
console.log(currentResult.value);
}
从上面的代码能看出,yield关键字返回一个json对象给消费者,该对象有个名为name的属性,包含的是具体计算的数值。Json对象的另一个属性名为done,类型为boolean,意思是这个FunctionGenerator的函数体执行是否已经结束。在我的这个例子里,每次next调用的yield返回的Json对象的done属性都为false,因为我的FunctionGenerator内部是一个无限循环。
采用ES6的FunctionGenerator打印出的结果和常规写法一致。
相信您面试的时候,如果能用ES6的FunctionGenerator完成这道题目,一定能让面试官对您刮目相看。
我写的程序员面试系列
Java面试系列-webapp文件夹和WebContent文件夹的区别?
程序员面试系列:Spring MVC能响应HTTP请求的原因?
Java程序员面试系列-什么是Java Marker Interface(标记接口)
JavaScript面试系列:JavaScript设计模式之桥接模式和懒加载
要获取更多Jerry的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码:


使用JavaScript ES6的新特性计算Fibonacci(非波拉契数列)的更多相关文章
- 如何在ABAP里用函数式编程思想打印出非波拉契Fibonacci(数列)
在JavaScript里可以用ES6提供的FunctionGenerator这种黑科技来打印非波拉契数列,具体细节参考我这篇文章. 在ABAP里也有很多种方式实现这个需求. 下面这个report分别用 ...
- 关于斐波拉契数列(Fibonacci)
斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10 ...
- python的生成器(斐波拉契数列(Fibonacci))
代码: 函数版本: #斐波拉契数列(Fibonacci) def fib(max): n=0 a,b=0,1 while n < max: a,b = b,a+b n = n+1 return ...
- 斐波拉契数列(用JavaScript和Python实现)
1.用JavaScript 判断斐波拉契数列第n个数是多少 //需求:封装一个函数,求斐波那契数列的第n项 //斐波拉契数列 var n=parseInt(prompt("输入你想知道的斐波 ...
- 递归算法之Fibonacci 斐波那契数列第n个数的求解
Fibonacci 斐波那契数列第n个数的求解,也可以用递归和非递归的形式实现,具体如下,dart语言实现. int fibonacci(int n) { if (n <= 0) throw S ...
- lintcode:Fibonacci 斐波纳契数列
题目: 斐波纳契数列 查找斐波纳契数列中第 N 个数. 所谓的斐波纳契数列是指: 前2个数是 0 和 1 . 第 i 个数是第 i-1 个数和第i-2 个数的和. 斐波纳契数列的前10个数字是: 0, ...
- 算法导论-求(Fibonacci)斐波那契数列算法对比
目录 1.斐波那契数列(Fibonacci)介绍 2.朴素递归算法(Naive recursive algorithm) 3.朴素递归平方算法(Naive recursive squaring) 4 ...
- 斐波拉契数列(Fibonacci)--用生成器生成数列
斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为"兔子数列&qu ...
- Fibonacci(斐波那契数列)的最佳实践方式(JavaScript)
1)低级版本 var fibonacci = function(n) { if (n == 0 || n == 1) { return n; } else { return fibonacci(n - ...
随机推荐
- 调试 Hadoop 源代码
环境是 64bit Ubuntu 14.04 系统, jdk 1.7 以及 Eclipse Mars (4.5) 这里介绍两种调试 Hadoop 源代码的方法: 利用 Eclipse 远程调试工具和打 ...
- jQuery EasyUI API 中文文档 - Tree树使用介绍
用 $.fn.tree.defaults 重写了 defaults. 依赖 draggable droppable 用法 Tree 能在 <ul> 元素里定义,此标记可以定义为叶节点和子节 ...
- Bootstrap表格分页(一)
最近在学习Bootstrap的分页,有一种方法用“Bootstrap-Paginator”的东西来做. 先预览一下: 为了能够局部刷新页面,我创建了一个PartialView 页面的HTML部分如下: ...
- 洛谷P2824 [HEOI2016/TJOI2016]排序(线段树)
传送门 这题的思路好清奇 因为只有一次查询,我们考虑二分这个值为多少 将原序列转化为一个$01$序列,如果原序列上的值大于$mid$则为$1$否则为$0$ 那么排序就可以用线段树优化,设该区间内$1$ ...
- hyperledger fabric 1.0.5 分布式部署 (三)
本篇博客主要是向读者介绍 fabric 在部署时的一些细节,还有作者自己学习过程中的心得. 初始化相关密钥的程序,实际上是一个shell脚本,并且结构特别简单 generateArtifacts.sh ...
- tpc-ds99 工具使用
安装部署 tpc-ds-99 工具 解压文件 unzip tpc-ds-tool.zip 进入目录 cd v2.3.0/tools 拷贝Makefile文件 cp Makefile.suite Mak ...
- 安装CocoaPods,ios的库安装工具
1.需要ruby环境,mac pro自带了 2.终端输入:sudo gem install cocoapods
- 自动化脚本- 安装更换Python3.5
本脚本所有信息: 1:判断是不是root用户,是则继续不是则退出脚本输出信息2:定义自己的版本3:根据用户输入的版本号,来下载对应的版本包4:使用系统命令wget来下载,注意wet后面有一个空格5:o ...
- JVM加载类的原理机制
在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载.链接和初始化,其中链接又可以分成校验.准备.解析装载:查找和导入类或接口的二进制数据: 链接:执行下面的校验.准备和解析 ...
- SpringBoot | Hibernate @Transient 注解
在默认情况下,持久化类的所有属性会自动映射到数据表的数据列.如果在实际应用中,不想持久保存某些属性,则可以考虑使用@Transient来修饰它们. 如果一个属性并非数据库表的字段映射,就务必将其标示为 ...