前端现场笔试题

现场面试题

沛华给的学生的笔试题

  1. css3 新增的伪类元素有哪些?

    • :before
    • :after
    • :first-child
    • :first-of-type
    • :last-child
    • :nth-of-type
  2. 伪类选择器有哪些?link、visited、hover、active

  3. 单行文本溢出以省略号表示:

    width:多少px自己决定;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    注:ellipsis :  当对象内文本溢出时显示省略标记
    助记:WTO
    
  4. 多行文本溢出以省略号表示:

    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;    // 最大行数
    -webkit-box-orient: vertical;
    
  5. 移动端适配方案 flexible.js 的实现原理大概是怎样的?

    作用:它就是一个终端设备适配的解决方案。也就是说它可以让你在不同的终端设备中实现页面适配。

    使用:flexible.js 的用法非常的简单,在页面的<head></head>中引入 flexible_css.js,flexible.js文件。

    flexible做的三件事:

    • 动态改写标签
    • 给元素添加data-dpr属性,并且动态改写data-dpr的值
    • 给元素添加font-size属性,并且动态改写font-size的值

    博客链接

  6. 遍历数组的方式有几种?哪种方式能中途停止?

    map、filter、forEach、some(能中途停止)、every、reduce

    博客链接

  7. js 如何判断一个变量是否为数组?

    1. instanceof

      let arr = [1, 2, 3]
      let res = arr instanceof Array
      console.log(res)
      
    2. 数组方法:isArray()

      let arr = [1, 2, 3]
      let res = Array.isArray(arr)
      console.log(res)
      
    3. 原型prototype + toString + call()

      let arr = [1, 2, 3]
      let res = Object.prototype.toString.call(arr).slice(8, -1).toLowerCase()
      console.log(res)
      
    4. 原型prototype + isPrototypeOf()

      注:isPrototypeOf() 是 Object函数(类)的下的一个方法,用于判断当前对象是否为另外一个对象的原型,如果是就返回 true,否则就返回 false

      let arr = [1, 2, 3]
      let res = Object.prototype.isPrototypeOf(arr)
      console.log(res) // true
      
    5. 构造函数 constructor

      let arr = [1, 2, 3]
      let res = arr.constructor
      console.log(res) // Array() { [native code] }
      

    博客链接

  8. js 把 Object 的实例化对象 A、B、C 合并,赋值给对象 C。

    方法一:

    let c = Object.assign(A, B, C)

    方法二:

    let a = [1, 2, 3]
    let b = [4, 5, 6]
    let c = [...a, ...b]
    console.log(c)
    
  9. const Greeters = [];
    for (var i = 0; i < 10; i++) {
      Greeters.push(function() {
        return console.log(i)
      })
    }
    Greeters[0]() // 10
    Greeters[1]() // 10
    Greeters[2]() // 10
    // 注意:在for循环中它用的是 var 关键字,所以得到的结果是一样的。
    
    const Greeters = [];
    for (let i = 0; i < 10; i++) {
      Greeters.push(function() {
        return console.log(i)
      })
    }
    Greeters[0]() // 0
    Greeters[1]() // 1
    Greeters[2]() // 2
    // 这里用的是 let 关键字
    
  10. var name = 'world!';
    (function() {
      if(typeof name === 'undefined') {
        var name = 'Jack';
        console.log("Goodbye" + name);
      } else {
        console.log('Hello' + name);
      }
    })() // GoodbyeJack
    
    // 注意:console.log(typeof name === 'undefined'); 为 true。意思就是说有没有 var name = 'world!'; 结果都是 GoodbyeJack。
    
  11. const num = {
      a: 10,
      add() {
        return this.a +2
      },
      reduce: () => this.a - 2
    };
    console.log(num.add()); // 12
    console.log(num.reduce()); // NaN
    
  12. 谈谈小程序的双向绑定和 Vue 的异同?(小程序里面的双向绑定和 vue 中的双向绑定有什么区别?)

    小程序的数据双向绑定:

    • 首先通过 bindinput 绑定文本框的输入事件。
    • 在 data 中声明一个变量 content ,将其动态绑定成文本框的 value 值。
    • 在 bindinput 事件中通过事件参数 e.detail.value 可以获取到文本框中最新的 value 值。
    • 通过 this.setData 将文本框最新的 value 值 赋值给 动态绑定的 value 值 content 即可实现数据的双向绑定。

    vue 的数据双向绑定:

    • 首先为文本框绑定 @input 监听文本框的输入事件。
    • 为文本框动态绑定 value 属性,其值是在 data 中定义的变量。
    • 在 @input 绑定的事件中 通过事件参数 event.target.value 可以获取到 input 框中最新的 value 值。
    • 将其重新获取到的 value 赋值给 value 值动态绑定的那个变量。

    区别:

    • 大体上区别不大,绑定事件不同,以及获取 value 值的具体方式不同,以及在小程序中设置 data中的数据,需要调用 this.setData 方法进行设置。
  13. uniApp 开发中如何获取上一个页面传递的数据?(uniapp 中获取上一页内容)

    let pages = getCurrentPages();
    let page = pages[pages.length - 2];
    page.$vm.refreshflag = true;(此参数为上一页中的参数)
    
  14. 写出以下的输出结果:

    console.log('1' + 2 + 3); // "123"
    console.log('' == false); // true
    console.log(0 == false); // true
    console.log(undefined == false); // false
    console.log(1 + 2 + '3'); // "33" // 引起注意
    console.log('0' == false); // true
    console.log('0' === false); // false
    console.log('123' == false); // false
    console.log(-1 == false); // false
    console.log(-1 == true); // false
    console.log(!!undefined == false); // true
    console.log(typeof a); // undefined
    
  15. function count() {
      var arr = [];
      for (var i = 1; i <= 3; i++) {
        arr.push(function () {
          return i * i
        })
      }
      return arr;
    }
    
    var results = count();
    var f1 = results[0];
    var f2 = results[1];
    var f3 = results[2];
    
    console.log(f1()); // 16
    console.log(f2()); // 16
    console.log(f3()); // 16
    // 原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了4,因此最终结果为16。(即,返回函数是在循环函数结束后才开始执行)
    
    // 返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
    
  16. 写出排序结果:

    var a = ['Google','Apple','Microsoft'].sort();
    var b = ['Google','apple','Microsoft'].sort();
    var c = ['Google','zpple','Microsoft'].sort();
    var d = [10, 20, 1, 2].sort();
    
    console.log(a); // [ 'Apple', 'Google', 'Microsoft' ]
    console.log(b); // [ 'Google', 'Microsoft', 'apple' ]
    console.log(c); // [ 'Google', 'Microsoft', 'zpple' ]
    console.log(d); // [ 1, 10, 2, 20 ]
    
  17. 请结合你对 vue 生命周期的理解分别写出 this.message 与 this.$el 的打印结果:

    let vm = new Vue({
      el: "app",
      data: {
        message: 1
      },
      template:'<div id="app"><p>{{message}}</p></div>',
      created() {
        console.log('调用了created'); // 第二步:'调用了created'
        console.log(this.message);  // 1
        console.log(this.$el); // undefined
      },
      beforeMount() {
        console.log('调用了beforeMount'); // 第三步 '调用了beforeMount'
        console.log(this.message);  // 1
        console.log(this.$el); // <div></div></div>
      },
      beforeCreate() {
        console.log('调用了beforeCreate'); // 第一步: '调用了beforeCreate'
        console.log(this.message);  // undefined
        console.log(this.$el); // undefined
      },
      mounted() {
        console.log('调用了mounted'); // 第四步: '调用了mounted'
        console.log(this.message);  // 1
        console.log(this.$el); // <div id="app"><p>{{message}}</p></div>
      },
    })
    vm.message = 2;
    
  18. 什么时候输出 1:

    setTimeout(function() {
      console.log(1);
    },2000)
    
    var time = Date.now();
    while(Date.now() - time < 5000){};
    // 5秒以后输出1。定时器里面的回调是异步的,等同步的 while 循环执行完之后才会执行。
    
  19. let a = {
      n:1
    };
    
    let b = a;
    
    a.x = a = {
      n:2
    };
    
    console.log(a.x); // undefined
    console.log(b.x); // {n: 2}
    // 难度在a.x
    
  20. JS 合并两个数组的方法:

    var a = [1, 2, 3];
    var b = [4, 5, 6];
    // 1. concat
    var c = a.concat(b); // c = [1, 2, 3, 4, 5, 6];
    
    // 2. for 循环
    for (var i in b) {
        a.push(b[i]);
    }
    
    // 3. apply
    a.push.apply(a,[4, 5, 6]);
    
    // 4. 扩展运算符
    var c = [...a, ...b]
    console.log(c); // c = [1, 2, 3, 4, 5, 6];
    
  21. (function executionSequence() {
      setTimeout(function() {
        console.log(1);
      },0)
      new Promise(function(resolve,reject){
        console.log(2);
        resolve()
        console.log(3)
      }).then(function() {
        console.log(4)
      })
      console.log(5)
    })() // 2 3 5 4 1
    
  22. js DOM 操作方法:

    • write():这个方法可以把任意字符串插入到文档中。
    • createElement():创建一个元素节点。
    • appendChild():将新节点追加到子节点列表的末尾。
    • createTextNode():创建一个文本节点。
    • insertBefore():将新节点插入在前面。
    • replaceChild():将新节点替换旧节点。
    • cloneNode():复制节点。
    • removeChild():移除节点。
    • 查找节点:getElementById(),querySelector()等。
  23. 1rem、1em、1vh、1px 各自代表的含义?

    **rem: **页面所有使用 rem 单位的长度都是相对于根元素<html>元素的 font-size 大小。即 1rem 等于根元素元素的 font-size 大小。

    em:

    • 子元素字体大小的 em 相对于父元素字体的大小。
    • 元素的 width/height/padding/margin 用 em 的话是相对于该元素的 font-size。

    **vh、vw:**全称是 Viewport Width 和 Viewport Height,视口的宽度和高度,1vh 相当于 视口高度的 1%。

    **px:**px像素(Pixel),相对长度单位。像素px是相对于显示器屏幕分辨率而言的。

    一般电脑的分辨率有 {1920*1080} 等不同的分辨率。

    1920*1080 前者是屏幕宽度总共有 1920 个像素,后者则是高度为 1080 个像素。

  24. 如何中断 Ajax 请求?

    有两种方式:

    1. 设置超时时间让 Ajax 自动断开。
    2. 手动去停止 Ajax 请求,核心是调用 XMLHttpRequest 对象上的 abort 方法。
    xmlHttp.open("POST","Url",true);
    xmlHttp.onreadystatechange=function(){
    	...// 得到响应之后的操作
    }
    xmlHttp.send();
    // 设置3秒钟后检查xmlHttp对象所发送的数据是否得到响应.
    setTimeout("CheckRequest()","3000");
      function CheckRequest(){
      //为4时代表请求完成了
      if(xmlHttp.readyState!=4){
        alert('数据响应超时');
        //关闭请求
        xmlHttp.close();
      }
    }<br>//根据响应状态的改变关闭
    

    **切记:**不可用 abort 方法来作为终止对服务器的请求操作,只有当做在前端页面立刻停止执行 ajax 成功后的方法,因为你执行 abort 方法后,ajax 很可能已经对服务端发送了请求,只是还未返回回馈信息而已。

  25. Vuex 中的 action 和 mutation 的区别:

    • 流程顺序:视图触发 Action,Action 再触发 mutation。

    • 角色定位:

      Action:业务代码、异步请求。

      Mutation:专注于修改 State,理论上是修改 State 的唯一途径。

    • 限制:

      Mutation:必须同步执行。(Mutation 中采取异步函数仍然是有效的,可以实现对 state 状态的更改,但是不推荐)

      Action:可以异步,但不能直接操作 State。

  26. 小程序, uni-app 生命周期:

    1. onLoad:首次进入页面加载时触发,可以在 onLoad 的参数中获取打开当前页面路径中的参数。
    2. onShow:加载完成后、后台切到前台或重新进入页面时触发。
    3. onReady:页面首次渲染完成时触发。
    4. onHide:从前台切到后台或进入其他页面触发。
    5. onUnload:页面卸载时触发。
    6. onPullDownRefresh:监听用户下拉动作。
    7. onReachBottom:页面上拉触底事件的处理函数。
    8. onShareAppMessage:用户点击右上角转发。
  27. 为什么要用闭包?

    闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。

  28. js 实现数组的随机排序。

    方法一:通过数组中的 sort 方法实现,return 一个 Math.random()-0.5

    var arr = [1,2,3,4,5,6,7,8,9,10];
    arr.sort(function(){
        return Math.random() - 0.5;
    })
    console.log(arr);
    

    方法二:遍历当前数组,并创建一个暂存容器,每次遍历时,出现一个随机索引,使用随机索引,获取数组中一个随机的值,取出到暂存容器,然后根据当前循环次数的索引,获取数组中的值,放入原来取出的地方,最后把暂存容器的值,赋值给当前循环次数的索引的值,实现随机排序;(即三个容器间的交互)

    var arr = [1,2,3,4,5,6,7,8,9,10];
    function randSort1(arr){
      for(var i = 0,len = arr.length;i < len; i++ ){
            var rand = parseInt(Math.random()*len);
            var temp = arr[rand];
            arr[rand] = arr[i];
            arr[i] = temp; 
       }
       return arr;
    } 
    console.log(randSort1(arr));
    
  29. 介绍一下 Web Storage 的概念和用法。

    Web Storage 包含如下两种机制:

    • sessionStorage 为每一个给定的源(given origin)维持一个独立的存储区域,该存储区域在页面会话期间可用(即只要浏览器处于打开状态,包括页面重新加载和恢复)。
    • localStorage 同样的功能,但是在浏览器关闭,然后重新打开后数据仍然存在。

    这两种机制是通过 Window.sessionStorage 和 Window.localStorage 属性使用(更确切的说,在支持的浏览器中 Window 对象实现了 WindowLocalStorage 和 WindowSessionStorage 对象并挂在其 localStorage 和 sessionStorage 属性下)—— 调用其中任一对象会创建 Storage 对象,通过 Storage 对象,可以设置、获取和移除数据项。对于每个源(origin)sessionStorage 和 localStorage 使用不同的 Storage 对象——独立运行和控制。

  30. // promise中的.then方法是微任务,定时器是宏任务
    setTimeout(function(){
     console.log('定时器开始啦');
    });
    new Promise (function(resolve) {
     console.log('马上执行 for 循环');
     for(var i = 0; i < 10000; i++) {
       i == 99 && resolve();
     }
    }).then(function() {
     console.log('执行 then 函数');
    });
    console.log('代码执行结束');
    // 1. '马上执行 for 循环'
    // 2. '代码执行结束'
    // 3. '执行 then 函数'
    // 4. '定时器开始啦'
    
  31. var name = "The Window";
    var object = {
     name: "My Object",
     getNameFunc: function () {
       return function () {
         return this.name
       }
     }
    }
    console.log(object.getNameFunc()()); // ‘The Window’
    // 解析:
    // 1. object.getNameFunc() 得到的是一个return出来的一个函数。
    // 2. object.getNameFunc()() 把return出来的函数调用,这个就属于隐式类型转换(光秃秃的调用), this指向window
    
  32. var name = "The Window";
    var object = {
     name: "My Object",
     getNameFunc: function () {
       var that = this;
       return function () {
         return that.name
       }
     }
    }
    console.log(object.getNameFunc()()); // My Object
    
  33. 前端路由和后端路由的区别?

    • 什么是路由?

    路由是根据不同的 URL 展示不同的内容和页面。

    • 什么是前端路由?

      **特点:**不向后台发送请求,不刷新页面,前后端分离。

      前端路由即响应页面内容的任务是由前端来做的,根据不同的 url 更新页面的内容,随着 SPA(单页面应用)的普遍使用,前后端开发分离,项目中基本都使用前端路由,通过路由实现页面的变化。例如,通过 vue 开发的 SPA 中,切换路由,并不刷新页面,而是根据路由在虚拟 DOM 中加载所需要的数据,实现页面内容的改变。

    • 什么是后端路由?

      **特点:**向服务器发送请求,会刷新页面,前后端分离。

      在浏览器的地址栏中切换不同的 url 时,每次都向后台服务器发出请求,服务器根据不同的响应不同的数据,浏览器接收到数据后再进行渲染,所以后端路由会刷新页面,如果网速慢的话,就会看到一个空白页面等待服务端返回数据,后台路由最大的问题就是不能前后端分离。

    • 什么时候使用前端路由?

      在单页面应用中,大部分页面结构不变,只改变部分内容时使用。

    • 前端路由的优缺点:

      优点:

      • 用户体验好,页面初始化后,只需要根据路由变换页面内容,不需要再向服务器发送请求,内容变换速度快。
      • 可以在浏览器中输入指定想要访问的 url。
      • 实现了前后端分离,方便开发。

      缺点:

      • 使用浏览器的前进、后退键的时候会重新发送请求,没有合理的利用缓存。
      • 单页面无法记住之前滚动的位置,无法在前进、后退的时候记住滚动的位置。
  34. node.js 中如何读写文件?

    nodejs 中所有与文件相关的操作都在fs模块中,而读写操作又是我们会经常用到的操作,nodejs 的 fs 模块针对读操作为我们提供了readFile,read, createReadStream 三个方法,针对写操作为我们提供了writeFile,write, createWriteStream 三个方法。

    博客地址

  35. Linux 中常用的命令?(沛华博客)

    Linux是一套开源免费的操作系统,与系统的交互通常用命令来实现,常用的命令有:

    • ls 查看当前文件夹下的文件(list单词的缩写), ls -al or ls -a -l查看隐藏文件并竖向排列
    • cd 进入某一个文件夹(change directory)的缩写,cd ..回到上一级。tab键代码自动补全
    • clear 清屏
    • mkdir 创建文件夹
    • touch test.html 创建一个文件
    • rm test.html 删除一个文件
    • rm -r dir 删除文件夹
    • mv 原文件或文件夹 目标文件或文件夹 移动文件
    • cat test.html 查看文件内容
    • ctrl+c 取消命令
  36. 使用 CSS 实现一个三角形。

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta name="keywords" content="zidingyi">
            <meta name="description" content="zidingyi">
            <meta>
            <title>triangle</title>
            <style>
                div {
                    height: 0;
                    width: 0;
                    border: 100px solid transparent;
                    border-bottom: 100px solid red;
                }
            </style>
        </head>
        <body>
            <div></div>
        </body>
    </html>
    
  37. 若干根粗细不均匀的绳子,每根烧完均需要1小时,怎样烧能计时45分钟?

    30 分钟:把一根绳子从两头同时烧, 就能得到30分钟了。
    45 分钟:方法类似。其中一根绳子从两头烧得到30分钟,另外一根绳子从中折一下两头一起烧,两段时间加起来就可以了。

  38. 假如每3个空啤酒瓶可以换一瓶啤酒,某人买了 10 瓶啤酒,那么他最多可以喝到多少瓶?

    喝完10瓶后用9个空瓶换来3瓶啤酒(喝完后有4个空瓶) 喝完这三瓶又可以换到1瓶啤酒(喝完后有2个空瓶)
    这时他有2个空酒瓶,如果他能向老板先借一个空酒瓶,就凑够了3个空瓶可以换到一瓶啤酒,把这瓶喝完后将空瓶还给老板就可以了。
    所以他最多可以喝 10+3+1+1 = 15 瓶。

  39. 小程序组件之间数据传递:博客地址

  40. 小程序页面跳转和参数传递。

    跳转的三种方式:

    1. wx.navigateTo():保留当前页面,跳转到应用内的某个页面,使用 wx.navigateBack可以返回到原页面。
    2. wx.redirectTo():关闭当前页面,跳转到应用内的某个页面。
    3. 使用组件<navigator>.

    wx.navigateTo() 和 wx.redirectTo() 的区别:

    • wx.navigateTo() 是保留当前页面,跳转到某个页面,跳转页面后可以返回上一页。
    • wx.redirectTo() 是关闭当前页面,跳转到某个页面,跳转页面后不能返回上一页。

    博客地址

  41. 输出结果:

    emp = new Array(5);
    emp[1] = 1;
    emp[2] = 2;
    document.write(emp.length); // 5
    
  42. 能够返回键盘上的按键对应字符的事件是:onkeypress事件。

  43. 关于 document 对象的属性错误的是(B)

    A. body 是它的属性

    B. close 是它的属性(这个不属于,可以通过console.dir(document)检查)

    C. title 是它的属性

    D. bgColor 是它的属性

  44. <a href="javascript.window.close()">退出</a> 用于关闭浏览器窗口。

  45. 请输出结果:

    var a = 1;
    if (true) {
      console.log(a); // 报错,因为let不会变量提升。
      let a = 2;
    }
    
  46. var a = {n:1};
    var b = a;
    
    a.x = a = {n:2};
    console.log(a.n,b.n); // 2 1
    console.log(a.x,b.x); // undefine {n:2}
    
  47. 谈谈你对 HTTP 协议的理解:(来自http课件)

    协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则。

    HTTP(hypertext transport protocol)协议也叫超文本传输协议,是一种基于 TCP/IP 的应用层通信协议,这个协议详细规定了浏览器和万维网服务器之间互相通信的规则。

    客户端与服务端通信时传输的内容我们称之为报文。

    HTTP 就是一个通信规则,这个规则规定了客户端发送给服务器的报文格式,也规定了服务器发送给客户端的报文格式。实际我们要学习的就是这两种报文。客户端发送给服务器的称为“请求报文”,服务器发送给客户端的称为“响应报文”。

  48. 项目中如何修改 UI 框架的样式?

    1. 行内修改样式:通过在行内设置 style 修改,用于局部组件块。

    2. scoped 问题:可以去掉 scoped。

    3. vue2 deep 样式穿透方法:在不去掉 scoped 的情况下,我们可以用 /deep/ 或使用 >>> 来更改样式。

    4. vue3 deep 样式穿透方法:在不去掉 scoped 的情况下,我们可以用 :deep() 或使用 ::v-deep 来更改样式。

      ::v-deep .el-form-item {
        border: 1px solid rgba(255, 255, 255, 0.1);
        background: rgba(0, 0, 0, 0.1);
        border-radius: 5px;
        color: #454545;
      }
      
      或者使用
      :deep(.el-form-item) {
        border: 1px solid rgba(255, 255, 255, 0.1);
        background: rgba(0, 0, 0, 0.1);
        border-radius: 5px;
        color: #454545;
      }
      

      博客地址

  49. 找出字符串中第一个只出现一次的字母

    var str = 'eerratrefffp'
    function fun(str){
        var arr = [],arr1 = []
        arr = str.split('')
        arr.forEach(function(item,index){
            var num  = str.split(item).length - 1
            if(num == 1){
                arr1.push(item)
            }
        })
        if(!arr1.length == 0){
            console.log(arr1[0])
        }else{
            console.log('没有符合条件的值')
        }
    }
    fun(str) // a
    

    博客地址

  50. 输出结果:

    // 1
    var strA = "hi there";
    var strB = strA;
    strB = "bye there";
    console.log(strA);
    console.log(strB);
    
    折叠代码块1 console.log(strA); // hi there console.log(strB); // bye there
    // 2
    var objA = {prop1: 42};
    var objB = objA;
    objB = {};
    console.log(objA); 
    
    折叠代码块2 // {prop1: 42}
    // 3
    var arrA = [0, 1, 2, 3, 4, 5];
    var arrB = arrA;
    arrB[0] = 42; // 同一个地址值
    console.log(arrA); 
    
    折叠代码块3 // [42, 1, 2, 3, 4, 5]
    // 4
    var employeeId = 'abc123';
    function foo() {
      employeeId = '123abc';
      return;
    }
    foo();
    console.log(employeeId); 
    
    折叠代码块4 // '123abc'
    // 5
    function foo() {
      employeeId();
      var product = 'Car';
      return;
      function employeeId() {
        console.log(product);
      }
    }
    foo(); 
    
    折叠代码块5 // undefined
    // 6
    var obj = {
      message: "Hello",
      innerMessage: !(function () {
        console.log(this.message)
      })()
    };
    console.log(obj.innerMessage);
    
    折叠代码块6 // undefined true // 因为在匿名函数自调用中的this指向的是window
    // 7
    function myFunc() {
      console.log(this.message);
    }
    myFunc.message = "Hi John";
    console.log(myFunc());
    
    折叠代码块7 // undefined undefined
    // 8
    function myFunc(param1,param2) {
      console.log(myFunc.length); 
    }
    console.log(myFunc());
    console.log(myFunc("a","b"));
    console.log(myFunc("a","b","c","d"));
    
    折叠代码块8 // 三个答案相同:undefined,函数没有return
    // 9
    (function() {
      var greet = "Hello World";
      var toGreet = [].filter.call(greet, function(element, index) {
        return index > 5;
      });
      console.log(toGreet);
    })();
    
    折叠代码块9 // [ 'W', 'o', 'r', 'l', 'd' ] 这个题目我看不懂:2022年8月31日14:26:54
    // 10
    function getDataFromServer(apiUrl) {
      var name = "John";
      return {
        then: function (fn) {
          fn(name);
        }
      }
    }
    
    getDataFromServer('www.google.com').then(function(name){
      console.log(name);
    })
    
    折叠代码块10 // "John"
    // 11
    function mul (x) {
      return function (y) {
        return [x*y, function (z) {
          return x*y + z;
        }];
      }
    }
    console.log(mul(2)(3)[0]);
    console.log(mul(2)(3)[1](4));
    
    折叠代码块11 // 6 10
    // 12
    var a = 10;
    a.pro = 10;
    console.log(a.pro); 
    console.log(a.pro+a);
    
    折叠代码块12 console.log(a.pro); // undefined console.log(a.pro+a) // NaN(相当有undefined+a=NaN)
    // 13
    var s = 'hello';
    s.pro = 'world';
    console.log(s.pro+s);
    
    折叠代码块13 // 'undefinedhello'
  51. 合并对象:合并 obj1, obj2, obj3,使用新变量obj4保存。

    // ES6在Object新加的方法  assign() 
    // 作用:将多个对象{}  合并成一个独立对象。
    // 使用方式: Object.assign(合并的对象,传入合并中的对象....)
    var obj1 = {name: 'xiaoming', age: 8, weight: '60kg'};
    var obj2 = {account: 'admin', password: 'admin'}
    var obj3 = {remember: true};
    
    var obj4 = Object.assign(obj1, obj2, obj3);
    console.log(obj4);
    
    // 使用ES6中的扩展运算符
    var obj1 = { name: 'xiaoming', age: 8, weight: '60kg' }
    var obj2 = { account: 'admin', password: 'admin' }
    var obj3 = { remember: true }
    
    // var obj4 = Object.assign(obj1, obj2, obj3)
    var obj4 = { ...obj1, ...obj2, ...obj3 }
    console.log(obj4)
    
  52. 过滤对象中数据。

    /**
    * [过滤对象]
    * @param  obj [过滤前数据]
    * @param  arr [过滤条件,要求为数组]
    */
    function filterObj(obj, arr) {
        if (typeof (obj) !== "object" || !Array.isArray(arr)) {
        	throw new Error("参数格式不正确")
        }
    	const result = {}
    	Object.keys(obj).filter((key) => arr.includes(key)).forEach((key) => {
    		result[key] = obj[key]
    	})
    	return result
    }
    
    // 使用
    let obj = {
      a: '1',
      b: '2',
      c: '3'
    }
    
    let newObj = filterObj(obj,["a", "b"]);
    console.log(newObj);
    // 返回结果 :
    newObj = {
      a: '1',
      b: '2'
    }
    
  53. 怎么让 Chrome 支持小于 12px 的文字?

    <style>
        p span {
          font-size: 10px;
          -webkit-transform: scale(0.8);
          display: block;
        }
    </style>
    <body>
      <p><span>haorooms博客测试10px</span></p>
    </body>
    
  54. const promise = new Promise ((resolve,reject) => {
      console.log(1);
      resolve();
      console.log(2)
    })
    promise.then(() => {
      console.log(3)
    })
    console.log(4); 
    // 1 2 4 3
    
  55. function Foo() {
      var i = 0;
      return function() {
        console.log(i++);
      }
    }
    var f1 = Foo(), f2 = Foo();
    f1();
    f1();
    f2();
    
    折叠代码块
    f1(); // 0
    f1(); // 1
    f2(); // 0
        
  56. var a = "40";
    var b = 7;
    console.log(a % b);
    
    折叠代码块
    // 5 (数字5)
        
  57. 如果同时有两个请求,怎么让他们分开发送(一个请求结束,另一个请求开始)

    .then链式调用,或者使用async+await

    博客地址

  58. 全屏滚动的原理是什么? 用到了css的那些属性?

    • 全屏滚动和轮播图类似,都是通过改变元素位置或者显示与隐藏来实现,配合JS的一些交互距离判断,实现类似原生滚动捕获的效果。
    • 关键CSS属性是父容器 overflow: hidden; 。
    • 实现全屏滚动还可以简单的通过插件来实现,比如fullpage,很多大公司的页面都是用这个实现的,比如小米一些产品的官网。

