前端面试题(五)7.12

10 篇文章 2 订阅
7 篇文章 1 订阅

1到40亿中存在的1的个数

说明 forEach 和 map 区别

定义
  • foreEach()方法:
    针对每一个元素执行提供的函数。
  • map()方法:
    创建一个新的数组,其中每一个元素由调用数组中的每一个元素执行提供的函数得来。
区别

forEach()方法不会返回执行结果,而是undefined。也就是说,forEach()会修改原来的数组。而map()方法会得到一个新的数组并返回。

例子
制作一个数组的平方
有如下一个数组

	let arr =[1,2,3,4,5,6]

下面分别用forEach()和Map()

  1. forEach()
    注意,forEach是不会返回有意义的值的。
    我们在回调函数中直接修改arr的值。
arr.forEach((value, key) => {
 return arr[key] = value * value;
});

执行结果如下:
执行结果

  1. Map()
let list = arr.map(value => {
 return value * value;
});

执行结果如下:
执行结果

执行速度对比

在这里插入图片描述

如何使用

forEach适合于你并不打算改变数据的时候,而只是想用数据做一些事情 – 比如存入数据库或则打印出来。

let arr = ['a', 'b', 'c', 'd'];
arr.forEach((letter) => {
 console.log(letter);
});
// a
// b
// c
// d

map()适用于你要改变数据值的时候。不仅仅在于它更快,而且返回一个新的数组。这样的优点在于你可以使用复合(composition)(map(), filter(), reduce()等组合使用)来玩出更多的花样。

let arr = [1, 2, 3, 4, 5];
let arr2 = arr.map(value => value * value).filter(value => value > 10);
// arr2 = [16, 25]

我们首先使用map将每一个元素乘以它们自身,然后紧接着筛选出那些大于10的元素。最终结果赋值给arr2。

总结
  • forEach()可以做到的东西,map()也同样可以。反过来也是如此。

  • map()会分配内存空间存储新数组并返回,forEach()不会返回数据。

  • forEach()允许callback更改原始数组的元素。map()返回新的数组。

借鉴文章出处

计算出字符串中出现字次数最多的字符,出现的次数是多少?(写出过程)

第一种
// 给定的字符串
        const str = 'abcabc'
        // 统计字符串中出现次数最多的字符,出现多少次
        function statistics(str) {
            // 声明一个变量
            const obj = {}
            // 存放出现次数最多的字符
            let maxStr = ''
            // 存放出现的次数
            let max = 0
            // 遍历字符串,统计每个字符出现的次数
            for (const key of str) {
                // 判断对象中是否有这个属性
                if (obj.hasOwnProperty(key)) {
                    // 如果有这个属性
                    obj[key]++
                } else {
                    // 如果没有这个属性
                    obj[key] = 1
                }
            }
            // 遍历对象,找出出现最多的字符
            for (const key in obj) {
                // 如果当前属性的值大于 max ,则更新 max
                if (obj[key] > max) {
                    // 保存出现次数最多的字符
                    maxStr = key
                    // 保存出现次数
                    max = obj[key]
                }
            }
            // 返回出现次数最多的字符,还有次数
            return { maxStr, max }
        }

        const obj = statistics(str)

        console.log(`字符串中出现次数最多的字符是 ${obj.maxStr} ,出现了 ${obj.max}`)

第二种
// 给定的字符串
const str = 'abcabc'
// 统计字符串中出现次数最多的字符,出现多少次
function statistics(str) {
  // 声明一个变量
  const obj = {}
  // 存放出现次数最多的字符
  let maxStr = ''
  // 存放出现的次数
  let max = 0
  // 遍历字符串,统计每个字符出现的次数
  for (const key of str) {
    // 判断对象中是否有这个属性
    if (obj.hasOwnProperty(key)) {
      // 如果有这个属性
      obj[key]++
    } else {
      // 如果没有这个属性
      obj[key] = 1
    }
  }
  // 遍历对象,找出出现最多的字符
  for (const key in obj) {
    // 如果当前属性的值大于 max ,则更新 max
    if (obj[key] > max) {
      // 保存出现次数最多的字符
      maxStr = key
      // 保存出现次数
      max = obj[key]
    }
  }
  // 返回出现次数最多的字符,还有次数
  return { maxStr, max }
}

const obj = statistics(str)

console.log(`字符串中出现次数最多的字符是 ${obj.maxStr} ,出现了 ${obj.max}`)

第三种

for in语句可以用来列举出一个变量的所有成员。如果object是函数(或类即构造函数),那么将列出函数的所有静态成员;如果object是对象,那就是所有实例成员,key的类型是一个字符串,表示成员的名称。


