前端面试题集锦(5)

目录

1、Promsie.all() 使用过吗, 它是怎么使用的 ?

2、for in 和 for of 循环的区别 ?

3、 什么是事件流以及事件流的传播机制 ?

4、token 一般存放在哪里 ? 为什么不存放在 cookie 内 ?

5、 数组方法 forEach 和 map 的区别 ?

6、 ES6 中 Set 和 Map 的区别 ?

7、 0.1 + 0.2 为什么不等于 0.3, 在项目中遇到要怎么处理 ?

8、 什么是模块化思想 ?

9、 说说怎么用js 写无缝轮播图

10、 闭包的使用场景 ?

10.1 防抖:

10.2 节流:

10.3 迭代器:

10.4 缓存:

10.5 getter和setter:

10.6 函数的柯里化:

10.7 循环中绑定事件或执行异步代码:

10.8 单例模式:


1、Promsie.all() 使用过吗, 它是怎么使用的 ?

🌻  promise.all()用于一个异步操作需要在几个异步操作完成后再进行时使用。
🌻  promise.all()接受一个 promise 对象组成的数组参数,返回 promise 对象。
🌻  当数组中所有promise 都完成了,就执行当前 promise 对象的 then 方法,如果数组中有一个 promise 执行失败了,就执行当前promise 对象的 catch 方法。

2for in for of 循环的区别 ?

`for in` 用于遍历对象的键 ( `key` ) `for in` 会遍历所有自身的和原型链上的可枚举属性。如果是数组,for in 会将数组的索引 (index) 当做对象的 key 来遍历,其他的 object 也是一样的。
`for of` `es6` 引入的语法,用于遍历 所有迭代器 iterator ,其中包括
`HTMLCollection` , `NodeList` , `Array` `Map` `Set` `String` `TypedArray` `arguments`
对象的值 ( `item` )

3、 什么是事件流以及事件流的传播机制 ?

事件触发后,从开始找目标元素,然后执行目标元素的事件,再到离开目标元素的整个过程称之为事件流。
W3C 标准浏览器事件流的传播分为 3 个阶段:捕获阶段、目标阶段、冒泡阶段
        🌻  捕获阶段指找目标元素的过程,这个找的过程,是从最大的document 对象到 html ,再到body,......直到目标元素。
        🌻  找到目标元素后,调用执行他绑定事件时对应的处理函数,这个过程被称之为目标阶段。
        🌻  当目标元素的事件执行结束后,再从目标元素,到他的父元素。。。body html 再到 document 的过程,是冒泡阶段。

4、token 一般存放在哪里 ? 为什么不存放在 cookie ?

🌻  token一般放在本地存储中。 token 的存在本身只关心请求的安全性,而不关心 token 本身的安全,因为 token 是服务器端生成的,可以理解为一种加密技术。但如果存在cookie 内的话,浏览器的请求默认会自动在请求头中携带cookie,所以容易受到 csrf 攻击。

5、 数组方法 forEach map 的区别 ?

🌻  forEach和 map 都是循环遍历数组中的每一项。 forEach() map() 里面每一次执行匿名函数都支持 3 个参数:数组中的当前项item, 当前项的索引 index, 原始数组 input 。匿名函数中的 this 都是指 Window 。只能遍历数组。
🌻  他们的区别是:forEach 没有返回值,但 map 中要有返回值,返回处理后的所有新元素组成的数组。

6ES6 Set Map 的区别 ?

🌻  Set 是无重复值的有序列表。根据 `Object.is()` 方法来判断其中的值不相等,以保证无重复。 Set 会自动移除重复的值,因此你可以使用它来过滤数组中的重复值并返回结果。 Set 并不是数组的子类型,所以你无法随机访问其中的值。但你可以使用`has()` 方法来判断某个值是否存在于 Set 中,或通过 `size` 属性来查看其中有多少个值。 Set 类型还拥有 `forEach()` 方法,用于处理每个值
🌻  Map 是有序的键值对,其中的键允许是任何类型。与 Set 相似,通过调用 `Object.is()` 方法来判断重复的键,这意味着能将数值 5 与字符串 "5" 作为两个相对独立的键。使用 `set()` 方法能将任何类型的值关联到某个键上,并且该值此后能用 `get()` 方法提取出来。 Map 也拥有一个 `size` 属性与一个 `forEach()` 方法,让项目访问更容易

70.1 + 0.2 为什么不等于 0.3, 在项目中遇到要怎么处理 ?

