资讯专栏INFORMATION COLUMN

《javascript忍者秘籍》补遗-01

Eric / 1011人阅读

摘要:第二例这段代码是用来做将断言测试分组的,代码多了些,问题自然也更多了些。首先作者使用了自执行方法封闭了作用域,使用来指向全局对象,进而产生全局可访问的属性。没想到,久负盛名,豆瓣评分的大作,作者的光环,代码风格居然是如此的不谨慎。

第二章中 作者给了几个简单的断言例子,思路与方向是极不错的,创造JQ的大神,思想高度绝对无法让我质疑的,但是代码的功底细节,实在是让人不敢恭维。

第一例:
function assert(value, desc) {
    var li = document.createElement("li");
    li.className = value ? "pass" : "fail";
    li.appendChild(document.createTextNode(desc));
    //为何不直接使用textContent进行文本赋值呢?相比下,性能会更好!
    document.getElementById("result").appendChild(li);
    //每次执行断言 都要重新动态查找一次result节点?
}

assert(true, "这是真币!");
assert(false, "这是假币@");

上述书中案例,我从鸡蛋里挑骨头,选了两处不妥之处,一个是反复查找节点无缓存,另一个是文本节点创造的低效率。

改造代码:
var assert = (function () {
    //通过闭包 缓存断言的根ul节点
    var results = document.getElementById("result");
    return function (value, desc) {
        var li = document.createElement("li");
        li.className = value ? "pass" : "fail";
        //使用textContent属性插入文本节点 提高效率
        li.textContent = desc;
        results.appendChild(li);
    };
})();

上面的代码改善了书里的小遗漏,仍然不够完美,因为初始的惰性加载,会有额外的性能损耗,下面再提供两种极改善方案。

function getAssert() {
    //取消惰性加载
    var results = document.getElementById("result");
    return function (value, desc) {
        var li = document.createElement("li");
        li.className = value ? "pass" : "fail";
        li.textContent = desc;
        results.appendChild(li);
    };
};
//需要初始拿到返回方法
var assert = getAssert();

assert(true, "这是真币!");
assert(false, "这是假币@");

上面这一则,取消了惰性加载,但是需要手动获取返回的方法。

下面使用重载:

var assert = function(value,desc)  {
    //保留作用域 缓存私有变量results
    var results = document.getElementById("result");
    //重赋值
    assert =  function (value, desc) {
        var li = document.createElement("li");
        li.className = value ? "pass" : "fail";
        li.textContent = desc;
        results.appendChild(li);
    };
    //第一次调用 手动调用
    assert(value,desc);
};


assert(true, "这是真币!");
assert(false, "这是假币@");

世界清静了,代码终于看似完美了。但实际的需求里,可能我们要将方法封闭起来,让同事或者用户使用,那么results这个id,就有了相当大的局限性了,fail与pass的类名也不够灵活。这个场景下,我们更应该使用再往上一个的方式,可以给与我们更大的diy空间。

第二例
(function () {
    
    var results;
    
    this.assert = function (value, desc) {
        var li = document.createElement("li");
        li.className = value ? "pass" : "fail";
        results.appendChild(li);
        if (value) {
            li.parentNode.parentNode.className = "fail";
        }
        return li;
    };
    
    this.test = function (name, fn) {
        results = document.getElementById("results");
        results = assert(true, name).appendChild(
            document.createElement("ul");
    )
        fn();
    };
    
});

这段代码是用来做将断言测试分组的,代码多了些,问题自然也更多了些。

首先作者使用了自执行方法封闭了作用域,使用this来指向全局对象,进而产生全局可访问的属性。

但这段代码是有着执行缺陷的,assert方法可以在test方法外调用,那么此时results是根级ul,还是分组Ul呢?而且动态查找节点的问题依旧没有改动。

代码改善:
var global = (function () {
    //严格模式下全局的this 无法访问 在此做一个防御措施
    return this ? this : window;
})();

