ECMAScript规范

您所在的位置:网站首页 es6新特性面试 ECMAScript规范

ECMAScript规范

2023-03-12 23:59| 来源: 网络整理| 查看: 265

ECMAScript规范

ECMAScript是一种脚本语言规范,从ES6开始广泛使用

新的规范不一定所有JS引擎都能支持,所以出现了Babel用于将ECMAScript2015+版本的代码转换为向后兼容的JavaScript语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

Babel通过语法转换器来支持新版本的JavaScript语法,这些插件让你现在就能使用新的语法,无需等待浏览器的支持

Web标准与ECMAScript规范

Web标准是关于Web技术领域的一系列标准,包括HMTL、CSS、DOM、媒体、性能、WebAPI、安全、无障碍、图形等。ECMAScript则是一种语规范,JavaScript是ECMAScript的一种实现和扩展。

ECMAScript和JavaScript

1996年初网景推出了JavaScript,1996年11月网景正式向ECMA(欧洲计算机制造商协会)提交语言标准。1997年6月,ECMA以JavaScript语言为基础制定了ECMAScript标准规范ECMA-262。JavaScript成为了ECMAScript最著名的实现之一。

除此之外,ActionScript和JScript也都是ECMAScript规范的实现语言。

所以是先有JavaScript,后有ECMAScript规范。ECMAScript规范是基于JavaScript制定的,JavaScript是ECMAScript规范的实现。但ECMAScript只是描述语言的语法和基本对象,JavaScript除了核心语言部分,还包括BOM和DOM的WebAPI部分。

JavaScript由三部分组成

1.ECMAScript(核心):规定了语言的组成部分=>语法、类型、语句、关键字、保留字、操作符、对象

2.BOM(浏览器对象模型):支持访问和操作浏览器窗口,可以控制浏览器显示页面以外的部分。

3.DOM(文档对象模型):把整个页面映射为一个多层节点结果,可借助DOM提供的API,可删除、添加和修改任何节点

什么是ES5?

ES5全程ECMAScript5,即ES5,是ECMAScript的第五次修订(第四版因为过于复杂废弃了),又称ECMAScript2009,于2009年完成标准化。

什么是ES6?

ES6,全称ECMAScript6.0,即ES6,是ECMAScript的第六次修订,又称ES2015,于2015年06月发版,是JavaScript的下一个版本标准。

ES6主要是为了解决ES5的先天不足,目前浏览器的JavaScript是ES5版本。大多数高版本的浏览器也支持ES6,不过只实现了ES6的部分特性和功能。ES6是继ES5之后的一次改进,相对于ES5更加简洁。提高了开发效率

ES5特性

1.stric模式:严格模式(developer.mozilla.org/zh-CN/docs/…)限制了一些用法

2.Array增加方法:有every、some、forEach、filter、indexOf、lastIndexOf,isArray、map、reduce、reduceRight方法。

3.Object方法:Object.getPrototypeOf、Object.create等方法。

Object.getPrototypeOf - 方法返回指定对象的原型 Object.create - 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型 Object.getOwnPropertyNames - 方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 值作为名称的属性)组成的数组。 Object.defineProperty - 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。 Object.getOwnPropertyDescriptor - 方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性) Object.defineProperties - 方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。 Object,keys - 法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致。 Object.preventExtensions / Object.isExtensible - 方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。 Object.seal / Object.isSealed - 方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。 Object.freeze / Object.isFrozen - 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。 ES6特性 1.块级作用域 => 关键字 let,常量const

在ES6中通常用let和const来声明,let表示变量、const表示常量

特点:let和const都是块级作用域。以{}代码块作为作用域范围只能在代码块里面使用,不存在变量提升,只能先声明再使用,否则会报错。在代码块内,在声明变量之前,该变量都是不可用的,这在语法上,称为“暂时性死区”,在同一个代码块内,不允许重复声明。

const声明的是一个只读常量,在声明时就需要赋值。(如果const的是一个对象,对象所包含的值是可以被修改的。抽象点说,就是对象所指向的地址不能改变,而变量成员是可以修改的)

2.对象的扩展

属性和方法的简写

对象字面量属性的简写

ES6允许在对象之中,直接写变量,这时,属性名为变量名,属性值为变量的值

let foo = "bar"; let baz = { foo }; // {foo: "bar"} 复制代码

对象字面量方法的简写。省略冒号与function关键字

let o = { method() { return "Hello!"; } }; ==> let o = { method:function() { return "Hello!"; } } 复制代码 Object.keys()

获取对象的所有属性名或方法名(不包括原型的内容),返回一个数组。

