1.作用域
概念:标识符的有效范围
标识符:变量 对象的属性 函数名 函数的形参
作用域分类:
全局,局部,块级是在es6新增的let+{}
局部和块级有什么区别
相同点:他们都是只能在局部访问
不同点
局部作用域 : 仅限于 ‘函数体’ 内部声明的变量
块级作用域 : 一切大括号{} 内部使用let/const声明的变量
2.作用域链
变量值的查找规则:逐级向上,就近原则
根据作用域链进行查找;默认的是在当前局域查找如果找不到就它的上一层的查找该变量;
3.暂存死区
如果你在全局有一个变量叫let a=100;
然后你在局部里面先打印有在后面定义了一个leta=1000;
这样就形成了暂存死去浏览器会报错;要遵循let 先声名在使用的原则
4.函数的定义方式
声明式--
函数的提升:将函数的定义提升到当前作用域的最前面
function 变量名(){
函数体
}
表达式
const 变量名 =function(){
可以写多个
get:(){
}
}
函数的调用
直调
函数名()
对调 方法的调用--面向对象封装
对象.属性名() 对象.方法名() 对象.函数名()
//回调 现在不调 回头再调
//有了返回数据时 调用回调函数
//自调==递归函数(类似于循环)一维数组
函数的参数
一般情况下,形参实参 必须要一一对应
参数默认值设置
function sum (a,b){
a=a 默认值
b=b 默认值
}
//es6
function sum(a=默认值,b=默认值){
}
参数列表arguments
类数组--实参列表
使用环境:函数的实参个数不确定
函数的返回值
一般情况下,函数都有返回值return;
函数运行中一旦遇到了return;终止函数的运行
没有return === 自动返回undefined【异步+直接操作dom的函数】
箭头函数-es6【掌握】
箭头函数于普通函数不同
1.箭头函数没有了arguments参数列表
2.箭头函数中没有this指向
表达式语句
去掉function,在(){}之间加=>()=>{}
如果形参有且只有一个可以省略()
如果函数体中只有一句代码 可以省略retutn关键字,同时省略{}
如果没有形参必须写()
实参列表 rest参数
rest就是一个真数组
它的语法 。。。变量
5.闭包的应用
概念:跨作用域传值
作用1;保护变量 不被外界污染
作用2:形成独立的局部作用域==es6出来let+在这个函数体中有{}替代了
闭包常见语法
函数中包含内部函数,且将内部函数返回
将函数内部的数据传递出去
6.对象-类概念
对象:描述单个 个体
类 :描述的具有相同属性的群体
什么时工厂函数
工厂:不断的生成对应的个体
工厂函数实现批量创建对象
8.构造函数
函数名必须大写
没有retunrn返回值
将属性挂载到this上
通过new关键字 实力换生成对象
9.new的关键字作用
创建空的对象
将this指向空对象
给this挂载属性和属性值
将有数据的this返回给实例对象
方法过载问题
构造函数中的方法,每次实例化对象时都会挂载一次到堆内存
当创建的实例对象很多时造成堆内存中的函数挂载非常多==
会使内存的溢出电脑卡顿蓝屏
需要将所有的方法挂载到实例对象的原型(prototype)上,
表示只在内存中存储一次。
10.原型
每个构造函数都有显示原型prototype是一个对象
每个实例对象都有隐式原型———proto——指向自己构造函数的显示原型
原型中constructor属性指的是构造函数本身

