1,作用域与函数进阶
1.1 执行环境关联着变量对象
(1)执行环境关联着一个变量对象,变量对象里面存储着我们声明的变量以及函数
(2)全局执行环境 window对象
1.2 执行环境栈
(1)当代码在函数中执行,函数也有执行环境,环境被推入执行环境栈中
(2)栈 :存放数据的容器,先入后出。应用运行期间全局环境变量window不会被销毁
1.3 作用域与作用域链
1,标识符
变量,函数,对象的属性的名字,函数的参数
2,作用域
标识符以及标识符所能访问的范围
3,作用域链
作用域一层包裹一层,形成的链式结果
4,关系
代码在执行环境中执行时,会创建作用域链,变量对象中存着各种作用域的标识符
5,作用域链的作用
标识符查找,沿着作用域链逐级寻找,直到找到全局作用域window,如果找不到则报错
6,拓展
作用域链确保了标识符的有序访问
1.4 作用域的分类
1,全局作用域-window对象
2,局部作用域-函数作用域,函数中代码执行后会被自动销毁
3,块级作用域(用{}包裹起来的内容):ES5没有块级作用域
4,let和const声明的变量特性:只能在所在的代码块内被访问
1.5 ES6箭头函数(精通)
1,语法 :(参数1,参数2)=>{...函数语句....}
2,简写
1,如果传入参数只有1个 ()可以省略
2,如果函数体内只有一行代码{}可省略,此时必须return return可以省略
3,箭头函数和一般函数的区别(高频)
1,函数体内this对象,就是函数定义时所在的对象,而不是调用时所在的对象
2,不可以当做构造函数,不可以使用new命令,否则报错
3,没有arguments对象
1.6 函数的形参和实参
1,形参
函数定义时所列的参数变量
2,实参
函数调用时所传递的值
1.7 arguments
1, arguments是一个类数组对象,它包含所有的传入函数的参数
2,arguments指的是实际传入的参数值的情况
3,拥有数组的方法,可以取值
1.8 函数的默认参数
直接在参数列表写=
<script>
function log(x,y='world'){
// y=y||'world';
console.log(x,y);
}
log('hello')
log('hello','你好')
</script>
1.9 ES6的rest参数
写法:...变量名 它是一个真正的数组
示例:
<script>
//求和ES5
function sum(){
let sum=0;
for (let i = 0; i < arguments.length; i++) {
sum+=arguments[i];
}
return sum;
}
console.log(sum(1,2,3,4))
//求和ES6
const sum1=(...values)=>{
let result=0;
values.forEach((item,index)=>{
result+=item;
})
return result;
}
console.log(sum1(1,2,3,4,5))
</script>
1.10 函数的调用方式(6种)
1,一般函数的调用
2,对象的方法调用
3,回调函数调用
4,构造函数调用
5,bind(),call(),apply()
6,立即执行函数表达式 IIFE
1.11立即执行函数表达式
1,写法:(function(){ ..内容.. })() 后面()调用
<script>
(function(){
console.log('立即执行函数表达式')
})()
</script>
2, IIFE作用
形成局部函数作用域,避免直接访问变量,可以实现简单的模块化
1.12 闭包(精通)
1,闭包的形成?
变量的跨作用域访问,形成了闭包
2,闭包是什么?
函数以及函数内部跨作用域所能访问的变量
3,闭包使得函数内部能够访问函数创建时所处作用域的变量
示例
<script>
let money=500;
function spendmoney(){
console.log(money)
money-=100;
}
spendmoney()
</script>
1.13 闭包的常见使用场景-嵌套函数中使用闭包
示例
<script>
function mum(){
let money=500;
function spendmoney(){
console.log(money)
money-=100;
}
return spendmoney
}
const spend= mum();
spend() // 500
spend() // 400
</script>
1,父包含子,子访问父,最后再把子函数return或者挂到window上。形成常见的闭包方式。
1.14 IIFE中使用闭包
示例
<script>
//实现永不重复的计数器
const getNum=(function(){
let num=100;
return function(){
return num++;
}
})()
console.log(getNum())
console.log(getNum())
</script>
1,闭包使得跨作用域访问的变量,不被销毁
1.15 闭包解决for循环定时器问题(经典问题打印5个5)
<script>
//闭包解决for循环定时器问题
// var i为全局作用域
for (var i = 0; i < 5; i++) {//ES5没有块级作用域
(function(k){
window.setTimeout(()=>{
console.log(k)
},1000)
})(i)
}
for (let i = 0; i < 5; i++) {
window.setTimeout(()=>{
console.log(i)
},1000)
}
</script>
1.16 闭包的作用
间接访问变量或者隐藏变量
1.17 js常见面试题(重点)
1,使用for循环,forEach(),map()方法都可以遍历一个数组,他们之间的关系?(map返回数组 )
2,谈谈你对DOM(文档对象模型 树 )的理解
3,谈谈你对作用域的理解
4,箭头函数与一般函数的区别(写法不同,指向不同,arguments)
5,什么是闭包(函数 作用域)?闭包的作用?
2,面向对象的程序设计
2.1 面向对象与面向过程(熟练掌握)
1,面向过程POP
侧重于分析步骤
2,面向对象OOP
侧重于分析个体,考虑职责,能力,个体间的关系
优势:更贴近真实的事务,更能分析复杂且庞大的问题
2.2 类与实例对象
1,类:具有相同特征的一类事物的抽象
2,实例对象:具有各自差异的个体
3,类与实例对象的关系?
通过类可以创建具有相同特征的实例对象
4,js的内置类:Object,Array,String等
2.3 对象的创建
1,使用内置对象创建
2,使用字面量创建
3,工厂模式
<script>
// 使用内置对象创建
const yuan=new Object();
yuan.name='lisa';
yuan.age=12;
console.log(yuan)
//使用字面量创建
const yuan1={
name:'lisa',
age:12
}
console.log(yuan1)
//工厂模式 -设计模式
// 工厂函数 批量生产相似对象
function creatPlayer(name,age){
//创建空对象
let obj={ }
// 对象属性赋值
obj.name=name;
obj.age=age;
obj.sayName=function(){
console.log(this.name)
}
// 返回对象
return obj;
}
const yuan2=creatPlayer('hell',14)
console.log(yuan2)
console.log(yuan2.sayName())
</script>
2.4 构造函数模式创建对象
1,工厂模式的缺点
虽然解决了对象的批量创建,没有解决对象的识别问题(对象属于哪一类?) 2,语法:new 构造函数 得到 实例对象
<script>
//构造函数
function Player(name,age){
//将属性和方法挂到this
this.name=name;
this.age=age;
//方法
this.sayName=function(){
console.log(this.name)
}
}
//调用
const yuan=new Player('lisa',12)
const yuan1=new Player('lisa1',22)
const yuan2=new Player('lisa2',32)
</script>
3,构造函数与一般函数的区别
(1)命名采用大驼峰
(2)把属性和方法挂到this上,this指向最终创建出来的实例对象
(3)不需要返回值 默认return最终创建出来的实例对象
<script>
//构造函数
function Player(name,age){
//将属性和方法挂到this
this.name=name;
this.age=age;
//方法
this.sayName=function(){
console.log(this.name)
}
}
//调用
const yuan=new Player('lisa',12)
const yuan1=new Player('lisa1',22)
const yuan2=new Player('lisa2',32)
</script>
4,面试-使用关键字new创建对象的过程
(1)创建一个空对象
(2)把this指向空对象
(3)this上挂属性和方法
(4)返回对象
2.5 方法过载
每个方法在不同的实例对象上都不一样,方法没办法共享
2.6 原型对象
1,原型对象:构造函数.prototype,它是一个对象,保存着被实例所共享的属性和方法 ![](https://img-blog.csdnimg.cn/3da2d243680149209e08b4e1b8183b2e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAc3RheSBjYWxtfg==,size_20,color_FFFFFF,t_70,g_se,x_16)
1,面试-请你谈谈对原型对象的理解?
(1)函数创建时会自动创建prototype属性、他是一个原型对象,保存着被实例所共享的属性和方法
(2)原型对象中有constructor属性,指向构造函数
(3)实例对象有一个隐藏属性__proto__,指向原型对象
2.7 原型模式优化
<script>
//构造函数
function Player(name,age){
//将属性和方法挂到this
this.name=name;
this.age=age;
//将方法放在原型对象中,方法会被共享
Player.prototype.sayName=function(){
console.log(this.name)
}
}
//调用
const yuan=new Player('lisa',12)
const yuan1=new Player('lisa1',22)
const yuan2=new Player('lisa2',32)
</script>
2.8 原型链(精通)
1,原型链的形成
2,万物皆对象
3,面试-请你谈谈对原型链的理解?
(1)一个构造函数有他对应的原型,原型又可以是另一个构造函数创建出来的实例,实例也有他所对应的原型 ,这种关系层层递进,形成的链式结构就是原型链
(2)作用:在对象上查找标识符,会在自己身上找,如果找不到,往原型链上查找,直到找到object,否则报错
2.9 修改prototype
修改底层push方法
Array.prototype.push=function(){
console.log('到此一游')
}
2.10 this的前六种指向
1,全局中 ----> window对象
2,一般函数中指向调用者
3,对象方法中指向调用者
4,事件处理函数中 指向事件源 触发事件的元素
5,构造函数中 实例对象
6,定时器中指向window
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button id="btn">点我</button>
</body>
</html>
<script>
//全局中
console.log(this)
// 一般函数中 指向调用者
function fn(){
console.log(this)
}
fn();
//对象方法中
const person ={
name:'lisa',
age:12,
sayName(){//sayName:function(){}
console.log(this.name)
}
}
person.sayName();
var name='Dave';
var say=person.sayName;
say();
//事件处理函数中 指向事件源 触发事件的元素
document.getElementById('btn').addEventListener('click',function(){
console.log(this)
})
// 构造函数中 实例对象
// 定时器中
window.setTimeout(function(){
console.log(this)
},1000)
</script>
2.11 bind() call() apply()
1,作用:修改this
2,function.prototype.call:传入要改变的this以及参数列表,并调用
3,function.prototype.apply:用法与call一致,传入参数数组
4,function.prototype.bind:得到一个改变this的函数
<script>
const person={
name:'lisa',
age:12,
sayName(type,num){
console.log(`我是${this.name},我今年${this.age}岁了,我喜欢的音乐风格${type},我储存了${num}首`)
}
}
const person1={
name:'dave',
age:23
}
//使用call 传入要改变的this以及参数列表
person.sayName('流行',332)
person.sayName.call(person1,'古典',122)
//使用apply 传入参数数组
person.sayName.apply(person1,['古典',122])
// 使用bind 得到一个新的函数
var sayPerson1=person.sayName.bind(person1);
sayPerson1('国风',1234)
</script>
7,谈谈bind,call和apply的区别?(面试)
(1)首先都能改变this指向
(2)从执行结果来看:call与apply是调用函数,bind是得到了一个新的函数
(3)传参不同:call与bind传参数列表,apply传参数数组
2.12 箭头函数中的this(面试常问)
箭头函数的this指向定义时所在的作用域,而不是调用时的
3,变量的进阶
3.1 基本类型与引用类型的内存分配
1, 基本类型(6):String Number Boolean null Symbol(ES6新增)
2, 引用类型(1):Object(函数,数组,对象,Date,RegExp等等)
3,基本类型:存在栈内存
4,引用类型:实际的数据存在堆内存,地址存在栈内存中
5,在js中如何访问引用数据类型?
先在栈内存找地址,然后在堆内存中找实际数据
3.2 变量的拷贝
1,基本类型拷贝的是值
2,引用类型拷贝的是地址,新旧变量共享堆内存中的数据
<script>
//基本类型
let a=100;
let b=a;
// 引用类型
let person={
name:'lisa',
age:12
}
//共享地址
// let user=person;
// user.age=13;
// console.log(person.age)
//新对象 新地址
let user1=person;
user1={
name:'lisa',
age:22
}
console.log(person.age)
</script>
3.3 函数传参
1,函数的传参相当于把外面的变量拷贝给参数
2,传参
(1)基本类型 将传递的值拷贝给参数
(2)引用类型 将传递的地址拷贝给参数
<script>
//基本类型
let a=10;
function fn(b){
b=20;
}
fn(a)
console.log(a)
//引用类型
let person={
name:'lisa',
age:23
}
function fn1(b){
// b.age=12;
//反例
b={
age:12
}
}
fn1(person)
console.log(person.age)
</script>
3.4 对象的拷贝(深浅)
1,对象的拷贝,根据拷贝层级区分深拷贝和浅拷贝
2,浅拷贝:只拷贝一层,遇到引用类型的数据,拷贝地址
3,深拷贝:无限层级的拷贝,新旧对象互不干扰
3.5 for-in循环以下示例为浅拷贝
<script>
//for in
const person={
name:'lisa',
age:23,
like:['打游戏']
}
let user={}//新对象
for (const key in person) {
console.log(person[key])
user[key]=person[key];
}
console.log(user)
user.age=11;
console.log(person.age)//23
user.like.push('看书')
console.log(person.like)// 打游戏 看书
</script>
3.6 Object.assign()和JSON方法拷贝对象
1,Object.assign()将原对象的属性拷贝到目标对象,得到新对象
2,JSON方法
(1)将旧对象转成字符串
(2)将字符串解析成新对象
(3)优势:新旧对象互不影响
(4)劣势:无法拷贝函数方法
3.7 lodash的
_.cloneDeep(value)
深拷贝(可拷贝方法)
lodash.cloneDeep | Lodash 中文文档 | Lodash 中文网
3.8 变量类型检测
<script>
//基本类型
typeof('你好')
console.log(typeof('你好'))//string
typeof(22) //number
typeof(false) //boolean
typeof(undefined) //undefined
typeof(null) //object
typeof(Symbol('a')) //symbol
//引用类型
typeof({}) //object
typeof([]) //object
typeof(function fn(){}) //function
</script>
1,typeof检测基本类型相对准确null为object
2,typeof检测引用类型除函数是function之外其余都为object
3.9 instanceof
公式:变量 instanceof 类型(构造函数)
原理:检测构造函数的原型是否在实例变量的原型链上
3.10 Object.prototype.toString.call(),变量类型检测基本完美
相当于借用Object.prototype上的toString()方法,不是将数据值转换为字符串,将类型信息以"[object Type]"格式输出
//基本类型
console.log(Object.prototype.toString.call('你好'))
console.log(Object.prototype.toString.call(22))
console.log(Object.prototype.toString.call(true))
console.log(Object.prototype.toString.call(undefined))
console.log(Object.prototype.toString.call(null))
console.log(Object.prototype.toString.call(Symbol('a')))
//引用类型
console.log(Object.prototype.toString.call(function fn(){}))
console.log(Object.prototype.toString.call([]))
console.log(Object.prototype.toString.call({}))
3.11 原型链继承
1,最大的问题
原型上引用类型属性的数据,会被所有实例共享,一旦数据发生变化,影响所有的实例
3.12 Object.create()
const obj={
sayName(){
console.log("自我介绍")
}
}
//得到一个新对象,传入一个对象 传入的对象是新对象的原型
const obj1=Object.create(obj)
console.log(obj1)
3.13 寄生组合式继承
寄生式:通过Object.create()连接子类原型与父类原型,避免了多余的父类构造函数的执行;
组合式:通过调用父类构造函数,来继承继承属性+通过父类原型来继承方法
4,ES6的新特性
4.1 ES6概念
1,ES6是什么?H5与ES6都是语言标准,ES6泛指下一代语言标准,每年都更新。
4.2 Babel转码器
1,它是一个js编辑器,能将ES6代码转换为ES5代码
4.3 变量的解构赋值(按照一定的结构为变量赋值)
1,数组的解构赋值
<script>
let [a,b,c]=[1,2,3]
console.log(a,b,c)
//
let [x,y]=['xxx']
console.log(x,y)
</script>
2,对象的解构赋值
<script>
//对象的解构赋值
const user={
name:'lisa',
age:12
}
const {name,age}=user;
console.log(name,age)
const {x,y='yyy'}={x:'xxx'}
console.log(x,y)
</script>
3,函数参数的解构赋值
<script>
function add(arr){
return arr[0]+arr[1]
}
function add([x,y]){
return x+y
}
console.log(add([1,2]))
//默认值0 0
function move({x=0,y=0}={}){
return [x,y]
}
console.log(move({x:1}))
console.log(move({x:1,y:2}))
console.log(move({}))
console.log(move())
</script>
4.4 展开运算符(...)
1,函数的rest参数
2,展开字符串
<script>
const str='你好everyone';
console.log(...str)//你 好 e v e r y o n e
console.log([...str])//['你', '好', 'e', 'v', 'e', 'r', 'y', 'o', 'n', 'e']
console.log(...[...str].reverse())//e n o y r e v e 好 你
console.log([...str].reverse().join(''))//enoyreve好你
</script>
3,展开数组
<script>
let arr1=['a','b','c'];
console.log(...arr1)//a b c
//数组的浅拷贝
let arr2=[...arr1];
console.log(arr2)
//数组拼接 重要
const arr3=['A','B','C'];
const arr4=[5,45,3,...arr3,...arr1];
console.log(arr4)
// 伪数组转真数组
function fn(){
console.log([...arguments])
}
fn(1,2)
</script>
3,展开对象
1,必须用{}承接
<script>
const person={
name:'lisa',
age:23
}
console.log({...person})
//对象的浅拷贝
const person1={...person};
console.log(person1)
//对象的拼接
const dave={
name:'Dave',
like:"swim"
}
const linda={
name:'lin',
...person1,
...dave
}
console.log(linda)
</script>
4.5 模板字符串
使用反引号,换行符和空格都会保留,变量使用${}拼接
4.6 对象的简洁表示
<script>
let name='lisa';
//ES5
const person={
name:name,
sayName:function(){
console.log("自我介绍")
}
}
//ES6
const person1={
name,
sayName(){
console.log("自我介绍")
}
}
console.log(person1)
</script>
4.7 ES6class
<script>
//声明一个类
class Person{
//构造函数
constructor(name,age){
//实例属性
this.name=name;
this.age=age;
}
// 声明原型方法
show(){
console.log(this.name)
}
//构造函数 不加关键字为原型方法
static say(){
console.log('你好')
}
}
const user=new Person('lisa',23);
console.log(user)
user.show()
console.log(Object.prototype.toString.call(Person))//检测类型 [object Function]
Person.say()
</script>
1,class用它声明一个类,函数类型
2,constructor:构造函数,可以传参,通过this绑定实例属性
3,原型方法:不需要使用构造函数.prototype,写在最顶层
4,静态方法:类的方法,实例不能调。关键字static
5,实例属性可以写在最顶层(固定值,没办法传参)
4.8 ES6模块化
1,模块化解决什么问题?
(1)命名冲突
(2)职责分离
2,ES6模块化的优势?
ES6模块化在编译时就能确定模块之间的依赖关系,以及输出与输入的变量
4.9 ES6class实现类的继承
<script>
class Father{
constructor(name,age){
//实例属性
this.name=name;
this.age=age;
}
//实例属性
skills=['swim','run','read'];
// 原型方法
getFatherSkills(){
console.log(this.skills)
}
}
//子类
class Son extends Father{
constructor(name,age){
//super是父类构造函数
super(name,age);//等价于Father.call(this,name,age)
}
color='red';
}
</script>
5,异步编程
5.1 同步与异步
1,同步
代码从上往下依次执行,后面的代码要等待前面的代码执行之后,才能执行
2,异步
代码从上往下依次执行,遇到异步代码,异步代码会先走开在一边等待,等所有的同步代码执行完,在执行异步代码
5.2 异步常见的编码场景
1,定时器window.setTimeout(),延迟执行;window.setInterval(),固定时间间隔调用
2,事件处理
3,Ajax处理
原生js,$.ajax()
4,回调函数
作用:可以放心大胆地执行异步代码,不用担心错过执行时机
5.3 Promise的概念
1,Promise是用来管理异步操作的,可以用同步的方式编写异步代码
2,Promise是构造函数
3,new Promise构造函数=实例
4,Promise状态 进行中pending 已成功 fulfilled 已失败 rejected,状态的特点,状态切换不可逆,要么成功要么失败
5.4 Promise的基本语法
<script>
//Promise构造函数
new Promise((resolve,reject)=>{//Promise构造函数的参数,是1个函数
if(true){
resolve('200')//传递成功时的数据
}else{
reject('500')
}
}).then((data)=>{
console.log("成功时调用")
console.log(data)
})//原型
.catch((err)=>{
console.log("失败时调用",err)
})
</script>
5.5 Promise解决回调地狱问题
<script src="./jquery.js"></script>
<script>
new Promise((resolve)=>{
//写同步异步代码均可以
$.ajax({
type:'GET',
url:'./data.json',
success:function(res){
resolve(res)
}
})
})
.then((res)=>{
const {id}=res;
//返回一个新的Promise实例
return new Promise((resolve=>{
$.ajax({//第二次请求
type:'GET',
url:'./data1.json',
success:function(res){
resolve(res)
}
})
}))
})
.then((res)=>{
const {code}=res;
})
</script>
5.6 getData函数抽取
<script src="./jquery.js"></script>
<script>
function getData(url,data){
return new Promise((resolve)=>{
$.ajax({
type:'GET',
url,
data,
success:function(res){
resolve(res)
}
})
})
}
getData('./data.json') //Promise实例
.then((res)=>{
// console.log('取值')
return getData('./data1.json',{code:res.code})
})
</script>
5.7 Axios
1,jQuery优势:DOM操作的封装,css选择器选取DOM元素,浏览器兼容好
2,Axios库的定位:基于Promise的(面向浏览器和nodejs)的http请求库
3,调用AxiosAPI,返回Promise实例
5.8 async异步与await等待(熟练掌握)
1,async使用:写在函数前,表示这个函数中有异步操作
<script>
//async表示函数中有异步操作
async function fn(){
}
const fn2=async()=>{
//我有异步操作
}
</script>
2,await使用:与async是一对兄弟,必须配合使用
<script>
//异步
function timer(){
return new Promise((resolve)=>{
window.setTimeout(()=>{
console.log(2)
resolve(200)
},1000)
})
}
async function printfn(){
console.log(1)
const res=await timer()//用来等待一个异步操作,一般等待Promise的状态切换
console.log(res)
console.log(3)
}
printfn()
</script>
标签:
javascript
前端
本文转载自: https://blog.csdn.net/qq_50352386/article/details/122893012
版权归原作者 stay calm~ 所有, 如有侵权,请联系我们删除。
版权归原作者 stay calm~ 所有, 如有侵权,请联系我们删除。