美文网首页JS相关橙子学院-30天专注橙长计划
30天学习计划 js忍者秘籍 第10章 with语句

30天学习计划 js忍者秘籍 第10章 with语句

作者: 如201608 | 来源:发表于2016-10-09 14:58 被阅读40次

    第10章 with语句

    with语句是一个强大的、但经常被误解的、有争议的js特性。with语句允许我们将一个对象的所有属性引用到当前作用域,允许我们无需使用拥有者对象的前缀,就可以对这些属性进行引用和赋值操作。

    重点的一点,在js中该语句的存在是暂时的,ES5规范在严格模式下已经禁用了该语句。

    如果不会阅读程序代码,并确保自己知道程序代码到底要做什么,就没办法确保程序会正常工作。出于这个原因,应该避免使用with语句。——Douglas Crockford

    10.1 with是怎么回事

    with语句会创建一个作用域,在该作用域内,在引用特定对象的属性时,可以不使用前缀。

    10.1.1 在with作用域内引用属性

    示例 10.1 利用一个对象创建一个with作用域

    test suite

    #results .pass{color:green;}

    #results .fail{color:red;}

    function assert(value,desc){

    var li = document.createElement('li');

    li.className = value ? 'pass' : 'fail';

    li.appendChild(document.createTextNode(desc));

    document.getElementById('results').appendChild(li);

    }

    var use = 'other';

    var katana = {

    isSharp:true,

    use:function(){

    this.isSharp = !this.isSharp;

    }

    };

    with(katana){

    assert(use != 'other' && typeof use == 'function','use is a function from the katana object');

    assert(this !== katana,'context isn\'t changed; keeps its original value.')

    }

    assert(use == 'other','outside the with use is unaffected.');

    assert(typeof isSharp === 'undefined','outside the with the properties don\'t exist.')

    注意,在with语句的作用域内,对象属性的优先级绝对高于在更高层级作用域内定义的同名变量。这是with被嘲笑的主要原因之一,with作用域内的代码意义可能是含糊不清的。

    我们也证明了函数上下文(this)是不受with语句影响的。

    101.2 在with作用域内进行赋值

    示例10.2 with作用域内的赋值操作

    test suite

    #results .pass{color:green;}

    #results .fail{color:red;}

    function assert(value,desc){

    var li = document.createElement('li');

    li.className = value ? 'pass' : 'fail';

    li.appendChild(document.createTextNode(desc));

    document.getElementById('results').appendChild(li);

    }

    var katana = {

    isSharp:true,

    use:function(){

    this.isSharp = !this.isSharp;

    }

    };

    with(katana){

    isSharp = false;

    assert(katana.isSharp === false,'properties can be assigned');

    cut = function(){

    isSharp = false;

    }

    }

    assert(typeof katana.cut == 'function','new properties can be created on the scoped object.')

    assert(typeof window.cut == 'function','new properties are create in the global scope.')

    如果要在katana上创建新属性,就需要使用对象引用前缀,即便是在with作用域内也要这样做,如 katana.cut = function(){isSharp = false;}

    10.1.3 性能方面的注意事项

    它降低了所包含js代码的执行性能,而不仅仅是局限于与之交互的对象。

    示例10.3 with语句的性能测试

    test suite

    #results .pass{color:green;}

    #results .fail{color:red;}

    function assert(value,desc){

    var li = document.createElement('li');

    li.className = value ? 'pass' : 'fail';

    li.appendChild(document.createTextNode(desc));

    document.getElementById('results').appendChild(li);

    }

    var ninja = {foo:'bar'},

    value,

    maxCount = 1000000,

    n,

    start,

    elapsed;

    start = new Date().getTime();

    for(n=0;n

    value = ninja.foo;

    }

    elapsed = new Date().getTime()-start;

    assert(true,'without with:'+elapsed);

    start = new Date().getTime();

    with(ninja){

    for(n=0;n

    value = foo;

    }

    }

    elapsed = new Date().getTime()-start;

    assert(true,'with (with access):'+elapsed);

    start = new Date().getTime();

    with(ninja){

    for(n=0; n

    foo=n;

    }

    }

    elapsed = new Date().getTime()-start;

    assert(true,'with (with assignment):' + elapsed);

    start = new Date().getTime();

    with(ninja){

    for(n=0; n

    value = 'no test'

    }

    }

    elapsed = new Date().getTime()-start;

    assert(true,'with (without access):' + elapsed);

    without with:31

    with (with access):1196

    with (with assignment):1211

    with (without access):1109

    在决定要享受with语句带来的任何便利时,我们必须确保适应这种程度的额外开销。

    10.2 真实示例

    Prototype中使用的例子:

    Object.extend(String.prototype.escapeHTML,{

    div:document.createElement('div'),

    text:document.createTextNode('')

    })

    with(String.prototype.escapeHTML) div.appendChild(text);

    在这里,Prototype使用with语句,避免了String.prototype.escapeHTML的div和text属性的引用前缀,否则的话,每个属性都要使用前缀。

    可以实现相同目标而又不必使用with作用域的方法

    (function(s){

    s.div.appendChild(s.text)

    })(String.prototype.escapeHTML)

    在即时函数的作用域内,长引用String.prototype.escapeHTML可以通过一个简单的函数参数s进行引用。很多开发都认为,将一个复杂的引用转换成一个简单引用,远比完全消除前缀的方式要好。

    base2库的另外一个示例

    with(document.body.style){

    backgroundRepeat = 'no-repeat';

    backgroundImage = 'url(...)';

    backgroundAttachment = 'fixed';

    }

    10.3 导入有命名空间的代码

    YAHOO.util.Event.on(

    [YAHOO.util.Dom.get('item'),YAHOO.util.Dom.get('otheritem')],

    'click',function(){

    YAHOO.util.Dom.setStyle(this,'color','#c00');

    }

    )

    with(YAHOO.util.Dom){

    YAHOO.util.Event.on([get('item'),get('otheritem')],'click',function(){setStyle(this,'color','#c00')})

    }

    额外增加一个with语句,极大地增加了代码的简单性。

    10.4 测试

    new Test.Unit.Runner({

    testSliderBasics:function(){

    with(this){

    var slider = new Control.Slider('handle1','track1');

    assertInstanceOf(Control.Slider,slider);

    assertEqual('horizontal',slider.axis);

    assertEqual(false,slider.disabled);

    assertEqual(0,slider.value);

    slider.dispose();

    }

    }

    })

    通过使用with(this),得到更简单的代码。

    10.5 使用with进行模板化

    模板系统的目标通常包括以下功能:

    .应该有一种运行嵌入式代码和打印数据的方法

    .应该有一种缓存编译模板的方法

    .访问映射数据应该很简单

    总的来说,一个易于使用的模板系统,在很大程度上,取决于with语句的能力。

    相关文章

      网友评论

      • currygolden:例子里的代码是求生之路的武器描述吗,我怎么看到了katana

      本文标题:30天学习计划 js忍者秘籍 第10章 with语句

      本文链接:https://www.haomeiwen.com/subject/hynpyttx.html