1215面试题(笔试)

  1. 有哪些方法可以遍历对象中的所有属性?这些方法有何区别?

    • Object.keys()

      Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for...in 循环遍历该对象时返回的顺序一致 。如果对象的键-值都不可枚举,那么将返回由键组成的数组。

    • Object.values() 返回属性值。

      **Object.values()**方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for...in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。

    • Object.entries()

    **Object.entries()**方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环也枚举原型链中的属性)。

    Object.entries() 返回键值对数组,如 [ [key1, value1], [key2, value2], ..., [keyN, valueN] ]

    博客链接

  2. for of 和 for in 的区别?

    • for of 无法遍历 不可迭代的对象。

      可迭代的对象包括:Array, Map, set, String, TypedArray, arguments等。

    • for of 遍历的是值,for in 遍历的是key。

  3. let arr = ['a', 'b', 'c', 'd', 'e']
    
    for (let i of arr) {
      console.log(i)
    }
    // 'a', 'b', 'c', 'd', 'e'
    
    
    for (let i in arr) {
      console.log(i)
    }
    // 0 1 2 3 4
    
  4. 以下布尔转换的结果是什么?

    console.log(Boolean(0)); // false
    console.log(Boolean(1)); // true
    console.log(Boolean(NaN)); // false
    console.log(Boolean("  ")); // true
    console.log(Boolean("")); // false
    console.log(Boolean([])); // true
    console.log(Boolean({})); // true
    
  5. 以下哪些情况会导致回流?哪些情况会导致重绘?

    **reflow(回流)**是指浏览器为了重新渲染部分或者全部的文档,重新计算文档中的元素的位置。

    回流可能导致整个 DOM 树的重新构造,是性能的一大杀手。

    以下操作会引起回流:

    1. 改变窗口大小
    2. font-size 大小变化
    3. 增加或者溢出样式表
    4. 内容变化(input 中输入文字)
    5. 激活 CSS 伪类(:hover)
    6. 操作 class 属性,新增或者减少
    7. js 操作 dom
    8. offset 相关属性计算
    9. 设置 style 的值

    render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如 background-color、opacity等。则就叫称为重绘(repaint)

  6. 以下程序的执行结果是什么?

    let f = () => {
    	console.log(this);
    }
    let o = {
      f,
      g: {
        h: f
      }
    };
    o.f(); // window
    o.g.h(); // window
    
  7. let log = console.log;
    let timeId = 0;
    let handleReadyState = () => {
      if (document.readyState === 'complete') {
        window.clearTimeout(timeId);
        log('complete');
      }
    };
    let loop = () => {
      timeId = window.setTimeout(() => {
        handleReadyState();
        loop();// 递归调用loop
      }, 0);
    };
    loop();
    // 一直输出‘complete’死循环
    
  8. div+css 布局较 table 布局有什么优点?

    1. 改版的时候更方便,只要改 css 文件。
    2. 页面加载速度更快、结构化清晰、页面显示简洁。
    3. 样式与结构相分离。
    4. 易于优化(SEO)搜索引擎更友好,排名更容易靠前。
    5. 实现一些复杂的布局更加容易。
  9. js 延迟加载的几种方式?

    1. defer 属性:HTML 4.01 为 <script>标签定义了 defer属性。在<script> 元素中设置 defer 属性,等于告诉浏览器立即下载,但延迟执行

      <!DOCTYPE html>
      <html>
      <head>
          <script src="test1.js" defer="defer"></script>
          <script src="test2.js" defer="defer"></script>
      </head>
      <body>
      <!-- 这里放内容 -->
      </body>
      </html>  
      
    2. async 属性:HTML5 为 <script>标签定义了 async属性。与defer属性类似,都用于改变处理脚本的行为。同样,只适用于外部脚本文件
      目的:不让页面等待脚本下载和执行,从而异步加载页面其他内容

      异步脚本一定会在页面 load 事件前执行。不能保证脚本会按顺序执行。

      <!DOCTYPE html>
      <html>
      <head>
          <script src="test1.js" async></script>
          <script src="test2.js" async></script>
      </head>
      <body>
      <!-- 这里放内容 -->
      </body>
      </html>
      
    3. 使用 jQuery 的 getScript()方法

      $.getScript("outer.js",function(){ // 回调函数,成功获取文件后执行的函数
            console.log("脚本加载完成")  
      });
      
    4. 使用setTimeout延迟方法。

    5. 让 JS 最后加载

      把 js 外部引入的文件放到页面底部,来让 js 最后引入,从而加快页面加载速度。

  10. js 哪些操作会造成内存泄露?如何避免?

    内存泄露:

    1. 意外的全局变量引起的内存泄露。

      function leak(){
        leak="xxx"; // leak成为一个全局变量,不会被回收
      }
      
    2. 闭包引起的内存泄露。

    3. 没有清理的 DOM 元素引用。

      var elements={
          button: document.getElementById("button"),
          image: document.getElementById("image"),
          text: document.getElementById("text")
      };
      function doStuff(){
          image.src="http://some.url/image";
          button.click():
          console.log(text.innerHTML)
      }
      function removeButton(){
          document.body.removeChild(document.getElementById('button'))
      }
      
    4. 被遗忘的定时器或者回调。

      var someResouce=getData();
      setInterval(function(){
          var node=document.getElementById('Node');
          if(node){
              node.innerHTML=JSON.stringify(someResouce)
          }
      },1000)
      

    内存泄漏解决方法:

    1. 减少不必要的全局变量,或者声明周期较长的对象,及时对无用的数据进行垃圾回收。
    2. 注意程序逻辑,避免“死循环”之类的代码。
    3. 避免创建过多的对象,原则:不用了的东西要及时归还。
  11. 为什么利用多个域名来存储网站资源会更有效?

    1. CDN 缓存更方便。
    2. 突破浏览器并发限制(谷歌和火狐浏览器最大并发数是6个)。
    3. 节约 cookie 带宽。
    4. 节约主域名的连接数,优化页面响应速度。
  12. 回调函数有什么缺点。

    1. 回调函数最大的缺点是会造成回调地狱(Callback hell)。

      回调地狱的根本问题是:

      • 嵌套函数存在耦合性,一旦有所改动,就会牵一发而动全身。
      • 嵌套函数一多,就很难处理错误。
    2. 不能使用 try catch 捕捉错误。

    3. 不能直接 return。

  13. 前端如何进行性能优化?

    1. 减少 HTTP 请求。
    2. 减少页面的重绘和重排。
    3. 减少对 DOM 的操作。
    4. 用 JSON 格式来进行数据交换。
    5. 使用 CDN 加速(内容分发网络):各大云服务提供商都有CDN服务,如:阿里云、腾讯云、百度云,七牛 等。
    6. 精简 CSS 和 JS 的文件。
    7. 压缩图片。
    8. 图片懒加载。

    博客链接

  14. console.log(2 * "2") // 4 (数字4)
    console.log([1,2] + [2,1]) // “1221”
    
  15. “i’m a good man” 倒着打印出来(比如:“hello world” -> “dlrow olleh”)

    方法一:

    let str = "i'm a good man"
    let newStr = ''
    for (let i = str.length - 1; i >= 0; i--) {
      newStr += str[i]
    }
    console.log(newStr)
    

    方法二:

    var str = "i'm a good man";
    str = str + "";
    var arr = str.split("");
    // console.log(arr); //[ '1', '2', '3' ]
    for (var i = arr.length - 1; i >= 0; i--) {
      console.log(arr[i]);
    }
    
  16. js 获取嵌套数组,嵌套对象的值

    let obj = { aa: { xx: 'cc', '0': 0, '1': '1', '-1': -1 } }
    console.log(getObjChild(obj, 'aa.xx')) // "cc"
    // 获取嵌套数组/对象中的值
    function getObjChild(obj, key, gap = '.') {
      let tmp = {}
      let arr = key.split(gap) // 将key拆成数组
    
      if (obj[arr[0]]) {
        tmp = obj[arr[0]]
        for (let i = 1; i < arr.length; i++) {
          //逐层进入匹配查找
          let is_found = false
          if (typeof tmp === 'object') {
            for (let j in tmp) {
              if (j === arr[i]) {
                tmp = tmp[j]
                is_found = true
                break
              }
            }
          }
    
          if (!is_found) {
            tmp = false
            console.log('未找到 ' + arr[i])
            break
          }
        }
      } else {
        console.log('未找到 ' + arr[0])
        tmp = false
      }
    
      return tmp
    }
    
  17. 用尽可能简短的代码求得数组 arr = [3, 1, 4, 5, 2] 的最大值。

    方法一:

    let arr = [3, 1, 4, 5, 20, 18]
    let res = Math.max(...arr)
    console.log(res)
    

    方法二:

    var arr = [3, 1, 4, 5, 20, 18]
    var max = arr.reduce(function(a , b){
      return b > a ? b : a;
    });
      
    console.log(max); // 20
    
  18. 用原型如何实现下列代码:[1,2, 3, 4, 5].duplicator(); // [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]。要求不改变原数组,并返回新的值。

    var arr = [1, 2, 3, 4, 5]
    Array.prototype.duplicator = function () {
      let newArr = []
      // 此处的this是arr
      for (var i = 0; i < this.length; i++) {
        newArr.push(this[i])
      }
      return [].concat(this, newArr)
    }
    let res = arr.duplicator()
    console.log(res) // [1,2,3,4,5,1,2,3,4,5]
    console.log(arr) // [1,2,3,4,5]
    
  19. 求两个正整数的最大公约数

    lcm = function(m,n){ // 辗转相除法 求最大公约数
    	var u=+m,v=+n,t=v;
    	while(v!=0){
    		t=u%v;
    		u=v;
    		v=t;
    	}
    	return parseInt(u)
    }
    
    console.log(lcm(3, 10))
    

    扩展:欧几里得算法又称辗转相除法,是指用于计算两个非负整数a,b的最大公约数

    假如需要求 1997 和 615 两个正整数的最大公约数,用欧几里得算法,是这样进行的:

    997 / 615 = 3 (余 152)

    615 / 152 = 4(余7)

    152 / 7 = 21(余5)

    7 / 5 = 1 (余2)

    5 / 2 = 2 (余1)

    2 / 1 = 2 (余0)

    至此,最大公约数为1

    以除数和余数反复做除法运算,当余数为 0 时,取当前算式除数为最大公约数,所以就得出了 1997 和 615 的最大公约数 1。

  20. JavaScript 中如何检测变量是一个 String 类型?请写出函数实现。

    // 方法一:
    function isString(obj){
      // 注意:这个String是一个函数,不需要加引号
      return obj.constructor === String? true: false;
    }
    
    console.log(isString("5")) // true
    
    // 方法二:
    function isString(obj){
      return typeof(obj) === "string"? true: false;
      // 也可以这样写:return typeof obj === 'string' ? true : false
    }
    console.log(isString("5"))
    
    // 方法三:
    function isString(obj){
      return Object.prototype.toString.call(obj) === "[object String]" ? true : false;
    }
    console.log(isString('5'););  // true
    
  21. 请编写简要 js 代码,实现判断一个字符串中出现次数最多的字符,统计这个次数的需求。

    // 用对象(推荐用法)
    var str = "zhaochucichuzuiduodezifu";
    var o = {};
    for (var i = 0, length = str.length; i < length; i++) {
    // var char = str[i];
    // .charAt(索引) :返回值是指定索引位置的字符串,超出索引,结果是空字符串。
    var char = str.charAt(i);
      if (o[char]) { //char就是对象o的一个属性,o[char]是属性值,o[char]控制出现的次数
        o[char]++; //次数加1
      } else {
        o[char] = 1; //若第一次出现,次数记为1
      }
    }
    console.log(o); //输出的是完整的对象,记录着每一个字符及其出现的次数
    
    //遍历对象,找到出现次数最多的字符和次数
    var max = 0;
    var maxChar = null;
    for (var key in o) {
      if (max < o[key]) {
        max = o[key]; //max始终储存次数最大的那个
        maxChar = key; //那么对应的字符就是当前的key
      }
    }
    console.log("最多的字符是" + maxChar); // 最多的字符是u
    console.log("出现的次数是" + max); // 出现的次数是5
    
  22. $this 和 this 关键字在 jQuery 中有何不同?

    1. 表示对象不同:this表示的是javascript提供的当前对象,$(this)表示的是用jquery封装候的当前对象。
    2. 过程不同:this对象可以直接用this.style修改样式,$(this)可以使用jquery提供的方法访问样式。
  23. $(document).ready() 方法和 window.onload 有什么区别?

    JQuery中 $(document).ready() 的作用类似于传统 JavaScript 中的 window.onload 方法,不过与window.onload 方法还是有区别的:

    1. 执行时间不同:
      • window.onload 必须等到页面内包括图片的所有元素和资源加载完毕后才能执行。
      • $(document).ready() 是 DOM 加载完毕后就执行,不必等到整个网页资源加载完毕。
      • 所以,使用 $(document).ready() 方法的执行速度比 window.onload 的方法要快。
    2. 编写个数不同:
      • $(document).ready()可以同时编写多个,并且都可以得到执行。
      • window.onload不能同时编写多个,如果有多个window.onload方法,只会其中执行一个。
    3. 简化写法:
      • window.onload没有简化写法。
      • $ (document).ready(function(){ })可以简写成$(function(){方法体 });又因为JQuery的默认参数是document,则还可以写成$().ready(function{ })
  24. 简单描述微信小程序的相关文件类型?

    微信小程序项目结构主要有四个文件类型,如下:

    1. .WXML:是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。内部主要是微信自己定义的一套组件。(主要借鉴W3C,但是没有完全遵循W3C的规范)
    2. .WXSS:(WeiXin Style Sheets) 是一套样式语言,用于描述WXML的组件样式。
    3. .js:逻辑处理,网络请求。
    4. .json:小程序设置,如页面注册,页面标题及tabBar

    app.json:必须要有这个文件,如果没有这个文件,项目无法运行,因为微信框架把这个作为配置文件入口,整个小程序的全局配置。包括页面注册,网络设置,以及小程序的window背景色,配置导航条样式,配置默认标题。

    app.js:必须要有这个文件,没有也是会报错!但是这个文件创建一下就行,什么都不需要写以后我们可以在这个文件中监听并处理小程序的生命周期函数、声明全局变量。

  25. 你是怎么封装微信小程序的数据请求的?

    1. 将所有的接口放在统一的 JS 文件中并导出。
    2. 在 app.js 中创建封装请求数据的方法。
    3. 在子页面中调用封装的方法请求数据。
  26. 小程序有哪些参数传值的方法?

    1. 给HTML元素添加 data-* 属性来传递我们需要的值,然后通过 e.currentTarget.dataset 或 onload 的param 参数获取。但 data- 名称不能有大写字母、不可以存放对象。
    2. 设置id 的方法标识来传值通过 e.currentTarget.id 获取设置的id的值,然后通过设置全局对象的方式来传递数值。
    3. 在 navigator 中添加参数传值。
  27. 怎么解决小程序的异步请求问题?

    使用 promise 解决。

    博客链接

  28. js scroll 滚动连续多次触发事件只执行一次。

    (function() {
        var finished = true;
        function loadData() {
            //xxxx
            finished = true;
        }
        dom.onscroll = function() {
            if(finished && this.scrollHeight - this.clientHeight == this.scrollTop) {
                finished = false;
                loadData();
            }
        }
    })();
    
  29. 获取滚动条的位置

    // scrollTop没有括号
    document.documentElement.scrollTop
    
  30. 重写数组 map 方法:

    Array.prototype.newMap = function(fn) {
      var newArr = [];
      for(var i = 0; i < this.length; i++){
        newArr.push(fn(this[i], i, this))
      }
      return newArr;
    }
    

    博客链接

  31. 字符串反转。示例:输入 www.baidu.com 输出 moc.udiab.www

    方法一:reverse(),join()

    var name = "www.baidu.com";
    var resultStr = name.split('').reverse().join(''); 
    console.log(resultStr);  // moc.udiab.www
    

    方法二:charAt()

    var name = "www.baidu.com";
    var nameArr = name.split('');
    var resultStr = '';
    for (var i = nameArr.length-1; i >= 0; i--) {
        resultStr += name.charAt(i);
    }
    console.log(resultStr); // moc.udiab.www
    

    MDN charAt方法

  32. 输出的结果是:

    let obj = {
      a: 222,
      fn: function () {
          console.log(this.a);
      }
    }
    obj.fn() 
    
    
    
    
    
    // 222
    
    let obj = {
      a: 222,
      fn: function () {
        setTimeout(function(){
          console.log(this.a);
        })
      }
    }
    obj.fn() 
    
    
    
    
    // undefined
    // 定时器里面的this指向的是window
    
  33. 简述 HTTPS 加密原理:

    如果client和server之间通信采用对称加密,那么双方需要有同一个密钥。如何让双方都有该密钥?

    假设1:client在请求时将密钥发送给server:第三方可以拦截这个信息从而获得该密钥。如果使用该方法,必须将该密钥加密后, 然后发送给server,并且只能server进行解密。

    假设2: server将密钥发送给client:相当于没有加密,所有的请求端都能拿到密钥。

    博客链接

  34. 简述 HTTP 2.0 新增的内容。

    1. 二进制分帧层。
    2. 请求与响应复用。
    3. 服务器推送。
    4. 标头压缩。

    博客链接

  35. 数组和列表有什么区别?什么时候应该使用Array,而不是ArrayList?

    1. 存储内容比较:

      Array 数组可以包含基本类型和对象类型,ArrayList 却只能包含对象类型。
      Array 数组在存放的时候一定是同种类型的元素。ArrayList 就不一定了 。

    2. 空间大小比较:

      Array 数组的空间大小是固定的,所以需要事前确定合适的空间大小。
      ArrayList 的空间是动态增长的,而且,每次添加新的元素的时候都会检查内部数组的空间是否足够。

    3. 方法上的比较:ArrayList 方法上比 Array 更多样化,比如添加全部 addAll()、删除全部 removeAll()、返回迭代器 iterator() 等。


