字符串(String)

字符串的扩展

字符的Unicode表示方法的扩展

  • ES5只能用四位表示\uxxxx
    • 超出这个范围的字符,必须用两个双字节的形式表示:\uD842\uDFB7 (”𠮷”)
  • ES6的Unicode表示方法的扩展:\u{x} 到 \u{xxxxx}
  • JS 规定有5个字符,不能在字符串里面直接使用,只能使用转义形式
    • 反斜杠'\'\u005C或者'\\' —— 转义形式
    • 回车:\u000D或者\r —— 转义形式
    • 行分隔符:'\u2028' —— 转义形式
    • 段分隔符:'\u2029' —— 转义形式
    • 换行符:'\u000A' —— 转义形式
  1. // ES6
  2. "\u{20BB7}"
  3. // "𠮷"
  4. "\u{41}\u{42}\u{43}"
  5. // "ABC"
  6. let hell\u{6F} = 123;
  7. console.log(hello); // 123
  8. '\u{1F680}' === '\uD83D\uDE80'
  9. // true
  1. // JavaScript 共有 6 种方法可以表示一个字符
  2. '\z' === 'z' // true
  3. '\172' === 'z' // true
  4. '\x7A' === 'z' // true
  5. '\u007A' === 'z' // true
  6. '\u{7A}' === 'z' // true
  • JSON 格式允许字符串里面直接使用'\u2028'(行分隔符)和 '\u2029'(段分隔符)

    • 这样一来,服务器输出的 JSON 被JSON.parse解析,就有可能直接报错
    • 模板字符串现在就允许直接输入这两个字符。
    • 另外,正则表达式依然不允许直接输入这两个字符,这是没有问题的,因为 JSON 本来就不允许直接包含正则表达式。
      1. const json = '"\u2028"';
      2. JSON.parse(json); // 可能报错
  • JSON 格式已经冻结(RFC 7159),没法修改了。

    • 为了消除这个报错,ES2019 允许 JavaScript 字符串直接输入 '\u2028'(行分隔符)和 '\u2029'(段分隔符)

      JSON.stringify()的改造

  • 根据标准,JSON 数据必须是 UTF-8 编码。但是,现在的JSON.stringify()方法有可能返回不符合 UTF-8 标准的字符串。

    • UTF-8 标准规定,0xD8000xDFFF之间的码点,不能单独使用,必须配对使用
      • 如可以'\uDF06\uD834',不能'\uDF06'
    • 为了确保返回的是合法的 UTF-8 字符,ES2019 改变了JSON.stringify()的行为。如果遇到0xD8000xDFFF之间的单个码点,或者不存在的配对形式,它会返回转义字符串,留给应用自己决定下一步的处理。
      1. JSON.stringify('\uD834') // "\ud834"
      2. JSON.stringify('\uDF06\uD834') // "\udf06\ud834"

      模板字符串

  • ES5的字符串是用''(单引号)或者""(双引号)包起来的——叫普通字符串

  • ES6的字符串可以用```(反引号)包起来。如果要引入变量params,这样使用${params}`——叫模板字符串

    • 模板字符串的空格和换行,都是被保留的
    • ${}中 大括号内部可以放入任意的 JS 表达式,可以进行运算,以及引用对象属性。
    • 模板字符串能嵌套,即里面可嵌套。比如I am `a ${good}` boy

      String内置对象上新增的方法

  • String.fromCodePoint()

    • ES6 提供了String.fromCodePoint()方法,可以识别大于0xFFFF的字符
    • 弥补了ES5中String.fromCharCode()方法的不足
    • 在作用上,正好与其实例对象新增的codePointAt()方法相反。
      1. String.fromCharCode(0x20BB7) // "ஷ" 丢了一位,相当于String.fromCharCode(0x0BB7)
      2. String.fromCodePoint(0x20BB7) // "𠮷"
  • String.raw()

    • 该方法返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串
    • 往往用于模板字符串的处理方法,不需要用括号调用
      • 与模板字符串搭配时,使用方式比较独特,习惯就好
      • 只需要把模板字符串放在String.raw后面就好了
    • 用括号调用该方法的使用方式,Stirng.raw({ raw: [...] }, ...) ``javascript // 与模板字符串的搭配 String.rawHi\n${2+3}!; // 'Hi\n5!' String.rawHi\n`; // ‘Hi\n’

