牛客 前端大挑战

柯里化

已知 fn 为一个预定义函数,实现函数 curryIt,调用之后满足如下条件:
1、返回一个函数 a,a 的 length 属性值为 1(即显式声明 a 接收一个参数)
2、调用 a 之后,返回一个函数 b, b 的 length 属性值为 1
3、调用 b 之后,返回一个函数 c, c 的 length 属性值为 1
4、调用 c 之后,返回的结果与调用 fn 的返回值一致
5、fn 的参数依次为函数 a, b, c 的调用参数

输入
var fn = function (a, b, c) {return a + b + c}; curryIt(fn)(1)(2)(3);

输出
6

function curryIt(fn) {
    let args = [];
    
    return function curried(arg){
        args.push(arg)
        if(args.length >= fn.length){
            return fn.apply(this,args)
        }
        else{
            return function(arg2){
                return curried.call(this,arg2)
            }
        }
    }
}

二次封装函数

实现函数 partialUsingArguments,调用之后满足如下条件:
1、返回一个函数 result
2、调用 result 之后,返回的结果与调用函数 fn 的结果一致
3、fn 的调用参数为 partialUsingArguments 的第一个参数之后的全部参数以及 result 的调用参数

function partialUsingArguments(fn) {
    let args1 = Array.prototype.slice.call(arguments, 1)
 
    return function() {
        let args2 = Array.prototype.slice.call(arguments, 0)
        return fn.apply(this, args1.concat(args2))
    }
}

已知函数 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!!!

function partial(fn, str1, str2) {
   //返回一个函数 result,该函数接受一个参数 
    return function(str3){
        //执行 result(str3) ,返回的结果与 fn(str1, str2, str3) 一致
        return fn(str1,str2,str3); 
    }
}

使用apply函数调用

实现函数 callIt,调用之后满足如下条件
1、返回的结果为调用 fn 之后的结果
2、fn 的调用参数为 callIt 的第一个参数之后的全部参数

function callIt(fn) {
     let args = Array.prototype.slice.call(arguments, 1) 
     return fn.apply(this, args)
}
  • apply() 和 call()方法
    person 的 fullName 方法被应用到 person

    var person = {
        fullName: function() {
            return this.firstName + " " + this.lastName;
        }
    }
    var person1 = {
        firstName: "Bill",
        lastName: "Gates",
    }
    person.fullName.apply(person1);  // 将返回 "Bill Gates"
    
  • call() 和 apply() 之间的区别

    不同之处是:
    call() 方法分别接受参数。
    apply() 方法接受数组形式的参数。
    如果要使用数组而不是参数列表,则 apply() 方法非常方便。

  • apply方法能劫持另外一个对象的方法,继承另外一个对象的属性
    Function.apply(obj,args)方法能接收两个参数
    obj:这个对象将代替Function类里this对象
    args:这个是数组,它将作为参数传给

闭包:
如果在函数func内部声明函数inner,然后在函数外部调用inner,这个过程即产生了一个闭包。
闭包最大的用处有两个:可以读取到函数内部的变量,让这些变量的值始终保持在内存中

使用arguments

函数useArguments可以接收1个及以上的参数。请实现函数useArguments,返回所有调用参数相加后的结果。

function useArguments() {
    let sum = 0;
    for(let i = 0; i < arguments.length; i++){
        sum += arguments[i];
    }
    return sum;
}
  • Arguments对象
    arguments 是一个对应于传递给函数的参数的类数组对象

    arguments对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引0处。例如,如果一个函数传递了三个参数,你可以以如下方式引用他们:

    arguments[0]
    arguments[1]
    arguments[2]
    

    arguments对象不是一个 Array 。它类似于Array,但除了length属性和索引元素之外没有任何Array属性。例如,它没有 pop 方法。但是它可以被转换为一个真正的Array

使用闭包

