Javascript:函数中的变量赋值
考虑以下两个方面: 块AJavascript:函数中的变量赋值,javascript,Javascript,考虑以下两个方面: 块A obj = { a: 1, b: 2, c: 3, f: function() { alert(this.a); alert(this.b); alert(this.c); } } 块B obj = { a: 1, b: 2, c: 3, f: function() { var a = this.a; var b =
obj = {
a: 1,
b: 2,
c: 3,
f: function() {
alert(this.a);
alert(this.b);
alert(this.c);
}
}
块B
obj = {
a: 1,
b: 2,
c: 3,
f: function() {
var a = this.a;
var b = this.b;
var c = this.c;
alert(a);
alert(b);
alert(c);
}
}
一种方法比另一种更正确/有效吗?当然,这是一个简明的例子——在我的代码中有更多的变量,我试图做的是节省时间,不必每次在函数中键入this.varName
,而是为当前函数的作用域重新分配变量。它是有效的,但它是正确的吗
编辑:为了澄清,变量将在整个函数中广泛使用。一般的共识似乎是,对于这一点,通过局部作用域进行重新分配是可行的。第一种方法相对来说更有效,因为在第二种方法中,您制作了变量的一个副本,因此所有变量都有一个额外的语句,并且会占用更多的内存空间(代码和变量).视情况而定。如果只使用一次该值,那么增加存储和检索该值的开销是没有意义的。另一方面,如果在函数范围内多次引用该值,则只获取一次是有意义的。
f: function() {
a = this.a;
b = this.b;
c = this.c;
alert(a);
alert(b);
alert(c);
}
不仅全局赋值和查找效率较低,而且您正在污染全局范围,因为a=this.a
正在分配给全局a
编辑:
让我们假设this.a
和this.b
导致一个getter触发,alert(a)
导致调用a
值的toString
方法
两者之间存在操作顺序差异
var a = this.a, b = this.b;
alert(a); alert(b);
哪一个(得到a,得到b,一个toString,一个toString)和
哪一个(得到a,a toString,得到b,b toString)和
可能有一个很好的理由选择一种操作顺序而不是另一种,但从效率角度看,第二种可能更好
由于操作顺序的不同,当成员只有一次使用时,您不应该依赖于保留语义的JavaScript小型化器来优化第一到第二次。如果在函数中只访问一次属性,则第一次访问速度更快。如果您多次访问它,那么使用修改后的版本作为第二个代码块会更快 将第二个版本更改为将
a
、b
和c
声明为f()
的本地变量将避免多次扫描范围链和遍历此
——同样,如果您需要多次访问这些属性,也可以这样做。视频摘要:
与全局变量类似,可以通过创建局部变量来保存多次引用的对象属性和数组项,从而提高性能。另外,请记住,更深层次的对象属性和数组项查找(例如,obj.name1.name2.name3)速度较慢
如果可以稍微更改对象结构,请尝试将所需的属性放入容器(z)中,如下所示:
obj = {
z: {
a: 1,
b: 2,
c: 3
},
f: function() {
var z = this.z;
for(var prop in z) {
alert(z[prop]);
}
}
}
您在示例中遗漏了一些关键内容。我只将重点放在
f
函数上,假设其余代码是相同的:
如果您只是访问存储在对象上的值,那么没有理由存储临时变量,它只会使工作陷入困境:
function () {
//use the values as they are
alert( this.a );
alert( this.b );
alert( this.c );
}
但是,如果您正在执行计算,并且需要临时缓存结果以供重用,则应使用局部变量。确保它们不会污染全局范围(窗口
对象);使用var
使变量仅在本地持久化
function () {
var foo;
foo = this.a / this.b + this.c;
alert( this.a * foo );
alert( this.b / foo );
alert( this.c + foo );
}
编辑以添加:
有两种不同类型的变量被引用。附加到对象的变量(使用this.varname
或this['varname']
访问)和仅存在于本地范围内的变量(使用var varname
声明并使用varname
访问)
附加到对象的任何变量都可以公开访问,并且应该用于在函数调用之间显示数据或持久性。函数中声明的任何变量只能在函数的上下文中访问,因此是函数的私有变量。它们不会在调用之间保留值,但可以用于在对子函数的调用之间保留数据
在块A和块B之间,块A是与对象数据交互的首选方法,但是在大多数情况下,函数执行更大系列的操作,通常涉及更复杂的行为。如果函数包含需要this.a
、this.b
和this.c
值的回调,则需要使用别名来传递数据,因为this
会在上下文之间更改
这不会像预期的那样发出警报1
、2
和3
f:function ()
{
$(foo).click(function g(){
//`this` does not refer to the object `f` belongs to, but the element being clicked on
//and therefor is not likely to work as expected
alert( this.a );
alert( this.b );
alert( this.c );
});
}
此版本将:
1) 您应该使用var
来声明变量,否则它们将是全局变量
2) 是的,复制值可以节省键入时间,而且执行速度更快,因为访问对象属性并不是一个真正便宜的操作。JavaScript不实现数组;它们总是散列。我希望您打算将var放在块B中每个变量声明的前面。否则,您正在做一些您可能不打算做的事情。您将在全局对象的属性a、b、c上设置值,而不是将值设置为匿名函数所独有的变量,该匿名函数是为属性f指定的
var obj = {
a: 1,
b: 2,
c: 3,
f: function () {
for (var property in this) {
if (property != "f")
alert(property + "=" + this[property]);
}
}
};
obj.f();
我想您的意思是将var放在匿名函数中每个变量a、b和c的前面
根据尼古拉斯·扎卡斯(Nicholas Zakas)的书,他提到了标识符解析(查找您正在使用的变量名)所涉及的成本。他指出,局部变量的成本最低,而全局变量的成本最低
f:function()
{
var a,b,c;
a = this.a;
b = this.b;
c = this.c;
$(foo).click(function g(){
alert( a );
alert( b );
alert( c );
});
}
var obj = {
a: 1,
b: 2,
c: 3,
f: function () {
for (var property in this) {
if (property != "f")
alert(property + "=" + this[property]);
}
}
};
obj.f();
$(function() {
var b;
var d = { b : 1 }
var n = 100000;
var now = function() {
return new Date().getTime();
};
var doTime = function(f) {
var t = now();
f();
return now() - t;
};
var tm1 = doTime(function() {
for (var i=0; i<n; i++) {
b = 1;
}
});
var tm2 = doTime(function() {
for (var i=0; i<n; i++) {
b = d.b;
}
});
$('body').empty().html("<table><tr><tr><td>Time without</td><td>"
+ tm1 + "ms</td><tr>"
+ "<tr><tr><td>Time with</td><td>"+ tm2 + "ms</td><tr>"
+ "<tr><tr><td>Total diff</td><td>"+ (tm2 - tm1) + "ms</td><tr>"
+ "<tr><tr><td>Avg. diff</td><td>"+ ((1000000.0 * (tm2 - tm1)) / n)
+ "ns</td><tr>"
+ "</table");
});
(function () {
var i = 10;
(function () {
(function() {
console.log(i); // i is 10
})();
})();
})();
var i = 1;
function test() {
console.log(i); // undefined
var i = 10;
}
test();
var i = 1;
function test() {
var i;
console.log(i); // undefined
i = 10;
}
test();
var obj = {
a: 1,
b: 2,
c: 3,
f: function() {
var a, b, c;
a = this.a;
b = this.b;
c = this.c;
alert(a);
alert(b);
alert(c);
}
}