JavaScript语言精粹——函数(第二部分)

  • 九.参数

  • 十.返回

  • 十一.异常

  • 十二.扩充类型的功能

  • 十三.递归

  • 十四.作用域

  • 十五.闭包

  • 十六.回调

  • 十七.模块

  • 十八.级联

  • 十九.套用

  • 二十.记忆

九.参数:

        当函数被调用的时候,会得到一个 “免费” 奉送的参数,那就是 arguments 数组。通过它函数可以访问所有它被调用时传递给它的参数列表,包括那些没有被分配给函数声明时定义形式参数的多参数。这使得编写一个无需指定参数个数的函数成为可能:

<script>
        //构造一个讲很多个值相加的函数

        //注意函数内部定义的变量 sum 不会与函数外部定义的 sum 产生冲突。
        //该函数只会看到函数内部的那个变量
        var sum = function(){
            var  i,sum = 0;
            for(i =0;i<arguments.length;i +=1){
                sum += arguments[i];
            }
            return sum;
        };
        document.writeln(sum(4,8,15,16,23,42)); //108
</script>

        这不是一个特别有用的模式。在第6章中,我们将会看到如何给数组添加一个相似的方法来达到同样的效果。

        因为语言的一个设计错误,arguments 并不是一个真正的数组。它只是一个“类似数组(array-like)”的对象。arguments拥有一个length 属性,但它缺少所有的数组方法。我们将在本章结尾看到这个设计错误导致的后果。

十.返回

        当一个函数被调用时,它从第一个语句开始执行,并在遇到关闭函数体的)时结束。那使得函数把控制权交还给调用该函数的程序部分。

         return语句可用来使函数提前返回。当return被执行时,函数立即返回而不再执行余下的语句。
        一个函数总是会返回一个值。如果没有指定返回值,则返回undefined .

        如果函数以在前面加上 new前缀的方式来调用,且返回值不是一个对象,则返回this (该新对象)。

十一.异常

        JavaScript 提供了一套异常处理机制。异常是干扰程序正常流程的非正常(但是并非完全是出乎意料)的事故。当查出这样的事故时,你的程序就应该抛出一个异常:

var add = function(a,b){
    if(typeof a !== 'number' || typeof b !=='number'){
        throw{
            name: "TypeError",
            message: "add needs number"
        };
    }
    return a+b;
}

        throw 语句中断函数的执行。它应该抛出一个 exception 对象。该对象包含可识别的异常类型的 name 属性和一个描述性的 message 属性。你也可以添加其他的属性。

        该 exception 对象将被传递到一个 try 语句的 catch 从句:

<script>
    var try_it = function(){
        try{
            add("sevent");
        }catch(e){
            document.writeln(e.name + ": "+ e.message);
        }
    }
    try_it()

//ReferenceError: add is not defined
</script>

        如果在 try 代码块内抛出一个异常,控制权就会跳转到他的 catch 从句。

        一个 try 语句只会有一个将捕捉所有异常的 catch代码块。如果你的处理手段取决于异常的类型,那么异常处理器必须检查异常对象的 name 属性以确定异常的类型。

        注:其实 try catch 语句也可以嵌套使用,还可以和 finally 一起使用,本文就不加以讲解,要想了解的同学可以百度以下,或者私信我。

十二.给类型增加方法

        JavaScript 允许给语言的基本类型增添方法。在上一次对象的博客中,我们可以清晰地看到,通过给Object.prototype 添加方法来使得该方法所有对象可用。这样的方式对所有函数可用:

<script>
        Function.prototype.medthod = function(name,func){
            this.prototype[name] = func;
            return this;
        }
</script>

        通过给 Function.prototype 增加一个 method 方法,我们就不必键入 prototype 这个属性名了。这个缺点也就被掩盖了

        JavaScript 并没有单独的整数类型,因此有时候只提取数值中的整数部分是必要的。JavaScript 本身提供的取整方法有些丑陋,我们可以通过给 Number.prototype 添加一个 integer 方法来改善它。他会根据数字的正负来判断是使用 Math.ceiling 还是 Math.floor。

<script>
        Number.method ('integer' , function (){
            return Math[this< 0 ? 'ceiling' : 'floor' ](this);
        });
        document.writeln ( (-10 / 3) .integer ()) // -3
</script>

         JavaScript缺少一个移除字符串末端空白的方法。那是一个很容易修复的疏忽:

<script>
        string.method ( 'trim', function (){
            return this.replace (/^\S+|\s+$/g, "") ;
        });
        document.writeln ( '"'+" neat ".trim() + '"');
