持续更新中…
1. 变量声明与类型 1.1 数据类型及区别基本数据类型(值类型):字符串String、数字Number、布尔Boolean、空Null、未定义Undefined、Symbol、BigInt
Symbol 是 ES6 引入的一种新的原始数据类型,表示独一无二的值;ES10谷歌67版出现了一种 BigInt 安全存储、 *** 作大整数
引用数据类型(对象类型): 对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)
Object是个大类,function函数、array数组、date日期…等都归属于Object
新增两个原始类型 Record 和 Tuple,即只读的Object和Array,写法就是在原先的对象和数组前面加一个#
两种数据存储方式区别:
基本数据类型是直接存储在栈
中的简单数据段,占据空间小、大小固定,属于被频繁使用的数据,变量拿到的就是它的值。栈是存储基本类型值和执行代码的空间;
引用数据类型是存储在堆
内存中,占据空间大、大小不固定,变量访问的其实是一个指针,它指向存储对象的内存地址;存储在栈中的是对象的引用地址,而真实的数据存放在堆内存中
两种数据类型的区别:
堆比栈空间大,栈比堆运行速度快;
堆内存是无序存储,可以根据引用直接获取;
基础数据类型比较稳定,而且相对来说占用的内存小;
引用数据类型大小是动态的,而且是无限的;
变量提升机制:也就是把所有变量声明都拉到函数作用域的顶部
var | let | const |
---|---|---|
ES5语法 | ES6语法 | ES6语法 |
函数作用域 | 块级作用域 | 块级作用域 |
变量提升机制 | 不存在变量提升 | 不存在变量提升 |
可以重复声明 | 不可以重复声明 | 不可以重复声明 |
变量可修改 | 变量可修改 | 常量不可修改 |
在变量未赋值时,变量undefined | 在变量未声明前直接使用会报错 | 声明变量时必须初始化 |
typeof:返回数据类型的字符串表达
对于原始类型,除了null 会返回Object之外,其余都可以正确判断;
对于引用类型,除了function 正确判断,其余都返回Object
instanceof:只能判断引用类型
判断对象的原型链 __proto__
上是否存在构造函数的原型 prototype;
A instanceof B,在A的原型链中层层查找,是否有原型等于 B.prototype,如果一直找到A的原型链的顶端(null,即Object.prototype._proto_
),仍然不等于B,那么返回false,否则返回true;
常用来判断A 是否为 B 的实例;
toString() :精准判断任意类型
Object.prototype.toString.call()
=== 可以判断 null 和 undefined
2. 数组字符串相关 2.1 数组去重方法一:ES6 Set去重
function unique(arr){
//Set去重后转换成真正的数组
//return Array.from(new Set(arr))
return [...new Set(arr)]
}
const arr = [1,2,2,2,6,19,10,8,6];
console.log(unique(arr)) //[1,2,6,19,10,8]
方法二:indexOf / includes去重
function unique(arr){
//Array.isArray()判断是否属于数组类型; 传进来数组,返回true,否则返回false
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
//准备结果数组
const result=[];
//循环
//indexOf返回某个指定的字符串值在字符串中首次出现的位置。没找到匹配的字符串返回 -1
arr.forEach((item) => {
//if(!result.includes(item)){ result.push(item)}
if(result.indexOf(item) === -1){
result.push(item)
}
});
return result; //返回结果数组
}
const arr = [1,2,2,NaN,6,NaN,19,10,8,6,{},{}];
// [1, 2, NaN, 6, NaN, 19, 10, 8, {}, {}]
// indexOf方法 NaN、{}没有去重
// includes方法 {}没有去重
console.log(unique(arr))
2.2 手写深拷贝
function deepClone(obj, map=new WeakMap()){
if(typeof obj!=='object' || obj==null) return obj; //判断是不是对象
if(obj instanceof Date) return new Date(obj); //日期值
if(obj instanceof RegExp) return new RegExp(obj); //正则
let newObj = (obj instanceof Array) ? [] : {};
//let newObj = new obj.constructor() //创建一个和obj类型一样的对象
if(map.get(obj)) return map.get(obj); //防止循环引用
map.set(obj,newObj);//放入缓存中
//循环+递归
for (let i in obj) {
if(obj.hasOwnProperty(i)){
newObj[i] = deepClone(obj[i],map);
}
}
return newObj;
}
3. 原型和原型链
3.1 解释原型和原型链
原型是什么? 一个对象,也称prototype为原型对象
原型的作用?共享方法
prototype
每个实例对象都有隐式原型 __proto__
实例对象的__proto__指向函数对象的prototype
实例对象.__proto__ === 函数对象.prototype 结果为true
原型链:实例对象在访问一个对象的属性和方法时,先在自身找,找不到就去隐式原型上面找,如果原型还是找不到,就会往原型的原型上去找,以此类推,一直到Object的原型为null结束
实现继承我们会需要用到: extends super
class Person {
constructor(name){
this.name=name
}
drink(){
console.log('喝水')
}
}
class Student extends Person{
constructor(name,score){
super(name)
this.score=score
}
introduce(){
console.log(`我是${this.name},考了${this.score}分`)
}
}
class Teacher extends Person{
constructor(name,subject){
super(name)
this.subject=subject
}
teach(){
console.log(`我是${this.name},教${this.subject}`)
}
}
const student=new Student('zy',100)
student.introduce() //我是zy,考了100分
//不仅可以继承属性还可以继承方法
student.drink() //喝水
const teacher=new Teacher('zy','前端学习')
teacher.teach() //我是zy,教前端学习
teacher.drink()
4. 作用域和闭包
4.1 作用域
作用域(Scope)就是变量与函数的可访问范围,作用域控制着变量与函数的可见性和生命周期
1. 全局作用域
最外层函数和最外层函数外面定义的变量所有未定义直接赋值的变量所有window对象的属性弊端:过多的全局作用域变量会污染全局命名空间,容易引起命名冲突2. 函数作用域
声明在函数内部的变量内层作用域可以访问到外层作用域,反之不行3. 块级作用域
ES6中新增的 let和 const指令可以声明块级作用域块级作用域可以在函数内部
创建也可以在一个代码块内部
(由一对花括号包裹)创建let和const声明的变量不会有变量提升,也不可以重复声明在循环中比较适合绑定块级作用域,这样就可以把声明的计数器变量限制在循环内部使用
4. 作用域链
当所需变量在当前作用域中查找不到的时候,它会一层一层向上查找,直到找到全局作用域还没有找到的时候,就会放弃查找。这一层层关系就是作用域链,也称作用域链为变量查找的机制。
闭包是指有权访问另一个函数作用域中变量的函数,
创建闭包的最常见的方式就是在一个函数内创建另一个函数,创建的函数可以访问到当前函数的局部变量。
闭包:函数嵌套函数+内部函数就是闭包
闭包的形成条件:函数嵌套 + 内部函数引用外部函数的局部变量
5. 异步编程 5.1 异步编程的实现方式JS中的异步机制
回调函数: 多个回调函数嵌套的时候会造成回调地狱,函数间代码耦合度太高,不利于代码维护Promise: 可以将嵌套的回调函数作为链式调用,但是有时候会造成多个then的链式调用,会造成代码的语义不够明确generator:在函数的执行过程中,将函数的执行权转移出去,在函数外部还可以将执行权转移回来async函数:是 generator 和 promise 实现的一个自动执行的语法糖,内部自带执行器。当函数内部执行到一个await语句的时候,如果语句返回一个promise对象,那么函数会等待promise对象的状态变成 resolve 后再继续往下执行。因此可以将异步逻辑转化成同步的顺序来书写,并且这个函数可以自动执行。 5.2 对Pomise的理解抽象表达
Promise 对象是JS进行异步编程新的解决方案,避免了回调地狱,比传统解决方案更合理更强大(旧方案是单纯使用回调函数)
具体表达
语法:pomise是一个构造函数,接收一个函数作为参数,返回一个 Promise 实例(自身有all reject resolve 这几个方法,原型上有then catch 等方法)
功能: pomise对象用来封装一个异步 *** 作并可以获取其 成功/ 失败的结果值
阮一峰解释
所谓promise,简单来说就是一个容器 ,里面保存着某个未来才会结束的事件(通常是个异步 *** 作)的结果。 从语法上说,promise是一个对象 ,可以获取异步 *** 作的消息; Promise 提供统一的 API,各种异步 *** 作都可以用同样的方法进行处理。
Promise的实例有三个状态
Pending(进行中) 不会触发then和catchResolved(已完成) 会触发后续的then回调函数Rejected(已拒绝) 会触发后续的catch回调函数then正常返回 resolved,里面有报错则返回 rejected
catch正常返回 resolved,里面有报错则返回 rejected
Promise 的实例有两个过程
pending -> fulfilled : Resolved(已完成)pending -> rejected:Rejected(已拒绝)欢迎分享,转载请注明来源:内存溢出
评论列表(0条)