前端大挑战
修改this指向
题目描述
封装函数 f,使 f 的 this 指向指定的对象
代码:
// 第一种
function bindThis(f, oTarget) {
return function() {
return f.apply(oTarget, arguments);
}
}
// 第二种
function bindThis(f, oTarget) {
return f.bind(oTarget);
}
// 第三种
function bindThis(f, oTarget) {
let args = Array.prototype.slice.call(arguments, 2);
return function(){
return f.apply(oTarget, Array.prototype.slice.call(arguments).concat(args));
}
}
获取 url 中的参数
题目描述
- 指定参数名称,返回该参数的值 或者 空字符串
- 不指定参数名称,返回全部的参数对象 或者 {}
- 如果存在多个同名参数,则返回数组
// 输入
http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe key
// 输出
[1, 2, 3]
思路:
给定一个url为http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe key
,首先根据#
截取字符串url的前半部分,即``http://www.nowcoder.com?key=1&key=2&key=3&test=4`,然后再通过`?`截取`url`参数,即`key=1&key=2&key=3`,接着分情况讨论:
当指定参数名称时,首先对上边处理获得的参数字符串通过
&
进行分割,得到一个字符串数组,如["key=1", "key=2", "key=3"]
,对该字符串数组进行遍历,先对遍历到的当前字符串通过=
进行分割,得到的结果记为tmp
,判断该字符串是否与指定的参数名称相等,如果相同,则将其添加到数组中。遍历结束之后,如果数组长度为2,则直接返回值,如果长度为0,则直接返回空字符串。当不指定参数时,大致流程同上,最后通过判断返回全部的参数对象 或者 {}
代码:
function getUrlParam(sUrl, sKey) {
var param = sUrl.split('#')[0].split('?')[1];
if (sKey){//指定参数名称
var strs = param.split('&');
var arrs = new Array();//如果存在多个同名参数,则返回数组
for(var i = 0, len = strs.length; i < len; i++){
var tmp = strs[i].split('=');
if(tmp[0] == sKey){
arrs.push(tmp[1]);
}
}
if (arrs.length == 1){//返回该参数的值或者空字符串
return arrs[0];
} else if (arrs.length == 0){
return "";
} else {
return arrs;
}
} else {//不指定参数名称,返回全部的参数对象 或者 {}
if(param == undefined || param == ""){
return {};
} else {
var strs = param.split('&');
var arrObj = new Object();
for(var i = 0, len = strs.length; i < len; i++){
var tmp = strs[i].split('=');
if (!(tmp[0] in arrObj)) {
arrObj[tmp[0]] = [];
}
arrObj[tmp[0]].push(tmp[1]);
}
return arrObj;
}
}
}
dom
节点查找
题目描述
查找两个节点的最近的一个共同父节点,可以包括节点自身。
输入描述:
oNode1 和 oNode2 在同一文档中,且不会为相同的节点
代码:
// 方法一
function commonParentNode(oNode1, oNode2) {
while (oNode1) {
if (oNode1.contains(oNode2)) {
return oNode1;
}
oNode1 = oNode1.parentNode;
}
}
// 方法二
function commonParentNode(oNode1, oNode2) {
for (; oNode1; oNode1 = oNode1.parentNode) {
if (oNode1.contains(oNode2)) {
return oNode1;
}
}
}
根据包名,在指定空间中创建对象
题目描述(✨)
根据包名,在指定空间中创建对象
// 输入
namespace({a: {test: 1, b: 2}}, 'a.b.c.d')
// 输出
{a: {test: 1, b: {c: {d: {}}}}}
代码:
// 方法一
function namespace(oNamespace, sPackage) {
var arr = sPackage.split('.');
// 保留对原始对象的引用
var res = oNamespace;
for (var i = 0, len = arr.length; i < len; i++) {
// 空间名在对象中
if (arr[i] in oNamespace) {
if (typeof oNamespace[arr[i]] !== "object") {
// 将此属性设为空对象
oNamespace[arr[i]] = {};
}
} else {
// 空间名不在对象中,建立此空间名属性,赋值为空
oNamespace[arr[i]] = {};
}
// 将指针指向下一个空间名属性
oNamespace = oNamespace[arr[i]];
}
return res;
}
// 方法二
function namespace(oNamespace, sPackage) {
sPackage.split('.').forEach((k) => {
if (!oNamespace[k]) {
oNamespace[k] = {};
}
oNamespace = oNamespace[k];
});
}
数组去重
题目描述
为 Array 对象添加一个去除重复项的方法
// 输入
[false, true, undefined, null, NaN, 0, 1, {}, {}, 'a', 'a', NaN]
// 输出
[false, true, undefined, null, NaN, 0, 1, {}, {}, 'a']
代码:
// 方法一
Array.prototype.uniq = function () {
return [...new Set(this)];
}
// 方法二
Array.prototype.uniq = function () {
var arr = [];
var flag = true;
for (var i = 0; i < this.length; i++) {
if (arr.indexOf(this[i]) == -1) {
// 判断NaN
if (this[i] != this[i] && typeof this[i] === 'number') {
if (flag) {
arr.push(this[i]);
flag = false;
}
} else {
arr.push(this[i]);
}
}
}
return arr;
}
斐波那契数列
题目描述
用 JavaScript 实现斐波那契数列函数,返回第n个斐波那契数。 f(1) = 1, f(2) = 1 等
function fibonacci(n) {
if (n == 1 || n == 2) return 1;
return fibonacci(n - 1) + fibonacci( n - 2);
}
时间格式化输出
题目描述(✨)
按所给的时间格式输出指定的时间
格式说明
对于 2014.09.05 13:14:20
yyyy: 年份,2014
yy: 年份,14
MM: 月份,补满两位,09
M: 月份, 9
dd: 日期,补满两位,05
d: 日期, 5
HH: 24制小时,补满两位,13
H: 24制小时,13
hh: 12制小时,补满两位,01
h: 12制小时,1
mm: 分钟,补满两位,14
m: 分钟,14
ss: 秒,补满两位,20
s: 秒,20
w: 星期,为 [‘日’, ‘一’, ‘二’, ‘三’, ‘四’, ‘五’, ‘六’] 中的某一个,本 demo 结果为 五
// 输入
(new Date(1409894060000), 'yyyy-MM-dd HH:mm:ss 星期w')
// 输出
2014-09-05 13:14:20 星期五
代码:
function formatDate(date, str) {
var obj = {
yyyy: date.getFullYear(),
yy: ("" + date.getFullYear()).slice(-2),
M: date.getMonth() + 1,
MM: ("0" + (date.getMonth() + 1)).slice(-2),
d: date.getDate(),
dd: ("0" + date.getDate()).slice(-2),
H: date.getHours(),
HH: ("0" + date.getHours()).slice(-2),
h: date.getHours() % 12,
hh: ("0" + date.getHours() % 12).slice(-2),
m: date.getMinutes(),
mm: ("0" + date.getMinutes()).slice(-2),
s: date.getSeconds(),
ss: ("0" + date.getSeconds()).slice(-2),
w: ['日', '一', '二', '三', '四', '五', '六'][date.getDay()]
};
// + 匹配任何包含至少一个 n 的字符串
return str.replace(/[a-z]+/ig, function(v){return obj[v]});
}
获取字符串的长度
题目描述
如果第二个参数 bUnicode255For1 === true,则所有字符长度为 1,否则如果字符 Unicode 编码 > 255 则长度为 2
// 输入
'hello world, 牛客', false
// 输出
17
代码:
// 方法一
function strLength(s, bUnicode255For1) {
if (bUnicode255For1) {
return s.length;
} else {
let sum = 0;
for (let i = 0; i < s.length; i++) {
if (s.charCodeAt(i) > 255) {
sum += 2;
} else {
sum += 1;
}
}
return sum;
}
}
// 方法一简化版
function strLength(s, bUnicode255For1) {
let sum = 0;
for (let i = 0; i < s.length; i++) {
sum += (s.charCodeAt(i) > 255) ? 2 : 1;
}
return bUnicode255For1 ? s.length : sum;
}
邮箱字符串判断
题目描述
判断输入是否是正确的邮箱格式,返回布尔值
代码:
// 方法一
function isAvailableEmail(sEmail) {
var reg = /^([A-z0-9_\-\.])+\@([A-z0-9_\-\.])+\.([A-z]{2,4})$/;
return reg.test(sEmail);
}
// 方法二
function isAvailableEmail(sEmail) {
var reg = /^([\w+\.])+@(\w+)([.]\w+)+$/;
return reg.test(sEmail);
}
将字符串转化为驼峰格式
题目描述
css 中经常有类似 background-image 这种通过 - 连接的字符,通过 javascript 设置样式的时候需要将这种样式转换成 backgroundImage 驼峰格式,请完成此转换功能
- 以 - 为分隔符,将第二个起的非空单词首字母转为大写
- -webkit-border-image 转换后的结果为 webkitBorderImage
// 输入
'font-size'
// 输出
fontSize
代码:
function cssStyle2DomStyle(sName) {
let str = sName.split('-');
let arr = [];
str.forEach((key,index) => {
if (key != '') {
arr.push(key);
}
for (let i = 1; i < arr.length; i++) {
let char = arr[i].charAt(0).toUpperCase();
arr[i] = char + arr[i].substring(1);
}
});
return arr.join('');
}
字符串字符统计
题目描述
统计字符串中每个字符的出现频率,返回一个 Object,key 为统计字符,value 为出现频率
- 不限制 key 的顺序
- 输入的字符串参数不会为空
- 忽略空白字符
// 输入
'hello world'
// 输出
{h: 1, e: 1, l: 3, o: 2, w: 1, r: 1, d: 1}
代码:
// 方法一
function count(str) {
var obj = {};
// 代替空白字符
str = str.replace(/\s+/g, '');
for (var i = 0; i < str.length; i++) {
if (obj[str[i]]) {
obj[str[i]] += 1;
} else {
obj[str[i]] = 1;
}
}
return obj;
}
// 方法二
function count(str) {
var obj = {};
// 遍历非空白字符
str.replace(/\S/g, function(str) {
obj[str] ? obj[str] += 1 : obj[str] = 1;
});
return obj;
}
颜色字符串转换
题目描述(✨)
将 rgb 颜色字符串转换为十六进制的形式,如 rgb(255, 255, 255) 转为 #ffffff
- rgb 中每个 , 后面的空格数量不固定
- 十六进制表达式使用六位小写字母
- 如果输入不符合 rgb 格式,返回原始输入
// 输入
'rgb(255, 255, 255)'
// 输出
#ffffff
代码:
function rgb2hex(sRGB) {
return sRGB.replace(/^rgb\((\d+)\s*\,\s*(\d+)\s*\,\s*(\d+)\)$/g, function(a, r, g, b){
return '#' + hex(r) + hex(g) + hex(b);
});
}
function hex(n){
return n < 16 ? '0' + (+n).toString(16) : (+n).toString(16);
}