JavaScript高级步伐计划根本(三)

[复制链接]
发表于 2025-12-29 11:49:22 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
上接语言根本:JavaScript高级步伐计划根本(二)
2.3.6 String范例


  • 字符串的特点
ECMAScript  中的字符串是不可变的( immutable ),一旦创建,它们的值就不能变了。要修改   某个变量中的字符串值,必须先烧毁原始的字符串,然后将包罗新值的另一个字符串生存到该变量
        2.转换为字符串 


  • 险些全部值都有toString()方法(字符串值也有 toString()方法,该方法只是简单地返回自身的一个副本),null 和 undefined 值没有 toString()方法
  •       toString()通过传入参数,得到对应参数的进制字符串
  •       如果不确定一个值是不是    null    或    undefined   ,可以使用    String()   转型函数,该机制如下​​​​​

    • 如果值有 toString()方法,则调用该方法(不传参数)并返回效果
    •           如果值是      null     ,返回     "null"
    •           如果值是      undefined     ,返回     "undefined"

  ​​​​​        3.模板字面量
    模板字面量可以生存换行字符,跨行界说字符串     
  1. let myMultiLineString = 'first line\nsecond line';
  2. let myMultiLineTemplateLiteral = `first line
  3. second line`;
  4. console.log(myMultiLineString);
  5. // first line
  6. // second line"
  7. console.log(myMultiLineTemplateLiteral);
  8. // first line
  9. // second line
  10. console.log(myMultiLineString === myMultiLinetemplateLiteral); // true
复制代码
     模板字面量会保持反引号内部的空格        
  1. // 这个模板字面量在换行符之后有 25 个空格符
  2. let myTemplateLiteral = `first line
  3. second line`;
  4. console.log(myTemplateLiteral.length); // 47
复制代码
           4.字符串插值
                技能上讲,模板字面量不是字符串,而是一种特别的 JavaScript     句法表达式,只不外求值后得到的是字符串。                         模板字面量在界说时立刻求值并转换为字符串实例,任何插入的变量也会从它们最靠近的作               用域中取值                 
  1. console.log(`Hello, ${ `World` }!`); // Hello, World!
复制代码
             全部插入的值都会使用 toString()欺凌转型为字符串,而且任何 JavaScript 表达式都可以用于插值                   5.模板字面量标签函数                                让我们举例子来明确标签函数                起首我们先来界说一个函数        
  1. function simpleTag(strings, aValExpression, bValExpression, sumExpression) {
  2. console.log(strings);
  3. console.log(aValExpression);
  4. console.log(bValExpression);
  5. console.log(sumExpression);
  6. return 'foobar';
  7. }
复制代码
           接着我们调用并给它传入模板字符串
   
  1. let a = 6;
  2. let b = 9;
  3. let taggedResult = simpleTag`${ a } + ${ b } = ${ a + b }`;
  4. // ["", " + ", " = ", ""]
  5. // 6
  6. // 9
  7. // 15
  8. console.log(taggedResult); // "foobar"
复制代码
           可以看出来,如果我们直接传入一个模板字符串,函数吸取到的参数,分别为原始字符串数组以及各个变量
            我们再让函数简化(究竟每个函数的参数个数并不都为3),使用剩余操纵符(rest operator)将它们网络到一个数组中
   
  1. let a = 6;
  2. let b = 9;
  3. function simpleTag(strings, ...expressions) {
  4. console.log(strings);
  5. for(const expression of expressions) {
  6. console.log(expression);
  7. }
  8. return 'foobar';
  9. }
  10. let taggedResult = simpleTag`${ a } + ${ b } = ${ a + b }`;
  11. // ["", " + ", " = ", ""]
  12. // 6
  13. // 9
  14. // 15
  15. console.log(taggedResult); // "foobar"
复制代码
           对于有 n 个插值的模板字面量,传给标签函数的表达式参数的个数始终是 n(即expressions),而传给标签函数的第一个参数(strings)所包罗的字符串个数则始终是 n+1。
            如果你想还原字符串可以这么做
   
  1. function zipTag(strings, ...expressions) {
  2. return strings[0] +
  3. expressions.map((e, i) => `${e}${strings[i + 1]}`)
  4. .join('');
  5. }
复制代码
           6.原始字符串
            可以使用默认的 String.raw 标签函数直接获取原始的模板字面量内容(如换行符或 Unicode 字符)
   
  1. // Unicode 示例
  2. // \u00A9 是版权符号
  3. console.log(`\u00A9`); // ©
  4. console.log(String.raw`\u00A9`); // \u00A9
