
2024-11-25 日报 Day17

今日的鸡汤
把行动交给现在,把结果交给时间。
今日学习内容
1、JS红皮书P38-47 第三章:语言基础
今日笔记
1、String类型: 表示零或多个 16 位 Unicode 字符序列。字符串可以使用双引号(”)、单引号(’)或反引号(`)标示,因此下面的代码都是合法的:
1 | let firstName = "Nicholas"; |
- 字符字面量: 如下表所示:
字面量 含义 \n 换行 \t 制表 \b 退格 \r 回车 \f 换页 \ 反斜杠 ' 单引号 " 双引号 ` 反引号 \xnn 以十六进制代码nn表示的一个字符 \unnnn 以十六进制代码nnnn表示的一个 Unicode 字符 2、字符串的特点:变量中的字符串值,必须先销毁原始的字符串,然后将包含新值的另一个字符串保存到该变量,如下所示: let lang = “Java”; lang = lang + “Script”; 这里,变量 lang 一开始包含字符串”Java”。紧接着,lang 被重新定义为包含”Java”和”Script”的组合,也就是”JavaScript”。整个过程首先会分配一个足够容纳 10 个字符的空间,然后填充上”Java”和”Script”。最后销毁原始的字符串”Java”和字符串”Script”,因为这两个字符串都没有用了。所有处理都是在后台发生的,而这也是一些早期的浏览器(如 Firefox 1.0 之前的版本和 IE6.0)在拼接字符串时非常慢的原因。这些浏览器在后来的版本中都有针对性地解决了这个问题 3、转换为字符串:有三种方法可以把值转换为字符串:toString()、String()和模板字面量。 - toString()方法: 该方法是所有引用类型中都具有的方法,其基本思想是返回一个表示该对象的字符串。null和undefined值没有toString()方法,如果调用这两个值的这个方法会导致错误。如果不确定一个值是不是null或undefined,可以使用String()转型函数。String()函数遵循如下规则:
1
2
3
4let age = 11;
let ageAsString = age.toString(); // 字符串"11"
let found = true;
let foundAsString = found.toString(); // 字符串"true" - 如果值有toString()方法,则调用该方法(没有参数)并返回结果。
- 如果值是null,则返回”null”。
- 如果值是undefined,则返回”undefined”。注意 用加号操作符给一个值加上一个空字符串””也可以将其转换为字符串
1
2
3
4
5
6
7
8let value1 = 10;
let value2 = true;
let value3 = null;
let value4;
console.log(String(value1)); // "10"
console.log(String(value2)); // "true"
console.log(String(value3)); // "null"
console.log(String(value4)); // "undefined"
3、模版字面量:ECMAScript 6 新增了使用模板字面量定义字符串的能力。与使用单引号或双引号不同,模板字面量保留换行字符,可以跨行定义字符串:
顾名思义,模板字面量在定义模板时特别有用,比如下面这个 HTML 模板:
let pageHTML = ` `; 由于模板字面量会保持反引号内部的空格,因此在使用时要格外注意。格式正确的模板字符串看起来可能会缩进不当: 4、字符串插值:字符串插值通过在${}中使用一个 JavaScript 表达式实现: `${ value } to the ${ exponent } power is ${ value * value }` 所有插入的值都会使用 toString()强制转型为字符串,而且任何 JavaScript 表达式都可以用于插值。嵌套的模板字符串无须转义: 将表达式转换为字符串时会调用 toString(): let foo = { toString: () => 'World' }; console.log(`Hello, ${ foo }!`); // Hello, World! 5、模版字面量标签函数:标签函数可以自定义插值行为。标签函数 会接收被插值记号分隔后的模板和对每个表达式求值的结果。因为表达式参数的数量是可变的,所以通常应该使用剩余操作符(rest operator)将它们收集到一个数组中:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15let a = 6;
let b = 9;
function simpleTag(strings, aValExpression, bValExpression, sumExpression) {
console.log(strings); // ["The sum of ", " + ", " = ", ""]
console.log(aValExpression); // 6
console.log(bValExpression); // 9
console.log(sumExpression); // 15
return 'foobar';
}
let untaggedResult = `${ a } + ${ b } = ${ a + b }`;
let taggedResult = simpleTag`${ a } + ${ b } = ${ a + b }`;
console.log(untaggedResult); // "6 + 9 = 15"
console.log(taggedResult); // "foobar"6、原始字符串:使用模板字面量也可以直接获取原始的模板字面量内容(如换行符或 Unicode 字符),而不是被转换后的字符表示。为此,可以使用默认的 String.raw 标签函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15let a = 6;
let b = 9;
function simpleTag(strings, ...expressions) {
console.log(strings);
for(const expression of expressions) {
console.log(expression);
}
return 'foobar';
}
let taggedResult = simpleTag`${ a } + ${ b } = ${ a + b }`;
// ["", " + ", " = ", ""]
// 6
// 9
// 15
console.log(taggedResult); // "foobar"🔹 模板字面量的行为1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22// unicode示例
console.log(`\u00A9`); // ©
console.log(String.raw`\u00A9`); // \u00A9
// 换行符示例
console.log(String.raw`Hello\nWorld`); // "Hello\nWorld"
function printRaw(strings) {
console.log('Actual characters:');
for (const string of strings) {
console.log(string);
}
console.log('Escaped characters;');
for (const rawString of strings.raw) {
console.log(rawString);
}
}
printRaw`\u00A9${ 'and' }\n`;
// Actual characters:
// ©
//(换行符)
// Escaped characters:
// \u00A9
// \n
当你使用标签模板时,字符串部分和插值部分是分开的,具体来说:
• strings 是一个 数组,包含字符串部分。
• strings.raw 是原始字符串数组,不会对 \u00A9 或 \n 进行转义解析。
• 插值的 ${‘and’} 不会包含在 strings 数组中,而是作为函数的额外参数传递。
⸻
🔹 解析 printRaw\u00A9${ ‘and’ }\n``
printRaw 函数的实际接收参数是:
1 | printRaw(["\u00A9", "\n"], "and"); |
参数解析
1 | strings = ["\u00A9", "\n"]; // 解析后是 ["©", "\n"] |
7、Symbol类型:Symbol(符号)是 ECMAScript 6 新增的数据类型。符号是原始值,且符号实例是唯一、不可变的。符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。
symbol符号的基本使用方法如下:
1 | let sym = Symbol(); |
符号没有字面量语法,这也是它们发挥作用的关键。按照规范,你只要创建 Symbol()实例并将其用作对象的新属性,就可以保证它不会覆盖已有的对象属性,无论是符号属性还是字符串属性。
最重要的是,Symbol()函数不能与 new 关键字一起作为构造函数使用。这样做是为了避免创建符号包装对象,像使用 Boolean、String 或 Number 那样,它们都支持构造函数且可用于初始化包含原始值的包装对象:
let myBoolean = new Boolean();
console.log(typeof myBoolean); // “object”
let myString = new String();
console.log(typeof myString); // “object”
let myNumber = new Number();
console.log(typeof myNumber); // “object”
1 | - 使用全局符号注册表:如果运行时的不同部分需要共享和重用符号实例,那么可以用一个字符串作为键,在全局符号注册表中创建并重用符号。使用Symbol.for()方法 |
Symbol.for()对每个字符串键都执行幂等操作。第一次使用某个字符串调用时,它会检查全局运行时注册表,发现不存在对应的符号,于是就会生成一个新符号实例并添加到注册表中。后续使用相同字符串的调用同样会检查注册表,发现存在与该字符串对应的符号,然后就会返回该符号实例。
1 | let fooGlobalSymbol = Symbol.for('foo'); |
即使采用相同的符号描述,在全局注册表中定义的符号跟使用 Symbol()定义的符号也并不等同:
1 | let localSymbol = Symbol('foo'); |
可以使用 Symbol.keyFor()来查询全局注册表,这个方法接收符号,返回该全局符号对应的字
符串键。如果查询的不是全局符号,则返回 undefined。
1 | // 创建全局符号 |
- 使用符号作为属性:凡是可以使用字符串或数值作为属性的地方,都可以使用符号。这就包括了对象字面量属性和Object.defineProperty()/Object.defineProperties()定义的属性。对象字面量只能在计算属性语法中使用符号作为属性。类似于 Object.getOwnPropertyNames()返回对象实例的常规属性数组,Object.getOwnPropertySymbols()返回对象实例的符号属性数组。这两个方法的返回值彼此互斥。Object.getOwnPropertyDescriptors()会返回同时包含常规和符号属性描述符的对象。Reflect.ownKeys()会返回两种类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20let s1 = Symbol('foo'),
s2 = Symbol('bar'),
s3 = Symbol('baz'),
s4 = Symbol('qux');
let o = {
[s1]: 'foo val'
};
// 这样也可以:o[s1] = 'foo val';
console.log(o);
// {Symbol(foo): foo val}
Object.defineProperty(o, s2, {value: 'bar val'});
console.log(o);
// {Symbol(foo): foo val, Symbol(bar): bar val}
Object.defineProperties(o, {
[s3]: {value: 'baz val'},
[s4]: {value: 'qux val'}
});
console.log(o);
// {Symbol(foo): foo val, Symbol(bar): bar val,
// Symbol(baz): baz val, Symbol(qux): qux val}
的键1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16let s1 = Symbol('foo'),
s2 = Symbol('bar');
let o = {
[s1]: 'foo val',
[s2]: 'bar val',
baz: 'baz val',
qux: 'qux val'
};
console.log(Object.getOwnPropertySymbols(o));
// [Symbol(foo), Symbol(bar)]
console.log(Object.getOwnPropertyNames(o));
// ["baz", "qux"]
console.log(Object.getOwnPropertyDescriptors(o));
// {baz: {...}, qux: {...}, Symbol(foo): {...}, Symbol(bar): {...}}
console.log(Reflect.ownKeys(o));
// ["baz", "qux", Symbol(foo), Symbol(bar)]