什么是原型?原型链
每个对象都有原型,对象的原型可以通过其构造函数的 prototype 属性访问。查找㇐个对象的属性或⽅法时,
如果在对象本身上没有,就会去其原型上查找;
⽽原型本身也是㇐个对象,如果在
原型上也找不到,就会继续找原型的原型, 原型链的终点是null
什么是闭包
内部函数 inner 如果引⽤了外部函数 outer 的变量 a,会形成闭包。如果这个内部函数作为外部函数的返回值,就会形成词法环境的引⽤闭环(循环引⽤),对
应变量 a 就会常驻在内存中,形成⼤家所说的“闭包内存泄漏”。虽然闭包有内存上的问题,但是却突破了函数作⽤域的限制,使函数内外搭起了沟通的桥
梁。闭包也是实现私有⽅法或属性,暴露部分公共⽅法的渠道。还可以引申出柯⾥化,bind 等概念,⾯试官说“可以啊,⼩伙⼦!” 变量提升问题
JS 分为词法分析阶段和代码执⾏阶段。在词法分析阶段,变量和函数会被提升(Hoist),注意 let 和 const 不会提升。⽽赋值操作以及函数表达式是不会被提
升的。
出现变量声明和函数声明重名的情况时,函数声明优先级⾼,会覆盖掉同名的变量声明!为了降低出错的⻛险,尽量避免使⽤hoist!
简单来说就是 函数内部访问函数外部的变量
var obj = {
val: 5
}
function test(obj) {
obj.val = 10;
console.log(obj.val);
var obj = { val: 20 };
console.log(obj.val)
}
test(obj);
console.log(obj.val)
// 10 20 10
JS中的this
如果是在全局作⽤域下,this 的值是全局对象,浏览器环境下是 window。
函数中 this 的指向取决于函数的调⽤形式,在㇐些情况下也受到严格模式的影响。
●作为普通函数调⽤:严格模式下,this 的值是 undefined,⾮严格模式下,this 指向全局对象。
● 作为⽅法调⽤:this 指向所属对象。
● 作为构造函数调⽤:this 指向实例化的对象。
● 通过 call, apply, bind 调⽤:如果指定了第㇐个参数 thisArg,this 的值就是 thisArg 的值(如果是原始值,会包装为对象);如果不传 thisArg,要判断
严格模式,严格模式下 this 是 undefined,⾮严格模式下 this 指向全局对象。
继承
- 通过原型链实现继承
// 定义一个动物类
function Animal (name) {
// 属性
this.name = name || 'Animal';
// 实例方法
this.sleep = function(){
console.log(this.name + '正在睡觉!');
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};
- 核心: 将父类的实例作为子类的原型
function Cat(){
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
特点:
-
非常纯粹的继承关系,实例是子类的实例,也是父类的实例
-
父类新增原型方法/原型属性,子类都能访问到
-
简单,易于实现
2构造继承
核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
缺点
- 只能继承父类的实例属性和方法,不能继承原型属性/方法
- 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
- 实例并不是父类的实例,只是子类的实例
3实例继承
核心:为父类实例添加新特性,作为子类实例返回
function Cat(name){
var instance = new Animal();
instance.name = name || 'Tom';
return instance;
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false
特点
- 不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果
- 实例是父类的实例,不是子类的实例
- 不支持多继承
节流防抖
防抖
抖的意思是,在连续的操作中,无论进行了多长时间,只有某一次的操作后在指定的时间内没有再操作,这一次才被判定有效。具体场景可以搜索框输入关键字过程中实时 请求服务器匹配搜索结果,如果不进行处理,那么就是输入框内容一直变化,导致一直发送请求。如果进行防抖处理,结果就是当我们输入内容完成后,一定时间(比如500ms)没有再 输入内容,这时再触发请求。
应⽤场景:
- 窗⼝⼤⼩变化,调整样式
- 搜索框,输⼊后 1000 毫秒搜索
- 表单验证,输⼊1000 毫秒后验证
- 频繁点击按钮,使⽤防抖避免重复提交请求
function debounce(handler,ms,flag){
let timer = null;
return function(...args){
clearTimeout(timer);
if(flag&&!timer){
handler.apply(this,args);
}
timer = setTimeout(()=>{
handler.apply(this,args);
},ms)
}
}
//demo
window.addEventListener('resize',debounce(handler,1000));
function handler(){
console.log('ok');
}
节流
节流( throttle ):节流的意思是,规定时间内,只触发一次。比如我们设定500ms,在这个时间内,无论点击按钮多少次,它都只会触发一次。具体场景可以是抢购时候,由于有无数人 快速点击按钮,如果每次点击都发送请求,就会给服务器造成巨大的压力,但是我们进行节流后,就会大大减少请求的次数。