ES6 对象的扩展、Symbol

17 篇文章 0 订阅
15 篇文章 0 订阅

ES6 对象的扩展、Symbol

一、 ES6 对象的扩展

1、 属性的简洁表示法

  • ES6允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
var some='aaa';
var obj={some};
console.log(obj);   //{some:aaa}
//等同于 var obj={some:some}
//只写属性名,不写属性值。这时,属性值等于属性名所代表的变量
  • 除了属性简写,方法也可以简写。
var obj={
    func(){
    return 'hi!';
    }
}
//等同于
var obj={
    func:function(){
    return 'hi!';
    }
}
  • 如果某个方法的值是一个Generator函数,前面需要加上星号。

  • 注意,简洁写法的属性名总是字符串

2、属性名表达式

js中定义对象属性的方法有两种,即

//方法一
obj.some:'aaa';
//方法二
obj['a',+'i']:'bbb';

上面代码的方法一是直接用标识符作为属性名,方法二是用表达式作为属性名,这时要将表达式放在方括号之内。
但是,如果使用字面量方式定义对象(使用大括号),在ES5中只能使用方法一(标识符)定义属性。

var obj={
   some:'aaa';
   num:123;
}
  • ES6允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在方括号内。
var str='zzz';
var obj={
 [zzz]:'sss';
 ['a'+'b']:111;
}
  • 属性名表达式还可以用来定义方法名
  • 注:属性名表达式与简洁表示法,不能同时使用,会报错。
      var num = 123;
        var str = 'aaa';
        var obj = {
            [num]
        }
        //报错
     //正确的写法如下
      var num = 123;
        var str = 'aaa';
        var obj ={[num]:1111}

3,方法的name值

  • 函数的name属性,返回函数名。对象方法也是函数,因此也有name属性
  var obj = {
            name: 'kykyky',
            num: 111,
            func1() {
                console.log(this.name);
            },
            func2() {
                console.log(this.num);
            }
        }
        console.log(obj.func1.name);   //func1
        console.log(obj.func2.name);   //func2
  • 有两种特殊情况:bind方法创造的函数,name属性返回“bound”加上原函数的名字;Function构造函数创造 的函数,name属性返回“anonymous”。(anonymous 匿名)
  • 如果对象的方法是一个Symbol值,那么name属性返回的是这个Symbol值的描述。

4. Object.is()

  • Object.is() 用来比较两个值是否严格相等。它与严格比较运算符(===)的行为基本一致。
 console.log(Object.is('foo', 'foo'));  //true
 console.log(Object.is({}, {}));        //false
 console.log(Object.is(+0, -0));        //false
 console.log(Object.is(NaN, NaN));      //true
  • 不同之处只有两个:一是+0不等于-0,二是NaN等于自身。如上。
   //用ES5部署Object.is
        Object.defineProperty(Object, 'is', {
            value: function (x, y) {
                if (x === y) {
                    //针对+0不等于-0的情况
                    return x !== 0 || 1 / x === 1 / y;
                }
                return x !== x && y !== y;
            },
            configurable: true,
            enumerable: false,
            writable: true
        });

5. Object.assign()

(assign 分配 指派)

  • Object.assign()方法用来将源对象(source)的所有可枚举属性,复制到目标对象(target)。它至少需要两 个对象作为参数,第一个参数是目标对象,后面的参数都是源对象。只要有一个参数不是对象,就会抛出 TypeError错误。
        var target = { a: 1 };
        var sour1 = { b: 2 };
        var sour2 = { c: 3 };
        Object.assign(target, sour1, sour2);
        console.log(target);        //{a:1,b:2,c:3}
  • 如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
        var target = { a: 1 };
        var sour1 = { b: 2 };
        var sour2 = { b: 3 };
        Object.assign(target, sour1, sour2);
        console.log(target);      //32 {a: 1, b: 3}
  • Object.assign()只拷贝自身属性,不可枚举的属性(enumerable 为false)和继承的属性不会被拷贝。
  • 对于嵌套的对象,Object.assign()的处理方法是替换,而不是添加。
        var t = { a: { b: "111", c: 1223 } };
        var s = { a: {b:"hello"} };
        Object.assign(t, s);
        console.log(t);  // {a: {b:"hello"}}

6、属性的可枚举性

  • 对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOenPropertyDescriptor方法可以获取该属性的描述对象。
 var obj = { a: 111 };
   console.log(Object.getOwnPropertyDescriptor(obj, 'a'));
// {
 value: 111, 
 writable: true,
 enumerable: true, 
 configurable: true
 }

