【前端面试篇】JavaScript基础(一)

前言

本文将总结JS的相关知识以及面试常考知识点,不会细致的讲解,遇到重要的知识点我会推荐给大家几篇自认为不错的文章,方便大家更好的理解。

问题1:JavaScript的数据类型有哪些?

基本数据类型:Number、String、boolean、null、undefined

引用数据类型:Object、Array、Function

衍生问题1:怎么判断一个数据是什么类型?

 可以判断数据类型的方式有三种:typeof、instanceof、===,其中typeof不能区分Array与object,null与object,instanceof可以判断对象的具体类型,=== 仅可以判断null与undefined,因为他们的值是唯一的。

衍生问题2:为什么typeof判断null的结果是object?

第一,因为null表示一个空对象指针,它代表的其实就是一个空对象,所以使用typeof操作符检测时返回”object”也是可以理解的。第二,因为JavaScript中的值是由一个表示类型的标签和实际的数值表示的,对象的标签值为0,由于null代表空指针,绝大多数的平台表示为0x00,因为,null的类型标签为0,typeof null因此返回object。ES6时,曾有人提出将typeof null修改为null,但是被拒绝了。

衍生问题3:null与undefined的区别是什么?

当我们声明了一个值,没有初始化时,他的值为undefined。undefined 其实是一个全局变量,window.undefined的值为undefined。

 当初始化时赋值为null,表示将要赋值为一个对象。结束后,赋值为null,表示该对象成为垃圾对象,被垃圾回收器回收。

具体区别可以参考这篇文章:深入理解undefined与null

 问题2:什么是作用域与作用域链

作用域:作用域指的是变量的适用范围,即在程序的执行上下文中变量的可访问性,作用域相对于执行上下文是静态的,在编写代码时就确定了。作用就是隔离变量,不同作用域的同名变量不会有冲突。

作用域链:作用域链决定了哪些数据能被函数访问。当一个函数创建后,它的作用域链会被创建此函数的作用域中可访问的数据对象填充。

给大家推荐几篇文章:

一道js面试题引发的思考

JavaScript深入之词法作用域和动态作用域

问题3:什么是执行上下文?

执行上下文是评估和执行JS代码的环境的抽象概念,JS代码执行的时候都是在执行上下文中运行。JS中执行上下文分为三种:全局执行上下文、函数执行上下文、eval函数执行上下文。执行上下文在创建时会有三个阶段:绑定this、创建词法环境、创建变量环境。

推荐大家看这篇文章更详细的了解执行上下文:理解 JavaScript 中的执行上下文和执行栈

问题4:为什么会有变量提升?

JS引擎在代码执行前会有一个解析过程,创建了执行上下文,初始化了一些代码执行时需要用到的对象。当我们访问一个变量时,我们会到当前执行上下文中的作用域链去查找,而作用域链的首段指向的是当前执行上下文的变量对象,这个变量对象就是执行上下文的一个属性,它包含了函数的形参、所有的函数和变量声明,这个对象是在代码解析的时候创建的,这就是会出现变量提升的根本原因。

问题5:说一说你知道的this

本质上任何函数都是通过对象来调用的,默认就是window,所有函数内部都有 一个变量this,this的值就是调用当前函数的对象。改变this指向的方法有:直接函数调用,默认指向window、对象方法调用,this指向这个对象、函数通过new调用,this指向新创建的对象、call/apply/bind

衍生问题:call、apply、bind的区别

  • call方法的第一个参数是要绑定给thi的值,后面传入的是一个参数列表。当第一个参数为null、undefined时。默认指向window
  • apply接收两个参数,第一个参数是要绑定给this的值,第二个参数是一个参数数组。同call一样,当第一个参数为null、undefined时,默认指向window
  • bind和call很相似,第一个参数是this的指向,从第二个参数开始是接收的参数列表。区别在于bind方法返回值是函数以及bind接收的参数列表的使用,bind的返回值是一个函数。

