闭包
什么是闭包?闭包的作用?闭包的应用?
答:
函数执行,形成私有的执行上下文,使内部私有变量不受外界干扰,起到保护和保存的作用
作用:
- 保护
- 避免命名冲突
- 保存
- 解决循环绑定引发的索引问题
-
变量不会销毁
- 可以使用函数内部的变量,使变量不会被垃圾回收机制回收
应用:
- 设计模式中的单例模式
- for循环中的保留i的操作
- 防抖和节流
- 函数柯里化
缺点
- 会出现内存泄漏的问题
原型和原型链
什么是原型?什么是原型链?如何理解
答:
原型: 原型分为隐式原型和显式原型,每个对象都有一个隐式原型,它指向自己的构造函数的显式原型。
原型链: 多个__proto__
组成的集合成为原型链
- 所有实例的
__proto__
都指向他们构造函数的prototype
- 所有的
prototype
都是对象,自然它的__proto__
指向的是Object()
的prototype
- 所有的构造函数的隐式原型指向的都是
Function()
的显示原型 - Object的隐式原型是null
继承
说一说 JS 中的常用的继承方式有哪些?以及各个继承方式的优缺点。
答:
原型继承、组合继承、寄生组合继承、ES6的extend
原型继承
// ----------------------方法一:原型继承 // 原型继承 // 把父类的实例作为子类的原型
// 缺点:子类的实例共享了父类构造函数的引用属性 不能传参
var person = { friends: ["a", "b", "c", "d"] } var p1 = Object.create(person) p1.friends.push("aaa")
//缺点:子类的实例共享了父类构造函数的引用属性 console.log(p1); console.log(person);
//缺点:子类的实例共享了父类构造函数的引用属性
组合继承
// ----------------------方法二:组合继承
// 在子函数中运行父函数,但是要利用call把this改变一下,
// 再在子函数的prototype里面new Father() ,使Father的原型中的方法也得到继承,最后改变Son的原型中的constructor
// 缺点:调用了两次父类的构造函数,造成了不必要的消耗,父类方法可以复用
// 优点可传参,不共享父类引用属性
function Father(name) {
this.name = name
this.hobby = ["篮球", "足球", "乒乓球"] }
Father.prototype.getName = function () { console.log(this.name); }
function Son(name, age) { Father.call(this, name) this.age = age }
Son.prototype = new Father()
Son.prototype.constructor = Son
var s = new Son("ming", 20)
console.log(s);
寄生组合继承
// ----------------------方法三:寄生组合继承
function Father(name) {
this.name = name
this.hobby = ["篮球", "足球", "乒乓球"] }
Father.prototype.getName = function () {
console.log(this.name); }
function Son(name, age) {
Father.call(this, name)
this.age = age }
Son.prototype = Object.create(Father.prototype)
Son.prototype.constructor = Son
var s2 = new Son("ming", 18)
console.log(s2);
extend
// ----------------------方法四:ES6的extend(寄生组合继承的语法糖)
// 子类只要继承父类,可以不写 constructor ,一旦写了,则在 constructor 中的第一句话
// 必须是 super 。
class Son3 extends Father {
// Son.prototype.__proto__ = Father.prototype constructor(y) {
super(200)
// super(200) => Father.call(this,200)
this.y = y } }