复制代码
           也可以使用过标签函数的第一个参数,即字符串数组的.raw 属性取得每个字符串的原始内容
   
  1. printRaw`\u00A9${ 'and' }\n`;
  2. function printRaw(strings) {
  3. for (const rawString of strings.raw) {
  4. console.log(rawString);
  5. }
  6. }
  7. // \u00A9
  8. // \n
复制代码
   2.3.7 Symbol范例

              是确保对象属性使用唯一标识符,不会发生属性辩论的伤害                       1.符号的根本使用                             符号必要使用 Symbol()     初始化。由于符号本身是原始范例,以是      typeof      操纵符对符号返回               symbol     。                                          也可以传入一个字符串参数作为对符号的形貌(description      ),未来可以通过这个字符串来调试代码。但是,这个字符串参数与符号界说或标识完全无关                 
  1. let fooSymbol = Symbol('foo');
  2. let otherFooSymbol = Symbol('foo');
  3. console.log(fooSymbol == otherFooSymbol); //false
复制代码
              最紧张的是,Symbol()函数不能与 new 关键字一起作为构造函数使用,如许做是为了制止创建符号包装对象
                       
  1. let myNumber = new Number();
  2. console.log(typeof myNumber); // "object"
  3. let mySymbol = new Symbol(); // TypeError: Symbol is not a constructor
复制代码
           如果你确实想使用符号包装对象,可以借用 Object()  函数     
  1. let mySymbol = Symbol();
  2. let myWrappedSymbol = Object(mySymbol);
  3. console.log(typeof myWrappedSymbol); // "object"
复制代码
          2.使用全局符号注册表
           如果运行时的差别部分必要共享和重用符号实例,必要使用 Symbol.for()方法
  
  1. let fooGlobalSymbol = Symbol.for('foo'); // 创建新符号
  2. let otherFooGlobalSymbol = Symbol.for('foo'); // 重用已有符号
  3. console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true
复制代码
          第一次使用某个字符串调用时,它会查抄全局运行时注册表,发现不存在对应的符号,于是就会天生一个新符号实例并添加到注册表中。后续使用雷同字符串的调用同样会查抄注册表,发现存在与该字符串对应的符号,然后就会返回该符号实例
           必须使用字符串键创建,作为参数传给Symbol.for的任何参数都会被转换为字符串
  
  1. let emptyGlobalSymbol = Symbol.for();
  2. console.log(emptyGlobalSymbol); // Symbol(undefined)
复制代码
          还可以使用 Symbol.keyFor()来查询全局注册表
  
  1. let foo=Symbol.for('m')
  2. console.log(Symbol.keyFor(foo)) //'m'
复制代码
          3.使用符号作为属性
           凡是可以使用字符串或数值作为属性的地方,都可以使用符号,这就意味着符号同样可以作为对象的属性
  
  1. const S1=Symbol('foo'),
  2.       S2 = Symbol('bar'),
  3.       S3 = Symbol('baz'),
  4.       S4 = Symbol('qux');
  5. let obj={
  6.     [S1]:'11'
  7. }
  8. console.log(obj);
  9. // {Symbol(foo): 11}
  10. Object.defineProperty(obj, S2, {value: 'bar val'});
  11. console.log(obj);
  12. // {Symbol(foo): 11, Symbol(bar): bar val}
  13. Object.defineProperties(obj, {
  14. [s3]: {value: 'baz val'},
  15. [s4]: {value: 'qux val'}
  16. });
  17. console.log(obj);
  18. // {Symbol(foo): 11, Symbol(bar): bar val,
  19. // Symbol(baz): baz val, Symbol(qux): qux val}
复制代码
             雷同于 Object.getOwnPropertyNames()   返回对象实例的通例属性数组                Object.getOwnPropertySymbols()返回对象实例的符号属性数组。                Object.getOwnPropertyDescriptors()会返回同时包罗通例和符号属性形貌符的对象。              Reflect.ownKeys()会返回两种范例的键 
          由于符号属性是对内存中符号的一个引用,以是直接创建并用作属性的符号不会丢失。但是,如果没有显式地生存对这些属性的引用,那么必须遍历对象的全部符号属性才气找到相应的属性键  
  1. let o = {
  2. [Symbol('foo')]: 'foo val',
  3. [Symbol('bar')]: 'bar val'
  4. };
  5. let barSymbol = Object.getOwnPropertySymbols(o)
  6. .find((symbol) => symbol.toString().match(/bar/));
  7. console.log(barSymbol);
  8. // Symbol(bar)
