八股文(五)

目录

一、 说一说cookie sessionStorage localStorage 区别

二、 说一说JS数据类型有哪些,区别是什么

三、 说一说你对闭包的理解

四、 说一说promise是什么与使用方法

1.什么是Promise

2.Promise的使用

五、 说一说跨域是什么?如何解决跨域问题?

六、 说一说BFC

七、 说一说JavaScript有几种方法判断变量的类型?

八、实现异步的方法

九、 说一说数组去重都有哪些方法

1.两层for语句遍历判断加上splice

2.通过数组API indexOf()进行筛选

3.通过数组API includes()进行筛选

4. 通过Set对象进行过滤

十、说一下浮动

1.为什么要清除浮动

2.清除浮动

(1)给父级盒子添加高度

(2)给父级添加 overflow 属性

(3)给父级添加after伪元素

一、 说一说cookie sessionStorage localStorage 区别

  • Cookie、SessionStorage、 LocalStorage都是浏览器的本地存储

  • cookie是由服务器端写入的,而SessionStorage、 LocalStorage都是由前端写入的

  • cookie的生命周期是由服务器端在写入的时候就设置好的,LocalStorage是写入就一直存在,除非手动清除,SessionStorage是页面关闭的时候就会自动清除

  • cookie的存储空间比较小大概4KB,SessionStorage、 LocalStorage存储空间比较大,大概5M

  • Cookie、SessionStorage、 LocalStorage数据共享都遵循同源原则,SessionStorage还限制必须是同一个页面

  • 在前端给后端发送请求的时候会自动携带Cookie中的数据,但是SessionStorage、 LocalStorage不会

使用场景:

  • cookie:判断用户是否登陆过网站,以便下次登录时能够实现自动登录(或者记住密码)。如果我们删除cookie,则每次登录必须从新填写登录的相关信息。

  • LocalStorage:常用于存储不易变动的数据,减轻服务器的压力

  • SessionStorage:可以用来检测用户是否是刷新进入页面 或者记录网上商城中的购物车

二、 说一说JS数据类型有哪些,区别是什么

  • Number、String、Boolean、BigInt、Symbol、Null、Undefined、Object、8种

  • JS数据类型分为两类:一类是基本数据类型,也叫简单数据类型,包含7种类型,分别是Number 、String、Boolean、BigInt、Symbol、Null、Undefined。另一类是引用数据类型也叫复杂数据类型,通常用Object代表,普通对象,数组,正则,日期,Math数学函数都属于Object。

  • 数据分成两大类的本质区别:基本数据类型和引用数据类型它们在内存中的存储方式不同。基本数据类型是直接存储在栈中的简单数据段,占据空间小,属于被频繁使用的数据。引用数据类型是存储在堆内存中,占据空间大。引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址,当解释器寻找引用值时,会检索其在栈中的地址,取得地址后从堆中获得实体。

  • Symbol是ES6新出的一种数据类型,这种数据类型的特点就是没有重复的数据,可以作为object的key。

  • BigInt也是ES6新出的一种数据类型,这种数据类型的特点就是数据涵盖的范围大,能够解决超出普通数据类型范围报错的问题。

三、 说一说你对闭包的理解

  • 一般就是一个函数A,return其内部的函数B,被return出去的B函数能够在外部访问A函数内部的变量,这时候就形成了一个B函数的变量背包,A函数执行结束后这个变量背包也不会被销毁,并且这个变量背包在A函数外部只能通过B函数访问。

  • 闭包形成的原理:作用域链,当前作用域可以访问上级作用域中的变量 闭包解决的问题:能够让函数作用域中的变量在函数执行结束之后不被销毁,同时也能在函数外部可以访问函数内部的局部变量。

  • 闭包带来的问题:由于垃圾回收器不会将闭包中变量销毁,于是就造成了内存泄露,内存泄露积累多了就容易导致内存溢出。

四、 说一说promise是什么与使用方法

1.什么是Promise

Promise是ES6异步编程的一种解决方案(目前最先进的解决方案是async和await的搭配(ES8),但是它们是基于promise的),从语法上讲,Promise是一个对象或者说是构造函数,用来封装异步操作并可以获取其成功或失败的结果。 同时可以避免多层异步调用嵌套问题(回调地狱) 。 让代码的可读性更高,更容易维护

2.Promise的使用