0223面试题(笔试)

  1. 什么是 Token?

    • Token 的定义:Token 是服务端生成的一串字符串,以作为客户端进行请求的一个令牌,当第一次登录后,服务器生成一个 Token 便将此 Token 返回给客户端,以后客户端只需带上这个 Token 前来请求数据即可,无需再次带上用户名和密码。
    • 使用 Token 的目的:Token 的目的是为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。
    • Token 的引入:Token 是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,在这样的背景下,Token 便应运而生。

    博客链接

  2. 什么是 WebSocket?怎么使用?

    • WebSocket 是一种网络通信协议,很多高级功能都需要它。

    • 初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HTTP 协议,为什么还需要另一个协议?它能带来什么好处?

      答案很简单,因为 HTTP 协议有一个缺陷:通信只能由客户端发起。

    • webSocket 的特点:

      • 建立在 TCP 协议之上,服务器端的实现比较容易。
      • 与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
      • 数据格式比较轻量,性能开销小,通信高效。
      • 可以发送文本,也可以发送二进制数据。
      • 没有同源限制,客户端可以与任意服务器通信。

    阮一峰博客

  3. promise 与 setTimeout 的区别:

    Promise 是一个 微任务,主线程是一个 task,为任务队列 会在 task 后面执行。

    setTimeout 返回的函数是一个新的 task,宏任务队列,所以 Promise 会先于 新任务执行。

    根据 HTML 标准,一个 task 执行完后,UI 会重新渲染。

    宏任务队列:setTimeout,setInterval,事件回调,setImmediate等

    微任务队列:promise,MutationObserver,Object.observe等

  4. console.log(['1','2','3'].map(parseInt));输出:[1, NaN, NaN]

    博客地址

  5. 什么是 Ajax?浏览器是怎样完成一次 Ajax 请求并执行其回调函数的?

    Ajax 的全称是:AsynchronousJavaScript+XML

    Ajax 的定义:Ajax 不是一个技术,它实际上是几种技术,每种技术都有其独特之处,合在一起就成了一个功能强大的新技术。

    Ajax 的特点:

    1. 无刷新更新数据。
    2. 异步与服务器通信(优化了浏览器和服务器之间的沟通,减少不必要的数据传输、时间。降低了网络上的数据流量)。
    3. 界面与应用分离(Ajax 使 Web 中的界面与应用分离,也可以说数据与呈现分离,有利于分工合作)。

    Ajax 的缺点:

    1. Ajax 干掉了 Back 和 History 功能,即对浏览器机制的破坏。
    2. Ajax 的安全问题(Ajax 的逻辑可以对客户端的安全扫描技术隐藏起来,允许黑客从远端服务器上建立新的攻击)。
    3. 对搜索引擎支持比较弱(如果使用不当,Ajax 会增大网络数据的流量,从而降低系统的性能)。

    博客地址

  6. 执行结果:

    let promise = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(1);
      },0);
      resolve(2);
    }).then((resolve) => {
      console.log('resolve', resolve)
    },(reject) => {
      console.log('reject', reject)
    })
    // "resolve" 2
    
  7. js 获取 URL 中参数值的方法:博客地址

  8. JavaScript 的全局函数有:

    1. decodeURI():解码某个编码的 URI。
    2. decodeURIComponent():解码一个编码的 URI 组件。
    3. encodeURI():把字符串编码为 URI。
    4. encodeURIComponent():把字符串编码为 URI 组件。
    5. escape():对字符串进行编码。
    6. eval():计算 JavaScript 字符串,并把它作为脚本代码来执行。
    7. isFinite():检查某个值是否为有穷大的数。
    8. isNaN():检查某个值是否是数字。
    9. Number():将对象的值转换成数字。
    10. parseFloat():解析一个字符串并返回一个浮点数。
    11. parseInt():解析一个字符串并返回一个整数。
    12. String():把对象的值转换为字符串。
    13. unescape():对由 escape() 编码的字符串进行解码。
  9. sort 函数的内部机制:

    V8 引擎 sort 函数只给出了两种排序 InsertionSort(插入排序) 和 QuickSort(快排),数量小于 10 的数组使用 InsertionSort,比10大的数组则使用 QuickSort。

  10. vue 相对于 jQuery 的优势在哪里?

    1. 减少 DOM 操作。
    2. 双向数据绑定。
    3. 组件化。

    博客地址

  11. 谈一谈响应式:

    响应式网站设计(Responsive Web design)的理念是:集中创建页面的图片排版大小,可以智能地根据用户行为以及 使用的设备环境(系统平台、屏幕尺寸、屏幕定向等)进行相对应的布局,无论用户正在使用笔记本还是iPad,我们 的页面都应该能够自动切换分辨率、图片尺寸及相关脚本功能等,以适应不同设备。

    基本原理: 媒体查询 @media

    代码:

    @media screen and (max-device-width:960px){
        body{background:red;}
    }
    
  12. 输出结果:

    console.log("64" - 4); 
    
    
    // 60
    
    
    
    
    console.log("64" + 4); 
    
    
    
    // “644”
    
  13. 输出结果:

    console.log([typeof null, null instanceof Object]); // ["object", false]
    
    console.log(Object instanceof null); // 报错 TypeError: Right-hand side of 'instanceof' is not an object
    
  14. 输出结果:

    function showCase(value) {
      switch(value) {
        case "A":
          console.log("Case A");
          break;
        case "B":
          console.log("Case B");
          break;
        case "C":
          console.log("Case C");
          break;
        default:
          console.log("Do not know");
      }
    }
    showCase(new String("A")); 
    
    
    
    
    // 输出结果:"Do not know"
    // new String() 得到的是一个空对象:{""}
    // new String('A') 得到的是:String {'A'}
    
  15. 输出结果:

    setTimeout(function() {
      console.log(1);
    });
    
    new Promise(function(resolve){
      console.log(2)
      for (var i = 0; i < 10000; i++) {
        i = 9999 && resolve();
      }
    }).then(function() {
      console.log(3)
    });
    console.log(4);
    
    
    
    
    
    // 2 4 3 1
    
  16. 用 CSS 实现一个最大的正方形:

    <section></section>
    <style>
        section {
          width: 100%;
          padding-top: 100%;
          background: #333;
        }
    </style>
    
  17. 请看题:

    function Person (name) {
          this.name = name;
    }
    let p = new Person('js');
    // 1. p.__proto__ 等于什么?
    
    
    
    console.log(p.__proto__ == Person.prototype); // true
    
    
    
    
    // 2. Person.__proto__ 等于什么?
    
    
    
    
    console.log(Person.__proto__ == Function.prototype); // true
    
    
    
    
    // 3. Person.prototype.__proto__ 等于什么?
    
    
    
    
    console.log(Person.prototype.__proto__ === Object.prototype); // true
    
  18. HTML5 Canvas 元素有什么用?

    在HTML5中<canvas>元素可以为你提供一种使用 JavaScript 来绘制图形的简单而强大的方法。它可以用于绘制图形,合成制作照片或做简单(而不是那么简单)的动画。

    <canvas>是一个简单的元素,它只有两个特定属性“width”和“height”以及所有核心HTML5属性,如id,name和class等。

    什么是canvas?

    1、是页面中一个无色透明的区域

    2、HTML5的canvas元素使用JavaScript在网页上绘制图像

    3、画布是一个矩形区域,可以控制其每一个像素

    4、canvas拥有多种绘制矩形、路径、圆形、字符以及添加图像的方法

    canvas的应用领域

    1、游戏:canvas 在基于 Web 的图像显示方面比 Flash 更加立体、精巧,canvas 游戏在流畅度和跨平台方面更牛。

    2、可视化数据:数据图表,如echart、F2、G2 …。

    3、banner 广告:用Canvas可实现动态的广告效果。

  19. 请详解 js 切割字符串的方法:

    1. string.slice(start, end);
    2. string.substr(start, length)
    3. string.substring(start, stop)
    4. indexOf
    5. lastIndexOf
    6. split

    博客地址

  20. 请举例操作日期的 API 代码。

    博客地址

  21. 请输出结果:

    let msg = "hello";
    for(let i = 0; i < 10; i++) {
        msg = "hello" + i * 2 + i
    }
    alert(msg);
    
    
    
    
    // “hello189” 此时的i是等于最后一次,也就是等于9
    
  22. 请写出输出结果:

    let str = true;
    console.log(str + "xyz"); // "truexyz"
    console.log(str + true); // 2
    console.log([str].map()); // undefined is not a function // 这一题不管数组中是什么内容,都会报错,因为map要接收一个回到函数做为参数,而此时并没有给
    console.log([str].map(Number)); // [1]
    console.log([str].map(String)); // "true"
    console.log([str].map(Object)); // "[Boolean]"
    console.log([str].map(Null)); // Null is not defined
    
  23. js 如何判断一个对象是否是空对象?

    1. 将 JSON 对象转换为 JSON 字符串,再判断该字符串是否为"{}"。
    2. for in 循环判断。
    3. Object.getOwnPropertyNames() 方法。
    4. Object.keys() 方法。

    博客地址

  24. 算法:一个无序的数组里有 99 个不重复的正整数,范围从 1 到 100, 唯独缺少一个整数,如何查找?

    思路:用空间来换时间。再开一个 100 的数组,全部初始化为0,然后将乱序的数组遍历一遍
    ,每个数字对应新开的数组下标,对应的++,再遍历一遍新开的数组,为零的就没有出现,返回该下标就好了。

  25. 把 1 - 100 个数存入数组的方法:方法特别多

    博客地址

  26. 列举几个常见的浏览器兼容性问题:

    1. 滚动条。
    2. 网页可视区兼容。
    3. 事件对象兼容。
    4. 阻止冒泡兼容。
    5. 阻止默认行为兼容。

    博客地址

  27. 多页面通信有哪些方法?简述这些方法的区别。

    1. cookie + setInterval。
    2. localStorage 方式。
    3. WebSocket 方式。
    4. SharedWorker 方式。

    博客地址

  28. 请输出打印结果:

    function add(m) {
      return function b(n) {
        return n + m++
      }
    }
    var add1 = add(070);
    var add2 = add(050);
    console.log(add1(010)); // 64
    console.log(add2(010)); // 48
    // 这题我看不懂,不知道怎么来的
    // 0开头是8进制的数
    
  29. WebSocket 是如何保持长连接的?

    1. 建立 WebSocket 连接。
    2. 在连接下保持心跳,使用 jmeter 循环控制器发送心跳保持连接。
    3. 参数化请求参数:如并发量、链接循环次数。

    概念:

    ​ Websocket 是一种持久化连接,先通过 http 协议建立一次连接,在连接中通过 WebSocket 协议持续和服务器进行交互,同时该协议存在被动性特点,服务器可以主动通知客户端下面的具体抓包情况,可以看出在 WebSocket 连接之后,向服务器发送请求,无需再次建立 http 连接。

  30. js 原生实现自定义滚动条效果

    请看:黑马36期,第十三部分,07页面

  31. js 如何判断两个对象内容是否相等:需要用到递归

    博客地址

  32. 路由懒加载的实现方式?

    要实现路由懒加载,就得先将进行懒加载的子模块(子组件)分离出来。懒加载前提的实现:ES6 动态地加载模块——import()。

    简单的说就是通过 import() 引用的子模块会被单独分离出来,打包成一个单独的文件(打包出来的文件被称为 chunk)。

    依照 webpack 原本的打包规则打包项目,我们就无法确定子模块在打包出来的那个 js 文件中,而且子模块的代码会和其他代码混合在同一个文件中。这样就无法进行懒加载操作。所以要实现懒加载,就得保证懒加载的子模块代码单独打包在一个文件中。

    一:借助ES6函数实现懒加载–import()

    实现原理:

    1. 将需要进行懒加载的子模块打包成独立的文件(children chunk)。
    2. 借助函数来实现延迟执行子模块的加载代码。
    二:vue-router 实现懒加载。
    三:webpack 提供的方法实现懒加载–require.ensure()

    博客地址

  33. vue 中的多线程实现机制是什么?

    1. Web Worker。
    2. Comlink。
    3. Comlink-loader。

    博客地址

  34. 简述 websocket 的通讯过程:

    http 1.0 :基于请求和应答模式,也就是服务器不能主动给客户端推送消息。

    http 1.1:HTTP 1.1相对于HTTP 1.0有了一些进步,1.0 建立一次连接,只能发送一次请求,而1.1修改了connection: keep-alive, 这样就可以进行一次连接,进行多次请求和应答,但是 response == request。

    websocket:webSocket 是一个持久化协议,webSocket 是基于 HTTP 协议的,或者说 借用 HTTP 的协议来完成一部分握手。具体步骤:

    1. 发送一个 get 请求。
    2. 服务器收到了协议,返回一个 Switching Protocal,这样就连接成功了。
    3. 接下来的通信都是 websocket,这样就很好的连接了。

    博客地址

  35. 常见排序算法的时间复杂度和空间复杂度:博客地址

  36. css 有哪些继承属性:

    一:字体系列

    1. font-family:规定元素的字体系列。
    2. font-weight:设置字体的粗细。
    3. font-size:设置字体的尺寸。
    4. font-style:定义字体的风格。

    二:文本系列属性

    1. text-indent:文本缩进。
    2. text-align:文本水平对齐。
    3. text-shadow:设置文本阴影。
    4. line-height:行高。
    5. work-spacing:增加或减少单词间的空白(即字间隔)。
    6. letter-spacing:增减或减少字符间的空白(字符间距)。
    7. text-transform:控制文本大小写。
    8. direction:规定文本的书写方向。
    9. color:文本颜色。

    三:其他

    1. visibility
    2. border-collapse
    3. list-style
    4. cursor

    博客地址

  37. display float position 的关系

    这是 box 布局的三种方式。

    1. 常规流(normal flow)
    2. 浮动(float)
    3. 定位(position)

    博客地址

  38. 什么是 webpack(熊键)

    • Webpack 是一个模块打包器(bundler)。

    • 在 Webpack 看来, 前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理

    • 它将根据模块的依赖关系进行静态分析,生成对应的静态资源

    1. 五大“护法”
    • Entry:入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。

    • Output:output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为 ./dist。

    • Loader:loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只能解析 JavaScript)。

    • Plugins:插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。

    • Mode:模式,有生产模式 production 和开发模式 development。

  39. Vue 中 assets、static 和 public 的区别:

    相同点:两个文件夹中的资源在 HTML 中使用都是可以的。

    不同点:

    assets:assets 中的文件会经过 webpack 打包,重新编译。(vue 脚手架3和4)

    public:放 favicon.ico 和 html 文件,不会被 webpack 打包。(vue 脚手架3和4)

    static:static 目录下的文件是不会被 webpack 处理的,它们会被直接复制到最终的打包目录下面(默认是 dist/static ),且必须使用绝对路径来引用这些文件。这是通过在 config.js 文件中的 build.assetsPublicPathbuild.assetsSubDirectory 链接来确定的。(vue 脚手架 2)

    注意:任何放在 static 中的文件需要以绝对路径的形式引用:/static/[filename]

  40. Vue 中的观察者模式

    **观察者模式定义:**观察者模式是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实时事件处理系统。

    作用

    • 当抽象个体有两个互相依赖的层面时。封装这些层面在单独的对象内将可允许程序员单独地去变更与重复使用这些对象,而不会产生两者之间交互的问题。
    • 当其中一个对象的变更会影响其他对象,却又不知道多少对象必须被同时变更时。
    • 当对象应该有能力通知其他对象,又不应该知道其他对象的实做细节时。

    **Vue 中的观察者模式:**vwatcher 订阅 dep,dep 通知 watcher 执行 update。

  41. 写出输出结果:

    function getAge(...args) {
      console.log(typeof args); // “object”
    }
    getAge(18);
    
    解析:
    console.log(args) 得到的是数组 [18]
    数组也是对象,typeof args 得到的是“object”
    

