前端面试考题

前端面试题

Call、Apply和 Bind 的区别?

  • Call、Apply、bind 都可以改变函数内部的 this

call

  • call()方法调用一个函数,其具有一个指定的 this值和分别地提供的参数(参数的列表)

  • 注意:该方法的作用和 apply()方法类似,只有一个区别,就是call()方法接收的是若干个参数的列表,而apply()方法接收的是一个包含多个参数的数组。

  • 语法:

    • fun.call(thisArg,arg1,arg2)
  • 参数:

    • thisArg
      • 在 fun 函数运行时指定的 this 值
      • 如果指定了 null 和 undefined 则内部 this 指向 window
  • arg1,arg2,...

    • 指定的参数列表
      <script>
        var obj = {
          name: "admin",
        };
    
        function foo(a, b) {
          console.log(this.name); // admin this指向obj
          console.log(a + b); // 30
        }
        foo.call(obj, 10, 20);
      script>
    

apply

  • apply()方法调用一个函数,其具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数

  • 注意:该方法的作用和call()方法类似,只有一个区别,就是call()方法接受的是若干个参数的列表,而apply()方法接收的是一个包含多个参数的数组。

  • 语法:

    • fun.apply(thisArg,[argsArray])
  • 参数:

    • thisArg
    • argsArray
  • apply()call()非常相似,不同之处在于提供参数的方式

  • apply()使用参数数组而不是一组参数列表

    • 例如:fun.apply(this,['eat','bananas'])
      <script>
        var obj = {
          name: "admin",
        };
    
        function foo(a, b) {
          console.log(this.name); // admin this指向obj
          console.log(a + b); // 30
        }
        foo.apply(obj, [10, 20]);
      script>
    

bind

  • bind()函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体。

  • 当目标函数被调用时 this 值绑定到bind()的第一个参数,该函数不能被重写。绑定函数被调用时,bind()也接收预设的参数提供给原函数

  • 一个绑定函数也能使用 new 操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数

  • 语法:

    • fun.bind(thisArg,arg1,arg2,...)
  • 参数:

    • thisArg
      • 当绑定函数被调用时,该参数会作为原函数运行时的 this 指向。当使用 new 操作符调用绑定函数时,该参数无效
    • arg1,arg2,...
      • 当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法
      <script>
        var obj = {
          name: "admin",
        };
    
        function foo(a, b, c, d) {
          console.log(this.name); // admin this指向obj
          console.log(a + b); // 30
          console.log(c + d); // 70
        }
        // foo.bind(obj, 10, 20)(); // 最后一个括号表示调用
        foo.bind(obj, 10, 20)(30, 40);
      script>
    

小结

  • call()apply()特性一样
    • 都是用来调用函数,而且是立即调用
    • 但是可以在调用函数的同时,通过第一个参数指定函数内部this的指向
    • call 调用的时候,参数必须以参数列表的形式进行传递,也就是以逗号分割的方式依次传递即可
    • apply 调用的时候,参数必须是一个数组,然后在执行的时候,会将数组内部的元素一个一个拿出来,与形参一一对应进行传递
    • 如果第一个参数指定了null或者undefined ,则内部 this 指向 window
  • bind
    • 可以用来指定内部 this 的指向,然后生成一个改变了 this 指向的新的函数
    • 它和callapply最大的区别是:bind不会调用
    • bind 支持传递参数,它的传参方式比较特殊,一共有两个位置可以传递
      • bind的同时,以参数列表的形式进行传递
      • 在调用的时候,以参数列表的形式进行传递
    • bind的时候以传递的参数为准还是以调用的时候传递的参数为准
      • 两者合并:bind的时候传递的参数和调用的时候传递的参数会合并到一起。传递到函数内部

JS 延迟加载方式有哪些?

  • js 的加载、解析和执行会阻塞页面的渲染过程,因此我们希望 js 脚本能够尽可能的延迟加载,提高页面的渲染速度。

  • JS 延迟加载的方式:

    • 将 js 脚本放在文档底部,来使 js 脚本尽可能的在最后来执行

      DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta http-equiv="X-UA-Compatible" content="IE=edge" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>Documenttitle>
        head>
        <body>body>
        <script src="./js1.js">script>
      html>
      
    • 给 js 脚本添加 defer 属性,这个属性会让脚本的加载与文档的解析同步,然后在文档解析完成后再执行这个脚本文件,这样的话就能使页面的渲染不被阻塞。多个设置了 defer 属性的脚本按规范来说最后是顺序执行的,但是在一些浏览器中可能不是这样的

      • 表面脚本在执行时不会影响页面的构造,也就是说,脚本会被延迟到整个页面都解析完毕之后再执行。
      DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta http-equiv="X-UA-Compatible" content="IE=edge" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>Documenttitle>
          
          <script src="./js1.js" defer>script>
        head>
        <body>body>
      html>
      
    • 给 js 脚本添加 async 属性,这个属性会使脚本异步加载,不会阻塞页面的解析过程,但是当脚本加载完成后立即执行 js 脚本,这个时候如果文档没有解析完成的话同样会阻塞。多个 async 属性的脚本的执行顺序是不可预测的,一般不会按照代码的顺序依次执行

      • 不让页面等待脚本下载和执行,从而异步加载页面其他内容
      • 缺点:不能控制加载的顺序
      DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta http-equiv="X-UA-Compatible" content="IE=edge" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>Documenttitle>
          <script src="./js1.js" async>script>
        head>
        <body>body>
      html>
      
    • 动态创建 DOM 标签的方式,我们可以对文档的加载事件进行监听,当文档加载完成后再动态的创建 script 标签来引入 js 脚本

          <script type="text/javascript">
            function downloadJS() {
              var element = document.createElement("script");
              element.src = "test.js";
              document.body.appendChild(element);
            }
            //三种事件模型,DOM0,DOM2,IE
            if (window.addEventListener) {
              window.addEventListener("load", downloadJS, false);
            } else if (window.attachEvent) {
              window.attachEvent("onload", downloadJS);
            } else {
              window.onload = downloadJS;
            }
          script>
      

