百度前端技术学院(IFE)2015春task练习记录01

前言

个人觉得IFE的练习非常不错,学习前端不久,看完几本Head First,JS编程艺术等等后,我就拿来当练习做了。初学者有时候会很迷惑,比如JS这块的练习,判断数据类型这一题其实我最开始都是搜索复制粘贴。做完之后也是迷迷糊糊的,只知道这样是对的,而不知其所以然。
做完之后去看看其他的笔试题面试题,才发现好多都是这里面出过的。练习里基本每个知识点都覆盖了,但要融会贯通,还要自己的基础知识够扎实。
当初看不懂的很多东西,现在回过头来看,也都能说出来为什么要这么做,其中有些什么知识点。如果能把里面的每个知识点都搞透彻了,我觉得前端基本算是入门了。
非常良心的,这是免费的,而且每个练习后,都有附上相关知识的资料、博客等的链接。如果有心,自学肯定是没问题的。
哈哈哈免费当个自来水宣传一下。废话太多了,接下来正题。

这是我自己做的时候记录下来的做题思路以及答案。
具体的问题点这里。

我是从2015_Spring开始做的,所有代码可以在我的Github中找到,记录从task002开始。
task0001都是HTML+CSS布局的练习,这个没什么思路,多练习多感受就好。(其实是自己写的烂不好意思拿出来
由于这边不好生成目录,这一块全部放出来又太长,于是分成了两篇发,全文可以去我的博客看哟

判断各种数据类型

要求

// 判断arr是否为一个数组,返回一个bool值
function isArray(arr) {
    // your implement
}

// 判断fn是否为一个函数,返回一个bool值
function isFunction(fn) {
    // your implement
}

思路

最开始使用typeof()方法,然后发现在判断array时返回是object,与判断对象类型时重合。在查阅资料后,使用了一种更为通用的方法。

实现

function getVarType(data) {
    if (data === undefined) {
        return 'Undefined';
    }
    if (data === null) {
        return 'Null';
    }
    return Object.prototype.toString.call(data).slice(8, -1).toLowerCase();
};

function isArray(arr) {
    if (getVarType(arr) == 'array') {
        return true;
    } else return false;
}

function isFunction(fn) {
    if (getVarType(fn) == 'function') {
        return true;
    } else return false;
}

补充

除此之外,还有instanceof和constructor等方法
typeof()方法,对于基本类型的判断十分有用。

typeof(123);//"number"
typeof("123");//"string"
typeof(false);//"boolean"
typeof(undefined);//"undefined"

//注意null和function得到的值
typeof(null);//"object"
typeof(function(){});//"function"

上面给出了所有使用typeof()比较特殊的结果,除此之外,所用的引用类型使用该方法得出的结果都是object
instanceof适用于判断引用类型。
MDN中这样描述:

instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。

并且看定义的语法是这样的:

object instanceof constructor

即是说,instanceof左边的,是一个对象,而右边必须是一个构造函数。如果左边是一个基本类型,那不管右边是什么,返回的一定是false
那么这个就可以用来判断引用类型了,例如

var arr = [1,2,3];
var date = new Date();
arr instanceof Array;//true
date instanceof Date;//true

//这里自定义一个构造函数
function Person(){}
var franose = new Person();
franose instanceof Person;//true;

深度克隆

要求

// 使用递归来实现一个深度克隆,可以复制一个目标对象,返回一个完整拷贝
// 被复制的对象类型会被限制为数字、字符串、布尔、日期、数组、Object对象。不会包含函数、正则对象等
function cloneObject(src) {
    // your implement
}

// 测试用例:
var srcObj = {
    a: 1,
    b: {
        b1: ["hello", "hi"],
        b2: "JavaScript"
    }
};
var abObj = srcObj;
var tarObj = cloneObject(srcObj);

srcObj.a = 2;
srcObj.b.b1[0] = "Hello";

console.log(abObj.a);
console.log(abObj.b.b1[0]);

console.log(tarObj.a);      // 1
console.log(tarObj.b.b1[0]);    // "hello"

思路

首先对判断参数类型,对于类型String, Boolean, Number,只需要新建一个变量,并将参数的值赋值给新建的变量即可;对于类型Data, Array, Object则要分情况。
Data():new一个Date对象,使用getTime()方法得到原对象的值,再使用setTime()给新建的对象赋值。
Array():new一个Array对象,使用for循环对原数组遍历,再依次赋值到新建的Array对象中。
Object():new一个对象,对对象中的属性遍历,使用递归对属性进行赋值,多层属性也可以使用递归解决。

实现

function cloneObject(data) {
    var objectType = getVarType(data);
    //the object for cloning is native object
    if (objectType == "null" || objectType == "undefined") {
        return data;
    }

    if (objectType == "string" || objectType == "number" || objectType == "boolean") {
        var copy = data;
        return copy;
    } else if (objectType == "date") {
        var copy = new Date();
        copy.setTime(data.getTime());
        return copy;
    } else if (objectType == "array") {
        var copy = [];
        for (var i = 0; i < data.length; i++) {
            copy[i] = cloneObject(data[i]);
        }
        return copy;
    } else if (objectType == "object") {
        var copy = {};
        for (var attr in data) {
            if (data.hasOwnProperty(attr)) {
                copy[attr] = cloneObject(data[attr]);
            }
        }
        return copy;
    }
}

补充

数组去重

要求

// 对数组进行去重操作,只考虑数组中元素为数字或字符串,返回一个去重后的数组
function uniqArray(arr) {
    // your implement
}

// 使用示例
var a = [1, 3, 5, 7, 5, 3];
var b = uniqArray(a);
console.log(b); // [1, 3, 5, 7]

思路

一开始的思路是先new一个数组,对原数组遍历,使用indexOf()函数,若新数组中没有当前遍历到的元素,则push到数组中去。

实现

function uniqArray(arr) {
    var uniqarr = [];
    for (i = 0; i < arr.length; i++) {
        if (uniqarr.indexOf(arr[i]) == -1) {
            uniqarr.push(arr[i]);
        }

    }
    return uniqarr;
}

补充

正则表达式

要求

// 对字符串头尾进行空格字符的去除、包括全角半角空格、Tab等
//返回一个字符串
// 尝试使用一行简洁的正则表达式完成该题目
function trim(str) {
    // your implement
}

// 使用示例
var str = '   hi!  ';
str = trim(str);
console.log(str); // 'hi!'
// 判断是否为邮箱地址
function isEmail(emailStr) {
    // your implement
}

// 判断是否为手机号
function isMobilePhone(phone) {
    // your implement
}

思路

这俩要求不在一起,但都是使用正则表达式实现的,所以就放在了一起。

  1. 首先是去掉一个字符串开头和结尾的表格,刚开始看错题了,以为就是去掉空格,这样给出的示例是能通过了,但是实现还是不对,于是用到了正则表达式里的分组,将字符串分为开头的空格结尾的空格以及中间的任意字符三组,最后结果取第二个分组即中间的任意字符即可。
    最开始正则式是这样写的(^\s*)(.*)(\s*$),但这里有个问题是开头的空格能够去掉了,结尾的空格却去不掉。因为对第二个分组中的正则式而言,匹配到任意字符串,即紧接在它之后的任意个空格也算在了里面,这样就不会匹配第三个分组的正则式。
    所以在最后这里还用到了一个正则表达式中的向前匹配,正则表达式改为(^\s*)(.*)(?=\S\s*$),即在匹配空格时还要查看前面的字符是否为非空字符。
    但是这样的问题是结尾的空格的前一个字符也被当做第三组里的了,尝试了几次发现这样的思路没法实现,于是查了一下jq源码,发现用一个或者运算符就可以搞定。
    于是最后的正则式定为^\s+|\s+$
  2. 这个比较简单,网上类似的表达式很多,随便写了一下,匹配不太严格,但是基本能符合要求。

实现

    function trim(str) {
        var reg = /^\s+|\s+$/g;
        return str.replace(reg, "");
    }
// 判断是否为邮箱地址
function isEmail(emailStr) {
    var reg = /^[a-zA-z0-9_\.-]+@[a-zA-z0-9\.-]+\.[a-z]{2,6}$/g;
    if (reg.test(emailStr) == true) {
        return true;
    } else return false;
}

// 判断是否为手机号
function isMobilePhone(phone) {
    var reg = /^1[34578]\d{9}$/g;
    if (reg.test(phone) == true) {
        return true;
    } else return false;
}

补充

暂无

数组和对象遍历

要求

// 实现一个遍历数组的方法,针对数组中每一个元素执行fn函数
//并将数组索引和元素作为参数传递
function each(arr, fn) {
    // your implement
}

// 其中fn函数可以接受两个参数:item和index

// 使用示例
var arr = ['java', 'c', 'php', 'html'];
function output(item) {
    console.log(item)
}
each(arr, output);  // java, c, php, html

// 使用示例
var arr = ['java', 'c', 'php', 'html'];
function output(item, index) {
    console.log(index + ': ' + item)
}
each(arr, output);  // 0:java, 1:c, 2:php, 3:html

// 获取一个对象里面第一层元素的数量,返回一个整数
function getObjectLength(obj) {}

// 使用示例
var obj = {
    a: 1,
    b: 2,
    c: {
        c1: 3,
        c2: 4
    }
};
console.log(getObjectLength(obj)); // 3

思路

对于数组,最开始用的是for..in...,后来看见review中说不要用for...in...,就改了一下。
其他也没啥难度,直接看代码吧。

实现

function each(arr, fn) {
    for(var i = 0, length1 = arr.length; i < length1; i++){
        fn(arr[i], i);
    }
}

// 获取一个对象里面第一层元素的数量,返回一个整数
function getObjectLength(obj) {
    var length = 0;
    for (item in obj) {
        length += 1;
    }
    return length;
}

补充

  1. 在review里看到说for(;;)循环有两种形式,for(var i = 0, len = arr.length; i < len; i++)for(var i = 0; i < arr.length; i++),建议使用前一种。

    这两者区别在第一种只调用了一次arr.length方法,而第二种在每一次循环时都调用了arr.length,很明显第一种的执行更快一些。

  2. 为什么数组不要用for...in... ,首先它遍历的时候顺序是不确定的;其次对象属性的enumerablefalse 的话,该对象在for...in... 中就不会出现;最后for...in... 受原型链的影响,如果该对象的原型链中有该对象没有的属性的话,for...in... 也会遍历到。

    对于for...in... 受原型链影响这点,如果不想遍历到原型链中的属性,可以加一个hasOwnProperty 的判断。

    for (i in obj) {
      if (obj.hasOwnProperty(i)){
        console_log(i);
    }
    }
    
    

你可能感兴趣的:(百度前端技术学院(IFE)2015春task练习记录01)