面试回答技巧(一)
如何回答的一个技术记汇,或者你对xxxx的理解?
例如:你说一下对闭包的理解?
答
:1.xxx是什么?
2.应用场景
3.优缺点
4.具体实现
5.还有没有更好的解决方案!
今天的内容都是从这几个方面来讲解。
一、闭包
1、闭包是什么?
函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成闭包(closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在 JavaScript 中,每当函数被创建,就会在函数生成时生成闭包。
总结来说:闭包就是函数加词法作用域。只要符合这两种情况基本上都是闭包。
那么什么是词法作用域呢?这里就来说说,看下面的代码:
function init() {
var name = "张三"; // name 是一个被 init 创建的局部变量
function displayName() { // displayName() 是内部函数,一个闭包
alert(name); // 使用了父函数中声明的变量
}
displayName();
}
init();
init()
创建了一个局部变量 name
和一个名为 displayName()
的函数。displayName()
是定义在 init()
里的内部函数,并且仅在 init()
函数体内可用。请注意,displayName()
没有自己的局部变量。然而,因为它可以访问到外部函数的变量,所以displayName()
可以使用父函数 init()
中声明的变量 name
。
总结:
词法作用域:即以变量声明定义的位置为参照,如果当前位置没有定义,就会访问父级定义的位置。
闭包又分为广义和狭义两种:
a、广义的闭包:
var a=1000;
function fn1() {
alert(a)
}
fn1()
b、狭义的闭包:
平时工作中用到的闭包是狭义上的闭包:
1.函数内嵌套函数
2.子函数引用了父函数的相关变量
符合上面的条件都是狭义的闭包。
特点:长期驻留内存
2、闭包的应用场景和怎么实现?
//求和
function makeAdd(x) {
return function(y) {
return x+y
}
}
//设置字号
function setFontSize(size) {
return function() {
document.body.style.fontSize=size+"px"
}
}
//循环表单
function makeHelp(help) {
return function() {
console.log(help)
document.querySelector('.help').innerHTML=help
}
}
function init() {
var userInfo=[
{id:'username',helpText:'请输入用户名'},
{id:'email',helpText:'请输入邮箱'},
{id:'address',helpText:'请输入地址'},
]
//动态绑定onfocus事件
for(var i=0;i<userInfo.length;i++) {
var item=userInfo[i];
document.getElementById(item.id).onfocus=makeHelp(item.helpText)
}
}
init()
//封装组件或插件
var Counter=(function() {
//私有变量
var index=0;
//私有方法
var add=function() {
return index++;
}
var jian=function() {
}
return {
//暴露出去供用户的方法
increment:function() {
add()
},
getValue:function() {
return index;
}
}
})()
3、闭包的优缺点
优点:
1.长期驻留内存,可以缓存数据
2.可以隔离作用域,避免全局污染
缺点:
长期使用,会造成内存泄漏。
解决内存泄漏的方法:
链接:https://www.jianshu.com/p/d903be89f211
上面的链接,自我感觉可以。
4、最好的解决方案
使用ES6的let方法,可以有效的避免。
二、原型链
https://www.jianshu.com/p/08c07a953fa0
1、原型链是什么?
每个对象都可以有一个原型_proto_,这个原型还可以有它自己的原型,以此类推,形成一个原型链。查找特定属性的时候,我们先去这个对象里去找,如果没有的话就去它的原型对象里面去,如果还是没有的话再去向原型对象的原型对象里去寻找… 这个操作被委托在整个原型链上,这个就是我们说的原型链了。
- 原型链是JS特有的一种继承机制。
- 原型链会涉及到__proto__,prototype。
- 原型链的顶端就是null。
2、原型链的主要应用场景
继承
3、优点和缺点
- 优点:把相同或类似的方法写在原型上,方便实例化对象复用
- 缺点:不好理解,通常只前端人才理解
4、解决方案
ES6推出class extends来实现继承。
三、JavaScript继承
1、继承是什么?
继承是面向对象开发思想的特性之一。
面向对象的三大特点:封装、继承、多态(多种状态)。
2、实现方式(有两种)
a、ES5继承(主要通过函数来实现类)
- 原型链继承
//创建一个父类
function Parent() {
this.name='jack'
}
Parent.prototype.getName=function() {
return this.name;
}
//创建一个子类
function Child() {
}
//子类的原型等于父类的实例化对象
Child.prototype=new Parent();
var c1=new Child()
缺点:
1、不能传参
2、 没有解决对象引用问题
- 借用构造函数继承
//创建一个父类
function Parent(name) {
this.name=name ||'jack'
this.colors=['red','green','blue']
}
Parent.prototype.getName=function() {
return this.name;
}
//创建一个子类
function Child(name) {
//借用父类来承继实例属性,但不能继承父类方法
Person.call(this,name)
}
缺点:不能继承父类方法
- 组合继承(原型链继承 + 借用构造函数)
//创建一个父类
function Parent(name) {
this.name=name ||'jack'
this.colors=['red','green','blue']
}
Parent.prototype.getName=function() {
return this.name;
}
var p1=new Parent();
p1.getName();
//创建一个子类
function Child(name) {
Parent.call(this,name)
}
Child.prototype=new Parent();
var c1=new Child()
c1.getName()
优点:既能继承父类的原型和方法,也能传递参数属性。
b、ES6继承
通过class,extends,super实现 //继承必须要写super
//创建一个父类
class Parent {
constructor(name) {
this.name=name ||'jack'
this.colors=['red','green','blue']
}
getName() {
return this.name;
}
}
//创建一个子类
class Child extends Parent {
constructor(name) {
super(name) //super就是父类Parent
}
getValue() {
}
}