JavaScript语言精粹学习笔记之函数(二)

九、作用域

        作用域控制着变量与参数的可见性及生命周期。对我们来说是一个重要的帮助,因为它减少了名称冲突,并且提供了自身内存管理。

var foo = function () {
    var a = 3, b = 5;
    
    var bar = function () {
        var b = 7, c = 11;

// 此时,a 为 3 , b 为 7 , c 为 11
        a += b + c;

// 此时,a 为 21, b 为 7 , c 为 11
    };
// 此时,a 为 3, b 为5 , c 未定义

    bar();

// 此时,a 为 21, b 为 5 
};

JS中,定义在函数中的参数和变量在函数外部是不可见的,而且在一个函数中的任何位置定义的变量在该函数中的任何地方都可见。

十、闭包

        

// 创建一个名为 quo 的构造函数。
// 它构造出带有 get_status 方法和 status 私有属性的一个对象。

var quo = function (status) {
    return {
         get_status: function () {
            return status;
        }  
    };
};

// 构造一个 quo 实例

var myQuo = quo("amazed");

document.writeln(myQuo.get_status()); 

这个 quo 函数被设计成无须在前面加上 new 来使用,所以它名字也没有首字母大写。当我们调用 quo 时,它返回包含 get_status 方法的一个新对象。该对象的一个引用保存在myQuo中。即使 quo 已经返回了,但 get_status 方法仍然享有访问 quo 对象的 status 属性的特权。get_status 方法并不是访问该参数的一个拷贝,它访问的就是该参数本身。因为该函数可以访问它被创建时所处的上下文环境。这被称为闭包。

十一、回调

        函数可以让不连续事件处理变得更容易。

request = qrepare_the_request();
response = send_request_stnchronously(request);
display(response);

这种方式的问题在于网络上的同步请求将会导致客户端进入假死状态。如果网络传输或服务器很慢,响应性的降低将是不可接受的。

我们有一个更好的方法:发起异步请求,提供一个当服务器的响应达到将被调用的回调函数。异步的函数立即返回,这样客户端就不会被阻塞。

request = qrepare_the_request();
send_request_asynchronously(request, function (response){
    display(response);   
});

我们传递了一个函数作为参数给 send_request_asynchronously 函数,它将在收到响应时被调用。

十二、模块

        模块是一个提供接口却影藏状态与实现的函数或对象。

        我们可以使用函数和闭包来构造模块。

        模块模式利用了函数作用域和闭包来创建绑定对象与私有成员的关联。

        模块模式:一个定义了私有变量和函数的函数,利用闭包创建可以访问私有变量和函数的特权函数,最后返回这个特权函数,或者把它们保存到一个可访问的地方。

模块模式也可以用来产生安全的对象:

var serial_maker = function () {
    // 返回一个用来产生唯一字符串的对象。
    // 唯一字符串由两部分组成: 前缀 + 系列号。
    // 该对象包含一个设置前缀的方法,一个设置序列号的方法。
    // 和一个产生唯一字符串的 gensym 方法

 var prefix = '';
 var seq = 0;
 return {
    set_prefix: function (p) {
         prefix = String(p);
    },
    set_seq: function (s) {
         seq = s;
    },
    gensym: function () {
            var result = prefix + seq;
            seq += 1;
            return result;
        }
    };
};

var seqer = serial_maker();
seqer.set_perfix('Q');
seqer.ser_seq (1000);
var unique = seqer.gensym();  // unique is "Q1000"

seqer 包含的方法都没有用到 this 或 that。 因此没有办法损害 seqer 。除非调用对应的方法,否则没法改变 prefix 或 seq 的值。 seqer 对象是可变的,所以它的方法可能会被替换掉,但替换后的方法依然不能访问私有成员。seqer 就是一组函数的集合,而且那些函数被授予特权,拥有使用或修改私有状态的能力。

如果把 seqer.gensym 作为一个值传递给第三方函数,那个函数能用它产生唯一字符串,但是不能通过它来改变 prefix 或 seq 的值。

