引言html
牛客网这个前端笔试题库,能够说这60道是最基础的了,也是考察的东西比较杂,有时间4天差很少就能够刷完,巩固基础仍是有些用的。作完题回顾一上午就能够过完一遍。如今我结合个人答案和参考的其余人的答案,在这里作一个总结,也是本身知识的整理结果。前端
封装函数 f,使 f 的 this 指向指定的对象。
这里给出三种写法,哪一种均可以。正则表达式
// apply修改this做用域 function bindThis(f, oTarget) { return function () { return f.apply(oTarget,arguments) } } // call修改this做用域 function bindThis(f, oTarget) { return function (){ return f.call(oTarget,...arguments) } } // bind修改this做用域 function bindThis(f, oTarget) { return function (){ return f.bind(oTarget,...arguments)() } } // 或者直接简写 function bindThis(f, oTarget) { return f.bind(oTarget) }
相关知识点:数组
apply、call、bind区别缓存
apply、call、bind的做用都是修改执行上下文
apply、call都是返回函数当即执行的结果,其中apply第二个参数以后是数组,call第二个参数以后是单个的值。
bind返回的是函数,须要手动执行结果。第二个参数以后是单个的值。
获取 url 中的参数服务器
- 指定参数名称,返回该参数的值 或者 空字符串
- 不指定参数名称,返回所有的参数对象 或者 {}
- 若是存在多个同名参数,则返回数组
输入:
http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe key
数据结构输出:[1, 2, 3]app
function getUrlParam(sUrl, sKey) { let newArr = [] let newObj = {} // 获取?号后面#号前面的值 let query = sUrl.split('#')[0].split('?')[1] // 若是query存在 if (query) { let arr = query.split('&') for(let i = 0 ; i < arr.length; i++) { if (arr[i]) { arr[i] = arr[i].split('=') // 数组 if (sKey !== undefined) { if(arr[i][0] === sKey) { newArr.push(arr[i][1]) } // 对象 } else { if(arr[i][0] in newObj) { newObj[arr[i][0]].push(arr[i][1]) } else { newObj[arr[i][0]] = [arr[i][1]] } } } } // 判断sKey有没有值 if(sKey !== undefined) { switch(newArr.length) { case 0 : return '';break; case 1 : return newArr[0]; break; default: return newArr;break; } } else { return newObj } // 若是query不存在,判断sKey是否存在,若是存在就返回空对象,若是不存在就返回空字符串 } else { return sKey !== undefined ? {} : '' } }
相关知识点:dom
url的组成部分函数
https://user:pass@www.baidu.com:80/index.html?type=1&name=2#haha
http/https
是协议
user:pass@
是登陆认证
www.baidu.com
是域名,服务器地址
:80
是端口号
/index.html
是请求资源文件路径
?type=1&name=2
是查询字符串,携带参数,给服务器传的内容。
#haha
是哈希,片断标识符
split方法
字符串分割成数组的方法,里面的参数是以什么分割,若是不传就是空字符串为分割,返回值是一个数组。
查找两个节点的最近的一个共同父节点,能够包括节点自身
输入描述:
oNode1 和 oNode2 在同一文档中,且不会为相同的节点
function commonParentNode(oNode1, oNode2) { if(oNode1.contains(oNode2)) { return oNode1 } else { return commonParentNode(oNode1.parentNode,oNode2) } }
相关知识点:
contains API
查看dom元素包含关系,包含返回true,不包含返回false
参考MDN
根据包名,在指定空间中建立对象
输入描述:
namespace({a: {test: 1, b: 2}}, 'a.b.c.d')
输出描述:
{a: {test: 1, b: {c: {d: {}}}}}
function namespace(oNamespace, sPackage) { let scope = sPackage.split('.') let ns = oNamespace for(let i = 0; i< scope.length; i++) { // 若是对象中没有该元素,或者不是对象,那么就置为空对象 if(!ns.hasOwnProperty(scope[i]) || Object.prototype.toString.call(ns[scope[i]]) !== '[object Object]') { ns[scope[i]] = {} } // 而后继续往下找 ns = ns[scope[i]] } return oNamespace }
考察知识点:
hasOwnProperty / typeof / in / instanceof 的区别
- hasOwnProperty 是判断对象自身有没有某属性,不包含原型链的方法。
- in 是判断对象在自身和原型链上有没有该方法。
- instanceof 是判断对象在原型链上有没有该方法。
- typeof 判断操做数的类型,可是null也会判断为"object"
准确判断某值的类型
Object.prototype.toString.call(123) === "[object Number]"
Object.prototype.toString.call('aaa') === "[object String]"
Object.prototype.toString.call(true) === "[object Boolean]"
Object.prototype.toString.call(undefined) === "[object Undefined]"
Object.prototype.toString.call(null) === '[object Null]'
Object.prototype.toString.call({}) === '[object Object]'
Object.prototype.toString.call([]) === '[object Array]'
Object.prototype.toString.call(Math) === "[object Math]"
Object.prototype.toString.call(new Date()) === "[object Date]"
Object.prototype.toString.call(new RegExp) === "[object RegExp]"
为 Array 对象添加一个去除重复项的方法
输入
[false, true, undefined, null, NaN, 0, 1, {}, {}, 'a', 'a', NaN]
输出
[false, true, undefined, null, NaN, 0, 1, {}, {}, 'a']
这个题,狗就狗在,还有NaN
// 方法一:终极思路 Array.prototype.uniq = function () { return [...new Set(this)] } // 方法二:普通思路,遍历以后比较值 Array.prototype.uniq = function () { let arr = [] let flag = true this.forEach(value => { // == -1 有两种状况,一种是NaN,一种是有相同值 if(arr.indexOf(value) === -1) { // 若是是NaN if(value !== value) { // flag是标记,第一个NaN就进,以后的就不进去 if(flag){ arr.push(value) flag = false } } else { arr.push(value) } } }) return arr }
相关知识点:
uniq方法中的this指向哪里?
Array构造函数的原型方法中的this指的是数组实例。
Set的特性
Set存储的成员是惟一的,不是重复的,若是有重复会自动过滤掉.
ES6(七)—— Set & Map
(NaN === NaN) => false
NaN : is not a number,不等于本身
typeof NaN => number
Object.prototype.toString.call(NaN) => "[object Number]"
ES6 新增方法:Number.isNaN() 用来判断是否属于数字
用 JavaScript 实现斐波那契数列函数,返回第n个斐波那契数。 f(1) = 1, f(2) = 1 等
斐波那契数列基本学js都会,1 1 2 3 5 8 13,后一个是前两个的和。
// 方法一:递归思路 function fibonacci(n) { if(n === 0) return 0 if(n === 1 || n === 2) return 1 return fibonacci(n-1) + fibonacci(n-2) } // 方法二:迭代思路 function fibonacci(n) { let num1 = 1 let num2 = 1 let sum = 0 for(let i = 3; i <= n; i++) { sum = num1 + num2 num1 = num2 num2 = sum } return sum } // 上面写法能够过oj,可是若是数字大点就超级慢,使用缓存很可 // 方法三:递归优化思路 function fibonacci(n,cache = {}) { // 有缓存就直接读缓存 if(n in cache) return cache[n] if(n === 1 || n === 2) { cache[n] = 1 return 1 } // 没有缓存算完以后存入缓存 let temp = fibonacci(n-1, cache) + fibonacci(n-2,cache) cache[n] = temp return temp }
相关知识点:
题目描述
按所给的时间格式输出指定的时间
格式说明
对于 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 结果为 五输入
formatDate(new Date(1409894060000), 'yyyy-MM-dd HH:mm:ss 星期w')输出
2014-09-05 13:14:20 星期五
function formatDate(t,str) { let year = ''+t.getFullYear() let month = t.getMonth() + 1 let day = t.getDate() let hour = t.getHours() let minutes = t.getMinutes() let second = t.getSeconds() let week = ['日','一','二','三','四','五','六'] let date = { 'yyyy': year, 'yy': year.slice(2), 'MM': ten(month), 'M': month, 'dd': ten(day), 'd': day, 'HH': ten(hour), 'H': hour, 'hh': ten(hour % 12), 'h': hour % 12, 'mm': ten(minutes), 'm': minutes, 'ss': ten(second), 's': second, 'w': week[t.getDay()] } for(let key in date) { str = str.replace(key,date[key]) } return str } // 不足10的前面要加0 let ten = num => num >= 10 ? num : '0' + num
考察知识点:
题目描述
若是第二个参数 bUnicode255For1 === true,则全部字符长度为 1
不然若是字符 Unicode 编码 > 255 则长度为 2
输入
hello world, 牛客', false
输出 17
function strLength(s, bUnicode255For1) { if(bUnicode255For1) return s.length; let len = s.length for(let i = 0; i < s.length; i++) { if(s[i].charCodeAt() > 255) len++ } return len }
相关知识点:
题目描述
判断输入是不是正确的邮箱格式
考察正则的一道题目,方法也是多种多样,这里只有一种简单的参考。
// ^ 表示开头 // [] 表示匹配字符的范围 // \w 表示正常符号 [0-9a-zA-Z_] // \. 是对任意符.进行转义,表示字符. // + 表示前面的表达式,一次到屡次 function isAvailableEmail(sEmail) { return /^[\w\.]+@\w+\.\w+/.test(sEmail) }
相关知识点:
题目描述
将 rgb 颜色字符串转换为十六进制的形式,如 rgb(255, 255, 255) 转为 #ffffff
- rgb 中每一个 , 后面的空格数量不固定
- 十六进制表达式使用六位小写字母
- 若是输入不符合 rgb 格式,返回原始输入
输入 :'rgb(255, 255, 255)'
输出 :#ffffff
function rgb2hex(sRGB) { // 正则匹配获取三个数值 let reg = sRGB.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)/) if(!reg) return sRGB; // 字符串拼接 let str = '#' for(let i = 1; i < reg.length; i++) { // 将字符串转成数字 let m = parseInt(reg[i]) if (m >= 0 && m <= 255) { // 而后转化成16进制 str += (m >= 16 ? m.toString(16) : '0' + m.toString(16)) } else { return sRGB } } return str }
相关知识点:
toString的进制转换
颜色是16进制,因此toString(16)能够获得结果
注意:必定要理解以后去程序里面运行一遍。