Promise构造函数接收一个函数作为参数,这个函数有两个参数,分别是两个函数 resolverejectresolve将Promise的状态由等待变为成功,将异步操作的结果作为参数传递过去;reject则将状态由等待转变为失败,在异步操作失败时调用,将异步操作报出的错误作为参数传递过去。实例创建完成后,可以使用then方法分别指定成功或失败的回调函数,也可以使用catch捕获失败,then和catch最终返回的也是一个Promise,所以可以链式调用。

五、 说一说跨域是什么?如何解决跨域问题?

跨域:当前页面中的某个接口请求的地址和当前页面的地址如果协议、域名、端口其中有一项不同,就说该接口跨域了

跨域限制的原因:浏览器为了保证网页的安全,出的同源协议策略。

  • 跨域解决方案 cors:目前最常用的一种解决办法,通过设置后端允许跨域实现。

  • node中间件、nginx反向代理:跨域限制的时候浏览器不能跨域访问服务器,node中间件和nginx反向代理,都是让请求发给代理服务器,静态页面面和代理服务器是同源的,然后代理服务器再向后端服务器发请求,服务器和服务器之间不存在同源限制

六、 说一说BFC

BFC 全称:Block Formatting Context, 名为 “块级格式化上下文”

让空间里的子元素不会影响到外面的布局 , 独立的渲染区域,不会影响边界外的元素

实际效果

七、 说一说JavaScript有几种方法判断变量的类型?

JavaScript有4种方法判断变量的类型,分别是typeof、instanceof、Object.prototype.toString.call()(对象原型链判断方法)、 constructor (用于引用数据类型)

  • typeof:常用于判断基本数据类型,对于引用数据类型除了function返回’function‘,其余全部返回’object'。

  • instanceof:主要用于区分引用数据类型,检测方法是检测的类型在当前实例的原型链上,用其检测出来的结果都是true,不太适合用于简单数据类型的检测,检测过程繁琐且对于简单数据类型中的undefined, null, symbol检测不出来。

  • constructor:用于检测引用数据类型,检测方法是获取实例的构造函数判断和某个类是否相同,如果相同就说明该数据是符合那个数据类型的,这种方法不会把原型链上的其他类也加入进来,避免了原型链的干扰。

  • Object.prototype.toString.call():适用于所有类型的判断检测,检测方法是Object.prototype.toString.call(数据) 返回的是该数据类型的字符串。 这四种判断数据类型的方法中,各种数据类型都能检测且检测精准的就是Object.prototype.toString.call()这种方法。

  • constructor 获取的是原型链的最顶层,instanceof可以判断是否属于原型链的任意一层,同时instanceof无法检测基本数据类型,而constructor 可以检测基本数据类型。

八、实现异步的方法

promise/定时器/回调函数

九、 说一说数组去重都有哪些方法

1.两层for语句遍历判断加上splice

简单思路: 从数组第一个元素开始,每一次循环拿数组的下一个元素与其之后的每个元素都进行遍历比较,如果存在相同的元素,则通过splice()将其删除并从删除的索引位置开始继续比较(因为splice()删除后,后面元素往前移)。

// 第一种方法:
function noRepeat1(arr){
    // 第一层for用来控制循环的次数
    for(var i=0; i<arr.length; i++){
        //第二层for 用于控制与第一层比较的元素
        for(var j=i+1; j<arr.length; j++){
            //如果相等
            if(arr[i] == arr[j]){
                //删除后面的 即第 j个位置上的元素  删除个数 1 个
                arr.splice(j,1);
                // j--很关键的一步  如果删除 程序就会出错 
                //j--的原因是 每次使用splice删除元素时 返回的是一个新的数组 
                // 这意味这数组下次遍历是 比较市跳过了一个元素
                /*
                    例如: 第一次删除后 返回的是 1 1 3 2 1 2 4
                 *  但是第二次遍历是 j的值为2  arr[2] = 3
                 *  相当于跳过一个元素 因此要 j--
                 * */
                j--;
 
            }
 
        }
    }
 
    return arr;
}
 
var array=[1,2,3,4,5,3,7,8];
var arr=noRepeat1(array);
console.log(arr);

2.通过数组API indexOf()进行筛选

indexOf()方法 返回数组中值为其参数的数组索引,不存在则返回-1。 简单思路: 首先,定义一个新数组用于接收去重后的原数组元素。 然后,遍历判断新数组中是否存在当前原数组元素,若不存在(即indexOf()返回-1)则通过push()方法将该元素存到新数组的最后位置。

