面试中遇到的平常没注意的问题——持续更新

面试中遇到的平常没注意的问题

1. for循环中let 声明的变量i 和 var 声明的变量i 有什么区别

  • let 声明的是块级作用域;var 声明的是在全局范围内都有效
  • let 声明的变量只在本轮循环有效;var 声明的全局范围有效,全局只有这一个i值,所以每次循环变量i的值都会发生改变

实例代码

 var a = []
 for (let i=0; i<10;i++){
    a[i] = function(){
       console.log(i)
    }
 }
 
 console.log(a[6]())  // 6
 
 var a = []
 
 for (var i=0; i<10; i++) {
   a[i] = function() {
      console.log(i)
   }
 }
 
 console.log(a[6]()) // 10

for循环还有一个特别的地方, 就是设置循环变量的部分是一个父作用域,循环体内部是一个单独的子作用域

 for(let i = 0;i�<3;i++){
   let i = 'abc'
   console.log(i)
 }
 // abc
 // abc
 // abc

2.如何才能实现深复制(深拷贝)

使用递归的方式进行深拷贝

1 第一种递归方式,复制目标对象是函数参数

  // 深拷贝函数 复制目标对象
  function deepCopy(targetObject) {
       let newObj = {}
        if(typeof targetObject !== 'object'){
            return targetObject
        } else {
               for(let property in targetObject){
             newObj[property] = deepCopy(targetObject[property])
           }
        }
        return newObj
  }

2 序列化反序列化 (一句代码搞定,装逼爽歪歪)

  let newObject = JSON.parse(JSON.stringify(targetObject))

3.实现一个function sum 达到以下目的

  sum(1,2,3,4,5).valueOf()    // 15
  sum(1,2,3,4)(5).valueOf()   // 15
  sum(1,2,3)(4)(5).valueOf()  // 15
  sum(1,2)(3)(4)(5).valueOf() // 15
  sum(1,2)(3,4)(5).valueOf()  // 15
   
  • 这道题考的是 函数 的柯里化
  • valueOf 涉及到的是 js 的隐式转换

柯里化:(Currying) 又称为部分求值,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回一个新的函数的技术,新函数接受余下参数并返回运算结果。

1.接收单一参数,因为要携带不少信息,因此常常以回调函数的理由来解决

2.将部分参数通过回调函数等方式传入函数中

3.返回一个新函数,用于处理所有的想要传入的参数

概念我晚点查阅一下专业的书籍来补充,包括柯里化的好处这些

由浅入深的柯里化

  // 普通的add函数
  function add(x, y){
     return x + y
  }
  
  // 柯里化后
  function curryingAdd(x){
    return function(y){
       return x+y
    }
  }
  
  add(1, 2)           // 3
  curryingAdd(1)(2)   // 3

接着,补充几个隐式转换的小问题

  function fn(){
    return 20
  }
  
  console.log(fn + 10)
  // 输出什么
  
  function fn(){
    return 20
  }10
  function fn() {
    return 20
  }
  
  fn.toString = function() {
    return 10
  }
  
  console.log(fn + 10)
  // 输出什么
  
  20
  function fn() {
    return 20
  }
  
  fn.toString = function() {
    return 10
  }
  
  fn.valueOf = function() {
    return 5
  }
  
  console.log(fn + 10)
  // 输出什么
  
  15
  • 这里是JavaScript 中隐式转换的知识点

  • 其中 valueOf 的优先级比 toString 要高

开始解这个题

  function add() {
     // 第一次执行时,定义一个数组专门用来存储所有的参数
     var _args = Array.prototype.slice.call(arguments)
     
     // 在内部声明一个函数,利用闭包特性保存_args并收集所有的参数
     var _adder = function() {
       _args.push(...arguments);
       return _adder
     }
     
     // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回(valueOf 也可以,优先级比toString高)
     _adder.toString = function() {
        return _args.reduce(function(a,b){
            return a+b; 
        })
     }
     
     _adder.valueOf = function() {
        return _args.reduce(function(a,b){
            return a+b; 
        })
     }
          
     return _adder
  }

4.如何自己实现双向绑定

使用 Object.defineProperty

  html 部分
  <html>
     <head></head>
     <body>
        <input type='text' id='test-input' />
        <span id='test-label'></span>
        <script>
          (function(){
             const obj = {}
             const _input = document.getElementById('test-input')
             const _label = document.getElementById('test-label')
             
            Object.defineProperty(obj,'val', {
                 get: function(){
                    return obj
                 },
                 set: function(newValue){
                     _input.value = newValue;
                     _label.innerHTML = newValue
                 }
            })
            
            // 监听input的改值事件
            _input.addEventListener('keyup', function(e){
                obj.val = e.target.value 
            })
            
          })()
        </script>
     </body>
  </html>