复制代码
        4.常用内置符号
            用于袒露语言内部举动,开发者可以直接访问、重写或模拟这些举动。这些内置符号都以   Symbol   工厂函数字符串属性的情势存在       留意:经常会引用符号在规范中的名称,前缀为@@。比如,@@iterator 指的就是 Symbol.iterator            5.Symbol.asyncIterator
         for-await-of 循环会使用这个函数实行异步迭代操纵
  1. class Emitter {
  2. constructor(max) {
  3. this.max = max;
  4. this.asyncIdx = 0;
  5. }
  6. // Symbol.asyncIterator为键的函数
  7. async *[Symbol.asyncIterator]() {
  8. while(this.asyncIdx < this.max) {
  9. yield new Promise((resolve) => resolve(this.asyncIdx++)); //返回一个实现迭代器 API 的对象
  10. }
  11. }
  12. }
  13. async function asyncCount() {
  14. let emitter = new Emitter(5);
  15. for await(const x of emitter) {
  16. console.log(x);
  17. }
  18. }
  19. asyncCount();
  20. // 0
  21. // 1
  22. // 2
  23. // 3
  24. // 4
复制代码
  留意:Symbol.asyncIterator 是 ES2018 规范界说的,因此只有版本非常新的欣赏器支持它。
           6.Symbol.hasInstance
        该方法决定一个构造器对象是否认可一个对象是它的实例,由 instanceof 操纵符使用
  1. function Foo() {}
  2. let f = new Foo();
  3. console.log(f instanceof Foo); // true
  4. console.log(Foo[Symbol.hasInstance](f)); // true
复制代码
         可以在继承的类上通过静态方法重新界说这个函数
  1. class Bar {}
  2. class Baz extends Bar {
  3. static [Symbol.hasInstance]() {
  4. return false;
  5. }
  6. }
  7. let b = new Baz();
  8. console.log(Bar[Symbol.hasInstance](b)); // true
  9. console.log(b instanceof Bar); // true
  10. console.log(Baz[Symbol.hasInstance](b)); // false
  11. console.log(b instanceof Baz); // false
复制代码
        7.Symbol.isConcatSpreadable
        这个符号作为一个属性体现一个布尔值,如果是 true,则意味着对象应该用 Array.prototype.concat()打平其数组元素。false 或假值会导致整个对象被追加到数组末端
  1. let initial = ['foo'];
  2. let array = ['bar'];
  3. console.log(array[Symbol.isConcatSpreadable]); // undefined
  4. console.log(initial.concat(array)); // ['foo', 'bar']
  5. array[Symbol.isConcatSpreadable] = false;
  6. console.log(initial.concat(array)); // ['foo', Array(1)]
复制代码
        8.Symbol.iterator
        返回对象默认的迭代器,由 for-of 语句使用,许多时间,返回的对象是实现该 API的 Generator
        技能上,这个由 Symbol.iterator 函数天生的对象应该通过其 next()方法连续返回值,也可以隐式地通过天生器函数返回
  1. class Emitter {
  2. constructor(max) {
  3. this.max = max;
  4. this.idx = 0;
  5. }
  6. *[Symbol.iterator]() {
  7. while(this.idx < this.max) {
  8. yield this.idx++;
  9. }
  10. }
  11. }
  12. function count() {
  13. let emitter = new Emitter(5);
  14. for (const x of emitter) {
  15. console.log(x);
  16. }
  17. }
  18. count();
  19. // 0
  20. // 1
  21. // 2
  22. // 3
  23. // 4
复制代码
        9.Symbol.match
          一个正则表达式方法,该方法用正则表达式去匹配字符串。这个方法不作过多先容          10.Symbol.replace           一个正则表达式方法,该方法更换一个字符串中匹配的子串  
  1. console.log('foobarbaz'.replace(/bar/, 'qux'));
  2. // 'fooquxbaz'
复制代码
           给这个方法传入非正则表达式值会导致该值被转换为 RegExp 对象。如果想改变这种举动,让方法直接使用参数,可以重新界说 Symbol.replace 函数以代替默认对正则表达式求值的举动     
  1. class StringReplacer {
  2. constructor(str) {
  3. this.str = str;
  4. }
  5. [Symbol.replace](target, replacement) {
  6. return target.split(this.str).join(replacement);
  7. }
  8. }
  9. console.log('barfoobaz'.replace(new StringReplacer('foo'), 'qux'));
  10. // "barquxbaz"
