zoukankan      html  css  js  c++  java
  • (转 Uncle Tom )深入理解javascript(1)学习笔记

    1、最小全局变量(Minimizing Globals)                                     

    Javascript 通过函数管理作用域,在函数内部声明的变量只能在内部使用,函数外面不可用。

    所谓“全局变量”:

          1、任何在函数外面声明的变量

          2、未声明直接简单使用的(隐式全局变量)

    所谓“全局对象”window

    每个javascript环境有一个全局对象,当你在任意的函数外面使用this时可以访问到。

    你创建的每一个全局变量都成为这个全局对象的属性。

    在浏览器中,该全局对象有个附加属性叫:window。通常window指向该全局对象本身。

    下面的代码片段显示如何在浏览器环境中创建和访问的全局变量:

    myglobal="hello"
    
    console.log(myglobal); //不推荐写法
    
    console.log(window.myglobal);
    console.log(window["myglobal"]);
    console.log(this.myglobal);

     

    2、全局变量的问题                                                                             

    第三方js库,广告方脚本代码,不同类型组件等,均会定义全局变量,有可能造成命名冲突

    3、应尽量避免使用全局变量                                                                    

    function sum(x, y) {   // 不推荐写法: 隐式全局变量 
       result = x + y;
       return result;
    }

    1) 经验法则是始终使用var声明变量,正如改进版的sum()函数所演示的:

    function sum(x, y) {
    var result = x + y;
    return result;
    }

     但是b确实全局变量,这可能不是你希望发生的:

    // 反例,勿使用 
    function foo() {
    var a = b = 0;  // 不推荐写法: b为隐式全局变量

       var c = (d = 0);// 不推荐写法: d为隐式全局变量
      
    }

    正确写法:

    function foo() {
    var a, b;
    // ... a = b = 0; // 两个均局部变量
    }

    4、忘记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"

    在ES5严格模式下,未声明的变量(如在前面的代码片段中的两个反面教材)工作时会抛出一个错误。

    5、访问全局对象(Access to the Global object  )

    1、全局对象使用window属性访问

    2、自己写代码创建全局对象,作用是写自己的js库时,通过此种方法获取全局对象

     

        var global=(function(){
            return this;
         }());

     

    单var形式(Single var Pattern)                 

    在函数顶部使用单var语句是比较有用的一种形式,其好处在于:

    1、提供一个单一的地方寻找所有局部变量

    2、防止变量在定义之前使用的逻辑错误(先声明,后使用)

    3、帮助你记住全局变量

    单var形式长得就像下面这个样子:

    function func() {
    var a = 1,
    b = 2,
    sum = a + b,
    myobject = {},
    i,
    j;
    // function body...
    }
    function updateElement() {
    var el = document.getElementById("result"),
    style = el.style;
    // 使用el和style干点其他什么事...
    }

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

    预解析(hosting): javascript中,你可以在函数的任何位置声明多个var语句,并且它们就好像在函数顶部声明一样发挥作用。这种行为叫预解析。当你使用了一个变量,之后在函数中又重新声明,就可以产生逻辑错误。只要你的变量在同一作用域(函数)内,它都被当成声明的。即使是它在var声明前使用。

    // 反例
    myname = "global"; // 全局变量
    function func() {
    alert(myname); // "undefined"
    var myname = "local";
    alert(myname); // "local"
    }
    func();

    为什么第一次alert myname值为:undefined?
    由于预解析(func函数中有变量myname,因此myname变量声明当被悬置到函数的顶部),myname被当成函数局部变量.

    上面的代码片段执行的行为可能就像下面这样:

    myname = "global"; // global variable
    function func() {
    var myname; // 等同于 -> var myname = undefined;
    alert(myname); // "undefined"
    myname = "local";
    alert(myname); // "local"}
    func();


    结论:由于javascript默认预解析函数内所有变量,并将其声明悬挂在函数顶端,
       因此建议函数内最好预先声明好所有要使用的变量 


    for循环(for Loops)


    //
    次佳的循环
    for (var i = 0; i < myarray.length; i++) {
    // 使用myarray[i]做点什么
    }
    如果myarrary.length值每次通过计算获取,则建议使用var max存储使用
    特别当myarrary 为htmlCollection时,这种建议就更有必要了

    记住Dom操作是比较昂贵的

    修改后:
    function looper() {
    var i = 0,
    max,
    myarray = [];
    // ...
    for (i = 0, max = myarray.length; i < max; i++) {
    // 使用myarray[i]做点什么
    }
    }
    
    

    for-in循环(for-in Loops)

    
    

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

    所以最好数组使用正常的for循环,对象使用for-in循环。

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

    思考下面一段代码:

    // 对象
    var man = {
    hands: 2,
    legs: 2,
    heads: 1
    };

    // 在代码的某个地方
    //
    一个方法添加给了所有对象
    if (typeof Object.prototype.clone === "undefined") {
    Object.prototype.clone = function () {};
    }

     

    在这个例子中,我们有一个使用对象字面量定义的名叫man的对象。在man定义完成后的某个地方,在对象原型上增加了一个很有用的名叫 clone()的方法。此原型链是实时的,这就意味着所有的对象自动可以访问新的方法。为了避免枚举man的时候出现clone()方法,你需要应用hasOwnProperty()方法过滤原型属性。如果不做过滤,会导致clone()函数显示出来,在大多数情况下这是不希望出现的。

    // 1.
    //
    for-in 循环
    for (var i in man) {
    if (man.hasOwnProperty(i)) { // 过滤
    console.log(i, ":", man[i]);
    }
    }
    /* 控制台显示结果
    hands : 2
    legs : 2
    heads : 1
    */
    // 2.
    //
    反面例子:
    //
    for-in loop without checking hasOwnProperty()
    for (var i in man) {
    console.log(i, ":", man[i]);
    }
    /*
    控制台显示结果
    hands : 2
    legs : 2
    heads : 1
    clone: function()
    */

     

    另外一种使用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)

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

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

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

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

    避免隐式类型转换(Avoiding Implied Typecasting )

    JavaScript的变量在比较的时候会隐式类型转换。这就是为什么一些诸如:false == 0 或 “” == 0 返回的结果是true。为避免引起混乱的隐含类型转换,在你比较值和表达式类型的时候始终使用===和!==操作符。

    var zero = 0;
    if (zero === false) {
    // 不执行,因为zero为0, 而不是false
    }

    // 反面示例
    if (zero == false) {
    // 执行了...
    }
  • 相关阅读:
    Python文件的两种用途
    模块的搜索路径
    循环导入问题
    import和from...import
    模块的四种形式
    函数小结
    面向过程编程
    内置函数
    匿名函数
    递归
  • 原文地址:https://www.cnblogs.com/lindaWei/p/2440426.html
Copyright © 2011-2022 走看看