ECMAScript 6学习(五)

本人是android开发的,由于最近React Native的火热,再加上自己完全不懂JS的语法,俗话说的好"落后就要挨打",虽然不知道谁说的,不过很有道理.

学习书籍《ECMAScript 6 入门 》

Symbol和Set、Map


Symbol

ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,前六种是:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。

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

Symbol 作为属性名,该属性不会出现在for...infor...of循环中,也不会被Object.keys()Object.getOwnPropertyNames()JSON.stringify()返回。它通过Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。

var obj = {};

var a = Symbol('a');

var b = Symbol('b');

obj[a] = 'Hello';

obj[b] = 'World';

var objectSymbols = Object.getOwnPropertySymbols(obj);

objectSymbols

// [Symbol(a), Symbol(b)]

另一个新的API,Reflect.ownKeys方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。

let obj = {

[Symbol('my_key')]: 1,

enum: 2,

nonEnum: 3

};

Reflect.ownKeys(obj)

//  ["enum", "nonEnum", Symbol(my_key)]


Symbol.for(),Symbol.keyFor()

有时,我们希望重新使用同一个Symbol值,Symbol.for方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的Symbol值。如果有,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值。

var s1 = Symbol.for('foo');

var s2 = Symbol.for('foo');

s1 === s2 // true

Symbol.for()Symbol()这两种写法,都会生成新的Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。Symbol.for()不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值。比如,如果你调用Symbol.for("cat")30次,每次都会返回同一个 Symbol 值,但是调用Symbol("cat")30次,会返回30个不同的Symbol值。

Symbol.for("bar") === Symbol.for("bar")

// true

Symbol("bar") === Symbol("bar")

// false

Symbol.keyFor方法返回一个已登记的 Symbol 类型值的key,未登记的Symbol值,返回undefined.

var s1 = Symbol.for("foo");

Symbol.keyFor(s1) // "foo"

var s2 = Symbol("foo");

Symbol.keyFor(s2) // undefined

需要注意的是,Symbol.for为Symbol值登记的名字,是全局环境的,可以在不同的 iframe 或 service worker 中取到同一个值。


内置的Symbol值

Symbol.hasInstance  当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法。

class Even {

static [Symbol.hasInstance](obj) {

     return Number(obj) % 2 === 0;

    }

}

1 instanceof Even // false

2 instanceof Even // true

12345 instanceof Even // false


Symbol.isConcatSpreadable  表示该对象使用Array.prototype.concat()时,是否可以展开。

Symbol.isConcatSpreadable 属性等于trueundefined,可以展开。

Symbol.isConcatSpreadable 属性等于false,不可以展开。

let arr1 = ['c', 'd'];

['a', 'b'].concat(arr1, 'e') // ['a', 'b', 'c', 'd', 'e']

arr1 [Symbol.isConcatSpreadable] // undefined

let arr2 = ['c', 'd'];

arr2[Symbol.isConcatSpreadable] = false;

['a', 'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']


Symbol.species 指向当前对象的构造函数。

class MyArray extends Array {

static get [Symbol.species]() { return Array; }

}

var a = new MyArray(1,2,3);

var mapped = a.map(x => x * x);

mapped instanceof MyArray // false

mapped instanceof Array // true

上面代码中,由于构造函数被替换成了Array。所以,mapped对象不是MyArray的实例,而是Array的实例。


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

String.prototype.match(regexp)

// 等同于

regexp[Symbol.match](this)

class MyMatcher {

   [Symbol.match](string) {

       return 'hello world'.indexOf(string);

    }

}

'e'.match(new MyMatcher()) // 1


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

Symbol.replace方法会收到两个参数,第一个参数是replace方法正在作用的对象,下面例子是Hello,第二个参数是替换后的值,上面例子是World

const x = {};

x[Symbol.replace] = (...s) => console.log(s);

'Hello'.replace(x, 'World') // ["Hello", "World"]


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

String.prototype.search(regexp)

// 等同于

regexp[Symbol.search](this)

class MySearch {

    constructor(value) {

         this.value = value;

    }

     [Symbol.search](string) {

          return string.indexOf(this.value);

      }

}