str = 'asdasddsfdsfadsfdghdadsdfdgdasd'
    str = str.split('');
    console.log(str);
    var newStr = {};
    // 数组去重 和计算出现的次数
    str.forEach(function (item) {
        if (newStr[item]) {
            newStr[item]++;
        } else {
            newStr[item] = 1;
        }
    })
    var max=0;
    var strkey=null;
    for(var key in newStr){
         if(newStr[key]>max){
            max=newStr[key];
            strkey=key;
         }
  }
   console.log("最多的字符是" + strkey);
  console.log("出现的次数是" + max);


第四种

charAt() 方法可返回指定位置的字符。
请注意,JavaScript 并没有一种有别于字符串类型的字符数据类型,所以返回的字符是长度为 1 的字符串。


  // 统计一个字符,中出现次数最多的字符。
  var str = "zhaochucichuzuiduodezifu";
  var o = {};
  for (var i = 0, l = str.length; i < l; i++) {
    // var char = str[i];
    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);
  console.log("出现的次数是" + max);


Vue中 $set 和 $next Tick 使用场景

什么是 $next Tick

定义:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

所以就衍生出了这个获取更新后的DOM的Vue方法。所以放在Vue.nextTick()回调函数中的执行的应该是会对DOM进行操作的 js代码;

理解:nextTick(),是将回调函数延迟在下一次dom更新数据后调用,简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数,

<template>
  <div class="hello">
    <div>
      <button id="firstBtn" @click="testClick()" ref="aa">{{testMsg}}</button>
    </div>
  </div>
</template>
 
<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      testMsg:"原始值",
    }
  },
  methods:{
    testClick:function(){
      let that=this;
      that.testMsg="修改后的值";
      console.log(that.$refs.aa.innerText);   //that.$refs.aa获取指定DOM,输出:原始值
    }
  }
}
</script>
 

使用this.$nextTick()

  methods:{
    testClick:function(){
      let that=this;
      that.testMsg="修改后的值";
      that.$nextTick(function(){
        console.log(that.$refs.aa.innerText);  //输出:修改后的值
      });
    }
  }

注意:Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM,

什么时候需要用的Vue.nextTick()?
  1. Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中,原因是在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。与之对应的就是mounted钩子函数,因为该钩子函数执行时所有的DOM挂载已完成。
  created(){
    let that=this;
    that.$nextTick(function(){  //不使用this.$nextTick()方法会报错
        that.$refs.aa.innerHTML="created中更改了按钮内容";  //写入到DOM元素
    });
  },
  1. 当项目中你想在改变DOM元素的数据后基于新的dom做点什么,对新DOM一系列的js操作都需要放进Vue.nextTick()的回调函数中;通俗的理解是:更改数据后当你想立即使用js操作新的视图的时候需要使用它
<template>
  <div class="hello">
    <h3 id="h">{{testMsg}}</h3>
  </div>
</template>
 
<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      testMsg:"原始值",
    }
  },
  methods:{
    changeTxt:function(){
      let that=this;
      that.testMsg="修改后的文本值";  //vue数据改变,改变dom结构
      let domTxt=document.getElementById('h').innerText;  //后续js对dom的操作
      console.log(domTxt);  //输出可以看到vue数据修改后DOM并没有立即更新,后续的dom都不是最新的
      if(domTxt==="原始值"){
        console.log("文本data被修改后dom内容没立即更新");
      }else {
        console.log("文本data被修改后dom内容被马上更新了");
      }
    },
 
  }
}
</script>
 

正确的用法是:vue改变dom元素结构后使用vue.$nextTick()方法来实现dom数据更新后延迟执行后续代码

    changeTxt:function(){
      let that=this;
      that.testMsg="修改后的文本值";  //修改dom结构
       
      that.$nextTick(function(){  //使用vue.$nextTick()方法可以dom数据更新后延迟执行
        let domTxt=document.getElementById('h').innerText; 
        console.log(domTxt);  //输出可以看到vue数据修改后并没有DOM没有立即更新,
        if(domTxt==="原始值"){
          console.log("文本data被修改后dom内容没立即更新");
        }else {
          console.log("文本data被修改后dom内容被马上更新了");
        }
      });
    },

在使用某个第三方插件时 ,希望在vue生成的某些dom动态发生变化时重新应用该插件,也会用到该方法,这时候就需要在 $nextTick 的回调函数中执行重新应用插件的方法。

Vue.nextTick(callback) 使用原理:

原因是,Vue是异步执行dom更新的,一旦观察到数据变化,Vue就会开启一个队列,然后把在同一个事件循环 (event loop) 当中观察到数据变化的 watcher 推送进这个队列。如果这个watcher被触发多次,只会被推送到队列一次。这种缓冲行为可以有效的去掉重复数据造成的不必要的计算和DOm操作。而在下一个事件循环时,Vue会清空队列,并进行必要的DOM更新。
当你设置 vm.someData = ‘new value’,DOM 并不会马上更新,而是在异步队列被清除,也就是下一个事件循环开始时执行更新时才会进行必要的DOM更新。如果此时你想要根据更新的 DOM 状态去做某些事情,就会出现问题。。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。

