let
1、let 声明的成员只会在所声明的块中生效
2、let 在 for 循环中的表现
总结:
1.如果用var包裹2层for,里层for会循环所有,外层for只打印一次;
2.如果外层用var,里层用let,外层会打印总次数。
3、let 应用场景:循环绑定事件,事件处理函数中获取正确索引
总结:
1.使用for用var,变量i是var命令声明的,在全局范围内都有效,循环内的i指向的就是全局的i,输出的是最后一轮的i的值,只会返回最大的数值;
2.否则就采用(function(j){})(i),第一个括号定义了一个匿名函数,后一个括号是指调用了这个函数,并传入参数i。当然这个匿名函数接受一个参数,命名为j。
3.使用for用let会返回对应的数值,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量。JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
4、for 循环会产生两层作用域
总结:
for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。
let注意:
1、没有预解析,不存在变量提升
**在代码块内,只要let定义变量,在之前使用,都是报错**
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
**先定义完,再使用**
2、同一个作用域里,不能重复定义变量
3、for循环,for循环里面是父级作用域,里面又一个
块级作用域:
{
//块级作用域
}
{{{let a = 12}}} //ES6 允许块级作用域的任意嵌套。内层作用域可以定义外层作用域的同名变量。
if(){}
for(){}
while(){}
补充:
4.块级作用域的出现,实际上使得获得广泛应用的匿名立即执行函数表达式(匿名 IIFE)不再必要了。
5.块级作用域内部,优先使用函数表达式
{
let a = 'secret';
let f = function () {
return a;
};
}
6.ES6 的块级作用域必须有大括号
如果没有大括号,JavaScript 引擎就认为不存在块级作用域。
函数声明也是如此,严格模式下,函数只能声明在当前作用域的顶层。
为什么需要块级作用域?
第一种场景,内层变量可能会覆盖外层变量。
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
第二种场景,用来计数的循环变量泄露为全局变量。
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
const
1、恒量声明过后不允许重新赋值
2、恒量要求声明同时赋值
3、恒量只是要求内层指向不允许被修改
4、对于数据成员的修改是没有问题的
const注意:
const:特性和let一样
const定义变量不能修改
const定义完变量,必须有值,不能后赋值,不能修改
Object.freeze(对象) 将对象冻结
const可以通过s[0],s[1],s[2]改变数组
结构赋值
1、非常有用,特别在做数据交互 ajax
let [a,b,c] = [12,5,6];
注意:左右两边,结构格式要保持一致
2、解构的时候可以给默认值:
let [a,b,c='默认值'] = ['aaa','bbb'];
3、import {a,b,c} from './mod'
字符串模板
1、字符串模板:
关于字符串的一些东西
优点:可以随意换行
`${变量名字}`
2、字符串查找:
str.indexOf(要找的东西) 返回索引(位置),没找到返回-1
str.includes(要找的东西) 返回值 true/false
(1)判断浏览器:
if(navigator.userAgent.includes('Chrome')){
alert('是');
}else{
alert('不是');
}
3、字符串是否以谁开头:
str.startsWith(检测东西)
4、字符串是否以谁结尾:
str.endsWith(检测东西)
(1)检测地址
(2)检测.png等
5、重复字符串:
str.repeat(次数);
6、填充字符串:
str.padStart(整个字符串长度,填充东西) 往前填充
str.padEnd(整个字符串长度,填充东西) 往后填充
函数默认参数、箭头函数、剩余参数
1、函数变化:
*函数默认参数
*函数参数默认已经定义了,不能再使用let,const声明
2、扩展运算符、reset运算符(3个点)
3、剩余运算符,必须放到最后
4、箭头函数:
()=>return东西
()=>{
语句
return
}
注意:
1、this问题,定义函数所在的对象,不再是运行时所在的对象。
2、箭头函数里面没有arguments。
3、箭头函数不能当构造函数
proxy(代理)
1、扩展(增强)对象一些功能
比如:
Vue
Vue.config.keyCodes.enter=65
2、Proxy作用:比如Vue中拦截
预警、上报、扩展功能、统计、增强对象等
proxy是设计模式,代理模式
------------------------------------------------
let obj={
name:'Stive'
}
//您访问了name
obj.name
------------------------------------------------
语法:
new Proxy(target,handler);
let obj = new Proxy(被代理的对象,对代理的对象做什么操作)
handler
{
set();
get();
deleteProperty();
has();
apple()
...
}
实现一个,访问一个对象身上属性,默认不存在的时候给了undefined,希望如果不存在错误(警告)信息;
Reflect
1、set(),设置,拦截:
2、deleteProperty():删除,拦截
3、has():检测
4、Reflect.apple(调用函数,this指向,参数数组);
fn.call()
fn.apple() 类似
Reflect:反射
Object.xxx 语音内部的一些方法
Object.defineProperty
放到Reflect对象身上
通过Reflect对象身上直接拿到语言内部东西
'xxx' in Object -> Reflect.has(Object,'assign')
delete json.a -> Reflect.deleteProperty()
类(class)和继承
类:
1、 -----------------
const Person = class{}
-----------------
let a = 'strive';
let b = 'method';
class Person{
[a+b](){
}
}
2、注意:
1、es6里面class没有提升功能,在es5,用函数模拟可以,默认函数提升
2、es6里面this比之前轻松多了
矫正this:
1、fn.call(this指向谁,args1,args2,......)
2、fn.apply(this指向谁,[args1,args2,......])
3、fn.bind()
3、class里面取值函数(getter),存值函数(setter)
4、静态方法:就是类身上方法
继承:
之前:
Person
Student
es5的写法
现在:
extends
拖拽
Set和WeakSet
1、数据结构:
数组
json,二叉树...
2、set数据结构:
类似数组,但是里面不能有重复值
let arr = ['a','b','c'];
let arr = new Array();
3、set用法:
let setArr = new Set(['a','b']);
setArr.add('a'); 往setArr里面添加一项
setArr.delete('b'); 删除一项
setArr.has('a'); 判断setArr里面有没有此值
setArr.size 个数
setArr.clear() 清空
for...of...
循环:
数组去重
set数组结构变成数组
[...set]
想让set使用数组的,map循环和filter
let arr = [{},{}];
new Set([]); 存储数组,这种写法对
new WeakSet({}); 存储json,这种写法不靠谱 (不靠谱,不推荐)
WeakMap没有size,也没有clear();
确认,初始往里面添加东西,是不行的,最好用add添加
map和WeakMap
map:
1、map:
类似json,但是json的键(key)只能是字符串
map的key可以是任意类型
2、使用:
let map = new Map();
map.set(key,value); 设置一个值,(key可以是任何的值)
map.get(key); 获取一个值
map.delete(key); 删除一项 没有返回undefined
map.has(key); 判断有没有
map.clear(); 清空
3、循环:
for(let [key,value] of map){}
for(let key of map.keys()){};
for(let value of map.values()){}
for(let [k,v] of map.entries()){}
map.forEach((value,key) => {
console.log(value,key);
})
WeakMap():
1、key只能是对象
总结:
Set 里面是数组,不重复,没有get方法
Map 对json功能增强,key可以是任意类型值
Symbol & generator
数据类型:
number、string、boolean、Object、undefined、function...
用typeof检测出来数据类型:
symbol
new Number(12)
new String()
new Array()
1、symbol 使用情况一般
定义:
let syml = Symbol('aaa');
注意:
1、Symbol不能new
2、Symbol()返回是一个唯一值
坊间传说:做一个key,定义一些唯一或者私有东西
3、symbol是一个单独的数据类型,就叫symbol,基本类型
4、如果symbol作为key,用for in循环,出不来
json -> for in
箭头函数:
()=>
2、generator函数
生成器
解决异步,深度嵌套的问题,async
语法:
function * show(){
yield
}
function* show(){
}
function *show(){
}
for...of 自动遍历 generator
return的东西,它不会遍历
generator不仅可以配合 for...of...还可以:
1、结构赋值:
let[a,...b] = gen();
2、扩展运算符:
‘...’
3、Array.from()
generator结合 axios数据请求:
异步:不连续,上一个操作没有执行完,下一个操作照样开始
同步:连续执行,上一个操作没有执行完,下一个操作没法开始
关于异步,解决方案:
1、回调函数
2、事件监听
3、发布/订阅
4、Promise对象
数组循环
数组:
ES5里面新增一些东西
循环:
1、for
for(let i=0; i<arr.length; i++){}
2、while
arr.forEach() //代替普通for
arr.map() //非常有用,做数据交互 “映射”
正常情况下,需要配合return,返回是一个新数组
若是没有return,相当于forEach
注意:平时只要用map,一定是要有return
重新整理数据结构:
[{title:'aaa'}] -> [{t:'aaa'}]
arr.filter()
过滤,过滤一些不合格“元素”,如果回调函数返回true,就流下来
arr.some()
类似查找。数组里面某一元素符合条件,返回true
arr.every()
数组里面所有的元素都要符合条件,才返回true
其实他们可以接收两个参数:
arr.forEach/map...(循环回调函数,this指向谁);
arr.reduce() //从左往右
求数组的和、阶乘
arr.reduceRight() //从右往左
for ... of...:
arr.keys() 数组下标
arr.entries() 数组的某一项
扩展运算符:
...
let arr = [1,2,3];
let arr2 = [...arr];
let arr2 = Array.from(arr);
Array.from:
作用:把类数组(获取一组元素,arguments...)对象转成数组
个人观点:具备length这个东西,就靠谱
Array.of:
Array.find():
查找,找出第一个符合条件的数组成员,如果没有找到,返回undefined
Array.findIndex():
找的是位置,没找到返回-1
Array.fill():
arr.fill(填充的东西,开始位置,结束位置)
arr.indexOf()
arr.includes()
atr.includes()
ES2017新增一个运算符:
幂
Math.pow(2,3)
2**3
Promise
1、promise 承诺,许诺
作用:解决异步回调问题
传统方式,大部分用回调函数,事件
ajax(url,{ //获取token
ajax(url,()=>{ //获取用户信息
ajax(url,()=>{
//获取用户新闻
}){
}
})
})
Promise.catch(err=>{})
new Promise().then(res=>{
}).catch(err=>{
})
Promise.resolve("aa"): 将现有的东西,转成一个promise对象,resolve状态,成功状态
↓等价于
new Promise(resolve =>{
resolve("aaa");
})
Promise.reject("aa"): 将现有的东西,转成一个promise对象,reject状态,失败状态
↓等价于
new Promise(reject =>{
reject("aaa");
})
Promise.all(p1, p2, p3): 把promise打包,扔到一个数组里面,打包完还是一个promise对象。
必须确保,所有的promise对象,都是resolve状态,都是成功的状态
Promise.race(p1,p2,p3): 只要有一个成功,就返回
async、await
ES2017,规定 async
nodeJS
读取文件 方式,readFile
1.promise
2.genrator
3.async
-----------------------------------------------
async function fn(){ //表示异步,这个函数里面异步任务
let result = await xxx //表示后面结果需要等待
}
------------------------------------------------
async特点:
1.await只能放到async函数中
2.相比genrator语义化更强
3.await后面可以是promise对象,也可以数字,字符串,布尔。
4.async函数返回是一个promise对象
5.只要await语句后面Promise状态变成reject,那么整个async函数会中断执行
如何解决async函数中抛出错误,影响后续代码
a:
try{
}catch(e){
}
b:promise本身catch
个人建议大家
任何有await的地方,都try{}catch(e){}掉
Promise.all([])
ES6 声明变量的6种方法
var function let const import class