题目来源牛客网:https://www.nowcoder.com/ta/front-end

1. 封装函数 f,使 f 的 this 指向指定的对象

1
2
3
4
5
function bindThis(f, oTarget) {
return function() {
return f.apply(oTarget, arguments);
}
}

2. 获取 url 中的参数

  1. 指定参数名称,返回该参数的值 或者 空字符串
  2. 不指定参数名称,返回全部的参数对象 或者 {}
  3. 如果存在多个同名参数,则返回数组

示例:

输入:http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe 参数名称: key

输出: [1, 2, 3]

思路:

  1. 首先将url根据?号、#号分段,得到中间参数的那一段。
  2. 使用replace找到所有符合key=value形式的匹配项,进行全局搜索替换需要在正则表达式中包含g标志。
  3. 在替换函数中i表示匹配项,k表示第一个捕获组,v表示第二个捕获组。
  4. 通过result[k] instanceof Array来判是不是数组对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function getUrlParam1(sUrl, sKey) {
sUrl = sUrl.split('#')[0].split('?')[1];
var result = {};
sUrl.replace(/(\w+)=(\w+)/g, function(i, k, v) {
if (k in result) {
if (result[k] instanceof Array) {
result[k].push(v);
} else {
result[k] = [result[k], v];
}
} else {
result[k] = v;
}
})
return sKey == undefined? result: result[sKey] || '';
}

3 .查找两个节点的最近的一个共同父节点

查找两个节点的最近的一个共同父节点,可以包括节点自身

思路:

有一个contains方法可以判断某个节点是不是当前节点的子节点。

1
2
3
4
5
6
7
function commonParentNode(n1, n2) {
for(;n1;n1=n1.parentElement) {
if (n1.contains(n2)) {
return n1
}
}
}

4.根据包名,在指定空间中创建对象

输入:namespace({a: {test: 1, b: 2}}, ‘a.b.c.d’)

输出:{a: {test: 1, b: {c: {d: {}}}}}

思路:

遍历sPackage,对每一个包名,判断它在oNamespace里面是不是对象,如果不是这创建这个对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function namespace(oNamespace, sPackage) {
var packages = sPackage.split('.'),
result = oNamespace;

for (var i = 0; i < packages.length; i++) {
var l = packages[i];
if (typeof oNamespace[l] != "object") {
oNamespace[l] = {}
}
oNamespace = oNamespace[l]
}
oNamespace = result
return result
}

5. 为 Array 对象添加一个去除重复项的方法

输入:[false, true, undefined, null, NaN, 0, 1, {}, {}, ‘a’, ‘a’, NaN]

输出:[false, true, undefined, null, NaN, 0, 1, {}, {}, ‘a’]

对于undefined、null都是可以通过Array.prototype.indexOf来看是否已经包含在res中,唯一需要判断的是NaN,对于arr = [NaN], arr.indexOf(NaN)会返回-1,所以每次indexOf返回-1都需要通过item!=item && (typeof item == “number”)来判断item是NaN。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Array.prototype.uniq = function () {
var res = [],
findNaN = true;
this.forEach(function (item) {
if (res.indexOf(item) != -1) {
return;
}
if (item !== item && (typeof item==="number") ) {
if(findNaN) {
res.push(item)
findNaN = false;
}
return;
}
res.push(item)
})
return res;
}

6. 斐波那契数列

输入:fibonacci(3)

输出:2

输入:fibonacci(4)

输出:3

1
2
3
4
5
6
7
8
9
10
function fibonacci(n) {
var a = 0,
b = 1;
for (var i = 2; i <= n; i++) {
var t = a;
a = b;
b += t;
}
return b;
}

7.时间格式化输出

输入:formatDate(new Date(1409894060000), ‘yy-MM-dd hh:mm:ss 星期w’)

输出:14-09-05 01:14:20 星期五

