前端JS编程题

1.题目描述 找出数组 arr 中重复出现过的元素 输入 [1, 2, 4, 4, 3, 3, 1, 5, 3] 输出 [1, 3, 4]

function duplicates() {
var arr = [1, 2, 4, 4, 3, 3, 1, 5, 3]
var temp = [];
arr.forEach(function(elem){
if(arr.indexOf(elem) != arr.lastIndexOf(elem) && temp.indexOf(elem) == -1){
temp.push(elem);
}
});
return temp;
}

做法:
1.找出重复的数组项‘[1,4,4,3,3,1,3]
2.在重复的数组项中做一个去重,筛选出[1,3,4]

2.数组去重

1.它是最简单的数组去重方法(indexOf方法)

实现思路:新建一个数组,遍历去要重的数组,当值不在新数组的时候(indexOf为-1)就加入该新数组中;
var arr=[2,8,5,0,5,2,6,7,2];
function unique1(arr){
var hash=[];
for (var i = 0; i < arr.length; i++) {
if(hash.indexOf(arr[i])==-1){
hash.push(arr[i]);
}
}
return hash;
}

2.数组下标判断法

调用indexOf方法,性能和方法1差不多

实现思路:如果当前数组的第 i 项在当前数组中第一次出现的位置不是 i,那么表示第 i 项是重复的,忽略掉。否则存入结果数组。

function unique2(arr){
var hash=[];
for (var i = 0; i < arr.length; i++) {
if(arr.indexOf(arr[i])==i){
hash.push(arr[i]);
}
}
return hash;
}

3.题目描述 给定字符串 str,检查其是否符合如下格式

		1、XXX-XXX-XXXX 2、其中 X 为 Number 类型
    首先:(\d{3}-) 重复了两次,所以是(\d{3}-){2}。即XXX-XXX-。
    然后:d{4}。即XXXX。
    最后,全局匹配,所以加上开始符^和结束符$。
    */
    function matchesPattern(str) {
        var res=/^(\d{3}\-){2}\d{4}$/;
        return  res.test(str);
    }
    console.log(matchesPattern('800-555-1212'));
	

## 4.给定字符串 str,检查其是否包含 连续3个数字 1、如果包含,返回最先出现的 3 个数字的字符串 2、如果不包含,返回 false
function captureThreeNumbers(str) {
  var reg;
  if(reg = str.match(/(\d{3})/)){
    return reg[0];
  }else{
    return false;
  }
}

## 5.题目描述 找出元素 item 在给定数组 arr 中的位置 输出描述: 如果数组中存在 item,则返回元素在数组中的位置,否则返回 -1
function indexOf(arr, item) {
  if (Array.prototype.indexOf){   //判断当前浏览器是否支持
      return arr.indexOf(item);
  } else {
      for (var i = 0; i < arr.length; i++){
          if (arr[i] === item){
              return i;
          }
      }
  }     
  return -1;     //总是把return -1暴漏在最外层
}

