美文网首页
读《深入理解ES6》

读《深入理解ES6》

作者: BeADre_wang | 来源:发表于2018-01-26 19:09 被阅读0次

    第一章:块级作用域绑定

    块级声明

    1.var声明及变量提升机制:在函数作用域或者全局作用域中通过关键字var声明的变量,无论实际上是在哪里声明的,都会被当成在当前作用域顶部声明的变量。变量value的声明会被提升到函数顶部,而初始化操作依旧留在原处执行。而如果将var改为let的话,就可以把变量的作用域限制在当前代码块中。

    2. 禁止重声明:在不用条件语句的情况下,如果一个变量已经被声明,那么不能用let重新声明它。

    3.const声明:const声明的常量必须初始化。const声明的常量与let一样都只在当前作用域有效。在同一作用域用const声明已经存在的变量也会导致错误。不能给const定义的常量重新赋值。用const声明的对象可以修改对象中的值,但不能修改绑定对象。

    4.临时死区(TDZ):JS引擎在扫描代码发现变量声明时,如果是用var声明则将其提升到当前作用域顶部,如果是let和const声明则会放到TDZ中。访问TDZ中的变量会报错,只有执行过变量声明的语句后,变量才会从TDZ中移出,方可正常访问。

    循环中的块作用域绑定

    1.在for循环中使用let声明变量可以让循环外的地方无法访问该变量;

    2.循环中的函数:如下列子。将var改为let的话,就可以直接正确的输出0到9,对于for-in和for-of是一样的。(书上说到let声明在循环内部的行为是标准中专门定义的,它不一定与let的不提升特性相关)

    3.循环中的const声明:如果在for循环中用const来声明常量,则只能执行一次循环就会报错,如上面例子,将var改为const则该循环只能执行一次。

    全局块作用域绑定

    通常情况下使用var定义全局变量时,该变量都会自动成为window的属性,如果window有了该属性的话新定义的属性会将其覆盖。而使用let或const定义的量不会成为window的属性,所以也不可能覆盖window中同名的属性。例如:let alert = 3;window.alert(alert)就能成功弹出3;所以如果要创建全局变量,为了避免全局污染,尽量使用let或const。

    使用块级绑定的最佳实践是:默认使用const,只有在确实需要改变变量的值时使用let。这样就可以在某种程度实现代码的不可变,从而防止错误的产生。

    第二章:字符串和正则表达式

    1.字符串中的字串识别:①includes()方法:如果在字符串中检测到指定文本返回true,否则返回false;②startsWith()方法:如果在字符串起始部分检测到指定文本返回true,否则返回false;③endsWith()方法:如果在字符串结束部分检测到指定文本返回true,否则返回false;以上3个方法都接收2个参数,第一个是指定要搜索的文本,第二个是可选的开始搜索的位置的索引值。④repeat()方法:接收一个number参数,表示要将指定字符串重复次数。如"abc".repeat(2)为"abcabc"。(与前三种方法无关)

    第三章:函数

    函数形参的默认值

    1:ES5和ES6中的默认参数

    2:默认参数值对arguments对象的影响

    3:函数参数表达式

    4:默认参数的临时死区:下面例子报错的原因是因为当x初始化的时候y尚未初始化,此时的y处于临时死区中,所以会抛出错误,正如第一章中提到的临时死区一样,所有引用临时死区中绑定的行为都会报错。

    处理无命名参数

    1:ES5中的无命名参数:缺点是一:不易发现pick函数可以接受任意数量参数;二:当需要查找拷贝的属性名称时,需要从索引1而不是索引0开始查找。

    2:ES6中不定参数:限制是每个函数最多只能声明一个不定参数并且一定要放在所有参数的末尾;其次是不定参数不能用于对象字面量setter中,因为setter的参数有且只能一个。而在不定参数中,参数的量可以无限多。

    展开运算符

    在ES5中,如果需要查找并返回一个数组中的最大值,那么只能用for循环或者使用apply方法(Math.max.apply(Math,array),使用call的话需要将array中的值一个一个传入)。而在ES6中直接用Math.max(...array)就能返回最大值,并且展开运算符可以和其他正常传入的参数混合使用。还可以直接用展开运算符连接数组

    块级函数

    在ES5严格模式下,在代码块内部声明函数时会抛出错误。在ES6中会将代码块内部声明的函数当作一个块级声明,在严格模式下,该函数只会被提升到代码块的最顶部(用let声明则无法提升),在代码块外无法访问。而在非严格模式下,该函数会被提升至外围函数或全局作用域的顶部。

    箭头函数

    1:与常规JS函数的不同:①没有this、super、arguments和new.target的绑定,这些值由外围最近一层非箭头函数决定。②不能通过new关键字调用 箭头函数没有[[Construct]]方法,所以不能被用作构造函数,如果用new关键字调用会报错。③没有原型  由于不能用new关键字调用,因而没有构建原型的需求,所以箭头函数不存在prototype这个属性。④不能改变this绑定  函数内部的this值不能被改变,在函数生命周期内始终保持一致。⑤不支持arguments对象  箭头函数没有arguments的绑定,所以只能通过命名参数和不定参数两种形式访问函数的参数。⑥不支持重复的命名参数  无论是严格还是非严格模式都不支持重复的命名函数;而在传统模式下,只有严格模式才不支持重复的命名函数。

    2:语法

    3:创建立即执行函数表达式

    4:箭头函数没有this绑定:箭头函数中没有this绑定,必须通过查找作用域链来决定其值。如果箭头函数被非箭头函数包含,则this绑定的是最近一层非箭头函数的this;否则this的值会被设置为全局对象。如下例:箭头函数中的this绑定的是init函数中的this,所以起到了和注释中bind一样的作用。

    5:箭头函数没有arguments绑定

    尾调用优化

    1:ES6中的尾调用优化:条件函数不是一个闭包。在函数内部,尾调用是最后一条语句。尾调用的结果作为函数值返回。满足以上3个条件,可被JS引擎自动优化。递归函数是其最主要应用的场景,此时尾调用优化的效果最显著。

    第四章:扩展对象的功能性

    新增方法

    1:Object.is()方法:接收2个参数并且比较他们的值与类型是否相等(相当于 ===),相等返回true否则返回false

    2:Object.assign方法:第一个参数为目标对象,之后的任意数量参数为源对象,并按指定顺序将属性复制到目标对象中。如果出现同名属性则会发生属性值覆盖的情况。

    增强对象原型

    1:改变对象原型:Object.setPrototypeOf()方法:其接收2个参数:被改变原型的对象及替代第一个参数原型的对象。

    2:简化原型访问的super引用:super引用相当于指向对象原型的指针,可以使用其调用对象原型上的方法,此时的this绑定会自动设置为当前作用域的this值。

    第五章:解构:使数据访问更简单

    对象解构

    如下例:其中let定义的变量的名称需和对象中的属性名相同,并且使用var,let,const解构声明变量,则必须提供初始化(等号右边的值),否则报错

    1:解构赋值&&默认值:如下例:函数outPutInfo()中打印true是因为解构赋值表达式的值与表达式右侧(也就是等号右侧,并且右侧的值不能为null和undefined,不然会报错)的值相等,因而传入的值等同于node;下面打印type和name为对象里属性的值是因为变量type和name的值被修改了;最后打印的age为3是因为给其默认值设置为3,如果不设置默认值并且在node对象中没有age属性的话,其值为undefined。

    2:为非同名局部变量赋值

    3:嵌套对象解构

    数组解构

    当通过var、let、const声明数组绑定解构时,必须提供一个初始化程序,这与对象解构的规定相同。

    1:解构赋值

    ①已被定义的变量赋值:与对象解构赋值不同的是数组解构不需要加小括号

    ②交换两个变量的值:不需要使用第三个变量

    2:默认值

    3:嵌套数组解构

    4:不定元素&&数组克隆:在被解构的数组中,不定元素和不定参数一样必须是最后一个条目,在后面继续添加逗号被报错

    ①不定元素

    ②数组克隆

    混合解构

    解构参数

    第六章:Symbol和Symbol属性

    1:为什么提出Symbol:假设我们使用别人给我们提供的一个对象,我们并不清楚这个对象中有哪些属性,所以当我们新增属性的时候可能会与原属性重名从而覆盖原属性。显然我们是不希望这种情况发生的。所以,我们需要确保每 个属性名都是独一无二的,这样就可以防止属性名的冲突了。因此,ES6里就引入了Symbol,用它来产生一个独一无二的值。

    2:描述:Symbol是JavaScript中的一个新的原始类型,用于创建必须通过Symbol才能引用的属性。尽管这些属性不是完全私有的,但是它们比较难以被意外覆盖而改变,如此一来,这些属性非常适合那些需要一定程度保护的功能。

    创建Symbol

    由于Symbol是原始值,因此调用new Symbol()会导致程序抛出错误。其中,Symbol函数接收一个可选参数,用于添加一段文本来描述即将创建的Symbol,这段描述不可用于属性访问。Symbol的检测可用typeof来检测

    Symbol共享体系

    1:Symbol.for()方法:接收一个参数,也就是即将创建的Symbol的字符串标识符,这个参数同样被用作Symbol的描述

    2:Symbol.keyFor()方法:在全局注册表中检索与Symbol有关的键。全局注册表是一个类似全局作用域的共享环境

    Symbol与类型强制转换

    其中,不能将Symbol强制转换为字符串。但是可以显式转换为字符串和布尔值number类型无论如何都不能转换

    Symbol属性检索:使用Object.getOwnPropertySymbols(obj)方法

    通过well-known Symbol暴露内部操作

    1.Symbol.hasInstance:一个在执行instanceof时调用的内部方法,用于检测对象的继承信息。每一个函数中都有一个该方法。

    2.Symbol.isConcatSpreadable:一个布尔值,用于表示当传递一个集合作为Array.prototype.concat()方法的参数时,是否应该将集合内的元素规整到同一层级。其中当该属性为true时,表示对象有length属性和数字键,其数值型属性值该被独立添加到concat()调用的结果中。

    3.Symbol.iterator:一个返回迭代器(将在第8章讲解)的方法。

    4.Symbol.match:一个在调用String.prototype.match()方法时调用的方法,用于比较字符串。

    5.Symbol.replace:一个在调用String.prototype.replace()方法时调用的方法,用于替换字符串中的字串。

    6.Symbol.search:一个在调用String.prototype.search()方法时调用的方法,用于在字符串中定位字串。

    7.Symbol.split:一个在调用String.prototype.split()方法时调用的方法,用于分割字符串。

    8.Symbol.species:用于创建派生对象(将在第9章讲解)的构造函数。

    9.Symbol.toPrimitive:一个返回对象原始值的方法。

    10.Symbol.toStringTag:一个在调用Object.prototype.toString()方法时使用的字符串,用于创建对象描述。

    11.Symbol.unscopables:一个定义了一些不可被with语句引用的对象属性名称的对象集合。

    第七章:Set集合与Map集合

    ES5中的Set集合与Map集合

    问题:set的问题是当某个值为0时,如下例子其会去执行else中的代码(用in操作符可以不用检测值就能发现属性是否存在,但是只有当该对象的原型为null时才有用,因为in操作符会检索对象的原型);map的问题是当用对象作为属性名时,由于对象的属性名必须是字符串,所以key1、key2被转换为对象对应的默认字符串“[object object]”,所以map[key1]和map[key2]引用的是同个属性。

    ES6中的Set集合

    1.创建Set集合并添加、检查、移除元素:实际上,Set构造函数可以接受所有可迭代对象作为参数(数组、Set集合、Map集合)

    2.Set集合的forEach()方法:该方法同样接收2个参数:第一个为运行的函数,函数包括三个参数①传入set中数组的值;②与第一个参数相同的值;③被遍历的set集合本身。该函数与数组中forEach中函数参数的不同是第二个参数是值的索引值。第二个和数组中forEach一样:运行执行函数的作用域对象。

    3:将Set集合转化为数组:用展开运算符实现。有数组去重的功能。

    4.WeakSet集合(弱引用Set集合):因为Set集合是强引用,可能会导致内存泄漏,所以引入WeakSet集合。其中大部分操作都和Set集合相同,不同点创建方式为let set = new WeakSet();在WeakSet的实例中,如果想add()方法传入非对象参数会导致程序报错,而向has()和delete()方法传入非对象参数会返回false;WeakSet集合不可迭代,所以不能用于for-of循环;WeakSet集合不暴露任何迭代器(如keys()和values()方法),所以无法通过程序本身来检测其中内容;WeakSet集合不支持forEach()方法;WeakSet集合不支持size属性

    ES6中的Map集合

    1.创建Map集合并添加、获取、检查、移除元素以及初始化:其中键名和键值支持所有类型

    2.Map集合的forEach()方法:回调函数同样接收三个参数:①传入map中数组的键值;②键值对应的键名;③被遍历的Map集合本身。forEach中第二个参数同样是运行执行函数的作用域对象。

    3.WeakMap集合(弱引用Map集合):其最大的用途是保存web页面中的DOM元素;WeakMap集合中的键名必须是对象,否则报错。键值可以是任意类型。该类型只支持三个方法:set(),has(),delete()

    第八章:迭代器和生成器

    什么是迭代器

    迭代器是一种特殊对象,它具有一些专门为迭代过程设计的专有接口,所有迭代器对象都有一个next()方法,每次调用都返回一个结果对象。结果对象有2个属性:一个是value,表示下一个将要返回的值,如果没有值了返回undefined;另一个是done,它是一个布尔值,当没有更多可返回数据时返回true。下例是ES5语法创建的迭代器:

    什么是生成器

    生成器是一种返回迭代器的函数,通过function关键字后的星号(*)来表示,函数中会用到新的关键字yield。星号可以紧挨function关键字,也可以在中间添一个空格。如上面例子可以重写为下面这样:其中,函数createIterator前的星号表明它是一个生成器;而yield关键字是ES6新特性,通过它来指定调用迭代器的next()方法时的返回值以及返回顺序。并且每执行完一条yield语句后函数就会自动停止执行,所以下面需要不停的调用next方法。

    1.yield关键字:除上面所讲特性外,还可以使用yield关键字可以返回任意值或者表达式,所以可以通过生成器函数批量给迭代器添加元素。其限制为只可在生成器内部使用,其他地方会导致程序抛出错误,即便在生成器内部的函数也同样如此

    2.生成器函数表达式:上面讲了函数声明的生成器创建方法,而生成器的函数表达式创建方法为let createIterator = function *(){},将星号加载function关键字和小括号中间即可。最后不能用箭头函数来创建生成器

    可迭代对象和for-of循环

    在ES6中,所有的集合对象(数组、Set集合及Map集合)和字符串都是可迭代对象,这些对象中都有默认的迭代器。可迭代对象具有Symbol.iterator属性,该属性通过指定的函数返回一个作用于附属对象的迭代器。

    下例这段for-of循环代码通过调用values数组的Symbol.iterator方法来获取迭代器,随后迭代器的next()方法多次被调用,从其返回对象的value属性读取值并储存在变量num中,依次为1,2和3,当结果对象的done属性值为true时循环退出,所以num不会被赋值为undefined;for-of语句用于不可迭代对象、null或undefined时会报错。

    1.访问默认迭代器及检查对象是否为可迭代对象。

    2.创建可迭代对象:默认情况下,开发者定义的对象都是不可迭代对象,但如果给Symbol.iterater属性添加一个生成器,则可将其变为可迭代对象。

    内建迭代器

    1.集合对象(数组、Map集合与Set集合)迭代器:这3种对象都内建了以下三种迭代器:①entires() 返回一个迭代器,其值为多个键值对。②values() 返回一个迭代器,其值为集合的值。③keys() 返回一个迭代器,其值为集合中所有键名.

    高级迭代器功能

    1.给迭代器传参:这里有一个特例,第一次调用next方法时,无论传递什么参数都会被丢弃。由于传递给next方法的参数会替代上一次yield的返回值,而第一次时,没有任何yield语句执行,因此第一次调用next方法时传参无意义

    2.在迭代器中抛出错误

    3.生成器返回语句

    4.委托生成器:yield *也可直接用于字符串,例如yield * “hello”,此时将使用字符串迭代器

    第九章:JavaScript中的类

    类的声明

    1.基本的类声明语法:建议在constructor中定义所有自有属性,其他地方定义原型上的方法。并且与函数不同的是,类属性不可被赋予新值,如Person.prototype是一个只读属性。

    2.类与自定义类型的不同

    函数声明可以被提升,而类声明与let声明类似,不能被提升;在执行声明语句之前,其会一直处于临时死区中。

    类声明中的所有代码将自动运行在严格模式下,而且无法强行让代码脱离严格模式运行。

    在自定义类型中,需要通过Object.defineProperty()方法手工指定某个方法为不可枚举;而在类中,所有方法都是不可枚举。

    每个类都有一个名为[[Construct]]的内部方法,通过关键字new调用那些不含[[Construct]]的方法会导致程序抛出错误

    使用除关键字new以外的方式调用类的构造函数会导致程序抛出错误。

    在类中修改类名会导致程序报错。

    3.类声明的实现:从下例中可以看出,为何能在外部修改类名而不能在内部修改(内部是const声明);new.target属性允许你检测函数或构造方法是否是通过new运算符被调用的。在通过new运算符被初始化的函数或构造方法中,new.target返回一个指向构造方法或函数的引用。在普通的函数调用中,new.target 的值是undefined。

    类表达式

    1.基本的类表达式语法:let PersonClass = class{};类声明与类表达式均不能像函数声明一样被提升,所以在运行时无论选择哪种方式代码执行结果没有太大区别。

    2.命名类表达式:let PersonClass = class PersonClass2{};标识符PersonClass2只存在于类定义中,在类的外部,不存在一个名为PersonClass2的绑定。

    作为一等公民的类

    在程序中,一等公民是指一个可以传入函数,也可以从函数返回,并且可以赋给变量的值.JS函数是一等公民。

    生成器方法

    1.在类中定义生成器

    2.定义默认迭代器

    静态成员

    类中的所以方法和属性都可以用static关键字来定义,唯一的限制是不能将static用于定义构造函数方法。并且不可在实例中访问静态成员,必须要直接在类中访问静态成员。

    继承与派生类

    继承自其他类的类被称为派生类,如果在派生类中指定了构造函数则必须要调用super(),否则程序报错。如果不使用构造函数,则当创建新的类实例时会自动调用super()并传入所有参数。如下例:

    使用super切记:①只可在派生类的构造函数中使用super(),如果在非派生类(不是用extends声明的类)或函数中使用会报错;在构造函数中访问this之前一定要调用super(),它负责初始化this,如果在调用super()之前访问this会报错。如果不想调用super(),则唯一方法是让类的构造函数返回一个对象。

    1.类方法遮蔽:派生类(如Square)中的方法会覆盖基类(Rectangle)中的同名方法,如果你想访问基类中的该方法:如下例:在派生类中 getArea(){return super.getArea()}

    2.静态成员继承:如果基类有静态成员,则这些静态成员在派生类中也可用(在实例中不可用)

    3.派生自表达式的类:只要表达式可以被解析为一个函数并且有[[constructor]]属性和原型,那么就可以用extends进行派生继承

    在类的构造函数中使用new.target

    因为类必须通过new关键字才能调用,所以在类的构造函数中,new.target属性永远不会是undefined

    创建抽象基类:如下例

    第十章:改进的数组功能

    创建数组

    1.Array.of()方法:let arr =  Array.of(2);无论向该方法传递何种类型参数,该参数会被直接当成数组中的一员而不是数组长度。

    2.Array.from()方法:该方法接收三个参数:第一个参数将被转换为数组的类数组对象(如arguments);第二个参数是可选的将第一个参数的每一个值进行一些操作的函数;第三个参数是表示运行第二个函数的this作用域值。除此之外,该方法能够将所有含有Symbol.iterator属性(可迭代对象)的对象转化为数组

    为所有数组添加新方法

    1.find()方法和findIndex()方法:都接收2个参数:一个是回调函数;一个是可选参数,用于指定回调函数中this的值。执行回调函数时,传入的参数分别为数组中的值及其索引和数组本身,与传入forEach方法的参数相同。如果传入的值满足给定标准则返回true,并且find()或findIndex()停止运行。两者唯一的却别是前者返回查找到的值而后则放回该值的索引。

    2.fill()方法:用指定的值填充一至多个数组元素。当传入一个值时,fill方法会用这个值重写数组中的所有值;如果指向改变一部分值,可以传入开始索引和不包含结束索引(不包含结束索引当前值)这两个可选参数;该方法会修改原数组

    3.copyWithin()方法:从数组中复制元素的值。调用该方法需要传入2个参数:一个是该方法开始填充值的索引位置,另一个是开始复制值的索引位置。可提供可选的第三个参数来限制被重写元素的数量;该方法会修改原数组

    定型数组

    定型数组是一种用于处理数值类型(正如其名,不是所有类型)数据的专用数组;

    1.定型数组与普通数组的相似之处:①具有相同的length属性以及可以通过索引访问定型数组中的元素;通用方法:定型数组上包括许多功能上与数组方法等效的方法;具有3个相同的迭代器,分别是entires()、keys()、values(),意味着可以把定型数组当作普通数组一样来使用展开运算符、for-of循环;拥有和Array.of和Array.from相似的of()和from()方法,只不过前2种返回的是普通数组而后2种返回的是定型数组。

    2.定型数组与普通数组的差别:①定型数组不继承自Array,通过Array.isArray()方法返回false;普通数组的长度可以更改,而定型数组不可以更改,给定型数组中不存在的数值索引赋值会被忽略;定型数组只能存放数值,当存放值补位数值时,会被0取代;缺失的方法有concat()、shift()、pop()、splice()、push()、unshift(),因为除concat()方法其他方法都改变了数组尺寸,而concat方法是因为当两个定型数组处理不同数据类型而连接时会变得不稳定。

    第十一章:Promise与异步编程

    Promise的基础知识

    1.promise的生命周期:每个Promise都会经历一个短暂的生命周期:先是处于进行中(pending)的状态,操作结束后,Promise可能会进入以下两个状态的其中一个:①Fulfilled:Promise异步操作成功完成;②Rejected:由于程序错误或其他一些原因,Promise异步操作未能成功完成。当Promise状态改变时,通过then()方法来采取特定行动。该方法接收两个可选参数,第一个是promise状态变为fulfilled时要调用的函数;第二个是promise状态变为rejected时要调用的函数,所以可以按照任意组合方式来监听Promise。

    2.创建未完成的Promise:用Promise构造函数可以创建新的promise,构造函数只需要接收一个参数:包含初始化Promise代码的执行器函数。执行器接受两个参数,分别是resolve()函数和reject()函数,执行器成功完成调用前者,失败调用后者

    3.创建已处理的Promise:Promise.resolve()和Promise.reject()方法都可以接受非Promise的Thenable对象(能够实现then方法)作为参数。如果传入一个非Promise的Thenable对象,则这些方法会创建一个新的Promise,并在then()函数中被调用。

    4.执行器错误:如果执行器内部抛出一个错误,则Promise的拒绝处理程序会被调用。

    全局的Promise拒绝处理

    如果在没有拒绝处理程序(即promise.catch或promise.then)的情况下拒绝一个Promise,那么不会提示失败信息。浏览器环境的拒绝处理

    链式Promise

    首先,每次每次调用then()方法或者catch()方法时实际创建并返回另一个Promise

    捕获错误 :务必在Promise链的末尾留有一个拒绝处理程序以确保能够正确处理所有可能发生的错误

    Promise链的返回值

    响应多个Promise

    1.Promise.all()方法:该方法只接收并返回一个Promise,该参数是一个含有多个受监视Promise的可迭代对象(数组),只有当可迭代对象中所有Promise都被解决后返回的Promise才会被解决,只有当可迭代对象中所有Promise都被完成后返回的Promise才回被完成。

    所有传入Promise.all()方法的Promise只要有一个被拒绝,那么返回的Promise没等所有Promise都完成就立即拒绝,并且拒绝处理程序只接受一个值而非数组,该值来自被拒绝的值

    2.Promise.race()方法:该方法与上面方法类似,区别为不管是已完成Promise或已拒绝Promise都只返回一个值,返回的值为先解决的值。

    第十二章:代理(Proxy)和反射(Reflection)API

    代理和反射

    调用new Proxy()可创建代替其他目标(target)对象的代理,它虚拟化了目标,所以二者看起来功能一致;代理可以拦截JS引擎内部目标的底层操作对象,这些底层操作被拦截后会触发响应特定操作的陷阱函数。

    反射API以Reflect对象的形式出现,对象中方法的默认特性与相同的底层操作一致,而代理可以覆写这些操作,每个代理陷阱对应一个命名和参数都相同的Reflect方法。

    用set陷阱验证属性

    set陷阱接收4个参数:tarpTarget(代理目标对象),key(要写入的属性键),value(属性值),receiver(通常是代理)

    用get陷阱验证对象结构

    该方法只有三个参数:tarpTarget(代理目标对象),key(要写入的属性键),receiver(通常是代理)

    普通对象检查不存在的属性会返回undefined而不会报错,可以用get方法来检查

    使用has陷阱隐藏已有属性

    该方法有两个参数:tarpTarget(代理目标对象),key(要写入的属性键)

    用deleteProperty防止删除属性

    该方法有两个参数:tarpTarget(代理目标对象),key(要删除的属性键)

    原型代理陷阱

    getPropertyOf:接收一个参数 tarpTarget(得到的对象);

    setPropertyOf:接收两个参数tarpTarget(接收原型设置的对象);proto(作为原型使用的对象)

    Object.getPrototypeOf()和Reflect.getPrototypeOf()区别:前者会将传入参数强制转化为一个对象,后者只能传入一个对象否则报错;如传入数字1,前者将1转化为Number对象,最后结果返回Number.prototype;而后则则会直接报错。

    Object.setPrototypeOf()和Reflect.setPrototypeOf()区别:前者方法成功后会返回一个对象,失败会报错;后则成功返回true,失败返回false。

    对象可拓展陷阱

    preventExtensions和isExtensible都只接受一个参数:即tarpTarget对象;前者表示操作是否成功,后者表示对象是否可拓展。两种方法都返回布尔值

    Object.isExtensible()和Reflect.isExtensible()的区别是传入非对象值前者返回false后者抛出错误;

    Object.preventExtensions()和Reflect.preventExtensions()的区别是传入非对象值前者返回该值后者抛出错误;

    属性描述符的陷阱

    defineProperty接收三个参数: tarpTarget(要定义属性的对象)、key(属性的值)、descriptor(属性的描述符对象)

    getOwnPropertyDescriptor接收2个参数:tarpTarget(要定义属性的对象)、key(属性的值)

    Object.defineProperty和Reflect.defineProperty的区别是:前者返回第一个参数,后者返回布尔值

    Object.getOwnPropertyDescriptor和Reflect.getOwnPropertyDescriptor的区别是:前者传入非对象参数会将第其强制转化为对象,而后者传入非对象参数会报错

    函数代理中的apply和construct陷阱

    在所有代理陷阱中,只有这两种方法代理目标是函数;其中直接调用函数执行apply,使用new操作符执行construct

    apply接收三个参数:tarpTarget(被执行函数)、thisArg(函数被调用时内部this的值)、argumentsList(传递给函数的参数数组)

    construct接收2个参数::tarpTarget(被执行函数)、argumentsList(传递给函数的参数数组)

    第十三章:用模块封装代码

    导出的基本语法

    使用export关键字放在任何变量、函数或者类声明前面

    导入的基本语法

    使用import关键字在另一个模块中访问,当导入一个绑定时,它好像使用const定义一样。你无法定义另一个同名变量。

    模块语法的限制:它们必须在其他语句(如if)和函数之外使用,其只能在模块顶部使用,否则报错

    导入和导出时重命名

    在导入和导出过程中改变导出元素的名称

    模块的默认值

    模块的默认值指的是通过default关键字指定的单个变量、函数或类,只能为每个模块设置一个默认的导出值,导出时多次使用default关键字是一个语法错误。

    导出默认值

    导入默认值:导入默认值可以不用加大括号

    ECMAScript6中的较小改动

    1.使用Number.isInteget()方法来确定一个值是否为整数

    2.JS只能准确的表示-2^53至2^53之间的整数,超出范围易出错

    相关文章

      网友评论

          本文标题:读《深入理解ES6》

          本文链接:https://www.haomeiwen.com/subject/qlaiaxtx.html