实现函数 makeClosures,调用之后满足如下条件:
1、返回一个函数数组 result,长度与 arr 相同
2、运行 result 中第 i 个函数,即 resulti,结果与 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[i] = fn.bind(this.arr[i]);
  }
  return result;
}
ES6 新增了let命令,用来声明局部变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效,而且有暂时性死区的约束

返回函数

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

function functionFunction(str) {
   return f = function(arr){
        return str+", "+arr;
    };
}

函数的上下文

将函数 fn 的执行上下文改为 obj 对象

输入
function () {return this.greeting + ', ’ + this.name + ‘!!!’;}, {greeting: ‘Hello’, name: ‘Rebecca’}
输出
Hello, Rebecca!!!

function speak(fn, obj) {
    obj.fn = fn
    return obj.fn()
}

函数传参

将数组 arr 中的元素作为调用函数 fn 的参数

function argsAsArray(fn, arr) {
    return fn.apply(this,arr)
}

计时器

实现一个打点计时器,要求
1、从 start 到 end(包含 start 和 end),每隔 100 毫秒 console.log 一个数字,每次数字增幅为 1
2、返回的对象中需要包含一个 cancel 方法,用于停止定时操作
3、第一个数需要立即输出

function count(start, end) {
    console.log(start); //立即输出第一个数
    var timer = setInterval(()=>{
        if(start<end){//从start到end
            console.log(++start);//每次数字增幅为1     
        }
        else{
            clearInterval(timer);
        }
    },100) //100毫秒执行一次
    return{//返回一个包含cancel的方法
        cancel(){
            clearInterval(timer);
        }        
    }
}

正确的使用parseInt

修改 js 代码中 parseInt 的调用方式,使之通过全部测试用例

function parse2Int(num) {
    var reg = /[a-zA-Z]/g;
    var res = new RegExp(/^(?![^a-zA-Z]+$)/);
    if(res.test(num)){
        return parseInt(num.split(reg)[0]);
    }
    return parseInt(num);
}

正确的函数定义

请修复给定的 js 代码中,函数定义存在的问题
思路:else中的语句相当于将if中的function重写,因此无论flag为何值,返回的方法始终为重写后的方法。将方法赋值给一个变量,方法就不会被重写,因此才能得到正确的结果。

function functions(flag) {
    /*if (flag) {
      function getValue() { return 'a'; }
    } else {
      function getValue() { return 'b'; }
    }*/
    if(flag){
        var getValue = function(){
            return 'a';
        }
    }else{
        var getValue = function(){
            return 'b';
        }
    }
    return getValue();
}

避免全局变量

给定的 js 代码中存在全局变量,请修复
思路:在Javascript语言中,声明变量使用的都是关键字var,如果不使用var而直接声明变量,则该变量为全局变量。

function globals() {
    var myObject = {
      name : 'Jory'
    };

    return myObject;
}

查找元素位置

在数组 arr 中,查找值与 item 相等的元素出现的所有位置
输入
[‘a’,‘b’,‘c’,‘d’,‘e’,‘f’,‘a’,‘b’,‘c’] ‘a’
输出
[0, 6]

function findAllOccurrences(arr, target) {
    let newArr = [];
    arr.forEach((el,index)=>{
        if(el == target){
            newArr.push(index);
        }
    })
    return newArr;
}

求二次方

为数组 arr 中的每个元素求二次方。不要直接修改数组 arr,结果返回新的数组

function square(arr) {
  return arr.map(el => Math.pow(el,2))
}

查找重复元素

找出数组 arr 中重复出现过的元素

function duplicates(arr) {
    var temp = [];
    arr.forEach(function(elem){
        if(arr.indexOf(elem) != arr.lastIndexOf(elem)&& temp.indexOf(elem) == -1){
            temp.push(elem);
        }
    });
    return temp;
}
forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。
indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
stringObject.indexOf(searchvalue,fromindex)
lastIndexOf() 方法可返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。
stringObject.lastIndexOf(searchvalue,fromindex)

计数

统计数组 arr 中值等于 item 的元素出现的次数

// 相同的加一
function count(arr, item) {
    var j = 0;
    arr.forEach(function (ele) {
        if (ele == item)
           j++;
    });
    return j;
}
//去除不同的,返回长度
function count(arr, item) {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] != item) {
            arr.splice(i, 1);
            i--;
        }
    }
    return arr.length;
}
//遇到不同的往前移动,然后返回长度
function count(arr, item) {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] != item) {
            for (var j = i; j < arr.length; j++) {
                arr[j] = arr[j + 1];
            }
            arr.pop();
            i--;
        }
    }
    return arr.length;

