閱讀718 返回首頁    go 阿裏雲 go 技術社區[雲棲]


secrets of the javascript Ninja( with(){} 的用法)(javascript忍者的秘密)

      with語句也是一個功能強大的特性,但是它常常不能被正確的理解。它允許你把一個對象的所有屬性放到with語句所指定的作用域中,這樣這些屬性就可以想平常的JavaScript變量被使用。理解with語句是如何工作的,在你開發中會帶來很大的好處。

 

JavaScript中with(){}語句是如何工作的

讓我們首先通過一個小例子來看看with(){}語句的基本用法:

var use = "other"; var katana = { isSharp: true, use: function(){ this.isSharp = !!this.isSharp; } }; with ( katana ) { //assert( true, "You can still call outside methods." ); isSharp = false; use(); alert(use!='other');//true alert(this);//window Object //assert( use != "other", "Use is a function, from the katana object." ); //assert( this != katana, "this isn't changed - it keeps its original value" ); } alert(typeof isSharp);//undefined alert(katana.isSharp);//false 

從這個例子我們來總結一下with的基本用法:

 

1.在with(){}語句中,你可以直接使用with指定的對象的變量和方法

2.如果外部存在和with指定的對象的變量同名的屬性,那麼with指定對象中的屬性會覆蓋其他同名的屬性

3.this指定的是katana的外部作用域。

 

那麼我們能否在with(){}語句中添加一些屬性和方法呢?來看一段代碼:

var katana = { isSharp: true, use: function(){ this.isSharp = !!this.isSharp; } }; with ( katana ) { isSharp = false; cut = function(){ isSharp = false; }; } alert(katana.cut);//undefined alert(cut); } 

從上麵的代碼我們可以發現:

 

1.在with語句中隻能使用和更改對象已有屬性,不能為對象添加新的屬性

2.如果為對象添加新的屬性,新添加的屬性會作為全局對象的屬性,而不是with指定對象的屬性

JavaScript中如何使用with(){}語句

我們主要通過一些著名的JavaScript庫的示例代碼來看看with(){}如何使用:

 

  1. Prototype庫中使用with(){}的情況。

Object.extend(String.prototype.escapeHTML, { div: document.createElement('div'), text: document.createTextNode('') }); with (String.prototype.escapeHTML) div.appendChild(text); 

下麵是base2庫中使用with的情況:

with (document.body.style) { backgroundRepeat = "no-repeat"; backgroundImage = "url(https://ie7-js.googlecode.com/svn/trunk/lib/blank.gif)"; backgroundAttachment = "fixed"; }

base2中另外的一中情況:

with (document.body.style) { backgroundRepeat = "no-repeat"; backgroundImage = "url(https://ie7-js.googlecode.com/svn/trunk/lib/blank.gif)"; backgroundAttachment = "fixed"; } base2中另外的一中情況: var Rect = Base.extend({ constructor: function(left, top, width, height) { this.left = left; this.top = top; this.width = width; this.height = height; this.right = left + width; this.bottom = top + height; }, contains: function(x, y) { with (this) return x >= left && x <= right && y >= top && y <= bottom; }, toString: function() { with (this) return [left, top, width, height].join(","); } }); 

 

 

Firebug firefox extension中使用with(){}的情況

const evalScriptPre = "with (.vars) { with (.api) { with (.userVars) { with (window) { const evalScriptPost = "}}}}"; with ( obj ) { with ( window ) { ... } } 

導入命名空間的時候使用如下

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

第二個代碼是不是簡單了很多。

淨化麵向對象的代碼,使用如下方式編寫麵向對象的代碼。

function Ninja(){with(this){ // Private Information var cloaked = false; // Public property this.swings = 0; // Private Method function addSwing(){ return ++swings; } // Public Methods this.swingSword = function(){ cloak( false ); return addSwing(); }; this.cloak = function(value){ return value != null ? cloaked = value : cloaked; }; }} 

 

從上麵的代碼我們可以發現一下三點:

1.私有數據和共有數據是的定義是不一樣的

2.由於使用with(this){}使得訪問共有數據和私有數據是一樣的

3.方法的的定義和變量的定義相似,共有方法必須使用this前綴,但是訪問共有方法的時候和私有方法是一樣的,由於使用with(this){}

 

 

測試

下麵是Scriptaculous test suite.中的一個示例

 

 

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

 

 

模板

下麵來看看John Resig寫的一個模板係統:

 

 

(function(){ var cache = {}; this.tmpl = function tmpl(str, data){ // Figure out if we're getting a template, or if we need to // load the template - and be sure to cache the result. var fn = !//W/.test(str) ? cache[str] = cache[str] || tmpl(document.getElementById(str).innerHTML) : // Generate a reusable function that will serve as a template // generator (and which will be cached). new Function("obj", "var p=[],print=function(){p.push.apply(p,arguments);};" + // Introduce the data as local variables using with(){} "with(obj){p.push('" + // Convert the template into pure JavaScript str .replace(/[/r/t/n]/g, "") .split("<%").join("/t") .replace(/((^|%>)[^/t]*)'/g, "$1/r") .replace(//t=(.*?)%>/g, "',$1,'") .split("/t").join("');") .split("%>").join("p.push('") .split("/r").join("//'") + "');}return p.join('');"); // Provide some basic currying to the user return data ? fn( data ) : fn; }; })(); assert( tmpl("Hello, <%= name =>!", {name: "world"}) == "Hello, world!", "Do simple variable inclusion." ); var hello = tmpl("Hello, <%= name =>!"); assert( hello({name: "world"}) == "Hello, world!", "Use a pre-compiled template." ); 

具體解釋在此:https://ejohn.org/blog/javascript-micro-templating/

最後更新:2017-04-02 00:06:43

  上一篇:go 廣州技術交流腐敗會之IBM技術沙龍開源技術 &amp; WebSphere &amp; Tivoli
  下一篇:go 我的opengl編程學習(一)(簡介、繪製圖像、三維觀察、光照)