《Head First HTML5 javascript》第9章 认识对象

2022.11.21 第9章 认识对象

对象

对象是一个包含相关数据和方法的集合(通常由一些变量和函数组成,我们称之为对象里面的属性和方法)对象是存储在单个分组中的相关功能的集合。在 JavaScript 中,大多数事物都是对象,从作为核心功能的字符串和数组,到建立在 JavaScript 之上的浏览器 API

  1. 构造函数

    Object 构造函数将给定的值包装为一个新对象。

    • 如果给定的值是 [null] 或 [undefined], 它会创建并返回一个空对象。
    • 否则,它将返回一个和给定的值相对应的类型的对象。
    • 如果给定值是一个已经存在的对象,则会返回这个已经存在的值(相同地址)。

    在非构造函数上下文中调用时, Object 和 new Object()表现一致。

    new Object()
    new Object(value)
    

    创建一个新对象

    let o = new Object()
    o.foo = 42
    
    console.log(o)
    // Object { foo: 42 }
    

    使用 Object 创建 undefined 和 null 类型

    下面的例子保存了一个空 Object 对象在 o:

    let o = new Object()
    
    let o = new Object(undefined)
    
    let o = new Object(null)
    
  2. this

    function Blog(body, date){
    				this.body = body;
    				this.date = date;
    			}
    
  3. new运算符调用

    var blog = [new Blog("Got the new cube I ordered. It's a real pearl.", new Date("08/14/2008")),
    						new Blog("second line.", new Date("08/19/2008")),
    						new Blog("third line.", new Date("08/16/2008")),
    						new Blog("the fourth line.", new Date("08/21/2008"))];
    
  4. 对象字面量(object literal)对象里的对象

    function Blog(body, date){
    				this.toString = function(){
    					return "[" + this.date.getFullYear()  + "/" + (this.date.getMonth() + 1) + "/" + this.date.getDate() + "]" + this.body;
    				};
    			}
    

Date对象

Date对象基于 Unix Time Stamp,即自 1970 年 1 月 1 日(UTC)起经过的毫秒数。

  1. 创建一个新Date对象的唯一方法是通过[new](<https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new>)操作符,例如:let now = new Date();  若将它作为常规函数调用(即不加 [new](<https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new>)操作符),将返回一个字符串,而非 Date对象。

    new Date();
    new Date(value);
    new Date(dateString);
    new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]]);
    
  2. 设定日期数据的方法

    1. setMonth()根据本地时间为一个日期对象设置月份。

      dateObj.setMonth(monthValue[, dayValue])
      

      monthValue

      介于 0 到 11 之间的整数(表示一月到十二月)。

      dayValue

      从 1 到 31 之间的整数,表示月份中的第几天。0 为上个月最后一天

      返回值

      基于 1 January 1970 00:00:00 UTC 开始计算的毫秒数

      var theBigDay = new Date();
      theBigDay.setMonth(6);
      
    2. setFullYea()根据本地时间为一个日期对象设置年份。

      dateObj.setFullYear(yearValue[, monthValue[, dayValue]])
      

      yearValue

      指定年份的整数值,例如 1995。

      monthValue

      一个 0 到 11 之间的整数值,表示从一月到十二月。

      dayValue

      一个 1 到 31 之间的整数值,表示月份中的第几天。如果你指定了 dayValue 参数,就必须同时指定 monthValue

      var theBigDay = new Date();
      theBigDay.setFullYear(1997);
      
  3. 取得日期数据的方法

    1. getDate()根据本地时间,返回一个指定的日期对象为一个月中的哪一日(从 1--31)

      var Xmas95 = new Date("December 25, 1995 23:15:00");
      var day = Xmas95.getDate();
      
      alert(day); // 25
      
    2. getDay()方法根据本地时间,返回一个具体日期中一周的第几天,0 代表星期日,1 代表星期一,2 代表星期二,依次类推。

      var Xmas95 = new Date("December 25, 1995 23:15:30");
      var weekday = Xmas95.getDay();
      
      console.log(weekday); // 1
      

      备注: 如果需要,可以使用[Intl.DateTimeFormat](<https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat>)与一个额外的options 参数,从而返回这天的全称(如"Monday").使用此方法,结果会更加国际化:

      var options = { weekday: 'long'};
      console.log(new Intl.DateTimeFormat('en-US', options).format(Xmas95));
      // Monday
      console.log(new Intl.DateTimeFormat('de-DE', options).format(Xmas95));
      // Montag
      
    3. getFullYear()根据本地时间返回指定日期的年份。

      getFullYear()返回的值是绝对数。对于 1000 到 9999 之间的日期

      getFullYear()返回一个四位数字,如 1995。使用此函数确保在 2000 年后兼容。

      var today = new Date();
      var year = today.getFullYear();
      

