前端js面试技巧(1)——js基础部分

前言

先从几道面试题说起

      面试题1、JS中使用typeof能得到的哪些类型?**考点:JS变量类型**
      面试题2、何时使用===何时使用==?**考点:强制类型转换**
      面试题3、window.onload和DOMContentLoaded的区别?**考点:浏览器的渲染过**程
      面试题4、用JS创建10个`<a>`标签,点击的时候弹出来对应的序号?考点:**作用域**
      面试题5、简述如何实现一个模块加载器,实现类似require.js的基本功能?**考点:JS模块化**
      面试题6、实现数据的随机排序?**考点:JS基础算法**

思考

     1、拿到一个面试题,你第一时间看到的是什么?->**考点**
     2、又如何看待网上搜出来的永远也看不完的题海->**不变应万变**
     3、如何对待接下来遇到的面试题?->**题目到知识再到题目**

js基础部分

 1、原型 原型链
 2、作用域 闭包
 3、异步 单线程

-

变量类型和计算

 *变量类型*
    1、值类型vs引用类型
        var a=100;
        var b=a;
        a=200;
        console.log(b) //100

        var a={age:20};
        var b=a;
        b.age=21;
        console.log(a.age) //21

        引用类型包括:数组,函数,对象
        引用类型是为了共用空间,才会出现用地址指向同一量
   2typeof运算符详解
        typeof undefined;//undefined
        typeof 'abc';//string
        typeof 123;//number
        typeof true;//boolean
        typeof {};//object
        typeof [];//object
        typeof null;//object
        typeof console.log//function

        typeof只能区分值类型的详细类型,对引用类型无能为力,但可以区分出函数来


  *变量计算*
    1、强制类型转换(值类型的计算)
       ①字符串拼接
       ②==运算符
       ③if语句
       ④逻辑运算
       上面四种操作可能导致强制类型转换
       var a=100+10;//110
       var b=100+'10'//'10010'

       100=='100'//true
       0==''//true
       null==undefined//true

       var a=true;
       if(a){
          //...
       }
       var b=100;
       if(b){
          //...
       }
       var c='';
       if(c){
          //...
       } 

       console.log(10&&0)//0
       console.log(''||'abc')//abc
       console.log(!window.abc)//true
       //判断一个变量会被当做true还是false
       var a=100;
       console.log(!!a)//true



***解答***
----

     面试题1、JS中使用typeof能得到的哪些类型?
            typeof undefined;//undefined
            typeof 'abc';//string
            typeof 123;//number
            typeof true;//boolean
            typeof {};//object
            typeof [];//object
            typeof null;//object
            typeof console.log//function

            typeof只能区分值类型的详细类型,对引用类型无能为力,但可以区分出函数来
     面试题2、何时使用===何时使用==?
            if(obj.a==null){
                //这里相当于obj.a===null||obj.a===undefined,简写形式
                //这是jquery源码中推荐的方法,其他的都用===
            }
     面试题3、JS中有哪些*内置函数*--数据封装类对象?
          //JS作为单纯语言的内置函数
            Object
            Array
            Boolean
            Number
            String
            Function
            Date
            RegExp
            Error
            //Global浏览器内置对象
            //Math是对象,不是函数
     面试题4、JS变量按照存储方式区分为哪些类型,并描述其特点
            //分为值类型和引用类型
            //值类型
            var a=10
            var b=a
            a=11
            console.log(b)//10

            //引用类型
            var obj1={x:100}
            var obj2=obj1
            obj1.x=200
            console.log(obj2.x)//200
            值类型直接存储的是值
            引用类型存储的是指向值的指针,这样做是为了节省内存
            值类型的值赋值后不会相互干预
            引用类型的赋值是变量指针的赋值,不是真的值的拷贝,他们的赋值是相互干预的。
     面试题5、如何理解JSON?
            //JSON只不过是一个JS对像而已,和MATH一样
            JSON.stringfy({a:10,b:20})
            JSON.parse('{"a":10,"b":20}')
            //注意:JS中为false的为 0 NaN null undefined '' false

- 原型和原型链