## 6.题目描述 计算给定数组 arr 中所有元素的总和 输入描述: 数组中的元素均为 Number 类型
function sum(arr) {
    var arr
    var sum = 0
    for(var i =0;i str3 => fn(str1, str2, str3);

## 19.题目描述 函数 useArguments 可以接收 1 个及以上的参数。请实现函数 useArguments,返回所有调用参数相加后的结果。本题的测试参数全部为 Number 类型,不需考虑参数转换。
这里重点就是类数组对象:arguments -- 接收所有传入函数的参数值的类数组对象,它有两个特点跟数组很像,1.可以用下标访问每个元素2.具有length属性。
这里最好先通过Array.prototype.slice.call(我们的类数组对象) 将其转换成一个真正的数组对象,然后再遍历求和即可。
function useArguments() {
var aArguments=Array.prototype.slice.call(arguments);
    var sum=0;
    aArguments.forEach(function(value){
        sum+=value;
    });
    return sum;
}

## 20.题目描述 实现函数 callIt,调用之后满足如下条件 1、返回的结果为调用 fn 之后的结果 2、fn 的调用参数为 callIt 的第一个参数之后的全部参数
function callIt(fn) {
    let args = Array.prototype.slice.call(arguments,1)
    return fn.apply(this,args)
}

## 21.题目描述 实现函数 partialUsingArguments,调用之后满足如下条件: 1、返回一个函数 result 2、调用 result 之后,返回的结果与调用函数 fn 的结果一致 3、fn 的调用参数为 partialUsingArguments 的第一个参数之后的全部参数以及 result 的调用参数
function partialUsingArguments(fn) {
    let args1 = Array.prototype.slice.call(arguments, 1);  //获得函数partialUsingArguments()  除第一个参数外的参数数组
    return function() {
        let args2 = Array.prototype.slice.call(arguments, 0)   //获得函数的参数数组
        return fn.apply(this, args1.concat(args2))
    }
}

## 22.什么是柯里化?
维基百科上说道:柯里化,英语:Currying(果然是满满的英译中的既视感),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

curry的一些性能问题你只要知道下面四点就差不多了:

存取arguments对象通常要比存取命名参数要慢一点
一些老版本的浏览器在arguments.length的实现上是相当慢的
使用fn.apply( … ) 和 fn.call( … )通常比直接调用fn( … ) 稍微慢点
创建大量嵌套作用域和闭包函数会带来花销,无论是在内存还是速度上
其实在大部分应用中,主要的性能瓶颈是在操作DOM节点上,这js的性能损耗基本是可以忽略不计的,所以curry是可以直接放心的使用。

## 23. 实现一个add方法,使计算结果能够满足如下预期:

add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;

function add() {
    // 第一次执行时,定义一个数组专门用来存储所有的参数
    var _args = Array.prototype.slice.call(arguments);

    // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
    var _adder = function() {
        _args.push(...arguments);
        return _adder;
    };

    // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
    _adder.toString = function () {
        return _args.reduce(function (a, b) {
            return a + b;
        });
    }
    return _adder;
}

add(1)(2)(3)                // 6
add(1, 2, 3)(4)             // 10
add(1)(2)(3)(4)(5)         // 15
add(2, 6)(1)                // 9

## 24.题目描述 已知 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 的调用参数
柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。简单理解题目意思,就是指,我们将预定义的函数的参数逐一传入到curryIt中,当参数全部传入之后,就执行预定义函数。于是,我们首先要获得预定义函数的参数个数fn.length,然后声明一个空数组去存放这些参数。返回一个匿名函数接收参数并执行,当参数个数小于fn.length,则再次返回该匿名函数,继续接收参数并执行,直至参数个数等于fn.length。最后,调用apply执行预定义函数。

function curryIt(fn) {
     //获取fn参数的数量
     var n = fn.length;
     //声明一个数组args
     var args = [];
     //返回一个匿名函数
     return function(arg){
         //将curryIt后面括号中的参数放入数组
         args.push(arg);
         //如果args中的参数个数小于fn函数的参数个数,
         //则执行arguments.callee(其作用是引用当前正在执行的函数,这里是返回的当前匿名函数)。
         //否则,返回fn的调用结果
         if(args.length < n){
            return arguments.callee;
         }else return fn.apply("",args);
     }
 }

## 25.题目描述 完成函数 createModule,调用之后满足如下要求: 1、返回一个对象 2、对象的 greeting 属性值等于 str1, name 属性值等于 str2   3、对象存在一个 sayIt 方法,该方法返回的字符串为 greeting属性值 + ', ' + name属性值
function createModule(str1, str2) {
		    var obj = {
		        greeting:str1,
		        name:str2,
		        sayIt : function (){
		            return this.greeting + ', ' + this.name  //注意逗号后面有空格
		        }
		    }
		    return obj
}

## 26.题目描述 求 a 和 b 相乘的值,a 和 b 可能是小数,需要注意结果的精度问题
function multiply(a, b) {
    return parseFloat((a*b).toFixed(10));
}

## 27.题目描述 将函数 fn 的执行上下文改为 obj,返回 fn 执行后的值
在JavaScript中,函数是一种对象,其上下文是可以变化的,对应的,函数内的this也是可以变化的,函数可以作为一个对象的方法,也可以同时作为另一个对象的方法,可以通过Function对象中的call或者apply方法来修改函数的上下文,函数中的this指针将被替换为call或者apply的第一个参数。将函数 fn 的执行上下文改为 obj 对象,只需要将obj作为call或者apply的第一个参数传入即可。

共有四种正确方案(按提交的运行时间由快到慢排列):

1. apply 方法改变函数 this 值(平均 172ms )

function alterContext(fn, obj) {
	return fn.apply(obj); 
}
2. call 方法改变函数 this 值(178 ms)

function alterContext(fn, obj) {
  return fn.call(obj); 
}
3. bind 方法创建指定 this 值的函数实例(208 ms)

function alterContext(fn, obj) {
  const bindedFn = fn.bind(obj);
  return bindedFn();
}
4. 给 obj 增加 fn 方法(213 ms)

function alterContext(fn, obj) {
    obj.fn = fn;
  return obj.fn();
}

## 28.给定一个构造函数 constructor,请完成 alterObjects 方法,将 constructor 的所有实例的 greeting 属性指向给定的 greeting 变量。
function alterObjects(constructor, greeting) {
     constructor.prototype.greeting = greeting;    
}

## 29.题目描述 找出对象 obj 不在原型链上的属性(注意这题测试例子的冒号后面也有一个空格~) 1、返回数组,格式为 key: value 2、结果数组不要求顺序
题目要求找不在原型链上的属性,即返回实例属性,有3种正确方法(按提交运行速度由快到慢排列):
1. Object.keys 方法(156 ms)
返回可枚举的实例属性的数组。

function iterate(obj) {
    return Object.keys(obj).map(function(key) {
        return key + ":  " + obj[key];
    });
}

2. for-in 和 hasOwnProperty 方法(171 ms)
前者用于遍历所有属性,后者用于判断是否为实例属性。

function iterate(obj) {
    const res = [];
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) {
            res.push(prop + ":  " + obj[prop]);
        }
    }
    return res;
}
3. Object.getOwnPropertyNames 方法(209 ms)
用法跟1一样,区别在于返回的是所有实例属性(包括不可枚举的)。