5. react 中的key的作用,和为什么最好不要使用索引index作为key

和react的diff算法有关

  • 当使用React,在某一个时间点,可以认为render()函数是在创建React元素树
  • 在下一个状态或属性更新时,render()函数将返回一个不同的React元素树。
  • React需要算出如何高效更新UI以匹配最新的树
  • react 基于两点假设,实现了一个启发的O(n)算法
    1. 两个不同类型的元素将产生不同的树
    1. 开发者可以使用Key属性来提示那些子元素贯穿不同渲染是稳定的

所以使用key属性是为了区分相同类型的元素,避免重新渲染所有元素树来使用的

  • 当子节点有key时,react使用Key来匹配原始树的子节点和随后树的子节点
  • 这个key在兄弟元素中必须是惟一的
  • 如果使用索引来作为Key, 如果元素顺序不变,效果不错,但是重新排序就会很慢

6.实现一个闭包,每调用一次就自增加1

  const addSelf = (function(){
     var num = 0;
     return function(){
        return num++
     }
  })()

6.盒子模型描述

标准盒子模型: 盒子的总宽度/总高度 = margin+padding+border+width/height

IE盒子模型: 盒子的总宽度/总高度 = marging+width/height

7. ajax 的事件是

ajaxStart()——————用于为ajax请求的ajaxStart事件绑定处理函数

ajaxStop()——————用于为ajax请求ajaxStop事件绑定处理函数

ajaxSend()——————用于设置当Ajax请求即将被发送时执行的回调函数

ajaxComplete()——————用于设置当Ajax请求完成(无论成功或失败)时执行的回调函数

ajaxSuccess()——————用于设置当Ajax请求成功完成时执行的回调函数

ajaxError()———————用于设置当Ajax请求失败时执行的回调函数

8. JavaScript 异步编程,如何解决回调地狱

  1. 拆解function
  2. 事件发布/监听模式
  3. Promise
  4. generator 函数
  5. async/await
  • 拆解function // 缺点:缺少通用性
  // 将各步拆解为单个的function
  function getData(count){
    get(`/sampleget?count=${count}`, data=>{
      console.log(data)
    })
  }
  
  function queryDB(kw){
    db.find(`select * from sample where kw = ${kw}`, (err, res)=>{
        getData(res.length)
    })
  }
  
  function readFile(filepath){
    fs.readFile(filepath, 'utf-8',(err, content)=>{
       let keyword = content.substring(0, 5);
       queryDB(keyword)
    })
  }

  readFile('./sample.txt')
  • 事件发布/监听模式 // event.emitter 一方面监听事件,事件发生时,进行相应回调操作; 另一方面,当某些操作完成后,通过发布事件触发回调
  const events = require('events')
  const eventEmitter = new events.EventEmitter();
  
  // 订阅
  eventEmitter.on('db',(err, kw)=>{
     db.find(`select * from sample where kw = ${kw}`, (err, res)=>{
        // 发布
        eventEmitter.emit('get', res.length);
     })
  })
 
 // 订阅 
  eventEmitter.on('get',(err,count)=>{
     get(`/sampleget?count=${count}`, data=>{
        console.log(data);
     })
  })
  
  fs.readFile('./sample.txt', 'utf-8', (err, content)=>{
    let keyword = content.substring(0, 5);
    // 发布
    eventEmitter.emit('db', keyword)
  })

  • Promise 链式调用
  // 借助原生promise来改造需要用到的方法, 以 fs.readFile为例
  // 对其他一些异步方法也可以参照这种方法进行改造
  const readFile = function(filepath){
     let resolve;
     let reject;
     let promise = new Promise((_resolve, _reject)=>{
        resolve = _resolve;
        reject = _reject;
     })
     let deferred = {
        resolve,
        reject,
        promise
     };
     fs.readFile(filepath, 'utf-8', function(err, ...args){
       if(err){
          deferred.reject(err)
       } else {
          deferred.resolve(...args)
       }
     })
     return deferred.promise
  }

使用中就变成了

  readFile('./sample.txt').then(content=>{
      let keyword = content.substring(0, 5);
      return queryDB(keyword)
  }).then(res => {
      return getData(res.length)
  }).then(data => {
     console.log(data)
  }).catch(err => {
     console.log(err);
  })

  • generator 函数 // 在function关键字后面添加*即可 通过 yield暂停; 通过next方法来恢复yield 后面的代码执行
  • async/await 函数;相当于generator函数的语法糖,在async函数中可以使用await语句,await后一般是一个Promise对象