小胖梅现场面试题

1. 单击鼠标依次触发哪些事件

在命令按钮上单鼠标左键,会依次激发如下事件:MouseDown 、 Click 、 MouseUp 事件。

2. 下面代码输出什么

var b = 10
function a(c) {
  console.log(this.b)
  console.log(c)
}

a(20)
a.call({ b: 20 }, 30)
a.apply({ b: 30 }, [40])
答案
  • a(20) // 10 20
  • a.call({ b: 20 }, 30) // 20 30
  • a.apply({ b: 20 }, [40]) // 30 40

3. 下面代码输出什么

var fullname = '李雷'
var obj = {
  fullname: '韩梅梅',
  prop: {
    fullname: '汤姆',
    getFullname: function() {
      return this.fullname
    }
  }
}

console.log(obj.prop.getFullname())
var test = obj.prop.getFullname
console.log(test()) 
答案
  • console.log(obj.prop.getFullname()) // 汤姆
  • var test = obj.prop.getFullname
  • console.log(test()) // 李雷

4. 哪一个能够实现层的隐藏?

isplay:none

5. parseInt(‘x8x8’) + parseFloat(‘8’)的结果是多少?

let res = parseInt('x8x8') 
console.log('res', res)
let res2 = parseFloat('8')
console.log('res2', res2)
console.log(res + res2)
答案
  • let res = parseInt('x8x8') console.log('res', res) 结果为NaN,注意了,NaN加减乘除任何数都得NaN
  • lparseInt('x8x8') + parseFloat('8')的结果是NaN

