js常见面试题详解(都学到手后找不到工作算我输)

290 阅读6分钟

好久没有来更新文章了,最近总结了一些面试题,适合初次进入前端领域的伙计们。废话就不多说了,我们直入主题吧。

面试题第一弹

一:就让我们从最“基础”的开始吧。
  • js有几种引入方式

    • 行内式、(直接在标签中写js代码)
    • 内嵌式、(只要写一个script标签即可,把对应的代码写在script标签内部即可)
    • 外链式、(仍是通过script的src的行内属性引入外界的一个JS文件)
      • 注意: css的引入方式:行内式,内嵌式(必须写在head内)
  • innerHTML 和innerText 的区别

    • innerHTML返回的是标签内的 html内容,包含html标签。
    • innerText返回的是标签内的文本值,不包含html标签。

      小拓展

      • outerHTML 设置或获取标签自身及其所包含的HTML+文本信息(包括自身)
      • outerText 设置或获取标签自身及其所包含的文本信息(包括自身)

    相信没有什么能比一张图片更能理解这几句话了!

  • js 中用什么检测数据类型

    • 1、typeOf:只能检测基本数据类型
    • 2、instanceOf:检测当前实例是否属于某个类的方法
    • 3、Object.prototype.toString.call([]); 最准确的方式
  • for…in..和for…of..的区别

    • 我们先来看一下例子
      • 例子一

                const obj = {
                    a: 1,
                    b: 2,
                    c: 3
                }
                for (let i in obj) {
                    console.log(i)
                    // a b c
                }
                for (let i of obj) {
                    console.log(i)
                    // Uncaught TypeError: obj is not iterable 报错
                }
        
      • 例子二

                 const arr = ['a', 'b', 'c']
                 // for in 循环
                 for (let i in arr) {
                     console.log(i)
                     //  0 1 2
                 }
                 // for of循环
                 for (let i of arr) {
                     console.log(i)
                     // a b c
                 }
        
      • 例子三

                const arr = ['a', 'b']
                      // 手动给 arr数组添加一个属性
                 arr.name = 'hahahha'
                      // for in 循环可以遍历出 name 这个键名
                 for (let i in arr) {
                     console.log(i)
                     // a b name
                 }
        

    由此可见,for in特点如下:

          *       for ... in 循环返回的值都是数据结构的 键值名。
          *       遍历对象返回的对象的key值,遍历数组返回的数组的下标(key)
          *       循环不仅可以遍历数字键名,还会遍历原型上的值和手动添加的其他键
          *       特别情况下, for ... in 循环会以任意的顺序遍历键名
    

    然而:for of ?

          *   用来获取一对键值对中的值,一个数据结构只要部署了Symbol.iterator 
              属性,就被视为具有 iterator接口, 就可以使用 for of循环。
          *   例1这个对象,没有 Symbol.iterator这个属性,所以使用for of会报错
          *   for of 不同与 forEach, 它可以与 break、continue和return 配合使
              用,也就是说 for of 循环可以随时退出循环。 提供了遍历所有数据结构的
              统一接口
    

    总结一句: for in 循环特别适合遍历对象。

  • 遍历数组或者对象你有几种方法?

    for(初始化;条件;遍历时要做的事情)

    for(var i=0,length=array.length;i<length;i++){//缓存数组长度
        console.log(array[i]);//内部方法若有可能相互影响,也要置于闭包之内
    }        
    
    • 利用for时要注意:for循环只能遍历数组,不能遍历对象。

    do{...}while()

        var i = 0,
        len = array.length;
        do {
            if (i == 2) {
            break; // 循环被终止, 此处如果是continue就会造成循环无法退出
        };
        console.log('array['+ i +']:' + array[i]);
        i++;//此句建议放置循环while头部
        }
    
    • do while 的语法比较简化,只保留了对循环条件的判断,所以,一般情况下,为了避免造成死循环,一定要在循环体内部构造出退出本次循环的条件。 而它和for循环一样,只能遍历数组,不能遍历对象。

    forEach()

        array.forEach(function(item){//这里的item 代表数组中的每一项
            if(item=="囚徒")
            return;//这里只能使用return跳过当前元素处理
            consol
        while(i<len);e.log(item);
        }); 
    
    • forEach在循环的时候就更注意了,同样也不能遍历对象,而且还不能用在ie浏览器中(只能在谷歌和火狐中使用)。然而,最重要的一点是,它不能使用break,continue跳出循环。

    for in 和for of在此就不多讲了。直接看上述区别就ok!

  • 有关算法的一道题

    • 让数组实现扁平化你有几种方法

      • 先来实现一种最简单的办法

        let arr = [[1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14]]]], 10];
        let ary=Array.from(new Set(arr.flat(Infinity))).sort((a,b)=>a-b);
        console.log(ary);//=>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
        

        这种方式既简单又便捷,只用一行代码就能实现简单的去数组扁平化,而且还便于理解。

      • 第二种 方法也相当好理解,是利用JSON来处理的

        Array.prototype.flatten = function(){
            let res = JSON.stringify(this);
            let ary = res.replace(/(\[|\])+/g,'') 
            ary =  '[' + ary + ']'
            return JSON.parse(ary)
        }
        let arr = [[1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14]]]], 10];
        console.log(arr.flatten());//=>[1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12, 13, 14, 10]
        

        这种方式相比上一种,有不足之处,他只是简单的把数组中的内部[]去掉了,并没有进行数组的排序处理。

      • 第三种方式基于some方法进行判断检测,验证数数组中的某一项有没有符合函数中提供规则。

        let arr = [[1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14]]]], 10];     
        while (arr.some(item => Array.isArray(item))) {
            //Array.isArray检测某个值是不数是组类型
            arr = [].concat(...arr);//...arr每次这能展开一级
        }//=>[1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12, 13, 14, 10]
        

        同样的这种方法也没有起到排序作用,不过却有效去掉了数组中的[];

        • 小拓展: //=> find 和some 的区别 用法和forEach类似 some返回的是Boolean find返回的是找到符合规则的 返回当前这一项,没有找到符合的返回undefined
  • 谈谈你对闭包的了解

    • 闭包其实就是变量的保护机制,在函数运行的时候开辟一个私有作用域,而且是个不销毁的栈内存。它能保护私有变量不受外界污染,同时还能起到存储值的作用。一般在团队中出现多人开发同一项目时,就会用到闭包,但是闭包还有一个缺点,用多了还会造成内存泄漏。曾经还了解过一点柯里化函数,它也是通过闭包完成的。
  • call 和 apply 之间的区别

    • call和apply都是用来改变this指向的,区别在于传参。

    • call是一个一个的传给函数,而apply是以数组的形式传参。

      fn.call(obj,10,20,30);  第一个参数是改变this指向的,剩下的参数没有上限。
      fn.apply(obj,[10,20,30]);第一个参数也是改变this指向的,而它剩下的参数是要以数组的形式上传。
      
    • call和apply都是Function原型上的方法。每一个函数作为function上的实例,都能调用该方法。

    • 和他们两者一样,同样能改变this指向的还有bind,而bind并没有立即让函数执行,只是预先把函数中的this指向给处理了。

  • 利用实例调取方法,实现链式调用

    • (5).add(3).minus(2) //==> 结果是6怎么实现?

      function (){
          function check(n){
              n=number(n);//先把n做数据类型转换
              return isNaN(n)?0:n;
          }
          function add(n){
              n=check(n);
              return this +n;
          } 
          function minus(n){
              n=check(n);
              return this -n;
          } 
          Number.prototype.add=add;
          Number.prototype.minus=minus;//这样的写法就属于最基本写法,没什么技术含量。
          /*下面这种写法就很厉害了,属于懒人写法,但是很高大上*/
          /*  ['add','minus'].forEach(item=>{
                  Number.prototype[item]=eval(item);
              })*/
      }()
      

接下来还是会有更新的,请大家敬请期待.....