描述对象的enumerable属性,称为”可枚举性“,如果该属性为true ,就表示某些操作会忽略当前属性。
ES5有三个操作会忽略enumerable为false的属性:
for…in Object.keys() JSON.stringfy()
ES6新增了两个操作,会忽略enumerable为false的属性。
Object.assign():只拷贝对象自身的可枚举的属性
Reflect.enumerable() : 返回所有for… in循环会遍历的属性。
在以上五个操作中,只有 for…in和Reflect.enumerable() 会返回继承的属性。

7、属性的遍历

ES6一共有6种方法可以遍历对象的属性。

  1. for …in 循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)。
  2. Object.keys(obj) 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)。
  3. Object.getOwnPropertyNames(obj) 返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚 举属性)。
  4. Object.getOwnPropertySymbols(obj) 返回一个数组,包含对象自身的所有Symbol属性。
    5)Reflect.ownKeys(obj) 返回一个数组,包含对象自身的所有属性,不管是属性名是Symbol或字符串,也不管是否 可枚举。
    6))Reflect.enumerate(obj) 遍历对象自身的和继承的可枚举属性(不含Symbol属性)。 与for… in 循环相同。
  • 以上的6种方法遍历对象的属性,都遵守同样的属性遍历的次序规则。
    首先遍历所有属性名为数值的属性,按照数字排序。 其次遍历所有属性名为字符串的属性,按照生成时间排序。 后遍历所有属性名为Symbol值的属性,按照生成时间排序。

8、__ proto __属性,Object.setPrototypeOf(), Object.getPrototypeOf()

  • __proto__属性(前后各两个下划线),用来读取或设置当前对象的 prototype 对象。
  • Object.setPrototypeOf() 写操作
    Object.getPrototypeOf() 读操作b
    Object.create() 生成操作

9、对象的扩展运算符

  • 1,Rest参数
    Rest参数用于从一个对象取值,相当于将所有可遍历的、但尚未被读取的属性,分配到指定的对象上面。所有 的键和它们的值,都会拷贝到新对象上面。
 let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
        console.log(x);  //1
        console.log(y);  //2
        console.log(z);  //{a:3,b:4}
//上面代码中,变量z是Rest参数所在的对象。
//它获取等号右边的所有尚未读取的键(a和b),
//将它们和它们的 值拷贝过来。

注:
1)Rest参数的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么Rest参数拷 贝的是这个值的引用,而不是这个值的副本。
2)Rest参数不会拷贝继承自原型对象的属性。

  • 2, 扩展运算符…
    扩展运算符用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。
        let z = { a: 1, b: 2 };
        let n = { ...z };
        console.log(n);// {a: 1, b: 2}

这等同于使用Object.assign 方法。即

var k={a: 1, b: 2};
var obj={...k}
//即等于
var obj=Object.assign({},k);

二、Symbol

1、概述

ES5的对象属性名都是字符串,这容易造成属性名的冲突。ES6引入了一种新的原始数据类型Symbol,表示独一无二的值,它是JavaScript语言的第七种数据类型。

  • Symbol值通过Symbol 函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串, 另一种就是新增的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性 名产生冲突。
var m = Symbol();
console.log(typeof m);   //symbol

注:Symbol函数前不能使用new 命令,否则会报错。

        var s1 = Symbol('foo');
        var s2 = Symbol('bar');
        console.log(s1);   //Symbol(foo)
        console.log(s2);   // Symbol(bar)

        console.log(s1.toString()); //  Symbol(foo)
        console.log(s2.toString());//  Symbol(bar)

上面代码中,s1和s2是两个Symbol值。如果不加参数,它们在控制台的输出都是Symbol() ,不利于区分。 有了参数以后,就等于为它们加上了描述,输出的时候就能够分清,到底是哪一个值。

注意,Symbol 函数的参数只是表示对当前Symbol值的描述,因此相同参数的Symbol函数的返回值是不相等的。

  • Symbol值不能与其他类型的值进行运算,会报错。
  • Symbol值可以显式转为字符串。
  • Symbol值也可以转为布尔值,但是不能转为数值。

2、作为属性名的Symbol

  • 由于每一个Symbol值都是不相等的,这意味着Symbol值可以作为标识符,用于对象的属性名,就能保证不会 出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。
  • Symbol值作为对象属性名时,不能用点运算符。
        var mysymbol = Symbol();
        var a = { [mysymbol]: 123 };
        console.log(a.mysymbol);    //undefined
        console.log(a[mysymbol]);   //123
  • 同理,在对象的内部,使用Symbol值定义属性时,Symbol值必须放在方括号之中。如果mysymbol不放在方括号中,该属性的键名就是字符串mysymbol ,而不是mysymbol 所代表的那个Symbol值。