借鉴文章出处

什么是 $set

调用方法: Vue.set( target , key , value)

  • target: 要更改的数据源(可以是一个对象或者数组)
  • key 要更改的具体数据 (索引)
  • value 重新赋的值
什么情况下使用 $set

由于 Vue 会在初始化实例时进行双向数据绑定,使用Object.defineProperty()对属性遍历添加 getter/setter 方法,所以属性必须在 data 对象上存在时才能进行上述过程 ,这样才能让它是响应的。如果要给对象添加新的属性,此时新属性没有进行过上述过程,不是响应式的,所以会出想数据变化,页面不变的情况。此时需要用到$set。

场景1:

通过数组的下标去修改数组的值,数据已经被修改了,但是不触发updated函数,视图不更新,

export default {
    data () {
        return {
            items: ['a', 'b', 'c']
        };
    },
    updated () {
        console.log('数据更新', this.items[0]);
    },
    methods: {
        changeItem1 () {
            this.items[0] = 'x';
            console.log(111, this.items[0]);
        },
        changeItem2 () {
            this.$set(this.items, 0, 'x');
            console.log(222, this.items[0]);
        },
    }
};

执行changeItem1, 控制台打印 111 ‘x’, 没有触发updated,视图不更新
执行changeItem1, 控制台打印 222 ‘x’, 数据更新 ‘x’; 触发updated,视图更新

场景2:

vue中检测不到对象属性的添加和删除

data() {
     userProfile: {
        name: '小明',
    }
}

想要给userProfile加一个age属性

addProperty () {
     this.userProfile.age = '12';
     console.log(555, this.userProfile);
}

执行addProperty函数时,打印如下

555 { name: '小明', age: '12'}

但是没有触发updated, 视图未更新
改成下面这种

addProperty () {
      this.$set(this.userProfile, 'age', '12');
      console.log(666, this.userProfile);
 }

再次执行, 数据发生变化, 触发updated, 视图更新;

有时你想向已有对象上添加一些属性,例如使用 Object.assign() 或 _.extend() 方法来添加属性。但是,添加到对象上的新属性不会触发更新。在这种情况下可以创建一个新的对象,让它包含原对象的属性和新的属性:

// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
简单的解释一下原理:

vue在创建实例的时候把data深度遍历所有属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。让 Vue 追踪依赖,在属性被访问和修改时通知变化。所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
当你在对象上新加了一个属性 newProperty,当前新加的这个属性并没有加入vue检测数据更新的机制(因为是在初始化之后添加的),vue.$set是能让vue知道你添加了属性, 它会给你做处理

借鉴文章出处

常用的git命令,如何解决合并冲突

git命令大全

常用的CSS布局

前言

CSS 的布局应该是 CSS 体系中的重中之重了,主要的布局方式有 table 表格布局(早期),float 浮动布局和 flex 布局,还有针对于移动端的响应式布局,不论是工作还是面试都是非常重要的知识。

table 布局
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSS 布局</title>
</head>
<style>
.container{
    height:200px;
    width: 200px;
}
.left{
    background-color: red
}
.right{
    background-color: green
}
</style>
<body>
    <table class=container>
        <tbody>
            <tr>
                <td class=left></td>
                <td class=right></td>
            </tr>
        </tbody>
    </table>
</body>
</html>

在这里插入图片描述
table 的特性决定了它非常适合用来做布局,并且表格中的内容可以自动居中,这是之前用的特别多的一种布局方式

而且也加入了 display:table;dispaly:table-cell 来支持 teble 布局。用法如下

<style>
  .table {
    display: table
  }

  .left {
    display: table-cell;
  }

  .right {
    display: table-cell
  }
</style>

<div class=table>
  <div class=left></div>
  <div class=right></div>
</div>

但是它也有自身的局限性,比如 table 比其它 html 标记占更多的字节(造成下载时间延迟,占用服务器更多流量资源),table 会阻挡浏览器渲染引擎的渲染顺序。(会延迟页面的生成速度,让用户等待更久的时间),但是某些情况下,当采用其他方式不能很好的达到自己的效果时,采用 table 布局能适应当前场景。
原文借鉴文章

flex 布局

这里就不过多阐述详细讲解文章

响应式布局
float 布局

这里就不过多阐述详细讲解文章

html5标签

这里就不过多阐述详细讲解文章

思维题

绝和顾都是莽的学生,莽的生日是X月Y日,一天他把两个学生叫到跟前,让学生猜他的生日,给予了10组备选值莽把X值告诉了绝,把Y告诉了顾,问他们生日是哪一天
2月4号 2月5号 2月18日
5月4日 5月17日
7月1日 7月5号
10月1号 10月2号 10月18日

绝说:我不知道,但顾肯定也不知道
顾说:本来我不知道,但是现在我知道了
绝说:哦,那我也知道了
请根据对话判断出莽的生日

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值