1.字符串字符统计
题目要求
完善函数 count 的功能。
- 函数
count会统计传入的字符串其每个字符的的个数,并返回一个结果对象(Object)。 - 属性名称(key)为统计字符(区分大小写,即 a 不等于 A),属性值(value)为统计字符的个数。
如 count('javaScript') 会返回一个统计结果对象,该对象表示 javaScript 的字符统计结果。
count('javaScript'); // 返回结果为 {j: 1, a: 2, v: 1, S: 1, c: 1, r: 1, i: 1, p: 1, t: 1}
let len = str.length;
let obj = {};
for (let i = 0; i < len; i++) {
let char = str.charAt(i);
if (obj[char]) {
obj[char]++;
}
else {
obj[char] = 1;
}
}
return obj;
}
2.字符串转换为驼峰格式
本练习中我们将练习使用字符串的一些常用方法如:
分割字符串 split
split() 方法可以把字符串分割为字符串数组。如下所示:
"2:3:4:5".split(":") // 将返回 ["2", "3", "4", "5"]
"|a|b|c".split("|") // 将返回 ["", "a", "b", "c"]
截取字符串 substring
substring() 方法用于提取字符串中介于两个指定下标之间的字符。如下所示:
var str = 'Hello World!';
console.log(str.substring(3)); // 将返回 lo world!
字符串转换大写 toLocaleUpperCase()
toLocaleUpperCase() 方法用于把字符串转换为大写。如下所示:
var str = 'Hello World!';
console.log(str.toLocaleUpperCase()); // 将返回 HELLO WORLD!
题目要求
完善函数 convertToCamelCase 的功能。函数 convertToCamelCase 会转换传入的字符串参数 string 为驼峰格式,并返回转换后的字符串。具体要求如下:
- 参数 string 是以中划线(-)连接单词的字符串,需将第二个起的非空单词首字母转为大写,如 -webkit-border-radius 转换后的结果为 webkitBorderRadius。
- 返回转换后的字符串
如:
// background-image 转换后结果为 backgroundImage
var str1 = convertToCamelCase('background-image');
// -webkit-border-radius 转换后结果为 webkitBorderRadius
var str2 = convertToCamelCase('-webkit-border-radius');
这里 str1 和 str2 的值分别为 backgroundImage 和 webkitBorderRadius 。
思路:
- 去除参数字符串的中划线连接符,在这里使用到字符串分割方法 split
- 获取去除中划线连接符的单词数组,并保存在一个新的变量
strArr - 需要判断该数组第一项是否为空,如果为空则去掉。如
'-a-b-c'.split('-'); // 返回的是 ['', a, b, c] 第一项便为空字符串 - 使用循环语句,设置起始坐标
i = 1即只从第二个单词开始来进行处理 - 将每个单词的首字母调用字符串大写方法 toUpperCase
- 将更改的首字母字符和单词后面的字符再次拼接起来,成为一个新的单词字符串
- 循环后将单词数组拼接成一个完整的字符串,使用了数组的方法 join
参考答案如下:
/**
* 转换参数字符串为驼峰格式
* @param {String} str
*/
function convertToCamelCase(str) {
// 去除中划线分隔符获取单词数组
var strArr = str.split('-');
// 如果第一个为空,则去掉
if(strArr[0] === '') {
strArr.shift();
}
// 遍历第二个单词到最后一个单词,并转换单词首字母为答谢
for(var i = 1, len = strArr.length; i < len; i++){
// 如果不为空,则转成大写
if(strArr[i] !== '') {
strArr[i] = strArr[i][0].toUpperCase() + strArr[i].substring(1);
}
}
return strArr.join('');
}
如果了解正则表达式的同学可以这样写:
/**
* 转换参数字符串为驼峰格式
* @param {String} str
*/
function convertToCamelCase(str) {
return str.replace(/-[a-z]/g , function(a, b){
return b == 0 ? a.replace('-','') : a.replace('-','').toUpperCase();
});
}
3.数字数组去重
题目要求
完善函数 unique 的功能。
- 1、函数 unique 会对传入的参数数组进行去重
- 2、返回一个去重后的新的数组
如下所示:
unique([10,2,3,4,2,10]); // 返回结果为 [10,2,3,4]
(1)使用对象辅助记录数字是否重复
思路:
- 创建一个新的数组存放结果
- 创建一个空对象记录数字是否出现过
如下所示:
/**
* 对传入的参数数组进行去重
* @param {Array} numbers
*/
function unique(numbers) {
// 创建一个新的数组
var resultArr = [];
var numbersObj = {};
var i = 0;
for(; i < numbers.length; i++){
// 如果该数字还没见过,则放进新数组中
if(!numbersObj[numbers[i]]){
resultArr.push(numbers[i]);
numbersObj[numbers[i]] = 1;
}
}
return resultArr;
}
(2)循环遍历判断
思路:
- 构建一个新的数组存放结果
- 每次从原数组抽出一个数字,并且循环遍历结果数组,看是否已经存在相同的数组
- 如果没有重复,则存进结果数组
如下所示:
/**
* 对传入的参数数组进行去重
* @param {Array} numbers
*/
function unique(numbers) {
// 创建一个结果数组
var resultArr = [];
// 循环遍历原数组,每次抽出一个数字进行判断
for(var i = 0; i < numbers.length; i++){
// 标识符:是否重复
var isRepeat = false;
// 循环遍历结果数组,进行对比
for(var j = 0; j < resultArr.length; j++){
if(numbers[i] == resultArr[j]){
isRepeat = true;
// 如果发现重复,则不需进行后面判断了
break;
}
}
// 如果没重复,则存进结果数组
if(!isRepeat){
resultArr.push(numbers[i]);
}
}
return resultArr;
}
4.辗转相除法求最大公约数
题目背景
约数
如果数 a 能被数 b 整除,a 就叫做 b 的倍数,b 就叫做 a 的约数。
最大公约数
最大公约数就是两个数中,大家都能相约且最大的数。
辗转相除法
辗转相除法又名欧几里得算法(Euclidean algorithm),目的是求出两个正整数的最大公约数。它是已知最古老的算法,其可追溯至公元前300年前。
这条算法基于一个定理:两个正整数 a 和 b(a 大于 b),它们的最大公约数等于 a 除以 b 的余数 c 和 较小数 b 之间的最大公约数。
算法计算过程是这样的:
- 2个数相除,得出余数
- 如果余数不为0,则拿较小的数与余数继续相除,判断新的余数是否为0
- 如果余数为0,则最大公约数就是本次相除中较小的数。
比如数字 25 和 10 ,使用辗转相除法求最大公约数过程如下:
- 25 除以 10 商 2 余 5
- 根据辗转相除法可以得出,25 和 10 的最大公约数等于 5 和 10 之间的最大公约数
- 10 除以 5 商 2 余 0, 所以 5 和 10 之间的最大公约数为 5,因此25 和 10 的最大公约数为 5
题目要求
完善函数 gcd 的功能。函数 gcd 会计算并返回传入的两个正整数参数之间最大的公约数
如下所示:
gcd(30,3); // 返回结果为 3
gcd(12, 24); // 返回结果为 12
gcd(111, 11); // 返回结果为 1
实现辗转相除法通常有两种思路,分别如下
(1)使用循环实现
/**
* 函数 gcd 会计算并返回传入的两个正整数参数之间最大的公约数
* @param {Number} number1
* @param {Number} number2
*/
function gcd(number1, number2){
// 创建一个表示余数的变量
var remainder = 0;
// 通过循环计算
do {
// 更新当前余数
remainder = number1 % number2;
// 更新数字1
number1 = number2;
// 更新数字1
number2 = remainder;
} while(remainder !== 0);
return number1;
}
(2)使用函数递归
如下所示:
/**
* 对传入的参数数组进行去重
* @param {Number} number1
* @param {Number} number2
*/
function gcd(number1, number2) {
if (number2 == 0) {
return number1;
} else {
return gcd(number2, number1 % number2);
}
}
更多阅读
5.为一组按钮绑定事件
题目要求
提供的代码是一个编辑器组件,但功能还不完善,需要为该编辑器的工具栏按钮绑定相关事件(可使用 jQuery ),具体要求如下:
1、为 #js-add-fontsize 元素绑定 click 事件
当事件触发后改变编辑器内文本字体为 20px。
2、为 #js-change-bg 元素绑定 click 事件
当事件触发后改变编辑器的背景颜色色值为 "#6b6b6b", 文字颜色为 "#fff"。
3、为 #js-toggle-opacity 按钮元素绑定 click 事件
当事件触发后,如果 #editor 元素透明度( opacity )大于 0, 则设置 #editor 元素透明度为 0,否则设置 #editor 元素透明度为 1。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>编写一个 jQuery 事件监听器</title>
<style>
#editor {
width: 90%;
display: block;
height: 300px;
margin: 20px auto;
padding: 10px;
font-size: 14px;
line-height: 1.5;
background-color: '#fff';
color: '#000';
}
#operation {
text-align: center
}
button {
background: #fff;
color: #000;
border: 2px solid #000;
padding: 10px;
border-radius: 4px;
}
</style>
</head>
<body>
<!-- 请在index.js文件中完成练习 -->
<textarea id="editor">
我是小郭
</textarea>
<div id="operation">
<button id="js-add-fontsize">编辑器文字变大</button>
<button id="js-change-bg">编辑器颜色变暗</button>
<button id="js-toggle-opacity">显示/隐藏编辑器</button>
</div>
<!-- 引入jQuery-->
<script src="https://7.url.cn/edu/jslib/jquery/1.9.1/jquery.min.js"></script>
</body>
</html>
(1)在每个按钮元素上添加事件监听器
思路:
- 获取编辑器元素和按钮元素
- 给每个按钮写一次事件绑定
// 获取编辑器元素
var $editor = $('#editor');
/*
* 1、为 #js-add-fontsize 元素绑定 click 事件
* 当事件触发后改变编辑器内文本字体增大 2 px,如原来字体大小为 12 px,点击 #button1 则变成 14px
*/
$('#js-add-fontsize').click(function() {v
$editor.css('font-size', '20px');
});
/*
* 2、为 #js-change-bg 元素绑定 click 事件
* 当事件触发后改变编辑器的背景颜色色值为 "#6b6b6b", 文字颜色为 "#fff"
*/
$('#js-change-bg').click(function() {
$editor.css({
'background-color': '#6b6b6b',
'color': '#fff'
});
});
/*
* 3、为 #js-toggle-visibility 按钮元素绑定 click 事件
* 当事件触发后,如果 #editor 元素透明度( opactity )大于 0, 则设置 #editor 元素透明度为1,否则设置 #editor 元素透明度为0
*/
$('#js-toggle-opacity').click(function() {
if ($editor.css('opacity') > 0) {
$editor.css('opacity', 0);
} else {
$editor.css('opacity', 1);
}
});
(2)使用事件代理(委托)
思路:
- 获取编辑器元素和按钮父元素
#operation - 将按钮的事件委托到按钮父元素,通过按钮父元素来分发请求
需了解的是:事件委托是事件冒泡的一个应用,将事件的监听和执行操作完全委托给了其父节点,可以减少子元素绑定事件的个数,也不必担心子节点被替换后可能需要进行重新的事件绑定。如果页面中含有大量元素需要绑定事件,这样做会减少事件绑定数量,同时提高页面性能。
在事件绑定上,jQuery 提供了一种更通用的函数:
on(events,[selector],[data],fn)
参数:
- events:一个或多个用空格分隔的事件类型和可选的命名空间,如"click"或"keydown.myPlugin" 。
- selector[可选]:一个选择器字符串用于过滤器的触发事件的选择器元素的后代。如果选择的< null或省略,当它到达选定的元素,事件总是触发。
- data[可选]:当一个事件被触发时要传递event.data给事件处理函数。
- fn:该事件被触发时执行的函数。 false 值也可以做一个函数的简写,返回false。
将上述的功能改用on函数实现
下面所示:
var $editor = $('#editor');
$('#operation').on('click', 'button', function() {
// 获取button的id
var btnId = $(this).attr('id');
switch(btnId) {
case 'js-add-fontsize':
$editor.css('font-size', '20px');
break;
case 'js-change-bg':
$editor.css({
'background-color': '#6b6b6b',
'color': '#fff'
});
break;
case 'js-toggle-opacity':
if ($editor.css('opacity') > 0) {
$editor.css('opacity', 0);
} else {
$editor.css('opacity', 1);
}
}
});
6.实现todoList
题目要求
在提供的 HTML 和 CSS 的基础上,补充todoList的功能逻辑 (可使用 jQuery),具体要求如下:
- 实现点击添加任务按钮时,获取输入框内容,如果输入框不为空则添加一个新的任务到任务列表中的功能
- 实现点击任务 item 元素时,被点击任务元素如果带有类名 "checked",则去除类名 "checked", 否则增加类名 "checked" 的功能
- 实现点击任务 item 右边的删除按钮是,删除相应的任务 item 的功能
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>实现todoList</title>
</head>
<body>
<!-- 请在index.js文件中完成练习 -->
<div id="todoList">
<div class="todoList-header">
<h2>待办事项</h2>
<div class="todoList-operation">
<input type="text" id="add-task-input" placeholder="任务名称">
<button id="js-add-task">添加任务</button>
</div>
</div>
<ul class="todoList-content">
<li class="task">
<p lass="text">完成 30 分钟腹肌撕裂者训练</p>
<span class="close">x</span>
</li>
<li class="task checked">
<p>阅读《JavaScript程序设计》30分钟</p>
<span class="close">x</span>
</li>
<li class="task">
<p>准备明天演讲 ppt </p>
<span class="close">x</span>
</li>
<li class="task">
<p>完成今天的学习任务</p>
<span class="close">x</span>
</li>
<li class="task">
<p>看一部美剧</p>
<span class="close">x</span>
</li>
</ul>
</div>
<!-- 引入jQuery-->
<script src="https://7.url.cn/edu/jslib/jquery/1.9.1/jquery.min.js"></script>
</body>
</html>
/* 重置样式 */
* {
box-sizing: border-box;
}
ul, li, p{
margin: 0;
padding: 0;
list-style: none;
}
#todoList {
width: 80%;
max-width: 460px;
margin: 20px auto;
}
/* ToDoList 头部 */
.todoList-header {
background-color: #333;
padding: 10px 30px 30px;
color: #fff;
text-align: center;
}
.todoList-operation {
position: relative;
padding-right: 110px;
}
/* 设置输入框的样式 */
.todoList-header input {
width: 100%;
padding: 10px;
font-size: 16px;
vertical-align: middle;
}
/* 设置添加按钮的样式 */
.todoList-header button {
position: absolute;
right: 0;
top: 0;
width: 110px;
border: none;
background: #d9d9d9;
text-align: center;
font-size: 16px;
padding: 10px;
}
.todoList-header button:hover {
background-color: #bbb;
}
/*任务item样式*/
.todoList-content li {
cursor: pointer;
position: relative;
padding: 12px 8px 12px 50px;
background: #eee;
font-size: 18px;
transition: 0.2s;
}
/* 设置hover时的背景颜色 */
.todoList-content li:hover {
background: #ddd;
}
/* 任务item完成状态 */
.todoList-content li.checked {
text-decoration: line-through;
}
.todoList-content li.checked::before {
content: '';
position: absolute;
border-color: #0eb312;
border-style: solid;
border-width: 0 4px 4px 0;
top: 10px;
left: 16px;
transform: rotate(45deg);
height: 16px;
width: 7px;
}
/* 关闭按钮 */
.todoList-content .close {
position: absolute;
color: #000;
right: 0;
top: 0;
padding: 12px 15px 12px 15px;
}
.todoList-content .close:hover {
background-color: #f44336;
color: white;
}
思路:
- 获取所需的元素,如输入框,添加任务按钮等
- 这里使用了模板函数
taskTpl来生成任务元素的 HTML 文本 - 使用事件委托来绑定任务相关的事件
- 使用了jQuery 的 常用方法 toggleClass 来实现类名切换
- 使用了字符串的常用方法 trim 去除字符串左右两边的空格
参考代码如下:
var $addTaskInput = $('#add-task-input'); // 输入框元素
var $jsAddTask = $('#js-add-task'); // 添加任务按钮
var $content = $('.todoList-content'); // 任务内容元素
/**
* 任务元素 html 模板函数
* @param [String] title 任务标题
*/
function taskTpl(title) {
return (
'<li class="task">'+
'<p lass="text">' + title + '</p>'+
'<span class="close">x</span>'+
'</li>');
}
// 为添加按钮绑定事件
$jsAddTask.on('click', function() {
// 获取输入框内容,使用 trim 去除字符串左右两端的空格
var newTaskTitle = $addTaskInput.val().trim();
if (newTaskTitle === '') {
return;
}
var newTaskHtml = taskTpl(newTaskTitle);
$content.append(newTaskHtml);
});
// 使用事件委托绑定任务元素点击事件
$content.on('click', '.task', function() {
// toggle class checked
$(this).toggleClass('checked');
});
// 使用事件委托绑定关闭按钮点击事件
$content.on('click', '.close', function() {
// 获取关闭按钮的父元素 task
var $task = $(this).parent();
// 去除任务元素
$task.remove();
});
6.实现 AutoComplete
AutoComplete 是指用户在文本框输入前几个字母或是汉字的时候,该控件就能从存放数据的文本或是数据库里将所有以这些字母开头的数据提示给用户,供用户选择,提供方便。接下来我们将实现一个 AutoComplete。效果如下图所示:
基础准备
-
已提供基础的 HTML 和 CSS
-
在 index.js 文件中定义了变量
data, 变量data表示文本提示的范围数组// 提示范围数据 var data = ['apple', 'banana', 'carambola', 'grape', 'lemon', 'orange', 'watermelon'];
题目要求
实现 AutoComplete 的功能逻辑 (可使用 jQuery),具体效果如下:
- 1、完善
input框 focus 事件绑定逻辑,当事件触发时,显示.autocomplete提示框和相应的提示内容,并定位到触发事件的输入框的正下方。要求同时只能出现一个.autocomplete提示框
-
2、完善
input输入框的 keyup 事件绑定逻辑,同时获取输入框内容,修改.autocomplete提示框的提示选项内容 -
3、完善
.autocomplete .item的 click 事件绑定逻辑,当点击提示框选项时,填充选项文本数据到相应的input框中
提示
- 了解字符串的 indexOf() 方法,通过使用
indexOf()判断是否是匹配提示的的字符。 - 可使用 jQuery 的 offset() 返回匹配元素相对于文档的偏移(位置)。
- 可使用 jQuery 的 outerHeight() 获取元素的当前计算高度值,包括padding,border和选择性的margin
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>实现 autocomplete</title>
</head>
<body>
<!-- 请在index.js文件中完成练习 -->
<input type="text">
<input type="text">
<ul class="autocomplete">
<!--提示内容结构如下:<li class="item">apple</li>-->
</ul>
<!-- 引入jQuery-->
<script src="https://7.url.cn/edu/jslib/jquery/1.9.1/jquery.min.js"></script>
</body>
</html>
/* 重置样式 */
* {
box-sizing: border-box;
}
ul, li, p{
margin: 0;
padding: 0;
list-style: none;
}
input {
width: 180px;
height: 30px;
margin: 30px;
}
/* autocomplete 框 */
.autocomplete {
position: fixed;
width: 180px;
left: 10px;
background: #eee;
top: 50px;
}
.autocomplete .item {
border-bottom: 1px solid #dfdfdf;
cursor: pointer;
color: #999;
line-height: 30px;
padding: 0 10px;
}
.autocomplete .item:hover {
color: #333;
}
1. 输入框 focus 的时候,提示框出现在输入框正下方,并且只有一个。
首先,输入框 focus 的时候,要显示提示框,这里的难点是计算提示框的位置。
- 通过 jQuery 的 offset() 方法获取输入框的 top 和 left,
- 设置提示框的 left 等于 输入框的 left,
- 设置提示框的 top 等于 输入框的 top 加上 输入框的高度 (可通过 jQuery 的 outerHeight() 来获取)
- 根据输入框的内容遍历题目给的提示数据,展示在提示框中。
下面是参考代码:
$body.on('focus', 'input', function() {
// 获取输入框当前的位置
var position = $(this).offset();
var value = $(this).val();
// 计算 $autocomplete 需要展示的位置
$autocomplete.css({
'left': position.left,
'top': position.top + $(this).outerHeight(),
'display': 'block'
});
// 更新当前的 input 对象
$curInput = $(this);
// 展示autoComplete
autoComplete(value);
});
2. 当输入框输入内容的时候,提示框显示匹配的内容。
我们在浏览器的 keyup 事件回调中,需要做以下几步:
- 获取用户的输入内容,
- 根据输入内容,筛选提示数据
data(可使用 indexOf() )
$body.on('keyup', 'input', function() {
// 获取输入框的值
var value = $(this).val();
// 将输入框的值传入 autoComplete 函数
autoComplete(value);
})
/**
* 根据输入展示匹配的提示内容
*/
function autoComplete(value) {
var itemsArr = [];
// 遍历数据筛选数据
data.forEach(function (item) {
// 使用 indexOf 判断输入内容与提示内容是否匹配
if (item.indexOf(value) > -1) {
itemsArr.push('<li class="item">' + item +'</li>');
}
});
$autocomplete.html(itemsArr.join(''));
}
3. 点击提示内容时,将被点击的内容填入输入框中。
当选项被点击时,需要做以下几步:
- 获取被点击提示选项和其文本
- 将提示文本输入到当前
focus的输入框中。
$body.on('click', '.autocomplete .item', function() {
var itemValue = $(this).text();
$curInput.val(itemValue);
$autocomplete.hide();
})
到这里,就可以实现题目要求的所有功能了。
总结
本题涉及到 dom 操作,元素定位,数组处理,字符串匹配等多方面的内容,比较复杂,但是只要将问题拆解,一步步实现,其实也不是很难。
完整参考代码如下:
// 提示范围数据
var data = ['apple', 'banana', 'carambola', 'grape', 'lemon', 'orange', 'watermelon'];
// 获取所有的inputs
var $autocomplete = $('.autocomplete');
var $curInput;
var $window = $(window);
var $body = $(document.body);
/**
* 1、完善 `input` 框 `focus` 事件绑定逻辑,当事件出发时,设置 `.autocomplete` 提示框显示,并定位到触发事件的输入框的正下方。
* 注:要求同时只能出现一个 `.autocomplete` 提示框
*/
$body.on('focus', 'input', function() {
// 获取输入框当前的位置
var position = $(this).offset();
var value = $(this).val();
// 计算 $autocomplete 需要展示的位置
$autocomplete.css({
'left': position.left,
'top': position.top + $(this).outerHeight(),
'display': 'block'
});
// 更新当前的 input 对象
$curInput = $(this);
// 展示autoComplete
autoComplete(value);
});
/**
* 2、完善 `input` 输入框的 `keyup` 事件绑定逻辑,同时获取输入框内容,修改 `.autocomplete` 提示框的提示选项内容
*/
$body.on('keyup', 'input', function() {
var value = $(this).val();
autoComplete(value);
});
/**
* 3、完善 `.autocomplete .item` 的 `click` 事件绑定逻辑,当点击提示框选项时,填充选项文本数据到相应的input框中
*/
$body.on('click', '.autocomplete .item', function() {
var itemValue = $(this).text();
$curInput.val(itemValue);
$autocomplete.hide();
});
/**
* 优化: 点击非input的地方则隐藏 $autocomplete
*/
$window.on('click', function(event) {
var target = event.target;
if (target.tagName !== 'INPUT') {
$autocomplete.hide();
}
});
/**
* 展示提示框
* @param [String] value 判断提示的文本
*/
function autoComplete(value) {
var itemsArr = [];
// 遍历数据筛选数据
data.forEach(function (item) {
if (item.indexOf(value) > -1) {
itemsArr.push('<li class="item">' + item +'</li>');
}
});
$autocomplete.html(itemsArr.join(''));
}