添加元素

在数组 arr 的 index 处添加元素 item。不要直接修改数组 arr,结果返回新的数组

function insert(arr, item, index) {
    var temp = arr.slice(0);//从某个已有的数组返回选定的元素
    temp.splice(index,0,item);//删除元素并向数组添加新元素
    return temp;
}
  • Array对象方法

    方法描述
    concat()连接两个或更多的数组,并返回结果
    join()把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔
    pop()删除并返回数组的最后一个元素
    push()向数组的末尾添加一个或更多元素,并返回新的长度
    reverse()颠倒数组中元素的顺序
    shift()删除并返回数组的第一个元素
    slice()从某个已有的数组返回选定的元素
    sort()对数组的元素进行排序
    splice()删除元素,并向数组添加新元素
    toSource()返回该对象的源代码
    toString()把数组转换为字符串,并返回结果。
    toLocaleString()把数组转换为本地数组,并返回结果.
    unshift()向数组的开头添加一个或更多元素,并返回新的长度
    valueOf()返回数组对象的原始值

数组合并

合并数组 arr1 和数组 arr2。不要直接修改数组 arr,结果返回新的数组

//第一种:字符串方式
function concat(arr1, arr2) {
    return (arr1 + "," + arr2).split(",");
}

//第二种:原生concat方式
function concat(arr1, arr2) {
    return arr1.concat(arr2);
}

//第三种:扩展运算符...
function concat(arr1, arr2) {
    return [...arr1, ...arr2];
}

删除数组第一个元素

//使用shift方法
function cuttail(arr) {
    var newArr = arr.slice(0);
    newArr.shift();
    return newArr;
}
//使用splice切除第一个元素
function cuttail(arr) {
    var newArr = arr.slice(0);
    return newArr.splice(0,1);
 
}
//使用slice赋值元素,其实可以直接return arr.slice(0);
function cuttail(arr) {
    var newArr = arr.slice(0);
    console.log(newArr);
    return newArr.slice(1);
}
//每个元素往前移动,最后再pop一下
function cuttail(arr) {
    var newArr = arr.slice(0);
    for (var i = 0; i < newArr.length - 1; i++) {
        newArr[i] = newArr[i + 1];
    }
    newArr.pop();
    return newArr;
}
//使用filter函数过滤
function cuttail(arr) {
    return arr.filter(function (ele,i) {
        return i != 0;
    });
}

添加元素

在数组 arr 开头添加元素 item。不要直接修改数组 arr,结果返回新的数组

function prepend(arr, item) {
    let arr1 = [];
    for(let i=0;i<arr.length;i++){
        arr1[i] = arr[i]
    }
    arr1.unshift(item)
    return arr1
}

在数组 arr 末尾添加元素 item。不要直接修改数组 arr,结果返回新的数组

function append(arr, item) {
    var arr1 = arr.slice(0);
    arr1.push(item);
    return arr1;
}

删除数组最后一个元素

删除数组 arr 最后一个元素。不要直接修改数组 arr,结果返回新的数组

function truncate(arr) {
  var newArray = arr.slice(0, arr.length - 1); 
  return newArray;
}

移除数组中的元素

