let:
let声明变量的特点,和var有什么不同:
1、变量不能重复声明
2、块级作用域
3、不存在变量提升
4、不影响作用域链,同一个块级作用域下,声明在函数前的变量可以被函数访问到
let小案例:
const:
const的特点:
1、一定要赋初始值
2、一般常量使用大写(不是必须)
3、常量的值不能修改
4、块级作用域
5、对于数组和对象的元素的修改,地址没有改变,不会报错。const定义的变量引用不能修改,值可以修改 const和Object.freeze()搭配使用
解构赋值:
const arr = [100, 200, 300, 400] let [a, b, c, d] = arr console.log(a, b, c, d) // 100 200 300 400 const obj = { name: '孙艺珍', age: 20, doo: function () { console.log('演电影') } } let { name, age, doo } = obj console.log(name) console.log(age) console.log(doo) doo()
对象中的方法频繁调用想到可以使用结构赋值拿出该方法,调用就不用写对象名了
模板字符串:
1、可以直接出现换行符,es5的字符串要用+拼接
2、变量拼接
let str = `模板字符串` console.log(str) let num = 100 console.log(`我今年${num}岁了`) let mo = ` <ul> <li>100</li> <li>100</li> <li>100</li> <li>100</li> <li>100</li> </ul> ` console.log(mo) document.write(mo)
对象简化写法:
let name = `"'syz'"` let doo = function () { console.log('doo') } let person = { name, // name: name doo, // doo: doo improve() { // 省略function关键字 console.log('让你变漂亮') } } console.log(person) person.doo() person.improve()
箭头函数:
1、this是静态的,始终指向函数声明时所在作用域下的this值
2、不能作为构造函数实例化对象
3、不能使用arguments变量
4、简写 1)省略小括号:有且只有一个形参时 2)省略花括号:代码体有且只有一条语句时,此时语句的执行结果就是函数的返回值,return也必须要省略
function fn() { console.log(this.name) } // 1、this是静态的,this始终指向函数声明时所在作用域下的this的值 let fn1 = () => { console.log(this.name) } window.name = '孙艺珍' fn() // 孙艺珍 fn1() // 孙艺珍 let person = { name: '吴小明' } fn.call(person) // 吴小明 fn1.call(person) // 孙艺珍 this始终指向函数声明时所在作用域下的this的值 // 2、不能作为构造函数实例化对象 let Person = (name, age) => { this.name = name this.age = age } // let p = new Person('xx', 20) // Uncaught TypeError: Person is not a constructor // 3、不能使用arguments变量 function xx() { console.log(arguments) } xx(1, 2, 3) // Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ] let yy = () => { console.log(arguments) } // yy(1, 2, 3) // Uncaught ReferenceError: arguments is not defined // 4、简写 省略小括号:有且只有一个形参时可以省略 省略花括号:当代码体有且只有一条语句时可以省略,此时语句执行的结果就是函数的返回值,return语句也必须要省略 let add = n => { return n + n } console.log(add(4)) // 8 let add1 = n => n + n console.log(add1(5)) // 10
使用场景:
1、this指向上一级的this,函数嵌套时,里层函数中使用外层函数的this,此时可以使用箭头函数。如果使用es5的函数,第一种方法是在里层函数的上方定义变量 let _this = this 保存外层函数的this;第二种方法是调用时利用call()或apply(),如:xxx.call(this)
2、数组的方法回调中使用箭头函数
// 返回数组中偶数项 let arr = [1, 2, 3, 4, 5, 6] const even = arr.filter(function (item) { return item % 2 === 0 }) console.log(even) const even1 = arr.filter(item => item % 2 === 0) console.log(even1)
总结:
1、箭头函数适合与this无关的回调,定时器,数组的方法回调
2、箭头函数不适合与this有关的回调,事件回调,对象的方法
参数默认值:
1、形参初始值:具有默认值的参数----一般有初始值的参数位置放在后面,如果将参数c的位置放在前面或中间此时的值是NaN,因为b的值是undefined
function add(a, b, c = 10) { return a + b + c } console.log(add(1, 2))
2、和解构赋值结合
function connect({ host = '127.0.0.1', username, password, port }) { console.log(host) console.log(username) console.log(password) console.log(port) } connect({ host: 'baidu.com', username: 'root', password: 'root1', port: 3000 })
rest参数:
// ES5获取实参的方式:arguments function fn() { console.log(arguments) } fn(100, '200', true) // Arguments(3) [100, "200", true, callee: ƒ, Symbol(Symbol.iterator): ƒ] // ES6引入 rest 参数,用于获取实参,代替arguments function fn1(...rest) { console.log(rest) } fn1(100, '200', true) // [100, "200", true] // rest 参数必须放到参数最后 function fn2(a, b, ...rest) { console.log(a, b, rest) } fn2(100, '200', true, {}) // 100 "200" (2) [true, {…}]
注意:arguments是一个类数组,rest是一个数组
扩展运算符:
const arr=['孙艺珍','吴小明','郭德纲'] function fn(...rest){ console.log(rest) } // 扩展运算符能将数组转换为逗号分隔的参数序列 // fn(...arr) // ["孙艺珍", "吴小明", "郭德纲"] fn('孙艺珍','吴小明','郭德纲') // ["孙艺珍", "吴小明", "郭德纲"]
...的使用:
// 数组的合并 const arr = ['唐僧', '八戒'] const arr1 = ['沙悟净', '悟空'] const newArr = arr.concat(arr1) // ["唐僧", "八戒", "沙悟净", "悟空"] const newArr1 = [...arr, ...arr1] // ["唐僧", "八戒", "沙悟净", "悟空"] console.log(newArr) console.log(newArr1) // 数组的拷贝(浅拷贝) const copyArr = [...arr] console.log(copyArr) // ["唐僧", "八戒"] // 将伪数组转为真正的数组 const divs = document.querySelectorAll('div') const divArr = [...divs] console.log(divs) // NodeList(3) [div, div, div] console.log(divArr) // [div, div, div]
Symbol:
/* Symbol: ES6新引入的简单数据类型,表示独一无二的值。它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。 Symbol特点: 1、Symbol的值是唯一的,用来解决命名冲突的问题 2、Symbol值不能与其他数据进行运算 3、Symbol定义的对象属性不能使用 for...in 循环病遍历,但是可以使用Reflect.ownKeys 来获取对象的所有键名 */ // 创建Symbol let s1 = Symbol() console.log(s1, typeof s1) // Symbol() "symbol" let s2 = Symbol('孙艺珍') let s3 = Symbol('孙艺珍') console.log(s2) // Symbol(孙艺珍) console.log(s3) // Symbol(孙艺珍) console.log(s2 == s3) // false // Symbol.for() 创建 let s4 = Symbol.for('小明') let s5 = Symbol.for('小明') console.log(s4) // Symbol(小明) console.log(s5) // Symbol(小明) console.log(s4 === s5) // true
Symbol给对象中添加属性和方法的两种方式:
// 1、利用Symbol给对象中添加方法 let game = { name: '俄罗斯方块', up: function () { console.log('我是up') }, down: function () { console.log('我是down') } } let methods = { up: Symbol(), down: Symbol() } // 如果直接写 game.up=function(){} 可能会替换掉 game 中原有的方法 game[methods.up] = function () { console.log('upupupupup') } game[methods.down] = function () { console.log('downdown') } console.log(game) game.up() // 2、Symbol() 不能直接作为键使用,可以写成 [Symbol('xxx')] let youxi = { name: '狼人杀', [Symbol('say')]: function () { console.log('我可以说话') }, [Symbol('zibao')]: function () { console.log('我可以自爆') } } console.log(youxi)
Symbol内置值:
Symbol.hasInstance | 当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法 |
Symbol.isConcatSpreadable | 对象的Symbol.isConcatSpreadable属性等于的是一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开 |
Symbol.species | 创建衍生对象时,会使用该属性 |
Symbol.match | 当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值 |
Symbol.replace | 当该对象被str.replace(myObject)方法调用时,会返回该方法的返回值 |
Symbol.search | 当该对象被str.search(myObject)方法调用时,会返回该方法的返回值 |
Symbol.split | 当该对象被str.split(myObject)方法调用时,会返回该方法的返回值 |
Symbol.iterator | 对象进行for...of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器 |
Symbol.toPrimitive | 该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值 |
Symbol. toStringTag | 在该对象上面调用toString方法时,返回该方法的返回值 |
Symbol. unscopables | 该对象指定了使用with关键字时,哪些属性会被with环境排除 |
// Symbol.hasInstance class Person { static [Symbol.hasInstance](param) { console.log(param) // {name: "111"} console.log('我被用来检测数据类型了') return true } } let obj = { name: '111' } let result = obj instanceof Person // true console.log(result) // Symbol.isConcatSpreadable let arr = [1, 2, 3] let arr1 = [4, 5, 6] arr1[Symbol.isConcatSpreadable] = false // 设置不可以展开 let newArr = arr.concat(arr1) console.log(newArr) // [1, 2, 3, Array(3)] console.log(newArr[3]) // [4, 5, 6, Symbol(Symbol.isConcatSpreadable): false]
注意:遇到唯一性的场景时要想到Symbol
迭代器:
遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据只要部署 Iterator 接口(对象中的一个属性),就可以完成遍历操作。
原生具备 Iterator 接口的数据(可用for...of遍历):Array、Arguments、Set、Map、String、TypedArray、NodeList
工作原理:
1、创建一个指针对象,指向当前数据结构的起始位置
2、第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
3、接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
4、每调用 next 方法返回一个包含 value 和 done 属性的对象
// for...of 遍历值,for...in 遍历键 let str = '123456789' for (item of str) { console.log(item) } let arr = [1, 2, 3, 4, 5] for (item of arr) { console.log(item) } let iterator = arr[Symbol.iterator]() console.log(iterator) console.log(iterator.next()) // {value: 1, done: false} console.log(iterator.next()) // {value: 2, done: false} console.log(iterator.next()) // {value: 3, done: false} console.log(iterator.next()) // {value: 4, done: false} console.log(iterator.next()) // {value: 5, done: false} console.log(iterator.next()) // {value: undefined, done: true}
自定义遍历数据:
const banji = { name: '重点班', students: ['小明', '小红', '小芳', '小华'], // 自定义iterator接口函数 [Symbol.iterator]() { let index = 0 let _this = this return { next: function () { if (index < _this.students.length) { const result = { value: _this.students[index], done: false } index++ return result } else { return { value: undefined, done: true } } } } } } for (let item of banji) { console.log(item) }
注意:需要自定义遍历数据的时候,要想到迭代器
生成器:
生成器函数是ES6提供的一种异步编程方案,语法行为与传统函数完全不同
特点:
1、* 的位置没有限制
2、生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到 yield 语句后的值
3、yield 相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next 方法,执行一段代码
4、next 方法可以传递实参,作为 yield 语句的返回值
function * fn() { console.log(111) yield '你好呀' console.log(222) yield '我是安徽人' console.log(333) yield '你是哪里人' console.log(444) } let iterator = fn() // 生成迭代器对象 console.log(iterator.next()) // {value: "你好呀", done: false} console.log(iterator.next()) // {value: "我是安徽人", done: false} console.log(iterator.next()) // {value: "你是哪里人", done: false} console.log(iterator.next()) // {value: undefined, done: true} // 遍历 for(let item of fn()){ console.log(item) // 返回结果为 yield 表达式后的内容 }
生成器函数参数:
function* gen(arg) { console.log(arg) // AAA let one = yield 111 console.log(one) // BBB 调用 next() 时传入的参数作为 yield 语句的返回值----第二次调用 next() 传入的参数作为第一个 yield 语句的返回值 let two = yield 222 console.log(two) // CCC let three = yield 333 console.log(three) // DDD let four = yield 444 console.log(four) // undefined } let iterator = gen('AAA') // 获取迭代器对象 console.log(iterator.next()) // {value: 111, done: false} console.log(iterator.next('BBB')) // {value: 222, done: false} console.log(iterator.next("CCC")) // {value: 333, done: false} console.log(iterator.next('DDD')) // {value: 444, done: false} console.log(iterator.next()) // {value: undefined, done: true}
小案例:
1、异步编程:1秒后输出111,2秒后输出222,3秒后输出333
// 第一种:回调地狱问题 setTimeout(() => { console.log(111) setTimeout(() => { console.log(222) setTimeout(() => { console.log(333) }, 3000); }, 2000); }, 1000); // 第二种:利用生成器函数,获取迭代器对象,通过调用迭代器的 next() 方法一步步执行one two three function one() { setTimeout(() => { console.log(111) iterator.next() }, 1000); } function two() { setTimeout(() => { console.log(222) iterator.next() }, 2000); } function three() { setTimeout(() => { console.log(333) iterator.next() }, 3000); } function* gen() { yield one() yield two() yield three() } let iterator = gen() // 调用生成器函数,获取迭代器对象 iterator.next()
2、场景:请求接口当前接口需要依赖于上一次请求返回的数据,生成器函数是异步的,此处可以替代回调函数,解决回调地狱问题
// 先拿到用户数据,再拿到订单数据,再拿到商品数据 function getUsers() { setTimeout(() => { let data = '用户数据' iterator.next(data) }, 1000); } function getOrders() { setTimeout(() => { let data = '订单数据' iterator.next(data) }, 1000); } function getGoods() { setTimeout(() => { let data = '商品数据' iterator.next(data) }, 1000); } function* gen() { let users = yield getUsers() console.log(users) let orders = yield getOrders() console.log(orders) let goods = yield getGoods() console.log(goods) } let iterator = gen() iterator.next()
Promise:
Promise是ES6引入的异步编程的新解决方案。语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果
Promise基本语法:
const p = new Promise(function (resolve, reject) { setTimeout(() => { let data = '数据' // resolve(data) reject('失败') }, 100); }) p.then(function (value) { console.log(value) }).catch(function (err) { console.log(err) })
Promise封装读取文件:
const fs = require('fs') // 1、直接读取 // fs.readFile('./resources/插秧诗.md', (err, data) => { // if (err) throw err // console.log(data.toString()) // }) // 2、使用Promise封装 const p = new Promise(function (resolve, reject) { fs.readFile('./resources/为学.md', (err, data) => { if (err) reject(err) resolve(data) }) }) p.then(function (value) { console.log(value.toString()) }).catch(function (err) { console.log(err) })
Promise封装ajax:
// 1、原生ajax const xhr = new XMLHttpRequest() xhr.addEventListener('load', loadHandler) // Firefox 支持 load 事件 xhr.open('get', 'https://api.apiopen.top/getJoke') xhr.send() function loadHandler() { if (xhr.readyState === 4 && xhr.status === 200) { // console.log(xhr.response) } else { console.error(xhr.status) } } // 2、Promise封装 const p = new Promise(function (resolve, reject) { const xhr1 = new XMLHttpRequest() xhr1.addEventListener('load', loadHandler1) xhr1.open('get', 'https://api.apiopen.top/getJoke') xhr1.send() function loadHandler1() { if (xhr1.readyState === 4 && xhr1.status === 200) { resolve(xhr1.response) } else { reject(xhr1.status) } } }) p.then(function (value) { console.log(value) }).catch(function (err) { console.error(err) })
Promise读取多个文件,避免回调地狱:
const fs = require('fs') // 1、使用回调,会有回调地狱问题 // fs.readFile('./resources/为学.md', (err, data) => { // fs.readFile('./resources/插秧诗.md', (err, data1) => { // fs.readFile('./resources/观书有感.md', (err, data2) => { // const result = data + ' ' + data1 + ' ' + data2 // console.log(result) // }) // }) // }) // 2、使用 Promise 实现 const p = new Promise((resolve, reject) => { fs.readFile('./resources/为学.md', (err, data) => { resolve(data) }) }) p.then((value) => { return new Promise((resolve, reject) => { fs.readFile('./resources/插秧诗.md', (err, data) => { resolve([value, data]) }) }) }) .then((value) => { return new Promise((resolve, reject) => { fs.readFile('./resources/观书有感.md', (err, data) => { value.push(data) resolve(value) }) }) }) .then((value) => { console.log(value.join(' ')) })
x