这里写图片描述

  *构造函数*
     function Foo(name,age){
        this.name=name;
        this.age=age;
        this.class="class-1";
        //return this;//默认有这一行
     }
     var f=new Foo('zhangsan',20)
     var f1=new Foo('lisi',22)//创建多个对象
     //new对象时函数中的this初始化为空对象,参数赋值完后返回this给f和f1
  *构造函数--扩展*
     var a={}其实是var a=new Object()的语法糖
     var a=[]其实是var a=new Array()的语法糖
     function Foo(){...}其实是var Foo=new Function(...)
     //使用instanceof判断一个函数是否是一个变量的构造函数
     //对象,数组,函数的构造函数其实是Object,Array,Function
     //判断一个变量是否是'数组'  变量 instanceof Array        
  *原型规则和示例*
     5条原型规则
     //原型规则是学习原型链的基础
         ①所有的引用类型(数组,对象,函数),都具有对像特性,即可自由扩展属性(除了null)
         ②所有的引用类型(数组,对象,函数),都有一个__proto__(隐式原型)属性,属性值也是一个普通对象
         ③**所有的函数**,都有一个prototype(显式原型)属性,属性值也是一个普通对象
         ④所有的引用类型(数组,对象,函数),__proto__属性值指向它的构造函数的“prototype”属性值
         ⑤当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找

         var obj={};obj.a=100;
         var arr=[];arr.a=100;
         function fn(){}
         fn.a=100;

         console.log(obj.__proto__);
         console.log(arr.__proto__);
         console.log(fn.__proto__);

         console.log(fn.prototype)

         console.log(obj.__proto__===Object.prototype)


        function Foo(name,age){
            this.name=name;
        }             
        Foo.prototype.alertName=function(){
             alert(this.name)
        }
        var f=new Foo('zhangsan');
        f.printName=function(){
            console.log(this.name);
        }
        f.printName();
        f.alertName();

        //循环对象自身的属性
        var item;
        for(item in f){
          //高级浏览器已经在for in中屏蔽了来自原型的属性
          //但是这里建议大家还是加上这个判断,保证程序的健壮性
          if(f.hasOwnProperty(item))
              console.log(item);
        }

  *原型链*
     f.toString()//要去f.__proto__.__proto__中去找
  *instanseof*
     **注意:** //用于判断引用类型属于哪个构造函数的方法
      f instanceof Foo的判断逻辑是:
         f的__proto__一层一层向上找,能否对应到Foo.prototype
      f instanceof Object也是正确的

  *解答*
    面试题1、如何准确判断一个变量时数组类型?
           var arr=[]
           arr instanceof Array //true
           typeof arr//object,typeof是无法判断是否是数组的
    面试题2、写一个原型链继承的例子
       ①function Animal(){
          this.eat=function(){
             console.log('animal eat');
          }
       }
       function Dog(){
          this.bark=function(){
             console.log('dog bark')
          }
       }
       Dog.prototype=new Animal();
       var hashiqi=new Dog()

       ②function Elem(id){
           this.elem=document.getElementById(id);
       }
       Elem.prototype.html=function(val){
          var elem=this.elem;
          if(val){
              elem.innerHTML=val;
              return this;//链式操作
          }else{
             return elem.innerHTML;
          }
       }
      Elem.prototype.on=function(type,fn){
         var elem=this.elem;
         elem.addEventListener(type,fn);
         return this;
      }
      var elem=new Elem("div1");
      elem.html("<p>hello world</p>").on("click",function(){alert("clicked")}).html("<p>javascript</p>");
    面试题3、描述new一个对象的过程
       ①创建一个新对象
       ②this指向这个新对象
       ③执行代码,即对this赋值
       ④返回this
    面试题4、zepto(或其他框架)源码中如何使用原型链
       ①阅读源码是高效提高技能的方式
       ②但不能“埋头苦钻”有技巧在其中
       ③慕课网搜索“zepto设计和源码分析”

- 执行上下文

    console.log(a);//undefined
    var a=100

    fn('zhangsan') //'zhangsan' 20
    function fn(name){
       age=20;
       console.log(name,age);
       var age;
    }
    范围:一段<script>或者一个函数之内都会生成一个上下文
    全局:变量定义,函数声明   //执行之前,一段<script>会生成全局上下文
    函数:变量定义,函数声明,thisarguments //函数执行之前会生成函数上下文

    注意:‘函数声明’和‘函数表达式’的区别

-

this

    this要在执行时才能确认值,定义时无法确认

    var a={
       name:"A",
       fn:function(){
           console.log(this.name)
       }
    }
    a.fn()  //this===a
    a.fn.call({name:B}) //this==={name:'B'}
    var fn1=a.fn;
    fn1() //this===window

    使用场景
    ①作为构造函数执行
       function Foo(name){
          //this={};
          this.name=name;
          //return this
       }
       var f=new Foo('zhangsan')
    ②作为对象属性执行
        var obj={
            name:'A',
            printName:function(){
                console.log(this.name)
            }
        }
        obj.printName();
    ③作为普通函数执行
       function fn(){
          console.log(this)  //this===window
       }
       fn()
    ④call apply bind
       function fn1(name,age){
          alert(name);
          console.log(this)  //this===window
       }
       fn1.call({x:100},'zhangsan',20)
       fn1.apply({x:100},['zhangsan',20])
       var fn2=function(name,age){
          alert(name);
          console.log(this)  //this==={x:100}
       }.bind({x:100})//bind只能用函数表达式,函数声明不可用,会报错
       fn2('zhangsan',200)

