function a() {
var name = 'dov';
return function(){
return name;
}
}
var b = a();
consoe.log(b())
这段代码中,a()中的返回值是一个匿名函数,这个函数在a()作用域内部,所以它可以获取a()作用域下变量 name 的值,将这个值作为返回值赋给全局作用域下的变量b,实现了在全局变量下获取到局部变量中的变量值。
function fn() {
var num = 3;
return function() {
var n = 0;
console.log(++n);
console.log(++num)
}
}
var fn1 = fn();
fn1() // 1 4
fn1() // 1 5
一般情况下,在函数fn执行完后,就应该连同它里面的变量一同被销毁,但是在这个例子中,匿名函数作为fn的返回值被赋值给了fn1,这个时候,相当于fn1=function(){var n = 0 ...},并且匿名函数内部引用着 fn 里的变量 num,所以变量 num 无法被销毁,而变量 n 是每次被调用时新建的,所以每次fn1 执行完后它属于自己的变量连同自己一起销毁,于是最后就剩下num,于是这里就产生了内存消耗的问题。
var n = true;
n.constructor === Boolean; // true
var num = 1;
num.constructor === Number; // true
var str = 'hello world';
str.constructor === String // true
var num = new Number();
num.constructor === Number // true
写在前面
像很多的印象,对美的的认识,就是这不就是一家制造业公司,怎么还会有前端开发工程师呢,他们在苏州成立了一个美的清洁公司,专门做的是扫地机器人方面的,偏向于物联网。
这次的面试,对我的打击还是挺大的,明显觉得自己的能力不足,回答起问题仅仅是大概,了解,给人的印象是,这个人能力仅仅停留在了解,认识方面,但没有深入,对原理行的内容没有深入的研究和思考,没有真正形成自己的认识。浅尝辄止。印象深刻啊,我现在年龄也不小了,不能在这样下去了。
面试的内容记录
闭包 闭包有三个特性:
函数作为返回值
这段代码中,a()中的返回值是一个匿名函数,这个函数在a()作用域内部,所以它可以获取a()作用域下变量 name 的值,将这个值作为返回值赋给全局作用域下的变量b,实现了在全局变量下获取到局部变量中的变量值。
一般情况下,在函数fn执行完后,就应该连同它里面的变量一同被销毁,但是在这个例子中,匿名函数作为fn的返回值被赋值给了fn1,这个时候,相当于
fn1=function(){var n = 0 ...}
,并且匿名函数内部引用着 fn 里的变量 num,所以变量 num 无法被销毁,而变量 n 是每次被调用时新建的,所以每次fn1 执行完后它属于自己的变量连同自己一起销毁,于是最后就剩下num,于是这里就产生了内存消耗的问题。定时器与闭包: 一个for循环,让它按顺序打印当前循环次数
按照预期,它应该依次输出1 2 3 4 5,而且结果它输出了五次5,这是为什么呢?原来由于js是单线程的,所以在执行for循环的时候定时器settTimeout 被安排到任务队列中排队等待执行,而等待过程中for循环就已经执行,等到setTimeout可以执行的时候,for 循环已经结束了,i 的值也已经变成了5,所以打印出来5个5,那么我们为了实现预期结果应该怎么改呢(ps:如果for循环里面的var变成let,也能实现预期结果)
引入闭包来保存变量i,将setTimeout放入立即执行函数中,将for循环中的循环值i作为参数传递,100毫秒后同时打印出1 2 3 4 5 函数作为参数传递
优点: 保护函数内的变量安全,实现封装,防止变量流入其他环境发生命名冲突 在内存中维持一个变量,可以做缓存(但使用多了,同时也是一项缺点,消耗内存) 匿名自执行函数可以减少内存消耗 缺点: 其中一点上面已经体现了,就是被引用的私有变量不能被销毁,增大了内存消耗,造成了内存泄漏,解决方法是使用完变量后,手动为它赋值为null 其次:由于闭包涉及跨作用域访问,会导致性能损失,通常把跨作用域的变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响
设计模式 问到了单例模式和观察者模式 观察者模式和发布订阅的区别 观察者模式是如何实现当被观察者发生变化,通知所有观察者的
webpack的原理
路由 history模式存在的问题 需要后端配合写对应的路由,不然会出现404问题
vue的响应式原理
Object.defineProperty是如何实现响应式的 对对象进行监听 利用Object.defineProperty(obj, pop, descriptor)对对象的属性进行数据劫持加上发布订阅来实现数据的双向绑定的。
proxy 在目标对象之前架一层拦截,外界对该对象访问,都要经过该拦截。因此,提供了一种机制,可以对外界的访问进行过滤和改写。
ES6 Array 有哪些方法 from,fill,of,find,findIndex,includes,flat,flatMap,entries,keys,values,copyWithin;
TS泛型 不仅能支持当前的数据类型,也能支持未来的数据类型
静态资源的刷新问题
事件环,EventLoop
git pull 和 git pull rebase的区别 git pull = git fetch + git merge git pull rebase = git fetch + git rebase
如何使用git指令合并代码冲突
为什么代码的管理存在冲突
数组的map和forEach方向有什么区别么 map 方法返回一个新的数组 不会对空数组进行检测,不会改变原数组 要操作的数组是空数组,返回的也是一个空数组。 forEach 无论数组是不是空的,forEach返回的都是undefined 对数组的每个元素,将元素返回给回调函数 对空数组不会调用回调函数 这个方法只是将数组的每一项作为callback的参数,执行一遍
如何优化组件
性能优化方面有哪些 加载优化 渲染优化 构建优化
项目方面的内容
判断object的数据类型
19.1 typeof typeof 只能判断区分基本类型,number、string、boolean、undefined 和 object,function;
typeof null; // object typeof {}; // object typeof []; // object
var a={} a instanceof Object // true a instanceof Array // false
var b = []; b instanceof Array // true b instanceof Object // true
var c='abc'; c instanceof String; // false var d = new String(); d instanceof String // true
var o={} o.constructor === Object // true var arr = [] arr.constructor === Array // true arr.constructor === Oject // false
var n = true; n.constructor === Boolean; // true var num = 1; num.constructor === Number; // true var str = 'hello world'; str.constructor === String // true var num = new Number(); num.constructor === Number // true