Alan Storm的评论是对我关于with
语句回答的回应,这让我开始思考。我很少找到使用这个特定语言功能的原因,并且从未考虑过它可能会引起麻烦。现在,我想知道如何有效地使用with
,同时避免其缺点。
你在哪里发现with
语句有用?
Alan Storm的评论是对我关于with
语句回答的回应,这让我开始思考。我很少找到使用这个特定语言功能的原因,并且从未考虑过它可能会引起麻烦。现在,我想知道如何有效地使用with
,同时避免其缺点。
你在哪里发现with
语句有用?
我认为显而易见的用途是作为快捷方式。比如,如果您正在初始化一个对象,您只需省略很多“ObjectName.”的输入。有点像Lisp的“with-slots”,它可以让您编写
(with-slots (foo bar) objectname
"some code that accesses foo and bar"
这与编写以下内容相同
"some code that accesses (slot-value objectname 'foo) and (slot-value objectname 'bar)""
with-slots
要求您指定要使用哪些 slot,而 with
将使用在运行时绑定的任何 slot。 - Samuel Edwin Wardvar photo = document.getElementById('photo');
photo.style.position = 'absolute';
photo.style.left = '10px';
photo.style.top = '10px';
with(document.getElementById('photo').style) {
position = 'absolute';
left = '10px';
top = '10px';
}
我想这取决于你是更注重易读性还是表达性。
第一个例子更易读,对于大多数代码来说可能更推荐。但是大多数代码本身就很平淡无奇。第二个例子有点更加晦涩,但是利用了语言的表达性质量来减少代码大小和不必要的变量。
我想喜欢Java或C#的人会选择第一种方式(object.member),而喜欢Ruby或Python的人则会选择后者。
with语句可用于减少代码大小或私有类成员,例如:
// demo class framework
var Class= function(name, o) {
var c=function(){};
if( o.hasOwnProperty("constructor") ) {
c= o.constructor;
}
delete o["constructor"];
delete o["prototype"];
c.prototype= {};
for( var k in o ) c.prototype[k]= o[k];
c.scope= Class.scope;
c.scope.Class= c;
c.Name= name;
return c;
}
Class.newScope= function() {
Class.scope= {};
Class.scope.Scope= Class.scope;
return Class.scope;
}
// create a new class
with( Class.newScope() ) {
window.Foo= Class("Foo",{
test: function() {
alert( Class.Name );
}
});
}
(new Foo()).test();
var o={x: 5},r, fnRAW= function(a,b){ return a*b; }, fnScoped, s, e, i;
with( o ) {
fnScoped= function(a,b){ return a*b; };
}
s= Date.now();
r= 0;
for( i=0; i < 1000000; i++ ) {
r+= fnRAW(i,i);
}
e= Date.now();
console.log( (e-s)+"ms" );
s= Date.now();
r= 0;
for( i=0; i < 1000000; i++ ) {
r+= fnScoped(i,i);
}
e= Date.now();
console.log( (e-s)+"ms" );
因此,在上述提到的使用with语句的方式中,它对性能没有负面影响,反而有好处,因为它可以减小代码大小,从而影响移动设备的内存使用。
对于一些短代码片段,我想使用三角函数,如sin
,cos
等,以度数模式而不是弧度模式。为此,我使用一个AngularDegree
对象:
AngularDegree = new function() {
this.CONV = Math.PI / 180;
this.sin = function(x) { return Math.sin( x * this.CONV ) };
this.cos = function(x) { return Math.cos( x * this.CONV ) };
this.tan = function(x) { return Math.tan( x * this.CONV ) };
this.asin = function(x) { return Math.asin( x ) / this.CONV };
this.acos = function(x) { return Math.acos( x ) / this.CONV };
this.atan = function(x) { return Math.atan( x ) / this.CONV };
this.atan2 = function(x,y) { return Math.atan2(x,y) / this.CONV };
};
然后我可以在with
块中使用角度模式的三角函数而不需要更多的语言噪音:
function getAzimut(pol,pos) {
...
var d = pos.lon - pol.lon;
with(AngularDegree) {
var z = atan2( sin(d), cos(pol.lat)*tan(pos.lat) - sin(pol.lat)*cos(d) );
return z;
}
}
with
语句并不是一个好主意,因为这会使代码难以阅读。你无法确定哪个函数是全局的,哪个函数是在with
对象的作用域内调用的。如果任何函数在对象作用域内未被定义,那么它将尝试在全局命名空间中访问该函数。 - Saket Patelz = Math.atan2( Math.sin(d * Math.PI / 180), Math.cos( pol.lat * Math.PI / 180) * Math.tan( pos.lat * Math.PI / 180 ) - Math.sin( pol.lat * Math.PI / 180 ) * Math.cos( d * Math.PI / 180) ) * 180 / Math.PI;
可以得出相同的结果,但这太可怕了。 - rplantikowith
的例子,这可能会让你困惑。 - Ruan Mendeswith
语句可以消除某些不确定性:if (typeof Object.merge !== 'function') {
Object.merge = function (o1, o2) { // Function to merge all of the properties from one object into another
for(var i in o2) { o1[i] = o2[i]; }
return o1;
};
}
我可以像使用with
一样使用它,但我知道它不会影响我不想影响的任何范围。
用法:
var eDiv = document.createElement("div");
var eHeader = Object.merge(eDiv.cloneNode(false), {className: "header", onclick: function(){ alert("Click!"); }});
function NewObj() {
Object.merge(this, {size: 4096, initDate: new Date()});
}
for(var i = nodes.length; i--;)
{
// info is namespaced in a closure the click handler can access!
(function(info)
{
nodes[i].onclick = function(){ showStuff(info) };
})(data[i]);
}
for(var i = nodes.length; i--;)
{
// info is namespaced in a closure the click handler can access!
with({info: data[i]})
{
nodes[i].onclick = function(){ showStuff(info) };
}
}
我认为真正的风险是意外操纵不属于with语句的变量,这就是为什么我喜欢通过传入对象字面量到with语句来添加上下文信息,你可以清楚地看到代码中添加上下文信息后的结果。
将在相对复杂的环境中运行的代码放入容器中是一个不错的选择:我使用它来创建本地绑定,使得“window”等可以运行面向Web浏览器的代码。
使用with在许多实现中会使你的代码变慢,因为所有内容现在都包装在一个额外的范围内进行查找。在JavaScript中没有合法使用with的理由。
with
关键字,而第二段代码则没有使用这个关键字。在执行循环语句时,第一段代码比第二段代码慢了约三倍。 - yorickwith
关键字的代码为 1138,而不使用 with
为 903。由于这个微小的差异即使在紧密循环中也不会产生太大影响,因此在关注性能之前,我会根据编码简单性和重构易用性来考虑每种情况并作出选择。 - Plynx
with
,所以这个东西已经不存在了。 - Thomas Aylott