小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
本文同时参与掘力星计划,赢取创作大礼包,挑战创作激励金
前言
前期回顾
如何写好JavaScript肯定是每一个前端工程师一直以来要思考的问题,老师告诉我们一些写好JavaScript的原则,同时也教了一些我们如何写好JavaScript的技巧,今天来继续跟着老师学JavaScript吧!
这是一段真实的代码
其实这是spriteJs 框架的一段真实的代码,可以翻到131行看一下!
其实这是spriteJs 框架的一段真实的代码,可以翻到131行看一下
spriteJs 是一款由 360 奇舞团开源的跨终端 canvas 绘图框架,可以基于 canvas 快速绘制结构化 UI、动画和交互效果,是跨平台的2D绘图对象模型库,它能够支持web、node、桌面应用和微信小程序的图形绘制和实现各种动画效果。
写代码最关注什么?
当年的Left-pad事件
function leftpad(str, len, ch){
str = String(str);
var i = -1;
if(!ch && ch !== 0) ch = "";
len = len - str.length;
while(++i < len){
str = ch + str;
}
return str;
}
事件本身有很多槽点
-
NPM 模块粒度
-
代码风格
-
代码质量/效率
-
代码更简洁
-
效率提升 Repeat polyfill/MDN
-
性能更好
- 优化一下
交通灯:状态切换
实现一个切换多个交通灯状态切换的功能
版本一
const traffic = document.getElementById('traffic');
(function reset(){
traffic.className = 's1';
setTimeout(function(){
traffic.className = 's2';
setTimeout(function(){
traffic.className = 's3';
setTimeout(function(){
traffic.className = 's4';
setTimeout(function(){
traffic.className = 's5';
setTimeout(reset, 1000)
}, 1000)
}, 1000)
}, 1000)
}, 1000);
})();
版本二
const traffic = document.getElementById('traffic');
const stateList = [
{state: 'wait', last: 1000},
{state: 'stop', last: 3000},
{state: 'pass', last: 3000},
];
function start(traffic, stateList){
function applyState(stateIdx) {
const {state, last} = stateList[stateIdx];
traffic.className = state;
setTimeout(() => {
applyState((stateIdx + 1) % stateList.length);
}, last)
}
applyState(0);
}
start(traffic, stateList);
版本三
const traffic = document.getElementById('traffic');
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function poll(...fnList){
let stateIndex = 0;
return async function(...args){
let fn = fnList[stateIndex++ % fnList.length];
return await fn.apply(this, args);
}
}
async function setState(state, ms){
traffic.className = state;
await wait(ms);
}
let trafficStatePoll = poll(setState.bind(null, 'wait', 1000),
setState.bind(null, 'stop', 3000),
setState.bind(null, 'pass', 3000));
(async function() {
// noprotect
while(1) {
await trafficStatePoll();
}
}());
版本四
const traffic = document.getElementById('traffic');
function wait(time){
return new Promise(resolve => setTimeout(resolve, time));
}
function setState(state){
traffic.className = state;
}
async function start(){
//noprotect
while(1){
setState('wait');
await wait(1000);
setState('stop');
await wait(3000);
setState('pass');
await wait(3000);
}
}
start();
判断是否是4的幂
版本一
function isPowerOfFour(num) {
num = parseInt(num);
while(num > 1) {
//不能被4整除的话,返回false
if(num % 4) return false;
num /= 4;
}
return true;
}
版本二
function isPowerOfFour(num) {
num = parseInt(num);
while(num > 1) {
//判断二进制数的末两位,是00的话就是4的倍数
if(num & 0b11) return false;
//num/4就相当于右移两位
num >>>= 2;
}
return true;
}
版本三
function isPowerOfFour(num) {
num = parseInt(num);
return num > 0 &&
//num与num-1按位相与得到0,这是2的幂
(num & (num -1)) === 0 &&
//且没有奇数个0,只有偶数个0
(num & 0xAAAAAAAA) === 0;
}
版本四
function isPowerOfFour(num) {
//转换成一个二进制的字符串
num = parseInt(num).toString(2);
//然后用正则表达式匹配一下
return /^1(?:00)*$/.test(num);
}
洗牌
const cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function shuffle(cards) {
return [...cards].sort(() => Math.random() > 0.5 ? -1 : 1);
}
console.log(shuffle(cards));
正确性
const cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function shuffle(cards) {
return [...cards].sort(() => Math.random() > 0.5 ? -1 : 1);
}
const result = Array(10).fill(0);
for(let i = 0; i < 1000000; i++) {
const c = shuffle(cards);
for(let j = 0; j < 10; j++) {
result[j] += c[j];
}
}
console.log(result);
版本一
每次都随机抽出一张牌,把它换到最后的位置去。
const cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function shuffle(cards) {
const c = [...cards];
for(let i = c.length; i > 0; i--) {
const pIdx = Math.floor(Math.random() * i);
[c[pIdx], c[i - 1]] = [c[i - 1], c[pIdx]];
}
return c;
}
const result = Array(10).fill(0);
for(let i = 0; i < 10000; i++) {
const c = shuffle(cards);
for(let j = 0; j < 10; j++) {
result[j] += c[j];
}
}
console.log(shuffle(cards));
console.log(result);
版本二
const cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function * draw(cards){
const c = [...cards];
for(let i = c.length; i > 0; i--) {
const pIdx = Math.floor(Math.random() * i);
[c[pIdx], c[i - 1]] = [c[i - 1], c[pIdx]];
yield c[i - 1];
}
}
const result = draw(cards);
console.log([...result]);
分红包
版本一
每次将金额分成两部分,总会有大的部分和小的部分,我们挑选出最大的一块进行划分,然后将目前的部分再挑出最大的一块进行划分。这个方法分出的红包相对均匀。
function generate(amount, count){
let ret = [amount];
while(count > 1){
//挑选出最大一块进行切分
let cake = Math.max(...ret),
idx = ret.indexOf(cake),
part = 1 + Math.floor((cake / 2) * Math.random()),
rest = cake - part;
ret.splice(idx, 1, part, rest);
count--;
}
return ret;
}
版本二
假设将100元切9刀,有9999个位置去切分,则这个问题可以转换成洗牌问题,切分位置从1号到9999号,然后将这9999个数随机洗牌,然后分出10个位置,就切出来了。后面位置-前面位置得到切分出的大小。
function * draw(cards){
const c = [...cards];
for(let i = c.length; i > 0; i--) {
const pIdx = Math.floor(Math.random() * i);
[c[pIdx], c[i - 1]] = [c[i - 1], c[pIdx]];
yield c[i - 1];
}
}
function generate(amount, count){
if(count <= 1) return [amount];
const cards = Array(amount - 1).fill(0).map((_, i) => i + 1);
const pick = draw(cards);
const result = [];
for(let i = 0; i < count; i++) {
result.push(pick.next().value);
}
result.sort((a, b) => a - b);
for(let i = count - 1; i > 0; i--) {
result[i] = result[i] - result[i - 1];
}
return result;
}
结语
- 如以上有错误的地方,请在评论区中指出,谢谢! 小可爱们看完点个赞再走一走~~