移除数组 arr 中的所有值与 item 相等的元素,直接在给定的 arr 数组上进行操作,并将结果返回
indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。

function removeWithoutCopy(arr, item) {
    while(arr.indexOf(item)!==-1){
        arr.splice(arr.indexOf(item),1);
    }
    return arr;
}

移除数组 arr 中的所有值与 item 相等的元素。不要直接修改数组 arr,结果返回新的数组

function remove(arr, item) {
 	var arr2=arr.filter(value=>{return value!=item})
	return arr2
}

数组求和

计算给定数组arr中所有元素的总和

function sum(arr) {
    var suma = 0;
    for(var i = 0; i < arr.length; i++){
        suma += arr[i];
    }
    return suma;
}
//函数式编程
function sum(arr) {
    return arr.reduce(function(prev, curr, idx, arr){
        return prev + curr;
    });
}
//foreach方法
function sum(arr) {
    var s = 0;
    arr.forEach(function(val, idx, arr) {
        s += val;
    }, 0);
  
    return s;
};
//eval
function sum(arr) {
    return eval(arr.join("+"));
};

查找数组元素位置

找出元素 item 在给定数组 arr 中的位置

function indexOf(arr, item) {
    while(arr.length > 0) {
        if (arr.pop() == item)
            return arr.length;
    }
    return -1;
}

设置文字颜色

请使用嵌入样式将所有p标签设置为红色文字

<p>欢迎来到牛客网</p>
<p>在这里,我们为你提供了IT名企的笔试面试题库</p>
<p>在这里,我们以题会友</p>
<p>QQ群号:272820159</p>
var aP = document.getElementsByTagName('p');
for(var i=0;i<aP.length;i++)
	aP[i].style.color = 'red';

段落标识

请将下面这句话以段落的形式展示在浏览器中——“牛客网是一个专注于程序员的学习和成长的专业平台。”

加粗文字

使用一个标签将“牛客网”三个字加粗显示

<p>牛客网,程序员必备求职神器</p>
let p = document.querySelector('p');
let t= p.innerText;
t = t.splice('牛客网').join('<strong>牛客网</strong>');
p.innerHTML = t;

方法2

let p = document.getElementsByTagName("p")[0]
p.innerHTML = p.innerText.replace("牛客网","<strong style='font-weight:999'>牛客网</strong>")

字符串字符统计

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

  1. 不限制 key 的顺序
  2. 输入的字符串参数不会为空
  3. 忽略空白字符
function count(str) {
   let obj = {}
   for(var i = 0;i<str.length;i++){
       if(str[i]!==''){
           var key = str[i];
           if (obj[key] !== undefined){
               obj[key] = obj[key] + 1;
           }
           else{
               obj[key]=1;
           }
       }         
   }
    return obj
}

将字符串转换成驼峰格式

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

  1. 以 - 为分隔符,将第二个起的非空单词首字母转为大写
  2. -webkit-border-image 转换后的结果为 webkitBorderImage
function cssStyle2DomStyle(sName) {
   return sName.replace(/^-/, '').replace(/-([a-z])/g, (_, $) => $.toUpperCase());
}

数组去重

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

Array.prototype.uniq = function () {
    return Array.from(new Set(this))
}

Set数据结构类似于数组,但里面的成员都是唯一的,判断是否唯一的标准基本等同于===,唯一的区别在于, ‘===’判断是NaN与NaN不相等,但Set会认为它们相等并去重。
由于Set只是类似数组,所以要用Array.from返回一个真正的数组。

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

function namespace(oNamespace, sPackage) {
    var list = sPackage.split('.');
    if (list[0] === '') {
        return;
    }
    if (oNamespace[list[0]] instanceof Object) {
        namespace(oNamespace[list[0]], list.slice(1).join('.'));
    } 
    else{
        oNamespace[list[0]] = {};
        namespace(oNamespace[list[0]], list.slice(1).join('.'));
    }
 };

