3

题目来源:http://www.nowcoder.com/ta/front-end

1.数组去重

1.两个循环:

思路: 新建一个新数组用于存放重复的数组元素,通过两个循环,比较两个数组元素是否相同。外循环控制第一个比较元素,内循环控制第二个比较元素,如果有重复元素则将该元素添加到新数组中,最后返回这个新数组。
实现:

Array.prototype.distinct = function() {
    var ret = [];
    for (var i = 0; i < this.length; i++)
    {
        for (var j = i+1; j < this.length;) {   
            if (this[i] === this[j]) {
                ret.push(this.splice(j, 1)[0]);
            } else {
                j++;
            }
        }
    }
     return ret;
};
//for test
alert(['a','b','c','d','b','a','e'].distinct());

2.一次循环

思路:创建一个空对象的和空数组,通过循环,将原数组中的每个元素的值作为键值对添加到控对象中,如果这个对象中已经存在该属性,则说明这个数组元素是重复的,则将他添加到空数组中,最后返回新创建的数组。
实现:

Array.prototype.distinct=function(){
    var arr=[];
    var obj={};
    for(var i=0;i<this.length;i++){
        if(obj[this[i]]==undefined)
            obj[this[i]]=this[i];
        else if(obj[this[i]])
            arr.push(this[i]);
    }
    return arr;
 }
alert(['a','b','c','d','b','a','e'].distinct());  

2.dom 节点查找

描述:查找两个节点的最近的一个共同父节点,可以包括节点自身
思路:

有两个dom的节点,dom1,dom2
1.判断dom1节点是否包含dom2节点;包含则返回dom1,不包含继续向下运行;
2.判断dom2节点是否包含dom1节点;包含则返回dom2,不包含继续向下运行;
3.通过其中一个节点dom1去获取该节点的父节点,dom_p;
4.通过父节点dom_p去查dom_f的子节点,看dom2是否在父节点dom_f的子节点中;
5.如果dom2在dom_f的子节点中,则dom_f是最近的父节点;
6.如dom2不在dom_f的子节点中,则以domf_f继续去查dom_f的父节点,重复1,2,3,4步骤最终得出父节点dom_f

实现1:

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

实现2:

function commonParentNode(oNode1, oNode2) {
    if(oNode2.contains(oNode1)) return oNode2;
    while(oNode1) {
        if(oNode1.contains(oNode2)){
            return oNode1;
        }
        oNode1 = oNode1.parentNode;
    }
}

3.URL相关

描述:

获取 url 中的参数
1. 指定参数名称,返回该参数的值 或者 空字符串
2. 不指定参数名称,返回全部的参数对象 或者 {}
3. 如果存在多个同名参数,则返回数组
输入:
getUrlParam('http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe', 'key')

输出:
['1', '2', '3']

实现:

