使用内联函数进行递归

我曾经以为匿名函数就是匿名函数,事实上,匿名函数就是匿名函数。

在JavaScript中实现递归有很多种方法,常见的有使用函数名调用自身、使用arguments.callee。

现在有这么一个例子,判断一个字符串是不是回文,返回’true’或’false’。

我们把递归函数赋值给一个对象的属性:

1
2
3
4
5
6
7
var JudgeTool = {
isPalindrome : function (text){
if (text.length <= 1) return true;
if (text.charAt(0) != text.charAt(text.length - 1)) return false;
return Judge.isPalindrome(text.subString(1,text.length - 2));
}
}

我们可以用一个回文字符串测试一下:

1
JudgeTool.isPalindrome("htmlmth"); //返回true

功能是实现了,但是,如果另一个对象也想拥有一个同样功能的方法,我们或许可以这样做:

1
2
3
var AnotherTool = {
isPalindrome:JudgeTool.isPalindrome
}

没有问题,我们依然可以用AnotherTool.isPalindrome方法去判断字符串是否是回文,但是,如果我在AnotherTool对象后面加一句:

1
JudgeTool = {};

大家可以想到,肯定会出错,因为在递归函数内部调用的是Judge.isPalindrome(),现在Judge对象被重置,那肯定取不到这个对象的属性了。

那我们改写一下函数内部的递归调用:

1
2
3
4
5
6
7
var JudgeTool = {
isPalindrome : function (text){
if (text.length <= 1) return true;
if (text.charAt(0) != text.charAt(text.length - 1)) return false;
return this.isPalindrome(text.subString(1,text.length - 2));
}
}

我们只改写了一处,把Judge.isPalindrome改成了this.isPalindrome,现在再清空Judge对象,我们还是能够调用AnotherTool.isPalindrome,因为this是指向当前调用此方法的对象。

但问题又来了,我们的方法名必须为:isPalindrome,如果我不想叫这个方法名,又或者函数的其中一个引入不是对象的属性怎么办?这时候就要引入内联函数的概念了。

看下例子,我们可以这样改写Judge对象:

1
2
3
4
5
6
7
var JudgeTool = {
isPalindrome : function same(text){
if (text.length <= 1) return true;
if (text.charAt(0) != text.charAt(text.length - 1)) return false;
return same(text.subString(1,text.length - 2));
}
}

注意,我们只给匿名函数加了一个名字,并且在内部用这个名字去调用它,这样,不管外面的方法名怎么变,都不会影响到内部的函数运行。

这个技巧在很多地方都有用到,如果你有看jQuery源码的话。

而且有趣的是,在函数内部,JudgeTool.isPalindrome == sametrue

尽管我们可以给内联函数进行命名,但这个名称只在函数内部可见,你可以把内联函数的名称想象成函数内的一个变量,它的作用域仅限于函数的内部。

我们看这样一个例子就明白了:

1
2
3
4
5
var foo = function bar(){
typeof bar;//返回function
}
typeof bar;//返回undefined

这个技巧在递归中常常会用到,如果你留意的话。

本文作者:余震(Freak)
本文出处:Rockjins Blog
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN许可协议。转载请注明出处!

坚持,您的支持将鼓励我继续爬下去!