- 作用域

       ①没有块级作用域
            if(true){
                var name='zhangsan'
            }
            console.log(name)//'zhangsan'
       ②只有全局和函数作用域
            var a=100;
            function fn(){
                var a=200;
                console.log('fn',a)
            }
            console.log('global',a)
            fn()

-

作用域链

       var a=100
       function fn(){
               var b=200
               //当前作用域没有定义的变量,即'自由变量'
               console.log(a)

               console.log(b)
       }
       fn()


       var a=100;
       function F1(){
          var b=200;
          function F2(){
              var c=300;
              console.log(a);//a是自由变量
              console.log(b);//b是自由变量
              console.log(c);
          }
          F2()
       }
       F1();
       注意:函数的父级作用域是函数定义时候的作用域,不是函数执行时候的作用域,也就是说那个作用域定义了这个函数,这个函数的父级作用域就是谁,跟函数执行没有关系,函数自由变量要到父级作用域中找,就形成了作用域链

-

闭包

     function F1(){
          var a=100;
          //返回一个函数(函数作为返回值)
          return function(){
              console.log(a);//自由变量,父作用域寻找
          }
     }
     //f1得到一个函数
     var f1=F1();
     var a=200;
     f1();//100


     闭包使用场景
     ①函数作为返回值
     ②函数作为参数传递(函数自由变量要到父级作用域中找)
       function F1(){
          var a=100;
          return  function(){
              console.log(a);
          }
       }
       var f1=F1();
       function F2(fn){
           var a=200
           fn();(自由变量要到声明定义时的父作用域中找,和执行的作用域没有关系)
       }
       F2(f1);//100

-

解题

      问题1、说一下对变量提升的理解
            ①变量的定义
            ②函数的声明(注意和函数表达式的区别)
      问题2、说明this几种不同的使用场景
             参考上文**this**
      问题3、创建10个`<a>`标签,点击的时候弹出来对应的序号
            var i;
            for(i=0;i<10;i++){
            (function(i){
               var a=document.createElement('a');
               a.innerHTML=i+'<br>';
               a.addEventListener('click',function(e){
               e.preventDefault();
               alert(i);
              })
              document.body.appendChild(a);
              })(i);//相当于创建了10个函数
            }

      问题4、如何理解作用域
         ①自由变量
         ②作用域链,即自由变量的查找
         ③闭包的两个场景
      问题5、实际开发中闭包的应用
      //闭包实际应用中主要用于封装变量,收敛权限
      function isFirstLoad(){
             var _list=[];
              return function(id){
                 if(_list.indexOf(id)>=0){
                     return false;
                 }else{
                    _list.push(id);
                    return true;
                 }
              }
      }
      //使用
      var firstLoad=isFirstLoad();
      firstLoad(10);
      firstLoad(10);
      firstLoad(20);
    //你在 isFirstLoad 函数外面,根本不可能修改掉_list的值

- 什么是异步

console.log(100)
setTimeout(function(){
console.log(200)
},1000)
console.log(300) //100 300 200

console.log(100)
alert(200);
console.log(300)  //100 200 300

何时需要异步
①在可能发生等待的情况下
②等待过程中不能像alert一样阻塞程序运行
③因此,所以的”等待的情况”都需要异步

前端使用异步的场景
①定时任务:setTimeout,setInterval
②网络请求:ajax请求,动态加载
③事件绑定

console.log('start');
$.get('./data1.json',function(data1){
       console.log(data1);
})
console.log('end')//'start'  'end'   data1



console.log(start);
var img=document.createElement('img')
img.onload=function(){
        console.log('loaded')
}//图片加载完执行
img.src='/xx.png';
console.log('end');//start end loaded


console.log('start')
document.getElementById('btn1').addEventListener('click',function(){
       alert('clicked');
})//点击时才会执行
console.log('end');//start clicked end

- 异步和单线程

JS是单线程的,所以是异步

console.log(100)
setTimeout(function(){
console.log(200)
})
console.log(300) //100 300 200
这里写图片描述

- 解答