// 用括号的方式调用 String.raw({ raw: [‘a’, ‘b’, ‘c’] }, 1 + 2, ‘good’) // ‘a3bgoodc’ String.raw({ raw: [‘a’, ‘b’, ‘c’] }, 1 + 2, ‘good’, ‘JS’) // ‘a3bgoodc’

  1. ```javascript
  2. // raw方法的实现
  3. String.myRaw = function (strings, ...values) {
  4. let output = '';
  5. if (!!strings === false || !!strings.raw === false) {
  6. return new Error('第一个参数必须带有raw');
  7. }
  8. let rawLen = strings.raw.length;
  9. let valLen = values.length;
  10. let index;
  11. for (index = 0; index < valLen; index++) {
  12. if (!!strings.raw[index] === false) break;
  13. if (index !== rawLen - 1) {
  14. output += strings.raw[index] + values[index];
  15. } else {
  16. output += strings.raw[index];
  17. }
  18. }
  19. for (; index < rawLen; index++) {
  20. output += strings.raw[index];
  21. }
  22. return output;
  23. }

实例对象新增的方法

  • codePointAt()
    • 该方法的作用:能够正确处理 4 个字节储存的字符,返回一个字符的码点(十进制值)
      • 如需转换为十六进制:s.codePointAt(0).toString(16)
    • 对于那些需要4个字节储存的字符(Unicode 码点大于0xFFFF的字符),JavaScript 会认为它们是两个字符
    • ES5中,charAt()方法无法读取整个字符,charCodeAt()方法只能分别返回前两个字节和后两个字节的值。 ```javascript // ES5 var s = “𠮷”; s.length // 2 s.charAt(0) // ‘’ s.charAt(1) // ‘’ s.charCodeAt(0) // 55362 s.charCodeAt(1) // 57271

// ES6 s.codePointAt(0) // 134071 s.codePointAt(1) // 57271

  1. - `normalize()`
  2. - 该方法作用:将字符的不同表示方法统一为同样的形式,这称为 Unicode 正规化
  3. - 四个参数:
  4. - NFC,默认参数,表示“标准等价合成”,返回多个简单字符的合成字符。所谓“标准等价”指的是视觉和语义上的等价。
  5. - NFD,表示“标准等价分解”,即在标准等价的前提下,返回合成字符分解的多个简单字符。
  6. - NFKC,表示“兼容等价合成”,返回合成字符。所谓“兼容等价”指的是语义上存在等价,但视觉上不等价,比如“囍”和“喜喜”。(这只是用来举例,normalize方法不能识别中文)
  7. - NFKD,表示“兼容等价分解”,即在兼容等价的前提下,返回合成字符分解的多个简单字符
  8. - 许多欧洲语言有语调符号和重音符号。为了表示它们,Unicode 提供了两种方法。
  9. - 直接提供带重音符号的字符,比如`Ǒ`\u01D1
  10. - 提供合成符号,即原字符与重音符号的合成,两个字符合成一个字符,比如`O`\u004F)和`ˇ`\u030C)合成`Ǒ`\u004F\u030C
  11. - 这两种表示方法,在视觉和语义上都等价,但是 JS 不能识别,所以出现`normalize()`这个方法
  12. ```javascript
  13. // 对于这个字符 Ǒ
  14. '\u01D1'==='\u004F\u030C' // false
  15. '\u01D1'.normalize() === '\u004F\u030C'.normalize() // true
  16. '\u004F\u030C'.normalize('NFC').length // 1
  17. '\u004F\u030C'.normalize('NFD').length // 2
  18. '\u01D1'.normalize('NFD').length // 2
  • 字符串中查找字符串
    • ES5中,提供了indexOf()方法
    • ES6中,新增了三个方法
      • **includes()**:返回布尔值,表示是否找到了参数字符串
      • **startsWith()**:返回布尔值,表示参数字符串是否在原字符串的头部
      • **endsWith()**:返回布尔值,表示参数字符串是否在原字符串的尾部 ```javascript let s = ‘Hello world!’;

s.startsWith(‘Hello’) // true s.endsWith(‘!’) // true s.includes(‘o’) // true