6. 如何监控手机网络请求?

一、Fiddler是位于客户端和服务器端之间的代理,也是目前最常用的抓包工具之一 fiddler监控手机请求。windows上用Fiddler进行抓包操作

二、mac上通过charles监控手机网络请求

三、通过postman设置代理抓取手机上的请求

四、一言以蔽之,ZanProxy 是一个基于 Node.js 的代理服务器。它专注于帮助前端开发提高开发效率

7. 当调用bar方法时,输出什么?

这是一个vue2的题目

export default {
  name: 'App',
  components: {
    Child,
    Child2,
  },
  data() {
    return {
      money: 1000,
    }
  },
  mounted() {
    this.bar()
  },
  methods: {
    foo() {
      console.log('foo')
    },
    bar() {
      setTimeout(function() {
        this.foo() // 会报错,此时的this指向的是window,window上没有foo方法
        console.log('bar')
      }, 0)
    },
  },
}

setTimeout内的函数修改为箭头函数,就不会报错:

export default {
  name: 'App',
  mounted() {
    this.bar()
  },
  methods: {
    foo() {
      console.log('foo')
    },
    bar() {
      setTimeout(() => {
        this.foo()
        console.log('bar')
      }, 0)
    },
  },
}

8. 以下哪一个选项是html5的dtd()?

