收藏 笔试题

题目一:找出数组中最接近指定值的数

 

// 边界值的处理
// 变量的命名
// API的熟悉程度
function findNext(num, arr) {
    / your code ... /
    if (!num || Object.prototype.toString.call(num) !== '[object Number]'){
        throw new TypeError('num参数不可省略且必须为Number类型');
    }
    arr = arr || [];
    var diffArr = [];
    arr.map(function(x){
        // 对数组各个数值求差值
        diffArr.push(Math.abs(x - num));
    });
    var minimum =  Math.min.apply(null, diffArr);
    // 最后是返回数组中最接近指定值数的索引
    var result = [];
    diffArr.forEach(function(d, i){
        if(d === minimum) {
            result.push(i)
        }
    })
    return result;
}
/ TEST CASE/
findNext('s');
findNext(1,[1,2,1]);  // [0,2]
findNext(4,[2,6,10]); // [0,1]

 

题目二:CSS 多边框实现

// your css code ...
// 第一种 
div {
    box-shadow: 0 0 0 10px red,0 0 0 16px green, 0 2px 5px 16px rgba(0,0,0,.5);
}

// 第二种 (有局限,只能模拟出双边框) 

div {
    outline: 1px solid red;
    border: 1px solid green;
}
// 如果使用嵌套dom结构,检查对普通css属性的理解

题目三:实现一个EventEmitter用于事件监听、触发、移除

// 可以追问,如果要控制每个方法上回调函数数量怎么做
// 增加一个 once api 调用一次即注销如何实现
function Emitter() {
}
const proto = Emitter.prototype;
proto._getEvents = function() {
    if (!this._events) {
        this._events = {};
    }

    return this._events;
};

// 注册事件
proto.on = function(event, listener) {
    const events = this._getEvents();

    events[event] = events[event] || [];

    events[event].push(listener);
    return this;
};

// 移除事件
proto.off = function(event, listener) {
    const events = this._getEvents();

    // 移除所有事件
    if (arguments.length === 0) {
        this._events = {};
        return this;
    }

    const listeners = events[event];
    if (!listeners) {
        return this;
    }

    // 移除指定事件下的所有监听器
    if (arguments.length === 1) {
        delete events[event];
        return this;
    }

    let cb;
    for (let i = 0; i < listeners.length; i++) {
        cb = listeners[i];
        if (cb === listener) {
            listeners.splice(i, 1);
            break;
        }
    }
    return this;
};

// 触发事件
proto.emit = function(event) {
    const events = this._getEvents();
    let listeners = events[event];
    let i;
    const args = [];
    for (let i = 1; i < arguments.length; i++) {
        args.push(arguments[i]);
    }

    if (listeners) {
        listeners = listeners.slice(0);
        for (i = 0; i < listeners.length; i++) {
            listeners[i].apply(this, args);
        }
    }

    return this;
};

 

 

题目四: 深度克隆函数deepClone

/**
* 取决于你深度拷贝的内容是什么,是一个真正的JSON object 还是js中的任何对象
* var cloned = JSON.parse(JSON.stringify(objectToClone)); 这个处理不了function、undefined、Infinity等对象的
* 注意 Object.assign({}, original) / { ...original }也是浅拷贝函数
*/
function type(obj) {
    var toString = Object.prototype.toString;
    var map = {
        '[object Boolean]'      : 'boolean',
        '[object Number]'       : 'number',
        '[object String]'       : 'string',
        '[object Function]'     : 'function',
        '[object Array]'        : 'array',
        '[object Date]'         : 'date',
        '[object RegExp]'       : 'regExp',
        '[object Undefined]'    : 'undefined',
        '[object Null]'         : 'null',
        '[object Object]'       : 'object'
    };
    return map[toString.call(obj)];
}
function deepClone(data){
    let dataType = type(data);
    if (dataType === 'null' || dataType === 'undefined' || dataType === 'number' || dataType === 'string' || dataType === 'boolean') {
        return data;
    }
    
    // Date
    if (dataType === 'date') {
        return new Date(data.getTime());
    }
    
    // RegExp
    if (dataType === 'regExp') {
        return new RegExp(data.source, data.flags);
    }
    
    // HtmlNode
    if (data.nodeType && typeof data.cloneNode === "function"){
        return data.cloneNode(true);
    }
    // Array
    if (dataType === 'array') {
        var result = [];
        data.forEach(function(child, index) {
            result[index] = deepClone(child);
        });
        return result;
    }
    
    // Object
    if (dataType === 'object'){
        var result = {};
        if (!data.prototype){
            // 普通对象
            for (var i in data) {
                result[i] = deepClone(data[i]);
            }
        } else {
            // 函数
            if (data.constructor) {
                // 这里会有什么副作用
                result = new data.constructor();
            } else {
                result = data;
            }
        }
    }
    
    return result;
}

// 每当调用postMessage时,都会使用结构化克隆算法。
// 我们可以创建一个MessageChannel并发送消息。在接收端,消息包含我们原始数据对象的结构化克隆。
// 如果能回答出这个方法加分
// 这个方法也是有缺陷的:一是不能处理dom节点 另外是异步的
function structuralClone(obj) {
    return new Promise(resolve => {
        const {port1, port2} = new MessageChannel();
        port2.onmessage = ev => resolve(ev.data);
        port1.postMessage(obj);
    });
}

 

题目五:针对下段html文档实现一个简单 AST 解析方法

// 
// 正则表达式
//
const htmlStr = `<div class="parent"><div class="child has-more" style="widht:100px; height:200px;"><a target="_blank" href="positionDetail.htm" title="欢迎应聘蚂蚁金服前端工程师">FE</a></div></div>`

var tagRE = /<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g;
var attrRE = /([\w-]+)|['"]{1}([^'"]*)['"]{1}/g;

function parseTag (tag) {
    var i = 0;
    var key;
    var res = {
        type: 'tag',
        name: '',
        attrs: {},
        children: []
    };
    
    tag.replace(attrRE, function (match) {
        if (i % 2) {
            key = match;
        } else {
            if (i === 0) {
                res.name= match;
            } else {
                res.attrs[key] = match.replace(/['"]/g, '');
            }
        }
        i++;
    });
    
    return res;
};

function parse(html, options) {
    options || (options = {});
    var result = [];
    var current;
    var level = -1;
    var arr = [];
    var byTag = {};

    html.replace(tagRE, function (tag, index) {
        var isOpen = tag.charAt(1) !== '/';
        var start = index + tag.length;
        var nextChar = html.charAt(start);
        var parent;
        if (isOpen) {
            level++;
            current = parseTag(tag);
            if ( nextChar && nextChar !== '<') {
                current.children.push({
                    type: 'text',
                    content: html.slice(start, html.indexOf('<', start))
                });
            }
            byTag[current.tagName] = current;

            if (level === 0) {
                result.push(current);
            }

            parent = arr[level - 1];
            if (parent) {
                parent.children.push(current);
            }
            arr[level] = current;
        } else {
            level--;
            if ( nextChar !== '<' && nextChar) {
                parent = level === -1 ? result : arr[level].children;
                var end = html.indexOf('<', start);
                var content = html.slice(start, end === -1 ? undefined : end);
                if (!/^\s*$/.test(content)) {
                    parent.push({
                        type: 'text',
                        content: content
                    });
                }
            }
        }
    });

    return result;
};
parse(htmlStr)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值