8. 隐式转换类问题 下面代码输出什么

console.log(1+"2"+"2") // 122
console.log(1+ +"2"+"2") // 32 这种隐式转换只有+和-才能转,* 和 / 皆要报错
console.log('A'-'B'+ 2) // NaN
console.log('A'-'B'+'2') // NaN2 字母和数字字符串的转换也只能用 +

9.以下js表达式返回false的是; 这个只有输出看,考隐式转换

1 == true;
''== false;
false == null; // false undefined == false; false == undefined 也是false
null==undefined;

9.关于屏幕尺寸标准

col-xs-* < 768 手机
col-sm-* >= 768 平板
col-md-* >= 992 桌面
col-lg-* >= 1200 大屏幕桌面

10. var a = b = 3 ===> var a = 3; b = 3; 变量声明提升是将var a;提升到最上面,赋值不会

11 什么是事件委托,事件委托的好处是什么?

事件委托就是利用事件冒泡机器指定一个事件处理程序,来管理某一类型的所有事件。
即: 利用冒泡的原理,给父元素绑定事件,用来监听子元素的冒泡事件,并找到是哪个子元素的事件
好处:

只在内存中开辟了一块空间,避免对每个子元素添加事件监听器,节省资源同时减少了dom操作,提高性能

对于新添加的元素也会有之前的事件

12 用setTimeout来模拟setInterval();有什么区别

 function simulateInterval(){
   setTimeout(function(){
      simulateInterval();
   }, 1000)
 }
 
 setTimeout(simulateInterval, 1000)
 

区别是setTimeout是调用自身函数

13 垂直居中的方式

常用的
flex布局

  父元素{
     display: flex;
     justify-content: center;
     align-items: center;
  } 

万能居中

  父元素{
    position: relative;
  }
  
  子元素{
     position: absoluted;
     top: 50%;
     left:50%;
     transform: translate(-50%,-50%)
  }
 

确定子元素高度的居中

  父元素{
    position: 除了static之外的定位
  }
  
  子元素{
    position: absoluted;
    top:0;
    left:0;
    right:0;
    bottom:0;
    margin:auto;
    overflow:auto;
    width: XX px;
    height: XX px;
  }

14 js中的new()到底做了什么?

  1. 创建了一个新的对象实例
  2. 将构造函数的作用域赋给了新对象实例(使this指向了这个新的对象实例)
  3. 调用构造函数(为新对象添加属性和方法)
  4. 返回新对象

15 js垃圾回收机制,它的存在有什么必要性(删除使用过不再使用的变量,释放内存),具体的垃圾回收方法有哪几种?各自的特点是什么?

垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存

垃圾回收的方法有两种

1.标记清除法: 在函数声明一个变量的时候,就将这个变量标记为“进入环境”。而当变量离开环境时,则将其标记为“离开环境”。 垃圾回收器在运行时会给存储在内存中的所有变量都加上标记, 然后会去掉环境中的变量以及被环境中变量引用的的变量的标记。 在此之后再被标记的变量将被视为准备删除的变量,因为环境中的变量已经无法访问到这些变量了。最后,垃圾回收器完成内存清除工作,销毁那些带标记的值并回收他们所占用的内存空间

  function test(){
    var a = 10; // 被标记,进入环境
    var b = 20; // 被标记, 进入环境
 }

  test();  // 执行完毕之后, a、b又被标记离开环境,被回收 

2.引用计数法
引用计数的含义是跟踪记录每个值被引用的次数。当生命了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1.如果同一个值又被赋给另一个变量,则该值的引用次数加1.相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1.当这个值的引用次数变成0时,则说明没有办法再范文这个值了,因而可以将其占用的内存空间回收回来。这样,当垃圾回收器下次再运行时,它就会释放那些引用次数为0的值所占用的内存。

当遇到循环引用的时候,函数的引用次数就不会为0,所以不会被垃圾回收器回收内存,会造成内存泄露

 function test(){
   var a = {}; // a的引用次数为0
   var b = a;  // a的引用次数加1, 为1
   var c = a; // a 的引用次数再加1, 为2
   var b = {}  // a的引用次数减1, 为1 
}

16 TCP与UDP区别总结

  1. TCP面向连接(如电话要先拨号建立连接); UDP是无连接的,即发送数据之前不需要建立连接
  2. TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按需到达;UDP尽最大努力交付,即不保证可靠交付
  3. UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性较高的通信或广播通信。
  4. 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
  5. TCP对系统资源要求较多,UDP对系统资源要求较少
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容