A.

B.

C.

D.

答案
  • A

9. object.create()和new object()区别

**object.create():**创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。 --MDN

new object():

构造函数中的 new,是 js 中内置的。

new 做了什么?

​ 1. 创建了一个对象

​ 2. 调用构造函数,并把构造函数的 this 指向了这个对象,这个对象就是当前实例

​ 3. 对象的隐式原型指向了当前函数的显式原型(构成原型链)

​ 4. 判断构造函数的返回值,如果是基本类型,则正常返回实例化对象,如果是对象类型,则返回当前的对象 。

区别

new Object()继承内置对象Object,而Object.create()则是继承指定对象
可以通过Object.create(null) 创建一个干净的对象,也就是没有原型,而 new Object()创建的对象是 Object的实例,原型永远指向Object.prototype

10. vue css 加载顺序

加载顺序以main.js中 important 引入顺序为主,后引入样式会覆盖先引入样式

本地运行时,App以及router相关样式的权值会被提到最高

import App from './App'
// 控制App.vue文件中style的加载

import router from './router'
// 控制view和 components 中相关style的加载
本地运行时css加载顺序:
  1. 按序加载 main.js 中important 引入的样式以及组件(除却App以及router)

  2. 加载App.vue中 style以及相关组件style

  3. 加载当前页面 style 以及页面相关组件style