'foobar'.search(new MySearch('foo')) // 0


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

class MySplitter {

    constructor(value) {

        this.value = value;

    }

[Symbol.split](string) {

   var index = string.indexOf(this.value);

   if (index === -1) {

         return string;

    }

   return [

     string.substr(0, index),

     string.substr(index + this.value.length)

   ];

  }

}

'foobar'.split(new MySplitter('foo'))

// ['', 'bar']

'foobar'.split(new MySplitter('bar'))

// ['foo', '']

'foobar'.split(new MySplitter('baz'))

// 'foobar'


Symbol.iterator 指向该对象的默认遍历器方法。

var myIterable = {};

myIterable[Symbol.iterator] = function* () {

      yield 1;

      yield 2;

      yield 3;

};

[...myIterable] // [1, 2, 3]


Symbol.toPrimitive 指向一个方法。该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。

Symbol.toPrimitive被调用时,会接受一个字符串参数,表示当前运算的模式,一共有三种模式。

Number:该场合需要转成数值

String:该场合需要转成字符串

Default:该场合可以转成数值,也可以转成字符串

let obj = {

[Symbol.toPrimitive](hint) {

     switch (hint) {

              case 'number':

                       return 123;

              case 'string':

                       return 'str';

              case 'default':

                        return 'default';

               default:

                        throw new Error();

            }

       }

};

2 * obj // 246

3 + obj // '3default'

obj == 'default' // true

String(obj) // 'str'


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

class Collection {

    get [Symbol.toStringTag]() {

           return 'xxx';

     }

}

var x = new Collection();

Object.prototype.toString.call(x) // "[object xxx]"

ES6新增内置对象的Symbol.toStringTag属性值如下。

JSON[Symbol.toStringTag]:'JSON'

Math[Symbol.toStringTag]:'Math'

Module对象M[Symbol.toStringTag]:'Module'

ArrayBuffer.prototype[Symbol.toStringTag]:'ArrayBuffer'

DataView.prototype[Symbol.toStringTag]:'DataView'

Map.prototype[Symbol.toStringTag]:'Map'

Promise.prototype[Symbol.toStringTag]:'Promise'

Set.prototype[Symbol.toStringTag]:'Set'

%TypedArray%.prototype[Symbol.toStringTag]:'Uint8Array'等

WeakMap.prototype[Symbol.toStringTag]:'WeakMap'

WeakSet.prototype[Symbol.toStringTag]:'WeakSet'

%MapIteratorPrototype%[Symbol.toStringTag]:'Map Iterator'

%SetIteratorPrototype%[Symbol.toStringTag]:'Set Iterator'

%StringIteratorPrototype%[Symbol.toStringTag]:'String Iterator'

Symbol.prototype[Symbol.toStringTag]:'Symbol'

Generator.prototype[Symbol.toStringTag]:'Generator'

GeneratorFunction.prototype[Symbol.toStringTag]:'GeneratorFunction'


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

// 没有 unscopables 时

 class MyClass {

     foo() { return 1; }

}

var foo = function () { return 2; };

with (MyClass.prototype) {

     foo(); // 1

}


// 有 unscopables 时

class MyClass {

foo() { return 1; }

   get [Symbol.unscopables]() {

      return { foo: true };

    }

}

var foo = function () { return 2; };

with (MyClass.prototype) {

    foo(); // 2

}

上面代码通过指定Symbol.unscopables属性,使得with语法块不会在当前作用域寻找foo属性,即foo将指向外层作用域的变量。


Set和Map

这两个数据结构我就不多说和java差不多.

1.Set

Set 类似于数组,但是成员的值都是唯一的,没有重复的值。Set 函数可以接受一个数组(或类似数组的对象)作为参数,用来初始化。

Set 书写格式如下:

const s = new Set();  //Set初始化;

var set = new Set([1,2,3,4,4]); // Set初始化并接受一个数组(或类似数组的对象);

[2,3,5,4,5,2,2].forEach (x => s.add(x)); // Set通过add添加数据

Set实例的属性和方法

属性:

 ---- Set.prototype.constructor:构造函数,默认就是Set函数。

 ---- Set.prototype.size:返回Set实例的成员总数。

