Yihui’s Blog

牛客网刷题04

31. 正确的函数定义

题目描述 请修复给定的 js 代码中,函数定义存在的问题 输入:true 输出:a

?好像没有问题

function functions(flag) {
 if (flag) {
   function getValue() { return 'a'; }
 } else {
   function getValue() { return 'b'; }
 }
 return getValue();
}
// 方法一:使用函数表达式
function functions(flag) {
    if (flag) {
      var getValue = ()  => { return 'a'; }
    } else {
      var getValue = () => { return 'b'; }
    }
 
    return getValue();
}

// 上面的等同于下面的,变量提升
function functions(flag) {
    var getValue
    if (flag) {
      getValue = () => { return 'a'; }
    } else {
      getValue = () => { return 'b'; }
    }

    return getValue();
}

相关知识点:

  • 函数的定义方式

函数声明式:函数声明在函数没有执行之前就已经在作用域中会提升,同名的声明会进行覆盖,以下面的为准,那么程序执行的时候一直输出的就是b。

函数表达式:使用函数表达式,还是会进行变量的提升,只不过这次提升的是变量getValue,在执行的时候,才会根据if语句的流程控制执行不同的函数。

32. 正确的使用 parseInt

题目描述 修改 js 代码中 parseInt 的调用方式,使之通过全部测试用例 输入:‘12’ 输出:12 输入: ‘12px’ 输出:12 输入: ‘0x12’ 输出:0

// 方法,确定是10进制
function parse2Int(num) {
    return parseInt(num,10);
}

相关知识点:

  • parseInt

parseInt经常用于强制类型转换中显式转换成数字,接收两个参数,返回数值或者NaN

parseInt(string, radix) 第一个参数是字符串,必须传的。 第二个参数是数字的基数,2-36,如果不传或者传0都是以10位基数来计算,如果小于2(不等于0)或者大于36一律返回NaN,如果’0x’开头为16进制,‘0’开头不包括0是8进制。

parseInt强制类型转化的时候,**如果第一位不是数字就会返回NaN,如果第一位是数字,那么会把后面是数字的返回,不是数字的过滤掉。**如果是小数的话,会向下取整成整数。

33. 完全等同

题目描述 判断 val1 和 val2 是否完全等同

function identity(val1, val2) {
     return val1 === val2
}

相关知识点:

  • 等同

== 和 === 的区别,简单来说在于,== 只判断值相同,遇到问题,=== 还要判断类型是否相同。 这里其实我觉得还需要考虑NaN的问题,NaN !== NaN

34. 正确的函数定义

题目描述 实现一个打点计时器,要求

  1. 从 start 到 end(包含 start 和 end),每隔 100 毫秒 console.log 一个数字,每次数字增幅为 1
  2. 返回的对象中需要包含一个 cancel 方法,用于停止定时操作
  3. 第一个数需要立即输出
function count(start, end) {
    // 第一个立即输出
    console.log(start++)
    let time = setInterval(function () {
        if(start >= end) clearInterval(time)
        console.log(start++)
    },100)
    return {
        // 返回的方法是一个函数
        cancel: function () {
            clearInterval(time)
        }
    }
}

相关知识点:

  • setInterval

计时器,如果第一个要立即输出,那么需要手动写一次。 定义的时候接收两个参数,第一个是每次执行的函数,第二个是执行时间间隔。 返回值接收计时器名称,可以用于清空计时器用。

  • 闭包

35. 流程控制

题目描述 实现 fizzBuzz 函数,参数 num 与返回值的关系如下: 1、如果 num 能同时被 3 和 5 整除,返回字符串 fizzbuzz 2、如果 num 能被 3 整除,返回字符串 fizz 3、如果 num 能被 5 整除,返回字符串 buzz 4、如果参数为空或者不是 Number 类型,返回 false 5、其余情况,返回参数 num 输入: 15 ; 输出: fizzbuzz

// 方法一:if-else if-else
function fizzBuzz(num) {
    // 如果num为空或者不传,isNaN都为true
    if(isNaN(num)) return false
    if(num % 3 === 0 && num % 5 === 0) {
        return 'fizzbuzz'
    } else if (num % 3 === 0) {
        return 'fizz'
    } else if (num % 5 === 0) {
        return 'buzz'
    } else {
        return num
    }
}