问题6:什么是原型与原型链?

  • 任何实例对象都有一个__proto__属性,即隐式原型;任何函数都有一个prototype属性,默认指向一个空的Object实例对象,即显示原型,这个实例对象也有__proto__属性,这样就构成了原型链。
  • 实例对象的隐式原型等于其构造函数的显示原型。
  • 访问一个对象的属性时,先在自身的属性中查找,找到返回,如果没有,再沿着__proto__属性向上查找,找到返回,找不到返回undefined。
  • 任何函数都是Function的实例。
  • Object的原型对象是原型链的尽头

为了更好的理解原型与原型链,可以参考下图:

推荐大家阅读这篇文章:深入理解JavaScript原型

问题7:什么是闭包?

  • 当一个嵌套的内部函数引用了外部函数的变量时,就产生了闭包,闭包存在于内部函数中。
  • 闭包产生的条件:外部函数被调用,内部函数引用了外部函数的数据,执行内部函数的定义就会产生闭包;
  • 闭包的作用:使函数内部的变量在函数执行完之后,仍然存活在内存中(延长了局部变量的声明周期)、让函数外部可以访问到函数内部的数据、模块化
  • 闭包在内部函数定义执行时就产生了,在内部函数成为垃圾对象时死亡。
  • 闭包的缺点:函数执行完之后,函数内的局部变量没有释放,占用内存的时间会变长,容易造成内存泄露。

大家可以做一下这道题,看看是否掌握了闭包

  function fun(n, o) {
        console.log(o)
        return {
          fun: function(m) {
            return fun(m, n)
          }
        }
      }
      var a = fun(0);  a.fun(1); a.fun(2); a.fun(3); 
      var b = fun(0).fun(1).fun(2).fun(3); 
      var c = fun(0).fun(1); c.fun(2); c.fun(3); 

推荐大家阅读几篇文章,可以更好的理解闭包:

发现 JavaScript 中闭包的强大威力

JavaScript闭包的底层运行机制

我从来不理解JavaScript闭包,直到有人这样向我解释它...

问题8:什么是防抖和节流?

防抖:当持续触发事件时,一定时间内没有在触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又触发了事件,就重新开始延时。

节流:当持续触发事件时,保证一定时间段内只调用一次时间处理函数。

// 防抖
function debounce(fn, wait) {
    var timeout = null;
    return function() {
        if(timeout !== null) 
                clearTimeout(timeout);
        timeout = setTimeout(fn, wait);
    }
}


// 节流
 var throttle = function(func, delay) {
            var timer = null;
            return function() {
                var context = this;
                var args = arguments;
                if (!timer) {
                    timer = setTimeout(function() {
                        func.apply(context, args);
                        timer = null;
                    }, delay);
                }
            }
        }

衍生问题1:防抖和节流的区别

函数节流不管事件触发的多频繁,都会保证在规定的时间内一定会执行一次事件处理函数,而函数防抖只是在最后一次事件后才触发一次。比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。

问题9:普通函数和箭头函数的区别

  • 箭头函数没有this、argument的绑定
  • 不能使用new操作符,没有construct属性
  • this的指向不能修改
  • 不支持arguments对象
  • 没有原型

问题10:数组的方法有哪些?

不修改原数组:

  • concat:连续两个或多个数组,返回新的拼接后的新数组
  • join:把数组转成字符串,按规定字符连接
  • toString:将数组转为字符串
  • slice:返回数组中指定区间的元素,包左不包右
  • indexOf:返回选项在数组中第一次出现的位置
  • lastIndexOf:返回选项在数组中最后一次出现的索引
  • reduce:遍历迭代,返回计算后的值
  • some:判断数组中是否有一项满足条件,满足返回true
  • every:判断数组中的每一项是否满足

修改原数组

  • push:向数组的末尾添加一个元素,返回数组新的长度
  • shift:删除数组中的第一个元素,并返回删除的值
  • unshift:向数组的开头添加一个元素,返回数组新的长度
  • pop:删除并返回数组的最后一个元素
  • splice:删除或添加数组
  • reverse:反转数组
  • sort:数组排序