// 三个方法都支持第二个参数,表示开始搜索的位置 s.startsWith(‘world’, 6) // true s.endsWith(‘Hello’, 5) // true s.includes(‘Hello’, 6) // false

  1. - `repeat(n)`
  2. - 该方法的作用:返回一个新字符串,表示将原字符串重复n
  3. - `n > 1`n含小数,向下取整。如`2.9``2``2.3`2
  4. - `n <= -1``n = Infinity`:报错
  5. - `-1 < n < 1`或者`n= NaN`:取`n``0`
  6. - `n`为字符串时,会先转成数字
  7. <a name="bEnCs"></a>
  8. # 数值(Number)
  9. <a name="vWBLT"></a>
  10. ## 数值的扩展
  11. <a name="hxQar"></a>
  12. ### 二进制和八进制的表示
  13. - ES5 开始,在严格模式之中,八进制就不再允许使用前缀`0`表示
  14. - ES6 进一步明确
  15. - 使用前缀`0o``0O`表示八进制
  16. - 使用前缀`0b``0B`表示二进制
  17. - 如果要将`0b``0o`前缀的字符串数值转为十进制,要使用`Number()`方法
  18. ```javascript
  19. // ES6
  20. 0b111110111 === 503 // true
  21. 0o767 === 503 // true
  22. Number('0b111') // 7
  23. Number('0o10') // 8

Number内置对象上新增的方法

  • ES5中,全局有两个方法isFinite()isNaN()
    • isFinite(param)用来检查一个数值是否为有限的(finite)
    • isNaN(param)用来检查一个值是否为NaN
    • 这两个方法,若param是非数值类型,转为数值再判断
  • ES6 在Number对象上,新增了两个方法

    • Number.isFinite(param)用来检查一个数值是否为有限的(finite)
    • Number.isNaN()用来检查一个值是否为NaN
    • 这个两个方法,当param是数值才判断truefalse,其他都返回false
  • ES6 将全局方法parseInt()parseFloat(),移植到Number对象上面,行为完全保持不变 ```javascript // ES5的写法 parseInt(‘12.34’) // 12 parseFloat(‘123.45#’) // 123.45

// ES6的写法 Number.parseInt(‘12.34’) // 12 Number.parseFloat(‘123.45#’) // 123.45

  1. <a name="FrF8H"></a>
  2. ### 安全整数
  3. - JS能够准确表示的整数范围在`-2^53`到`2^53`之间(不含两个端点),超过这个范围,无法精确表示这个值
  4. ```javascript
  5. Math.pow(2, 53) // 9007199254740992
  6. 9007199254740992 // 9007199254740992
  7. 9007199254740993 // 9007199254740992
  8. Math.pow(2, 53) === Math.pow(2, 53) + 1
  9. // true
  • ES6引入了Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限 ```javascript Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1 // true Number.MAX_SAFE_INTEGER === 9007199254740991 // true

Number.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER // true Number.MIN_SAFE_INTEGER === -9007199254740991 // true

  1. - `Number.isSafeInteger(num)`则是用来判断一个整数是否落在这个范围之内
  2. - 返回布尔值
  3. <a name="QJ6VF"></a>
  4. ### Math对象上新增的方法
  5. - ES6 Math 对象上新增了 17 个与数学相关的方法
  6. - 所有这些方法都是静态方法,只能在 Math 对象上调用
  7. - 下面列举一些方法
  8. - `Math.trunc()`:用于去除一个数的小数部分,返回整数部分
  9. - `Math.sign()`:用来判断一个数到底是正数、负数、还是零
  10. - 参数为正数,返回`+1`
  11. - 参数为负数,返回`-1`
  12. - 参数为 0,返回`0`
  13. - 参数为-0,返回`-0`
  14. - 其他值,返回`NaN`
  15. - `Math.cbrt()`:用于计算一个数的立方根
  16. - `Math.hypot()`:返回所有参数的平方和的平方根
  17. - 新增指数,对数方法
  18. - `Math.expm1(x)`:返回`ex - 1`
  19. - `Math.log1p(x)`:返回`loge(1 + x)`
  20. - `Math.log10(x)`:返回`log10(1 + x)`
  21. - `Math.log2(x)`:返回`log2(1 + x)`
  22. - 双曲函数的方法
  23. - `Math.sinh(x)` :返回`x`的双曲正弦
  24. - `Math.cosh(x)` :返回`x`的双曲余弦
  25. - `Math.tanh(x)` :返回`x`的双曲正切
  26. - `Math.asinh(x)` :返回`x`的反双曲正弦
  27. - `Math.acosh(x)` :返回`x`的反双曲余弦
  28. - `Math.atanh(x)` 返回`x`的反双曲正切
  29. <a name="wUoDH"></a>
  30. # 函数(Function)
  31. <a name="whxJP"></a>
  32. ## 函数的参数默认值
  33. - ES5 不能为函数的参数设置默认参数,得变通一下
  34. - ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面
  35. - 参数变量是默认声明的,在函数体中,不能用letconst再次声明,否则会报错。
  36. ```javascript
  37. // ES5
  38. // 但万一参数是布尔值,就会有问题
  39. function add (a, b) {
  40. a = a || 0;
  41. b = b || 0;
  42. return a + b;
  43. }
  44. // ES6
  45. function add(a = 0, b = 0) {
  46. return a + b;
  47. }
  • 函数参数与解构赋值结合 ```javascript // 写法一 function m1({x = 0, y = 0} = {}) { return [x, y]; }