// 方法二:观察合理使用if
function fizzBuzz(num) {
    if (isNaN(num)) return false;
    let str = '';
    if (num % 3 === 0) str += 'fizz';
    if (num % 5 === 0) str += 'buzz';
    
    return str === '' ? num : str;
}

相关知识点:

  • 流程控制:if-else
  • isNaN

isNaN(),遇到不是Number类型的判断都用这个函数,如果参数不是数字就返回true,其他的判断我觉得都不是这个题要考的。ES6之后新增了方法Number.isNaN() 判断是否是NaN

  • 取余 %

36. 函数传参

题目描述 将数组 arr 中的元素作为调用函数 fn 的参数 输入: function (greeting, name, punctuation) {return greeting + ’, ’ + name + (punctuation || ’!’);}, [‘Hello’, ‘Ellie’, ’!’] 输出: Hello, Ellie!

// 方法一:量身定做,传的是数组
function argsAsArray(fn, arr) {
    return fn.apply(this,arr)
}

// 方法二:如果用call就需要使用扩展符打散
function argsAsArray(fn, arr) {
    return fn.call(this,...arr)
}

// 方法三:如果bind处理
function argsAsArray(fn, arr) {
    return fn.bind(this,...arr)()
}

相关知识点:

  • apply/call/bind (详情见一的第一题)
  • fn传参问题

37. 函数的上下文

题目描述 将函数 fn 的执行上下文改为 obj 对象 输入: function () {return this.greeting + ’, ’ + this.name + ’!!!’;}, {greeting: ‘Hello’, name: ‘Rebecca’} 输出:Hello, Rebecca!!!

// 方法一:apply
function speak(fn, obj) {
    return fn.apply(obj)
}

// 方法一:call
function speak(fn, obj) {
    return fn.call(obj)
}

// 方法一:bind
function speak(fn, obj) {
    return fn.bind(obj)()
}

相关知识点:

  • this指向

apply/call/bind 都可以修改执行上下文,如果直接调用fn,this指的是window,如果用 apply/call/bind 可以将this改成对象obj

38. 返回函数

题目描述 实现函数 functionFunction,调用之后满足如下条件: 1、返回值为一个函数 f 2、调用返回的函数 f,返回值为按照调用顺序的参数拼接,拼接字符为英文逗号加一个空格,即 ’, ’ 3、所有函数的参数数量为 1,且均为 String 类型 输入: functionFunction(‘Hello’)(‘world’) 输出: Hello, world

// 方法一:直接用扩展运算符获取参数
function functionFunction(str) {
    return function f(...arg) {
        // 记得逗号之后要加一个空格,才能过oj
        return str + ', '+arg
    }
}

// 方法二:用原生方法获取参数
function functionFunction(str) {
    return function() {
        return  str+ ', ' + arguments[0]
    }
}

相关知识点:

  • 闭包 + 柯里化

闭包是一个函数可以访问另一个函数作用域的变量。

39. 使用闭包

题目描述 实现函数 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) {
    let result = []
    for(let i = 0; i < arr.length; i++) {
        result.push(function(){
          return fn(arr[i])  
        })
    }
    return result
}

相关知识点:

  • 闭包

上面的题,如果不用闭包,那么for循环的嘶吼,最后调用函数的时候,i都是arr.length,如果使用闭包,可以是当时循环的i值。

40. 二次封装函数

题目描述 已知函数 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!!!

// 方法一:直接调用,因为没有涉及到this,这里直接用arguments来获取,因为arguments是类数组
function partial(fn, str1, str2) {
    return function result() {
        return fn(str1,str2,arguments[0])
    }
}

// 方法二:用扩展运算符拿到参数传入,更加的通用
function partial(fn, str1, str2) {
    return function result(...arg) {
        return fn(str1,str2,arg)
    }
}

// 方法二:ES6箭头函数,this指的是undefined
const partial = (fn, str1, str2) => str3 => fn(str1, str2, str3)

相关知识点:

  • 闭包
  • 获取函数参数arguments

arguments 类数组, 获取长度arguments.length 获取元素用数组下标arguments[0] 获取当前执行的函数 arguments.callee (ES5严格模式下禁用)

后面的东西可能会上一些小难度~~~

维护与整理 · Yihui在 GitHub 上编辑