盒子模型box-sizing有几种,都有什么区别?

  • W3C 盒子模型(content-box

    • box-width = width + 2 * padding + 2 * border
      
    • DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta http-equiv="X-UA-Compatible" content="IE=edge" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>Documenttitle>
          <style>
            div {
              box-sizing: content-box;
              width: 100px;
              height: 100px;
              padding: 1px;
              border: 1px solid yellow;
              background: red;
            }
          style>
        head>
        <body>
          <div>div>
        body>
      html>
      
  • IE 盒子模型(border-box

    • box-width = width
      
    • DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta http-equiv="X-UA-Compatible" content="IE=edge" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>Documenttitle>
          <style>
            div {
              box-sizing: border-box;
              width: 100px;
              height: 100px;
              padding: 1px;
              border: 1px solid yellow;
              background: red;
            }
          style>
        head>
        <body>
          <div>div>
        body>
      html>
      

第一行和第二行的颜色分别是什么?

DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Documenttitle>
    <style>
      .red {
        color: red;
      }
      .green {
        color: green;
      }
    style>
  head>
  <body>
    <div class="red green">第一行:颜色是什么?div>
    <div class="green red">第二行:颜色是什么?div>
  body>
html>
  • 答:
    • 两行都为绿色
    • 因为后声明的样式优先级高

简述防抖和节流

  • 函数防抖:是指在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。这可以使用在一些点击请求的事件上,避免因为用户的多次点击向后端发送多次请求

    • 防抖:就是将一段时间内连续的多次触发转化为最后一次触发
    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Documenttitle>
      head>
      <body>
        <input type="text" />
      body>
      <script>
        // 防抖:用户触发事件过于频繁,只要最后一个事件的操作
        let input = document.querySelector("input");
        // let t = null;
        // input.onchange = function () {
        //   if (t !== null) {
        //     clearTimeout(t);
        //   }
        //   t = setTimeout(() => {
        //     console.log(this.value);
        //   }, 500);
        // };
    
        // 根据上面的代码做出封装 使代码逻辑便于维护 
        input.onchange = debounce(function () {
          console.log(this.value);
        }, 500);
    	// 利用闭包
        function debounce(fn, delay) {
          let t = null;
          return function () {
            if (t !== null) {
              clearTimeout(t);
            }
            t = setTimeout(() => {
              fn.call(this);
            }, delay);
          };
        }
      script>
    html>
    
  • 函数节流:是指规定一个单位事件,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。节流可以使用在 scroll 函数的事件监听上,通过事件节流来降低事件调用的频率。

    • 节流:减少一段时间内触发的频率
    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Documenttitle>
        <style>
          body {
            height: 2000px;
          }
        style>
      head>
      <body>body>
      <script>
        // 防抖:只执行最后一次
        // 节流:控制执行次数 作用:控制高频时间执行次数
    
        // let flag = true;
        // window.onscroll = function () {
        //   if (flag) {
        //     setTimeout(() => {
        //       console.log("hello world");
        //       flag = true;
        //     }, 500);
        //     flag = false;
        //   }
        // };
    
        window.onscroll = throttle(function () {
          console.log("hello world");
        }, 500);
    
        function throttle(fn, delay) {
          let flag = true;
          return function () {
            if (flag) {
              setTimeout(() => {
                fn.call(this);
                flag = true;
              }, delay);
              flag = false;
            }
          };
        }
      script>
    html>
    
  • 区别:两者区别在于函数节流是固定时间做某一件事,比如每隔 1 秒发一次请求。而函数防抖是频繁触发后,只执行一次(两者的前提都是频繁触发)

以下console.log打印顺序的判断

  <script>
    setTimeout(function () {
      console.log("1");
    }, 0);
    new Promise(function (resolve) {
      console.log("2");
      resolve();
    }).then(function () {
      console.log("3");
    });
    console.log("4");
    // 2 4 3 1
    // 打印顺序: Promise log Promise其后的.then() setTimeout
  script>

你可能感兴趣的:(前端面试题,javascript,html,前端)