// 写法二 function m2({x, y} = { x: 0, y: 0 }) { return [x, y]; }

// 函数没有参数的情况 m1() // [0, 0] m2() // [0, 0]

// x 和 y 都有值的情况 m1({x: 3, y: 8}) // [3, 8] m2({x: 3, y: 8}) // [3, 8]

// x 有值,y 无值的情况 m1({x: 3}) // [3, 0] m2({x: 3}) // [3, undefined]

// x 和 y 都无值的情况 m1({}) // [0, 0]; m2({}) // [undefined, undefined]

m1({z: 3}) // [0, 0] m2({z: 3}) // [undefined, undefined]

  1. - 函数的`length`属性
  2. - `length`表示:返回没有指定默认值的参数个数
  3. - 注意:某个参数指定默认值以后,后面参数没有指定默认值,不计入`length`
  4. ```javascript
  5. function test(a, b, c) {}
  6. console.log(test.length); // 3
  7. function test(a, b, c = 2) {}
  8. console.log(test.length); // 2
  9. function test(a = 0, b = 1, c = 2) {}
  10. console.log(test.length); // 0
  1. // 参数指定默认值以后,后面参数没有指定默认值,不计入length
  2. function test(a, b = 1, c, d) { }
  3. console.log(test.length); // 1
  4. function test(a, b, c = 1, d) { }
  5. console.log(test.length); // 2
  6. function test(a, b, c, d = 1) { }
  7. console.log(test.length); // 3

剩余(rest)运算符/扩展(展开)运算符

  • 剩余(rest)运算符/扩展(展开)运算符:...
    • 剩余(rest)运算符:用于获取函数的多余参数,这样就不需要使用arguments对象了
      • 运算后,返回一个数组
      • ES6引入的
    • 扩展(展开)运算符:用于取出参数对象的所有可遍历属性,拷贝到当前对象之中
      • ...{}...[]
      • ES9引入的
        1. // rest运算符的用法
        2. function add(a, ...rest) {
        3. let res = a;
        4. for (let i in rest) {
        5. res += rest[i];
        6. }
        7. return res;
        8. }
        9. add(1, 2, 3, 4, 5, 6, 7);
        ```javascript // 注意:rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错 // 下面就报错了 function f(a, …b, c) { // … }

// 函数的length属性,不包括 rest 参数 function f(a, b = 1, …rest) {} console.log(f.length); // 1

  1. <a name="eeoKA"></a>
  2. ## 函数的name属性
  3. - 函数的`name`属性:返回该函数的函数名
  4. - 这个属性早就被浏览器广泛支持,但是直到 ES6,才将其写入了标准
  5. ```javascript
  6. // 如果将一个匿名函数赋值给一个变量
  7. var f = function () {};
  8. // ES5 的name属性会返回空字符串
  9. f.name // ""
  10. // ES6 的name会返回实际的函数名
  11. f.name // "f"
  1. // 如果将一个具名函数赋值给一个变量
  2. // ES5 和 ES6 的name属性都返回这个具名函数原本的名字
  3. const bar = function baz() {};
  4. // ES5
  5. bar.name // "baz"
  6. // ES6
  7. bar.name // "baz"
  1. // bind返回的函数,name属性值会加上bound前缀
  2. function foo() {};
  3. foo.bind({}).name // "bound foo"
  4. (function(){}).bind({}).name // "bound "

箭头函数

  • ES6 允许使用“箭头”=>定义函数 ```javascript // ES6 const add = (a, b) => { return a + b; } // 箭头函数的返回值,可以这样简化 const add = (a, b) => a + b; // 省去写return

