目录

  • 引言

    1. 批改 this 指向(中等)
    2. 获取 url 参数(较难)
    3. dom 节点查找(入门)
    4. 依据包名,在指定空间中创建对象(入门)
    5. 数组去重(较难)
    6. 斐波那契数列(入门)
    7. 工夫格式化输入(中等)
    8. 获取字符串的长度(简略)
    9. 邮箱字符串判断(中等)
    10. 色彩字符串转换(中等)

    引言

    牛客网这个前端口试题库,能够说这60道是最根底的了,也是考查的货色比拟杂,有工夫4天差不多就能够刷完,坚固根底还是有些用的。做完题回顾一上午就能够过完一遍。当初我联合我的答案和参考的其他人的答案,在这里做一个总结,也是本人常识的整顿后果。

    题目

    1. 批改this指向

    封装函数 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)}

相干知识点:

  1. apply、call、bind区别

    apply、call、bind的作用都是批改执行上下文
    apply、call都是返回函数立刻执行的后果,其中apply第二个参数之后是数组,call第二个参数之后是单个的值。
    bind返回的是函数,须要手动执行后果。第二个参数之后是单个的值。

2. 获取url参数

获取 url 中的参数

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

输出:http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe key

输入:[1, 2, 3]

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 ? {} : ''        }      }

相干知识点:

  • 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办法

    字符串宰割成数组的办法,外面的参数是以什么宰割,如果不传就是空字符串为宰割,返回值是一个数组。
  • query局部能够应用正则

3. dom节点查找

查找两个节点的最近的一个独特父节点,能够包含节点本身

输出形容:
oNode1 和 oNode2 在同一文档中,且不会为雷同的节点

function commonParentNode(oNode1, oNode2) {    if(oNode1.contains(oNode2)) {        return oNode1    } else {        return commonParentNode(oNode1.parentNode,oNode2)    }}

相干知识点:

  • contains API

    查看dom元素蕴含关系,蕴含返回true,不蕴含返回false
    参考MDN
  • 递归(参考数据结构树)

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

依据包名,在指定空间中创建对象
输出形容:
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)
  • 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]"
  • 递归(对象的嵌套参考数据结构中的树)

5. 数组去重

为 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() 用来判断是否属于数字

6. 斐波那契数列

用 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}

相干知识点:

  • 递归

7. 工夫格式化输入

题目形容
按所给的工夫格局输入指定的工夫
格局阐明
对于 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

考查知识点:

  • 获取年月日周时分秒的零碎API
  • 格局对立解决
  • 字符串替换 (replace)

8. 获取字符串的长度

题目形容
如果第二个参数 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}

相干知识点:

  • 获取字符的 Unicode 编码 API —— str.charCodeAt()

9. 邮箱字符串判断

题目形容
判断输出是否是正确的邮箱格局

考查正则的一道题目,办法也是多种多样,这里只有一种简略的参考。

// ^ 示意结尾// [] 示意匹配字符的范畴// \w 示意失常符号 [0-9a-zA-Z_]// \. 是对任意符.进行本义,示意字符.// + 示意后面的表达式,一次到屡次function isAvailableEmail(sEmail) {    return /^[\w\.]+@\w+\.\w+/.test(sEmail)}

相干知识点:

  • 邮箱格局
  • 正则表达式的规定和匹配

10. 色彩字符串转换

题目形容
将 rgb 色彩字符串转换为十六进制的模式,如 rgb(255, 255, 255) 转为 #ffffff

  1. rgb 中每个 , 前面的空格数量不固定
  2. 十六进制表达式应用六位小写字母
  3. 如果输出不合乎 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)能够失去后果
  • 字符串中如何截取数字(不限于正则)

留神:肯定要了解之后去程序外面运行一遍。