1.let & const
1) let,作用与var类似,用于声明变量
特性:
let
不能重复声明变量,var
可以重复声明变量;- 块级作用域,
es5
中存在全局作用域、函数作用域、eval
作用域;es6
中引入了块级作用域,
let
声明的变量在块级作用域{}
内有效let
声明的变量不存在var
的变量提升问题
举个例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div class="container"> <h2 class="page-header">点击切换颜色</h2> <div class="item">1</div> <hr> <div class="item">2</div> <hr> <div class="item">3</div> </div> <script> // 获取div对象 let items = document.getElementsByClassName('item') // 遍历并绑定事件 遍历时let i for(let i = 0; i < items.length; i++){ items[i].onclick = function(){ items[i].style.background = 'pink' } } /* 相当于在3个块级作用域内分别声明了i { let i = 0 items[i].onclick = function(){ items[i].style.background = 'pink' } } { let i = 1 items[i].onclick = function(){ items[i].style.background = 'pink' } } { let i = 2 items[i].onclick = function(){ items[i].style.background = 'pink' } } */ /* // 遍历并绑定事件 遍历时var i for(var i = 0; i < items.length; i++){ items[i].onclick = function(){ // 修改当前元素的背景颜色 this.style.background = 'pink' // 此处this指向’被绑定的元素对象‘,即调用该函数的对象 // 此处不能和上文一样使用 items[i].style.background = 'pink', // 因为var的i不考虑块级作用域, 则相当于在全局声明了一个变量,循环结束后i=3, // 函数执行时向上层寻找最终得到全局变量i=3,而items[3]为undefined } } 相当于 { var i = 0 // ... } { var i = 1 // ... } { var i = 2 // ... } { var i = 3 } */ </script> </body> <style> .item{ width: 200px; height: 50px; border-radius: 2%; background-color: brown; } </style> </html>
2) const 用于声明常量
注意事项:
- 一定要赋初始值
- 一般常量使用大写(属于编程规范)
- 常量值不能修改
- 存在块级作用域
- 对于数组和对象的元素修改,不算做对常量的修改,不会报错(因为引用数据类型保存的是内存地址,所以声明数组和对象时可以使用
const
声明,以此保证其保存的内存地址不变)
2.解构赋值
ES6
允许按照一定模式从数组和对象中提取值,对变量进行赋值
1) 数组的解构
const Web = ['html', 'css', 'javascript'] let [tool1, tool2, tool3] = Web console.log('tool1-----', tool1) // html console.log('tool2-----', tool2) // css console.log('tool3-----', tool3) // javascript
2) 对象的解构
const liMing = { name: 'liMing', age: '22', tell: function(){ console.log(`I am liMing`) } } let {name, age, tell} = liMing console.log(name) // 'liMing' console.log(age) // '22' console.log(tell) // f(){...} tell() // I am liMing
3.模板字符串
特性:
(反引号)内容中可以直接出现换行符,’ '和" "中则不可以,出现会报错
- 可以直接进行变量拼接
4.简化对象写法
ES6
允许在大括号里面,直接写入变量和函数,作为对象的属性和方法(在属性名和变量名相同的情况下),这样的书写更加简洁
let name = 'LiMing' let tell = function(){ console.log('I am LiMing') } const liMing = { name, tell, sayHi(){ console.log('hello') } } // 等效于 // const liMing = { // name: name, // tell: tell, // sayHi: function(){ // console.log('hello') // } // } console.log(liMing) liMing.tell() liMing.sayHi()
5.箭头函数
与function
声明的区别:
1.箭头函数this
是静态的。
- 箭头函数内的
this
指向上层对象;始终指向函数声明时所在作用域下的this
的值,无法被call
改变 - 普通函数内的
this
指向调用其函数的对象
function getName(){ console.log(this.name) } let getName2 = ()=>{ console.log(this.name) } // 设置window对象的name属性 window.student = 'LiMing' const student = { name: 'HanMei' } // 直接调用 getName() // LiMing getName2() // LiMing // call方法调用 getName.call(student) // HanMei getName2.call(student) // LiMing
2.箭头函数不能作为构造函数实例化对象
let Person = (name, age)=>{ this.name = name this.age = age } let me = new Person('LiMing', 20) // 报错:Uncaught TypeError: Person is not a constructor
3.箭头函数不能使用arguments
变量,但是可以使用....rest
let fn = ()=>{ console.log(arguments) } fn(1, 2, 3) // 报错:Uncaught ReferenceError: arguments is not defined let fn2 = (...rest)=>{ console.log(...rest) } fn2('a','b','c') // a b c
4.箭头函数的简写
① 当形参有且只有一个的时候,可以省略()
② 当代码体只有一条语句的时候,可以省略{}
,此时return
必须省略,而且语句的执行结果就是函数的返回值
// 当形参有且只有一个的时候,可以省略`()` let add = n => { return n + n } console.log(add(9)) // 当代码体只有一条语句的时候,可以省略`{}`,此时`return`必须省略,而且语句的执行结果就是函数的返回值 let pow = n => n*n console.log(pow(9))
5.箭头函数的例子
箭头函数适合与this
无关的回调,比如定时器setTimeout(()=>{...}, 2000)
、数组的方法回调arr.filter((item)=>{...})
;
不适合与this
有关的回调,比如dom
元素的事件回调ad.addEventListener('click', function(){...}
、对象内的方法定义{name: 'LiMing', getName: function(){this.name}}
例1:
// 需求-1 点击div 2s后颜色变红 // 获取元素 let ad = document.getElementById('ad') // 绑定事件 ad.addEventListener('click', function(){ setTimeout(function(){ console.log(this) // 定时器里的this指向window this.style.background = 'brown' // 报错 }, 2000) }) //解决方案1 // ad.addEventListener('click', function(){ // // 保存this的值 // let _this = this // _this指向ad // setTimeout(function(){ // console.log(_this) // _this.style.background = 'brown' // }, 2000) // }) // 解决方案2 // ad.addEventListener('click', function(){ // setTimeout(()=>{ // console.log(this) // this.style.background = 'brown' // this指向函数声明时所在作用域下this的值 即ad // }, 2000) // })
例2:
// 需求-2 从数组中返回偶数的元素 const arr = [1, 6, 9, 10, 100, 25] const result = arr.filter(function(item){ if(item %2 === 0){ return true }else{ return false } }) // 可以用箭头函数 // const result = arr.filter(item => { // if(item % 2 === 0){ // return true // }else{ // return false // } // }) // 还可以简写为 // const result = arr.filter(item => item % 2 === 0) console.log(result)
6.函数参数的默认值设置
ES6
允许给函数参数赋初始值
function add(a, b, c=10){ // 具有默认值的参数,一般位置要靠后 return a + b + c } console.log(add(1,2,))
可以与解构赋值一起使用
function connect({host='127.0.0.1', port, username, password}){ console.log(host, port) console.log(username, password) } connect({ port: 3306, username: 'root', password: 'root', })
7.rest参数
ES6
引入rest
参数,用于获取函数的实参,用来代替arguments
// ES5获取实参的方式 function printStudent(){ console.log(arguments) // arguments为一个对象 } printStudent('LiMing','HanMeimei') // ES6获取实参的方式 function printFriend(friend1, friend2, ...rest){ // rest参数必须放在形参列表最后,否则会报错 console.log(friend1) console.log(friend2) console.log(rest) // 得到一个数组,可以使用数组api } printFriend('小猫','小狗','兔子','鸭子') // 小猫 // 小狗 // ['兔子','鸭子']
8.扩展运算符
...
能将「数组」转为逗号分隔的「参数序列」
注:虽然形式与rest
参数类似,但是rest
参数是用在函数定义时的形参位置,扩展运算符是用在函数实际调用时的实参位置
const STUDENTS = ['小明','小芳','小红'] function printStudent(){ console.log(arguments) } printStudent(STUDENTS) // 参数为一个数组,数组内包含3个元素 printStudent(...STUDENTS) // 参数为3个元素
应用场景:
- 数组的合并
const STUDENTS1 = ['小明','小芳','小红'] const STUDENTS2 = ['小吴', '小王'] // es5写法 const STUDENTS_ES5 = STUDENTS1.concat(STUDENTS2) // es6写法 const STUDENTS_ES6 = [...STUDENTS1, ...STUDENTS2] console.log('es5------',STUDENTS_ES5) console.log('es6------',STUDENTS_ES6)
- 数组的克隆
const STUDENTS1 = ['小明','小芳','小红'] const PUPIL = [...STUDENTS1] // 注意:如果数组内元素是引用类型,拷贝的是内存地址,为浅拷贝 console.log('PUPIL----',PUPIL)
- 将伪数组转为真正的数组
const divs = document.querySelectorAll('div') console.log(divs) // 此处得到的divs实际是一个对象 const divsArr = [...divs] // 将其转为真正的数组,从而可以使用数组的api譬如filter、map console.log(divsArr)
9.Symbol
ES6
引入了一种新的原始数据类型Symbol
,表示独一无二的值。它是JavaScript
语言的第7种数据类型,是一个类似字符串的数据类型
Symbol特点
Symbol
的值是唯一的,用来解决命名冲突的问题Symbol
值不能与其他数据进行运算,也不能与自己进行运算,譬如+、-、*、/、比较运算Symbol
定义的对象属性不能使用for…in
遍历,但是可以使用Reflect.ownKeys
来获取对象的所有键名
创建Symbol
- 通过
let s2 = Symbol('张三')
的方式创建Symbol
,'张三’作为Symbol
描述,作用相当于注释,这种方式创建的Symbol
,即使传入的描述一致,但实际返回的值是不同的
// 创建Symbol let s = Symbol() console.log(s,typeof s) // Symbol() "symbol" let s2 = Symbol('张三') // '张三'作为Symbol描述,作用相当于注释 let s3 = Symbol('张三') // 即使传入的描述一致,但实际返回的值是不同的 console.log(s2 === s3) // false
- 通过
Symbol.for()
创建Symbol
,这种方式创建Symbol
,传入的描述一致,实际返回的值也一致,可以得到唯一的Symbol
值
// Symbol.for创建Symbol let s4 = Symbol.for('张三') let s5 = Symbol.for('张三') console.log(s4 === s5) // true
Symbol使用场景
给对象添加属性和方法。由于Symbol
值具有唯一性,所以可以很安全地把属性和方法加入对象中,如下所示
let game = { up: 'upp', down: 'doown' } let methods = { up: Symbol(), down: Symbol(), } // 添加方法 game[methods.up] = function(){ console.log('up up up') } game[methods.down] = function(){ console.log('down down down') } console.log('game----', game) // 调用 game[methods.up]()
let youxi = { name: '狼人杀', [Symbol('say')]: function(){ // 此处不能直接写 Symbol('say'): function(){...},因为Symbol('say')是动态的,和上面固定的'name'不一样 console.log('发言') } }
Symbol内置值
ES6
除了定义自己使用的Symbol
值以外,还提供了11个内置的Symbol
值,指向语言内部使用的方法,比如
Symbol.hasInstance
当其他对象使用instanceof
运算符,判断是否为该对象的实例时,会调用这个方法
class Person{ static [Symbol.hasInstance](param){ console.log('param----', param) console.log('检测类型') } } let o = {} console.log(o instanceof Person) // param---- {} // 检测类型 // false
Symbol.isConcatSpreadable
对象的Symbol.isConcatSpreadable
属性等于一个bool
值,表示该对象用于Array.prototype()
时,是否可以展开
const arr1 = [1,2,3] const arr2 = [4,5,6] arr2[Symbol.isConcatSpreadable] = false // arr2不可展开 const arr = arr1.concat(arr2) console.log(arr) // [1,2,3,[4,5,6]]
3.Symbol.unscopables
该对象指定了使用with关键字时,哪些属性会被with环境排除
4.Symbol.match
当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值
5.Symbol.replace
当该对象被str.replace(myObject)方法调用时,会返回该方法的返回值
6.Symbol.search
当该对象被str.search(myObject)方法调用时,会返回该方法的返回值
7.Symbol.split
当该对象被str.split(myObject)方法调用时,会返回该方法的返回值
8.Symbol.iterator
对象进行for ... of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器
9.Symbol.toPrimitive
该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值
10.Symbol.toStringTag
在该对象上调用toString方法时,返回该方法的返回值
11.Symbol.species
创建衍生对象时,会使用该属性