js相关(一)
1.闭包
定义:闭包就是能够读取其他函数内部变量的函数,将函数内部和函数外部连接起来的桥梁
意义:能够间接的访问函数内部变量
作用:内存常驻,隔离作用域,可以用来定义私有属性 和 私有方法
弊端:常驻内存 会增大内存的使用量 使用不当会造成内存泄露,可以改变父函数内部变量的值
2.变量作用域
3.原型和原型链
前者对象模版(每个对象都会在其内部初始化一个属性,就是prototype(原型))
后者利用原型让一个引用类型继承另一个引用类型的属性和方法
var A=function(){}
A.prototype.n=1
var b=new A()
A.prototype={
n:2,
m:3
}
var c=new A()
console.log(b.n,b.m,c.n,c.m)//多少
答案为1,undefined,2,3。原因是b继承A,所以b.n就为1,而m在A中找不到,所以为undefined,以此类推,c继承的时候A添加了n和m,所以c.n和c.m分别是2和3
var F = function () {}
Object.prototype.a = function () {}
Function.prototype.b = function () {}
var f = new F()
// 请问f有方法a 方法b吗
// 或者f.a()//?f.b()//?F.a()//?F.b()//?
f的__proto__指向F.prototype,F.prototype.__proto__指向Object.prototype,所以f 可以取到a方法, 由于f的原型链上没经过Function.prototype,所以取不到b方法,由于构造函数F是由
Function new出来的,所以F.__proto__指向Function.prototype,所以F函数可以取到b方法。
new运算法的工作原理:1.创建一个新对象,这个对象继承自构造函数的prototype属性2.把上下文this指向这个新对象3.要不要返回这个新对象,用return会取代,不用就返回这个新对象
4.深拷贝和浅拷贝区别及实现
ES6的Object.assign()方法 //先建立一个空对象{},接着把obj1中所有的属性复制过去,所以obj2会长得跟obj1一样,这时候再修改obj2.b也不会影响obj1。
var obj1 = {name:'lily'};
var obj2 = Object.assign({},obj1);
obj2.name = 'bob';
console.log(obj1.name); //lily
console.log(obj2.name); //bob
将对象转成字符串再转换回来 //用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象
var obj = {
a:'hello',
b:{
name:'lily',
age:21
},
c:[1,2,3]
};
var obj1 = JSON.parse(JSON.stringify(obj));
obj1.a = 'world';
obj1.b = {
name:'bob',
age:15
};
obj1.c = [6,7,8];
console.log(obj.a);
console.log(obj.b);
console.log(obj.c);
console.log(obj1.a);
console.log(obj1.b);
console.log(obj1.c);
//不能针对函数function,无效
递归方法实现深拷贝
function deepClone(obj){
//先制造一个新的数组或对象,指向一个新的空间
var newObj = Array.isArray(obj) ? [] : {};
//判断obj的类型
//基本类型
if(typeof obj != 'object'){ //是普通类型的话就直接赋值,但不能直接返回obj,那样是浅拷贝
return newObj = obj;
}
//引用类型
if(obj instanceof Array){ //是数组
for(var i=0;i<obj.length;i++){
newObj[i] = obj[i];
if(typeof newObj[i] == 'object'){ //如果数组的值有对象的话,就继续递归
deepClone(newObj[i]);
}
}
}else{ //是对象
for(var key in obj){
if(obj.hasOwnProperty(key)){
if(typeof obj[key] == 'object'){ //对象中的数组和对象
newObj[key] = deepClone(obj[key]); //继续递归
}else{//对象中没有引用类型
newObj[key] = obj[key];
}
}
}
}
return newObj;
}
var obj = {
a:'haha',
b:[1,2,3],
c:function(){
console.log('hello');
}
};
var cloneObj = deepClone(obj);
cloneObj.a = '你好';
cloneObj.b = [6,7,8];
cloneObj.c = function(){
console.log('world');
};
console.log(obj);
console.log(cloneObj);
5.防抖与节流
限制函数的执行频次,来优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象(例如input,keyup,keydown,scroll,resize,mousemove等)
函数防抖:触发完事件 n 秒内不再触发,才执行;如果n秒内事件再次被触发,则重新计算时间
应用场景:input及window的resize、scroll事件
function debounce(fn,delay = 100){
// 创建一个标记用来存放定时器的返回值
let timer = null
return function (){
// 每当事件触发的时候把前一个 setTimeout清除
if(timer) clearTimer(timer)
// 然后又创建一个新的 setTimeout, 这样就能保证时间间隔内如果事件持续触发,就不会执行 fn 函数
timer = setTimeOut(() => {
fn.apply(this,arguments)
timer = null
},delay)
}
}
函数节流:持续触发事件,每隔一段时间,只执行一次事件(类似于技能冷却时间)
应用场景:连续不断的触发某事件
function throttle(fn,delay = 100){
// 通过闭包保存一个标记,相当于一个开关
let timer = null
return function(){
// 在函数开头判断标记定时器是否触发,如果有值return
if(timer) return
timer = setTimeOut(() => {
fn.apply(this,arguments)
timer = null
},delay)
}
}