zoukankan      html  css  js  c++  java
  • JavaScript 标准参考教程-阅读总结(一)

    参考:http://javascript.ruanyifeng.com/

    1、字符串

    1)由于 HTML 语言的属性值使用双引号,所以很多项目约定 JavaScript 语言的字符串只使用单引号,本教程遵守这个约定。当然,只使用双引号也完全可以。重要的是坚持使用一种风格,不要一会使用单引号表示字符串,一会又使用双引号表示。

    2)反斜杠()在字符串内有特殊含义,用来表示一些特殊字符,所以又称为转义符。

    如果字符串的正常内容之中,需要包含反斜杠,则反斜杠前面需要再加一个反斜杠,用来对自身转义。【"Prev \ Next"=》"Prev Next"

    3)字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)。但是,字符串与数组的相似性仅此而已。实际上,无法改变字符串之中的单个字符

    var str = 'hello';
    console.log(str[0],str[5]); // h undefined
    str[5] = '!';
    console.log(str); // hello

    4)length属性返回字符串的长度,该属性也是无法改变的。

    var str = 'hello';
    console.log(str.length); // 5
    str.length = 3;
    console.log(str.length); // 5

    2、对象

    var obj = { p:1, q:2 };
    var props = [];
    for(var p in obj) {
        props.push(p);
    }
    console.log(props); // ['p','q']
    console.log(Object.keys(obj)); // ['p','q']

    3、数组

    1)数组的length属性,返回数组的成员数量。length属性是可写的。如果人为设置一个小于当前成员个数的值,该数组的成员会自动减少到length设置的值。

    var arr = [ 'a', 'b', 'c' ];
    arr.length // 3
    arr.length = 2;
    arr // ["a", "b"]

    清空数组的一个有效方法,就是将length属性设为0。

    var arr = [ 'a', 'b', 'c' ];
    arr.length = 0; // 等价于arr = []
    arr // []

     2)数组的遍历可以考虑使用for循环或while循环;数组的forEach方法,也可以用来遍历数组。

    var colors = ['red', 'green', 'blue'];
    colors.forEach(function (color) {
      console.log(color);
    });
    // red
    // green
    // blue

    4、函数

    1)函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值。这意味着,在函数体内修改参数值,不会影响到函数外部。

    var p = 2;
    function f(p) {
      p = 3;
    }
    f(p);
    p // 2

    如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址。也就是说,传入函数的原始值的地址,因此在函数内部修改参数,将会影响到原始值。

    var obj = { p: 1 };
    function f(o) {
      o.p = 2;
    }
    f(obj);
    obj.p // 2

    注意,如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值。

    var obj = [1, 2, 3];
    function f(o) {
      o = [2, 3, 4];
    }
    f(obj);
    obj // [1, 2, 3]
    /*在函数f内部,参数对象obj被整个替换成另一个值。这时不会影响到原始值。这是因为,形式参数(o)的值实际是参数obj的地址,重新对o赋值导致o指向另一个地址,
    保存在原地址上的值当然不受影响。*/

    2)arguments 对象

    由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。这就是arguments对象的由来。arguments对象包含了函数运行时的所有参数arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。

    function f(a) {
      console.log(arguments)
    }
    f(1,2,3) // [1, 2, 3]

    通过arguments对象的length属性,可以判断函数调用时到底带几个参数。

    3)闭包

    由于在 JavaScript 语言中,只有函数内部的子函数才能读取内部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。

    闭包的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在。注意,外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。

    4)立即调用的函数表达式

    有时,我们需要在定义函数之后,立即调用该函数。这时,你不能在函数的定义之后加上圆括号,这会产生语法错误。为了避免解析上的歧义,JavaScript 引擎规定,如果function关键字出现在行首,一律解释成语句。因此,JavaScript引擎看到行首是function关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。解决方法就是不要让function出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面

    (function(){ /* code */ }());
    // 或者
    (function(){ /* code */ })();

    两种写法都是以圆括号开头,引擎就会认为后面跟的是一个表示式,而不是函数定义语句,所以就避免了错误。这就叫做“立即调用的函数表达式”(Immediately-Invoked Function Expression),简称 IIFE。注意,上面两种写法最后的分号都是必须的。如果省略分号,遇到连着两个 IIFE,就会报错。

    通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。它的目的有两个:一是不必为函数命名,避免了污染全局变量;二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。

    // 写法一
    var tmp = newData;
    processData(tmp);
    storeData(tmp);
    // 写法二
    (function () {
      var tmp = newData;
      processData(tmp);
      storeData(tmp);
    }());
    // 写法二比写法一更好,因为完全避免了污染全局变量

     5、运算符

    1)任何值(包括NaN本身)与NaN比较,返回的都是false

    NaN == NaN // false

    2)(严格)相等运算符

    两个复合类型(对象、数组、函数)的数据比较时,不是比较它们的值是否相等,而是比较它们是否指向同一个地址。

    {} === {} // false
    [] === [] // false
    (function () {} === function () {}) // false

    如果两个变量引用同一个对象,则它们相等。

    var v1 = {};
    var v2 = v1;
    v1 === v2 // true

    3)布尔运算符

    3.1)取反运算符(!)

    如果对一个值连续做两次取反运算,等于将其转为对应的布尔值,与Boolean函数的作用相同。这是一种常用的类型转换的写法。

    !!x // 等同于Boolean(x)

    3.2)且运算符(&&)

    't' && '' // ""
    't' && 'f' // "f"
    't' && (1 + 2) // 3
    '' && 'f' // ""
    
    var x = 1;
    (1 - 1) && ( x += 1) // 0
    x // 1

    上面代码的最后一个例子,由于且运算符的第一个运算子的布尔值为false,则直接返回它的值0,而不再对第二个运算子求值,所以变量x的值没变。

    这种跳过第二个运算子的机制,被称为“短路”。有些程序员喜欢用它取代if结构

    if (i) { doSomething(); } // 等价于i && doSomething();

    上面代码的两种写法是等价的,但是后一种不容易看出目的,也不容易出错,建议谨慎使用

    3.3)或运算符(||)

    't' || '' // "t"
    't' || 'f' // "t"
    '' || 'f' // "f"
    '' || '' // ""
    var x = 1;
    true || (x = 2) // true
    x // 1

    短路规则对这个运算符也适用。上面代码中,且运算符的第一个运算子为true,所以直接返回true,不再运行第二个运算子。所以,x的值没有改变。这种只通过第一个表达式的值,控制是否运行第二个表达式的机制,就称为“短路”

    或运算符常用于为一个变量设置默认值

    function saveText(text) {
      text = text || '';
    } // 如果函数调用时,没有提供参数,则该参数默认设置为空字符串

    3.4)圆括号的作用

    圆括号(())可以用来提高运算的优先级,因为它的优先级是最高的。

    4 + 5 * 6 // 34
    (4 + 5) * 6 // 54
    // 由于使用了圆括号,加法会先于乘法执行

    运算符的优先级别十分繁杂,且都是硬性规定,因此建议总是使用圆括号,保证运算顺序清晰可读,这对代码的维护和除错至关重要

    6、数据类型转换

    1)强制转换

    1.1)Number函数将字符串转为数值,要比parseInt函数严格很多。基本上,只要有一个字符无法转成数值,整个字符串就会被转为NaN

    parseInt('42 cats') // 42
    Number('42 cats') // NaN

    1.2)String函数可以将任意类型的值转化成字符串

    String(123) // "123"
    String('abc') // "abc"
    String(true) // "true"
    String(undefined) // "undefined"
    String(null) // "null"

    String方法的参数如果是对象,返回一个类型字符串;如果是数组,返回该数组的字符串形式。

    String({a: 1}) // "[object Object]"
    String([1, 2, 3]) // "1,2,3"

    1.3)Boolean函数可以将任意类型的值转为布尔值。

    所有对象的布尔值都是true,这是因为 JavaScript 语言设计的时候,出于性能的考虑,如果对象需要计算才能得到布尔值,对于obj1 && obj2这样的场景,可能会需要较多的计算。为了保证性能,就统一规定,对象的布尔值为true

    Boolean({}) // true
    Boolean([]) // true

    2)自动转换

    由于自动转换具有不确定性,而且不易除错,建议在预期为布尔值、数值、字符串的地方,全部使用BooleanNumberString函数进行显式转换

    7、错误处理机制

    一旦发生错误,程序就中止执行了。JavaScript 提供了try...catch结构,允许对错误进行处理,选择是否往下执行。如果你不确定某些代码是否会报错,就可以把它们放在try...catch代码块之中,便于进一步对错误进行处理catch代码块捕获错误之后,程序不会中断,会按照正常流程继续执行下去

    // a //Uncaught ReferenceError: a is not defined
    // 上一行报错,程序中止执行了
    try {
        a
    } catch(e) {
        console.log(e); // ReferenceError: a is not defined
    }
    console.log('try catch'); // try catch

    8、编程风格

    1)全局变量

    JavaScript 最大的语法缺点,可能就是全局变量对于任何一个代码块,都是可读可写。这对代码的模块化和重复使用,非常不利。

    因此,建议避免使用全局变量。如果不得不使用,可以考虑用大写字母表示变量名,这样更容易看出这是全局变量,比如UPPER_CASE

    2)变量声明

    JavaScript 会自动将变量声明”提升“到代码块的头部。

    if (!x) {
      var x = {};
    }
    // 等同于
    var x;
    if (!x) {
      x = {};
    }

    这意味着,变量xif代码块之前就存在了。为了避免可能出现的问题,最好把变量声明都放在代码块的头部

    for (var i = 0; i < 10; i++) {
      // ...
    }
    // 写成如下,容易看出存在一个全局的循环变量i
    var i;
    for (i = 0; i < 10; i++) {
      // ...
    }

    另外,所有函数都应该在使用之前定义。函数内部的变量声明,都应该放在函数的头部

    9、包装对象

    原始类型的值,可以自动当作对象调用,即调用各种对象的方法和参数。这时,JavaScript 引擎会自动将原始类型的值转为包装对象实例,在使用后立刻销毁实例。比如,字符串可以调用length属性,返回字符串的长度

    'abc'.length // 3
    /* abc是一个字符串,本身不是对象,不能调用length属性。JavaScript 引擎自动将其转为包装对象,在这个对象上调用length属性。
    调用结束后,这个临时对象就会被销毁。这就叫原始类型与实例对象的自动转换。*/

    自动转换生成的包装对象是只读的,无法修改。所以,字符串无法添加新属性。

    var s = 'Hello World';
    s.x = 123;
    s.x // undefined
    /* 调用结束后,包装对象实例会自动销毁。这意味着,下一次调用字符串的属性时,实际是调用一个新生成的对象,
    而不是上一次调用时生成的那个对象,所以取不到赋值在上一个对象的属性。
    */

    10、JSON对象

    JSON对象是 JavaScript 的原生对象,用来处理 JSON 格式数据。它有两个静态方法:JSON.stringify()JSON.parse()

    JSON.stringify方法用于将一个值转为 JSON 字符串。该字符串符合 JSON 格式,并且可以被JSON.parse方法还原。如果对象的属性是undefined、函数或 XML 对象,该属性会被JSON.stringify过滤如果数组的成员是undefined、函数或 XML 对象,则这些值被转成null

    var obj = {
      a: undefined, b: function () {}
    };
    JSON.stringify(obj) // "{}"
    
    var arr = [undefined, function () {}];
    JSON.stringify(arr) // "[null,null]"

    JSON.parse方法用于将 JSON 字符串转换成对应的值。如果传入的字符串不是有效的 JSON 格式,JSON.parse方法将报错

  • 相关阅读:
    ECharts 3 -- gauge表盘的配置项
    8 -- 深入使用Spring -- 1...4 属性占位符配置器
    8 -- 深入使用Spring -- 1...两种后处理器
    window.location.href
    8 -- 深入使用Spring -- 1...3 容器后处理器
    8 -- 深入使用Spring -- 1...2 Bean后处理器的用处
    8 -- 深入使用Spring -- 1...1Bean后处理器
    8 -- 深入使用Spring -- 0...
    Java NIO原理 图文分析及代码实现
    Java NIO系列教程(十二) Java NIO与IO
  • 原文地址:https://www.cnblogs.com/colorful-coco/p/8868445.html
Copyright © 2011-2022 走看看