build(发布到线上)后:

app.xxx.css 加载顺序:按序加载 main.js 中important 引入的样式以及组件(包括App以及router)

router内部加载顺序:

  1. notfound 文件style加载

  2. 公用组件style加载

  3. 页面style以及页面组件style加载

css的顺序是“元素上的style” > “文件头上的style元素” >“外部样式文件”

  1. 样式表的元素选择器选择越精确,则其中的样式优先级越高:
    id选择器指定的样式 > 类选择器指定的样式 > 元素类型选择器指定的样式
    所以上例中,#navigator的样式优先级大于.current_block的优先级,即使.current_block是最新添加的,也不起作用。

  2. 对于相同类型选择器制定的样式,在样式表文件中,越靠后的优先级越高
    注意,这里是样式表文件中越靠后的优先级越高,而不是在元素class出现的顺序。比如.class2 在样式表中出现在.class1之后

规范:

main.js 文件引入顺序

  1. 静态css文件

  2. UI组件库

  3. App

  4. router

*全局样式尽量在App.vue中引入,在具体业务中引入global,引入多少次,app.css中就会打包多少次

CSS中link和import的加载顺序:

1、import与link的区别:
@import url(“CSS地址”) CSS专用语法
作用:@import作用于团队分工,最后合并一起
可以在.css中使用,即在一个css文件中能够引入另外的CSS文件,
或者是在标签使用,如下:

