《JS高级程序设计》第5章 基本引用类型

79 阅读6分钟

前言

  1. ECMAScript 缺少传统的面向对象编程语言所具备的某些基本结构,包括类和接口。引用值与传统面向对象编程语言中的类相似,但实现不同。
  2. 对象被认为是某个特定引用类型的实例。
  3. 新对象通过使用new操作符后跟一个构造函数(constructor) 来创建。构造函数就是用来创建新对象的函数。

一、Date

  1. 要创建日期对象,就使用new操作符来调用 Date 构造函数:
let now = new Date(); // 创建的对象将保存当前日期和时间
  1. Date.parse()方法接收一个表示日期的字符串参数,尝试将这个字符串转换为表示该日期的毫秒数。
let someDate = new Date(Date.parse("May 23, 2019"));
// 等价于
let someDate = new Date("May 23, 2019");
  1. Date.now()方法返回表示方法执行时日期和时间的毫秒数。toLocaleString()方法返回与浏览器 运行的本地环境一致的日期和时间。toString()方法通常返回带时区信息的日期和时间。
let newDate = new Date("2/14/2022")
console.log(newDate.toLocaleString()); // 2022/2/14 00:00:00
console.log(newDate.toString()); // Mon Feb 14 2022 00:00:00 GMT+0800 (中国标准时间)
  1. Date类型的valueOf()方法根本就不返回字符串,这个方法被重写后返回的是日期的毫秒表示。

二、RegExp

  1. 表示匹配模式的标记:

    1. g:全局模式,表示查找字符串的全部内容,而不是找到第一个匹配的内容就结束。
    2. i:不区分大小写,表示在查找匹配时忽略 pattern 和字符串的大小写。
    3. m:多行模式,表示查找到一行文本末尾时会继续查找。
    4. y:粘附模式,表示只查找从 lastIndex 开始及之后的字符串。
    5. u:Unicode 模式,启用 Unicode 匹配。
    6. s:dotAll 模式,表示元字符.匹配任何字符(包括\n\r)。
  2. RegExp 构造函数接收两个参数:模式字符串和(可选的)标记字符串。

// 匹配第一个"bat"或"cat",忽略大小写 
let pattern1 = /[bc]at/i;
// 跟 pattern1 一样,只不过是用构造函数创建的 
let pattern2 = new RegExp("[bc]at", "i");

三、原始值包装类型

  1. ECMAScript 提供了 3 种特殊的引用类型:BooleanNumberString。特点是:

    1. 每种包装类型都映射到同名的原始类型。
    2. 以读模式访问原始值时,后台会实例化一个原始值包装类型的对象,借助这个对象可以操作相应的数据。
    3. 涉及原始值的语句执行完毕后,包装对象就会被销毁。
  2. 每当用到某个原始值的方法或属性时,后台都会创建一个相应原始包装类型的对象,从而暴露出操作原始值的各种方法。在以读模式访问字符串值的任何时候,后台都会执行以下三步:

    1. 创建一个String类型的实例
    2. 调用实例上的特定方法
    3. 销毁实例
let s1 = "some text";
let s2 = s1.substring(2);

// 让原始值拥有对象的行为
let s1 = new String("some text");
let s2 = s1.substring(2);
s1 = null;
  1. 引用类型与原始值包装类型的主要区别在于对象的生命周期。
  2. Object构造函数作为一个工厂方法,能够根据传入值的类型返回相应原始值包装类型的实例。
let obj = new Object("some text");
console.log(obj instanceof String);  // true
  1. 理解原始布尔值和Boolean对象之间的区别非常重要,强烈建议永远不要使用后者。
let falseObject = new Boolean(false);
let falseValue = false;

// typeof 操作符对原始值返回 "boolean",
// 但对引用值返回 "object"。
console.log(typeof falseObject);             // object
console.log(typeof falseValue);              // boolean

// Boolean 对象是 Boolean 类型的实例,
// 在使用 instaceof 操作符时返回 true,
// 但对原始值则返回 false。
console.log(falseObject instanceof Boolean); // true
console.log(falseValue instanceof Boolean);  // false
  1. toFixed()方法返回包含指定小数点位数的数值字符串,toExponential()返回以科学记数法(也称为指数记数法),toPrecision()方法会根据情况返回最合理的输出结果。
  2. ES6 新增了Number.isInteger()方法,用于辨别一个数值是否保存为整数。