4. 属性名的遍历

  • Symbol作为属性名,该属性不会出现在for…of for…in循环中。但是,它也不是私有属性,有一 个Object.getOenPropertySymbols()方法,可以获取指定对象的所有Symbol属性名。Object.getOenPropertySymbols()方法返回一个数组,成员是当前对象的所有用作属性名的Symbol值。

5. Symbol.for(),Symbol.keyFor()

  • 有时,我们希望重新使用同一个Symbol值,Symbol.for()方法可以做到这一点。它接受一个字符串作为参数, 然后搜索有没有以该参数作为名称的Symbol值。如果有,就返回这个Symbol值,否则就新建并返回一个以该 字符串为名称的Symbol值。
        var s1 = Symbol.for('foo');
        var s2 = Symbol.for('foo');
        console.log(s1 === s2);    //true

上面代码中,s1和s2都是Symbol值,但是它们都是同样参数的Symbol.for方法生成的,所以实际上是同一个 值。
注:Symbol.for ()与Symbol ()这两种写法,都会生成新的Symbol。它们的区别是,前者会被登记在全局环境中供 搜索,后者不会。Symbol.for ()不会每次调用就返回一个新的Symbol类型的值,而是会先检查给定的key是 否已经存在,如果不存在才会新建一个值。比如,如果你调用Symbol.for ()30次,每次都会返回同一个 Symbol值,但是调用Symbol () 30次,会返回30个不同的Symbol值。

  • Symbol.keyFor方法返回一个已登记的Symbol类型值的key。
    由于Symbol () 写法没有登记机制,所以每次调用都会返回一个不同的值。Symbol.keyFor方法返回一个已登记的Symbol类型值的key。
    如下:
    var s1 = Symbol.for('aaa');
    console.log(Symbol.keyFor(s1));     //aaa
    var s2 = Symbol('bbb');
    console.log(Symbol.keyFor(s2));     //undefined

变量s2属于未登记的Symbol值,所以返回
undefined

6. 内置的Symbol值

除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。

  • Symbol.hasInstance
    对象的Symbol.hasInstance 属性,指向一个内部方法。该对象使用 incetanceof 运算符时,会调用这个方法, 判断该对象是否为某个构造函数的实例。比如,foo incetanceof Foo在语言内部,实际调用的是 Foo[Symbol.hasInstance] (foo)。

  • Symbol.isConcatSpreadable
    对象的Symbol.isConcatSpreadable 属性等于一个布尔值,表示该对象使用Array.prototype.concat()时,是否可以展开。

  • Symbol.species
    对象的Symbol.species属性,指向一个方法。该对象作为构造函数创造实例时,会调用这个方法。即如果this.constractor[Symbol.species]存在,就会使用这个属性作为构造函数,来创造新的实例对象。

  • Symbol.match
    对象的Symbol.match 属性,指向一个函数。当执行str.match(myObject)时,如果该属性存在,会调用它,返 回该方法的返回值。

  • Symbol.replace
    对象的Symbol.replace 属性,指向一个方法,当该对象被String.prototype.replace方法调用时,会返回该方法的返回值。

  • Symbol.search
    对象的Symbol.search属性,指向一个方法,当该对象被String.prototype.search 方法调用时,会返回该方 法的返回值。

  • Symbol.split
    对象的Symbol.split 属性,指向一个方法,当该对象被String.prototype.split 方法调用时,会返回该方法 的返回值。

  • Symbol.iterator
    对象的Symbol.iterator属性,指向该对象的默认遍历器方法,即该对象进行for…of循环时,会调用这个方 法,返回该对象的默认遍历器。

  • Symbol.toPrimitive
    对象的Symbol.toPrimitive 属性,指向一个方法。该对象被转为原始类型的值时,会调用这个方法,返回该对 象对应的原始类型值。
    Symbol.toPrimitive 被调用时,会接受一个字符串参数,表示当前运算的模式,一共有三种模式。
    Number:该场合需要转成数值
    String:该场合需要转成字符串
    Default:该场合可以转成数值,也可以转成字符串

  • Symbol.toStringTag
    对象的Symbol.toStringTag属性,指向一个方法。在该对象上面调用Object.prototype.toString方法时,如 果这个属性存在,它的返回值会出现在toString 方法返回的字符串之中,表示对象的类型。也就是说,这个属 性可以用来定制 [object Object]或 [object Array]中object后面的那个字符串。

  • Symbol.unscopables

对象的Symbol.unscopables属性,指向一个对象。该对象指定了使用 with 关键字时,哪些属性会被 with 环境 排除。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值