本次蓝桥杯省赛在4月13号结束,并在省赛中取得了一等奖的成绩,题目放在文末。本次记录主要是复盘一下知识点,引用官方题解,如果大佬们有更好的方法,欢迎交流学习~
我之前留意到一位UP主推荐的这本书,觉得挺吸引人的,于是入手了一本。该书出自外国作者之手并已被译成中文。阅读之后,我发现它的确颇有价值,特别是它为我提供了全新的视角去理解这门语言,尤其是在函数式编程和异步编程领域,让我收获了不一样的见解和领悟。
1、智能停车系统
第一题是“签到题”,也就是证明你来参加过比赛的,
考察的是css中的
作用于父元素:
display:flex;
justify-content:center; /*沿着轴的方向布局方式(居中)*/
flex-direction:column; /*改变轴的方向为垂直方向:*/
align-item:center; /*交叉轴的排列方式(居中)*/
flex-warp:warp; /*换行*/
子元素
flex-shrink:0; /*不允许被挤压*/
flex:flex-grow flex-shrink flex-basis; /*缩写形式*/
order:1; /*改变顺序*/
因此本题的答案只需要在最后三行添加代码即可
.cars {
position: absolute;
z-index: 2;
display: flex;
width: 600px;
height: 600px;
flex-direction: column;
/* TODO: 请在下方编写题目代码,不要更改其他选择器里的代码 */
flex-wrap: wrap;
align-content:space-between;
justify-content:space-between;
}
,
并且文档中的提示均已给出,直接使用space-around即可实现
2、布局切换
js中较为经典的题目了,同样也是签到题。“干掉他人,留下自己”是这道题的精髓,也就是当按钮被点击的时候,就取消所有样式,再给自己添加上这个样式
option.addEventListener('click', function () {
for (const otherOption of layoutOptions) {
// 移除其他选项的 active 类
otherOption.classList.remove('active');
}
// TODO:待补充代码
this.classList.add('active'); // 为当前选项添加active类
}
3、产品 360 度展示
开始上点难度了,考察的是Promise以及async,await
Promise的出现是解决回调地狱的问题,而async则是Promise和generator结合的语法糖,使得异步编程同步化 ,在执行同步操作的时候也不会造成阻塞。
const pipeline = async (initialValue, sequence) => {
let res = initialValue;
for (const fn of sequence) {
res = await fn(res);
}
return res;
};
4、多表单验证
考察的是Elementplus的表单验证 ,对于我来说,最难受的就是做布局的题目了。
这个题我当时想着后面做,结果发现没时间了。
const validateName = (rule, value, callback) => {
if (value === "") {
callback(new Error("请输入姓名"));
} else {
const reg = /[^\u4e00-\u9fa5]/g;
if (reg.test(value)) {
callback(new Error("只能输入汉字"));
}
callback();
}
};
// TODO-3:书写表单校验规则,并绑定到对应表单上
const rules = reactive({
name: [
{ required: true, message: "请输入姓名", trigger: "blur" },
{ validator: validateName, trigger: "blur" },
],
sex: [{ required: true, message: "请选择性别", trigger: "change" }],
age: [{ required: true, message: "请输入年龄", trigger: "blur" }],
isCompetition: [
{ required: true, message: "请选择是否参加过编程比赛", trigger: "change" },
],
isEntrepreneurship: [
{ required: true, message: "请选择是否有过创业经历", trigger: "change" },
],
});
5、找回连接的奇幻之旅
考察了闭包函数、剩余参数、call、apply以及this的指向问题
这里给大家辨析以下call和apply以及bind方法的区别,
call和apply的区别在于第二个参数前者接收的是单个参数(从第二个参数开始,你可以直接列举出需要传递给函数的参数,它们会按照顺序传递。),而后者接收的是一个数组,两个方法都会让函数能够立即执行。
bind方法第二个参数接收的方式与call相同,但是函数不会立即执行。
我理解的闭包函数特点有:
1、让内部函数访问其所在外部函数的作用域中的变量,即使外部函数已经执行完毕,只要内部函数还被引用,这些外部变量就不会被垃圾回收机制回收。
2、维持外部函数局部变量的持久性。即使外部函数执行结束,由于内部函数持有对外部变量的引用,这些变量的值可以跨函数调用被保留下来
function resetableOnce(fn) {
let done = false; // 标记函数是否已执行
let result; // 保存函数执行的结果
/**
* 保证只执行一次的函数
* @returns {Any} 返回函数fn的执行结果
*/
function runOnce(...ags) {
if (!done) {
// 如果之前没有执行过,则执行函数fn,并保存结果
result = fn.apply(this, ags);
done = true; // 标记为已完成,确保之后不再执行
}
// 返回之前执行的结果
return result;
}
/**
* 重置函数的执行状态
*/
function reset() {
done = false; // 重置done为false,允许函数再次执行
}
// 返回控制对象
return { runOnce, reset };
}
6、tree 命令助手
考察知识点:Node.js递归.fs操作
引用官方题解
function generateTree(dirPath) {
// 读取目录下的所有文件和文件夹
const files = fs.readdirSync(dirPath);
const tree = [];
files.forEach(file => {
const filePath = path.join(dirPath, file);
const isDirectory = fs.statSync(filePath).isDirectory();
if (isDirectory) {
// 如果是目录,则递归生成子目录的文件树
const subtree = generateTree(filePath);
tree.push({ name: file, children: subtree });
} else {
// 如果是文件,则直接添加到文件树
tree.push({ name: file });
}
});
return tree;
}
7、Github 明星项目统计
vue3的双向绑定、
array的原型方法,filter、map
由于JavaScript单线程的特性,为了不阻塞用户界面和其他任务的执行,它使用异步处理机制来处理耗时操作,因此大量的使用回调函数来处理问题,在js中函数是“一等公民”,也就是能够像变量一样当作参数来传递。而箭头函数与普通函数的区别则在于箭头函数不绑定自己的this值,它会捕获其所在上下文的this值作为自己的this。箭头函数其实就是其它编程语言的lambda表达式。
<select name="language" id="language" @change="changeHandle" v-model="language">
<option v-for="language in languages" :value="language">{{language}}</option>
</select>
<script>
setup() {
const changeHandle = () => {
let newData = chartData.value.filter(item => item.language === language.value);
if (language.value === 'All') {
newData = chartData.value;
}
newData = newData.slice(pageStart.value - 1, pageEnd.value);
xData.value = newData.map(item => item.name);
yData.value = newData.map(item => item.stars);
initChart();
};
}
</script>
8、小蓝驿站
主要还是考察vue3的数据处理以及字符串的原型方法。js是一门面向对象的语言,它实现面向对象的方式与java、python、php等编程语言不同,前者是基于原型实现,后者是基于类实现,在ES6中虽然引入了class的概念,但是它本质上还是原型的语法糖。
// 目标 1
<ul class="contacts-list">
<!-- 使用 Vue 的 v-for 指令循环渲染 sortedContacts 中的每个联系人组 -->
<li
class="contacts-group"
v-for="(group, groupIndex) in sortedContacts"
:key="groupIndex"
>
<!-- 如果联系人组中有联系人,则显示该组的标题 -->
<div v-if="group.contacts.length > 0" class="contacts-group-title">
{{ group.letter }}
</div>
<!-- 使用 v-for 指令循环渲染每个联系人 -->
<ul>
<li
class="contact-item"
v-for="(contact, contactIndex) in group.contacts"
:key="contactIndex"
>
<!-- 显示联系人名字 -->
<span class="contact-name">{{ contact.name }}</span>
<button class="del-contact-button">删除</button>
</li>
</ul>
</li>
</ul>
<script>
setup() {
// 目标 2
const addContact = () => {
// TODO:待补充代码 目标 2
if (newContact.value.trim() !== "") {
// 获取新联系人名字的首字母并转为大写
const firstLetter = newContact.value[0].toUpperCase();
// 查找是否有相同首字母的联系人组
const groupIndex = contacts.value.findIndex(
(group) => group.letter === firstLetter
);
if (groupIndex > -1) {
// 如果找到了相同首字母的联系人组,就添加到该组
contacts.value[groupIndex].contacts.push({ name: newContact.value });
} else {
// 如果没有找到相同首字母的联系人组,就新建一个组,并添加到联系人列表
const newGroup = {
letter: firstLetter,
contacts: [{ name: newContact.value }],
};
contacts.value.push(newGroup);
}
}
// TODO:END
// 添加完成清空联系人输入框
newContact.value = "";
};
}
</script>
9、 商品浏览足迹
考察知识点:
- axios
- 对象去重
- Date对象
window.onload = async ()=> {
const res = await axios("./js/data.json");
const newData = getData(res.data);
showData(newData);
};
/**
* 将同一天浏览的相同商品去重并作为数组返回
* @param {Array} defaultData json 文件中读取到的原始数据
* @returns 去重后的数据,数据结构与 defaultData 相同
*/
const removeDuplicates = defaultData => {
let newData = [];
// TODO:在下面补充代码,最终完成该函数封装
defaultData.forEach((defaultGoods) => {
const defaultDate = new Date(defaultGoods.viewed_on);
const dD = `${defaultDate.getFullYear()}-${
defaultDate.getMonth() + 1
}-${defaultDate.getDate()}`;
defaultGoods.date = dD;
let hadThisGoods = false;
newData.forEach((tmpGoods) => {
const tmpDate = new Date(tmpGoods.viewed_on);
const tD = `${tmpDate.getFullYear()}-${
tmpDate.getMonth() + 1
}-${tmpDate.getDate()}`;
if (tmpGoods.id == defaultGoods.id && tD == dD) {
hadThisGoods = true;
}
});
if (!hadThisGoods) {
newData.push(defaultGoods);
}
});
return newData;
}
/**
* 将去重后的数据根据字段 viewed_on(格式化为 YYYY-MM-DD) 降序排序
* @param {*} defaultData 去重后的数据
* @returns 根据字段 viewed_on(格式化为 YYYY-MM-DD) 降序排序
*/
const sortByDate = defaultData => {
let newData = [];
// TODO:在下面补充代码,最终完成该函数封装
function sortByProperty(property, asc) {
return function (value1, value2) {
let a = new Date(value1[property]);
let b = new Date(value2[property]);
// 默认升序
if (asc == undefined) {
return a - b;
} else {
return asc ? a - b : b - a;
}
};
}
newData = defaultData.sort(sortByProperty("date", false));
return newData;
}
/**
* 将去重排序后的所有商品数据,作为一个对象存储并返回,
* 该对象的所有 `key` 为浏览商品的当天日期(即,字段 viewed_on 格式化为 YYYY-MM-DD),
* `value` 为当天浏览的所有商品(以数组形式表现)。
* @param {Array} defaultData 重后的所有商品数据
* @returns
*/
const transformStructure = defaultData => {
let newData = {};
// TODO:在下面补充代码,最终完成该函数封装
// 月份和日期 不足10的前面补0
defaultData.forEach(item=>{
let date=new Date(item.date) ;
let y = date.getFullYear()
let m = date.getMonth()+1
m=m<10?'0'+m:m
let d = date.getDate();
d=d<10?'0'+d:d
item.date=`${y}-${m}-${d}`;
})
newData = defaultData.reduce((aD, item) => {
console.log(item);
if (!aD[item.date]) {
aD[item.date] = [];
aD[item.date].push(item);
} else {
if (!aD[item.date].includes(item.date)) {
aD[item.date].push(item);
}
}
return aD;
}, {});
return newData;
}
10、NPM Download Simulator
获取数据类型、 promise.race
function myRace(iterable) {
return new Promise((resolve, reject) => {
if (!(Symbol.iterator in Object(iterable))) {
reject(
new TypeError(
`${Object.prototype.toString
.call({ iterable })
.slice(-8, -1)
.toLocaleLowerCase()} is not iterable`
)
);
return;
}
const promises = Array.from(iterable);
let resolvedOrRejected = false;
for (const promise of promises) {
Promise.resolve(promise).then(
(value) => {
if (!resolvedOrRejected) {
resolvedOrRejected = true;
resolve(value);
}
},
(reason) => {
if (!resolvedOrRejected) {
resolvedOrRejected = true;
reject(reason);
}
}
);
}
});
}
版权属于:龙辉博客
本文链接:https://blog.eirds.cn/440.html
如果没有特别声明则为本博原创。转载时须注明出处及本声明!