数据类型
基本数据类型
Number,String,Boolean,null,undefined,symbol
symbol可生产唯一的、不可变的标识
let a =Symbol() //可以带参数Symbol("food")
let b=Symbol()
console.log(a==b);//false
引用数据类型
Object,Array,Function,Date,Set等
基本数据类型存放在栈中,引用数据类型地址存在栈中,值存在堆中
数据类型检测
typeof
检测基本数据类型
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof null // 'object'
typeof [] // 'object'
typeof {} // 'object'
typeof console // 'object'
typeof console.log // 'function'
instanceof
通过判断对象是否是该构建函数生成的实例对象
// 定义构建函数
let Car = function() {}
let benz = new Car()
benz instanceof Car // true
let car = new String('xxx')
car instanceof String // true
let str = 'xxx'
str instanceof String // fals
区别:
typeof返回一个变量的基本数据类型,instanceof返回布尔值
typeof适合判断基本数据类型,instanceof适合判断引用对象
推荐:Object.prototype.toString可以检测所有类型
BOM
window,location,navigator,history
window.open可以导航到一个特定的url,也可以打开一个新的浏览器窗口
location.reload()可以强制重新刷新当前页面
history.go(),接受一个整数或字符串参数
history.go(3) //向前跳转三个记录
history.go(-1) //向后跳转一个记录
history.forward() :向前跳转一个记录
history.back() :回退一个记录
history.length :获取历史记录长度
call、apply、bind
都是修改this指向的,第一个参数是指定this的指向
call除了第一个参数外,传参是参数列表
apply除了第一个参数外,传参是数组,跟array长相类似
bind会返回改变this指向后的函数,不会立即执行
let obj={name:'zhangsan'}
function fn (...args){
console.log(this,args);
}
fn.call(obj,1,2) //{ name: 'zhangsan' } [ 1, 2 ]
fn.apply(obj,[1,2]) //{ name: 'zhangsan' } [ 1, 2 ]
const bindFn= fn.bind(obj,1,2) //{ name: 'zhangsan' } [ 1, 2 ]
bindFn()
事件冒泡和事件捕捉
冒泡从小到大(从子到父),捕捉从大到小(从父到子)
闭包
一个函数和对其周围状态的引用捆绑在一起,这样的组合就是闭包
function init(){
let name="张三"
function changeName(){
name='李四' //使用别的函数里面的变量
}
changeName()
console.log(name);
}
init()
作用:创建私有变量,延长变量的生命周期
计时器,延迟调用,回调等都是闭包的具体用处。
浅拷贝深拷贝
浅拷贝
Object.assign,Array.prototype.slice(),Array.prototype.concat(),...展开运算符
只有引用对象会受影响
let obj={
name:"李四",
likes:['足球,篮球']
}
let newObj=Object.assign({},obj)
newObj.name="张三"
newObj.likes[0]='乒乓球'
console.log(obj); //{ name: '李四', likes: [ '乒乓球' ] }
const arr=["One", "Two", "Three"]
let newArr=arr.concat()
let newArr=arr.slice()
let newArr=[...arr]
深拷贝
_cloneDeep,JSON.parse(JSON.stringify()(会忽略undefined,symbol和函数)
递归克隆
function deep(obj){
//set对象就return new set ,,map。函数等。。。
if(Object.prototype.toString.call(obj)=="[object Function]"){
return obj
}
let targetObj=Object.prototype.toString.call(obj)=="[object Array]"?[]:{}
//先看是对象还是数组
for(let i in obj){
//忽略原型上的属性
if(obj.hasOwnProperty(i)){
//循环obj的i,如果是对象或者数组继续递归赋值
let val=obj[i]
if(i instanceof Array || i instanceof Object ){
targetObj[i]=deep(val)
}else{
targetObj[i]=val
}
}
}
return targetObj
}
函数缓存
将函数运算过的结果缓存起来
主要依靠闭包、柯里化、高阶函数
柯里化
把接受多个参数的函数 转化为接受单一参数的函数
function add (x,y){
return x+y
}
// 柯里化
function add1(x){
return function(y){
return x+y
}
}
add1(2)(3)
高阶函数
接收其他函数作为参数,或者返回其他函数的函数
function foo(){
let a =2
function bar(){
console.log(a);
}
return bar
}
let baz=foo()
baz()
字符串方法
//增
let str1 = "hello ";
let str2 = str1.concat("world");
console.log(str2); // "hello world"
//删除
//slice,截取包括前面不包括后面
//substr,截取包括前面也包括后面
//substring,截取包括前面不包括后面
let stringValue = "hello";
console.log(stringValue.slice(2)); // "llo"
console.log(stringValue.slice(1, 3)) //"el"
console.log(stringValue.substr(2)); // "llo"
console.log(stringValue.substr(1, 3)) //"ell"
console.log(stringValue.substring(2)) //"llo"
console.log(stringValue.substring(1, 3)) //"el"
//改
//trim():清空空格,toUpperCase(),toLowerCase()大小写
//replace("要替换对象","替换内容")
let repStr="abcd"
let res=repStr.replace('a',"f")
console.log(res);//fbcd
//查
//indexOf,查询是否存在字符串,有返回索引,没有返-1
let str3='mes'
console.log(str3.indexOf('e'));//1
//includes,查询是否存在字符串,返回布尔值
let str4="abc"
console.log(str4.includes('a')); //true
//转化方法
//spit,转化为数组
let str5 = "12+23+34"
let arr = str5.split("+") // [12,23,34]
//length,返回字符串长度
console.log(str5.length);//8
数组方法
//增 push,unshift,splice,concat
//删 pop,shift,splice,slice
//改 splice
// let arr1=[1,2,3,4]
// arr1.splice(1,0,9)
// console.log(arr1);//[ 1, 9, 2, 3, 4 ]
//查
//indexOf,返回元素索引,未找到返回-1
//includes,返回布尔值
//find,回调,返回符合第一个匹配的元素. findIndex,返回第一个符合条件的元素下标
//reverse,元素反转, sort排序,join返回元素组成的字符串
//some,every 满足条件返回true或者false
//filter,返回满足条件的元素组成的新数组
//forEach,map
//reduce,累加处理
// new Set去重
事件循环
先同步,后异步,异步中先微任务后宏任务
微任务:promise.then()等
宏任务:script,定时器等
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
new Promise((resolve, reject) => {
console.log("new Promise"); //promise里面是同步,.then后面才是异步
resolve();
}).then(() => {
console.log("then");
});
console.log(3);
//结果1 new Promise 3 then 2
async await
async function fn1() {
console.log(1);
await fn2();
console.log(2); //会阻塞,变成微任务
}
async function fn2() {
console.log("fn2");
}
setTimeout(()=>{
console.log(4);
},1)
fn1();
console.log(3)
//打印 1 fn2 3 2 4
async function async1() {
console.log("2");
await async2();
console.log("6"); //会阻塞,加入微任务列表
}
async function async2() {
console.log("3");
}
console.log("1");
setTimeout(function () {
console.log("8");
});
async1();
new Promise(function (resolve) {
console.log("4");
resolve();
}).then(function () {
console.log("7");
});
console.log("5");
本地储存
cookie
小型文本文件,指某些网站为了辨别用户身份而储存再本地终端的数据。大小不超过4kb,有name和value组成。但是cookie每次请求都会发生,如果不使用https并对其加密,容易泄露。
cookie的数据会自动传递到服务器
sessionStorage,localStorage,sessionStorage页面关闭就会删除数据 大小5m
indexedDB 数据库,储存没有上线,但是有一定门槛
大文件断点续传
125页,待续
防抖和节流
防抖:类似游戏回城,打断重新回。n秒后再执行该事件,如果n秒内重复触发,则重新计时。
//防抖主要用于搜索框输入,文本编译器实时保存
//定义一个全局变量
let timer: any = null
function dfn() {
//如果timer存在,就清除。
if (timer !== null) {
clearTimeout(timer)
}
//1秒后会打印,还没到1秒再次执行dfn,timer此时存在,就会cleartimer,在重新执行setTiomeout
timer = setTimeout(() => {
console.log("防抖");
}, 1000)
}
节流:n秒内不管触发多少次,只执行一次
//节流,主要是用于高频事件,比如快速点击,scroll事件,resize事件等
let timer: any = null
function jfn() {
//如果timer存在,就直接结束jfn
if (timer !== null) {
return
}
//1秒后会打印,还没到1秒再次执行jfn,timer此时存在,会直接return
timer = setTimeout(() => {
console.log("节流");
timer = null
}, 1000)
}
函数式编程
一种方案简单、功能独立、对作用域外没有任何副作用的编程范式
函数式编程:
1)功能独立——不依赖于程序的状态(比如可能发生变化的全局变量);
2)纯函数——同一个输入永远能得到同一个输出;
3)有限的副作用——可以严格地限制函数外部对状态的更改。
垃圾回收机制
引用计数
跟踪每个对象的引用次数。当一个对象被引用时,它的引用计数加一;当引用失效时,引用计数减一。当引用计数为零时,表示该对象不再被使用,可以被回收。
let obj1 = { a: 1 }; // 对象 { a: 1 } 的引用计数为 1
let obj2 = obj1; // 对象 { a: 1 } 的引用计数为 2
obj1 = null; // 对象 { a: 1 } 的引用计数减为 1
obj2 = null; // 对象 { a: 1 } 的引用计数减为 0,可以被回收
标记清除
通过定期遍历所有对象,标记那些仍然在使用的对象,然后清除那些未被标记的对象。
标记阶段:
从根对象(如全局对象、活动函数等)开始,遍历所有可以访问到的对象,并标记它们。
清除阶段:
遍历所有对象,清除那些未被标记的对象。
let obj1 = { a: 1 }; // 对象 { a: 1 } 被标记为活动对象
let obj2 = { b: 2 }; // 对象 { b: 2 } 被标记为活动对象
obj1 = null; // 对象 { a: 1 } 不再被引用,在下一次垃圾回收时将被清除
obj2 = null; // 对象 { b: 2 } 不再被引用,在下一次垃圾回收时将被清除
NEW操作符
new操作符做了哪些事:1,先创建一个新的空对象。2,新对象的原型指向构造函数的prototype。
3,执行构造函数。4,返回处理后的对象