</script>

        我们的 trim方法使用了一个正则表达式。我们将在后面看到更多关于正则表达式的内容。

        通过给基本类型增加方法,我们可以大大提高语言的表现力。因为JavaScript 原型继承的动态本质,新的方法立刻被赋予到所有的值(对象实例)上,哪怕值(对象实例)是在方法被创建之前就创建好了。

         基本类型的原型是公共的结构,所以在类库混用时务必小心。一个保险的做法就是只在确定没有该方法时才添加它。

<script>
//有条件地增加一个方法
Function.prototype.method = function (name,func){
    if( !this.prototype [name] ){
        this.prototype [name] =func;
    }
}
</script>

        另一个要注意的就是for in语句用在原型上时表现很糟糕。我们在讲述对象的时候已经看到了几个减轻这个问题的影响办法:我们可以使用 hasOwnProperty 方法去筛选出继承而来的属性,或者我们可以查找特定的类型。

十三.递归

        递归函数会直接或间接地调用自身的一种函数。递归是一种强大的编程技术,它将一个问题分解为一组相似的子问题,每一个都用一个寻常解去解决。一般来说,一个递归函数调用自身去解决它的子问题。

        “汉诺塔”是一个著名的难题。塔的设备包括三根柱子和一套直径各不相同的空心圆盘。开始时源柱子上的所有圆盘都按照较小的圆盘放在较大的圆盘之上的顺序堆叠。目标是通过每次移动一个圆盘到另一根柱子,最终将一堆圆盘移动到目标柱子上,过程中不可以将大的圆盘放置在较小的圆盘之上。这个难题有一个寻常解:

<script>
    var hanoi = function (disc, src, aux, dst){
        if(disc > 0){
            hanoi (disc - 1,src, dst, aux);
            document.writeln ( 'Move disc ' + disc +
                    ' from ' +src + ' to ' +dst) ;
            hanoi (disc - 1,aux,src, dst);
        }
    }
            hanoi(3, 'Src','Aux' , 'Dst' );
</script>

        圆盘数量为3时它返回这样的解法:

                 Move disc 1 from src to Dst

                 Move disc 2 from src to Aux

                 Move disc 1 from Dst to Aux

                 Move disc 3 from Src to Dst

                 Move disc 1 from Aux to Src

                 Move disc 2 from Aux to Dst

                 Move disc 1 from src to Dst

        hanoi函数把一堆圆盘从--根柱子移到另一根柱子,必要时使用辅助的柱子。它把该问题分解成三个子问题。首先,它移动一对圆盘中较小的圆盘到辅助柱子上,从而露出底下较大的圆盘。然后它就移动底下的圆盘到目标柱子上。最后,它将刚才较小的圆盘从辅助柱子上再移动到目标柱子上。通过递归地调用自身去处理-一对圆盘的移动,从而解决那些子问题。

        传递给hanoi函数的参数包括当前移动的圆盘编号和它将要用到的三根桂子。当它调用自身的时候,它去处理当前正在处理的圆盘之上的圆盘。最终,它会以一个不存在的圆盘编号去调用。在那样的情况下,它不执行任何操作。由于该函数对非法值不予理会,我们也就不必担心它会导致死循环。

        递归函数可以非常高效地操作树形结构,比如浏览器端的文档对象模型(DOM)。每次递归调用时处理给定树的一小段。

十四.作用域

        在编程语言中,作用域控制着变量与参数的可见性及生命周期。对于程序员来说这是一个重要的帮助,因为他减少了名称冲突,并且提供了自动内存管理。

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 
};

        大多数使用C语言语法的语言都拥有块级作用域。在一个代码块中(括在一对花括号中的语句集)定义的所有变量在代码块的外部是不可见的。定义在代码块中的变量在代码块执行结束后会被释放掉。这是件好事。

        糟糕的是,尽管代码块的语法似乎表现出它支持块级作用域,但实际上JavaScript 并不支持。这个混淆之处可能成为错误之源。

        JavaScript确实有函数作用域。那意味着定义在函数中的参数和变量在函数外部是不可见的,而且在一个函数中的任何位置定义的变量在该函数中的任何地方都可见。

        很多现代语言都推荐尽可能迟地声明变量。而用在JavaScript上的话却会成为糟糕的建议,因为它缺少块级作用域。所以,最好的做法是在函数体的顶部声明函数中可能用到的所有变量。

十五.闭包:

         作用域的好处是内部函数可以访问定义他们的外部函数的参数和变量(除了 this 和 arguments)。这是一件非常好的事情。

        我们的 getElementsByAttribute 函数可以工作是因为它声明了一个 results 变量,且传递给 walk_the_DOM 的内部函数也可以访问 results 变量。

        一个更有趣的情形是内部函数拥有比它的外部函数更长的生命周期。

        之前,我们构造了一个myobject对象,它拥有一个value属性和一个increment方法。假定我们希望保护该值不会被非法更改。

        和以对象字面量形式去初始化 my0bject 不同,我们通过调用一个函数的形式去初始化myobject ,该函数将返回一个对象字面量。此函数定义了一个 value 变量。该变量对 increment 和 getvalue 方法总是可用的,但函数的作用域使得它对其他的程序来说是不可见的。