复制代码
          11.symbol.search
              一个正则表达式方法,该方法返回字符串中匹配正则表达式的索引        
  1. console.log('foobar'.search(/bar/));
  2. // 3
复制代码
           给这个方法传入非正则表达式值会导致该值被转换为 RegExp 对象,如果想改变这种举动,让方法直接使用参数,可以重新界说 Symbol.search 函数以代替默认对正则表达式求值的举动
   
  1. class StringSearcher {
  2. constructor(str) {
  3. this.str = str;
  4. }
  5. [Symbol.search](target) {
  6. return target.indexOf(this.str);
  7. }
  8. }
  9. console.log('foobar'.search(new StringSearcher('foo'))); // 0
复制代码
           12.Symbol.species
                      一个函数值,该函数作为创建派生对象的构造函数                   现在明确,简单来说派生对象就是父类,基类就是子类。在第一个例子中Bar继承了Array,在Symbol.species没有改变的情况下,Bar的实例对象bar既是Bar的实例也是Array的实例;在第二个例子中,Symbol.species将返回Array,而Array肯定不是Bar的实例,以是会返回false           
  1. class Bar extends Array {}
  2. class Baz extends Array {
  3. static get [Symbol.species]() {
  4. return Array;
  5. }
  6. }
  7. let bar = new Bar();
  8. console.log(bar instanceof Array); // true
  9. console.log(bar instanceof Bar); // true
  10. bar = bar.concat('bar');
  11. console.log(bar instanceof Array); // true
  12. console.log(bar instanceof Bar); // true
  13. let baz = new Baz();
  14. console.log(baz instanceof Array); // true
  15. console.log(baz instanceof Baz); // true
  16. baz = baz.concat('baz');
  17. console.log(baz instanceof Array); // true
  18. console.log(baz instanceof Baz); // false
复制代码
            13.Symbol.split
                  一个正则表达式方法,该方法在匹配正则表达式的索引位置拆分字符串.给这个方法传入非正则表达式值会导致该值被转换为 RegExp 对象。如果想改变这种举动,让方法直接使用参数,可以重新界说 Symbol.split 函数以代替默认对正则表达式求值的举动              
  1. class StringSplitter {
  2. constructor(str) {
  3. this.str = str;
  4. }
  5. [Symbol.split](target) {
  6. return target.split(this.str);
  7. }
  8. }
  9. console.log('barfoobaz'.split(new StringSplitter('foo')));
  10. // ["bar", "baz"]
复制代码
             14.Symbol.toPrimitive
                          一个方法,该方法将对象转换为相应的原始值。许多内置操纵都会实验欺凌将对象转换为原始值,包罗字符串、数值和未指定的原始范例     
  1. class Foo {}
  2. let foo = new Foo();
  3. console.log(3 + foo); // "3[object Object]"
  4. console.log(3 - foo); // NaN
  5. console.log(String(foo)); // "[object Object]"
  6. class Bar {
  7.     constructor() {
  8.         this[Symbol.toPrimitive] = function(hint) {
  9.             switch (hint) {
  10.                 case 'number':
  11.                     return 3;
  12.                 case 'string':
  13.                     return 'string bar';
  14.                 case 'default':
  15.                     default:
  16.                     return 'default bar';
  17.             }
  18.         }
  19.     }
  20. }
  21. let bar = new Bar();
  22. console.log(3 + bar); // "3default bar"
  23. console.log(3 - bar); // 0
  24. console.log(String(bar)); // "string bar"
复制代码
          15. Symbol.toStringTag
           一个字符串,该字符串用于创建对象的默认字符串形貌。由内置方法 Object.prototype.toString()使用
  
  1. let s = new Set();
  2. console.log(s); // Set(0) {}
  3. console.log(s.toString()); // [object Set]
  4. console.log(s[Symbol.toStringTag]); // Set
  5. class Foo {}
  6. let foo = new Foo();
  7. console.log(foo); // Foo {}
  8. console.log(foo.toString()); // [object Object]
  9. console.log(foo[Symbol.toStringTag]); // undefined
  10. class Bar {
  11. constructor() {
  12. this[Symbol.toStringTag] = 'Bar';
  13. }
  14. }
  15. let bar = new Bar();
  16. console.log(bar); // Bar {}
  17. console.log(bar.toString()); // [object Bar]
  18. console.log(bar[Symbol.toStringTag]); // Bar
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表