• 汤姆大叔博客笔记【随时更新】


    1、忘记var的副作用(Side Effects When Forgetting var)

    隐式全局变量和明确定义的全局变量间有些小的差异,就是通过delete操作符让变量未定义的能力。

    • 通过var创建的全局变量(任何函数之外的程序中创建)是不能被删除的。
    • 无var创建的隐式全局变量(无视是否在函数中创建)是能被删除的。

    这表明,在技术上,隐式全局变量并不是真正的全局变量,但它们是全局对象的属性。属性是可以通过delete操作符删除的,而变量是不能的:

    // 定义三个全局变量
    var global_var = 1;
    global_novar = 2; // 反面教材
    (function () {
       global_fromfunc = 3; // 反面教材
    }());
    
    // 试图删除
    delete global_var; // false
    delete global_novar; // true
    delete global_fromfunc; // true
    
    // 测试该删除
    typeof global_var; // "number"
    typeof global_novar; // "undefined"
    typeof global_fromfunc; // "undefined"

    2、预解析:var散布的问题(Hoisting: A Problem with Scattered vars)

    // 反例
    myname = "global"; // 全局变量
    function func() {
        alert(myname); // "undefined"
        var myname = "local";
        alert(myname); // "local"
    }
    func();
    //等价于下面这段代码
    myname = "global"; // global variable
    function func() {
       var myname; // 等同于 -> var myname = undefined;
       alert(myname); // "undefined"
       myname = "local";
       alert(myname); // "local"}
    func();

    for-in循环(for-in Loops)

    for-in循环应该用在非数组对象的遍历上,使用for-in进行循环也被称为“枚举”。

    从技术上将,你可以使用for-in循环数组(因为JavaScript中数组也是对象),但这是不推荐的。因为如果数组对象已被自定义的功能增强,就可能发生逻辑错误。另外,在for-in中,属性列表的顺序(序列)是不能保证的。所以最好数组使用正常的for循环,对象使用for-in循环。

    有个很重要的hasOwnProperty()方法,当遍历对象属性的时候可以过滤掉从原型链上下来的属性。

    for (var i in man) {
       if (man.hasOwnProperty(i)) { // 过滤原型属性或方法
          console.log(i, ":", man[i]);
       }
    }
    
    // 反面例子:
    // for-in loop without checking hasOwnProperty()
    for (var i in man) {
       console.log(i, ":", man[i]);
    }

    另外一种使用hasOwnProperty()的形式是取消Object.prototype上的方法。像是:

    for (var i in man) {
       if (Object.prototype.hasOwnProperty.call(man, i)) { // 过滤
          console.log(i, ":", man[i]);
       }
    }

    其好处在于在man对象重新定义hasOwnProperty情况下避免命名冲突。也避免了长属性查找对象的所有方法,你可以使用局部变量“缓存”它。

    var i, hasOwn = Object.prototype.hasOwnProperty;
    for (i in man) {
        if (hasOwn.call(man, i)) { // 过滤
            console.log(i, ":", man[i]);
        }
    }

    严格来说,不使用hasOwnProperty()并不是一个错误。根据任务以及你对代码的自信程度,你可以跳过它以提高些许的循环速度。但是当你对当前对象内容(和其原型链)不确定的时候,添加hasOwnProperty()更加保险些。

    格式化的变化(通不过JSLint)会直接忽略掉花括号,把if语句放到同一行上。其优点在于循环语句读起来就像一个完整的想法(每个元素都有一个自己的属性”X”,使用”X”干点什么):

    // 警告: 通不过JSLint检测
    var i, hasOwn = Object.prototype.hasOwnProperty;
    for (i in man) if (hasOwn.call(man, i)) { // 过滤
        console.log(i, ":", man[i]);
    }

    (不)扩展内置原型((Not) Augmenting Built-in Prototypes)

    扩增构造函数的prototype属性是个很强大的增加功能的方法,但有时候它太强大了。

    增加内置的构造函数原型(如Object(), Array(), 或Function())挺诱人的,但是这严重降低了可维护性,因为它让你的代码变得难以预测。使用你代码的其他开发人员很可能更期望使用内置的 JavaScript方法来持续不断地工作,而不是你另加的方法。

    另外,属性添加到原型中,可能会导致不使用hasOwnProperty属性时在循环中显示出来,这会造成混乱。

    因此,不增加内置原型是最好的。你可以指定一个规则,仅当下面的条件均满足时例外:

    • 可以预期将来的ECMAScript版本或是JavaScript实现将一直将此功能当作内置方法来实现。例如,你可以添加ECMAScript 5中描述的方法,一直到各个浏览器都迎头赶上。这种情况下,你只是提前定义了有用的方法。
    • 如果您检查您的自定义属性或方法已不存在——也许已经在代码的其他地方实现或已经是你支持的浏览器JavaScript引擎部分。
    • 你清楚地文档记录并和团队交流了变化。

    如果这三个条件得到满足,你可以给原型进行自定义的添加,形式如下:

    if (typeof Object.protoype.myMethod !== "function") {
       Object.protoype.myMethod = function () {
          // 实现...
       };
    }

    注释(Writing Comments)

    你必须注释你的代码,即使不会有其他人向你一样接触它。通常,当你深入研究一个问题,你会很清楚的知道这个代码是干嘛用的,但是,当你一周之后再回来看的时候,想必也要耗掉不少脑细胞去搞明白到底怎么工作的。

    很显然,注释不能走极端:每个单独变量或是单独一行。但是,你通常应该记录所有的函数,它们的参数和返回值,或是任何不寻常的技术和方法。要想到注 释可以给你代码未来的阅读者以诸多提示;阅读者需要的是(不要读太多的东西)仅注释和函数属性名来理解你的代码。例如,当你有五六行程序执行特定的任务, 如果你提供了一行代码目的以及为什么在这里的描述的话,阅读者就可以直接跳过这段细节。没有硬性规定注释代码比,代码的某些部分(如正则表达式)可能注释 要比代码多。

    函数表达式和函数声明

    在ECMAScript中,创建函数的最常用的两个方法是函数表达式和函数声明,两者期间的区别是有点晕,因为ECMA规范只明确了一点:函数声明必须带有标示符(Identifier)(就是大家常说的函数名称),而函数表达式则可以省略这个标示符:

      函数声明:

      function 函数名称 (参数:可选){ 函数体 }

      函数表达式:

      function 函数名称(可选)(参数:可选){ 函数体 }

    所以,可以看出,如果不声明函数名称,它肯定是表达式,可如果声明了函数名称的话,如何判断是函数声明还是函数表达式呢?ECMAScript是通过上下文来区分的,如果function foo(){}是作为赋值表达式的一部分的话,那它就是一个函数表达式,如果function foo(){}被包含在一个函数体内,或者位于程序的最顶部的话,那它就是一个函数声明。

    function foo(){} // 声明,因为它是程序的一部分
      var bar = function foo(){}; // 表达式,因为它是赋值表达式的一部分
    
      new function bar(){}; // 表达式,因为它是new表达式
    
      (function(){
        function bar(){} // 声明,因为它是函数体的一部分
      })();

    函数声明只能出现在程序函数体内。从句法上讲,它们 不能出现在Block(块)({ ... })中,例如不能出现在 if、while 或 for 语句中。因为 Block(块) 中只能包含Statement语句, 而不能包含函数声明这样的源元素。另一方面,仔细看一看规则也会发现,唯一可能让表达式出现在Block(块)中情形,就是让它作为表达式语句的一部分。但是,规范明确规定了表达式语句不能以关键字function开头。而这实际上就是说,函数表达式同样也不能出现在Statement语句或Block(块)中(因为Block(块)就是由Statement语句构成的)。 

     
  • 相关阅读:
    C语言之分支语句
    C语言之运算符与表达式
    C语言之数据类型④——中文字符
    独特的对象引用:this
    理解赋值“=”的含义
    编写类的 “模板”
    类的定义
    Java语言规范
    第一周总结
    定义常量
  • 原文地址:https://www.cnblogs.com/huansky/p/5367222.html
Copyright © 2020-2023  润新知