var myObject = function(){
    var value = 0;
    return {
        increment:function(inc){
            value += typeof inc ==="number"? inc:1;
        },
        getValue:function(){
            return value;
        }
    }
}();

        我们并没有把一个函数赋值给 myObject 。我们是把调用该函数后返回的结果赋值给它。注意最后一行的()。该函数返回一个包含两个方法的对象,并且这些方法继续享有访问 value 变量的特权。

        之前构造器函数里面定义的的 Quo 构造器产生出带有 status 属性和 get_status 方法的一个对象。但那看起来并不是十分有趣。为什么要用一个 getter 方法去访问你本可以直接访问到的属性呢?如果 status 是私有属性时,它才是更有意义的。所以,让我们定义另一种形式的 quo 函数来做此事:

<script>
    //创建一个名为 que 的构造函数。
    //他构造出带有 get_status 方法和 status 私有属性的一个对象。

    var quo = function(stuats){
        return {
            get_status:function(){
                return status;
            }
        };
    };
    //构造一个 que 实例

    var myQue = que("amazed");
    document.writeln(myQue.get_status());
</script>

        这个 quo 函数被设计成无须在前面加上 new 来使用,所以名字也没有首字母大写。当我们调用 quo 时,它返回包含 get_status 方法的一个新对象。该对象的一个引用保存在 myQuo 中。即使 quo 已经返回了,但是 get_status 方法仍然享有访问 quo 对象的 status 属性的特权。get_status 方法并不是访问该参数的一个拷贝,他访问的就是该参数的本身。这是可能的,因为该函数可以访问它被创建时所处的上下文环境。这被称为闭包。闭包是一个能减少全局变量污染的很好用的方式,我在上面对对象解释的文章里面做了相关的介绍,感兴趣的同学可以去看一下。

十六.回调

        函数可以让不连续事件的处理变得更容易。例如:假定有这么一个序列,由用户交互开始,向服务器发送请求,最终显示服务器的响应。最纯朴的写法可能会是这样的:

request = prepare_the_request() ;
send_request_synchronously(request,function(response){
    display (response) ;
});

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

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

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

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

17.模块

        我们可以使用函数和闭包来构造模块。模块是一个提供接口却隐藏状态与实现的函数或对象。通过使用函数去产生模块,我们几乎可以完全摒弃全局变量的使用,从而缓解这个JavaScript的最为档糕的特性之一所带来的影响。

        举例来说,假定我们想要给 String 增加一个 deentityify 方法。它的任务是寻找字符串中的HTML字符实体并替换为它们对应的字符。在一个对象中保存字符实体的名字和它们对应的字符是有意义的。但我们该在哪里保存该对象呢?我们可以把它放到一个全局变量中,但全局变量是魔鬼。我们可以把它定义在该函数本身,但是那有运行时的损耗,因为该函数在每次被执行的时候该字面量都会被求值--次。理想的方式是将其放入一个闭包,而且也许还能提供一个增加更多字符实体的扩展方法:

String.method('deentityify',function(){
    // 字符实体表。他映射字符实体的名字到对应的字符
    var entity = {
        quot:'"',
        lt:'<',
        gt:'>'
    };
    //返回deentityify 方法
    return function(){
    // 这才是 deentityify 方法。他调用字符串的 replace 方法。
    // 查找'&'开头和';'结束的之字符串。如果这些字符可以在字符实体表中找到。
    // 那么就将该字符实体替换为映射表中的值,他用到一个正则表达式
        return this.replace(/&([^&;]+);/g,
            function (a,b){
                var r = entity[b];
                return typeof r === 'string' ? r: a;
            }
        );
    };
}());

        注意一下最后一行。我们用() 运算法立即调用我们刚刚构造出来的函数。这个调用所创建并返回的函数才是 deentityify 方法.

document.writeln('<">'.deentityify()); // <">

        模块模式利用了函数作用域和闭包来创建绑定对象与私有成员的关联,在这个例子中,只有deentityify方法有权访问字符实体表这个数据对象。 模块模式的一般形式是:

        一个定义了私有变量和函数的函数; 利用闭包创建可以访问私有变量和函数的特权函数; 最后返回这个特权函数,或者把它们保存到一个可以访问的地方。 使用模块模式就可以摒弃全局变量的使用。它促进了信息隐藏和其他优秀的设计实践。对于应用程序的封装,或者构造其他单例对象,模块模式非常有效。

        模块模式也可以用来产生安全的对象。假定我们想要构造一个用来产生序列号的对象:

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_prefix('Q'); 
seqer.set_seq(1000); 
var unique = seqer.gensym(); // unique is "Q1000"

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

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