🌻  计算机内部存储数据使用2 进制存储,两个数字进行的数学运算,首先是将这两个数字以 2 进制形式,存储在计算机内部,然后在计算机内部使用两个2 进制数字进行计算,最后将计算结果的 2 进制数字转为 10 进制展示出来。
🌻  由于10 进制的小数在转 2 进制的时候,规则是小数部分乘以 2 ,判断是否得到一个整数,如果得到整数,转换完成;如果没有得到整数,则继续乘以2 判断。所以, 0.1 0.2 在转换 2 进制的时候,其实是一个无限死循环,也就是一直乘以2没有得到整数的时候,但计算机内部对于无线死循环的数据,会根据一个标准保留 52 位。也就是说,计算机内部在存储0.1 0.2 的时候,本来就不精准,两个不精准的小数在计算后,距离精准的结果是有一定误差的。
🌻  项目中碰到这种情况,有3 种处理方法:

🍀 将小数乘以10的倍数,转为整数,然后计算,计算完成后,再缩小10的倍数,例如:

var result = ((0.1 * 10) + (0.2 * 10)) / 10
// result === 0.3
🍀  使用数字的toFixed 方法,强制保留小数点后多少位,例:
var result = (0.1 + 0.2).toFixed(2)
// result === 0.30
🍀  自定义数字运算方法,当需要进行数学运算的时候,不直接进行,调用自定义的方法进行,例: (加法封装)
function add(...args){
       var num = args.find(item => {
           if(item != 0 && !item){
              throw new Error("数学运算要使用数字")
           }
       })
       var arr = args.map(item => {
           var index = (item+'').indexOf('.')
           if(index >= 0){
                return (item+'').split('.')[1].length
           }
       })
       arr = arr.filter(item => item)
       if(arr.length){
          var max = Math.max(...arr)
          var data = args.map(item => item * Math.pow(10, max))
          var data.reduce((a, b) => a + b) / Math.pow(10, max)
       }else{
          var data = args
          return data.reduce((a, b) => a + b)
       }
}

// 调用使用:
var num1 = add(0.1, 0.2)
console.log(num1); // 0.3

var num2 = add(1, 2)
console.log(num2); // 3

var num3 = add(1, 2.1)
console.log(num3); // 3.1

8、 什么是模块化思想 ?

🌻  就是JS 中将不同功能的代码封装在不同的文件中 , 再互相引用时不会发生命名冲突的一种思想 , 大多数情况下 , 一个文件就是一个模块
🌻  模块化的实现,有多种方案:

🍀 CommonJS:

CommonJS nodejs 中使用的模块化规范

nodejs 应用中每个文件就是一个模块,拥有自己的作用域,文件中的变量、函数都是私有的,与其他文件相隔离。模块导出: module.exports=数据 ,模块导入: require('模块文件路径')

🍀 ES6的模块化:

模块功能主要由两个命令构成: export import export 命令用于规定模块的对外接口, import 命令用于输入其他模块提供的功能。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取
模块内部的某个变量,就必须使用 export 关键字输出该变量。下面是一个 JS 文件,里面使用 export 命令输出变量。

🍀 AMD (Asynchronous Module Definition):

特点 : 提倡依赖前置,在定义模块的时候就要声明其依赖的模块:导入模块
require([module],callback) ; 定义模块: define(' 模块名称 ', 函数 )

🍀 CMD (Common Module Definition):

CMD 规范是国内 SeaJS 的推广过程中产生的。提倡就近依赖(按需加载),在用到某个模块的时候
再去 require 。定义模块: define(function (require, exports, module) {}) ,使用模块: seajs.use()

9、 说说怎么用js 写无缝轮播图

🌻  将所有需要轮播的内容动态复制一份,放在原本的容器中,加定时器让整个容器中的内容滚动轮播,当内容轮播到left值为原本的内容宽度时,快速将内容切换到 left 值为 0 的状态。

10、 闭包的使用场景 ?

🌻  一个函数被当作值返回时,也就相当于返回了一个通道,这个通道可以访问这个函数词法作用域中的变量,即函数所需要的数据结构保存了下来,数据结构中的值在外层函数执行时创建,外层函数执行完毕时理因销毁,但由于内部函数作为值返回出去,这些值得以保存下来。而且无法直接访问,必须通过返回的函数。这也就是私有性。
🌻  本来执行过程和词法作用域是封闭的,这种返回的函数就好比是一个虫洞,开了挂。
🌻  闭包的形成很简单,在执行过程完毕后,返回函数,或者将函数得以保留下来,即形成闭包。