(function (global) {
        //缓存根root节点
    var rootResults = document.querySelector(".test-root"),
        results;
    // 将assert私有化 外部不得访问
    function assert(value, desc) {
        var domLi = document.createElement("li");
        domLi.className = value ? "pass" : "fail";
        domLi.textContent = desc;
        results.appendChild(domLi);
        if (!value) {
            domLi.parentNode.parentNode.className = "fail";
        }
        return domLi;
    };
    
    global.test = function (name, fn) {
        results = rootResults;
        results = assert(true, name).appendChild(
            document.createElement("ul")
        );
        //回调函数可以从参数里调用assert
        fn(assert);
    }
    
})(global);

重复了缓存DOM节点的操作,为this的指向做出回退机制,私有化assert方法,将assert方法入参到test方法的回调方法中,算是勉强完美了。

没想到,久负盛名,豆瓣评分8+的大作,JQ作者的光环,代码风格居然是如此的不谨慎。暂待我往下阅读,期望能够有打脸回馈。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89580.html

相关文章

  • 第一章无处不在的JavaScriptJavascript忍者秘籍2阅读笔记】

    摘要:无处不在的理解语言与其他主流语言相比,函数式语言的血统更多一些。函数式语言一类程序设计语言,是一种非冯诺伊曼式的程序设计语言。函数式语言主要成分是原始函数,定义函数和函数型。性能分析内置对象上的和方法。 无处不在的JavaScript 理解JavaScript语言 与其他主流语言相比,JavaScript函数式语言的血统更多一些。 函数式语言一类程序设计语言,是一种非冯.诺伊曼式的程序...

    yck 评论0 收藏0
  • 闭包:私有化变量 《JavaScript高程3》 《JavaScript忍者秘籍

    摘要:闭包闭包的特点就是内部匿名函数可以访问外部函数作用域的变量和方法变量对象。闭包的主要表现形式就是匿名函数,但是两者并不是等价的。中是没有块级作用域的,为了在中引入块级作用域,可以使用匿名函数模拟块级作用域。 在介绍闭包之前,首先解释在随后的测试实例中会使用的assert测试函数,这个方法有别于alert()测试,有很大的改进。 assert()测试方法 #...

    selfimpr 评论0 收藏0
  • 闭包:私有化变量 《JavaScript高程3》 《JavaScript忍者秘籍

    摘要:闭包闭包的特点就是内部匿名函数可以访问外部函数作用域的变量和方法变量对象。闭包的主要表现形式就是匿名函数,但是两者并不是等价的。中是没有块级作用域的,为了在中引入块级作用域,可以使用匿名函数模拟块级作用域。 在介绍闭包之前,首先解释在随后的测试实例中会使用的assert测试函数,这个方法有别于alert()测试,有很大的改进。 assert()测试方法 #...

    vspiders 评论0 收藏0
  • JS忍者秘籍中的定时器机制详解

    摘要:设置和清除定时器直接引用忍者秘籍中的图片注意定时器的时间间隔设为,也会有几毫秒的延迟。以上参考资料忍者秘籍第章驯服线程和定时器 showImg(https://segmentfault.com/img/remote/1460000015353524?w=1024&h=681); 前言 前段时间刚看完《JS忍者秘籍》,虽说是15年出版的,有些东西是过时了,但像对原型链、闭包、正则、定时器...

    keelii 评论0 收藏0
  • 忍者级别的JavaScript函数操作

    摘要:我们需要知道的是,对于而言,匿名函数是一个很重要且具有逻辑性的特性。通常,匿名函数的使用情况是创建一个供以后使用的函数。截图自忍者秘籍通过完善之前对匿名函数的粗略定义,我们可以修复解决这个问题。 从名字即可看书,此篇博客总结与《JavaScript忍者秘籍》。对于JavaScript来说,函数为第一类型对象。所以这里,我们主要是介绍JavaScript中函数的运用。 系列博客地址:h...

    suemi 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<