18.级联

        有一些方法没有返回值。例如,一些设置或修改对象的某个状态却不返回任何值得方法就是典型的例子。如果我们让这些方法返回this而不是undefined,就可以启用级联。在一个级联中,我们可以再单独一条的语句中一次调用同一个对象的很多方法。一个启用级联的Ajax类库可能允许我们一这样的形式去编码:

getElement('myBoxDiv').
    move(250, 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元素并提供了其他功能的对象。该方法允许我们移动元素,修改它的尺寸和样式,并添加行为。这些方法每一个都返回该对象,所以调用返回的结果可以被下一次调用所用。
级联可以产生出具备很强表现力的接口。它也能帮助控制那种构造试图一次做太多事情的接口的趋势。

19.套用

        函数也是只,从而我们可以用有趣的方式去操作函数值,套用允许我们将函数与传递给它的参数相结合去产生出一个新的函数。

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

        add1是吧1传递给add函数的curry方法后创建的一个函数。addl函数把传递给它的参数的值加1。JavaScript并没有curry方法,但我们可以通过给Function.prototype添加功能来实现:
 

Function.method('curry', function () {
    var args = arguments, that = this;
    return function () {
        return that.apply(null, args.concat(arguments));
    };
}); // 有些不太对头

        curry方法通过创建一个保存着原始函数和被套用的参数的闭包来工作。它返回另一个函数,该函数被调用时,会返回调用原始函数的结果,并传递调用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)));
    };
});
说明:
// concat方法
var a = [1,2,3];
document.write(a.concat(4,5));
// slice方法
var arr = new Array(3);
arr[0] = "George";
arr[1] = "John";
arr[2] = "Thomas";
document.write(arr.slice(1)); // John,Thomas

20.记忆

        函数可以用对象去记住先前操作的结果,从而能避免无谓的运算。这种优化被称为记忆。JavaScript的对象和数组要实现这种优化是非常方便的。

比如说,我们想要一个递归函数来计算Fibonacci数列,一个Fibonacci数字是之前连个Fibonacci数字之和。最前面的两个数字是0和1。

var fibonacci = function (n) {
    return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
};
for (var i = 0; i <= 10; i++) {
    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

这样是可以工作的,但它做了很多无谓的工作。fibonacci函数被调用的453次。我们调用了11次,而它自身调用了442次去计算可能已被刚计算过的值。如果我们让该函数具备记忆功能,就可以显著地减少它的运算量。
我们在一个名为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;
};

这个函数返回同样的结果,但它只被调用了29次。我们调用了它11次。它自身调用了18次去取得之前存储的记过。
我们可以把这种形式一般化,编写一个函数来帮助我们构造带记忆功能的函数。memoizer函数将取得一个初始化的memo数组和fundamental函数。它返回一个管理memo存储和在需要时调用的fundamental函数的shell函数。我们传递这个shell函数和该函数的参数给fundamental函数:

var memoizer = function (memo, fundamental) {
    var shell = function (n) {
        var result = memo[n];
        if (typeof result !== 'number') {
            result = fundamental(shell, n);
            memo[n] = result;
        }
        return result;
    };
    return shell;
};

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

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

        通过设计能产生出其他函数的函数。可以极大减少我们必须要做的工作。例如:要产生一个可记忆阶乘函数,我们只需提供基本的阶乘公式即可:

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

        注:上述讲述的就是JavaScript语言精粹一书的函数的第二部分,感兴趣的同学可以点击下方链接访问第一部分的内容 https://blog.csdn.net/qq_51227484/article/details/118768098

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: "JavaScript语言精粹"是一本由Douglas Crockford撰写的著名图书,是许多JavaScript开发者学习与掌握该语言不可或缺的重要资源。 这本书主要关注于JavaScript的核心概念和最佳实践,帮助开发者摆脱一些语言的怪异之处和陷阱,使其能够更加高效地编写可维护和可扩展的代码。 "JavaScript语言精粹"一书将JavaScript的精华提炼为19个章节,每一章节都深入浅出地介绍了一个关键概念,包括函数、对象、数组、代码风格、错误处理等。作者以清晰简洁的语言解释了这些概念的背后原理,并给出了许多实用的代码示例。 这本书不仅适合JavaScript初学者,对于有一定经验的开发者来说也是一本不可多得的参考书。通过阅读它,开发者可以拓宽对JavaScript的理解和认识,提高代码质量和效率。 除了对基础概念的详细介绍外,"JavaScript语言精粹"还包含了一些进阶话题,如闭包、原型链、模块化等,帮助开发者进一步提升其JavaScript编程能力。 总之,"JavaScript语言精粹"是一本权威而实用的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、付费专栏及课程。

余额充值