let obj = { name: 'john', age: 21, getName: function() { alert(this.name) } }; Object.keys(obj) ==> ["name","age","getName"]; Object.keys(obj).length ==> 3; Object.keys(['aa','bb','cc']) ==> ["0","1","2"]; Object.keys('abcdef') ==> ['0',"1","2","3","4","5"]; 复制代码 Object.assign()

assign方法将多个原对象的属性和方法都合并到了目标对象上面。可以接受多个参数,第一个参数是目标对象,后面的都是源对象

let target = {}; //目标对象 let source1 = {name: 'ming', age: "19"};//源对象1 let source2 = {sex: '女'};//源对象2 let source3 = {sex: '男'};//源对象3,和source2中的对象有同名属性sex Object.assign(target,source1,source2,source3); console.log(target) // {name: 'ming', age: '19', sex: '男'}; 复制代码 3.解构赋值

数组的解构赋值

解构赋值是对赋值运算符的扩展。是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。在代码书写上简洁且易读,语义更加清晰明了,也方便了复杂对象中数据字段获取。数组中的值会被解析到对应接收该值的变量中,数组的解构赋值要一一对应如果有对应不上的都是undefined

let [a, b, c] = [1, 2, 3]; // a = 1 b = 2 c = 3 复制代码

对象的解构赋值

对象的解构赋值和数组的解构赋值其实类似,但是数组的数组成员是有序的,而对象的属性则是无序的,所以对象的解构赋值简单理解是等号的左边和右边的结构相同。

let {foo, bar } = {foo: 'aaa', bar: 'bbb'}; // foo = 'aaa' bar = 'bbb' let {baz: foo} = {baz: 'ddd'} // foo = 'ddd'; 复制代码 4.展开运算符

展开运算符,允许一个表达式在某处展开,展开运算符在多个参数(用于函数调用)或多个元素(用于数组字面量)或者多个变量(用于解构赋值)的地方可以使用。

let obj1 = { value1: 1, value2: 2 }; let obj2 = {...obj1}; cosnole.log(obj2) // {value1: 1, value2: 2} 复制代码

展开运算符的写法与obj2 = obj1直接赋值的写法的区别在于如果直接赋值的话,对于引用类型来说,相当于只是赋值了obj1的内存空间地址,当obj2发生改变的时候,obj1也会随着发生改变,而使用展开运算符写法的话,由于obj1对象中的属性类型都是基本类型,相当于重新创建了一个对象,此时obj2发生改变的时候,并不会影响obj1这个对象,但是仅限于其属性都为基本类型的情况(或者说只进行了一层的深拷贝),如果该对象中的属性还有引用类型的话,修改属性中引用类型的值,则两个对象的属性值都会被修改。

let obj1 = { attri1: [3, 6, 0], attri2: 4, attri3: 5 }; let obj2 = {...obj1}; ​ obj2.attri2 = 888; obj2.attri1[0] = 7; ​ console.log(obj1) // {attri1: [7, 6, 0], attri2: 4, attri3: 5} console.log(obj2) // {attri1: [7, 6, 0], attri2: 888, attri3: 5} 复制代码

展开运算符的应用

1.在函数中使用展开运算符

function test(a, b, c){}; ​ let arr = [1, 2, 3]; test(...arr); 复制代码

2.在数组字面量中使用展开运算符

let arr1 = [1, 2]; let arr2 = [...arr1, 3, 4]; // [1,2,3,4] ​ // 使用push方法 let arr1 = [1, 2]; let arr2 = [3, 4]; arr1.push(..arr2) // [1,2,3,4] 复制代码

3.用于解构赋值,解构赋值中展开运算符只能用在最后,否则会报错

let [a, b, ...c] = [1, 2, 3, 4]; console.log(a ,b, c) // 1, 2, [3,4]; 复制代码

4.类数组变成数组

let oLis = docuemnt.getElementByTagName("li"); let liArr = [...oLis]; 复制代码

5.对象中使用展开运算符

ES7中的对象展开运算符可以让我们更快捷地操作对象:

let {x, y, ...z} = {x:1, y:2, a:3, b:4};\ x; // 1 y; // 2 z; // {a:3,b:4} 复制代码

将一个对象插入另外一个对象当中

let z = {a:3, b:4}; let n = {x:1, y:2, ...z}; cosnole.log(n); // {x:1, y:2, a:3, b:4} 复制代码

合并两个对象:

let a = {x:1, y:2}; let b = {z:3}; let ab = {...a, ...b}; console.log(ab); // {x:1, y:2, z:3}; 复制代码 5.函数的扩展

函数的默认参数

ES6为参数提供了默认值。在定义函数时便初始化了这个参数,以便在参数没有被传递进去时使用。

箭头函数

在ES6中,提供了一种简洁的函数写法,我们称作“箭头函数”

