这是我在做完牛客网的45道JS能力测评经典题之后,结合他人的解析整理的一些笔记。如果有什么不对的地方,欢迎大家指出。
1. 查找数组元素位置
题目描述:
找出元素 item 在给定数组 arr 中的位置
输出描述:
如果数组中存在 item,则返回元素在数组中的位置,否则返回 -1
示例:
输入
[ 1, 2, 3, 4 ], 3
输出
2
function indexOf(arr, item) {
return arr.indexOf(item);
}
这里用到了indexOf方法,返回指定的字符串值item在字符串arr中首次出现的位置。像本题中3出现在第3个位置,则返回2(从0开始算第一个位置)。如果要检索的字符串值item没有出现,则该方法返回 -1
2. 数组求和
题目描述:
计算给定数组 arr 中所有元素的总和
输入描述:
数组中的元素均为 Number 类型
示例:
输入
[ 1, 2, 3, 4 ]
输出
10
1.for循环
function sum(arr) {
var s = 0;
for (var i=0; i<arr.length; i++) {
s = s+arr[i];
}
return s;
}
2.for in循环
function sum(arr) {
var s = 0;
for (var i in arr) {
s = s+arr[i];
}
return s;
}
3.forEach
function sum(arr) {
var s = 0;
arr.forEach(function(val) {
s = s+val;
});
return s;
}
1.for循环相信大家都能看懂,我就不在此赘述了。
2.for in循环用于遍历数组或者对象的属性(对数组或者对象的属性进行循环操作)。我觉得它相当于for循环的变体,也很好理解。
3.forEach方法用于调用数组的每个元素,并将元素传递给回调函数function。val是遍历数组arr时,当前指向的arr里的一个数组项元素,相当于arr[i]。若数组为空,则不执行回调函数function。结合for in循环,也很好理解。
3.移除数组中的元素(返回新的数组)
题目描述:
移除数组 arr 中的所有值与 item 相等的元素。不要直接修改数组 arr,结果返回新的数组
示例:
输入
[1, 2, 3, 4, 2], 2
输出
[1, 3, 4]
function remove(arr, item) {
var arr1 = [];
arr.forEach(function(val) {
if(val!=item){
arr1.push(val);
}
});
return arr1;
}
这道题和上一题一样可以用for循环和for in循环。push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。结合pop可以实现堆栈的后进先出。
4.移除数组中的元素(返回原数组)
题目描述:
移除数组 arr 中的所有值与 item 相等的元素,直接在给定的 arr 数组上进行操作,并将结果返回
示例:
输入
[1, 2, 2, 3, 4, 2, 2], 2
输出
[1, 3, 4]
function removeWithoutCopy(arr, item) {
for(var i=0;i<arr.length;i++){
if(arr[i]==item){
arr.splice(i,1);
i--;
}
}
return arr;
}
splice(index,howmany,item1,…,itemX) 方法可删除从 index 处开始的howmany个元素,并且用参数列表中声明的一个或多个值item1,…,itemX来替换那些被删除的元素。在本题中,就是删除了从 i 处开始的1个元素。splice方法会改变数组的长度,当减掉一个元素后,后面的元素都会前移,因此在每次删除之后,都需要执行 i --。如果是用forEach或者for in循环,是不对的,因为splice改变数组长度,导致下一次索引位置错误,相当于for循环里去掉了 i --。
5.添加元素(末尾添加)
题目描述:
在数组 arr 末尾添加元素 item。不要直接修改数组 arr,结果返回新的数组
示例:
输入
[1, 2, 3, 4], 10
输出
[1, 2, 3, 4, 10]
function append(arr, item) {
var a=arr.slice(0);
a.push(item);
return a;
}
slice(start,end)方法可从已有的数组中返回一个新的数组,包含从 start 到 end (不包括该元素)的 arr 中的元素,其中end可省略不写,如果 end 未被规定,那么 slice() 方法会选取从 start 到数组结尾的所有元素。本题中则是返回从第一个位置到后面全部的元素,相当于把arr数组复制给a。
6.删除数组最后一个元素
题目描述:
删除数组 arr 最后一个元素。不要直接修改数组 arr,结果返回新的数组
示例:
输入
[1, 2, 3, 4]
输出
[1, 2, 3]
function truncate(arr) {
var a = arr.slice(0);
a.pop();
return a;
}
pop() 方法可删除并返回数组的最后一个元素。结合push可以实现堆栈的后进先出。
7.添加元素(开头添加)
题目描述:
在数组 arr 开头添加元素 item。不要直接修改数组 arr,结果返回新的数组
示例:
输入
[1, 2, 3, 4], 10
输出
[10, 1, 2, 3, 4]
function prepend(arr, item) {
var a = arr.slice(0);
a.unshift(item);
return a;
}
unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。
补充:
unshift() 方法将把它的参数插入 arr数组的头部,并将已经存在的元素顺次地移到较高的下标处,以便留出空间。该方法的第一个参数将成为数组的新元素0,如果还有第二个参数,它将成为新的元素 1,以此类推。
unshift()方法不创建新的数组,而是直接修改原有的数组。
若要把一个或多个元素添加到数组的尾部,则使用 push() 方法。
8.删除数组第一个元素
题目描述:
删除数组 arr 第一个元素。不要直接修改数组 arr,结果返回新的数组
示例:
输入
[1, 2, 3, 4]
输出
[2, 3, 4]
function curtail(arr) {
var a = arr.slice(0);
a.shift();
return a;
}
shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
补充:
如果数组是空的,那么 shift() 方法将不进行任何操作,返回 undefined 值。
shift() 方法不创建新数组,而是直接修改原有的 arr数组。
若要删除并返回数组的最后一个元素,则使用 pop() 方法。
9.数组合并
题目描述:
合并数组 arr1 和数组 arr2。不要直接修改数组 arr,结果返回新的数组
示例:
输入
[1, 2, 3, 4], [‘a’, ‘b’, ‘c’, 1]
输出
[1, 2, 3, 4, ‘a’, ‘b’, ‘c’, 1]
function concat(arr1, arr2) {
return arr1.concat(arr2)
}
concat() 方法用于连接两个或多个数组。
补充:
该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本(新的数组)。
该数组是通过把所有 arrayX 参数添加到 arr 数组中生成的。如果要进行 concat() 操作的参数是数组,那么添加的是数组中的元素,而不是数组。
10.添加元素(指定位置添加)
题目描述:
在数组 arr 的 index 处添加元素 item。不要直接修改数组 arr,结果返回新的数组
示例:
输入
[1, 2, 3, 4], ‘z’, 2
输出
[1, 2, ‘z’, 3, 4]
function insert(arr, item, index) {
var a=arr.slice(0);
a.splice(index,0,item);
return a;
}
splice方法可参考第4题,在本题中,就是删除了从index处开始的0个元素,并用item来替换那些被删除的元素,相当于没有删除,直接在index处插入item。
11.计数
题目描述:
统计数组 arr 中值等于 item 的元素出现的次数
示例:
输入
[1, 2, 4, 4, 3, 4, 3], 4
输出
3
1.for循环
function count(arr, item) {
var a=0;
for(var i=0;i<arr.length;i++){
if(arr[i]==item){
a++;
}
}
return a;
}
2.for in循环
function count(arr, item) {
var a=0;
for(var i in arr){
if(arr[i]==item){
a++;
}
}
return a;
}
3.forEach
function count(arr, item) {
var a=0;
arr.forEach(function(val) {
if(val==item){
a++;
}
});
return a;
}
本题的思路可以参考第2题,相信大家都能看懂,我就不在此赘述了。
12.查找重复元素
题目描述:
找出数组 arr 中重复出现过的元素
示例:
输入
[1, 2, 4, 4, 3, 3, 1, 5, 3]
输出
[1, 3, 4]
1.for循环
function duplicates(arr) {
var b=[];
arr.sort();
for(var i=0;i<arr.length;i++){
if(arr[i]==arr[i-1] && b.indexOf(arr[i])==-1){
b.push(arr[i]);
}
}
return b;
}
2.for in循环
function duplicates(arr) {
var b=[];
arr.sort();
for(var i in arr){
if(arr[i]==arr[i-1] && b.indexOf(arr[i])==-1){
b.push(arr[i]);
}
}
return b;
}
3.forEach
function duplicates(arr) {
var b=[];
arr.forEach(function(elem){
if(arr.indexOf(elem) !=arr.lastIndexOf(elem) && b.indexOf(elem) == -1){
b.push(elem);
}
});
return b;
}
1.sort() 方法用于对数组的元素进行排序。这种排序,是按照字符编码的顺序进行排序。sort() 方法不创建新数组,而是直接修改原有的 arr数组。
2.lastIndexOf() 方法类似于 indexOf() 方法,只不过 lastIndexOf() 方法返回的是元素最后出现的位置,indexOf() 方法返回的是元素首次出现的位置。
3.第三个方法的思路,也可以用前面的for循环或者for in循环去替换forEach,有兴趣的小伙伴可以自己尝试一下。
13.求二次方
题目描述:
为数组 arr 中的每个元素求二次方。不要直接修改数组 arr,结果返回新的数组
示例:
输入
[1, 2, 3, 4]
输出
[1, 4, 9, 16]
function square(arr) {
var a=[];
for(var i in arr){
a.push(arr[i]*arr[i]);
}
return a;
}
本题的思路相信大家都能看懂,我就不在此赘述了。
14.查找元素位置
题目描述:
在数组 arr 中,查找值与 item 相等的元素出现的所有位置
示例:
输入
‘abcdefabc’
输出
[0, 6]
function findAllOccurrences(arr, target) {
var a=[];
for(var i=0;i<arr.length;i++){
if(arr[i]==target){
a.push(i);
}
}
return a;
}
本题的思路相信大家都能看懂,我就不在此赘述了。
15.避免全局变量
题目描述:
给定的 js 代码中存在全局变量,请修复
原代码:
function globals() {
myObject = {
name : 'Jory'
};
return myObject;
}
在Javascript语言中,声明变量使用的都是关键字var,如果不使用var而直接声明变量,则该变量为全局变量。
function globals() {
var myObject = {
name : 'Jory'
};
return myObject;
}
16.正确的函数定义
题目描述:
请修复给定的 js 代码中,函数定义存在的问题
示例:
输入
true
输出
a
原代码:
function functions(flag) {
if (flag) {
function getValue() { return 'a'; }
} else {
function getValue() { return 'b'; }
}
return getValue();
}
else中的语句相当于将if中的function重写,因此无论flag为何值,返回的方法始终为重写后的方法。将方法赋值给一个变量,方法就不会被重写,因此才能得到正确的结果。
function functions(flag) {
if (flag) {
var getValue = function () { return 'a'; }
} else {
var getValue = function () { return 'b'; }
}
return getValue();
}
17.正确的使用 parseInt
题目描述:
修改 js 代码中 parseInt 的调用方式,使之通过全部测试用例
示例:
输入
‘0x12’
输出
0
原代码:
function parse2Int(num) {
return parseInt(num);
}
parseInt(string, radix) 函数可解析一个字符串,并返回一个整数。参数 radix 表示要解析的数字的基数。该值介于 2 ~ 36 之间。
如果省略该参数或其值为 0,parseInt() 会根据 string 来判断数字的基数。
举例,如果 string 以 “0x” 开头,parseInt() 会把 string 的其余部分解析为十六进制的整数。如果 string 以 0 开头,那么 ECMAScript v3 允许 parseInt() 的一个实现把其后的字符解析为八进制或十六进制的数字。如果 string 以 1 ~ 9 的数字开头,parseInt() 将把它解析为十进制的整数。
而本题则是要求解析为十进制的整数。
function parse2Int(num) {
return parseInt(num,10);
}
补充:
只有字符串中的第一个数字会被返回。
开头和结尾的空格是允许的。
如果字符串的第一个字符不能被转换为数字,那么 parseFloat() 会返回 NaN。
如果参数 radix 小于 2 或者大于 36,则 parseInt() 将返回 NaN。
18.完全等同
题目描述:
判断 val1 和 val2 是否完全等同
function identity(val1, val2) {
if(val1===val2) {
return true;
}
else{
return false;
}
}
一般使用双等来判断(= =),如果还需要类型相同那么就用三等(= = =)。
19.计时器
题目描述:
实现一个打点计时器,要求
1、从 start 到 end(包含 start 和 end),每隔 100 毫秒 console.log 一个数字,每次数字增幅为 1
2、返回的对象中需要包含一个 cancel 方法,用于停止定时操作
3、第一个数需要立即输出
function count(start, end) {
//立即输出第一个值
console.log(start++);
var timer = setInterval(
function()
{
if(start <= end){
console.log(start++);
}else{
clearInterval(timer);
}
},100);
//返回一个对象
return {
cancel : function()
{
clearInterval(timer);
}
};
}
setInterval(code,millisec) 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。code 是要调用的函数或要执行的代码串,millisec 是周期性执行或调用 code 之间的时间间隔,以毫秒计。
setInterval() 方法会不停地调用 code 函数,直到 clearInterval() 被调用或窗口被关闭。由 setInterval() 返回的 ID 值可用作 clearInterval() 方法的参数。
clearInterval() 方法可取消由 setInterval() 设置的 timeout,其中的参数必须是由 setInterval() 返回的 ID 值。
20.流程控制
题目描述:
实现 fizzBuzz 函数,参数 num 与返回值的关系如下:
1、如果 num 能同时被 3 和 5 整除,返回字符串 fizzbuzz
2、如果 num 能被 3 整除,返回字符串 fizz
3、如果 num 能被 5 整除,返回字符串 buzz
4、如果参数为空或者不是 Number 类型,返回 false
5、其余情况,返回参数 num
示例:
输入
15
输出
fizzbuzz
function fizzBuzz(num) {
if(num%3==0 && num%5==0){
return 'fizzbuzz';
}
else if(num%3==0){
return 'fizz';
}
else if(num%5==0){
return 'buzz';
}
else if(num==null || typeof num != 'number'){
return false;
}
else{
return num
}
}
typeof 运算符返回一个字符串,表示未经计算的操作数的类型。
对变量或值调用 typeof 运算符将返回下列值之一:
- undefined - 如果变量是 Undefined 类型
- boolean - 如果变量是 Boolean 类型
- number - 如果变量是 Number 类型
- string - 如果变量是 String 类型
- function - 如果变量是 函数对象
- symbol - 如果变量是 Symbol 类型
- object - 如果变量是一种引用类型或 Null 类型或任何其他对象
21.函数传参
题目描述:
将数组 arr 中的元素作为调用函数 fn 的参数
示例:
输入
function (greeting, name, punctuation) {return greeting + ', ’ + name + (punctuation || ‘!’);}, [‘Hello’, ‘Ellie’, ‘!’]
输出
Hello, Ellie!
function argsAsArray(fn, arr) {
return fn.apply(this, arr);
}
function.apply(newObj[, argsArray]) 方法可以修改指定函数的调用对象。function 是调用对象将被修改的函数,newObj 是函数的新调用对象,argsArray 是传递给function函数的参数,数组或者arguments对象。
apply 方法是将传递给函数的参数放入一个数组中,传入参数数组即可。
22.函数的上下文
题目描述:
将函数 fn 的执行上下文改为 obj 对象
示例:
输入
function () {return this.greeting + ', ’ + this.name + ‘!!!’;}, {greeting: ‘Hello’, name: ‘Rebecca’}
输出
Hello, Rebecca!!!
1.apply
function speak(fn, obj) {
return fn.apply(obj);
}
2.call
function speak(fn, obj) {
return fn.call(obj);
}
function.call(newObj[, arg1[, arg2[, [,…argN]]]]) 方法的作用和 apply() 方法类似,只有一个区别,就是 call() 方法接受的是若干个参数的列表,而 apply() 方法接受的是一个包含多个参数的数组。
将 fn 的执行上下文改为 obj 对象,也就是说把 fn 的方法放到 obj 上执行。这里涉及到作用域的知识,我还不是太了解,等我了解了相关的知识再修改这段文字。
23.返回函数
题目描述:
实现函数 functionFunction,调用之后满足如下条件:
1、返回值为一个函数 f
2、调用返回的函数 f,返回值为按照调用顺序的参数拼接,拼接字符为英文逗号加一个空格,即 ', ’
3、所有函数的参数数量为 1,且均为 String 类型
示例:
输入
functionFunction(‘Hello’)(‘world’)
输出
Hello, world
function functionFunction(str) {
return f = function (obj) {
return str + ', ' + obj;
}
}
首先执行functionFunction(‘Hello’),传入参数str,然后返回函数f,f与(‘world’)组合,执行f(‘world’),传入参数s,f返回str+", "+s,即Hello, world。注意中间的逗号后面有一个空格。
该函数只能接受两个参数,暂时没想到参数数目不定的实现方法,等我想到了实现方法再修改这段文字。
24.使用闭包
题目描述:
实现函数 makeClosures,调用之后满足如下条件:
1、返回一个函数数组 result,长度与 arr 相同
2、运行 result 中第 i 个函数,即 result[i] (),结果与 fn(arr[i]) 相同
示例:
输入
[1, 2, 3], function (x) {
return x * x;
}
输出
4
function makeClosures(arr, fn) {
var result = [];
arr.forEach(function(e){
result.push(function(){
return fn(e);
});
});
return result;
}
如果在函数 func 内部声明函数 inner ,然后在函数外部调用 inner ,这个过程即产生了一个闭包。
这里是使用不了 for 循环和 for in 循环的,因为题目要求的是返回一个函数数组,如果在循环中直接写 result[i] = function(){return fn(arr[i]);} 或者 result.push(function(){return fn(arr[i]);}) ,最终的结果是不正确的,因为在每次迭代的时候,那样的语句后面的方法并没有执行,只是创建了一个函数体为“ return fn(arr[i]); ”的函数对象而已,当迭代停止时,i 为最终迭代停止的值,在函数被调用时,i 依旧为最终迭代停止的值,因此无法返回正确的结果。
所以对于函数数组,最好使用 forEach 循环。声明一个匿名函数,并立即执行它,function(){return fn(e); },函数执行后,e 立即传入,因此就能得到正确的结果。闭包允许你引用存在于外部函数中的变量。
25.二次封装函数
题目描述:
已知函数 fn 执行需要 3 个参数。请实现函数 partial,调用之后满足如下条件:
1、返回一个函数 result,该函数接受一个参数
2、执行 result(str3) ,返回的结果与 fn(str1, str2, str3) 一致
示例:
输入
var sayIt = function(greeting, name, punctuation) { return greeting + ‘, ’ + name + (punctuation || ‘!’); }; partial(sayIt, ‘Hello’, ‘Ellie’)(’!!!’);
输出
Hello, Ellie!!!
function partial(fn, str1, str2) {
return result = function (str3) {
return fn(str1, str2, str3)
};
}
因为没有要求函数内部this指向和作用域,所以可以不用 call 和 apply 方法。
26.使用 arguments
题目描述:
函数 useArguments 可以接收 1 个及以上的参数。请实现函数 useArguments,返回所有调用参数相加后的结果。本题的测试参数全部为 Number 类型,不需考虑参数转换。
示例:
输入
1, 2, 3, 4
输出
10
function useArguments() {
var sum =0;
for(var i in arguments){
sum = sum + arguments[i];
}
return sum;
}
arguments能获得函数对象传入的参数组,类似于一个数组,包含传递给函数的每个参数,第一个参数在索引0处,能够通过length获取参数个数,能通过下标获取该位置的参数,但是它不能使用 forEach、pop 等方法。
arguments也可以被转换为一个真正的数组:
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);
27.使用 apply 调用函数
题目描述:
实现函数 callIt,调用之后满足如下条件
1、返回的结果为调用 fn 之后的结果
2、fn 的调用参数为 callIt 的第一个参数之后的全部参数
function callIt(fn) {
return fn.apply(this, [].slice.call(arguments, 1))
}
本题大家可以参考21题和上一题的知识点,我就不在此赘述了。
28.二次封装函数
题目描述:
实现函数 partialUsingArguments,调用之后满足如下条件:
1、返回一个函数 result
2、调用 result 之后,返回的结果与调用函数 fn 的结果一致
3、fn 的调用参数为 partialUsingArguments 的第一个参数之后的全部参数以及 result 的调用参数
function partialUsingArguments(fn) {
//先获取p函数第一个参数之后的全部参数
var args = [].slice.call(arguments,1);
//声明result函数
return result = function(){
//使用concat合并两个或多个数组中的元素
return fn.apply(this, args.concat( [].slice.call(arguments) ));
};
}
本题的思路和上一题类似,我就不在此赘述了。
29.柯里化
题目描述:
已知 fn 为一个预定义函数,实现函数 curryIt,调用之后满足如下条件:
1、返回一个函数 a,a 的 length 属性值为 1(即显式声明 a 接收一个参数)
2、调用 a 之后,返回一个函数 b, b 的 length 属性值为 1
3、调用 b 之后,返回一个函数 c, c 的 length 属性值为 1
4、调用 c 之后,返回的结果与调用 fn 的返回值一致
5、fn 的参数依次为函数 a, b, c 的调用参数
示例:
输入
var fn = function (a, b, c) {return a + b + c}; curryIt(fn)(1)(2)(3);
输出
6
1.有arguments.callee
function curryIt(fn) {
var args = [];
return function(arg){
args.push(arg);
if(args.length < fn.length){
return arguments.callee;
}else
return fn.apply(this,args);
}
}
2.无arguments.callee
function curryIt(fn) {
var args = [];
var result = function(arg){
args.push(arg);
if(args.length < fn.length){
return result;
}else
return fn.apply(this,args);
}
return result;
}
柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
arguments.callee 属性包含当前正在执行的函数。它可以用于引用该函数的函数体内当前正在执行的函数。这在函数的名称是未知时很有用,例如在没有名称的函数表达式 (也称为“匿名函数”)内。如第一个方法。
然而,这实际上是一个非常糟糕的解决方案,会导致一些意想不到的错误,(例如这样不能实现内联和尾递归,我没懂这一块,就没写上去)
我们可以通过命名函数表达式解决这些问题,这样的话该函数可以像代码内部的任何其他函数一样被调用,而且具有比访问arguments对象更好的性能。如第二个方法。
30.或运算
题目描述:
返回参数 a 和 b 的逻辑或运算结果
示例:
输入
false, true
输出
true
function or(a, b) {
return (a || b);
}
||为或运算。
31.且运算
题目描述:
返回参数 a 和 b 的逻辑且运算结果
示例:
输入
false, true
输出
false
function and(a, b) {
return (a && b);
}
&&为且运算(和运算)。
32.模块
题目描述:
完成函数 createModule,调用之后满足如下要求:
1、返回一个对象
2、对象的 greeting 属性值等于 str1, name 属性值等于 str2
3、对象存在一个 sayIt 方法,该方法返回的字符串为 greeting属性值 + ', ’ + name属性值
function createModule(str1, str2) {
var obj = {
greeting : str1,
name : str2,
sayIt : function(){
return obj.greeting+", "+obj.name;
}
};
return obj;
}
声明对象可以用 var obj = {};,可以直接在括号中以key:value的方式定义属性。
33.二进制转换(十进制转二进制)
题目描述:
获取数字 num 二进制形式第 bit 位的值。注意:
1、bit 从 1 开始
2、返回 0 或 1
3、举例:2 的二进制为 10,第 1 位为 0,第 2 位为 1
示例:
输入
128, 8
输出
1
function valueAtBit(num, bit) {
var s = num.toString(2);
return s[s.length - bit];
}
NumberObject.toString(radix) 方法可把一个 Number 对象转换为一个字符串,并返回数字的字符串表示。radix 表示数字的基数,为 2 ~ 36 之间的整数。若省略该参数,则默认使用基数 10。例如,当 radix 为 2 时,NumberObject 会被转换为二进制值表示的字符串。
补充:
当调用该方法的对象不是 Number 时抛出 TypeError 异常。
通过num.toString(2)能直接将num转换为2进制数格式的字符串,利用下标就能将对应值取出来。题目返回的数字是从右往左,因此下标为倒数。
34.二进制转换(二进制转十进制)
题目描述:
给定二进制字符串,将其换算成对应的十进制数字
示例:
输入
‘11000000’
输出
192
function base10(str) {
return parseInt(str,2);
}
parseInt(string, radix) 函数可以参考17题,我就不在此赘述了。
35.二进制转换(十进制转8位二进制)
题目描述:
将给定数字转换成二进制字符串。如果字符串长度不足 8 位,则在前面补 0 到满8位。
示例:
输入
65
输出
01000001
function convertToBinary(num) {
var s = num.toString(2);
while(s.length<8){
s = '0'+s;
}
return s;
}
用字符串拼接来补0
36.乘法
题目描述:
求 a 和 b 相乘的值,a 和 b 可能是小数,需要注意结果的精度问题
示例:
输入
3, 0.0001
输出
0.0003
function multiply(a, b) {
return a*b;
}
37.改变上下文
题目描述:
将函数 fn 的执行上下文改为 obj,返回 fn 执行后的值
示例:
输入
alterContext(function() {return this.greeting + ', ’ + this.name + ‘!’; }, {name: ‘Rebecca’, greeting: ‘Yo’ })
输出
Yo, Rebecca!
function alterContext(fn, obj) {
return fn.apply(obj);
}
38.批量改变对象的属性
题目描述:
给定一个构造函数 constructor,请完成 alterObjects 方法,将 constructor 的所有实例的 greeting 属性指向给定的 greeting 变量。
示例:
输入
var C = function(name) {this.name = name; return this;};
var obj1 = new C(‘Rebecca’);
alterObjects(C, ‘What’s up’); obj1.greeting;
输出
What’s up
function alterObjects(constructor, greeting) {
constructor.prototype.greeting = greeting;
}
prototype 属性可以向对象添加属性和方法。
这是原型链问题。访问一个对象的方法或者是属性,首先会在该对象中寻找,如果找到则返回,如果没找到,则在其原型链上面向上寻找,直至基原型,如还未找到,则返回undefined。将 constructor 的所有实例的 greeting 属性指向给定的 greeting 变量,只需要在constructor的原型上面添加greeting属性,并指定值。
39.属性遍历
题目描述:
找出对象 obj 不在原型链上的属性(注意这题测试例子的冒号后面也有一个空格~)
1、返回数组,格式为 key: value
2、结果数组不要求顺序
示例:
输入
var C = function() {this.foo = ‘bar’; this.baz = ‘bim’;};
C.prototype.bop = ‘bip’;
iterate(new C());
输出
[“foo: bar”, “baz: bim”]
function iterate(obj) {
const arr = [];
//使用for-in遍历对象属性
for(var key in obj){
//判断key是否为对象本身的属性
if(obj.hasOwnProperty(key)){
//将属性和值按格式存入数组
arr.push(key+": "+obj[key]);
}
}
return arr;
}
obj.hasOwnProperty(prop) 方法会返回一个布尔值,指示对象 obj 自身属性中是否具有指定的属性 prop 。这个方法可以用来检测一个对象是否含有特定的自身属性,并忽略掉那些从原型链上继承到的属性。
补充:
所有继承了 Object 的对象都会继承到 hasOwnProperty 方法。
const 定义的是常量( var 定义的是变量),常量不可以修改,而且必须初始化。
const arr = [];语句中,arr是个引用地址,这个地址不变,所以可以定义为常量。
40.判断是否包含数字
题目描述:
给定字符串 str,检查其是否包含数字,包含返回 true,否则返回 false
示例:
输入
‘abc123’
输出
true
function containsNumber(str) {
return /\d/.test(str);
}
RegExpObject.test(string) 方法用于检测一个字符串是否匹配某个模式。如果字符串 string 中含有与 RegExpObject 匹配的文本,则返回 true,否则返回 false。
RegExpObject 可以为正则表达式,\d 可以匹配数字字符。
41.检查重复字符串
题目描述:
给定字符串 str,检查其是否包含连续重复的字母(a-zA-Z),包含返回 true,否则返回 false
示例:
输入
‘rattler’
输出
true
function containsRepeatingLetter(str) {
return /([A-Z])\1/i.test(str);
}
在正则表达式中,利用()进行分组,使用斜杠加数字表示引用,\1就是引用第一个分组,\2就是引用第二个分组。将[a-zA-Z]做为一个分组,然后引用,就可以判断是否有连续重复的字母。具体可以参考正则基础之——反向引用。
42.判断是否以元音字母结尾
题目描述:
给定字符串 str,检查其是否以元音字母结尾
1、元音字母包括 a,e,i,o,u,以及对应的大写
2、包含返回 true,否则返回 false
示例:
输入
‘gorilla’
输出
true
function endsWithVowel(str) {
return /[a,e,i,o,u]$/i.test(str);
}
首先确定元音集合[a,e,i,o,u],然后是以元音结尾,加上 $ ,最后通配大小写,加上 i ,因此正则表达式为: /[a,e,i,o,u]$/i 。
43.获取指定字符串
题目描述:
给定字符串 str,检查其是否包含 连续3个数字
1、如果包含,返回最新出现的 3 个数字的字符串
2、如果不包含,返回 false
示例:
输入
‘9876543’
输出
987
function captureThreeNumbers(str) {
//声明一个数组保存匹配的字符串结果
var arr = str.match(/\d{3}/);
//如果arr存在目标结果,则返回第一个元素,即最早出现的目标结果
if(arr)
return arr[0];
else return false;
}
string.match(RegExpObject) 方法可在字符串 string 内检索指定的值,或找到一个或多个正则表达式的匹配,并返回存放匹配结果的数组。
补充:
若 RegExpObject 为普通字符串,此时match方法的返回值是存放首次匹配内容的数组。
连续的三个任意数字用正则表达式表示为 /\d{3}/ 。
44.判断是否符合指定格式
题目描述:
给定字符串 str,检查其是否符合如下格式
1、XXX-XXX-XXXX
2、其中 X 为 Number 类型
示例:
输入
‘800-555-1212’
输出
true
function matchesPattern(str) {
//return/^(\d{3}-){2}\d{4}$/.test(str);
return/^\d{3}-\d{3}-\d{4}$/.test(str);
}
本题需要注意格式,开头 ^ 和结尾 $ 必须加上来限定字符串,3个数可表示为\d{3},4个数则为\d{4},{n}表示前面内容出现的次数。正则表达式可写作 /^ \d{3}-\d{3}-\d{4}$ / ,有相同部分\d{3}-,因此也可写作 /^(\d{3}-){2}\d{4}$/ 。
45.判断是否符合 USD 格式
题目描述:
给定字符串 str,检查其是否符合美元书写格式
1、以 $ 开始
2、整数部分,从个位起,满 3 个数字用 , 分隔
3、如果为小数,则小数部分长度为 2
4、正确的格式如:$1,023,032.03 或者 $2.03,错误的格式如:$3,432,12.12 或者 $34,344.3
示例:
输入
‘$20,933,209.93’
输出
true
function isUSD(str) {
return/^\$( [1-9]\d{0,2}(,\d{3})*|0 )(\.\d{2})?$/.test(str);
}
首先,开头必是 $ ,而正则表达式中 $ 表示结尾,需要进行转义,因此开头为 ^\$ 。
然后$后必然接数字,开头第一个数字为1-9,并且最少一位,最多三位数,可用{m,n}表示,最少m位,最多n位,因此此段为 [1-9] \d{0,2} 。
接着,后面如还有数,则必然有,分隔,并且后面必有3个数,类似于,XXX的格式会出现0或者n次,因此此段可表示为 (,\d{3})* 。
另外,还要考虑整数部分为0的情况,则要加上 |0 。
最后,如有小数部分,则注意对小数点进行转义,此段可表示为(\.\d{2})? 。
因此,最后的正则表达式为 /^\$([1-9]\d{0,2}(,\d{3})*|0)(\.\d{2})?$/ 。