// 等同于ES5 var add = function(a, b) { return a + b; }

  1. ```javascript
  2. // 箭头函数如果参数只有一个,还可以去掉小括号
  3. const square = a => a * a;

箭头函数的this

  • 函数体内的this对象,继承的是外层代码块的this
  • 箭头函数没有自己的this,所以不能用call()、apply()、bind()这些方法去改变this的指向 ```javascript // 与setTimeout结合 // ES6 function test() { setTimeout(() => { console.log(this.id); }) } var id = 1; test.call({ id: 2 });

// ES5 function test() { setTimeout(function () { console.log(this.id); }) } var id = 1; test.call({ id: 2 });

  1. <a name="MspHb"></a>
  2. ### 使用箭头函数需注意
  3. - 函数没有prototype原型
  4. - 不可以作为构造函数。new了会报错
  5. - 没有`arguments`
  6. - 不可以使用`yield`命令,因此箭头函数不能用作 Generator 函数
  7. <a name="ZKvcI"></a>
  8. # 数组(Array)
  9. <a name="FjGHr"></a>
  10. ## 数组的扩展
  11. <a name="ae5ER"></a>
  12. ### Array内置对象上新增的方法
  13. - `Array.from()`:用于将两类对象转为真正的数组
  14. - 类似数组的对象(array-like object)
  15. - DOM 操作返回的 NodeList 集合
  16. - 函数内部的`arguments`对象
  17. - 可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)
  18. ```javascript
  19. let arrayLike = {
  20. '0': 'a',
  21. '1': 'b',
  22. '2': 'c',
  23. length: 3
  24. };
  25. // ES5的写法
  26. var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
  27. // 或者
  28. var arr1 = Array.prototype.slice.call(arrayLike); // ['a', 'b', 'c']
  29. // ES6的写法
  30. let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
  1. // Array.prototype.slice的模拟内部实现
  2. Array.prototype.slice = function(start, end) {
  3. let result = [],
  4. start = start || 0,
  5. end = end || this.length;
  6. for(let i = start;i < end;i++){
  7. result.push(this[i]);
  8. }
  9. return result;
  10. }

对象(Object)

对象的扩展

属性和方法更简洁的书写

  • 属性 ```javascript // 案例一:数据属性 const foo = ‘bar’; const a = { foo }; a // { foo: “bar” }

// 等同于 const a = { foo: foo };

  1. ```javascript
  2. // 案例二:访问器属性
  3. let obj = {
  4. _visit: 0,
  5. get visit() {
  6. return ++this._visit;
  7. },
  8. set visit(val) {
  9. this._visit = val;
  10. }
  11. }
  12. /**
  13. * visit这个属性的特性
  14. * {
  15. * cocnfigurate: true,
  16. * enumerable: true,
  17. * get: ...,
  18. * set: ...,
  19. * }
  20. */
  • 方法 ```javascript // 案例三 const o = { method() { return “Hello!”; } };

// 等同于 const o = { method: function() { return “Hello!”; } };

  1. <a name="tFItV"></a>
  2. ### 属性名表达式
  3. - JS 定义对象的属性,有两种方法
  4. - ES5 中只能使用标识符定义属性
  5. - ES6 允许用表达式作为对象的属性名,即把表达式放在方括号内
  6. ```javascript
  7. // ES5
  8. obj.foo = true;
  9. // ES6
  10. obj['a' + 'bc'] = 123;
  1. // ES5
  2. var obj = {
  3. foo: true,
  4. abc: 123,
  5. hello: function() {}
  6. };
  7. // ES6
  8. let propKey = 'foo';
  9. let obj = {
  10. [propKey]: true,
  11. ['a' + 'bc']: 123,
  12. ['h' + 'ello']() {
  13. return 'hi';
  14. },
  15. };

属性名的遍历

  • 五种遍历方式
    • for...in:循环遍历对象自身的 和 继承的可枚举属性(不含 Symbol 属性)
    • Object.keys(obj):返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名
    • Object.getOwnPropertyNames(obj):返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名
    • Object.getOwnPropertySymbols(obj):返回一个数组,包含对象自身的所有 Symbol 属性的键名
    • Reflect.ownKeys(obj):返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举
  • 这 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则
    • 首先遍历所有数值键,按照数值升序排列
    • 其次遍历所有字符串键,按照加入时间升序排列
    • 最后遍历所有 Symbol 键,按照加入时间升序排列 ```javascript let obj = {

b: 0, 10: 0, 2: 0, a: 0 }