写法:函数名=(形参)=>{.....} 当函数体只有一个表达式时,{}和return 可以省略

当函数体中只有一个时,()可以省略。

特点:箭头函数中的this始终指向箭头函数定义时的离this最近的一个函数,如果没有最近的函数就指向window

6.模板字符串

用一对反引号`标识,它可以当作普通字符串使用,也可以用来定义多行字符串,也可以在字符串中嵌入变量,js表达式或函数、变量、js表达式或函数需要写在${}中。

let name = "Bab", time = 'today'; `Hello ${name}, how are you ${time}?` // return "Hello Bob, how are you today?" 复制代码 7.for...of循环 let arr = ['小林',"小吴",'小佳']; for(let key of arr){ console.log(key) // 小林 小吴 小佳 } 复制代码 8.Class类,有constructor、extends、super 本质上是语法糖,(对语言的功能并没有影响,但是更方便程序员使用)。 class Artist { constructor(name){ this.name = name; } perform(){ return this.name + " performs"; } } class Singet extends Artist { constructor(name, song){ super.constructor(name); this.song = song; } perform(){ return super.perform() + "[" + this.song + "]"; } } let james = new Singer("Etta James","At last"); james instanceof Artist; // true james instanceof Singer; // true james.perform(); // "Etta James performs [At last]" 复制代码

class类的继承ES6中不再像ES5一样使用原型链实现继承,而是引入Class这个概念。

ES6所写的类相比于ES5的优点:

区别于函数,更加专业化(类似于JAVA中的类);

写法更加简便,更加容易实现类的继承

9.Map + Set + WeakMap + WeakSet

四种集合类型,WeakMap、WeakSet作为属性键的对象如果没有别的变量在引用它们,则会被回收释放掉。

// Sets let s = new Set(); s.add('hello').add('goodbye').add('hello'); s,size === 2; s.has('hello') === true; // Maps let m = new Map(); m.set('hello', 42); m.set(s, 34); m.get(s) == 34; // WeakMap let wm = new WeakMap(); wm.set(s, {extra: 42}); wm.size === undefined; // WeakSets let ws = new WeakSet(); ws.add({data: 42}); 复制代码 10.Math + Number + String + Array + Object APls

一些新的API

Number.EPSILON Number.isInteger(Infinity) // false Number.isNaN('NaN') // false Math.acosh(3) // 1.762747174039086 Math.hypot(3,4) // 5 Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2 "abcde".includes('cd') // true "abc".repact(3) // 'abcabcabc'; Array.from(document.querySelectorAll('*')) // Returns a real Array Array.of(1,2,3) // Similar to new Array(...), but without special one-arg behacior [0, 0, 0].fill(7, 1) // [0,7,7]; [1,2,3].find(x => x == 3) // 3; [1,2,3].findIndex(x => x == 2) // 1 [1,2,3,4,5].copyWithin(3,0) // [1,2,3,1,2]; ['a','b','c'].entries() // iterator [0, "a"], [1,"b"],[2,"c"] ['a','b','c'].keys() // iterator 0, 1, 2 ['a','b','c'].values() // iterator "a","b","c" Object.assign(Point, {origin: new Point(0,0) }); 复制代码 11.proxies:使用代理(Proxy)监听对象的操作,然后可以做一些相应事情。 let target = {}; let handler = { get: function(receiver,name) { return `Hello,${name}`; } } let p = new Proxy(target,handler); p.world === "Hello,world"; 复制代码

可监听的操作:get、set、has、deleteProperty,apply,construct、getOwnPropertyDescriptor、defineProperty、getPrototypeOf、setPrototypeOf、enumerate、ownKeys、preventExtensions、isExtensible

12.Symbol:唯一命名

Symbol是一种基本类型,Symbol通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的。

let key = Symbol('key'); ley key2 = Symbol('key'); key == key2 // false 复制代码 13.Promise:处理异步操作的对象,使用了Promise对象之后可以用一种链式调用的方式来组织代码,让代码更加直观(类似jQuery的deferred对象) function fakeAjax(url){ return new Promise(function(resolve,reject){ if(!url){ return setTimeout(reject,1000); } return setTimeout(resolve,1000); }); } // no Url,Promise rejected fakeAjax().then(function(){ console.log('success'); }.fnction(){ console.log('fail'); }) 复制代码

Promise对象是异步编程的一种解决方案,将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数,要是为了解决异步处理回调地狱(也就是循环嵌套的问题)而产生的。Promise构造函数包含一个参数和一个带有resolve(解析)和reject(拒绝)两个参数的回调,在回调中执行一些操作(例如异步),如果一切都正常,则调用resolve,否则调用reject

对于已经实例化过的Promise对象可以调用Promise.then()方法,传递resolve和reject方法作为回调

then()方法接收两个参数:onResolve和onReject,分别代表当前Promsie对象在成功或失败时Promise的3种状态:Fulfilled为成功的状态,Rejected为失败的状态,Pending既不是Fulfilld也不是Rejected的状态,可以理解为Promise对象实例创建时候的初始状态

14.import和export

ES6标准中,JavaScript原生支持模块(Module),这种将JS代码分割不同功能的小块进行模块化,将不同功能的代码分别写在不同文件中,各模块只需导出公共接口部分,然后通过模块导入的方式可以在其他地方使用。

export用于对外输出本模块(一个文件可以理解为一个模块)变量的接口

import用于在一个模块中加载另一个含有export接口的模块。

import和export命令只能在模块的顶部,不能再代码块之中。

15.Set数据结构

Set是ES6提供的一种新的数据结构,类似于数组,所有的数据都是唯一的,没有重复的值,它本身是一个构造函数,由于成员是唯一的。不重复的特点,因此可以通过Set轻松实现对数组的去重、交、并、补等操作

Set属性和方法

Size()数据的长度 Add()添加某个值,返回Set结构本身 Delete()删除某个值,返回一个布尔值,表示删除是否成功 Has()查找某条数据,返回一个布尔值 Clear()清楚所有成员,没有返回值 interface Set{ add(value):this; claer():void; delete(value):boolean; forEach(callbackfn: (value, value2, set: Set) => void, thisArg?: any):void; has(value): boolean; 7 | readonly size: number; } 复制代码

Set主要应用场景:数组去重、交集、并集、补集。

根据Set的特点,有很多场景可以通过Set快速实现。JavaScript Set 实用场景(数据:去重、交、并、补)

let arr1 = [1, 2, 3, 4, 5, 6, 7, 4, 3, 2, 1]; // 去重 let newArr = [...new Set(arr1)]; cosnole.log(newArr) // [1,2,3,4,5,6,7] 复制代码 let arr1 = [1, 2 ,3, 4, 5]; let arr2 = [3, 4, 5, 6, 7]; let arr1_set = new Set(arr1); let arr2_set = new Set(arr2); // 交集 let intersectionArr = [...arr_set].filter(val => arr2_set.has(val)); cosnole.log(intersectionArr) // [3,4,5] // 并集 let unionArr = [...new Set([...arrr1,...arr2])]; cosnole.log(unionArr) // [1,2,3,4,5,6,7] // 补集 let complementaryArr = [...arr1_set].filter(val => !arr2_set.has(val)); cosnole.log(complementaryArr) // [1,2] 复制代码 15.Modules

ES6的内置模块功能借鉴了CommonJS和AMD各自的优点:

(1)具有CommonJs的精简语法、唯一导出出口(single exports)和循环依赖(cyclicdependencies)的特点。

(2)类似AMD,支持异步加载和可配置的模块加载

// lib/math.js export function sum(x,y){ return x + y; } export var pi = 3.141593; // app.js import * as math from "lib/math"; alert("2π = " + math.sum(math.pi,math.pi)); // otherApp.js import {sum,pi} from "lib/math"; alert("2π = " + sum(pi,pi)); Module Loaders: // Dynamic Loading - "System" is default loader System.import('lib/math').then(function(m){ alert('2π = ' + m.sum(m.pi,m.pi)); }) // Directly manipulate module cache System.get('jquery'); System.set('jquery',Module({$:$})); // WARNING:not yet finalized 复制代码 ES5和ES6的区别 系统库的引入 ES5:需要先使用requrie导入React包,成为对象,再去进行真正引用 ES6:可以使用import方法来直接实现系统库引用,不需要额外制作一个类库对象 导出及引用单个类 ES5:要导出一个类给别的模块用,一般通过module.exports来实现,引用时,则依然通过require方法来获取 ES6:可以使用export default来实现相同的功能,使用import方法来实现导入 定义组件 ES5:组件类的定义可以通过React.createClass实现 ES6:让组件类去继承React.Component类就可以了 组件内部定义方法 ES5:采用的是 xxx.function()的形式,方法大括号末尾需要添加逗号; ES6:省略了【:fucntion】这一段,并且结尾不需要加逗号来实现分割 定义组件的属性类型和默认属性 ES5:属性类型和默认属性分别通过propTypes成员和getDefaultProps方法来实现(这两个方法应该是固定名称的) ES6:统一使用static成员来实现 初始化STATE ES5:初始化state的方法是固定的getlnitialState; ES6:第一种,直接构造state函数,第二种,相当于OC中的方法重写,重写cosntructor方法


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3