ECMAScript 和 JavaScript 的关系
一个常见的问题是,ECMAScript 和 JavaScript 到底是什么关系?
要讲清楚这个问题,需要回顾历史。1996 年 11 月,JavaScript 的创造者 Netscape 公司,决定将 JavaScript 提交给标准化组织 ECMA,希望这种语言能够成为国际标准。次年,ECMA 发布 262 号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的标准,并将这种语言称为 ECMAScript,这个版本就是 1.0 版。
该标准从一开始就是针对 JavaScript 语言制定的,但是之所以不叫 JavaScript,有两个原因。一是商标,Java 是 Sun 公司的商标,根据授权协议,只有 Netscape 公司可以合法地使用 JavaScript 这个名字,且 JavaScript 本身也已经被 Netscape 公司注册为商标。二是想体现这门语言的制定者是 ECMA,不是 Netscape,这样有利于保证这门语言的开放性和中立性。
因此,ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现。
let特点
- 变量不能重复声明
JS
1 2 |
let star = '罗志祥'; let star = '小猪'; |
- 块儿级作用域
JS
1 2 3 4 5 |
{ let girl = '周扬青'; } console.log(girl); |
- 在里面定义的变量外面找不到
- 不存在变量提升
JS
1 2 |
console.log(song); let song = 'lemon tree'//无效写法,无法作用于console.log |
- 不影响作用域链PLAINTEXT
1 2 3 4 5 6 7 |
{ let school = 'ynnubs' function fn(){ console.log(school) } fn(); } |
- 通俗来讲,就是在外面定义的变量里面找得到,反之,函数里面定义的变量外面就找不到。案例JS
1 2 3 4 5 6 7 8 9 |
let items = document.getElementsByClassName('item'); //遍历并绑定事件 for(let i = 0;i<items.length;i++){ items[i].onclick = function(){ //修改当前元素的背景颜色 // this.style.background = 'pink'; items[i].style.background = 'pink'; } } |
- const定义常量
- 一定要赋初始值
- 一般常量使用大写。
- 常量的值不能修改
- 块级作用域
- 对于数组和对象的元素修改,不算做对常量的修改,不会报错。
1 2 3 4 5 6 |
const F4 = ['小沈阳','刘能','赵四','宋小宝']; let [xiao, liu, zhao, song] = F4; console.log(xiao); console.log(liu); console.log(zhao); console.log(song); |
对象的解构
JS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
const zhao = { name: '赵本山', age: '不详', xiaopin: function(){ console.log("我可以演小品"); } }; let {name, age, xiaopin} = zhao; console.log(name); console.log(age); console.log(xiaopin); xiaopin(); /*let {xiaopin} = zhao; xiaopin(); 可以单独的解构*/ |
模板字符串
- 声明
ES6 引入新的声明字符串的方式 『``』
let str = 我也是一个字符串哦!;
console.log(str, typeof str);
- 内容中可以直接出现换行符
JS
1 2 3 4 5 6 |
let str = `<ul> <li>沈腾</li> <li>玛丽</li> <li>魏翔</li> <li>艾伦</li> </ul>`; |
- 变量拼接
JS
1 2 3 |
let lovest = '魏翔'; let out = `${lovest}是我心目中最搞笑的演员!!`; console.log(out); |
简化对象写法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
JS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
let name = 'aaa'; let change = function(){ console.log('我们可以改变你!!'); } const school = { name, change, improve(){ console.log("我们可以提高你的技能"); } } console.log(school); |
箭头函数
ES6 允许使用「箭头」(=>)定义函数。
JS
1 2 3 4 5 6 |
let fn = (a,b) => { return a + b; } let result = fn(1, 2); console.log(result); |
JS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
//1. this 是静态的. this 始终指向函数声明时所在作用域下的 this 的值 functiongetName(){ console.log(this.name); } let getName2 = () => { console.log(this.name); } //设置 window 对象的 name 属性 window.name = 'aaa'; const school = { name: "ATGUIGU" } //直接调用 // getName(); // getName2(); //call 方法调用 // getName.call(school); // getName2.call(school); //2. 不能作为构造实例化对象 // let Person = (name, age) => { // this.name = name; // this.age = age; // } // let me = new Person('xiao',30); // console.log(me); //3. 不能使用 arguments 变量 // let fn = () => { // console.log(arguments); // } // fn(1,2,3); //4. 箭头函数的简写 //1) 省略小括号, 当形参有且只有一个的时候 // let add = n => { // return n + n; // } // console.log(add(9)); //2) 省略花括号, 当代码体只有一条语句的时候, 此时 return 必须省略 // 而且语句的执行结果就是函数的返回值 let pow = n => n * n; console.log(pow(8)); |
扩展运算符
扩展运算符能将『数组』转换为逗号分隔的『参数序列』,也就是将数组转成了实参。
JS
1 2 3 4 5 6 7 8 9 10 |
const tfboys = ['易烊千玺','王源','王俊凯']; // => '易烊千玺','王源','王俊凯' // 声明一个函数 functionchunwan(){ console.log(arguments); } chunwan(...tfboys);// chunwan('易烊千玺','王源','王俊凯') |
拓展运算符应用
- 数组的合并
JS
1 2 3 4 5 |
const kuaizi = ['王太利','肖央']; const fenghuang = ['曾毅','玲花']; // const zuixuanxiaopingguo = kuaizi.concat(fenghuang); const zuixuanxiaopingguo = [...kuaizi, ...fenghuang]; console.log(zuixuanxiaopingguo); |
- 数组的克隆
JS
1 2 3 |
const sanzhihua = ['E','G','M']; const sanyecao = [...sanzhihua];// ['E','G','M'] console.log(sanyecao); |
- 将伪数组转为真正的数组
JS
1 2 3 |
const divs = document.querySelectorAll('div'); const divArr = [...divs]; console.log(divArr);// arguments |
symbol的基本使用
ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol
的原因。
ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol
的原因。
Symbol 值通过Symbol
函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
JAVASCRIPT
1 2 3 4 |
let s = Symbol(); typeof s // "symbol" |
上面代码中,变量s
就是一个独一无二的值。typeof
运算符的结果,表明变量s
是 Symbol 数据类型,而不是字符串之类的其他类型。
注意,Symbol
函数前不能使用new
命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。也就是说,由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。
Symbol
函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
JAVASCRIPT
1 2 3 4 5 6 7 8 |
let s1 = Symbol('foo'); let s2 = Symbol('bar'); s1 // Symbol(foo) s2 // Symbol(bar) s1.toString() // "Symbol(foo)" s2.toString() // "Symbol(bar)" |
上面代码中,s1
和s2
是两个 Symbol 值。如果不加参数,它们在控制台的输出都是Symbol()
,不利于区分。有了参数以后,就等于为它们加上了描述,输出的时候就能够分清,到底是哪一个值。
迭代器(遍历器)
JavaScript 原有的表示“集合”的数据结构,主要是数组(Array
)和对象(Object
),ES6 又添加了Map
和Set
。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map
,Map
的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。
遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for...of
循环,Iterator 接口主要供for...of
消费。
Iterator 的遍历过程是这样的。
(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
(2)第一次调用指针对象的next
方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的next
方法,指针就指向数据结构的第二个成员。
(4)不断调用指针对象的next
方法,直到它指向数据结构的结束位置。
每一次调用next
方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value
和done
两个属性的对象。其中,value
属性是当前成员的值,done
属性是一个布尔值,表示遍历是否结束。
下面是一个模拟next
方法返回值的例子。
JS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
const banji = { name: "终极一班", stus: [ 'xiaoming', 'xiaoning', 'xiaotian', 'knight' ], [Symbol.iterator]() { //索引变量 let index = 0; // let _this = this; return { next: function () { if (index < _this.stus.length) { const result = { value: _this.stus[index], done: false }; //下标自增 index++; //返回结果 return result; }else{ return {value: undefined, done: true}; } } }; } } //遍历这个对象 for (let v of banji) { console.log(v); } |