方法:

-- 操作方法(用于操作数据)

 ---- add(value):添加某个值,返回Set结构本身。

 ---- delete(value):删除某个值,返回一个布尔值,表示删除是否成功。

 ---- has(value):返回一个布尔值,表示该值是否为Set的成员。

 ---- clear():清除所有成员,没有返回值。


-- 遍历方法(用于遍历成员)

 ---- keys():返回键名的遍历器

 ---- values():返回键值的遍历器

 ---- entries():返回键值对的遍历器

 ---- forEach():使用回调函数遍历每个成员


2.WeakSet

WeakSet结构与Set类似,也是不重复的值的集合。但是,它与Set有两个区别。

首先,WeakSet的成员只能是对象,而不能是其他类型的值。

其次,WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中。这个特点意味着,无法引用WeakSet的成员,因此WeakSet是不可遍历的

WeakSet可以接受一个数组或类似数组的对象作为参数。

var ws = new WeakSet();

var a = [[1,2],[3,4]]; 

var ws = new WeakSet(a);

注意,是a数组的成员成为WeakSet的成员,而不是a数组本身。这意味着,数组的成员只能是对象。

WeakSet 结构有以下三个方法。

 ---- WeakSet.prototype.add(value):向WeakSet实例添加一个新成员。

 ---- WeakSet.prototype.delete(value):清除WeakSet实例的指定成员。

 ---- WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在.


3.Map

Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。如果你需要“键值对”的数据结构,Map比Object更合适。

Map实例的属性和方法

size属性:返回Map结构的成员总数。


set(key, value)

       set方法设置key所对应的键值,然后返回整个Map结构。如果key已经有值,则键值会被更新,否则就新生成该键。

       set方法返回的是Map本身,因此可以采用链式写法。

let map = new Map()

.set(1, 'a')

.set(2, 'b')

.set(3, 'c');


get(key)

        get方法读取key对应的键值,如果找不到key,返回undefined

var m = new Map();

var hello = function() {console.log("hello");}

m.set(hello, "Hello ES6!") // 键是函数

m.get(hello)  // Hello ES6!


has(key)

        has方法返回一个布尔值,表示某个键是否在Map数据结构中。

var m= new Map();

m.set("edition",6);

m.has("edition") // true

m.has("years")  // false


delete(key)

        delete方法删除某个键,返回true。如果删除失败,返回false。

var m = new Map();

m.set(undefined, "nah");

m.has(undefined)    // true

m.delete(undefined)

m.has(undefined)      // false


clear()

        clear方法清除所有成员,没有返回值。


Map遍历方法

 ---- keys():返回键名的遍历器。

 ---- values():返回键值的遍历器。

 ---- entries():返回所有成员的遍历器。

 ---- forEach():遍历Map的所有成员。


4.WeakMap

WeakMap结构与Map结构基本类似,唯一的区别是它只接受对象作为键名(null除外),不接受其他类型的值作为键名,而且键名所指向的对象,不计入垃圾回收机制,不可遍历。

WeakMapMap在API上的区别主要是两个,一是没有遍历操作(即没有key()values()entries()方法),也没有size属性;二是无法清空,即不支持clear方法。这与WeakMap的键不被计入引用、被垃圾回收机制忽略有关。因此,WeakMap只有四个方法可用:get()set()has()delete()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容

  • 一、let 和 constlet:变量声明, const:只读常量声明(声明的时候赋值)。 let 与 var 的...
    dadage456阅读 737评论 0 0
  • //Clojure入门教程: Clojure – Functional Programming for the J...
    葡萄喃喃呓语阅读 3,501评论 0 7
  • 1.概述 ES5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象...
    赵然228阅读 771评论 2 10
  • [TOC] 参考阮一峰的ECMAScript 6 入门参考深入浅出ES6 let和const let和const都...
    郭子web阅读 1,745评论 0 1
  • 强大的for-of循环 ES6不会破坏你已经写好的JS代码。目前看来,成千上万的Web网站依赖for-in循环,其...
    Awe阅读 7,483评论 2 7