问题1、同步和异步的区别是什么?分别举一个同步和异步的例子
①同步会阻塞代码执行,而异步不会
②alert是同步,setTimeout是异步

问题2、一个关于setTimeout的笔试题
console.log(1)
setTimeout(function(){
console.log(2)
},0)
console.log(3)
setTimeout(function(){
console.log(4)
},1000)
console.log(5)
//1 3 5 2 4

问题3、前端使用异步的场景有哪些
①定时任务:setTimeout,setInterval
②网络请求:ajax请求,动态加载
③事件绑定

-

其他知识

①日期 
Date.now()  //获取当前时间毫秒数 
var dt=new Date() 
dt.getTime()   //获取毫秒数 
dt.getFullYear()   //年
 dt.getMonth()  //月
(0-31) dt.getHours()   //小时(0-23) 
dt.getMinutes() //分钟(0-59) 
dt.getSeconds() //(0-59)Math 
Math.random()

③数组API
forEach  遍历所有元素
  var arr=[1,2,3]
     arr.forEach(function(item,index){
     //遍历数组的所有元素
     console.log(index,item)
  })

 every  判断所有元素是否都符合条件
   var arr=[1,2,3]
   var result=arr.every(function(item,index){
      //用来判断所有的数组元素,都满足一个条件
        if(item<4){
           return true;
        }
    })
   console.log(result);

some  判断是否至少一个元素符合条件
    var arr=[1,2,3]
    var result=arr.some(function(item,index){
      //用来判断所有的数组元素,只要有一个满足条件即可
        if(item<2){
            return true;
       }
    })
    console.log(result);

sort  排序
   var arr=[1,4,2,3,5]
   var arr2=arr.sort(function(a,b){
         //从小到大排序
         return a-b
         //从大到小排序
         //return b-a
   })
   console.log(arr2)

map  对元素重新组装,生成新数组
   var arr=[1,2,3,4]
   var arr2=arr.map(function(item,index){
        //将元素重新组装,并返回
        return '<b>'+item+'</b>'
   })
   console.log(arr2)
filter过滤符合条件的元素
   var arr=[1,2,3]
   var arr2=arr.filter(function(item,index){
       //通过某一个条件过滤数组
       if(item>=2){
          return true;
       }
   })
   console.log(arr2)
④对象API
   var obj={
      x:100,
      y:200,
      z:300
   }
   var key
   for(key in obj){
      //注意这里的hasOwnProperty,再讲原型链时讲过了
      if(obj.hasOwnProperty(key)){
             console.log(key,obj[key])
      }

    }

- 解答

问题1、获取2017-06-10格式的日期 
     function formatDate(dt){
          if(!dt){
              dt=new Date()
          }
          var year=dt.getFullYear();
          var month=dt.getMonth()+1;
          var date=dt.getDate();
          if(month<10){
             //强制类型转换
             month="0"+month;
          }
          if(date<10){
              //强制类型转换
              date="0"+month;
          }
          return year+"-"+month+"-"+date
     }
     var dt=new Date()
     var formatDate=formatDate(dt)
     console.log(formatDate)
问题2、获取随机数,要求是长度一直的字符串格式 
      var random=Math.random()
      var random=random+'0000000000'   //后面加上10个零
      var random=random.slice(0,10)
      console.log(random)
问题3、写一个能遍历对象和数组的通用forEach函数
       function forEach(obj,fn){
           var key
           //准确判断是不是数据
           if(obj instanceof Array){
                  obj.forEach(function(item,inex){
                         fn(index,item)
                 })
           }else{
                //不是数组就是对象
                for(key in obj){
                     fn(key,obj[key])
                }
           }
       }

       var arr=[1,2,3];
       //注意,这里参数的顺序换了,为了和对象的遍历格式一致
       forEach(arr,function(index,item){
             console.log(index,item)
       })

       var obj={x:100,y:200};
       forEach(obj,function(key,value){
             console.log(key,value)
       })

js-web-api部分

 1、dom操作
 2、Ajax
 3、事件绑定

回顾JS基础知识

①变量类型和计算
②原型和原型链
③闭包和作用域
④异步和单线程
⑤其他(如日期、Math、各种常用API)

特点:表面看来并不能用于工作中开发代码
内置函数:Object Array Boolean String…
内置对象:Math JSON

js开发环境部分

  1、版本管理
  2、模块化
  3、打包工具

运行环境部分

   1、页面渲染
   2、性能优化

面试技巧

阅读更多
博主设置当前文章不允许评论。

博主推荐

换一批

没有更多推荐了,返回首页