目录
this是指:包含它的函数,作为方法被调用时,所指向的对象;
11. 遍历方法 for in 、for of 、Object.keys()的区别
1. JS的数据类型
基础类型:Number、String、Boolean、Undefined、Null、BigInt、Symbol(独一无二的值);
复杂数据类型:Object;
2. 判断数据类型的方法
(1)typeof
(2)instanceof
(3)Object.prototype.toString.call()
(4)constructor
3. JS的内置对象
(1)数据封装类对象:Object、Array、Boolean、Number、String;
(2)其他对象:Function、Math、Date、RegExp、Error;
4. var、let和const的区别,变量提升
(1) var声明的变量会挂载到window上,而let和const声明的变量不会;
var a=100;
console.log(a,window.a); //100 100
let b=10;
console.log(b,window.b); //10 undefined
let c=1;
console.log(c,window.c); //1 undefined
(2) var变量存在变量提升,而let和const没有;
(3) let和const声明形成块作用域;
if(1){
var a=100;
let b=10;
const c=1;
}
console.log(a,b,c) //100 报错:b is not defined 报错:c is not defined
(4) 同一作用域内,let和const不可重复声明;
(5)暂存死区;
var a = 100;
if(1){
a = 10;
//在当前块作用域中存在a使用let/const声明的情况下,给a赋值10时,只会在当前作用域找变量a,
// 而这时,还未到声明时候,所以控制台Error:a is not defined
let a = 1;
}
(6)const一旦声明变量,必须复制,且声明后不可修改其值;
5. new函数的具体实现
function _new(constructor,...args){
let obj = {};//新建一个空对象
obj._proto_ = constructor.prototype;//原型链连接
let res = constructor.apply(obj,...args);//改变this指向
return res instanceof Object ? res:obj;
}
6. apply、call、bind的实现
(1)apply:数组传参,返回函数执行结果;
apply实现
Function.prototype.myApply = function(context,args){
if(typeof this !== 'Function'){
throw new Error('this is not a function');
}
context = context || window;
context.fn = this;
let res;
if(!args){
res = context.fn();
}else{
res = context.fn(...args);
}
delete context.fn; //删除属性,避免副作用
return res;
}
(2)call:逐个传参,也会返回函数执行结果;
call实现
Function.prototype.myCall = function(context,...rest){
context = context || window;
context.fn = this;
let res = context.fn(...rest);
delete context.fn;
return res;
}
(3)bind:不执行,返回一个函数;
bind实现
Function.prototype.myBind = function(context,...rest){
let self = this;
return function(){
return self.apply(context,rest);
}
}
7. arguments和rest参数的区别
arguments不是数组,而是一个类数组对象,包含length属性,包含所有可用参数;利用 arguments ,可以获得调用者传入的所有参数;
arguments转换为数组的方法:Array.prototype.slice.call(argumen);
而rest是数组,是非定义的多余变量数组;
8. this指向的改变
this是指:包含它的函数,作为方法被调用时,所指向的对象;
优先级:箭头函数 > new > 显式 > 隐式 > 默认绑定
(1)默认绑定:非严格模式下,指向window对象;严格模式下,为undefined;
(2)隐式绑定:obj.fn;
(3)显式绑定:apply,call,bind方式;
(4)new绑定
9. 箭头函数和普通函数的区别
1. this:箭头函数没有自己的this;
2. arguments:不能使用arguments,改用rest代替;
3. 原型:没有prototype,无法作为构造函数;
4. yeild:箭头函数不能使用yeild;
10. 防抖和节流
(1)防抖:触发高频事件后,N秒内函数只会执行一次,若N秒内再次触发高频事件,则重新计时;
防抖
function debounce(fn,delay){
let timer =null;
return function(){
if(timer)clearTimeout(timer);
timer = setTimeout(fn,delay);
}
}
应用场景:
- 搜索框输入查询;
- 提交按钮;
- 浏览器窗口缩放;
- 表单验证;
(2)节流:高频事件多次触发,但在N秒内只会执行一次,稀释函数的执行频率;
节流
function throttle(fn,delay){
let timer = null;
return function(){
if(timer)return false;
timer = setTimeout(()=>{
fn();
timer = null;
},delay);
}
}
应用场景:
- 滚动加载onScroll;
- 拖拽事件;
- 高频表单提交;
11. 遍历方法 for in 、for of 、Object.keys()的区别
return 语句只能在函数体中,否则会报错
(1) for in:可遍历数组或对象的属性(随机遍历)
遍历数组:除了会遍历数组元素,还会遍历自定义可枚举的属性,以及原型链上可枚举的属性;
Array.prototype.sayLength = function(){
console.log(this.length);
}//原型链上
let arr = ['a','b','c','d'];
arr.name = '数组'; //自定义属性
Object.defineProperties(arr,{
type:{
value:true,
writable:true,
enumerable:true
}
});
for(let i in arr){
console.log(i); //0,1,2,3,name,type,sayLength
}
(2) Object.keys():遍历对象属性
和 for in 的区别在于:不能遍历原型链上的属性;
(3) for of(ES6新语法):可遍历拥有iterator迭代器对象的集合;
支持遍历数组、类对象、字符串、Set对象、Map对象;
let arr = [0,1,2,3];
for(let i of arr){
}
let person={
name:'1',
age:12
}
for(let key of Object.keys(person)){
}
或者
for(let [key,value] of Object.entries(person)){
}
12. 新增的Map、Set数据
(1)Map:一组键值对的结构,具有极快的查找速度;
let _map = new Map([['li',20],['zhao',40]]);
//新增元素
_map.set('zhu',21);
//检测key对应的值是否存在
_map.has('zhu');
//获取key对应的值
_map.get('zhu');
//删除元素
_map.delete('zhu'); //返回true或false
//计算map的长度
Object.getOwnPropertyNames(_map).length;
(2) Set:类似数组,一组key的组合,由于key不重复,故Set成员的值是唯一的,没有重复的值;
注意:在Set中,NaN等于自身;
NaN==NaN ====> false
let _set = new Set([1,2,3]);
//添加元素
_set.add('li');
//检测是否包含元素
_set.has(1);
//删除元素
_set.delete(1);
//计算set的长度
_set.size;
Set的用法:可用于去除数组重复元素;
- [... new Set(arr)];
- Array.from(new Set(arr));
(3)WeakSet:类似Set结构,但WeakSet成员只能是对象,且不可遍历,没有size属性;
WeakSet不能遍历的原因:因为WeakSet的成员都是弱引用,成员不稳定,随时可能消失;
WeakSet的用处:由于垃圾回收机制只在乎强引用,合理使用WeakSet可避免内存泄漏;
(1)使用WeakSet存储节点,避免节点从文档移除时,导致内存泄漏(即在被移除的节点上绑定的事件等);