十三、级联

        有些方法没有返回值。如果我们让这些方法返回 this 而不是 undefined, 就可以启用级联。

        在一个级联中我们可以在单独一条语句中依次调用同一个对象的很多方法。

        一个启用级联的Ajax 类库可能允许我们以这样的形式去编码:

getElement('myBoxDiv').
    move(350, 150).
    width(100).
    height(100).
    color('red').
    border('10px outset').
    padding('4px').
    appendText("Please stand by").

on('mousedown', function (m) {
    this.startDrag(m, this.getNinth(m));
}).
on('mousemove', 'drag').
on('mouseup', 'stopDrag').
later(2000, function () {
    this.
        color('yellow').
        setHTML("what hath God wraught?").
        slide(400, 40, 200, 200);
}).
tip('This box is resizeable');

这里,getElement 函数产生一个对应于 id="myBoxDiv" 的DOM元素并提供了其他功能的对象。该方法允许我们移动元素,修改它的尺寸和样式,并添加行为。这些方法每一个都返回该对象,所以调用返回的结果可以被下一次调用所用。

级联可以产生出具备很强表现力的接口,它也能帮助控制那种构造试图一次做太多事情的接口的趋势。

十四、套用

        函数也是值,套用 允许我们将函数与传递给它的参数相结合去产生出一个新的函数。

        

var add1 = add.curry(1);
document,writeln(add1(6)); // 7

JS并没有 curry 方法,但我们可以通过给 Function.prototype 添加功能来实现:

Function.method('curry', function () {
    var args = arguments, that = this;
    return function () {
        return that.apply(null, args.concat(arguments));
    };
})

curry 使用Array 的concat 方法去连接两个参数数组。

这样做会有问题,arguments 数组并非一个真正的数组,所以它并没有 concat 方法。

要避开这个问题我们必须在两个 arguments 数组上都应用数组的 slice 方法。这样产生出拥有 concat 方法的常规数组。

Function.method('Curry', function () {
    var slice = Array.prototype.slice,
        args = slice.apply(arguments),
        that = this;
    return function () {
        return that.apply(null, args.concat(slice.apply(arguments)));
    };
});

十五、记忆

          函数可以用对象先记住先前操作的结果,从而能避免无谓的运算,这种优化被称为记忆。

        JS的对象和数组要实现记忆是比较方便的:

var fibonacci = function (n) {
    return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
};

for (var i = 0; i <= 10; i += 1) {
    document.writeln('//' + i + ':' + fibonacci(i));
}

// 0:0
// 1:1
// 2:1
// 3:2
// 4:3
// 5:5
// 6:8
// 7:13
// 8:21
// 9:34
// 10:55

如果我们让该函数具备记忆功能,就可以减少它的运算量。

在一个名为memo的数组里保存我们的存储结果,存储结果可以隐藏才闭包中。当我们的函数被调用时,这个函数首先看是否已经知道存储结果,如果已经知道,就立即返回这个存储结果。

var fibonacci = function () {
    var memo = [0, 1];
    var fib = function (n) {
        var result = memo[n];
        if (typeof result !== 'number') {
            result = fib(n - 1) + fib(n - 2);
            memo[n] = result;
        }
        return result;
    };
    return fib;
}();

这个函数的返回同样的结果

还可以使用 memoizer 来定义 fibonacci 函数,提供其初始的 memo 数组和 fundamental 函数:

var fibonacci = memoizer([0, 1], function (shell, n) {
    return shell(n - 1) + shell(n - 2);
});

还能继续优化:

var fibonacci = memoizer([1, 1], function (shell, n) {
    return n * shell(n - 1);
});