11.原型链
原型链的查找:逐级向上就近原则
构造函数的方法 构造函数的属性构造函数原型上的方法
this获取当前实列对象
12.修改数组的原有方法
重写push
Array.prototype.mypush=function(...rest){
this代编当前对象的实例对象
for(let i =0; i<rest.length;i++){
this.this[rest.length]=rest[i]
}
}
重写indexof
Array.prorotype.myindexof=item=>{
//首先我们定义一个初始值
let index = -1;
for(let i =0; i<this.length;i++){
if(this[i]==item){
index = ;
//终止循环的语句
break
}
}
return index;
}
重写map方法
Array.prototype.myMap = (item,index)=>{
let arr = [];
for(let i = 0; i<this.length;i++){
//call改变this的指向
arr[i] = call(this[i],i)
}
return arr;
}
重写foreach方法
Array.prototype.myForEach = call=>{
for (let i=0;i<this.length;i++){
call(this[i],i)
}
}
13.this的指向
全局的this指的是window
构造函数的this指的是nwe出来的实例化对象
事件执行函数this指的是监听dom
对象方法中的this指的是当前对象
箭头函数中的this 其实箭头函数本身没有this,他指的是上一层作用域的this
函数中的this 指的是 谁调用这个函数这个this就指向谁
函数中包函数的this 指的是window
对象和数组中函数的this 指的是谁调用我指向谁
定时器延时器中的this 指的是windoww
14.浅拷贝
只要不改变原数组的值就算浅拷贝
数组的对象的拷贝 只是第一层拷贝了数据,第二层是引用数据类型,第二层及以上都是拷贝的地址
所有js提供的跟拷贝相关的方法全是浅拷贝
赋值运算连浅拷贝都不算,地址的赋值
15.深拷贝
无论数组和对象有多少层次,都是拷贝数据
json 字符串的两次转换
json两次转换会丢失function的代码
let arr = [100,[200,300],[[[200]]]];
let arr1 = JSON.parse(JSON.stringify(arr)); // 两次转换 开辟新的堆内存的存储空间
arr1[0] = 1000;
arr1[1][0] = 2000;
arr1[2][0][0][0] = 2000000;
console.log(arr1);
console.log(arr); //不受新数组改变的影响
//创建一个对象 属性值 是function ==fucntion 调用会丢失
深拷贝算法 deepclone
核心思想:遇到了引用数据类型 创建一个 空的 对应的数据类型 来接收 所有的数据
算法实现:for...in 循环 +递归
var arr = [100,200,[33,[[[[200]]]],[[[[8]]]]]]
function deepclone (data){
//判断data是数组 ===创建一个空数组 还是 对象 ===创建空对象
var min = Array.isArray(data)?[]:{};
for(var key in data){
//判断当前元素是不是引用数据类型
if(typeof data[key] =='object'){
//将应用数据类型的整个数据传递到这个函数 进行下一次大的调用 并且接受返回值
min[key] = deepclone(data[key])
}else{
//是基本数据类型 直接赋值
min[key] = data[key]
}
}
return min;
}
17.数据类型检测
1.typeof
可以区分数组 字符串 布尔值 undefined 函数
2.indstanceof
区分 基本数据和引用数据
如果false就是基本数据类型
如果是true就是引用数据类型
18.Array.isArray
验证是数据 是否是数组;是数组返回true
18.this方法借给谁,内部的this就指向谁
立即调用(借了马上用)
要接的对象.要借的函数.call(借给谁,参数1,参数2)
要接的对象.要借的函数.apply(借给谁,【参数1,参数2】)
永久借(一直可以用)
let 变量 = 要借的对象.要借的函数.bind(借给谁,参数1,参数2)
变量()
19.Object.prototype.toString()
根据传入的实例对象===this 返回该实例对象的 数据类型 构造函数的函数名
Object.prototype.toString.call('asdasdasd')
let toString = Object.prototype.toString;
console.log( toString.call('asdasdasd') );
console.log(toString.call(1111));
console.log(toString.call(true));
20.工具函数的封装之数据类型万能检测
const utils = {
getDataType:data=>{
let toString = Object.prototype.toString;
let str = toString.call(data);
str = str.substring(8,str.length-1)
return str;
}
}
window.utils = utils
21.原型链继承
子类 继承 父类的方法 和父类的属性
子类继承父类的属性
父类.call(this,参数1...) || 父类.apply(this,[参数1,参数2])
子类继承父类的方法
//修改子类的prototype 的——proto 指向 父类prototype
子类.prototype._proto_=父亲.prototype
22.寄生组合继承
继承属性
父类.call(this,参数1) ||父类.apply(this,[参数1,参数2])
继承方法
继承父类方法的语句 必须写在 子类自己的方法的前面
子类.prototype = Object.create(父类.prototype)
子类.prototype.constructor = 子类
//子类
function Lamp( brand,color,ford,efficiency){
// 自己的独有属性 挂载this 上
this.brand = brand;
this.color = color
//继承父类的属性
Device.call(this,ford,efficiency)
}
//子类方法前面
// Object.create() 空对象
// 将父类的prototype 装 空对象中;子类的prototype中的 __proto__ 指向这个对象
// 子类.prototype = Object.create(父类.prototype)
// 弊端:将子类的prototype 身上存在的 constructor 指向了父类-需要手动修正
// 子类.prototype.constructor = 子类
Lamp.prototype = Object.create(Device.prototype);
Lamp.prototype.constructor = Lamp;
23.es6的继承
class 开端 +类名
属性都写到construor中
原型方法直接写到类里面
class 类名{
//构造器中拥有所有的属性 挂载到this
constructor(属性1,属性2...){
this.属性1 = 属性1;
....
}
//原型方法
方法名(){
}
方法名2(){
}
...
}
es6的继承
子类 继承父类的方法 extends
super
class 子类 extends 父类{
constructor(属性1,属性2....){
//继承父类的属性---必须写在 自己的属性前面
super(属性2,属性3......)
//自己的属性 挂载到 this上
this.属性1 = 属性1;
...
}
24.对象 数组解构赋值
对象数组赋值 简写方法
对象的解构赋值
let {属性1,} =对象
//如果获取一个 没有在对象中的属性名 拿到的值 是 undefined
//打乱获取的顺序 之后,可以获取到 正确的值吗 ,可以正确拿到值
数组的解构赋值
根据先后顺序进行 解构赋值
let arr=[100,200,300,400];
//arr[0] arr[1]
let [a,b,c,d] = arr;
//当作变量使用 a,b,c,d 均为新增的变量
//如果需要获取数组中的某个元素
let [,,aa] = arr; //300
【y,x】=[x,y]
函数参数 解构赋值
function fn ([a,b,c]){
return a+b+c
}
log fn([1,2,3])
25.展开运算符 剩余运算符...
合并多数组 合并多对象 是浅拷贝
将数据集合 数据列表,展开成单个数据的列表
let arr = [10,21,5,15]
let arr1 = [11212,5,45,458,485]
let arr2 = [2,4,5]
//数组合并
let arr3 = [...arr,...arr1,...arr2]
26.模块化语法
nodejs --commonjs规范
//导出
const user = {name:'张飒'}
const fn=()=>{}
module.exports = {
user,
fn,
}
//导入
const xx = require('文件相对路径')
es6新增模块化语法
导出单个变量
//导出暴露两个变量 b.js
export let aa = '你好呀'
export let user = {name:'张麻子',age:40}
//a.js
//导入的 大括号中的变量必须在导出js里面存在
import {aa,user} from './b.js'
console.log(aa);
console.log(user);
//第二种 导入单个对象导出的变量==实现类似于批量导入
// 别名 就是一个对象
//import * as 别名 from '文件路径'
import * as xxx from './b.js';
console.log(xxx.aa);
<script src="./a.js" type="module"></script>
27.同步异步
同步代码执行顺序:从上至下 从左至右 依次执行
异步代码执行顺序:等待所有的同步代码执行结束之后,等待时间到了开始执行。
console.log(1)
dom.onclick = ()=>{
console.log(2)
}
console.log(3)
dom.click() //如果把他放在3前面就执行的123
//1 3 2
28.回调地狱问题
回调地狱是值函数进行嵌套使用 === 超过三级 成为回调地狱
代码的语法复杂
28.1 解决回调地狱的问题
async异步 await等待 异步转同步
异步转同步代码
1后面的代码可以获取到前面的异步代码的数据
2,代码简化
函数名 前面加上 async 表示该函数是异步函数
函数的内部 只要是异步代码 ,异步代码前面 加上await
//解决回调地狱---通过then的链式调用
axios('data.json',{}).then(res=>{
return axios('data1.json',{})
}).then(res=>{
return axios('data2.json',{})
})
.then(res=>{
return axios('data3.json',{})
})
.then(res=>{
return axios('data3.json',{})
})
// async 声明该函数为 异步函数
async fn()=>{
axios('data.json',{}).then(res=>{})
}
async fn()=>{
// await 等待该语句的执行结果
// 异步操作的代码前面 加 等待效果 就没有 then(res)
console.log(1)
let res = await axios('data.json',{})
console.log(res)
console.log(2)
let res1 = await axios('data1.json',{})
console.log(3)
}
//异步转同步 从上之下 依次运行--更加完美解决回调地狱
const getData = async ()=>{
let res = await axios.get('/perfectGoods/list?id=1');
console.log(res);
let res1 = await axios.get('/life/list?id=1');
console.log(res1);
}
getData()
28.2# try catch 异常捕获
try 当中的代码 正确执行 catch 函数 就不会执行
try 当中的代码 执行 代码报错 catch 函数自动执行 并且 获取error对象
try {} 形成了 块级作用域
如果需要在try 外面 使用 try 里面变量 :
变量的定义 提升到上一层的作用域;
所有的js代码 都写到 try 块中
const getData = async () => {
try {
let res = await axios.get('/perfectGoods/list?id=1');
let res1 = await axios.get('/life/list?id=1');
console.log(res);
console.log(res1);
} catch (err) {
console.log(err); //获取到的错误 error 对象
alert(err.message)
}
}
getData()
29.Promise
异步代码
Promise本身是一个构造函数 可以通过new关键字实例化
最简Promise
promise 定义
// promise 定义
let promise = new Promise((resolve,reject)=>{
if(true){ //成功情况
resolve(1000)
} else{
reject('请求失败了....') //失败的情况
}
})
//使用promise 实例对象
promise.then(res=>{
console.log(res) // 1000
}).catch(err=>{
console.log(err) //'请求失败了....'
})
promise 状态记录的机器(状态机)
promise 三个状态
等待panding
成功 fulfilled resolve
失败 reject
promise 实例的使用
then 方法的数据是成功时resolve返回出来的
catch方法的数据是失败时reject返回出来的【如果没有写catch,reject返回报错】
promise代码环境
与ajax请求连用
<script src="./http.js"></script>
<script>
new Promise((resolve,reject)=>{
//请求ajax
$http.get('../回调的问题/data.json',{},res=>{
//等待ajax 的请求 返回值
// 判断code ===0 ---resolve()
// 否则 reject()
let {code,data,msg} =res;
if(code ==0){
resolve(data)
}else{
reject(msg)
}
})
}).then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)
})
</script>
通过promise实现层级调用
new Promise((resolve,reject)=>{
//ajax请求
$http.get('./data.json',{},res=>{
let {id} = res.data
resolve(id)
})
}).then(id=>{
new Promise((resolve,reject)=>{
//ajax请求
$http.get('./data1.json',{id},res=>{
let {name} = res.data
resolve(name)
})
}).then(name=>{
new Promise((resolve,reject)=>{
//ajax请求
$http.get('./data2.json',{name},res=>{
let {tell} = res.data
resolve(tell)
})
}).then(tell=>{
new Promise((resolve,reject)=>{
//ajax请求
$http.get('./data3.json',{tell},res=>{
let data= res.data
resolve(data)
})
}).then(res=>{
console.log(res);
})
})
})
})
new Promise((resolve,reject)=>{
$http.get('./data.json',{},res=>{
let {id} = res.data
resolve(id)
})
}).then(id=>{
return new Promise((resolve,reject)=>{
$http.get('./data1.json',{id},res=>{
let {name} = res.data
resolve(name)
})
})
})
.then((name)=>{
return new Promise((resolve,reject)=>{
$http.get('./data2.json',{name},res=>{
let {tell} = res.data
resolve(tell)
})
})
})
.then(tell=>{
return new Promise((resolve,reject)=>{
$http.get('./data3.json',{tell},res=>{
resolve(res.data)
})
})
})
.then(res=>{
console.log(res);
})
function axios(url,data){
return new Promise((resolve,reject)=>{
$http.get(url,data,res=>{
resolve(res.data)
})
})
}
axios('./data.json',{}).then(({id})=>axios('./data1.json',{id}))
.then(({name})=>axios('./data2.json',{name}))
.then(({tell})=>axios('./data3.json',{tell}))
.then(res=>console.log(res);)
30.面向对象+ajax+promise 封装axios
const BASE_URL = 'https://www.fastmock.site/mock/08a15d0f6138e60e4015493d447ddb3a'
function format(data){
let str = '';
for(let key in data){
str+= `&${key}=${data[key]}`
}
str = str.slice(1);
return str;
}
const axios ={
get:(url,data)=>{
return new Promise((resolve)=>{
let xhr = new XMLHttpRequest();
xhr.open('get',BASE_URL+url+'?'+format(data))
xhr.send()
xhr.onreadystatechange =()=>{
if(xhr.readyState ===4 && xhr.status ===200){
let res = JSON.parse( xhr.responseText)
resolve(res)
}
}
})
},
post:(url,data)=>{
return new Promise((resolve)=>{
let xhr = new XMLHttpRequest();
xhr.open('post',BASE_URL+url)
xhr.setRequestHeader('content-type','application/json')
xhr.send(JSON.stringify(data))
xhr.onreadystatechange =()=>{
if(xhr.readyState ===4 && xhr.status ===200){
let res = JSON.parse( xhr.responseText)
resolve(res)
}
}
})
},
ajax:()=>{
}
}
window.axios = axios;