字符串对象

  1. 子字符串substring

    返回一个字符串在开始索引到结束索引之间的一个子集,或从开始索引直到字符串的末尾的一个子集。

    str.substring(indexStart[, indexEnd])
    

    indexStart需要截取的第一个字符的索引,该索引位置的字符作为返回的字符串的首字母。indexEnd可选。一个 0 到字符串长度之间的整数,以该数字为索引的字符不包含在截取的字符串内。

    返回值

    包含给定字符串的指定部分的新字符串。

    substring 提取从 indexStart 到 indexEnd(不包括)之间的字符。特别地:

    • 如果 indexStart 等于 indexEndsubstring 返回一个空字符串。
    • 如果省略 indexEndsubstring 提取字符一直到字符串末尾。
    • 如果任一参数小于 0 或为 NaN ,则被当作 0。
    • 如果任一参数大于 stringName.length,则被当作 stringName.length
    • 如果 indexStart 大于 indexEnd,则 substring 的执行效果就像两个参数调换了一样。见下面的例子。
    var anyString = "Mozilla";
    
    // 输出 "Moz"
    console.log(anyString.substring(0,3));
    console.log(anyString.substring(3,0));
    console.log(anyString.substring(3,-3));
    console.log(anyString.substring(3,NaN));
    console.log(anyString.substring(-2,3));
    console.log(anyString.substring(NaN,3));
    
    // 输出 "lla"
    console.log(anyString.substring(4,7));
    console.log(anyString.substring(7,4));
    
    // 输出 ""
    console.log(anyString.substring(4,4));
    
    // 输出 "Mozill"
    console.log(anyString.substring(0,6));
    
    // 输出 "Mozilla"
    console.log(anyString.substring(0,7));
    console.log(anyString.substring(0,10));
    

    运用 length 属性来使用 substring()

    下面一个例子运用了 String.length 属性去获取指定字符串的倒数元素。显然这个办法更容易记住,因为你不再像上面那个例子那样去记住起始位置和最终位置。

    // Displays 'illa' the last 4 characters
    var anyString = 'Mozilla';
    var anyString4 = anyString.substring(anyString.length - 4);
    console.log(anyString4);
    
    // Displays 'zilla' the last 5 characters
    var anyString = 'Mozilla';
    var anyString5 = anyString.substring(anyString.length - 5);
    console.log(anyString5);
    
  2. 转换字符串

    toString返回一个表示该对象的字符串。该方法旨在重写(自定义)派生类对象的类型转换的逻辑。默认情况下,toString()不接受任何参数。然而,继承自 Object的对象可能用它们自己的实现重写它,这些实现可以接受参数。

    返回值

    一个表示该对象的字符串。

    const arr = [1, 2, 3];
    
    arr.toString(); // "1,2,3"
    Object.prototype.toString.call(arr); // "[object Array]"
    
  3. String length

    字符串的 **length**只读属性包含字符串的长度(以 UTF-16 代码单元表示)。

    该属性返回字符串中的代码单元数量。JavaScript 使用 UTF-16 编码,其中每个 Unicode 字符可以编码为一个或两个代码单元,因此 length 返回的值可能与字符串中 Unicode 字符的实际数量不匹配。对于拉丁文、西里尔文、众所周知的 CJK 字符等常见脚本,这应该不是问题,但如果你正在使用某些脚本,例如表情符号、数学符号或晦涩的汉字,你可能需要考虑代码单元和字符之间的差异。

    语言规范要求字符串的最大长度为 253 - 1 个元素,这是精确整数的上限。但是,具有此长度的字符串需要 16384TB 的存储空间,这在任何合理的设备内存中都容纳不了,因此实现倾向于降低阈值,从而允许字符串的长度方便地存储在 32 位整数中。

    对于空字符串,length 为 0。

    静态属性 String.length 与字符串的长度无关。它是 String 函数的参数数量(简单地说,就是它有多少个形参),也就是 1。

    由于 length 统计的是代码单元而不是字符,如果你想得到字符的数量,你可以首先用它的迭代器分割字符串,它按字符进行迭代:

    function getCharacterLength(str) {
      // The string iterator that is used here iterates over characters,
      // not mere code units
      return [...str].length;
    }
    
    console.log(getCharacterLength("A\\uD87E\\uDC04Z")); // 3
    

    基本用法

    const x = "Mozilla";
    const empty = "";
    
    console.log(`${x} is ${x.length} code units long`);
    // Mozilla is 7 code units long
    
    console.log(`The empty string has a length of ${empty.length}`);
    // The empty string has a length of 0
    

    长度不等于字符数的字符串

    const emoji = "😄";
    console.log(emoji.length); // 2
    const adlam = "𞤲𞥋𞤣𞤫";
    console.log(adlam.length); // 8
    const formula = "∀𝑥∈ℝ,𝑥²≥0";
    console.log(formula.length); // 11
    

    指定长度

    因为字符串是一个基本类型,所以尝试为字符串的 length 属性赋值没有可观察到的效果,并且在严格模式下会抛出。

    const myString = "bluebells";
    
    myString.length = 4;
    console.log(myString); // "bluebells"
    console.log(myString.length); // 9
    
  4. indexOf()给定一个参数:要搜索的子字符串,搜索整个调用字符串,并返回指定子字符串第一次出现的索引。给定第二个参数:一个数字,该方法将返回指定子字符串在大于或等于指定数字的索引处的第一次出现。

    indexOf(searchString)
    indexOf(searchString, position)
    

    searchValue

    要搜索的子字符串,强制转换为字符串。 如果不带参数调用方法,searchString 将被强制转换为 "undefined"。因此,"undefined". indexof() 返回 0——因为子字符串 "undefined" 在字符串 "undefined" 中的 0 位置找到。但是 "undefine".indexof() 返回 -1——因为子字符串 "undefine" 在字符串 "undefined" 中找不到。

    position 可选

    该方法返回指定子字符串在大于或等于 position 位置的第一次出现的索引,默认为 0。如果 position 大于调用字符串的长度,则该方法根本不搜索调用字符串。如果 position 小于零,该方法的行为就像 position 为 0 时一样。

    hello world hello'.indexOf('o', -5) 返回 4——因为它使该方法的行为类似于第二个参数为 0,并且 o 在大于或等于 0 位置的第一次出现是在 4 位置。 • 'hello world hello'.indexOf('world', 12) 返回 -1——因为,虽然子字符串 world 确实出现在索引 6 处,但该位置不大于或等于 12。 • 'hello world hello'.indexOf('o', 99) 返回 -1——因为 99 大于 hello world hello 的长度,这会导致方法根本不搜索字符串。

    返回值

    查找的字符串 searchValue 的第一次出现的索引,如果没有找到,则返回 -1

    当使用空字符串搜索时的返回值

    搜索空字符串会产生奇怪的结果。如果没有第二个实参,或者有第二个实参的值小于调用字符串的长度,返回值与第二个实参的值相同:

    'hello world'.indexOf('') // 返回 0
    'hello world'.indexOf('', 0) // 返回 0
    'hello world'.indexOf('', 3) // 返回 3
    'hello world'.indexOf('', 8) // 返回 8
    

    然而,如果有第二个参数,其值大于或等于字符串的长度,则返回值为字符串的长度:

    'hello world'.indexOf('', 11) // 返回 11
    'hello world'.indexOf('', 13) // 返回 11
    'hello world'.indexOf('', 22) // 返回 11
    

    在前一个实例中,该方法的行为就像在第二个参数指定的位置之后发现了一个空字符串。在后一个实例中,该方法的行为就好像在调用字符串的末尾找到了一个空字符串。

    字符串中的字符被从左向右索引。第一个字符的索引(index)是 0,字符串的最后一个字符的索引是字符串的长度减 1。

    'Blue Whale'.indexOf('Blue')      // 返回  0
    'Blue Whale'.indexOf('Blute')     // 返回 -1
    'Blue Whale'.indexOf('Whale', 0)  // 返回  5
    'Blue Whale'.indexOf('Whale', 5)  // 返回  5
    'Blue Whale'.indexOf('Whale', 7)  // 返回 -1
    'Blue Whale'.indexOf('')          // 返回  0
    'Blue Whale'.indexOf('', 9)       // 返回  9
    'Blue Whale'.indexOf('', 10)      // 返回 10
    'Blue Whale'.indexOf('', 11)      // 返回 10
    

    indexOf() 方法是区分大小写的。例如,下面的表达式将返回 -1

    'Blue Whale'.indexOf('blue')      // 返回 -1
    

    检测是否存在某字符串

    当检查字符串中是否出现特定的子字符串时,正确的检查方法是测试返回值是否为 -1

    'Blue Whale'.indexOf('Blue') !== -1  // true; found 'Blue' in 'Blue Whale'
    'Blue Whale'.indexOf('Bloe') !== -1  // false; no 'Bloe' in 'Blue Whale'
    

    使用 indexOf()

    下面的例子使用 indexOf() 来定位字符串 "Brave new world" 中的子字符串。

    const str = 'Brave new world';
    
    console.log(`Index of first w from start is ${str.indexOf('w')}`); // logs 8
    console.log(`Index of "new" from start is ${str.indexOf('new')}`); // logs 6
    

    indexOf() 和区分大小写

    下例定义了两个字符串变量。

    两个变量包含相同的字符串,只是第二个字符串中的某些字符为大写。第一个 [console.log()](<https://developer.mozilla.org/zh-CN/docs/Web/API/Console/log>) 方法输出 19。但是由于 indexOf() 方法区分大小写,因此不会在 myCapString 中发现字符串 “cheddar",所以第二个 console.log() 方法会输出 -1

    const myString = 'brie, pepper jack, cheddar';
    const myCapString = 'Brie, Pepper Jack, Cheddar';
    
    console.log(`myString.indexOf("cheddar") is ${myString.indexOf('cheddar')}`);
    // logs 19
    console.log(`myCapString.indexOf("cheddar") is ${myCapString.indexOf('cheddar')}`);
    // logs -1
    

    使用 indexOf() 统计一个字符串中某个字母出现的次数

    在下例中,使用 count 来记录字母 e 在字符串 str 中出现的次数:

    // 翻译:生存还是毁灭?这是个问题。(莎士比亚《哈姆雷特》)
    const str = 'To be, or not to be, that is the question.';
    let count = 0;
    let position = str.indexOf('e');
    
    while (position !== -1) {
      count++;
      position = str.indexOf('e', position + 1);
    }
    
    console.log(count); // displays 4
    
  5. charAt()从一个字符串中返回指定的字符。

    str.charAt(index)
    

    参数

    index一个介于 0 和字符串长度减 1 之间的整数。(0~length-1) 如果没有提供索引,charAt() 将使用 0。

    字符串中的字符从左向右索引,第一个字符的索引值为 0,最后一个字符(假设该字符位于字符串 stringName 中)的索引值为 stringName.length - 1。如果指定的 index 值超出了该范围,则返回一个空字符串。

    例子:输出字符串中不同位置的字符

    下例输出字符串 "Brave new world" 不同位置处的字符:

    var anyString = "Brave new world";
    
    console.log("The character at index 0   is '" + anyString.charAt(0)   + "'");
    console.log("The character at index 1   is '" + anyString.charAt(1)   + "'");
    console.log("The character at index 2   is '" + anyString.charAt(2)   + "'");
    console.log("The character at index 3   is '" + anyString.charAt(3)   + "'");
    console.log("The character at index 4   is '" + anyString.charAt(4)   + "'");
    console.log("The character at index 999 is '" + anyString.charAt(999) + "'");
    

    上面代码的输出为:

    The character at index 0 is 'B'
    The character at index 1 is 'r'
    The character at index 2 is 'a'
    The character at index 3 is 'v'
    The character at index 4 is 'e'
    The character at index 999 is ''
    
  6. toLowerCase()调用该方法的字符串值转为小写形式 ,并返回。

    str.toLowerCase()
    

    返回值

    一个新的字符串,表示转换为小写的调用字符串。

    toLowerCase 会将调用该方法的字符串值转为小写形式,并返回。toLowerCase 不会影响字符串本身的值。

    例子:使用 toLowerCase()

    console.log('中文简体 zh-CN || zh-Hans'.toLowerCase());
    // 中文简体 zh-cn || zh-hans
    
    console.log( "ALPHABET".toLowerCase() );
    // "alphabet"
    
  7. toUpperCase()调用该方法的字符串转为大写形式并返回(如果调用该方法的值不是字符串类型会被强制转换)。

    str.toUpperCase()
    

    返回值

    一个新的字符串,表示转换为大写的调用字符串。

    错误处理

    TypeError(类型错误)在 null  或 undefined 类型上调用,例如:String.prototype.toUpperCase.call(undefined).

    toUpperCase() 返回转为大写形式的字符串。此方法不会影响原字符串本身的值,因为 JavaScript 中字符串的值是不可改变的。

    基本用法

    console.log('alphabet'.toUpperCase()); // 'ALPHABET'
    

    将非字符串类型的 this  (上下文)转为字符串

    此方法会将任何非字符串类型的值转为字符串,当你将其上下文 this 值设置为非字符串类型

    const a = String.prototype.toUpperCase.call({
      toString: function toString() {
        return 'abcdef';
      }
    });
    
    const b = String.prototype.toUpperCase.call(true);
    
    // 输出 'ABCDEF TRUE'。
    console.log(a, b);
    

Math对象

**Math**是一个内置对象,它拥有一些数学常数属性和数学函数方法。Math不是一个函数对象。Math用于 Number 类型。它不支持 BigIntMath的所有属性与方法都是静态的。

  1. math.floor函数总是返回小于等于一个给定数字的最大整数。

    Math.floor(-Infinity); // -Infinity
    Math.floor(-45.95); // -46
    Math.floor(-45.05); // -46
    Math.floor(-0); // -0
    Math.floor(0); // 0
    Math.floor(4); //   4
    Math.floor(45.05); //  45
    Math.floor(45.95); //  45
    Math.floor(Infinity); // Infinity
    
  2. Math.abs(x) 函数返回一个数字的绝对值。

  3. Math.toSource()返回字符串 "Math"

  4. 常量PI

    Math.PI 表示一个圆的周长与直径的比例,约为 3.14159:

    由于 PI 是 Math 的静态属性,所以应该像这样使用:Math.PI,而不是作为你创建的 Math 实例的属性(Math 不是构造函数)。

    使用 Math.PI

    下面的函数使用 Math.PI 计算给定半径的圆周长:

    function calculateCircumference (radius) {
      return 2 * Math.PI * radius;
    }
    
    calculateCircumference(1);  // 6.283185307179586
    
  5. Math.round()函数返回一个数字四舍五入后最接近的整数。

    如果参数的小数部分大于 0.5,则舍入到相邻的绝对值更大的整数。如果参数的小数部分小于 0.5,则舍入到相邻的绝对值更小的整数。如果参数的小数部分恰好等于 0.5,则舍入到相邻的在正无穷(+∞)方向上的整数。注意,与很多其他语言中的round() 函数不同,Math.round() 并不总是舍入到远离 0 的方向(尤其是在负数的小数部分恰好等于 0.5 的情况下)。

    因为 round() 是 Math 的静态方法,你应该直接使用 Math.round(),而不是作为你创建的 Math 对象的一个实例方法来使用(Math没有构造函数)。

    x = Math.round(20.49);   //20
    x = Math.round(20.5);    //21
    x = Math.round(-20.5);   //-20
    x = Math.round(-20.51);  //-21
    
  6. Math.floor()总是返回小于等于一个给定数字的最大整数。

    因为 floor() 是 Math 的静态方法,所以你应始终使用 Math.floor(),而不是作为你创建的 Math 对象的方法(Math 不是构造函数)。

    使用 Math.floor()

    Math.floor(-Infinity); // -Infinity
    Math.floor(-45.95); // -46
    Math.floor(-45.05); // -46
    Math.floor(-0); // -0
    Math.floor(0); // 0
    Math.floor(4); //   4
    Math.floor(45.05); //  45
    Math.floor(45.95); //  45
    Math.floor(Infinity); // Infinity
    
  7. Math.ceil()总是四舍五入并返回大于等于给定数字的最小整数。

    因为 ceil() 是 Math 的静态方法,所以你应始终使用 Math.ceil(),而不是作为你创建的 Math 对象的方法(Math 不是构造函数)。

    使用 Math.ceil()

    Math.ceil(-Infinity); // -Infinity
    Math.ceil(-7.004); // -7
    Math.ceil(-4); // -4
    Math.ceil(-0.95); // -0
    Math.ceil(-0); // -0
    Math.ceil(0); // 0
    Math.ceil(0.95); // 1
    Math.ceil(4); // 4
    Math.ceil(7.004); // 8
    Math.ceil(Infinity); // Infinity
    
  8. random()返回一个 0 到 1 之间的伪随机数。从 0(包括 0)往上,但是不包括 1(排除 1),然后您可以缩放到所需的范围。实现将初始种子选择到随机数生成算法;它不能被用户选择或重置。

    备注: Math.random()不能提供像密码一样安全的随机数字。不要使用它们来处理有关安全的事情。使用 Web Crypto API 来代替,和更精确的window.crypto.getRandomValues() 方法。

    得到一个大于等于 0,小于 1 之间的随机数

    function getRandom() {
      return Math.random();
    }
    

    得到一个两数之间的随机数

    这个例子返回了一个在指定值之间的随机数。这个值不小于 min(有可能等于),并且小于(不等于)max

    function getRandomArbitrary(min, max) {
      return Math.random() * (max - min) + min;
    }
    

    得到一个两数之间的随机整数

    这个例子返回了一个在指定值之间的随机整数。这个值不小于 min (如果 min 不是整数,则不小于 min 的向上取整数),且小于(不等于)max

    function getRandomInt(min, max) {
      min = Math.ceil(min);
      max = Math.floor(max);
      return Math.floor(Math.random() * (max - min)) + min; //不含最大值,含最小值
    }
    

    备注: 也许很容易想到用 Math.round() 来实现,但是这会导致你的随机数处于一个不均匀的分布,这可能不符合你的需求。

    得到一个两数之间的随机整数,包括两个数在内

    上一个例子提到的函数 getRandomInt() 结果范围包含了最小值,但不含最大值。如果你的随机结果需要同时包含最小值和最大值,怎么办呢?getRandomIntInclusive() 函数可以实现。

    function getRandomIntInclusive(min, max) {
      min = Math.ceil(min);
      max = Math.floor(max);
      return Math.floor(Math.random() * (max - min + 1)) + min; //含最大值,含最小值
    }
    

其他知识点:

  1. sort()

    方法用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的 UTF-16 代码单元值序列时构建的

    由于它取决于具体实现,因此无法保证排序的时间和空间复杂性。

    // 无函数
    sort()
    
    // 箭头函数
    sort((a, b) => { /* … */ } )
    
    // 比较函数
    sort(compareFn)
    
    // 内联比较函数
    sort(function compareFn(a, b) { /* … */ })
    Copy to Clipboard
    

    参数

    compareFn 可选用来指定按某种顺序进行排列的函数。如果省略,元素按照转换为的字符串的各个字符的 Unicode 位点进行排序。a第一个用于比较的元素。b第二个用于比较的元素。

    返回值

    排序后的数组。请注意,数组已原地排序,并且不进行复制。

    如果没有指明 compareFn ,那么元素会按照转换为的字符串的诸个字符的 Unicode 位点进行排序。例如 "Banana" 会被排列到 "cherry" 之前。当数字按由小到大排序时,9 出现在 80 之前,但因为(没有指明 compareFn),比较的数字会先被转换为字符串,所以在 Unicode 顺序上 "80" 要比 "9" 要靠前。

    如果指明了 compareFn ,那么数组会按照调用该函数的返回值排序。即 a 和 b 是两个将要被比较的元素:

    • 如果 compareFn(a, b) 大于 0,b 会被排列到 a 之前。
    • 如果 compareFn(a, b) 小于 0,那么 a 会被排列到 b 之前;
    • 如果 compareFn(a, b) 等于 0,a 和 b 的相对位置不变。备注:ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003 年之前的版本);
    • compareFn(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。
    compareFn(a, b) 返回值排序顺序
    > 0a 在 b 后
    < 0a 在 b 前
    === 0保持 a 和 b 的顺序

    所以,比较函数格式如下:

    function compareFn(a, b) {
      if (在某些排序规则中,a 小于 b) {
        return -1;
      }
      if (在这一排序规则下,a 大于 b) {
        return 1;
      }
      // a 一定等于 b
      return 0;
    }
    Copy to Clipboard
    

    要比较数字而非字符串,比较函数可以简单的用 a 减 b,如下的函数将会将数组升序排列(如果它不包含 Infinity 和 NaN):

    function compareNumbers(a, b) {
      return a - b;
    }
    Copy to Clipboard
    

    sort 方法可以使用 函数表达式 方便地书写:

    const numbers = [4, 2, 5, 1, 3];
    numbers.sort(function (a, b) {
      return a - b;
    });
    console.log(numbers);
    // [1, 2, 3, 4, 5]
    
    // 或者
    
    const numbers2 = [4, 2, 5, 1, 3];
    numbers2.sort((a, b) => a - b);
    console.log(numbers2);
    // [1, 2, 3, 4, 5]
    Copy to Clipboard
    

    对象可以按照某个属性排序:

    const items = [
      { name: 'Edward', value: 21 },
      { name: 'Sharpe', value: 37 },
      { name: 'And', value: 45 },
      { name: 'The', value: -12 },
      { name: 'Magnetic', value: 13 },
      { name: 'Zeros', value: 37 }
    ];
    
    // sort by value
    items.sort((a, b) => a.value - b.value);
    
    // sort by name
    items.sort((a, b) => {
      const nameA = a.name.toUpperCase(); // ignore upper and lowercase
      const nameB = b.name.toUpperCase(); // ignore upper and lowercase
      if (nameA < nameB) {
        return -1;
      }
      if (nameA > nameB) {
        return 1;
      }
    
      // names must be equal
      return 0;
    });
    
  2. script 的type属性

    该属性定义 script 元素包含或src引用的脚本语言。属性的值为 MIME 类型; 支持的 MIME 类型包括text/javascripttext/ecmascriptapplication/javascript, 和application/ecmascript如果没有定义这个属性,脚本会被视作 JavaScript。 如果 MIME 类型不是 JavaScript 类型(上述支持的类型),则该元素所包含的内容会被当作数据块而不会被浏览器执行。 如果 type 属性为module,代码会被当作 JavaScript 模块。

  3. return语句终止函数的执行,并返回一个指定的值给函数调用者。

    当在函数体中使用 return 语句时,函数将会停止执行。如果指定一个值,则该值会被返回给函数调用者。例如,以下函数返回其参数 x 的平方,其中 x 是数字。

    function square(x) {
      return x * x;
    }
    const demo = square(3);
    // demo will equal 9
    

    如果省略该值,则返回 undefined

    下面的 return 语句都会终止函数的执行:

    return;
    return true;
    return false;
    return x;
    return x + y / 3;
    

    自动插入分号(ASI)规则会影响 return 语句。在 return 关键字和被返回的表达式之间不允许使用换行符。

    return
    a + b;
    

    根据 ASI,被转换为:

    return;
    a + b;
    

    控制台会警告“unreachable code after return statement”。

    备注: 从 Firefox 40 开始,如果在 return 语句后发现不可达的代码,控制台会显示一个警告。

    为了避免这个问题(防止 ASI),你可以使用括号:

    return (
      a + b
    );
    

    返回一个函数

    参见关于闭包的文章。

    function magic() {
      return function calc(x) { return x * 42; };
    }
    
    const answer = magic();
    answer(1337); // 56154
    
  4. 条件运算符

    条件(三元)运算符是 JavaScript 仅有的使用三个操作数的运算符。一个条件后面会跟一个问号(?),如果条件为 truthy ,则问号后面的表达式 A 将会执行;表达式 A 后面跟着一个冒号(:),如果条件为 falsy ,则冒号后面的表达式 B 将会执行。本运算符经常作为 if  语句的简洁形式来使用。

    condition ? exprIfTrue : exprIfFalse Copy to Clipboard

    condition计算结果用作条件的表达式exprIfTrue如果表达式 condition 的计算结果是 truthy(它和 true 相等或者可以转换成 true ),那么表达式 exprIfTrue 将会被求值。exprIfFalse如果表达式 condition 的计算结果是 falsy(它可以转换成 false ),那么表达式 exprIfFalse 将会被执行。

    除了 false,可能的假值表达式还有:null 、NaN 、 0 、空字符串( "" )、和 undefined 。如果 condition 是以上中的任何一个,那么条件表达式的结果就是 exprIfFalse 表达式执行的结果。

    一个简单的例子:

    var age = 26;
    var beverage = (age >= 21) ? "Beer" : "Juice";
    console.log(beverage); // "Beer"
    Copy to Clipboard
    

    一个常见的用法是处理可能为 null 的值:

    function greeting(person) {
        var name = person ? person.name : "stranger";
        return "Howdy, " + name;
    }
    
    console.log(greeting({name: 'Alice'}));  // "Howdy, Alice"
    console.log(greeting(null));             // "Howdy, stranger"
    Copy to Clipboard
    

    条件链

    这个三元操作符是右结合的,也就是说你可以像这样把它链接起来,和 if … else if … else if … else 链类似:

    function example(…) {
        return condition1 ? value1
             : condition2 ? value2
             : condition3 ? value3
             : value4;
    }
    
    // Equivalent to:
    
    function example(…) {
        if (condition1) { return value1; }
        else if (condition2) { return value2; }
        else if (condition3) { return value3; }
        else { return value4; }
    }
    

案例:一个简单的博客目录

<html>
	<head>
		<title>YouCube - The Blog for Cube Puzzlers</title>
		<script>

			function Blog(body, date){
				this.body = body;
				this.date = date;

				this.toString = function(){
					return "[" + this.date.getFullYear()  + "/" + (this.date.getMonth() + 1) + "/" + this.date.getDate() + "]" + this.body;
				};

				this.toHTML = function(highlight){
					var blogHTML = "";
					blogHTML += highlight ? "<p style='background-color:#eeeeee'>" : "<p>";
					blogHTML += "<strong>" + this.date.getFullYear() + "/" + (this.date.getMonth() + 1) + "/" + this.date.getDate() + "</strong>" + "</br>" + this.body + "</p>" ;
					return blogHTML;
				};

				this.containsText = function(text){
					return(this.body.toLowerCase().indexOf(text.toLowerCase()) != -1);
				};
			}

			var blog = [new Blog("Got the new cube I ordered. It's a real pearl.", new Date("08/14/2008")),
						new Blog("second line.", new Date("08/19/2008")),
						new Blog("third line.", new Date("08/16/2008")),
						new Blog("the fourth line.", new Date("08/21/2008"))];

			function showBlog(numEn){
				//如果没有传入显示个数,则显示所有日志
				if (!numEn)
					numEn = blog.length;

				//显示日志
				var blogText = "";
				for (var i=0; i<numEn; i++){
					blogText += blog[i].toHTML(0 == i%2);
				}
				document.getElementById("blog").innerHTML = blogText;
			}

			blog.sort(function compare(blog1, blog2){return blog2.date - blog1.date; });

			function searchBlog(){
				var searchText = document.getElementById("searchtext").value;
				for (var i = 0; i<blog.length; i++){
					if (blog[i].containsText(searchText)){
						alert(blog[i]);
						break;
					}
				}
				if (blog.length == i)
				alert("sorry,there are no blog entries containing the search text.");
			}
			
			function randomBlog(){
				var i = Math.floor(Math.random() * blog.length);
				alert(blog[i]);
			}

		</script>
	
	</head>

	<body onload = "showBlog(2);">
		<h3>YouCube - The Blog for Cube Puzzlers</h3>
		<img src="cube.png" alt="YouCube" />
		<input type="button" id="search" value="search the blog" onclick="searchBlog();" />
		<input type="text" id="searchtext"  value="" />

		<div id="blog"></div>
		<input type="button" id="showall" value="show all blog" onclick="showBlog();" />
		<input type="button" id="random" value="random the blog" onclick="randomBlog();" />
		
	</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值