Reflect.ownKeys(obj); // [‘2’, ‘10’, ‘b’, ‘a’, Symbol()]

  1. <a name="ILjcL"></a>
  2. ### Object内置对象上新增的方法
  3. - `Object.is(a, b)`:
  4. - 作用:用来比较两个值是否严格相等。与严格比较运算符`===`的行为只有两处不同
  5. - `Object.is()`的 `+0`不等于`-0`
  6. - `Object.is()`的 `NaN`等于自身
  7. ```javascript
  8. // ES5自定义Object.is方法
  9. Object.defineProperty(Object, 'is', {
  10. value: function(x, y) {
  11. if (x === y) {
  12. // 针对+0 不等于 -0的情况
  13. return x !== 0 || 1 / x === 1 / y;
  14. }
  15. // 针对NaN的情况
  16. return x !== x && y !== y;
  17. },
  18. configurable: true,
  19. enumerable: false,
  20. writable: true
  21. });
  1. +0 === -0 //true
  2. NaN === NaN // false
  3. Object.is(+0, -0) // false
  4. Object.is(NaN, NaN) // true
  • Object.assign(target, source1, source2...)
    • 作用:将源对象source的所有可枚举属性,复制到目标对象target,然后返回target
    • 注意
      • 如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性
      • 该方法是浅拷贝
      • Object.assign()无法正确拷贝setget方法 ```javascript // 案例一 const target = { a: 1, b: 1 };

const source1 = { b: 2, c: 2 }; const source2 = { c: 3 };

Object.assign(target, source1, source2); target // {a:1, b:2, c:3}

  1. ```javascript
  2. // 案例二:只传了target
  3. // Object.assign()会直接返回该参数
  4. const obj = {a: 1};
  5. Object.assign(obj) === obj // true
  6. // 如果该参数不是对象,则会先转成对象,然后返回
  7. typeof Object.assign(2) // "object"
  1. // 案例三
  2. // source是undefined、null、数值、布尔值,会被忽略
  3. let obj = {a: 1};
  4. Object.assign(obj, undefined); // {a: 1}
  5. Object.assign(obj, null); // {a: 1}
  6. Object.assign(obj, 10); // {a: 1}
  7. Object.assign(obj, true); // {a: 1}
  8. // source是字符串会以数组形式,拷贝入目标对象
  9. const str = 'abc';
  10. const obj = Object.assign({}, str);
  11. console.log(obj); // { "0": "a", "1": "b", "2": "c" }
  12. // 相当于
  13. const arr = ['a', 'b', 'c'];
  14. const obj = Object.assign({}, arr);
  15. console.log(obj); // { "0": "a", "1": "b", "2": "c" }
  1. // 案例四:Object.assign会把数组视为属性名为0,1,2这些的对象,所以发生同名替换
  2. const target = ['a', 'b', 'c'];
  3. const source = ['d', 'f']
  4. const obj = Object.assign(target, source);
  5. console.log(obj); // ['d', 'f', 'c']
  1. // 案例五:Object.assign()无法正确拷贝set和get方法
  2. // 在ES8中,新增了一个方法,更加方便地解决这个问题
  3. let obj = {
  4. _val: 0,
  5. get val() {
  6. return this._val
  7. },
  8. set val(val) {
  9. this._val = val
  10. }
  11. };
  12. let test = Object.assign(obj);
  13. test.val = 100; // 调用set方法修改后,影响了obj
  14. console.log(test.val); // 100
  15. console.log(obj.val); // 100

对象的原型

  • __proto__:用来读取或设置当前对象的原型对象
    • 由于浏览器广泛支持,才被加入了 ES6
    • 只有浏览器必须部署这个属性,其他运行环境不一定需要部署
  • Object.setPrototypeOf(object, prototype):用来设置一个对象的原型对象,返回参数对象本身
  • Object.getPrototypeOf(object):用于读取一个对象的原型对象 ```javascript // 案例一 let proto = {}; let obj = { x: 10 }; Object.setPrototypeOf(obj, proto);

proto.y = 20; proto.z = 40;

obj.x // 10 obj.y // 20 obj.z // 40

  1. ```javascript
  2. // 如果第一个参数不是对象,会自动转为对象。
  3. // 但是由于返回的还是第一个参数,所以这个操作不会产生任何效果
  4. Object.setPrototypeOf(1, {}) === 1 // true
  5. Object.setPrototypeOf('foo', {}) === 'foo' // true
  6. Object.setPrototypeOf(true, {}) === true // true