//定义一个有重复数据的数组
let arr = [1,2,1,'j',5,'1',true,2,5,'h',true];
//去重方法
function duplicateRemoval(arr) {
    //定义接收去重后结果的新数组
    let newArr = [];
    for(let i = 0;i<arr.length;i++){
        //判断新数组中是否存在当前索引为i的原数组元素
        //例如,一开始arr[0]=1不存在newArr,返回-1,执行push,        //但arr[2]=1存在newArr,返回0,不执行push
        if (newArr.indexOf(arr[i])===-1) {
            //如果不存在,则将其放到新数组的最后位置
            newArr.push(arr[i]);
        }
    }
    //返回去重后的新数组
    return newArr;
}
//打印方法执行返回结果
console.log(duplicateRemoval(arr));

3.通过数组API includes()进行筛选

includes()方法 判断数组中是否存在值为其参数的元素,若存在则返回true,不存在则返回false。 简单思路: 与方法二类似,当新数组中不存在当前遍历的原数组元素时,将其插入到新数组中。

//定义一个有重复数据的数组
let arr = [1,2,1,'j',5,'1',true,2,5,'h',true];
//去重方法
function duplicateRemoval(arr) {
    //定义接收去重后结果的新数组
    let newArr = [];
    for(let i = 0;i<arr.length;i++){
        //判断新数组中是否存在当前索引为i的原数组元素
        if (!newArr.includes(arr[i])) {
            //如果不存在,则将其放到新数组的最后位置
            newArr.push(arr[i]);
        }
    }
    //返回去重后的新数组
    return newArr;
}
//打印方法执行返回结果
console.log(duplicateRemoval(arr));
​

4. 通过Set对象进行过滤

Set类似于数组,但是成员的值都是唯一的,没有重复的值。 简单思路:用数组初始化一个Set对象set,然后再将其转化为数组即可去除数组中重复的元素。

//定义一个有重复数据的数组
let arr = [1,2,1,'j',5,'1',true,2,5,'h',true];
//定义set对象,并用数组arr对其进行初始化
let set = new Set(arr);
//通过Array.from()方法将 set 转化为数组 并赋给新数组
let newArr = Array.from(set);
//打印结果
console.log(newArr);

十、说一下浮动

1.为什么要清除浮动

在我们的开发过程中,浮动元素是css中最常用的属性,浮动起来的元素会脱离标准流,如果我们的父级盒子没有设置高度就会造成父级盒子的高度塌陷,就会影响我们下面盒子的正常显示。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .father {
        width: 100%;
        border: 2px solid red;
      }
      .son {
        width: 300px;
        height: 300px;
        border: 2px solid blue;
      }
      .box {
        width: 100%;
        height: 300px;
        background-color: green;
      }
    </style>
  </head>
  <body>
    <div class="father">
      <div class="son"></div>
      <div class="son"></div>
    </div>
    <div class="box"></div>
  </body>
</html>
​
此时我并没有给father这个盒子设置高度,接下来给son盒子设置一个左浮动

发现father盒子成为一条红线,box盒子跑到son盒子的后面,这就是因为father盒子没有高度,在没有设置浮动之前son盒子是属于标准流的,son盒子会把father盒子撑开,一旦给son盒子设置浮动,它就会立即脱离标准流浮动起来(就是离开father盒子),而father没有设置高度,在失去son盒子支撑的时候就会变成一条横线,随即下面的box盒子就会跟随father盒子跑上去。这就是造成高度塌陷的原因。 高度塌陷会影响到我们下面的盒子,所以我们需要将浮动的son盒子重新塞回father盒子,也就是清除浮动,让我们的box盒子正常显示。

2.清除浮动

(1)给父级盒子添加高度

造成高度塌陷的原因就是父盒子没有高度,我们只需要给父盒子添加一个高度即可

.father {
        width: 100%;
        border: 2px solid red;
        height: 300px;
      }

(2)给父级添加 overflow 属性

 通过触发BFC方式,实现清除浮动

 .father {
        width: 100%;
        border: 2px solid red;
        overflow: hidden;
      }
​

(3)给父级添加after伪元素

 .clearfix::after {
        content: "";
        display: block;
        height: 0;
        clear: both;
        visibility: hidden;
      }
      .clearfix {
        /* IE6、7 专有 */
        *zoom: 1;
      }
<body>
    <div class="father clearfix">
      <div class="son"></div>
      <div class="son"></div>
    </div>
    <div class="box"></div>
  </body>
​

猜你喜欢

转载自blog.csdn.net/qq_55928824/article/details/129403844