没有足够的数据
(゚∀゚ )
暂时没有任何数据
Promise 回答了问题 · 2019-10-19
`
yarn redux-immutable
`
该插件返回一个combineReducers函数,把redux的combineReducers函数替换掉即可;
如下:
import { combineReducers } from 'redux-immutable';
import { reducer as user } from '../pages/user/store';
export default combineReducers({
user: user
});~~~~
` {代码...} ` 该插件返回一个combineReducers函数,把redux的combineReducers函数替换掉即可;如下: {代码...}
关注 3 回答 2
Promise 发布了文章 · 2019-07-09
,
vdom可以看作是一个对象,使用javascript模拟了DOM结构的树形结构,这个树结构包含整个DOM结构的信息;
html:
`
<div class="demo"><span>123</span></div>
`
vdom(是一个json 对象,暂时用数组表示):
`
['div', { class: 'demo' }, ['span', {}, '123']]
`
思考一:
1. 生成state 数据;
2. 解析jsx模版;
3. 数据 + 模版 生成真实DOM显示出来;
4. state 发生变化;
5. 数据 + 模版 生成真实DOM替换到原有DOM;
缺点:
生成了2次DOM模版,数据发生变化将原有DOM整个替换掉;
思考二:
1. 生成state数据;
2. 解析jsx模版;
3. 数据 + 模版生成真实DOM显示出来;
4. state 发生变化;
5. 数据 + 模版 生成真实DOM 并不替换原有DOM;?。,m n
6. 在内存中将新DOM(DocumentFragment)与原始DOM,做对比,找差异;
7. 找出对应的发生了变化;
8. 用新DOM对应的位置替换掉原始DOM发生变化的地方;
缺点:
虽然节约了整个替换的性能,但是也多了很多步骤,并且损耗了内存中做DOM比对的性能;在性能提升
上并没有得到多大的提升;
思考三:
1. 生成state数据;
2. 解析jsx模版;
3. 数据 + 模版生成真实DOM显示出来;
4. 数据 + 模版生成原始虚拟DOM(Json),来表述真实DOM;
5. state 发生变化;
6. 数据 + 模版生成新的虚拟DOM,
7. 对比原始虚拟DOM与新的虚拟DOM的差异;
8. 操作真实DOM,将差异部分进行修改;
主要是因为减少了对真实DOM的操作,以及真实DOM的对比,取而代之的是用js对象的对比,这样实现
了性能的极大的飞跃。
查看原文`<div class="demo"><span>123</span></div>`vdom(是一个json 对象,暂时用数组表示):
赞 1 收藏 1 评论 0
Promise 发布了文章 · 2019-07-09
,
vdom可以看作是一个对象,使用javascript模拟了DOM结构的树形结构,这个树结构包含整个DOM结构的信息;
html:
`
<div class="demo"><span>123</span></div>
`
vdom(是一个json 对象,暂时用数组表示):
`
['div', { class: 'demo' }, ['span', {}, '123']]
`
思考一:
1. 生成state 数据;
2. 解析jsx模版;
3. 数据 + 模版 生成真实DOM显示出来;
4. state 发生变化;
5. 数据 + 模版 生成真实DOM替换到原有DOM;
缺点:
生成了2次DOM模版,数据发生变化将原有DOM整个替换掉;
思考二:
1. 生成state数据;
2. 解析jsx模版;
3. 数据 + 模版生成真实DOM显示出来;
4. state 发生变化;
5. 数据 + 模版 生成真实DOM 并不替换原有DOM;?。,m n
6. 在内存中将新DOM(DocumentFragment)与原始DOM,做对比,找差异;
7. 找出对应的发生了变化;
8. 用新DOM对应的位置替换掉原始DOM发生变化的地方;
缺点:
虽然节约了整个替换的性能,但是也多了很多步骤,并且损耗了内存中做DOM比对的性能;在性能提升
上并没有得到多大的提升;
思考三:
1. 生成state数据;
2. 解析jsx模版;
3. 数据 + 模版生成真实DOM显示出来;
4. 数据 + 模版生成原始虚拟DOM(Json),来表述真实DOM;
5. state 发生变化;
6. 数据 + 模版生成新的虚拟DOM,
7. 对比原始虚拟DOM与新的虚拟DOM的差异;
8. 操作真实DOM,将差异部分进行修改;
主要是因为减少了对真实DOM的操作,以及真实DOM的对比,取而代之的是用js对象的对比,这样实现
了性能的极大的飞跃。
查看原文`<div class="demo"><span>123</span></div>`vdom(是一个json 对象,暂时用数组表示):
赞 1 收藏 1 评论 0
Promise 赞了文章 · 2019-06-06
个人专栏 ES6 深入浅出已上线,深入ES6 ,通过案例学习掌握 ES6 中新特性一些使用技巧及原理,持续更新中,←点击可订阅。
点赞再看,养成习惯本文
GitHub
https://github.com/qq44924588... 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料。欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西。
为了保证的可读性,本文采用意译而非直译。
async
与 await
的使用方式相对简单。 蛤当你尝试在循环中使用await
时,事情就会变得复杂一些。
在本文中,分享一些在如果循环中使用await
值得注意的问题。
对于这篇文章,假设你想从水果篮中获取水果的数量。
const fruitBasket = {
apple: 27,
grape: 0,
pear: 14
};
你想从fruitBasket
获得每个水果的数量。 要获取水果的数量,可以使用getNumFruit
函数。
const getNumFruit = fruit => {
return fruitBasket[fruit];
};
const numApples = getNumFruit('apple');
console.log(numApples); //27
现在,假设fruitBasket
是从服务器上获取,这里我们使用 setTimeout
来模拟。
const sleep = ms => {
return new Promise(resolve => setTimeout(resolve, ms))
};
const getNumFruie = fruit => {
return sleep(1000).then(v => fruitBasket[fruit]);
};
getNumFruit("apple").then(num => console.log(num)); // 27
最后,假设你想使用await
和getNumFruit
来获取异步函数中每个水果的数量。
const control = async _ => {
console.log('Start')
const numApples = await getNumFruit('apple');
console.log(numApples);
const numGrapes = await getNumFruit('grape');
console.log(numGrapes);
const numPears = await getNumFruit('pear');
console.log(numPears);
console.log('End')
}
首先定义一个存放水果的数组:
const fruitsToGet = [“apple”, “grape”, “pear”];
循环遍历这个数组:
const forLoop = async _ => {
console.log('Start');
for (let index = 0; index < fruitsToGet.length; index++) {
// 得到每个水果的数量
}
console.log('End')
}
在for
循环中,过上使用getNumFruit
来获取每个水果的数量,并将数量打印到控制台。
由于getNumFruit
返回一个promise
,我们使用 await
来等待结果的返回并打印它。
const forLoop = async _ => {
console.log('start');
for (let index = 0; index < fruitsToGet.length; index ++) {
const fruit = fruitsToGet[index];
const numFruit = await getNumFruit(fruit);
console.log(numFruit);
}
console.log('End')
}
当使用await
时,希望JavaScript暂停执行,直到等待 promise 返回处理结果。这意味着for
循环中的await
应该按顺序执行。
结果正如你所预料的那样。
“Start”;
“Apple: 27”;
“Grape: 0”;
“Pear: 14”;
“End”;
这种行为适用于大多数循环(比如while
和for-of
循环)…
但是它不能处理需要回调的循环,如forEach
、map
、filter
和reduce
。在接下来的几节中,我们将研究await
如何影响forEach
、map和filter
。
首先,使用 forEach
对数组进行遍历。
const forEach = _ => {
console.log('start');
fruitsToGet.forEach(fruit => {
//...
})
console.log('End')
}
接下来,我们将尝试使用getNumFruit
获取水果数量。 (注意回调函数中的async
关键字。我们需要这个async
关键字,因为await
在回调函数中)。
const forEachLoop = _ => {
console.log('Start');
fruitsToGet.forEach(async fruit => {
const numFruit = await getNumFruit(fruit);
console.log(numFruit)
});
console.log('End')
}
我期望控制台打印以下内容:
“Start”;
“27”;
“0”;
“14”;
“End”;
但实际结果是不同的。在forEach
循环中等待返回结果之前,JavaScrip先执行了 console.log('End')。
实际控制台打印如下:
‘Start’
‘End’
‘27’
‘0’
‘14’
JavaScript 中的 forEach
不支持 promise 感知,也支持 async
和await
,所以不能在 forEach
使用 await
。
如果在map
中使用await
, map
始终返回promise
数组,这是因为异步函数总是返回promise
。
const mapLoop = async _ => {
console.log('Start')
const numFruits = await fruitsToGet.map(async fruit => {
const numFruit = await getNumFruit(fruit);
return numFruit;
})
console.log(numFruits);
console.log('End')
}
“Start”;
“[Promise, Promise, Promise]”;
“End”;
如果你在 map
中使用 await
,map
总是返回promises
,你必须等待promises
数组得到处理。 或者通过await Promise.all(arrayOfPromises)
来完成此操作。
const mapLoop = async _ => {
console.log('Start');
const promises = fruitsToGet.map(async fruit => {
const numFruit = await getNumFruit(fruit);
return numFruit;
});
const numFruits = await Promise.all(promises);
console.log(numFruits);
console.log('End')
}
运行结果如下:
如果你愿意,可以在promise
中处理返回值,解析后的将是返回的值。
const mapLoop = _ => {
// ...
const promises = fruitsToGet.map(async fruit => {
const numFruit = await getNumFruit(fruit);
return numFruit + 100
})
// ...
}
“Start”;
“[127, 100, 114]”;
“End”;
当你使用filter
时,希望筛选具有特定结果的数组。假设过滤数量大于20的数组。
如果你正常使用filter
(没有 await),如下:
const filterLoop = _ => {
console.log('Start')
const moreThan20 = fruitsToGet.filter(async fruit => {
const numFruit = await fruitBasket[fruit]
return numFruit > 20
})
console.log(moreThan20)
console.log('END')
}
运行结果
Start
["apple"]
END
filter
中的await
不会以相同的方式工作。 事实上,它根本不起作用。
const filterLoop = async _ => {
console.log('Start')
const moreThan20 = await fruitsToGet.filter(async fruit => {
const numFruit = fruitBasket[fruit]
return numFruit > 20
})
console.log(moreThan20)
console.log('END')
}
// 打印结果
Start
["apple", "grape", "pear"]
END
为什么会发生这种情况?
当在filter
回调中使用await
时,回调总是一个promise
。由于promise
总是真的,数组中的所有项都通过filter
。在filter
使用 await
类以下这段代码
const filtered = array.filter(true);
在filter
使用 await
正确的三个步骤
map
返回一个promise 数组await
等待处理结果filter
对返回的结果进行处理const filterLoop = async _ => {
console.log('Start');
const promises = await fruitsToGet.map(fruit => getNumFruit(fruit));
const numFruits = await Promise.all(promises);
const moreThan20 = fruitsToGet.filter((fruit, index) => {
const numFruit = numFruits[index];
return numFruit > 20;
})
console.log(moreThan20);
console.log('End')
}
如果想要计算 fruitBastet
中的水果总数。 通常,你可以使用reduce
循环遍历数组并将数字相加。
const reduceLoop = _ => {
console.log('Start');
const sum = fruitsToGet.reduce((sum, fruit) => {
const numFruit = fruitBasket[fruit];
return sum + numFruit;
}, 0)
console.log(sum)
console.log('End')
}
运行结果:
当你在 reduce
中使用await
时,结果会变得非常混乱。
const reduceLoop = async _ => {
console.log('Start');
const sum = await fruitsToGet.reduce(async (sum, fruit) => {
const numFruit = await fruitBasket[fruit];
return sum + numFruit;
}, 0)
console.log(sum)
console.log('End')
}
[object Promise]14
是什么 鬼??
剖析这一点很有趣。
sum
为0
。numFruit
是27
(通过getNumFruit(apple)
的得到的值),0 + 27 = 27
。sum
是一个promise
。 (为什么?因为异步函数总是返回promises
!)numFruit
是0
.promise 无法正常添加到对象,因此JavaScript将其转换为[object Promise]
字符串。 [object Promise] + 0
是object Promise] 0
。sum
也是一个promise
。 numFruit
是14
. [object Promise] + 14
是[object Promise] 14
。解开谜团!
这意味着,你可以在reduce
回调中使用await
,但是你必须记住先等待累加器!
const reduceLoop = async _ => {
console.log('Start');
const sum = await fruitsToGet.reduce(async (promisedSum, fruit) => {
const sum = await promisedSum;
const numFruit = await fruitBasket[fruit];
return sum + numFruit;
}, 0)
console.log(sum)
console.log('End')
}
但是从上图中看到的那样,await
操作都需要很长时间。 发生这种情况是因为reduceLoop
需要等待每次遍历完成promisedSum
。
有一种方法可以加速reduce
循环,如果你在等待promisedSum之前先等待getNumFruits()
,那么reduceLoop
只需要一秒钟即可完成:
const reduceLoop = async _ => {
console.log('Start');
const sum = await fruitsToGet.reduce(async (promisedSum, fruit) => {
const numFruit = await fruitBasket[fruit];
const sum = await promisedSum;
return sum + numFruit;
}, 0)
console.log(sum)
console.log('End')
}
这是因为reduce
可以在等待循环的下一个迭代之前触发所有三个getNumFruit
promise。然而,这个方法有点令人困惑,因为你必须注意等待的顺序。
在reduce中使用wait最简单(也是最有效)的方法是
map
返回一个promise 数组await
等待处理结果reduce
对返回的结果进行处理const reduceLoop = async _ => {
console.log('Start');
const promises = fruitsToGet.map(getNumFruit);
const numFruits = await Promise.all(promises);
const sum = numFruits.reduce((sum, fruit) => sum + fruit);
console.log(sum)
console.log('End')
}
这个版本易于阅读和理解,需要一秒钟来计算水果总数。
await
调用,请使用for
循环(或任何没有回调的循环)。forEach
一起使用await
,而是使用for
循环(或任何没有回调的循环)。filter
和 reduce
中使用 await
,如果需要,先用 map
进一步骤处理,然后在使用 filter
和 reduce
进行处理。干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。
https://github.com/qq44924588...
我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!
关注公众号,后台回复福利,即可看到福利,你懂的。
点赞再看,养成习惯本文 GitHub [链接] 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料。欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西。
赞 96 收藏 74 评论 2
Promise 赞了文章 · 2019-06-06
个人专栏 ES6 深入浅出已上线,深入ES6 ,通过案例学习掌握 ES6 中新特性一些使用技巧及原理,持续更新中,←点击可订阅。
点赞再看,养成习惯本文
GitHub
https://github.com/qq44924588... 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料。欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西。
为了保证的可读性,本文采用意译而非直译。
async
与 await
的使用方式相对简单。 蛤当你尝试在循环中使用await
时,事情就会变得复杂一些。
在本文中,分享一些在如果循环中使用await
值得注意的问题。
对于这篇文章,假设你想从水果篮中获取水果的数量。
const fruitBasket = {
apple: 27,
grape: 0,
pear: 14
};
你想从fruitBasket
获得每个水果的数量。 要获取水果的数量,可以使用getNumFruit
函数。
const getNumFruit = fruit => {
return fruitBasket[fruit];
};
const numApples = getNumFruit('apple');
console.log(numApples); //27
现在,假设fruitBasket
是从服务器上获取,这里我们使用 setTimeout
来模拟。
const sleep = ms => {
return new Promise(resolve => setTimeout(resolve, ms))
};
const getNumFruie = fruit => {
return sleep(1000).then(v => fruitBasket[fruit]);
};
getNumFruit("apple").then(num => console.log(num)); // 27
最后,假设你想使用await
和getNumFruit
来获取异步函数中每个水果的数量。
const control = async _ => {
console.log('Start')
const numApples = await getNumFruit('apple');
console.log(numApples);
const numGrapes = await getNumFruit('grape');
console.log(numGrapes);
const numPears = await getNumFruit('pear');
console.log(numPears);
console.log('End')
}
首先定义一个存放水果的数组:
const fruitsToGet = [“apple”, “grape”, “pear”];
循环遍历这个数组:
const forLoop = async _ => {
console.log('Start');
for (let index = 0; index < fruitsToGet.length; index++) {
// 得到每个水果的数量
}
console.log('End')
}
在for
循环中,过上使用getNumFruit
来获取每个水果的数量,并将数量打印到控制台。
由于getNumFruit
返回一个promise
,我们使用 await
来等待结果的返回并打印它。
const forLoop = async _ => {
console.log('start');
for (let index = 0; index < fruitsToGet.length; index ++) {
const fruit = fruitsToGet[index];
const numFruit = await getNumFruit(fruit);
console.log(numFruit);
}
console.log('End')
}
当使用await
时,希望JavaScript暂停执行,直到等待 promise 返回处理结果。这意味着for
循环中的await
应该按顺序执行。
结果正如你所预料的那样。
“Start”;
“Apple: 27”;
“Grape: 0”;
“Pear: 14”;
“End”;
这种行为适用于大多数循环(比如while
和for-of
循环)…
但是它不能处理需要回调的循环,如forEach
、map
、filter
和reduce
。在接下来的几节中,我们将研究await
如何影响forEach
、map和filter
。
首先,使用 forEach
对数组进行遍历。
const forEach = _ => {
console.log('start');
fruitsToGet.forEach(fruit => {
//...
})
console.log('End')
}
接下来,我们将尝试使用getNumFruit
获取水果数量。 (注意回调函数中的async
关键字。我们需要这个async
关键字,因为await
在回调函数中)。
const forEachLoop = _ => {
console.log('Start');
fruitsToGet.forEach(async fruit => {
const numFruit = await getNumFruit(fruit);
console.log(numFruit)
});
console.log('End')
}
我期望控制台打印以下内容:
“Start”;
“27”;
“0”;
“14”;
“End”;
但实际结果是不同的。在forEach
循环中等待返回结果之前,JavaScrip先执行了 console.log('End')。
实际控制台打印如下:
‘Start’
‘End’
‘27’
‘0’
‘14’
JavaScript 中的 forEach
不支持 promise 感知,也支持 async
和await
,所以不能在 forEach
使用 await
。
如果在map
中使用await
, map
始终返回promise
数组,这是因为异步函数总是返回promise
。
const mapLoop = async _ => {
console.log('Start')
const numFruits = await fruitsToGet.map(async fruit => {
const numFruit = await getNumFruit(fruit);
return numFruit;
})
console.log(numFruits);
console.log('End')
}
“Start”;
“[Promise, Promise, Promise]”;
“End”;
如果你在 map
中使用 await
,map
总是返回promises
,你必须等待promises
数组得到处理。 或者通过await Promise.all(arrayOfPromises)
来完成此操作。
const mapLoop = async _ => {
console.log('Start');
const promises = fruitsToGet.map(async fruit => {
const numFruit = await getNumFruit(fruit);
return numFruit;
});
const numFruits = await Promise.all(promises);
console.log(numFruits);
console.log('End')
}
运行结果如下:
如果你愿意,可以在promise
中处理返回值,解析后的将是返回的值。
const mapLoop = _ => {
// ...
const promises = fruitsToGet.map(async fruit => {
const numFruit = await getNumFruit(fruit);
return numFruit + 100
})
// ...
}
“Start”;
“[127, 100, 114]”;
“End”;
当你使用filter
时,希望筛选具有特定结果的数组。假设过滤数量大于20的数组。
如果你正常使用filter
(没有 await),如下:
const filterLoop = _ => {
console.log('Start')
const moreThan20 = fruitsToGet.filter(async fruit => {
const numFruit = await fruitBasket[fruit]
return numFruit > 20
})
console.log(moreThan20)
console.log('END')
}
运行结果
Start
["apple"]
END
filter
中的await
不会以相同的方式工作。 事实上,它根本不起作用。
const filterLoop = async _ => {
console.log('Start')
const moreThan20 = await fruitsToGet.filter(async fruit => {
const numFruit = fruitBasket[fruit]
return numFruit > 20
})
console.log(moreThan20)
console.log('END')
}
// 打印结果
Start
["apple", "grape", "pear"]
END
为什么会发生这种情况?
当在filter
回调中使用await
时,回调总是一个promise
。由于promise
总是真的,数组中的所有项都通过filter
。在filter
使用 await
类以下这段代码
const filtered = array.filter(true);
在filter
使用 await
正确的三个步骤
map
返回一个promise 数组await
等待处理结果filter
对返回的结果进行处理const filterLoop = async _ => {
console.log('Start');
const promises = await fruitsToGet.map(fruit => getNumFruit(fruit));
const numFruits = await Promise.all(promises);
const moreThan20 = fruitsToGet.filter((fruit, index) => {
const numFruit = numFruits[index];
return numFruit > 20;
})
console.log(moreThan20);
console.log('End')
}
如果想要计算 fruitBastet
中的水果总数。 通常,你可以使用reduce
循环遍历数组并将数字相加。
const reduceLoop = _ => {
console.log('Start');
const sum = fruitsToGet.reduce((sum, fruit) => {
const numFruit = fruitBasket[fruit];
return sum + numFruit;
}, 0)
console.log(sum)
console.log('End')
}
运行结果:
当你在 reduce
中使用await
时,结果会变得非常混乱。
const reduceLoop = async _ => {
console.log('Start');
const sum = await fruitsToGet.reduce(async (sum, fruit) => {
const numFruit = await fruitBasket[fruit];
return sum + numFruit;
}, 0)
console.log(sum)
console.log('End')
}
[object Promise]14
是什么 鬼??
剖析这一点很有趣。
sum
为0
。numFruit
是27
(通过getNumFruit(apple)
的得到的值),0 + 27 = 27
。sum
是一个promise
。 (为什么?因为异步函数总是返回promises
!)numFruit
是0
.promise 无法正常添加到对象,因此JavaScript将其转换为[object Promise]
字符串。 [object Promise] + 0
是object Promise] 0
。sum
也是一个promise
。 numFruit
是14
. [object Promise] + 14
是[object Promise] 14
。解开谜团!
这意味着,你可以在reduce
回调中使用await
,但是你必须记住先等待累加器!
const reduceLoop = async _ => {
console.log('Start');
const sum = await fruitsToGet.reduce(async (promisedSum, fruit) => {
const sum = await promisedSum;
const numFruit = await fruitBasket[fruit];
return sum + numFruit;
}, 0)
console.log(sum)
console.log('End')
}
但是从上图中看到的那样,await
操作都需要很长时间。 发生这种情况是因为reduceLoop
需要等待每次遍历完成promisedSum
。
有一种方法可以加速reduce
循环,如果你在等待promisedSum之前先等待getNumFruits()
,那么reduceLoop
只需要一秒钟即可完成:
const reduceLoop = async _ => {
console.log('Start');
const sum = await fruitsToGet.reduce(async (promisedSum, fruit) => {
const numFruit = await fruitBasket[fruit];
const sum = await promisedSum;
return sum + numFruit;
}, 0)
console.log(sum)
console.log('End')
}
这是因为reduce
可以在等待循环的下一个迭代之前触发所有三个getNumFruit
promise。然而,这个方法有点令人困惑,因为你必须注意等待的顺序。
在reduce中使用wait最简单(也是最有效)的方法是
map
返回一个promise 数组await
等待处理结果reduce
对返回的结果进行处理const reduceLoop = async _ => {
console.log('Start');
const promises = fruitsToGet.map(getNumFruit);
const numFruits = await Promise.all(promises);
const sum = numFruits.reduce((sum, fruit) => sum + fruit);
console.log(sum)
console.log('End')
}
这个版本易于阅读和理解,需要一秒钟来计算水果总数。
await
调用,请使用for
循环(或任何没有回调的循环)。forEach
一起使用await
,而是使用for
循环(或任何没有回调的循环)。filter
和 reduce
中使用 await
,如果需要,先用 map
进一步骤处理,然后在使用 filter
和 reduce
进行处理。干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。
https://github.com/qq44924588...
我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!
关注公众号,后台回复福利,即可看到福利,你懂的。
点赞再看,养成习惯本文 GitHub [链接] 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料。欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西。
赞 96 收藏 74 评论 2
Promise 赞了文章 · 2019-06-06
以下是某场的一道面试题(大概):
1、一个停车场,车辆入场时,摄像头记录下车辆信息
2、屏幕上显示所接收的车辆的信息情况(车牌号)以及各层车位的车位余量
3、停车场一共四层车位,其中的三层都为普通车位,还有一层为特殊车位(体现在停车计费价格上面的不同)
看到第一个条件的时候,我大概知道了这道题考察的应该是面向对象相关的,三个条件看完后以及基本确认了。
说到这里,简单地说一下面向对象,至于什么是面向对象我这里就不多说了,每个人也都有自己不同的理解,包括它的三要素(封装、继承、多态)。
简单地说一下为什么我们要面向对象,为什么要使用面向对象?说一下我的理解
先抛开面向对象,首先计算机的 程序执行 无非就是 顺序、判断、循环 我们现在所有用到的语言包括c、java、php... 没有其它的, 如js中的 if...else, switch...case...就是判断,for,while就是循环,也包括一些遍历、递归也都是基于这三种方式!我们每天所产出的代码,所有的这些都是通过顺序、判断和循环这三个方式都能轻松搞定,没有第四种方式,为什么呢?因为我们通过这三种方式来解决就实现了一个结构化的问题,也就是我们通过这三个就能满足所有的需求,也就不需要第四个了这样的化对我们的程序就已经结构化了,对于编译器也能很高效的执行、解析这些东西, 外插一嘴,goto语句其实就是游离在这三个之外,会导致程序、逻辑的混乱,很少有用基本被淘汰了,不能说他因为效率低,它的效率可能会很高,但是因为脱离了结构化,所以至少在业务代码上我们极少使用它。
说到这里,也就是程勋执行我们都简化成 这个结构,而面向对象也让我们的数据也简化了即结构化(这句话也不是我说的,而是ruby语言的作者),书里说了,面向对象是为了模拟、表示事件得万物,比如人、鸟类、到具体服务员类,有具体行为的类。其实js里面向对象意义根本不拘泥于此,书上的只是为了让我们好入门好学习而已,它的意义是将零散的数据进行结构化。计算机有个毛病,结构化的程序对于它来说是最简单的!
简单解释一下,我们浏览器加载网页加载的是什么?是流,流是什么呢?其实就是字符串,虽然我们看到之后是html,css,js代码,但是代码不就是字符串嘛,那我们字符串怎么办,浏览器拿到字符串首先就是dom节点的解析然后生成生成渲染树(渲染树与dom树不同的地方在于,dom树会把所有的dom节点都展示出来,渲染树只会展示display非none的元素),都是一步步顺序执行的。
相比来说,程序也是如此了,如果我们的程序中充满了散乱的数据,那我们还怎么按照结构化的要求去操作呢?比如说,通过人做一个对象,人有外貌,行为,状态(吃、传、喝、高矮胖瘦)这么多东西可以集成在一个对象中来操作,但是如果没有面向对象,这些特征,行为也就散乱了,一旦散乱了以后还怎么管理,并且这只是一个人,就有这么多东西,再来十个,一百个,再来只狗类呢?我们的程序就成了一盘散沙了,当然这些只是举例子,具体业务还要拿来具体分析。所以面向对象不仅符合计算机所喜爱的结构化,还能让我们管理起来,维护起来,都符合结构化。
再引用双越老师的一句话:编程就应该简单&抽象。
有一篇小说里面有一段话我觉得还蛮有意思的,早期的人们之所以没有设计出来计算机,就是因为他们想的不够简单,而不是不够复杂,其实计算机很简单,不就是0和1吗。
所有说我们编程,设计时候要做到 结构化,简单+抽象,抽象完之后才能简单,简单的前提是我们应该抽象好,我认为这就是我们为什么要面向对象最主要的原因,我们之所以面向对象编程就是因为它可以抽象,可以扩展。而不是面向具体,可能这些话对于初学前端的来说不好理解,但是随着你工作时间的提升,相信很快就会理解的。
**回到面试题,我们来分析**
这个面试题,如果我们没有面向对象,面向抽象的概念, 那我们应该很快就能拿起键盘了,一个停车场,三个普通车位,一个豪华车位,一个摄像头,一个大屏幕显示器,各种各样的车,可能我们很快就能做完,‘设计完’,毕竟面向具体是真的很简单,要求什么我就做什么。。。
不过说回来,如果面试官再让你减一个车位或者增加两个豪华车位,加两个摄像头?如果按照我们之前的来写,简单。。。改一下不就行了,加一个豪华车位,加两个摄像头。。。其实到这里想必已经凉凉了。
下面我们来使用面向对象
类图这里就不再画了
首先面试题中所提到的我们都可以看成类,比如停车场是一个类吧,它里面的车位是一个类吧,摄像头,屏幕。。。我们都可以看做是类
停车场,有层位,有摄像头,屏幕,所以我们先来创建一个停车场,这一类
class Park {
constructor () {
}
}
停车场有层位,层位里面有若干车位
class Floor {
constructor (num, places) {
this.num = num
this.places = places
}
}
车位也归为一类,车位有自己的状态,有车,无车
class Place {
constructor () {
this.empty = true
}
}
车位分为普通车位,豪华车位,但是不论是普通还是豪华,他们也都有自己的状态,有车,无车,所以我们直接让这两个类继承车位类
普通车位
class NormalPlace extends Place{
constructor () {
super()
}
}
豪华车位
class SpecialPlace extends Place{
constructor () {
super()
}
}
摄像头
class Camera {
constructor () {
}
}
电脑,可以记录所有车的数据
class Computer {
constructor () {
this.symbols = {}
}
}
// 屏幕
class Screen {
}
这样一看我们所有类都创建完了,差的是来分析他们的行为,状态,联系,这里不再多做分析。只举一个简单的例子,然后上完整代码
停车场, 有层 摄像图 屏幕,有出入车时所发生的行为
class Park {
constructor (floors) {
this.floors = floors
this.camera = new Camera()
this.screen = new Screen()
}
in (car) {
}
out (car) {
}
}
我自己写了一个简单的demo,当然也没有考虑得特别细致
***完整代码***
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
body,html{
height: 100%;
}
ul,li {
list-style: none;
}
#inform {
text-align: center;
color: #9f9f9f;
font-size: 18px;
}
#inform span {
color: #ff4a3d;
}
#earch {
text-align: center;
font-size: 20px;
color: #2963ff;
}
</style>
</head>
<body>
<ul id="inform">
<li>第一层车位数量100,空余车位数量 <span data-num=1>100</span></li>
<li>第二层车位数量100,空余车位数量 <span data-num=2>100</span></li>
<li>第三层车位数量100,空余车位数量 <span data-num=3>100</span></li>
<li>第四层车位数量 20,空余车位数量 <span data-num=4> 20</span></li>
</ul>
<p style="text-align: center; color: #5eb4ff">收入 <span id="price">0</span> 元</p>
<ul id="earch">
<li>统计</li>
</ul>
<script>
let priced = document.getElementById('price')
let earch = document.getElementById('earch')
class Camera {
constructor () {
this.computer = new Computer()
}
record (car, place, floor) {
this.computer.show(car)
return {
num: car.num,
symbol: car.symbol,
inTime: new Date(),
place,
floor
}
}
}
class Computer {
constructor () {
this.symbols = {}
}
show (car) {
console.log(`车牌号为${car.num}的${car.symbol}驶入`)
if (this.symbols[car.symbol] !== undefined) {
this.symbols[car.symbol] = this.symbols[car.symbol] + 1
document.getElementById(car.symbol).innerText = this.symbols[car.symbol]
} else {
this.symbols[car.symbol] = 0
earch.innerHTML = earch.innerHTML + `<li>${car.symbol} <span id="${car.symbol}">${0}</span> 辆<li>`
}
}
}
class Screen {
reload (f, t) {
let dom = Array.prototype.slice.apply(document.querySelectorAll('#inform span'))
if (t === '1') {
dom.map(el => {
if (el.dataset.num === f + 1 + '') {
el.innerText = --el.innerText
}
})
} else {
dom.map(el => {
if (el.dataset.num === f + 1 + '') {
el.innerText = ++el.innerText
}
})
}
}
}
class Park {
constructor (floors) {
this.floors = floors
this.camera = new Camera()
this.screen = new Screen()
this.carList = {}
this.fullFloor = []
this.wait = []
}
in (car) {
let canChoice = []
let floors = this.floors
floors.map((el, index) => {
if (el.emptys > 0) {
canChoice.push(index)
}
})
if (canChoice.length === 0) {
if (Math.random() > 0.2) {
console.warn('没有找到车位,撤了')
return 'back'
} else {
console.warn(`没有找到车位,继续等待`)
this.in(car)
return 'wait'
}
}
let fi = canChoice[Math.floor(Math.random() * canChoice.length)]
let canChoicePlaceIndex = []
let places = floors[fi].places
places.map((el, index) => {
if (el.empty) {
canChoicePlaceIndex.push(index)
}
})
let pi = Math.floor(Math.random() * canChoicePlaceIndex.length)
this.carList[car.num] = this.camera.record(car, pi, fi)
places[pi].in(floors[fi])
this.screen.reload(fi, '1')
let outs = Math.ceil(Math.random() * 100000 + 5000)
setTimeout(() => {
this.out(car)
}, outs)
}
out (car) {
let place = this.floors[this.carList[car.num].floor].places[this.carList[car.num].place]
place.out(this.floors[this.carList[car.num].floor])
let price = (new Date() - this.carList[car.num].inTime)/1000 * place.price
this.screen.reload(this.carList[car.num].floor)
console.log(`车牌号为${car.num}驶出, 收费 ${price} 元`)
priced.innerText = (Number(priced.innerText) + Number(price)).toFixed(2)
delete this.carList[car.num]
}
}
class Floor {
constructor (num, places) {
this.num = num
this.places = places
this.emptys = places.length
}
inP () {
this.emptys--
}
outP () {
this.emptys++
}
}
class Place {
constructor () {
this.empty = true
}
in (floor) {
this.empty = false
floor.inP()
}
out (floor) {
this.empty = true
floor.outP()
}
}
class NormalPlace extends Place{
constructor () {
super()
this.color = 'blue'
this.price = 10
}
}
class SpecialPlace extends Place{
constructor () {
super()
this.color = 'yellow'
this.price = 60
}
}
class Car {
constructor (type, num, symbol) {
this.permit = type === '1'
this.num = num
this.symbol = symbol
}
}
// 以下部分全部为配合实现,请勿浪费时间观看
let Floors = []
for (let i = 0; i < 3; i++) {
let places = []
for (let j = 0; j < 100; j++) {
places.push(new NormalPlace())
}
Floors.push(new Floor(i + 1, places))
}
let specialPlace = []
for (let i = 0; i < 20; i++) {
specialPlace.push(new SpecialPlace())
}
Floors.push(new Floor(4, specialPlace))
let park = new Park(Floors)
var str = []
for(var i = 65; i < 91; i++){
str.push(String.fromCharCode(i))
}
let test = {
s: ['京', '冀', '黑', '蒙', '陕', '户', '津', '赣', '浣', '深', '藏', '疆' ],
n: str,
u: ['奔驰', '劳斯莱斯', '路虎', '大众', '保时泰', '保时捷', '兰博基尼', 'QQ', '丰田', '本田', '吉利', '宝马', '迈巴赫', '公交车', '火车', '坦克', '红旗', '捷豹', '法拉利', '宾利']
}
let enterTime = 100
setInterval( () => {
let number = test.s[Math.ceil(Math.random() * test.s.length) - 1] +
test.n[Math.ceil(Math.random() * test.n.length) - 1] +
Math.floor(Math.random() * 100000)
let na = test.u[Math.ceil(Math.random() * test.u.length) - 1]
let car = new Car('1', number, na)
park.in(car)
enterTime = Math.floor(Math.random() * 50)
}, enterTime)
</script>
</body>
</html>
代码可以直接粘贴到html里,直接运行打开,大家只要看各个类之间的联系就可以,具体到行为的逻辑代码只是怎么简单想怎么写就怎么写的,当然也有没考虑全面的,比如各个车位的价格应该也是动态的,为了赶时间,好多东西我都直接定死了。
抽象好了之后,这样不论是增加减少变更价钱我们都可以灵活地处理,每个类最基础的行为和方法几乎是不变得,我们只需要变容易变得抽象起来,封装起来。之后, 就变得‘简单’
欢迎一起探讨,大家共同进步!
查看原文1、一个停车场,车辆入场时,摄像头记录下车辆信息2、屏幕上显示所接收的车辆的信息情况(车牌号)以及各层车位的车位余量3、停车场一共四层车位,其中的三层都为普通车位,还有一层为特殊车位(体现在停车计费价格上面的不同)
赞 28 收藏 17 评论 7
Promise 关注了专栏 · 2019-06-06
知识,应该在它该在的地方。一个热爱代码,热爱新技术的程序熊。
关注 4999
Promise 关注了标签 · 2019-06-06
Web前端开发是从网页制作演变而来的,名称上有很明显的时代特征。在互联网的演化进程中,网页制作是Web 1.0时代的产物,那时网站的主要内容都是静态的,用户使用网站的行为也以浏览为主。2005年以后,互联网进入Web 2.0时代,各种类似桌面软件的Web应用大量涌现,网站的前端由此发生了翻天覆地的变化。网页不再只是承载单一的文字和图片,各种富媒体让网页的内容更加生动,网页上软件化的交互形式为用户提供了更好的使用体验,这些都是基于前端技术实现的。
Web前端开发是从网页制作演变而来的,名称上有很明显的时代特征。在互联网的演化进程中,网页制作是Web 1.0时代的产物,那时网站的主要内容都是静态的,用户使用网站的行为也以浏览为主。2005年以后,互联网进入Web 2.0时代,各种类似桌面软件的Web应用大量涌现,网...
关注 191211
Promise 关注了标签 · 2019-06-06
超文本标记语言(英文:HyperText Markup Language,HTML)是为“网页创建和其它可在网页浏览器中看到的信息”设计的一种标记语言。
超文本标记语言(英文:HyperText Markup Language,HTML)是为“网页创建和其它可在网页浏览器中看到的信息”设计的一种标记语言。
关注 66314
查看全部 个人动态 →
(゚∀゚ )
暂时没有
(゚∀゚ )
暂时没有
注册于 2019-06-06
个人主页被 91 人浏览
推荐关注