function iterate(obj) {
    return Object.getOwnPropertyNames(obj).map(function(key) {
        return key + ":  " + obj[key];
    });
}

注意:
1. 居然不支持 let。。。。。。改成 var 就行了
2. 是的,箭头函数也不支持。。。
3. 题目没有说明返回的实例属性是否包括不可枚举的,这里理解为包括。否则,由于 Object.keys() 返回的仅为可枚举的实例属性,应该无法通过。

## 30.题目描述 给定字符串 str,检查其是否包含数字,包含返回 true,否则返回 false
function containsNumber(str) {
    return /\d/.test(str)
}

## 31.题目描述 给定字符串 str,检查其是否包含连续重复的字母(a-zA-Z),包含返回 true,否则返回 false
function containsRepeatingLetter(str) {
    return /([a-zA-Z])\1/.test(str);   //\1表示重复正则第一个圆括号内匹配到的内容;  \2表示重复正则第二个圆括号内匹配到的内容
}

## 32.题目描述 获取数字 num 二进制形式第 bit 位的值。注意: 1、bit 从 1 开始  2、返回 0 或 1   3、举例:2 的二进制为 10,第 1 位为 0,第 2 位为 1
function valueAtBit(num, bit) {
    return (num >> (bit -1)) & 1;
}

## 33.题目描述 给定二进制字符串,将其换算成对应的十进制数字
function base10(str) {
    /**
        其它进制转十进制
        parseInt(str,2)
        parseInt(str,8)
        parseInt(str,16)
    */
    return parseInt(str,2);
}

## 34.题目描述 将给定数字转换成二进制字符串。如果字符串长度不足 8 位,则在前面补 0 到满8位。
首先通过toString方法将num转为2进制数形式,然后判断其长度是否足够8位。如不足8位,则声明一个“0000000”字符串用于补0,因为目标的2进制数形式最少为一位,因此最多只需要7个0;通过slice方法对“0000000”进行截取,然后将其结果加在目标前面即可。
unction convertToBinary(num){
			//转换为2进制格式
			var s = num.toString(2);
			//获得2进制长度
			var len = s.length
			if(len < 8){
				//声明一个字符串用于补满0
				var s1 = '00000000'
				var s2 = s1.slice(0,8-len)
				s=s2 + s
			}
			return s
}

你可能感兴趣的:(前端JS编程题)