一.定义变量
1,var
2,let
- let和var的区别:
1.let声明的变量不存在变量提升;
2.let不可以重复声明变量;
3.块作用域;{}代码块包含的区域; let声明的变量在块作用域,只在块作用域中有效4.暂时性死区for(let i=0;i<ali.length;i++){ ali.onclick=() =>{console.log(i)//i=0,1,2 } } console.log(i);//会报错,因为let声明的变量只在块作用域内有效
在块作用域内,let声明的变量必须在定义后调用,否则会报错;
3,const
- const声明的变量不能二次赋值;必须在定义声明时直接赋值;
- const定义引用类型的常量时,栈中存储的指针地址不可以修改,但堆中对应的内容可以改变(类比C++中的指针常量 int*const p)
二,解构赋值
1,数组
let a-1;
let b=2; <=>let[a,b,c]=[1,2,3];
let c=3;
2, 对象
obj={
name:'xx',
age=2
}
let{name,age}=obj;
对象的解构,按照key赋值,想用某一变量代表某一属性时,可以写成{name:x}
3,字符串
把字符串中的每一项提取出来,按照顺序一一对应,分别赋值;
例
let a=1;
let b=2
交换变量a,b的值
方法一:[a,b]=[b,a];
方法二:let tem=a;
a=b;
b=tem;
方法三:{a:b,b:a}={a:1,b:2}
三,当给方法传入默认值时,只有当实参==undefined时,方法的参数才会等于默认值
四,扩展运算符
用途
- 作为数组的一部分;
- 数组复制,可以实现深拷贝;
- 数组合并,但不会改变原数组,类似.concat()
- 合并对象(不同属性直接合并,相同属性后边会覆盖前面的对象属性)
- 把类数组转化成数组 let ali=[...ali]
五,rest
function fun(){
coonsole.log(arguments,callee)//当没有设置形参时,argument可以用来接收实参,是一个数组
//callee是这个函数本身
}(1,2,3,4)
六,函数的扩展
1,fun.length 可以获取没有默认值以外的形参的个数;
2,fun.name 获取方法名fun;
3,箭头函数
形式:定义var fun=()=>{}
区别:箭头函数中的this 指针指向父作用域中的this,且箭头函数不可以使用arguments获取额外实参,可以用rest代替;
七,字符串扩展
1,拼接
let a='url='_start+'count='+_count =>let a=`url=${_start}&count=${_count};
2, 方法
1,includes
判断字符串中是否含有某字符
str.includes('') 有,返回true,没有,返回false;
类似方法:str.indexof('')有,返回该字符的索引值,没有,返回-1;
2,startsswith、endwith
检索参数字符串或字符是否在字符串的头部/尾部;返回true/false
3,padstart/padend
padstart(num,'b')num传入数值,指定字符串的总长度;'b'是指传入的指定字符,利用字符从头部补全字符串到指定位置;
padsend(num,'b')num传入数值,指定字符串的总长度;'b'是指传入的指定字符,利用字符从尾部补全字符串到指定位置;
4,repeat
str.repeat(num)数值代表重复几次字符串;
八,数值的扩展
1,将es5中window下面的方法转化成number下的方法
- Number.isFinite()判断是否为数字;
- Number.isNaN()只有当括号内内容为NaN时返回值为true,其他时为false;
- Number.isInteger()判断是否为整数;
- Number.ParseFloat()保留小数;
- Number.Int()保留整数;
2,math下新增的方法
- math.trunc()除去小数部分,返回整数;
- Math.sign()判断一个数是正数(返回1),负数(返回-1),0(返回0),还是NaN;当传入字符串'67'会自动转化成67;
九,数组的扩展
1,Array from把类数组转化为数组(利用拓展运算符也可以)
2,Array of把值转化成数组
var a=new Array(3)长度为三的空数组;
a=Array of(3)[3]
3,arr.copywithin替换数组中的内容;
let arr = [1,2,3,4,5,6,7,8,9,10]
console.log(arr.copyWithin(0,2,3))
console.log(arr)
// [3, 4, 5, 4, 5, 6, 7, 8, 9, 10]
// [3, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 返回第一个符合判断条件的内容
4,arr.find(function(value,index,array){})
返回第一个满足条件的值
let arr1 = [1,2,5,2,7,8]
let a1 = arr1.find(function(val, index ,arr){
return val>3
})
5,arr.fill()
补全数组
arr.fill(a1,a2,a2)a1代表补全数组所利用的字符,a2表示从哪个位置开始补全数组,a3表示在哪个位置之前结束
6,arr.includes()
判断数组中是否包含某个数值,返回布尔值;
7,for of
let a=[1,2,4];
for(values of a){
console.log(values)=>1,2,4
}
循环后取出每一项的值
把a变成a.keys(),循环后拿到索引值;
把a变成a.values(),循环后拿到每一项的值;
把a变成a.entries(),循环后拿到每一项对应索引及数值;是一个数组;
8,foreach()
遍历
p.forEach(function(value, key){
console.log(value)
console.log(key)
})
遍历后取出的是每一项对应的值和索引;
9,filter
过滤
返回所有符合条件的值,是一个数组;和find()功能类似;
十,对象的扩展
1,属性和方法的简写
当属性等于某一变量时,且属性名和变量名刚好相等时,可以省区变量名;
定义对象时可以省略function;
let name='zs';
let age=1;
let obj={
name:name,
age:age,
eat:function(){}
}
可以简写为
let obj{
name,
age,
eat(){}
}
2,属性名的表达式
例:obj[age+'name']=aaa;
3,obj.is(a,b)
判断a,b是否严格相等,多数情况下等价于===;
特例:
console.log(NaN===NaN)//false
(object.is(NaN,NaN)//true;
console.log(+0===-0)//true
(object.is(+0,-0)//flase;
4,object.assign(obj1,obj2)
合并对象 不同属性值合并,相同属性值后面覆盖前面
等价于object=(...obj1,...obj2)
返回后的obj1是合并后的数组 若不想改变原数组的值,可以写成object.assign({},obj1,obj2)
5,obj.keys()/values()/entries()
同数组意义相同;keys拿到的是对象的属性;values拿到的是对象的值;entries拿到的是属性和值
6,for of
let a={
name:'xx',
age:12
}
for(values of a){
console.log(values)
}
循环后取出每一项的值
把a变成a.keys(),循环后拿到索引值;
把a变成a.values(),循环后拿到每一项的值;
把a变成a.entries(),循环后拿到每一项对应索引及数值;是一个数组;
7,a in obj
判断该对象下是否有某个属性;当a为数字时,则是判断某数组对应索引下是否有某个数值
十一,symbol
基本数据类型,表示独一无二的值;
-
var a=symbol();
obj[a]=''; -
var[symbol()]=''
注:当数据类型为symbol时,不管是否属性名与已有属性名相同,都不会被覆盖
十二,set
可以实现数组的去重,返回的是一个类数组,默认的属性是size,相当于数组的length;
数组去重的两种方法
* var a1=[1,2,2,3,3];
var a2=new set(a1);
* for(var i=0;i<a1.length;i++){
if(!a2.includes(a1[i])){
a2.push(a1[i]);
}
}
var b=new set(a1);
set定义数组具有的方法:
b.add();追加
b.delect();删除返回布尔值
b.has(); 返回布尔值
十三,map
创建的是一个类对象
let p1=new map();
p1.set('name',value)设置一个属性;
p1.get(key)获取一个属性对应的值;
p1.has(key)判断是否含有某属性,返回布尔值;
p1.delect(key)删除某个属性
将类对象转化为对象
1,let p2={};
p1.forEach(function(value,key){
p2[key]=value;
2,for(item of p1){p1[item(0)]=item[1];
十四,AJAX
可以实现不刷新页面而请求数据
1,原生方法
过程:
1.创建XMLHttpRequest对象
var xmlhttp;
if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else {// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
2.请求
xmlhttp.open("GET"/"POST","getData.json",true/flase);//true表示异步请求,false表示同步请求
xmlhttp.send();
3.响应
xmlhttp.onreadystatechange = function(){
if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
console.log(xmlhttp.responseText); // string
console.log(JSON.parse(xmlhttp.responseText))
}
}
xmlhttp.readyState返回值:
0: 请求未初始化
1: 服务器连接已建立
2: 请求已接收
3: 请求处理中
4: 请求已完成,且响应已就绪
xmlhttp.status返回值
200: ok
304: Not Modified 客户端有缓存的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。
400: Bad Request 请求出现语法错误
404: 找不到资源
500: 服务器错误
505: HTTP Version Not Supported 服务器不支持请求中所指明的HTTP版本
2,利用Jquery实现AJAX
$.ajax({
url: 'getData.json',
data: {
start: 0,
count: 10,
_: Math.random()//防止因请求数据相同只调用一次的现象
},
method: "GET",
success: function(res){
console.log(res)
$.ajax({
url: 'getData.json',
data: {
start: 0,
count: 10,
_: Math.random()
},
method: "GET",
success: function(res){
$.ajax({
url: 'getData.json',
data: {
start: 0,
count: 10,
_: Math.random()
},
method: "GET",
success: function(){
}
})
}
})
}
});
3,AJAX回调地狱——利用setTimeout模拟发送请求
setTimeout(function(){
console.log('1-success')
setTimeout(function(){
console.log('2-success')
},2000)
},1000)
十五,promise ?
1,异步请求的实现方式
// p 是一个 Object
let p = new Promise((resolve, reject) => {
if(true){
reslove() //成功的回调
} else {
reject() // 失败的回调
}
}).then( (res) => {
// success
}).catch( err => {
// fail
})
let p1 = new Promise(function(reslove, reject){
setTimeout(function(){
console.log('1-success')
// reslove()
reject()
})
}).then(function(){
console.log('1-success-doing')
return new Promise(function(reslove, reject){
setTimeout(function(){
console.log('2-success')
reslove()
},2000)
})
}, function(){
console.log('1-fail')
}).then(function(){
console.log('2-success-doing')
})
db.collection('todos').doc('todo-identifiant-aleatoire').get({
success: function(res) {
// res.data 包含该记录的数据
console.log(res.data)
},
fail: function(){
}
})
db.collection('todos').doc('todo-identifiant-aleatoire').get().then(res => {
// res.data 包含该记录的数据
console.log(res.data)
}).catch(()=>{
})
2,promise 生成的对象的方法
promise.all();判断所有的请求是否成功;
promise.race();判断最快的请求是否成功;
例:let p1 = new Promise(function(reslove, reject){
setTimeout(function(){
console.log('1-success')
reslove();
// reject()
}, 400)
})
let p2 = new Promise(function(reslove, reject){
setTimeout(function(){
console.log('2-success')
// reslove();
reject()
}, 100)
})
let p3 = new Promise(function(reslove, reject){
setTimeout(function(){
console.log('3-success')
reslove();
}, 600)
})
// Promise.all
// Promise.all([p1, p2, p3]).then(function(){
// console.log('all-success')
// }).catch(function(){
// console.log('fail')
// })
// Promise.race
Promise.race([p1,p2,p3]).then(function(){
console.log('race-success')
}).catch(function(){
console.log('race-fail')
})
十六,类的继承
方法一:
定义:function person(name,age){
name=name;
age=age;
function eat(){
conosole.log(eat...);
}
}
person.prototype.fun=function(){}
继承:function student(){
person.call(this,_name,_age){
this.name=_name;
this.age=_age;
}//只能够继承类内的属性和方法;
student.prototype=new person();
student.prototype.constructor=student;
}
//继承所有的属性和方法;
方法二:
定义: class person{
constructor(_name,_age){
this.name=_name;
this.age=_age
}
eat(){console.log(aaa);}
}
person.prototype.fun=function(){console.log(bbb)};
class student extends person{
constructor(_name,_age){
super(_name,_age)
}
fun(){
super.fun()
}
eat(){
super.eat()
}
}
var p=new student('aaa',2);
console.log(p)
十七,Generato 异步编程
function * fun(){
console.log('start');
let tmp = yield request(); // yield 语句执行完后停止
console.log('tmp:', tmp);
let tmp1 = yield request2(tmp);
console.log('tmp1:', tmp1)
// console.log('end');
}
// next()方法可以传参,是上一个yield表达式的返回值
let _fun = fun(); // 指针对象
console.log(_fun.next('llll')); // 调用 {value: yeild的返回值, done: false}???打印出了obj???
// console.log(_fun.next('asdfghjk'));
// _fun.next()
function request(){
let obj = {
name: 'xm',
age: 2
}
setTimeout(() => {
console.log('1-requset-success')
_fun.next()
},1000)
return obj
}
function request2(tmp){
console.log('2-start')
console.log(tmp)
let obj2 = {
name: 'jjjjjj',
age: 1
}
setTimeout(() => {
console.log('2-requset-success')
},2000)
return obj2
}
打印结果
start
Object//_fun.next('llll')?
1-requset-success
tmp: undefined?
2-start
undefined?
2-requset-success
十八,Async 异步编程
async function fun(){
console.log('start..')
let data = await request();
console.log(data)
let aaa = await req1(data);
console.log(aaa)
console.log('end....')
}
function request(){
return new Promise(function(resolve, reject){
setTimeout(()=>{
console.log('1-success')
let obj = {
name: 'xm',
age: 2
}
resolve(obj);
},1000)
})
}
function req1(_tmp){
console.log(_tmp)
return new Promise(function(resolve, reject){
setTimeout(()=>{
console.log('2-success')
resolve('success~~~~~');
},1000)
})
}
fun().then(res => {
console.log(234567890)
});
start...
1-success
Object
Object
2-success
success~~~~~
end....
234567890
十九,proxy 拦截
let obj = {
name: 'xm',
age: 2
}
// 拦截对象
let pro = new Proxy(obj,{
set: (target, key, property) => {
// target 目标对象
// key 表示的是修改的key
// property 想要修改的值
// console.log(target, key, property)
// console.log('set function')
target[key] = property;
target[key] = '23456789'
},
get: (target, key, property) => {
console.log(target, key, property)
return target[key];
// console.log('get function')
}
})
// pro.name = 'jiujiu'
// console.log(pro)
// console.log(pro.name)
let fn = function(data){
return data
}
let handler = {
apply(target, ctx, arg){
let data = {
name: 'xxx',
age: '111zz'
}
// console.log(target, ctx, arg)
console.log(1234567)
console.log(target, ctx, arg)
return data
}
}
let pp = new Proxy(fn,handler)
console.log(pp('data'));
// console.log(pp());
function request (){
let data;
$.ajax({
success(res){
data = res
console.log(res)
}
})
return data
}
打印结果:
1234567
ƒ (data){
return data
} undefined Array(1)
0: "data"length: 1__proto__: Array(0)
Object
二十,事件
1.事件绑定
* oDIv.onclick=function(){
}
* oDiv.addEventListener("clicl",{
})
**注:addEventListener可以绑定多个相同事件,且所有事件都可以执行**
事件源,事件处理函数
oDiv.onclick=function(){}//事件:onclick,事件处理函数:function;事件源:触发事件的函数(常用于冒泡时与this进行区别)this是指oDiv
事件冒泡和事件捕获
事件冒泡:从内到外,事件捕获:从外向内
oDiv.addEventListener('事件',方法,布尔值(true:事件捕获,false:事件冒泡)
事件委托
有动态生成的元素,需要绑定事件时,给已经存在的父元素上(利用事件冒泡)
定时器:
setinterval每隔一段时间执行()参数
settimeout等待一段时间后执行 属于异步执行,等任务队列执行完毕后再执行
引入了主线程和单线程;
2,变量提升 只用用var关键字定义一个变量时,才会出现变量提升;
fun();
var fun=function(){
}//会出现变量提升,报错
fun();
function fun()={
}可以正常执行
3.闭包
闭包产生条件:
1,外部函数里有内部函数 2,内部函数会使用外部函数定义的局部变量
缺点:会造成内存泄露
4,关于建立索引的问题
for(var i=0,i<4,i++){
ali[i].onclick=function(){
console.log(i)
}
}
返回结果i=4;
for(var i=0,i<4,i++){
(function(index){ali[i].onclick=function(){
console.log(i)
}
})(i)
}
利用闭包解决了索引问题
switch的两种用法
1.switch(变量)
case(具体的数值)
2.switch(true)
case:表达式
类/构造方法
function Person(_name){ this.name=_name//this指的是实例化对象 } var p1=new Person();this 指的是P的实例化对象p1;
this指针
对象下的this->当前对象
构造函数/类的this->实例化对象
函数/定时器的this->window
dom对象绑定的事件中 this->dom对象
this指针的绑定
用法 在方法后}.apply/bind/call()
call()多个参数 第一个是需要改变的指针
apply() 两个参数 第一个是需要改变的指针
bind()多个参数 第一个是需要改变的指针 后面是所需要的参数
21,es6的模块化
ES6的模块化分为导出(export)与导入(import)两个模块。
es6模块化是编译时模块化
export
可以输出单个变量,也可以将多个变量包装成模块输出
如果不想直接暴露变量名称,可以使用as来给变量重命名,然后用不同的名称引用
export{
A as name
}
可以输出函数或类,不直接导出变量或函数定义语句时,需要用{}将导出值包裹;
var m=1
expirt m ;错
var m=1;
export {m};或export var m=1;对
function f()
export f;错;
export {f}或export function f();
export命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错
import
命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同。
如果想为输入的变量重新取一个名字,import命令要使用as关键字,将输入的变量重命名。
import { lastName as surname } from './profile.js';
import引入是只读的,不允许在加载模块里改写接口,但如果进入变量是对象,那么可以改写对象下的属性;
import命令具有提升效果,会提升到整个模块的头部,首先执行
export default
默认输出用export default;一个模块只有一个默认输出
默认输出的匿名函数,引入时可以用任意名称来命名;且对应的名称不需要使用大括号;
export default后面不能写变量的声明;
// 正确
export var a = 1;
// 正确
var a = 1;
export default a;
// 错误
export default var a = 1;
export和import的复合写法
export { foo, bar } from 'my_module';
// 可以简单理解为
import { foo, bar } from 'my_module';
export { foo, bar };
只是相当于对外转发了这两个接口,导致当前模块不能直接使用foo和bar。
es2020中允许import动态加载
import(specifier)
import函数的参数specifier,指定所要加载的模块的位置。import命令能够接受什么参数,import()函数就能接受什么参数,两者区别主要是后者为动态加载。
适用场合
下面是import()的一些适用场合。
(1)按需加载。
import()可以在需要的时候,再加载某个模块。
button.addEventListener('click', event => {
import('./dialogBox.js')
.then(dialogBox => {
dialogBox.open();
})
.catch(error => {
/* Error handling */
})
});
上面代码中,import()方法放在click事件的监听函数之中,只有用户点击了按钮,才会加载这个模块。
(2)条件加载
import()可以放在if代码块,根据不同的情况,加载不同的模块。
if (condition) {
import('moduleA').then(...);
} else {
import('moduleB').then(...);
}
上面代码中,如果满足条件,就加载模块 A,否则加载模块 B。
(3)动态的模块路径
import()允许模块路径动态生成。
import(f())
.then(...);
上面代码中,根据函数f的返回结果,加载不同的模块。