思路:需要注意的是date的那些getXXXX的方法都是从0开始计数,getDay()从周日开始。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function formatDate(date, format) {
function addZero(num) {
if (num < 10) return "0" + num;
return num;
}
return format.replace(/([a-zA-Z]+)/g, function(item, group) {
if (item === 'yyyy') return date.getFullYear();
if (item == 'yy') return date.getFullYear()%100;
if (item == 'MM') return addZero(date.getMonth()+1);
if (item == 'M') return date.getMonth()+1;
if (item == 'dd') return addZero(date.getDate());
if (item == 'd') return date.getDate();
if (item == 'HH') return addZero(date.getHours());
if (item == 'H') return date.getHours();
if (item == 'hh') return addZero(date.getHours()%12);
if (item == 'h') return date.getHours()%12;
if (item == 'mm') return addZero(date.getMinutes());
if (item == 'm') return date.getMinutes();
if (item == 'ss') return addZero(date.getSeconds());
if (item == 's') return date.getSeconds();
if (item == 'w') return ['日','一','二','三','四','五','六'][date.getDay()];
})
}

8.获取字符串长度

如果第二个参数bUnicode255For1为false,那么unicode编码大于255的字符表示的长度为2,否则所有字符长度为1。

输入:’hello world, 牛客’, false

输出:17

1
2
3
4
5
6
7
8
function strLength(s, bUnicode255For1) {
if (bUnicode255For1) return s.length;
var length = 0;
for (var i = 0; i < s.length; i++) {
length += s.charCodeAt(i) > 255? 2: 1;
}
return length
}

9. 邮件字符串判断

判断输入是否是正确的邮件格式

输入:shao@gmail.com

输出: true

输入:dsa.shao@gmail.com

输出: true

输入:sh@ao@gmail.com

输出: false

1
2
3
function isAvailableEmail(sEmail) {
return /^\w+(\.\w+)*@\w+(\.\w+)+$/.test(sEmail)
}

10. 颜色字符串转换

描述:

将 rgb 颜色字符串转换为十六进制的形式,如 rgb(255, 255, 255) 转为 #ffffff

  1. rgb 中每个 , 后面的空格数量不固定
  2. 十六进制表达式使用六位小写字母
  3. 如果输入不符合 rgb 格式,返回原始输入

输入:’rgb(255, 255, 255)’

输出:#ffffff

输入:’rgb(0,32,255)

输出:#0020ff

思路:

主要还是使用正则来匹配替换。toHex函数使用toString(16)来将数字转换为16进制,然后通过前面加0来剪成两位。比如”2”在parseInt后变为2,在toString(16)后变为16进制,通过前面加0变为02,然后slice剪出从倒数第二到最后的子字符串。

1
2
3
4
5
6
function rgb2hex(sRGB) {
function toHex(num) { return ("0" + parseInt(num).toString(16)).slice(-2); }
return sRGB.replace(/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/, function(rgb, r, g, b) {
return '#' + toHex(r) + toHex(g) + toHex(b);
})
}

11.将字符串转换为驼峰格式

css 中经常有类似 background-image 这种通过 - 连接的字符,通过 javascript 设置样式的时候需要将这种样式转换成 backgroundImage 驼峰格式,请完成此转换功能

  1. 以 - 为分隔符,将第二个起的非空单词首字母转为大写
  2. -webkit-border-image 转换后的结果为 webkitBorderImage

样例

输入:’font-size’

输出:’fontSize’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function cssStyle2DomStyle(sName) {
function toUpper(s) { return s[0].toUpperCase()+s.slice(1) }
var names = sName.split('-'),
result = "",
first = true;

for (var i = 0; i < names.length; i++) {
if (names[i].length == 0) continue;
if (first) {
result += names[i];
first = false;
}
else result += toUpper(names[i]);
}
return result;
}

字符串字符统计

题目描述:

统计字符串中每个字符的出现频率,返回一个 Object,key 为统计字符,value 为出现频率

  1. 不限制 key 的顺序

  2. 输入的字符串参数不会为空

  3. 忽略空白字符

输入:’hello world’

输出;{h: 1, e: 1, l: 3, o: 2, w: 1, r: 1, d: 1}

1
2
3
4
5
6
7
8
9
10
11
function count(str) {
var map = {},
words = str.split(/\s+/);
for (var i = 0; i < words.length; i++) {
for (var j = 0; j < words[i].length; j++) {
var ch = words[i][j];
map[ch] = map[ch]? map[ch]+1: 1;
}
}
return map;
}