ホームページ  >  に質問  >  本文

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

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

伊谢尔伦伊谢尔伦2750日前1268

全員に返信(15)返信します

  • PHPz

    PHPz2017-04-11 10:31:59

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

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <p id="template-dom" class="{{className}}">
        <p class="user-profile">
            <p class="user-avatar">
                <img src="{{user.avatar}}">
            </p>
            {{user.name}}
        </p>
    </p>
    <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>

    返事
    0
  • 巴扎黑

    巴扎黑2017-04-11 10:31:59

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

    可能不对,大神轻喷。


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

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

    返事
    0
  • 高洛峰

    高洛峰2017-04-11 10:31:59

    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 ,所以直接输出字符串了。

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

    返事
    0
  • ringa_lee

    ringa_lee2017-04-11 10:31:59

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

    返事
    0
  • PHP中文网

    PHP中文网2017-04-11 10:31:59

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

    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);
    
    }

    返事
    0
  • 高洛峰

    高洛峰2017-04-11 10:31:59

    也来玩一下,同样的感觉没必要加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());
    };
    

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

    返事
    0
  • 巴扎黑

    巴扎黑2017-04-11 10:31:59

    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);
            });
        }
    
    })();

    返事
    0
  • 阿神

    阿神2017-04-11 10:31:59

    不能用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)

    返事
    0
  • 高洛峰

    高洛峰2017-04-11 10:31:59

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

    返事
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-11 10:31:59

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

    返事
    0
  • キャンセル返事