10.1 防抖:

function debounce(fn, interval) {
    let timer = null; // 定时器
    return function() {
        // 清除上一次的定时器
        clearTimeout(timer);
        // 拿到当前的函数作用域
        let _this = this;
        // 拿到当前函数的参数数组
        let args = Array.prototype.slice.call(arguments, 0);
        // 开启倒计时定时器
        timer = setTimeout(function() {
           // 通过apply传递当前函数this,以及参数
           fn.apply(_this, args);
           // 默认300ms执行
        }, interval || 300)
    }
}

10.2 节流:

function throttle(fn, interval) {
    let timer = null; // 定时器
    let firstTime = true; // 判断是否是第一次执行
    // 利用闭包
    return function() {
       // 拿到函数的参数数组
       let args = Array.prototype.slice.call(arguments, 0);
       // 拿到当前的函数作用域
       let _this = this;
       // 如果是第一次执行的话,需要立即执行该函数
       if(firstTime) {
          // 通过apply,绑定当前函数的作用域以及传递参数
          fn.apply(_this, args);
          // 修改标识为null,释放内存
          firstTime = null;
       }
       // 如果当前有正在等待执行的函数则直接返回
       if(timer) return;
       // 开启一个倒计时定时器
       timer = setTimeout(function() {
          // 通过apply,绑定当前函数的作用域以及传递参数
          fn.apply(_this, args);
          // 清除之前的定时器
          timer = null;
          // 默认300ms执行一次
       }, interval || 300)
   }
}

10.3 迭代器:

var arr =['aa','bb','cc'];
function incre(arr){
     var i=0;
     return function(){
        //这个函数每次被执行都返回数组arr中 i下标对应的元素
        return arr[i++] || '数组值已经遍历完';
     }
}
var next = incre(arr);
console.log(next());//aa
console.log(next());//bb
console.log(next());//cc
console.log(next());//数组值已经遍历完

10.4 缓存:

var fn=(function(){
        var cache={};//缓存对象
        var calc=function(arr){//计算函数
            var sum=0;
            //求和
            for(var i=0;i<arr.length;i++){
                sum+=arr[i];
            }
            return sum;
       }

       return function(){
          var args = Array.prototype.slice.call(arguments,0);//arguments转换成数组
          var key=args.join(",");//将args用逗号连接成字符串
          var result , tSum = cache[key];
          if(tSum){//如果缓存有
              console.log('从缓存中取:',cache)//打印方便查看
              result = tSum;
          }else{
             //重新计算,并存入缓存同时赋值给result
             result = cache[key]=calc(args);
             console.log('存入缓存:',cache)//打印方便查看
          }
          return result;
      }
 })();
fn(1,2,3,4,5);
fn(1,2,3,4,5);
fn(1,2,3,4,5,6);
fn(1,2,3,4,5,8);
fn(1,2,3,4,5,6);

10.5 gettersetter

function fn(){
       var name='hello'
       setName=function(n){
          name = n;
       }
       getName=function(){
           return name;
       }

       //将setName,getName作为对象的属性返回
       return {
           setName:setName,
           getName:getName
       }
}
var fn1 = fn();//返回对象,属性setName和getName是两个函数
console.log(fn1.getName());//getter
fn1.setName('world');//setter修改闭包里面的name
console.log(fn1.getName());//getter

10.6 函数的柯里化:

function curryingCheck(reg) {
     return function(txt) {
        return reg.test(txt)
     }
}

var hasNumber = curryingCheck(/\d+/g)
var hasLetter = curryingCheck(/[a-z]+/g)

hasNumber('test1') // true
hasNumber('testtest') // false
hasLetter('21212') // false

10.7 循环中绑定事件或执行异步代码:

var p1 = "ss";
var p2 = "jj";
function testSetTime(para1,para2){
    return (function(){
         console.log(para1 + "-" + para2);
    })
}
var test = testSetTime(p1, p2);
setTimeout(test, 1000);
setTimeout(function(){
      console.log(p1 + "-" + p2)
},1000)

10.8 单例模式:

var Singleton = (function () {
    var instance;

    function createInstance() {
         return new Object("I am the instance");
    }

    return {
        getInstance: function () {
            if (!instance) {
                instance = createInstance();
            }
            return instance;
        }
    };
})();

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

兰de宝贝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值