• ES6 |字符串\正则\数值\数组\函数\对象的扩展


    在这里插入图片描述

    1.字符串的扩展

    ES6 加强了对 Unicode 的支持,并且扩展了字符串对象

    方法

    • codePointAt()
    • String.fromCodePoint()
    • at():ES5对字符串对象提供charAt方法,返回字符串给定位置的字符,但不能识别码点大于0xFFFF的字符。这个可以
    • normalize()
    • includes(), startsWith(), endsWith():是否找到了参数字符串|是否在源字符串的头部|是否在源字符串的尾部
    • repeat():返回一个新字符串,表示将原字符串重复n
    • padStart(),padEnd():字符串补全长度的功能,一个用于头部补全,一个用于尾部
      '1'.padStart(10, '0') // "0000000001"
      
    • String.raw():返回一个斜杠都被转义的字符串

    其他

    • 码点放入大括号解读字符

      //以前:表示法只限于码点在\u0000~\uFFFF之间的字符
      "\uD842\uDFB7"	// ""
      
      //现在:码点放入大括号解读字符
      "\u{20BB7}"		// ""
      

    字符串遍历接口(Iterator)

    字符串可以被for...of循环遍历,

    for (let codePoint of 'foo') {
      console.log(codePoint)
    }
    // "f"
    // "o"
    // "o"
    

    模板字符串

    //以往:
    $('#result').append(
        'There are <b>' + basket.count + '</b> ' +
        'items in your basket, ' +
        '<em>' + basket.onSale +
        '</em> are on sale!'
    );
        
    //现在:
    $('#result').append(`
    	There are <b>${basket.count}</b> items
    	in your basket, <em>${basket.onSale}</em>
    	are on sale!
    `);
    

    标签模板

    标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能(tagged template)

    var a = 5;
    var b = 10;
    
    //tag是一个函数,整个表达式的返回值,就是tag函数处理模板字符串后的返回值。
    tag`Hello ${ a + b } world ${ a * b }`;
    
    // 等同于
    tag(['Hello ', ' world ', ''], 15, 50);
    

    2.正则的扩展

    字符串的正则方法

    字符串对象共有4个方法可以使用正则表达式:match()replace()search()split()。ES6将这4个方法全都定义在RegExp对象上:

    • String.prototype.match 调用 RegExp.prototype[Symbol.match]
    • String.prototype.replace 调用 RegExp.prototype[Symbol.replace]
    • String.prototype.search 调用 RegExp.prototype[Symbol.search]
    • String.prototype.split 调用 RegExp.prototype[Symbol.split]

    举例--以replace为例:替换符合正则表达式的字符

    var str="小明睡懒觉了"	==>将睡懒觉替换成起床
    
    //es5写法:
    str=str.replace(/睡懒觉/,"起床")
    
    //es6写法
    /睡懒觉/[Symbol.replace](str, '起床');
    

    修饰符

    u修饰符

    含义为“Unicode模式”,用来正确处理大于\uFFFF的Unicode字符

    y 修饰符

    y修饰符叫做“粘连”(sticky)修饰符。作用与g修饰符类似,也是全局匹配。但y修饰符确保匹配必须从剩余的第一个位置开始

    s 修饰符:dotAll 模式

    引入/s修饰符,使得.可以匹配任意单个字符

    //以前
    /foo.bar/.test('foo\nbar')	// false
    
    //现在
    /foo.bar/s.test('foo\nbar') // true
    

    属性

    • sticky属性:表示是否设置了y修饰符
    • flags属性:返回正则表达式的修饰符
    • dotAll属性,返回一个布尔值,表示该正则表达式是否处在dotAll模式

    3.数值的扩展

    方法

    • Number.isFinite(你要检测的值):检查一个数值是否为有限
    • Number.isNaN():检查一个值是否为NaN
    • Number.parseInt(),Number.parseFloat():ES6将全局方法parseInt()parseFloat(),移植到Number对象上面,行为完全保持不变
    • Number.isInteger():判断一个值是否为整数
    • Number.EPSILON:一个常量
    • 安全整数和Number.isSafeInteger()

    Math对象的扩展

    • Math.trunc方法用于去除一个数的小数部分,返回整数部分

      Math.trunc(4.9) // 4
      Math.trunc(-4.1) // -4
      Math.trunc(-0.1234) // -0
      
    • Math.sign方法用来判断一个数到底是正数、负数、还是零

      Math.sign(-5) // -1
      Math.sign(5) // +1
      Math.sign(0) // +0
      Math.sign(-0) // -0
      Math.sign(NaN) // NaN
      
    • Math.cbrt方法用于计算一个数的立方根

      Math.cbrt(2)  // 1.2599210498948734
      
    • Math.expm1(x)Math.exp(x) - 1

      Math.expm1(1)  // 1.718281828459045
      
    • Math.log1p(x)方法返回1 + x的自然对数,即Math.log(1 + x)。如果x小于-1,返回NaN

      Math.log1p(1)  // 0.6931471805599453
      Math.log1p(-1) // -Infinity
      Math.log1p(-2) // NaN
      
    • Math.log10(x)返回以10为底的x的对数。如果x小于0,则返回NaN

      Math.log10(100000) // 5
      
    • Math.log2(x)返回以2为底的x的对数。如果x小于0,则返回NaN

      Math.log2(3)       // 1.584962500721156
      Math.log2(2)       // 1
      
    • Math.sinh(x) 返回x的双曲正弦(hyperbolic sine)

    • Math.cosh(x) 返回x的双曲余弦(hyperbolic cosine)

    • Math.tanh(x) 返回x的双曲正切(hyperbolic tangent)

    • Math.signbit():判断一个值的正负,但是如果参数是-0,它会返回-0

    其他

    • 二进制和八进制表示法

    • 指数运算符(**)和赋值运算符(**=

      2 ** 2 // 4
      2 ** 3 // 8
      
      a **= 2;	// 等同于 a = a * a;
      

    4.数组的扩展

    静态方法

    • Array.from():用于将两类对象转为真正的数组:

      1.类似数组的对象(array-like object):所谓类似数组的对象,本质特征只有一点,即必须有length属性

      2.可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)

      //类似数组的对象
      let arrayLike = {
          '0': 'a',
          '1': 'b',
          '2': 'c',
          length: 3
      };
      
      let arr= Array.from(arrayLike); // ['a', 'b', 'c']
      
      //可遍历对象
      Array.from({ length: 3 });
      // [ undefined, undefined, undefined ]
      

      Array.from()接受第二个参数,作用类似于数组的map方法

      Array.from([1, 2, 3], (x) => x * x)
      // [1, 4, 9]
      
    • Array.of():将一组值,转换为数组。基本上可以用来替代Array()new Array()

      Array.of(3, 11, 8) // [3,11,8]
      

    数组实例的方法

    • copyWithin():在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组,即会修改当前数组

      //语法:---(开始替换的位置,开始读取的位置[可选],停止读取的位置[可选])
      Array.prototype.copyWithin(target, start = 0, end = this.length)
      
      [1, 2, 3, 4, 5].copyWithin(0, 3)	// [4, 5, 3, 4, 5] 从3号位复制到0号位
      
    • find():用于找出第一个符合条件的数组成员,它的参数是一个回调函数

      [1, 4, -5, 10].find((n) => n < 0)	// -5
      
    • findIndex():返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1

    • fill():使用给定值,填充一个数组

      ['a', 'b', 'c'].fill(7)		// [7, 7, 7]
      
      //接受第二个和第三个参数,用于指定填充的起始位置和结束位置
      ['a', 'b', 'c'].fill(7, 1, 2)	// ['a', 7, 'c']
      
    • entries():遍历数组-对键值对的遍历

      for (let [index, elem] of ['a', 'b'].entries()) {
        console.log(index, elem);
      }
      // 0 "a"
      // 1 "b"
      
    • keys():遍历数组-对键名的遍历

      for (let index of ['a', 'b'].keys()) {
        console.log(index);
      }
      // 0
      // 1
      
    • values():遍历数组-对键值的遍历

      for (let elem of ['a', 'b'].values()) {
        console.log(elem);
      }
      // 'a'
      // 'b'
      
    • includes():返回一个布尔值,表示某个数组是否包含给定的值。第二个参数表示搜索的起始位置,默认为0

      [1, 2, 3].includes(3, 3);  // false
      

    数组的空位

    数组的空位指,数组的某一个位置没有任何值。

    Array(3) // [, , ,]
    

    ES5对空位的处理大多数情况下会忽略空位

    1. forEach(), filter(), every() 和some()会跳过空位
    2. map()会跳过空位,但会保留这个值
    3. join()和toString()会将空位视为undefined,而undefined和null会被处理成空字符串
    
    // forEach方法
    [,'a'].forEach((x,i) => console.log(i)); // 1
    
    // filter方法
    ['a',,'b'].filter(x => true) // ['a','b']
    
    // every方法
    [,'a'].every(x => x==='a') // true
    
    // some方法
    [,'a'].some(x => x !== 'a') // false
    
    // map方法
    [,'a'].map(x => 1) // [,1]
    
    // join方法
    [,'a',undefined,null].join('#') // "#a##"
    
    // toString方法
    [,'a',undefined,null].toString() // ",a,,"
    

    ES6则是明确将空位转为undefined

    //Array.from方法
    Array.from(['a',,'b'])	// [ "a", undefined, "b" ]
    
    //扩展运算符(...)也会将空位转为undefined
    [...['a',,'b']]		// [ "a", undefined, "b" ]
    
    //copyWithin()会连空位一起拷贝
    [,'a','b',,].copyWithin(2,0) // [,"a",,"a"]
    
    //fill()会将空位视为正常的数组位置
    new Array(3).fill('a') // ["a","a","a"]
    
    //for...of循环也会遍历空位
    let arr = [, ,];
    for (let i of arr) {
      console.log(1);
    }
    // 1
    // 1
    
    entries()、keys()、values()、find()和findIndex()会将空位处理成undefined
    
    // entries()
    [...[,'a'].entries()] // [[0,undefined], [1,"a"]]
    
    // keys()
    [...[,'a'].keys()] // [0,1]
    
    // values()
    [...[,'a'].values()] // [undefined,"a"]
    
    // find()
    [,'a'].find(x => true) // undefined
    
    // findIndex()
    [,'a'].findIndex(x => true) // 0
    

    5.函数的扩展

    函数参数的默认值

    //1. 如何设置默认值
    function log(x, y = 'World') {
      console.log(x, y);
    }
    log('Hello') // Hello World
    
    //2. 参数变量是默认声明的,所以不能用let或const再次声明
    function foo(x = 5) {
      let x = 1; // error
      const x = 2; // error
    }
    
    //3. 使用参数默认值时,函数不能有同名参数
    function foo(x, x, y = 1) {
      // ...	
    }
    
    //4. 如果参数默认值是变量,那么每次都重新计算默认值表达式的值。参数默认值是惰性求值的
    let x = 99;
    function foo(p = x + 1) {
      console.log(p);
    }
    
    foo() 	// 100
    foo()	//还是100
    
    //默认值重新赋值才会改变
    x = 100;
    foo() // 101
    

    1. 与解构赋值默认值结合使用

    function foo({x, y = 5}) {
      console.log(x, y);
    }
    
    foo({}) // undefined, 5
    foo({x: 1}) // 1, 5
    foo() // TypeError: Cannot read property 'x' of undefined
    
    function fetch(url, { body = '', method = 'GET', headers = {} }) {
      console.log(method);
    }
    	
    fetch('http://example.com', {})	// "GET"
    fetch('http://example.com')	// 报错
    
    //上面的写法不能省略第二个参数,如果结合函数参数的默认值,就可以省略第二个参数
    function fetch(url, { method = 'GET' } = {}) {
      console.log(method);
    }
    
    fetch('http://example.com')		// "GET"
    

    区别

    // 写法一:函数参数的默认值是空对象,但是设置了对象解构赋值的默认值
    function m1({x = 0, y = 0} = {}) {
      return [x, y];
    }
    
    // 写法二:函数参数的默认值是一个有具体属性的对象,但是没有设置对象解构赋值的默认值
    function m2({x, y} = { x: 0, y: 0 }) {
      return [x, y];
    }
    

    2. 函数的 length 属性

    函数的length属性,将返回没有指定默认值的参数个数

    (function (a) {}).length // 1
    (function (a = 5) {}).length // 0
    (function (a, b, c = 5) {}).length // 2
    

    3. 作用域

    一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)

    对比:

    var x = 1;
    function f(x, y = x) {console.log(y)}
    f(2) // 2
    //解析:作用域里,默认值变量x指向第一个参数x,而不是全局变量x,所以输出是2
    
    let x = 1;
    function f(y = x) {let x = 2;console.log(y);}
    f() // 1
    //解析:作用域里,变量x本身没有定义,所以指向外层的全局变量x。函数调用时,函数体内部的局部变量x影响不到默认值变量x;但如果全局变量x不存在,就会报错
    

    4. rest参数

    ES6 引入 rest 参数(形式为“...变量名”),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中

    function add(...values) {
      let sum = 0;
      for (var val of values) {
        sum += val;
      }
      return sum;
    }
    
    add(2, 5, 3) // 10
    

    扩展运算符

    扩展运算符(spread)是三个点(...),好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列

    console.log(...[1, 2, 3])	// 1 2 3
    console.log(1, ...[2, 3, 4], 5)		// 1 2 3 4 5
    

    1. 应用:函数调用

    function add(x, y) {
      return x + y;
    }
    
    var numbers = [4, 38];
    add(...numbers) // 42
    

    2. 替代数组的apply方法

    // ES5的写法
    function f(x, y, z) {// ...}
    var args = [0, 1, 2];
    f.apply(null, args);
    
    // ES6的写法
    function f(x, y, z) {// ...
    }
    var args = [0, 1, 2];
    f(...args);
    
    // ES5的写法
    var arr1 = [0, 1, 2];
    var arr2 = [3, 4, 5];
    Array.prototype.push.apply(arr1, arr2);
    
    // ES6的写法
    var arr1 = [0, 1, 2];
    var arr2 = [3, 4, 5];
    arr1.push(...arr2);
    

    3. 应用:合并数组

    var arr1 = ['a', 'b'];
    var arr2 = ['c'];
    
    // ES5的合并数组
    arr1.concat(arr2);
    
    // ES6的合并数组
    [...arr1, ...arr2]
    

    4. 应用:与解构赋值结合

    const [first, ...rest] = [1, 2, 3, 4, 5];
    first // 1
    rest  // [2, 3, 4, 5]
    

    5. 应用:函数的返回值

    var dateFields = readDateFields(database);
    var d = new Date(...dateFields);
    //解析:上面代码从数据库取出一行数据,通过扩展运算符,直接将其传入构造函数Date
    

    6. 应用:字符串转数组

    [...'hello']	// [ "h", "e", "l", "l", "o" ]
    

    7. 应用:实现了Iterator接口的对象

    var nodeList = document.querySelectorAll('div');
    var array = [...nodeList];
    //任何Iterator接口的对象,都可以用扩展运算符转为真正的数组。扩展运算符可以将其转为真正的数组,原因就在于NodeList对象实现了Iterator接口
    

    8.应用

    //扩展运算符内部调用的是数据结构的Iterator接口,因此只要具有Iterator接口的对象,都可以使用扩展运算符,比如Map结构
    
    let map = new Map([
      [1, 'one'],
      [2, 'two'],
      [3, 'three'],
    ]);
    let arr = [...map.keys()]; // [1, 2, 3]
    

    严格模式

    《ECMAScript 2016标准》做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错

    name属性

    //函数的`name`属性,返回该函数的函数名
    function foo() {}
    foo.name // "foo"
    

    箭头函数

    var f = v => v;
    //等价于
    var f = function(v) {
      return v;
    };
    

    要点

    1. 如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分

      var f = () => 5;
      // 等同于
      var f = function () { return 5 };
      
      var sum = (num1, num2) => num1 + num2;
      // 等同于
      var sum = function(num1, num2) {
        return num1 + num2;
      };
      
    2. 如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回

      var sum = (num1, num2) => { return num1 + num2; }
      
    3. 所以如果箭头函数直接返回一个对象,必须在对象外面加上括号

      var getTempItem = id => ({ id: id, name: "Temp" });
      
    4. 箭头函数可以与变量解构结合使用

      const full = ({ first, last }) => first + ' ' + last;
      
      // 等同于
      function full(person) {
        return person.first + ' ' + person.last;
      }
      

    注意

    • 在箭头函数中,this指向是固定的。函数体内的this对象,就是定义时所在的对象
    • 不可以当作构造函数
    • 不可以使用arguments对象,但可以用Rest参数代替
    • 不可以使用yield命令,因此箭头函数不能用作Generator函数

    嵌套的箭头函数

    const plus1 = a => a + 1;
    const mult2 = a => a * 2;
    
    mult2(plus1(5))
    // 12
    

    绑定 this

    箭头函数并不适用于所有场合,所以ES7提出了“函数绑定”(function bind)运算符,用来取代callapplybind调用。函数绑定运算符是并排的两个双冒号(::),双冒号左边是一个对象,右边是一个函数

    foo::bar;
    // 等同于
    bar.bind(foo);
    
    foo::bar(...arguments);
    // 等同于
    bar.apply(foo, arguments);
    

    6.对象的扩展

    简洁表示法

    var birth = '2000/01/01';
    var Person = {
      name: '张三',
        
      //1. 属性简写----等同于birth: birth
      birth,	
        
      //2. 方法简写---等同于hello: function ()...
      hello() { console.log('我的名字是', this.name); }
    
    };
    

    属性名表达式

    // 方法一:标识符做属性名
    obj.foo = true;
    
    // 方法二:表达式做属性名
    obj['a' + 'bc'] = 123;
    

    ES5中,如果使用字面量方式定义对象,属性只能使用标识符定义

    var obj = {
      foo: true,
      abc: 123
    };
    

    ES6中,如果使用字面量方式定义对象,属性可以使用表达式定义

    let obj = {
      ['a' + 'bc']: 123
    };
    

    ES6中,方法名也可以用表达式定义

    let obj = {
      ['h' + 'ello']() {return 'hi';}
    };
    
    obj.hello() // hi
    

    对象方法的 name 属性

    const person = {
      sayName() {
        console.log('hello!');
      },
    };
    
    person.sayName.name   // "sayName"
    

    方法

    1. Object.is()

    背景:ES5比较两个值是否相等,只有两个运算符:相等运算符(==)和严格相等运算符(===)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0。JavaScript缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等

    Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致

    Object.is('foo', 'foo')	// true
    Object.is({}, {})	// false
    Object.is(+0, -0) // false
    Object.is(NaN, NaN) // true
    

    2. Object.assign()

    用于对象的合并。语法:Object.assign(target,source,source...),第一个参数是目标对象,后面的参数都是源对象

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

    这里是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用

    用途

    1. 为对象添加属性

      class Point {
        constructor(x, y) {
          Object.assign(this, {x, y});
        }
      }
      
    2. 为对象添加方法

      Object.assign(SomeClass.prototype, {
        someMethod(arg1, arg2) {···},
        anotherMethod() {···}
      });
      
      // 等同于下面的写法
      SomeClass.prototype.someMethod = function (arg1, arg2) {···};
      SomeClass.prototype.anotherMethod = function () {···};
      
    3. 克隆对象

      function clone(origin) {
        return Object.assign({}, origin);
      }
      
      //不过采用这种方法克隆,只能克隆原始对象自身的值,不能克隆它继承的值。如果想要保持继承链,可以采用下面的代码:
      
      function clone(origin) {
        let originProto = Object.getPrototypeOf(origin);
        return Object.assign(Object.create(originProto), origin);
      }
      
    4. 合并多个对象

      //在原数组上合并
      const merge =
        (target, ...sources) => Object.assign(target, ...sources);
      
      //合并成一个新数组
      const merge =
        (...sources) => Object.assign({}, ...sources);
      
    5. 为属性指定默认值

      const DEFAULTS = {
        logLevel: 0,
        outputFormat: 'html'
      };
      function processContent(options) {
        options = Object.assign({}, DEFAULTS, options);
        console.log(options);
        // ...
      }
      
      //上面代码中,DEFAULTS对象是默认值,options对象是用户提供的参数。Object.assign方法将DEFAULTS和options合并成一个新对象,如果两者有同名属性,则option的属性值会覆盖DEFAULTS的属性值。
      //注意:由于存在深拷贝的问题,DEFAULTS对象和options对象的所有属性的值,最好都是简单类型,不要指向另一个对象。否则,DEFAULTS对象的该属性很可能不起作用。比如:
      const DEFAULTS = {
        url: {
          host: 'example.com',
          port: 7070
        },
      };
      
      processContent({ url: {port: 8000} })
      // {
      //   url: {port: 8000}
      // }
      

    3. Object.keys()、Object.values()和Object.entries()

    遍历一个对象的补充手段,供for...of循环使用

    let {keys, values, entries} = Object;
    let obj = { a: 1, b: 2, c: 3 };
    
    for (let key of keys(obj)) {
      console.log(key); // 'a', 'b', 'c'
    }
    
    for (let value of values(obj)) {
      console.log(value); // 1, 2, 3
    }
    
    for (let [key, value] of entries(obj)) {
      console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
    }
    
    • Object.keys():方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值

      var obj = { foo: 'bar', baz: 42 };
      Object.keys(obj)	// ["foo", "baz"]
      
    • Object.values():只返回对象自身的可遍历属性,会过滤属性名为 Symbol 值的属性;如果Object.values方法的参数是一个字符串,会返回各个字符组成的一个数组

      var obj = { foo: 'bar', baz: 42 };
      Object.values(obj)	// ["bar", 42]
      
      Object.values('foo')	// ['f', 'o', 'o']
      
    • Object.entries():返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组

      var obj = { foo: 'bar', baz: 42 };
      Object.entries(obj)		// [ ["foo", "bar"], ["baz", 42] ]
      

    4. Object.getOwnPropertyDescriptors()

    返回指定对象所有自身属性(非继承属性)的描述对象

    const obj = {
      foo: 123,
      get bar() { return 'abc' }
    };
    
    Object.getOwnPropertyDescriptors(obj)
    // { foo:
    //    { value: 123,
    //      writable: true,
    //      enumerable: true,
    //      configurable: true },
    //   bar:
    //    { get: [Function: bar],
    //      set: undefined,
    //      enumerable: true,
    //      configurable: true } }
    

    属性的可枚举性

    Object.getOwnPropertyDescriptor():获取该属性的描述对象

    let obj = { foo: 123 };
    Object.getOwnPropertyDescriptor(obj, 'foo')
    //  {
    //    value: 123,
    //    writable: true,
    //    enumerable: true,
    //    configurable: true
    //  }
    

    enumerable属性,称为”可枚举性“;如果该属性为false,就表示某些操作会忽略当前属性。

    ES5有三个操作会忽略enumerablefalse的属性

    • for...in循环:只遍历对象自身的和继承的可枚举的属性
    • Object.keys():返回对象自身的所有可枚举的属性的键名
    • JSON.stringify():只串行化对象自身的可枚举的属性

    ES6中,Object.assign()只拷贝对象自身的可枚举的属性

    属性的遍历

    1. for...in:循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)
    2. Object.keys(obj):返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)
    3. Object.getOwnPropertyNames(obj):返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)
    4. Object.getOwnPropertySymbols(obj):返回一个数组,包含对象自身的所有Symbol属性
    5. Reflect.ownKeys(obj):返回一个数组,包含对象自身的所有属性,不管是属性名是Symbol或字符串,也不管是否可枚举

    以上方法遍历对象的属性都遵守同样的属性遍历的次序规则:

    • 首先遍历所有属性名为数值的属性,按照数字排序。
    • 其次遍历所有属性名为字符串的属性,按照生成时间排序。
    • 最后遍历所有属性名为Symbol值的属性,按照生成时间排序。

    原型对象

    • Object.setPrototypeOf():用来设置一个对象的prototype对象(原型对象),返回参数对象本身。它是 ES6 正式推荐的设置原型对象的方法

      //1. 格式
      Object.setPrototypeOf(object, prototype)
      //2. 用法
      var o = Object.setPrototypeOf({}, null);
      //等同于
      function (obj, proto) {
        obj.__proto__ = proto;
        return obj;
      }
      //3. 例子
      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
      
    • Object.getPrototypeOf():该方法与Object.setPrototypeOf方法配套,用于读取一个对象的原型对象

      //1. 格式
      Object.getPrototypeOf(obj);
      
      //2. 例子
      function Rectangle() {...}
      var rec = new Rectangle();
      Object.getPrototypeOf(rec) === Rectangle.prototype// true
                            
      Object.setPrototypeOf(rec, Object.prototype);
      Object.getPrototypeOf(rec) === Rectangle.prototype// false
      

    对象的扩展运算符

    1. 解构赋值

    let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
    x // 1
    y // 2
    z // { a: 3, b: 4 }
    //解析:从一个对象取值,相当于将所有可遍历的、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面
    

    2. 拷贝属性

    //用于取出参数对象的所有可遍历属性,拷贝到当前对象之中
    let z = { a: 3, b: 4 };
    let n = { ...z };
    n // { a: 3, b: 4 }
    
    let aClone = { ...a };
    // 等同于
    let aClone = Object.assign({}, a);
    

    Null 传导运算符

    编程实务中,如果读取对象内部的某个属性,往往需要判断一下该对象是否存在

    const firstName = message?.body?.user?.firstName || 'default';
    //解析:上面代码有三个?.运算符,只要其中一个返回null或undefined,就不再往下运算,而是返回undefined
    
  • 相关阅读:
    HAProxy从零开始到掌握
    学会这15点,让你分分钟拿下Redis数据库
    求一个字符串长度
    js时间戳怎么转成日期格式
    js获取url参数值的两种方式
    js 处理URL实用技巧
    jQuery操作radio、checkbox、select 集合
    js处理url的技巧和归纳
    ajax hash缓存
    jquery ajax跨域
  • 原文地址:https://www.cnblogs.com/sanhuamao/p/13595680.html
Copyright © 2020-2023  润新知