问题11:JS的事件循环模型

JS是单线程的,JS引擎先执行初始化代码,将事件回调函数交给对应的模块管理,当事件发生时,模块管理会将回调代码及其数据放到回调队列,只有当初始化代码全部完成之后,才会遍历读取回调队列中的回调函数执行。任务队列分为宏任务队列和微任务队列,进入整体代码之后,开始第一次循环,接着执行所有的微任务,然后再次从宏任务开始,找到其中第一个宏任务执行完毕,在执行所有的微任务。

阅读这篇文章可以深刻的理解事件循环模型:这一次,彻底弄懂 JavaScript 执行机制

问题12:in和hasOwnProperty的区别

in操作符:检查指定对象原型链上是否有对应的属性值

hasOwnProperty:检测指定对象自身上是否有对应的属性值

二者的区别在于in会查找原型链,而hasOwnProperty不会。

问题13:详细说一说Promise对象

  • 什么是promise:promise是一个对象,从它可以获取异步操作的信息,promise提供统一的API,各种异步操作都可以用相同的方式进行处理。
  • promise有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败),当promise对象的状态改变之后,就不会再改变,任何使用都可以得到这个结果。
  • promise构造函数接收一个函数作为参数,这个函数两个参数分别为:resolve、reject。resolve函数的作用是将promise对象的状态从pending变为fulfilled,在异步操作成功之后调用,并将异步结果作为参数传递出去。reject函数与resolve函数作用相似,只是将promise状态从pending变为rejected。
  • 可以调用promise实例的then方法,来指定resolve和rejected的回调函数
  • all函数:谁跑的慢,以谁为准执行回调。all接收一个数组参数,里面的值最终都算返回promise对象
  • race函数:谁跑的快,以谁为执行回调。

我们可以利用race函数,给某个异步操作设置超时时间,并且在超时后执行相应的操作,代码如下:

//请求某个图片资源
    function requestImg(){
        var p = new Promise((resolve, reject) => {
            var img = new Image();
            img.onload = function(){
                resolve(img);
            }
            img.src = '图片的路径';
        });
        return p;
    }
    //延时函数,用于给请求计时
    function timeout(){
        var p = new Promise((resolve, reject) => {
            setTimeout(() => {
                reject('图片请求超时');
            }, 5000);
        });
        return p;
    }
    Promise.race([requestImg(), timeout()]).then((data) =>{
        console.log(data);
    }).catch((err) => {
        console.log(err);
    });

requestImg函数会异步请求一张图片,我把地址写为"图片的路径",所以肯定是无法成功请求到的。timeout函数是一个延时5秒的异步操作。我们把这两个返回Promise对象的函数放进race,于是他俩就会赛跑,如果5秒之内图片请求成功了,那么遍进入then方法,执行正常的流程。如果5秒钟图片还未成功返回,那么timeout就跑赢了,则进入catch,报出“图片请求超时”的信息。

推荐大家阅读阮一峰老师的文章:Promise 对象 ---- 阮一峰

问题14:函数式编程的特点

  • 函数是一等公民:函数与其他数据类型一样,可以作为参数传递
  • 惰性执行:只在调用的时候执行,不产生无用的中间变量
  • 无状态和数据不可变
  • 没有副作用
  • 纯函数

问题15:JavaScript代码中的use strict 是什么意思?

use strict是一种ES5添加的严格运行模式,这种模式使得JavaScript在更严格的模式下运行。

设立严格模式的目的,主要有以下几个:

  • 消除JavaScript语法的一些不合理,不严谨之处,减少一些怪异行为。
  • 消除代码运行的一些不安全之处,保证代码的运行安全
  • 提高编译器效率,增加运行速度
  • 为未来新版本的JavaScript做铺垫

最后

以上只是部分JavaScript相关问题,后序还会继续总结,大家加油!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值