dom节点查找

查找两个节点的最近的一个共同父节点,可以包括节点自身
思路:判断一个节点以及它的父节点是否包含另一个节点。

function commonParentNode(oNode1, oNode2) {
    while(true){
        oNode1 = oNode1.parentNode;
        if(oNode1.contains(oNode2)){
            return oNode1;
        }
    }
}
function commonParentNode(oNode1, oNode2) {
  let parent1 = oNode1.parentNode;
  let parent2 = oNode2.parentNode;
  let parent3,parent4;
  let res = commonParent(parent1,parent2);
  return res;
 
  function commonParent(parent1,parent2){
    if(parent1 === parent2){
        return parent1;
    }else{
        parent3 = parent1.parentNode;
        parent4 = parent2.parentNode;
        //递归调用
        commonParent(parent3,parent4);
    }
  }
}

获取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) {
    var paramArr = sUrl.split('?')[1].split('#')[0].split('&'); // 取出每个参数的键值对放入数组
    const obj = {};
    paramArr.forEach(element => {
    const [key, value] = element.split('=');  // 取出数组中每一项的键与值
    if(obj[key] === void 0){   // 表示第一次遍历这个元素,直接添加到对象上面
    obj[key]=value
    } else{
    obj[key]=[].concat(obj[key],value); // 表示不是第一次遍历说明这个键已有,通过数组存起来。
    }});
    return sKey===void 0? obj:obj[sKey]||''   // 如果该方法为一个参数,则返回对象。
    //如果为两个参数,sKey存在,则返回值或数组,否则返回空字符。

}

修改this指向

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

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));
	}
}

箭头函数

箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this,arguments,super或new.target。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数

  • 基本语法

    (param1, param2,, paramN) => { statements }
    (param1, param2,, paramN) => expression
    //相当于:(param1, param2, …, paramN) =>{ return expression; }
    
    // 当只有一个参数时,圆括号是可选的:
    (singleParam) => { statements }
    singleParam => { statements }
    
    // 没有参数的函数应该写成一对圆括号。
    () => { statements }
    
  • 高级语法

    //加括号的函数体返回对象字面量表达式:
    params => ({foo: bar})
    
    //支持剩余参数和默认参数
    (param1, param2, ...rest) => { statements }
    (param1 = defaultValue1, param2,, paramN = defaultValueN) => {
    statements }
    
    //同样支持参数列表解构
    let f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
    f();  // 6	
    

引入箭头函数有两方面的作用:更简短的函数并且不绑定this

var elements = [
  'Hydrogen',
  'Helium',
  'Lithium',
  'Beryllium'
];
elements.map(function(element) {
  return element.length;
}); // 返回数组:[8, 6, 7, 9]
//上面的普通函数可以改写成如下的箭头函数
elements.map((element)=>{
  return element.length;
});
// 当箭头函数只有一个参数时,可以省略参数的圆括号
elements.map(element => {
 return element.length;
}); // [8, 6, 7, 9]

// 当箭头函数的函数体只有一个 `return` 语句时,可以省略 `return` 关键字和方法体的花括号
elements.map(element => element.length); // [8, 6, 7, 9]

// 在这个例子中,因为我们只需要 `length` 属性,所以可以使用参数解构
// 需要注意的是字符串 `"length"` 是我们想要获得的属性的名称,而 `lengthFooBArX` 则只是个变量名,
// 可以替换成任意合法的变量名
elements.map(({ "length": lengthFooBArX }) => lengthFooBArX); // [8, 6, 7, 9]
  • 没有单独的this
    在箭头函数出现之前,每一个新函数根据它是被如何调用的来定义这个函数的this值:
    • 如果是该函数是一个构造函数,this指针指向一个新的对象
    • 在严格模式下的函数调用下,this指向undefined
    • 如果是该函数是一个对象的方法,则它的this指针指向这个对象

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值