link:链接 relation:关联(可以省略)
type:类型 href: HyperText Reference超文本引用
作用:主要用来引入CSS和网页图标,指示告知搜索引擎,网页之间的关系

2、link与import加载顺序级别:link比import优先加载
加载顺序对于网站前台重构(优化网页结构,性能)有影响
第一:HTML,同时加载link,CSS和加载import的样式

HTML加载:
  1. 加载HTML-DOM结构

  2. CSS,JS

  3. 图片,多媒体

  4. 载完成后onload事件触发
    第二:加载顺序对网站的影响:
    import:import放到底部,数据先出来,然后美化
    link:CSS优先,边加载,边渲染
    link无论放到哪里都是优先加载,import受代码顺序影响

用自己的CSS建议使用link,放前面
用第三方:import,js放到底部,不影响自己网站

11. import Vue from 'vue’到底发生了什么?

在 nodejs 中,执行 import 就相当于执行了 require,而 require 被调用会用到 require.resolve 这个函数来查找包的路径,这个函数在 nodejs 中会有一个关于优先级的算法。

那 import Vue from ‘vue’ 这一句做了什么呢?

  • import Vue from ‘vue’ 解析为 const Vue = require(‘vue’)。
  • require 判断 vue 是否未 node.js 核心包,如我们常用的:path,fs 等,是则直接导入,否则继续往下走。
  • vue 非 nodejs 核心包,判断 vue 是否未 ‘/’ 根目录开头,显然不是,继续往下走。
  • vue 是否为 ‘./’、’/’ 或者 ‘…/’ 开头,显然不是,继续往下走。
  • 以上条件都不符合,读取项目目录下 node_modules 包里的包。

到此为止,import Vue from 'vue’这一句 就找到了 vue 所在的实际位置了。

12. 请输出各级id和菜单

let data = [{
  id: 1,
  name: '一级菜单',
  children: [{
    id: 2,
    name: '二级菜单',
    children: [{
      id: 3,
      name: '三级菜单'
    }]
  }]
}]
答案
  • lconsole.log(data[0].id, data[0].name) // 1 '一级菜单'
  • console.log(data[0].children[0].id, data[0].children[0].name) // 2 '二级菜单'
  • console.log(data[0].children[0].children[0].id, data[0].children[0].children[0].name) // 3 '三级菜单'

13. 如何实现浏览器内多个标签页之间的通信?

标签页之间没有办法直接通信,因此我们可以找一个中介来让标签页和中介进行通信,再让这个中介来进行消息的转发。

1.localstorage

localstorage是浏览器多个标签共用的存储空间,可以实现多标签之间的通信。

使用方式:直接在window对象上添加监听。

2.Websocket

使用 Websocket,通信的标签页连接同一个服务器,发送消息到服务器后,服务器推送消息给所有连接的客户端

可以地调用 localStorage,它会在另一个浏览上下文里被添加、修改或删除时,它都会触发一个 storage 事件,我们可以通过监听 storage 事件,控制它的值来进行页面信息之间通信。

假如能够获得对应标签页的引用,通过 postMessage 方法也可实现多个标签页之间通信。

14. 下面的代码输出什么

;(function () {
  var a = (b = 10) // var a; b = 10;
})()
console.log('1', typeof a, b)

var a = (b = 10)
console.log('2', typeof a, b)

var c = 20
console.log('3', typeof c)

d = 30
console.log('4', typeof d)
答案
  • 1 undefined 10
  • 2 number 10
  • 3 number
  • 4 number

15. 两个没有刻度的水桶,容量分别为4升和9升,如何盛出6升水?

  1. 先把9升的装满,然后用它去装满4升的,剩下的就是5升,找个空桶A装这4升水,找个空桶B装这5升水。
  2. 用4升的桶从空桶B中装满4升倒入空桶A。这时,空桶B还剩1升。
  3. 把9升的桶再装满,然后用它去装满4升的,把4升的水倒入空桶A。继续从9升水中剩下的5升装4升到4升桶中,那么此时9升桶中还剩下1升水。把这1升水倒入空桶B。
  4. 用4升桶从空桶A中装满4升,加上空桶B中的2升,全部倒入9升桶中,一共是6升。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值