var 声明,不合理的地方,可重复声明
var a = 1;
var b = 2;
var 可变量提升,意义不大
console.log(a);//undefined
var a = 12
for 循环中是全局变量,这里的i 是同一份i 变量,所以最后调用的时候i已经变成了10
var arr = []
for(var i=0;i<10;i++;){
arr[i] = function(){
console.log(i)
}
}
console.log(i)//10
arr[0]()//10
arr[1]()//10
arr[2]()//10
如果我们想要
arr0 打印 0
arr1 打印 1 怎么办呢
将var 换成 let
var arr = []
for(let i=0;i<10;i++;){
arr[i] = function(){
console.log(i)
}
}
console.log(i)//10
arr[0]()//0
arr[1]()//1
arr[2]()//2
let 特点
1.不存在变量提升`
console.log(a)//报错
let a = 23
2.在大括号里面声明的是局部变量
let a = 10
add(){
let a = 23
}
if(true){
cosnole.log(a)//报错
let a = 45// 一旦声明了,外面的全局变量a 就不能进来,这叫暂时性死区
}
add()
console .log(a)//10 全局变量访问不了局部变量
这里的三个a 是不同的3个变量
3.不允许重复声明
const 特点
let 有的特点,const 也有,他用来声明一个常量,一旦声明就不允许更改,否则会报错
小练习
for(let i=0;i<10;i++;){
let i = "qwe"
console.log(i)
}
//这里会打印三次 qwe 因为小括号的i是一个局部作用于,大括号里的i也是一个局部作用域,并且小括号是大括号的父级作用域
函数的参数是局部变量
function(arg){
let arg;//报变量重复声明的错
}
变量的解构赋值
1.数组的解构赋值
let arr = [1,2,3]
let [a,b,c,d = 0] = arr
a//1
b//2
c//3
d可以设置默认值
2.对象的解构赋值
对象的简写。当健名和健值一样时候
let obj ={
a,
b,
add(){} //add: function(){} 函数的简写
}
let datas = {
name:"hehe",
age:13
}
let {name:name,age:age} = datas
name // hehe
age //13
//因为对象可以简写
let {name,age} = datas
//可以解构原型上的属性
let {toString} = datas
//数组也可以按照对象的这种方式解构
let {"0":a} = [1,2]
a//1
let {length} = [1,2,3]
length//2
字符串也可解构赋值,用的不多 省略
展开运算符…
let arr = [1,2,3] //展开后 ...arr => 1,2,3
let bb = [...arr] // bb [1,2,3] bb和arr 是不同的两个数组 复制了一份
let obj = {a:1,b:2}// ...obj => a:1,b:2
let objt = {...obj} //相当于拷贝了一份
let obj1 = {name:"fenfen",age:18}
let obj2 = {sex:male}
let bobj = {...obj1,...obj2}//bobj {name:"fenfen",age:18,sex:male} 合并对象
//函数的形参
function add(...arr){
console.log(arr)
}
add(1,2,3)//[1,2,3]
add(2,3)//[2,3]
模板字符串
`我的名字叫${name},今年${age}岁`
类的理解
在这里插入图片描述
函数的this 的指向
1.this 一般只出现在函数的内部
2,设定this的意义:同一个函数在 不同的执行环境下有不同的效果,换言之,谁调用了这个函数,这个函数内部的this就指向谁
function sayProp(){
console.log(this.name)
}
let obj = {
name:"张三",
sayProp
}
let obj1 = {
name:"李四",
sayProp
}
obj.sayProp()//张三
obj1.sayProp()//李四
3只有在函数执行的时候才能去判断this的指向
4.函数内部的this的指向当前函数的执行环境(函数所挂靠的实例对象)
函数super的指向
1。跟this有同样的特性
2.函数内部的super指向当前函数的执行环境的(函数所挂靠的实例对象)的类的原型
Obiect.prototype.
const obj = {
name:'张三',
sayProp(){
console.log(super)//
}
}
obj.sayProp()//super 指代obj的原型
3。书写的时候只能写在实例的方法里面,不能写在单独的函数里面
改变函数this的指向 call apply bind
call 作用
a 调用函数,让函数执行
b改变this的指向
const obj = {
name:'张三',
sayProp(){
console.log(super)//
}
}
function add(a,b,c){
console.log(a,b,c)
console.log(this)
}
add()//this指向window
add.call(obj,1,2,3)//this 指向了obj 1,2,3 参数传递给了add函数
add.apply(obj,[1,2,3])
let f= add.bind(obj)//不会执行函数,生成了新的函数f,新函数this指向obj
f(1,2,3)//调用新的函数
从上面的例子可以看到apply和call的使用基本是一致的,唯一的区别就是传递参数的方式不一样,apply只能传递两个参数,第二个参数为一个数组
bind 特点
a.bind不能调用函数,让函数执行
b bind 可以改变函数this的指向
c.会生成一个新的函数
箭头函数
//以前的写法
function(){}
//箭头函数的写法
(参数)=> {代码块}
简写—小括号和大括号在一定的情况下可以简写
a.形参只有一个的时候可以省略小括号
res => {}
b.当代码块只有一句话的时候可以省略大括号,默认会在该句代码前加上return
()=> 'hello world'//相当于 ()=> {return 'hello world'}
箭头函数不会去绑定this ,里面的this 指向是根据他的父级执行环境判断的
let person = {
say(){
let m = () => {
cosnole.log(this)//person
}
}
}
person.say()
class 的基本使用
class Person {
//成员方法都是指向实例
constructor(name,age,height,wight){
this.name = name;
this.age = age;
this.height = height;
this.weight = weight;
}
//成员方法中间的沟通是通过this来沟通的
say(){
let {name,age,height,weight} = this
console.log(`我叫${name},今年${age}岁`)
}
}
小练习
创建一个原形的类
class Circle {
constructor(props = {}){
const {
r=20,//圆的半径
color="red",//圆的背景色
x=50,//圆的left
y=50//圆的top
} = props
this.r = r;
this.color = color;
this.x = x;
this.y = y;
this.creatEl();
}
creatEl(){
const {r,color,x,y} = this
this.circle = document.createElement('div');
this.circle.className = 'circle';
this.circle.style.width = `${r*2}px`;
this.circle.style.height = `${r*2}px`;
this.circle.style.bacgroundColor = color;
this.circle.style.top = `${y}px`;
this.circle.style.left = `${x}px`;
dom.appedChild(this.circle);//添加到一个dom 中
}
//生成随机数的方法
random(min,max){
return Math.floor(Math.random()*(max - min) + min)
}
//生成随机颜色
randomColor(){
let strs = ['a','b','c','d','e','f'];
let chars = [...strs]
for(let i=0;i<10;i++){
chars.push(i+'')
}
let color = '#';
for(let i=0;i<6;i++){
let index = this.random(0,chars.length)
color+=chars[index]
}
return color;
}
}
class 的继承
class Base {
//生成随机数的方法
random(min,max){
return Math.floor(Math.random()*(max - min) + min)
}
//生成随机颜色
randomColor(){
let strs = ['a','b','c','d','e','f'];
let chars = [...strs]
for(let i=0;i<10;i++){
chars.push(i+'')
}
let color = '#';
for(let i=0;i<6;i++){
let index = this.random(0,chars.length)
color+=chars[index]
}
return color;
}
}
class Circle extend Base {//Circle继承Base 将公共的方法提取到base中
constructor(props = {}){
super(props);//必须
const {
r=20,//圆的半径
color="red",//圆的背景色
x=50,//圆的left
y=50//圆的top
} = props
this.r = r;
this.color = color;
this.x = x;
this.y = y;
this.creatEl();
}
creatEl(){
const {r,color,x,y} = this
this.circle = document.createElement('div');
this.circle.className = 'circle';
this.circle.style.width = `${r*2}px`;
this.circle.style.height = `${r*2}px`;
this.circle.style.bacgroundColor = color;
this.circle.style.top = `${y}px`;
this.circle.style.left = `${x}px`;
dom.appedChild(this.circle);//添加到一个dom 中
}
//可以继承父类的方法,同时也可以覆写父类的方法,写在自己的类的原型,这时候如果想要调用父类的方法怎么办,super.方法名(),
randomColor(){
return "red"
}
}
数组的方法
let arr = [1,2,3]
//item 数组元素,index:数组元素下标,array:数组本身
arr.forEach((item, index, array) => {
//里面的函数依次执行数组的长度那么多次
})
//这个方法非诚有用,回调函数内部必须要有一个返回值,返回值就作为一个新的数组的元素,和原来的数组arr 里面的元素是一一映射的关系
arr.map(item => {
//这里可以返回任何值,比如数组,对象等
return item + 1
})
//找到第一个满足条件的元素,并且返回元素,特点找到满足条件的元素的时候就停止循环
arr.find(item => {
return item>1
})
//查找第一个满足条件的的元素,这个元素可以是一个对象,比如去查找某个ID 的索引
arr.findIndex(item=>{
return item ==1
})
//筛选出符合条件的所有元素,返回筛选出的心数组,注意和find方法区别
arr.filter(item => {
return item>1
})
//判断数组中所有的元素是否都满足条件,如果都满足就返回true,只要有一个不满足就返回false,当一个不满足的时候就不会继续往下执行(像且符号,&&)
arr.every(item => {
return item>0
})
//判断数组中的元素是否满足条件,只要有一个满足条件就返回true ,全部不满足才返回false(像或者||)
arr.some(item => {
return item > 0
})
//执行次数就数组的长度-1,pre 的初始值是数组的第一个元素,next的初始值就是数组的第二个元素,每执行一次回调函数 return 的值作为下一次执行的初始值,下面这个是求和的方法
arr.reduce((pre,next) => {//
return pre + next
})
//如果有第二个参数,那么执行次数就是数组的长度,且pre 的初始值就是第二个参数,next的初始值就是数组的第一个元素
arr.reduce((pre,next) => {
return pre + next
},3)
对象的方法(静态方法)
Object.assign(obj1,obj2)//把第二个参数,和后面的参数合并在第一个参数上,第一个对象改变并且作为新的对象返回,后面的对象没有被改变
Object.is(参数1,参2)//和比较运算===符效果完全一样,仅仅在比较NAN和NaN的时候行为不一样
Object.keys(obj1)//返回i一个数组,把obj1的key值作为数组的元素
异步的理解
回调地狱
元素有个监听动画完成的事件 transitionend
promise 的使用
function aa(){
return new Promise((resolve,reject) => {
//里面可以去封账请求
let num = Math.random()*5 + 1
if(num > 3){
reject(’失败了‘);//失败的回调
}else{
setTimeout(() => {
resolve(’成功了‘);//成功的回调
},2000)
}
})
}
aa().then((msg) => {
console.log(msg)
},(err) => {
console.log(err)
})
例子
1s后打印1,2s后打印2,3s后打印3
function delayPrint(num,time){
return new Promise(resolve => {
setTimeout(()=>{
resolve(num)
},time)
})
}
delayPrint(1,1000).then((num) => {
console.log(num);
return delayPrint(2,2000)
}).then((num) => {
console.log(num);
return delayPrint(3,3000)
}).then((num) => {
console.log(num);
})
promise 实现分段动画
let animations = ['translateX(500px)','translate(500px,600px)','translate(1000px,600px)'];
let globalResolve = null;
function doAimation(value) {
return new Promise((resolve) => {
dom.style.transform = value;
globalResolve = resolve
})
}
dom.addEventListener('transitionend',() => {
//监听动画完成后再执行成功的回调
globalResolve()
})
//动画的递归函数
function run(index){
//可以不用return 吧????待验证
return doAimation(animations[index]).then(() => run(index+1))
}
dom.onClick = () => {
//doAimation(animations[0]).then(() => doAimation(animations[1])).then(() => doAimation(animations[2]))
run(0)
}