要产生一个可以记忆的阶乘函数,我们只需要提供基本的阶乘公式即可。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: &quot;JavaScript语言精粹&quot;是一本由Douglas Crockford撰写的著名图书,是许多JavaScript开发者学习与掌握该语言不可或缺的重要资源。 这本书主要关注于JavaScript的核心概念和最佳实践,帮助开发者摆脱一些语言的怪异之处和陷阱,使其能够更加高效地编写可维护和可扩展的代码。 &quot;JavaScript语言精粹&quot;一书将JavaScript的精华提炼为19个章节,每一章节都深入浅出地介绍了一个关键概念,包括函数、对象、数组、代码风格、错误处理等。作者以清晰简洁的语言解释了这些概念的背后原理,并给出了许多实用的代码示例。 这本书不仅适合JavaScript初学者,对于有一定经验的开发者来说也是一本不可多得的参考书。通过阅读它,开发者可以拓宽对JavaScript的理解和认识,提高代码质量和效率。 除了对基础概念的详细介绍外,&quot;JavaScript语言精粹&quot;还包含了一些进阶话题,如闭包、原型链、模块化等,帮助开发者进一步提升其JavaScript编程能力。 总之,&quot;JavaScript语言精粹&quot;是一本权威而实用的JavaScript学习资源,对于想要深入理解和掌握该语言的人来说是极为重要的一本书籍。无论你是初学者还是有经验的开发者,这本书都能帮助你写出更优雅、可读性更高的JavaScript代码。 ### 回答2: 《JavaScript语言精粹》是一本由Douglas Crockford撰写的权威指南,它介绍了JavaScript语言中最重要和最有用的部分。该书通过简洁而清晰的语言讲解了JavaScript的核心概念和特性,为开发者提供了深入理解和运用JavaScript的方法和技巧。 这本书以独特的方式展现了JavaScript的精华,将复杂的语法和概念简化成易于理解和运用的形式。Crockford首先介绍了JavaScript中的基本语法和数据类型,然后深入讲解了函数、对象、原型、闭包等重要概念。他通过具体的示例和练习,引导读者掌握JavaScript中的核心概念和编程技巧。 《JavaScript语言精粹》还包含了对常见错误和陷阱的警示,帮助读者避免在编写JavaScript代码时常见的问题。此外,该书还提供了一些最佳实践和编码规范,帮助开发者写出高质量、可维护的JavaScript代码。 与其他JavaScript教程不同,《JavaScript语言精粹》不仅关注如何正确地使用JavaScript,还强调了一些可以帮助开发者避免错误和提高代码质量的技巧和原则。这使得这本书成为了一本适合初学者和有经验的开发者阅读的权威指南。 总之,《JavaScript语言精粹》是一本深入而全面地介绍JavaScript语言的书籍。无论你是初学者还是有经验的开发者,阅读这本书都可以帮助你建立起对JavaScript的深入理解,并提高你的JavaScript编程技巧。 ### 回答3: 《JavaScript语言精粹》是一本由Douglas Crockford所著的程序设计相关书籍,它主要介绍了JavaScript语言的核心概念和重要知识点。这本书在程序设计领域有着很高的声誉,被许多程序员视为JavaScript编程的经典参考书。 该书的目的是帮助读者深入理解JavaScript语言的精华部分,将复杂的语法和特性解释得简单易懂。它详细介绍了JavaScript的基本数据类型、函数、对象、原型链以及闭包等重要概念,并提供了一些实用的编程技巧和最佳实践。读者通过学习这些内容,可以更好地理解JavaScript的设计哲学和编程范式。 《JavaScript语言精粹》的内容不仅限于语法的讲解,还包括了一些关于代码风格、错误处理和性能优化等方面的建议。它强调代码的可读性、可维护性和可扩展性,帮助读者编写出高质量的JavaScript代码。 这本书的另一个亮点是作者Douglas Crockford的独特见解和深入思考。他不仅仅是介绍了JavaScript的特性,还对其设计和演变进行了深入的分析和比较。他提出了一些有关编程规范和标准化的建议,为读者在实际开发中避免一些常见的陷阱和错误提供了宝贵的经验。 总之,《JavaScript语言精粹》是一本经典的JavaScript编程参考书籍,适合有一定编程基础的读者阅读。它能够帮助读者深入理解JavaScript的核心概念和设计原理,提高编程技巧,写出高质量的代码。无论是初学者还是有经验的开发者,都会从这本书中获益匪浅。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值