function getUrlParam(sUrl, sKey) {

    var r = [] , s = null  , i = 0;
    var regexp = new RegExp(/[?&]([\w]*)=([^&#]*)/g);

    while((s = regexp.exec(sUrl)) != null){
        if(!r[s[1]])r[s[1]] = s[2];
        else if(typeof(r[s[1]]) == 'object'){
            r[s[1]].push(s[2]);
        }else{
            r[s[1]] = [r[s[1]],s[2]];
        }
    }
    if(sKey){
        //有参数,返回参数值或空
        if(r[sKey]){
            return r[sKey];
        }else{
            return '';
        }
    }else{
        return r;
    }
}

扩展:

1.window.location属性相关:

  • 设置或获取对象指定的文件名或路径。
    alert(window.location.pathname);

  • 设置或获取整个 URL 为字符串。
    alert(window.location.href);

  • 设置或获取与 URL 关联的端口号码。
    alert(window.location.port);

  • 设置或获取 URL 的协议部分。
    alert(window.location.protocol);

  • 设置或获取 href 属性中在井号“#”后面的分段。
    alert(window.location.hash);

  • 设置或获取 location 或 URL 的 hostname 和 port 号码。
    alert(window.location.host);

  • 设置或获取 href 属性中跟在问号后面的部分。
    alert(window.location.search);

2.其他的获取url参数的方法:

方式一:只能对固定url进行操作,返回全部参数

function GetRequest() {
var url = location.search; //获取url中"?"符后的字串
var theRequest = new Object();
if (url.indexOf("?") != -1) {
  var str = url.substr(1);
  strs = str.split("&");
  for(var i = 0; i < strs.length; i ++) {
     theRequest[strs[i].split("=")[0]]=(strs[i].split("=")[1]);
  }
}
 return theRequest;
}

方式二:正则表达式方式,只能对固定url操作,返回指定参数

function GetQueryString(name) {
   var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)","i");
   var r = window.location.search.substr(1).match(reg);
   if (r!=null) return (r[2]); return null;
}

方式三:对任意的url操作,返回指定数量的参数

function getUrlParames(url,keys){

    var request = {},
        result,
        parameStr = '',
        parames = [],
        keyValue = [],
        index = url.indexOf('?');

    if (index) {
        parameStr = url.substr(index+1);
        parames = parameStr.split("&");
        for(var i = 0, lng = parames.length; i < lng; i ++) {
            keyValue = parames[i].split("=");
            request[keyValue[0]] = keyValue[1];
      }
    }

    if (typeof keys == 'string') {
        result = request[keys];
    }else if(!keys){
        return request;
    }
    else{

        result = {};
        for(var j = 0,lng = keys.length;j < lng;j++){
            result[keys[j]] = request[keys[j]];
        }
    }

    return result;
}

4:修改 this 指向

描述:
封装函数 f,使 fthis 指向指定的对象
输入:bindThis(function(a, b){return this.test + a + b}, {test: 1})(2, 3)
输出:6
思路:
我们可以观察到
1.bindThis这个函数接受两个参数,第一个参数为执行函数,第二个参数是要指定的对象。
2.bindThis函数返回一个匿名函数

实现:

function bindThis(f, oTarget) {
    return function(){
        var parames = Array.prototype.slice.call(arguments);
        return f.apply(oTarget,parames); //注意这里需要返回f的执行结果
    }
}

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

描述:
根据包名,在指定空间中创建对象 :
输入:namespace({a: {test: 1, b: 2}}, 'a.b.c.d')
输出:{a: {test: 1, b: {c: {d: {}}}}}

思路:
namespace函数的第一个参数是原始对象,第二个参数是需要创建的对象的包含关系。
通过输出结果可以看出,如果第二个参数中的对象在原始对象中存在并且是它的值为一个对象则不做改变,若不为对象,则重新赋值为空对象{}.

实现:

function namespace(oNamespace, sPackage) {

    var properties = sPackage.split('.');
    var parent = oNamespace;

    for (var i = 0, lng = properties.length; i < lng; ++i) {

        var property = properties[i];

        if (Object.prototype.toString.call(parent[property])!== '[object Object]') {
            parent[property] = {};
        }

        parent = parent[property];

    }

    return oNamespace;

}

6.斐波那契数列

描述:

什么是斐波那契数列:1,1,2,3,5....n 。很容易看出规律,从第三个数字开始,每个数字等于前两个数字之和。

思路:

1.前两个数字都为 1
2.使用递归

实现:

function fibonacci(n) {
    if(n ==1 || n == 2){
        return 1
    }
    return fibonacci(n - 1) + fibonacci(n - 2);
}

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(oDate, sFormation) {
    var obj = {
        yyyy:oDate.getFullYear(),
        yy:(""+ oDate.getFullYear()).slice(-2),//非常精辟的方法
        M:oDate.getMonth()+1,
        MM:("0"+ (oDate.getMonth()+1)).slice(-2),
        d:oDate.getDate(),
        dd:("0" + oDate.getDate()).slice(-2),
        H:oDate.getHours(),
        HH:("0" + oDate.getHours()).slice(-2),
        h:oDate.getHours() % 12,
        hh:("0"+oDate.getHours() % 12).slice(-2),
        m:oDate.getMinutes(),
        mm:("0" + oDate.getMinutes()).slice(-2),
        s:oDate.getSeconds(),
        ss:("0" + oDate.getSeconds()).slice(-2),
        w:['日', '一', '二', '三', '四', '五', '六'][oDate.getDay()]
    };
    return sFormation.replace(/([a-z]+)/ig,function($1){return obj[$1]});
}

8.获取字符串的长度

描述:

如果第二个参数 bUnicode255For1 === true,则所有字符长度为 1
否则如果字符 Unicode 编码 > 255 则长度为 2
输入例子:

strLength('hello world, 牛客', false)

输出例子:
17

实现:

function strLength(s, bUnicode255For1) {

    if(bUnicode255For1) return s.length;

    var length = s.length;
    for(var i = 0, lng = length; i < lng; i++){
        if(s.charCodeAt(i)>255){
            length ++;
        }
    }
    return length;
}

9.邮箱字符串判断

描述:

判断输入是否是正确的邮箱格式
输入: 邮箱字符串
输出: true表示格式正确,false表示错误

实现:

function isAvailableEmail(sEmail) {
    var parter = /^[a-z0-9_+.-]+\@([a-z0-9-]+\.)+[a-z0-9]{2,4}$/;
    return parter.test(sEmail);
}

这题的关键是理解这个正则表达式,我们拆开来看看:

1.^[a-z0-9_+.-]+ : 这个表示以一个或多个小写字母,数字或_,+,.,-这几个个字符开头

2.\@([a-z0-9-]+\.)+ : 这个表示1中的字符连着@,后面再接着一个多个由小写字母,数字,-字符和点.的组成的字符串。

3.[a-z0-9]{2,4}$ 这个比较简单,表示以长度为2-4的,由小写字母和数字任意组合组成的字符串结尾。


ouou
8.7k 声望472 粉丝

进击的前端er...