目录
1到40亿中存在的1的个数
说明 forEach 和 map 区别
定义
- foreEach()方法:
针对每一个元素执行提供的函数。 - map()方法:
创建一个新的数组,其中每一个元素由调用数组中的每一个元素执行提供的函数得来。
区别
forEach()方法不会返回执行结果,而是undefined。也就是说,forEach()会修改原来的数组。而map()方法会得到一个新的数组并返回。
例子
制作一个数组的平方
有如下一个数组
let arr =[1,2,3,4,5,6]
下面分别用forEach()和Map()
- forEach()
注意,forEach是不会返回有意义的值的。
我们在回调函数中直接修改arr的值。
arr.forEach((value, key) => {
return arr[key] = value * value;
});
执行结果如下:
- 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()?
- 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元素
});
},
- 当项目中你想在改变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命令,如何解决合并冲突
常用的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日
绝说:我不知道,但顾肯定也不知道
顾说:本来我不知道,但是现在我知道了
绝说:哦,那我也知道了
请根据对话判断出莽的生日