console.log(Number.isInteger(1));    // true
// 小数位的0可能会让人误以为数值是一个浮点值。
console.log(Number.isInteger(1.00)); // true
  1. 每个String对象都有一个length属性,表示字符串中字符的数量。
  2. concat()用于将一个或多个字符串拼接成一个新字符串,更常用的方式是使用加号操作符(+)。
  3. 三个从字符串中提取子字符串的方法:slice()substr()substring(),区别如下:
let stringValue = "hello world";
console.log(stringValue.slice(3));        // "lo world"
console.log(stringValue.substring(3));    // "lo world"
console.log(stringValue.substr(3));       // "lo world"

// 对 slice() 和 substring() 而言,第二个参数是提取结束的位置
console.log(stringValue.slice(3, 7));     // "lo w"
console.log(stringValue.substring(3, 7)); // "lo w"
// substr() 的第二个参数表示返回的子字符串数量
console.log(stringValue.substr(3, 7));    // "lo worl"

// -3 会被转换为 8 (长度 11 加上负参数)
console.log(stringValue.slice(-3));         // "rld"
// -3 会转换为 0 ,返回整个字符串
console.log(stringValue.substring(-3));     // "hello world"
// -3 会被转换为 8 (长度 11 加上负参数)
console.log(stringValue.substr(-3));        // "rld"

// slice() 方法将所有负值参数都当成字符串长度加上负参数值
// 第二个参数转换为 7
console.log(stringValue.slice(3, -4));      // "lo w"
// substring() 方法会将所有负参数值都转换为 0
// 第二个参数转换为 0, 等价于 substring(0, 3)
console.log(stringValue.substring(3, -4));  // "hel"
// substr() 方法将第一个负参数值当成字符串长度加上该值,
// 将第二个负参数值转换为 0,即返回的字符串包含零个字符
console.log(stringValue.substr(3, -4));     // "" (empty string)
  1. 有两个方法用于在字符串中定位子字符串:indexOf()lastIndexOf()indexOf()方法从字符串开头开始查找子字符串,而lastIndexOf()方法从字符串末尾开始查找子字符串。
  2. 判断字符串中是否包含另一个字符串的方法:startsWith()endsWith()includes()
  3. 字符串的原型上暴露了一个@@iterator方法。
let message = "abc";
// 手动使用迭代器
let stringIterator = message[Symbol.iterator]();

console.log(stringIterator.next()); // {value: "a", done: false} 
console.log(stringIterator.next()); // {value: "b", done: false} 
console.log(stringIterator.next()); // {value: "c", done: false} 
console.log(stringIterator.next()); // {value: undefined, done: true}
  1. 字符串可以通过解构操作符来解构:
let message = "abcde";
console.log([...message]); // ["a", "b", "c", "d", "e"]
  1. 模式匹配的方法:match()search()replace()split()方法:
let text = "cat, bat, sat, fat";
let pattern = /.at/;
// 等价于pattern.exec(text)
let matches = text.match(pattern);
console.log(matches);
// ['cat', index: 0, input: 'cat, bat, sat, fat', groups: undefined]

let pos = text.search(/at/);
console.log(pos);  // 1

let result = text.replace("at", "ond");
console.log(result); // "cond, bat, sat, fat" 
result = text.replace(/at/g, "ond");
console.log(result);  // "cond, bond, sond, fond"

四、单例内置对象

  1. ECMA-262 对内置对象的定义是“任何由 ECMAScript 实现提供、与宿主环境无关,并在 ECMAScript 程序开始执行时就存在的对象”。两个单例内置对象:GlobalMath
  2. Global对象为一种兜底对象,它所针对的是不属于任何对象的属性和方法。
  3. 不存在全局变量或全局函数这种东西。在全局作用域中定义的变量和函数都会变成Global对象的属性。
  4. 浏览器将window对象实现为Global对象的代理。
  5. 调用一个简单返回this的函数是在任何执行上下文中获取Global对象的通用方式。
// 当一个函数在没有明确指定 this 值的情况下执行时,this 值等于 Global 对象
let global = function() {
  return this;
}();