首页 > 一个前端面试题,要求不用第三方js类库,不用innerhtml和eval。去往原有的dom里填充真实数据,怎么解?

一个前端面试题,要求不用第三方js类库,不用innerhtml和eval。去往原有的dom里填充真实数据,怎么解?

具体问题如上图,求大牛点拨。谢谢。


这种面试题可以直接PASS
完全没什么必要


其实就是想看看你有没有接触过mvvm 这种东西,并且是否有去思考过怎么实现么?


面试的干嘛不直接说, 你给我写个模板引擎


https://.com/a/1190000004428...


楼主的这个问题,好像当面试题真的是要让人感觉要吐呀


new Function(arg1, arg2, ..., argN, function_body)

可能不对,大神轻喷。


自己写了个demo, 不知道对不,这里

但我感觉绕来绕去没什么意思,面试题至于这么整吗?


这是模板页面吧,通过后台程序自动替换内容到页面中的,出题的人不懂技术吧,或者一枝半解,为了效率,功能也不会这样设计的


使用with以及Function应该可以完成这类问题,具体可以参考阮一峰javascript教程with使用方法


题目似乎有些问题,{{m.className}},{{user.avatar}}一个前面有m,一个没有,不知道是什么意思,就当做没有处理啦。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="template-dom" class="{{className}}">
    <div class="user-profile">
        <div class="user-avatar">
            <img src="{{user.avatar}}">
        </div>
        {{user.name}}
    </div>
</div>
<script>
    var render = (function() {
        var reg = /{{([^}]*)}}/g

        /**
         * 根据prop获取model的某个field
         * @param model
         * @param prop
         * @returns {*}
         */
        function getField(model, prop) {
            let keys = prop.split('.')
            for (let key of keys) {
                if (model[key] == null) {
                    return
                } else {
                    model = model[key]
                }
            }
            return model
        }


        function traverse(el,model){
            // 文本节点,替换文本内容
            if(el.nodeType == 3 ){
                el.textContent = el.textContent.replace(reg,function(word,prop){
                    return getField(model,prop)
                })
            }
            else {
                //非文本节点替换属性内容
                var attributes = Array.prototype.slice.call(el.attributes)
                for (let attr of attributes) {
                    let value = attr.value
                    value = value.replace(reg,function(word,prop){
                        return getField(model,prop)
                    })
                    attr.value = value
                }
            }
            /**
             * 递归替换子节点
             * @type {Array.<T>}
             */
            let childNodes = Array.prototype.slice.call(el.childNodes)
            for(let child of childNodes){
                traverse(child,model)
            }
        }
        function render(el,model){
            traverse(el,model)
        }
        return render;
    })()

</script>
<script>
    var m = {
        className: 'user',
        user:{
            name: 'wscn',
            avatar:'https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png'
        }
    }
    render(document.getElementById('template-dom'),m)
</script>
</body>
</html>

function render(dom, m) {
    var re = /\{\{(.*)\}\}/g;
    var outerHTML = dom.outerHTML;
    var mapper = outerHTML
        .match(re)
        .map(v => v.replace(/(\{\{|\}\})/g, '') )
        .map(v => {
            var x;
            try {
                x = eval(v);
            } catch(e) {
                x = '';
            }
            return x;
        });
    return outerHTML.replace(re, function() { return mapper.shift(); })
}

对不起,我还是用了 eval
原本以为可以用 (new Function('return ' + v))() 之类的替代 eval 的,但实验结果是不可以。
另外,没看懂什么叫不允许替换原始 dom ,所以直接输出字符串了。

最后说一下自己的看法,这类题目平时玩玩还好,真要做面试题?
恶心死人了,活该招不到人。


var render = (function(){
    function getValue(keyString, o){
        var keys = keyString.split(".");
        return keys.reduce(function(prev, curr){
            return prev[curr];
        }, o);
    }

    var reg = /\{\{([^\}]*)\}\}/g;

    return function(elem, o){
        var html = elem.outerHTML;
        elem.outerHTML = html.replace(reg, function(match, g){
            return getValue(g.trim(), o);
        });
    }

})();

不能用eval那就当然是用new Function啦。
不过还是第一个答案那样,用对象键名来取值最好
JSBin实例

var m = {
  className: 'user',
  user:{
    name: 'wscn',
    avatar:'https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png'
  }
}

var render = function (dom, model) {
  var reg = /{{([^{}]*)}}/g
  var attrs = Array.prototype.slice.call(dom.attributes)
  for (let attr of attrs) {
    attr.value = attr.value.replace(reg, function (src, val) {
      return new Function('return ' + val)()
    })
  }
  var childs = Array.prototype.slice.call(dom.childNodes)
  for (let child of childs) {
    if (child.nodeType === 1) {
      render(child, model)
    } else if (child.nodeType === 3) {
      child.nodeValue = child.nodeValue.replace(reg, function (src, val) {
        return new Function('return ' + val)()
      })
    }
  }
}
render(document.getElementById('template-dom'), m)

也来玩一下,同样的感觉没必要加m.,都已经把m对象传入了函数中了。


var render = function (dom, obj) {
    var pattern = /\{\{([^(\})]*)\}\}/g,
        html = dom.outerHTML,
        reps = html.match(pattern)
                   .map(val => val.replace(/[\{\{\}\}]/g, ""))
                   .map( (val) => {
                        var keys = val.split("."),
                            res = obj;
                        for (var i of keys) {
                            res = res[i];
                        }
                        return res;
                    });
    dom.outerHTML = html.replace(pattern, () => reps.shift());
};

另外,问下这是哪家公司?


试着做了一下,很菜....

function render(e,f){

    e.className = f.className;

    var imgObj = e.getElementsByTagName('img')[0];
    imgObj.src = f.user.avatar;

    var obj = e.childNodes;
    for (var i = 0; i < obj.length; i++) {
        if(obj[i].className == 'user-profile'){
            obj = obj[i];
        }
    };
    var o1 = obj.lastChild;
    var o2 = document.createElement('p');
    o2.textContent = f.user.name;

    console.log(obj.lastChild);
    obj.replaceChild(o2,o1);

}

node类的相关api

【热门文章】
【热门文章】