有没有办法在JavaScript中使用常量?
如果没有,指定用作常量的变量的常见做法是什么?
try{const thing=1091;}catch(e){var thing=1091;}
作品。
const
或var
根本没有意义?
const
它的作用域与相同var
,并且是功能级的,而不是块级的。如果您改为遵循即将发布的ECMAScript标准,const
则其范围与相同let
,这意味着它将无法使用。
有没有办法在JavaScript中使用常量?
如果没有,指定用作常量的变量的常见做法是什么?
try{const thing=1091;}catch(e){var thing=1091;}
作品。
const
或var
根本没有意义?
const
它的作用域与相同var
,并且是功能级的,而不是块级的。如果您改为遵循即将发布的ECMAScript标准,const
则其范围与相同let
,这意味着它将无法使用。
Answers:
const MY_CONSTANT = "some-value";
这几乎可以在除IE 8、9和10之外的所有浏览器中使用。有些可能还需要启用严格模式。
您可以var
与ALL_CAPS之类的约定一起使用,以表明如果需要支持旧版浏览器或使用旧版代码,则不应修改某些值:
var MY_CONSTANT = "some-value";
const
关键字。目前,除IE之外,所有现代浏览器均支持该功能。
Object.defineProperty
用来创建也不能删除的只读属性。这适用于所有主要浏览器的当前版本(但在IE8中不正确)。请参阅@NotAName的答案
const
现在,该关键字已正式成为该语言的一部分,并且每个浏览器都支持该关键字。根据statcounter.com的说法,只有百分之几的互联网用户仍在使用不支持的旧浏览器版本const
。
您是否要保护变量不被修改?如果是这样,则可以使用模块模式:
var CONFIG = (function() {
var private = {
'MY_CONST': '1',
'ANOTHER_CONST': '2'
};
return {
get: function(name) { return private[name]; }
};
})();
alert('MY_CONST: ' + CONFIG.get('MY_CONST')); // 1
CONFIG.MY_CONST = '2';
alert('MY_CONST: ' + CONFIG.get('MY_CONST')); // 1
CONFIG.private.MY_CONST = '2'; // error
alert('MY_CONST: ' + CONFIG.get('MY_CONST')); // 1
使用这种方法,无法修改值。但是,您必须在CONFIG :(上使用get()方法。
如果不需要严格保护变量值,则按照建议的方法进行操作并使用ALL CAPS的约定。
CONFIG.get = someNewFunctionThatBreaksTheCode
...总之,您绝对不能在JS中执行常量(不带const关键字)。您唯一能做的就是限制可见度。
private
是JavaScript中将来的保留字,如果您是我,我不会使用它。
该const
关键字是ECMAScript的第6条草案,但迄今只享受的浏览器支持一知半解:http://kangax.github.io/compat-table/es6/。语法为:
const CONSTANT_NAME = 0;
const
,则不会引发任何错误。赋值只是失败,并且常量仍然具有其原始值。恕我直言,这是一个主要的设计缺陷,但只要有一个清晰,一致的命名约定(例如流行的ALL_CAPS),我认为它不会引起太多的麻烦。
'use strict'
。
ALL CAPS
吗?
"use strict";
var constants = Object.freeze({
"π": 3.141592653589793 ,
"e": 2.718281828459045 ,
"i": Math.sqrt(-1)
});
constants.π; // -> 3.141592653589793
constants.π = 3; // -> TypeError: Cannot assign to read only property 'π' …
constants.π; // -> 3.141592653589793
delete constants.π; // -> TypeError: Unable to delete property.
constants.π; // -> 3.141592653589793
参见Object.freeze。如果您还希望将引用设为只读,则可以使用const
constants
。
i
const
声明的行为类似,例如,不能重新声明或重新分配属性,但是如果属性属于datatype object
,则可以对其进行突变。
const constants
代替var constants
来防止重新分配变量。
IE确实支持常量,例如:
<script language="VBScript">
Const IE_CONST = True
</script>
<script type="text/javascript">
if (typeof TEST_CONST == 'undefined') {
const IE_CONST = false;
}
alert(IE_CONST);
</script>
const
)。您能解释一下这是怎么回事吗?
ECMAScript 5确实引入了Object.defineProperty
:
Object.defineProperty (window,'CONSTANT',{ value : 5, writable: false });
writable: false
将如果这样做分配的代码正在下的ECMAScript 5的严格模式解释居然抛出一个错误。编写'use strict'
代码的另一个原因。
不,不是一般。Firefox实现了,const
但我知道IE没有。
@John指出了一种在其他语言上已经使用了多年的const命名惯例,我认为没有理由不能使用它。当然,这并不意味着某人无论如何也不会覆盖变量的值。:)
在JavaScript中,我的首选是使用函数返回常量值。
function MY_CONSTANT() {
return "some-value";
}
alert(MY_CONSTANT());
Mozillas MDN Web Docs包含有关的良好示例和说明const
。摘抄:
// define MY_FAV as a constant and give it the value 7
const MY_FAV = 7;
// this will throw an error - Uncaught TypeError: Assignment to constant variable.
MY_FAV = 20;
但是令人遗憾的是IE9 / 10仍然不支持const
。和它荒谬的原因:
那么,IE9在使用const做什么呢?到目前为止,我们的决定是不支持它。由于尚未在所有浏览器上使用,因此它尚未成为共识功能。
...
最后,似乎最好的长期网络解决方案是将其保留,并等待标准化过程正常进行。
他们没有实现它,因为其他浏览器没有正确实现它?太害怕使它变得更好?是否定义标准,常量是常量:设置一次,永不更改。
和所有想法:每个函数都可以被覆盖(XSS等)。因此,var
或中没有区别function(){return}
。const
是唯一的实常数。
更新:IE11 支持 const
:
IE11包括用于新兴的ECMAScript 6标准的明确定义和常用的功能,包括让,支承
const
,Map
,Set
,和WeakMap
,以及__proto__
改进的互操作性。
如果您不介意使用函数:
var constant = function(val) {
return function() {
return val;
}
}
这种方法为您提供函数而不是常规变量,但可以保证*设置值后,任何人都无法更改。
a = constant(10);
a(); // 10
b = constant(20);
b(); // 20
我个人觉得这很令人愉快,尤其是在从可观察的观测器适应了这种模式之后。
*除非有人constant
在您调用它之前重新定义了该函数
a = constant(10); a(10); // 10
后跟a = constant(25); a(); //25
,没有错误或警告,没有表明您的常量已损坏。
a
它,那么它将更改为新值
使用“新”对象api,您可以执行以下操作:
var obj = {};
Object.defineProperty(obj, 'CONSTANT', {
configurable: false
enumerable: true,
writable: false,
value: "your constant value"
});
看看这对Mozilla的MDN的更多细节。它不是第一级变量,因为它是附加到对象的,但是如果有作用域,则可以将其附加到对象。this
应该也可以。因此,例如在全局范围内执行此操作将在窗口上声明一个伪常量值(这是一个非常糟糕的主意,您不应该粗心地声明全局变量)
Object.defineProperty(this, 'constant', {
enumerable: true,
writable: false,
value: 7,
configurable: false
});
> constant
=> 7
> constant = 5
=> 7
注意:赋值将返回您在控制台中分配的值,但变量的值不会更改
在可能的情况下将常量分组为结构:
例如,在当前的游戏项目中,我使用了以下内容:
var CONST_WILD_TYPES = {
REGULAR: 'REGULAR',
EXPANDING: 'EXPANDING',
STICKY: 'STICKY',
SHIFTING: 'SHIFTING'
};
分配:
var wildType = CONST_WILD_TYPES.REGULAR;
比较:
if (wildType === CONST_WILD_TYPES.REGULAR) {
// do something here
}
最近,为了比较,我正在使用:
switch (wildType) {
case CONST_WILD_TYPES.REGULAR:
// do something here
break;
case CONST_WILD_TYPES.EXPANDING:
// do something here
break;
}
IE11带有带有“ const”声明的新ES6标准。
以上适用于IE8,IE9和IE10等较早的浏览器。
您可以轻松地为脚本配备常量机制,该常量可以设置但不能更改。尝试更改它们将产生错误。
/* author Keith Evetts 2009 License: LGPL
anonymous function sets up:
global function SETCONST (String name, mixed value)
global function CONST (String name)
constants once set may not be altered - console error is generated
they are retrieved as CONST(name)
the object holding the constants is private and cannot be accessed from the outer script directly, only through the setter and getter provided
*/
(function(){
var constants = {};
self.SETCONST = function(name,value) {
if (typeof name !== 'string') { throw new Error('constant name is not a string'); }
if (!value) { throw new Error(' no value supplied for constant ' + name); }
else if ((name in constants) ) { throw new Error('constant ' + name + ' is already defined'); }
else {
constants[name] = value;
return true;
}
};
self.CONST = function(name) {
if (typeof name !== 'string') { throw new Error('constant name is not a string'); }
if ( name in constants ) { return constants[name]; }
else { throw new Error('constant ' + name + ' has not been defined'); }
};
}())
// ------------- demo ----------------------------
SETCONST( 'VAT', 0.175 );
alert( CONST('VAT') );
//try to alter the value of VAT
try{
SETCONST( 'VAT', 0.22 );
} catch ( exc ) {
alert (exc.message);
}
//check old value of VAT remains
alert( CONST('VAT') );
// try to get at constants object directly
constants['DODO'] = "dead bird"; // error
忘记IE并使用const
关键字。
但是,尚无精确的跨浏览器预定义方法来执行此操作,您可以通过控制变量的范围来实现它,如其他答案所示。
但是我建议使用命名空间来区别其他变量。这会将与其他变量发生碰撞的机会降到最低。
正确的命名空间,例如
var iw_constant={
name:'sudhanshu',
age:'23'
//all varibale come like this
}
所以在使用这将是iw_constant.name
或iw_constant.age
您还可以使用Object.freeze方法阻止在iw_constant内部添加任何新键或更改任何键。但是,旧版浏览器不支持它。
例如:
Object.freeze(iw_constant);
对于较旧的浏览器,您可以使用polyfill进行冻结。
如果您可以调用函数,则以下是定义常量的最佳跨浏览器方式。在自执行函数中为对象定义范围,并为常量ex返回一个get函数,例如:
var iw_constant= (function(){
var allConstant={
name:'sudhanshu',
age:'23'
//all varibale come like this
};
return function(key){
allConstant[key];
}
};
//使用iw_constant('name')
或获取值
iw_constant('age')
**在这两个示例中,您都必须非常小心地注意名称间距,以免对象或函数被其他库替换(如果对象或函数本身将被替换,则整个常量将消失)
有一阵子,我在传递给with()
语句的对象常量中指定了“常量”(实际上并不是常量)。我以为它很聪明。这是一个例子:
with ({
MY_CONST : 'some really important value'
}) {
alert(MY_CONST);
}
在过去,我还创建了一个CONST
命名空间,我将在其中放置所有常量。再次,与开销。嘘。
现在,我只是var MY_CONST = 'whatever';
对KISS做。
with
。
我的意见(仅适用于对象)。
var constants = (function(){
var a = 9;
//GLOBAL CONSTANT (through "return")
window.__defineGetter__("GCONST", function(){
return a;
});
//LOCAL CONSTANT
return {
get CONST(){
return a;
}
}
})();
constants.CONST = 8; //9
alert(constants.CONST); //9
尝试!但是请理解-这是对象,而不是简单的变量。
也可以尝试:
const a = 9;
我也有这个问题。在寻找答案并查看每个人的所有回答之后,我想我已经找到了一个可行的解决方案。
看来,我遇到的大多数答案都是使用函数来保存常量。正如许多论坛的许多用户所张贴的那样,客户端的用户可以很容易地覆盖这些功能。基思·埃维茨(Keith Evetts)的回答使我很感兴趣,因为常量对象不能由外部访问,而只能从内部函数访问。
所以我想出了这个解决方案:
将所有内容放入匿名函数中,以使客户端无法更改变量,对象等。通过让其他函数从内部调用“真实”函数,还可以隐藏“真实”函数。我还考虑过使用函数来检查客户端上的用户是否更改了函数。如果功能已更改,请使用内部“受保护”且无法更改的变量将其改回。
/*Tested in: IE 9.0.8; Firefox 14.0.1; Chrome 20.0.1180.60 m; Not Tested in Safari*/
(function(){
/*The two functions _define and _access are from Keith Evetts 2009 License: LGPL (SETCONST and CONST).
They're the same just as he did them, the only things I changed are the variable names and the text
of the error messages.
*/
//object literal to hold the constants
var j = {};
/*Global function _define(String h, mixed m). I named it define to mimic the way PHP 'defines' constants.
The argument 'h' is the name of the const and has to be a string, 'm' is the value of the const and has
to exist. If there is already a property with the same name in the object holder, then we throw an error.
If not, we add the property and set the value to it. This is a 'hidden' function and the user doesn't
see any of your coding call this function. You call the _makeDef() in your code and that function calls
this function. - You can change the error messages to whatever you want them to say.
*/
self._define = function(h,m) {
if (typeof h !== 'string') { throw new Error('I don\'t know what to do.'); }
if (!m) { throw new Error('I don\'t know what to do.'); }
else if ((h in j) ) { throw new Error('We have a problem!'); }
else {
j[h] = m;
return true;
}
};
/*Global function _makeDef(String t, mixed y). I named it makeDef because we 'make the define' with this
function. The argument 't' is the name of the const and doesn't need to be all caps because I set it
to upper case within the function, 'y' is the value of the value of the const and has to exist. I
make different variables to make it harder for a user to figure out whats going on. We then call the
_define function with the two new variables. You call this function in your code to set the constant.
You can change the error message to whatever you want it to say.
*/
self._makeDef = function(t, y) {
if(!y) { throw new Error('I don\'t know what to do.'); return false; }
q = t.toUpperCase();
w = y;
_define(q, w);
};
/*Global function _getDef(String s). I named it getDef because we 'get the define' with this function. The
argument 's' is the name of the const and doesn't need to be all capse because I set it to upper case
within the function. I make a different variable to make it harder for a user to figure out whats going
on. The function returns the _access function call. I pass the new variable and the original string
along to the _access function. I do this because if a user is trying to get the value of something, if
there is an error the argument doesn't get displayed with upper case in the error message. You call this
function in your code to get the constant.
*/
self._getDef = function(s) {
z = s.toUpperCase();
return _access(z, s);
};
/*Global function _access(String g, String f). I named it access because we 'access' the constant through
this function. The argument 'g' is the name of the const and its all upper case, 'f' is also the name
of the const, but its the original string that was passed to the _getDef() function. If there is an
error, the original string, 'f', is displayed. This makes it harder for a user to figure out how the
constants are being stored. If there is a property with the same name in the object holder, we return
the constant value. If not, we check if the 'f' variable exists, if not, set it to the value of 'g' and
throw an error. This is a 'hidden' function and the user doesn't see any of your coding call this
function. You call the _getDef() function in your code and that function calls this function.
You can change the error messages to whatever you want them to say.
*/
self._access = function(g, f) {
if (typeof g !== 'string') { throw new Error('I don\'t know what to do.'); }
if ( g in j ) { return j[g]; }
else { if(!f) { f = g; } throw new Error('I don\'t know what to do. I have no idea what \''+f+'\' is.'); }
};
/*The four variables below are private and cannot be accessed from the outside script except for the
functions inside this anonymous function. These variables are strings of the four above functions and
will be used by the all-dreaded eval() function to set them back to their original if any of them should
be changed by a user trying to hack your code.
*/
var _define_func_string = "function(h,m) {"+" if (typeof h !== 'string') { throw new Error('I don\\'t know what to do.'); }"+" if (!m) { throw new Error('I don\\'t know what to do.'); }"+" else if ((h in j) ) { throw new Error('We have a problem!'); }"+" else {"+" j[h] = m;"+" return true;"+" }"+" }";
var _makeDef_func_string = "function(t, y) {"+" if(!y) { throw new Error('I don\\'t know what to do.'); return false; }"+" q = t.toUpperCase();"+" w = y;"+" _define(q, w);"+" }";
var _getDef_func_string = "function(s) {"+" z = s.toUpperCase();"+" return _access(z, s);"+" }";
var _access_func_string = "function(g, f) {"+" if (typeof g !== 'string') { throw new Error('I don\\'t know what to do.'); }"+" if ( g in j ) { return j[g]; }"+" else { if(!f) { f = g; } throw new Error('I don\\'t know what to do. I have no idea what \\''+f+'\\' is.'); }"+" }";
/*Global function _doFunctionCheck(String u). I named it doFunctionCheck because we're 'checking the functions'
The argument 'u' is the name of any of the four above function names you want to check. This function will
check if a specific line of code is inside a given function. If it is, then we do nothing, if not, then
we use the eval() function to set the function back to its original coding using the function string
variables above. This function will also throw an error depending upon the doError variable being set to true
This is a 'hidden' function and the user doesn't see any of your coding call this function. You call the
doCodeCheck() function and that function calls this function. - You can change the error messages to
whatever you want them to say.
*/
self._doFunctionCheck = function(u) {
var errMsg = 'We have a BIG problem! You\'ve changed my code.';
var doError = true;
d = u;
switch(d.toLowerCase())
{
case "_getdef":
if(_getDef.toString().indexOf("z = s.toUpperCase();") != -1) { /*do nothing*/ }
else { eval("_getDef = "+_getDef_func_string); if(doError === true) { throw new Error(errMsg); } }
break;
case "_makedef":
if(_makeDef.toString().indexOf("q = t.toUpperCase();") != -1) { /*do nothing*/ }
else { eval("_makeDef = "+_makeDef_func_string); if(doError === true) { throw new Error(errMsg); } }
break;
case "_define":
if(_define.toString().indexOf("else if((h in j) ) {") != -1) { /*do nothing*/ }
else { eval("_define = "+_define_func_string); if(doError === true) { throw new Error(errMsg); } }
break;
case "_access":
if(_access.toString().indexOf("else { if(!f) { f = g; }") != -1) { /*do nothing*/ }
else { eval("_access = "+_access_func_string); if(doError === true) { throw new Error(errMsg); } }
break;
default:
if(doError === true) { throw new Error('I don\'t know what to do.'); }
}
};
/*Global function _doCodeCheck(String v). I named it doCodeCheck because we're 'doing a code check'. The argument
'v' is the name of one of the first four functions in this script that you want to check. I make a different
variable to make it harder for a user to figure out whats going on. You call this function in your code to check
if any of the functions has been changed by the user.
*/
self._doCodeCheck = function(v) {
l = v;
_doFunctionCheck(l);
};
}())
看来安全性确实是一个问题,没有办法从客户端“隐藏”您的编程。对我来说,一个好主意是压缩您的代码,以使包括您,程序员在内的任何人都很难阅读和理解它。您可以访问一个网站:http : //javascriptcompressor.com/。(这不是我的网站,请放心,我不是在做广告。)这个网站可让您免费压缩和混淆Javascript代码。
显然,这表明需要标准化的跨浏览器const关键字。
但现在:
var myconst = value;
要么
Object['myconst'] = value;
两者似乎都足够,其他一切都像用火箭筒射击苍蝇。
在JavaScript中,我的实践是尽可能避免使用常量,而改用字符串。当您想将常量公开给外界时,就会出现常量问题:
例如,可以实现以下Date API:
date.add(5, MyModule.Date.DAY).add(12, MyModule.Date.HOUR)
但是简单地写起来会更短,更自然:
date.add(5, "days").add(12, "hours")
这样,“天”和“小时”实际上就像常量,因为您无法从外部更改“小时”所代表的秒数。但是很容易覆盖MyModule.Date.HOUR
。
这种方法也将有助于调试。如果Firebug告诉您action === 18
,很难理解其含义,但是当您看到时,action === "save"
便会立即清楚。
"Hours"
而不是"hours"
-但IDE可能会在Date.Hours
未定义的早期就让您知道。
好的,这很丑陋,但是它为我提供了Firefox和Chromium中的常量,Safari和Opera中的常量(WTF?),以及IE中的变量。
当然eval()是邪恶的,但是如果没有它,IE就会抛出错误,从而阻止脚本运行。
Safari和Opera支持const关键字,但是您可以更改const的值。
在此示例中,服务器端代码将JavaScript写入页面,用值替换{0}。
try{
// i can haz const?
eval("const FOO='{0}';");
// for reals?
var original=FOO;
try{
FOO='?NO!';
}catch(err1){
// no err from Firefox/Chrome - fails silently
alert('err1 '+err1);
}
alert('const '+FOO);
if(FOO=='?NO!'){
// changed in Sf/Op - set back to original value
FOO=original;
}
}catch(err2){
// IE fail
alert('err2 '+err2);
// set var (no var keyword - Chrome/Firefox complain about redefining const)
FOO='{0}';
alert('var '+FOO);
}
alert('FOO '+FOO);
这有什么用?不多,因为它不是跨浏览器。充其量,也许至少有些省心浏览器不会让bookmarklet或第三方脚本修改该值,这样可以让您。
经过Firefox 2、3、3.6、4,Iron 8,Chrome 10、12,Opera 11,Safari 5,IE 6、9的测试。
如果值得一提的,你可以定义常量的角度使用$provide.constant()
angularApp.constant('YOUR_CONSTANT', 'value');
Burke答案的改进版本,可让您CONFIG.MY_CONST
代替CONFIG.get('MY_CONST')
。
它需要IE9 +或真实的Web浏览器。
var CONFIG = (function() {
var constants = {
'MY_CONST': 1,
'ANOTHER_CONST': 2
};
var result = {};
for (var n in constants)
if (constants.hasOwnProperty(n))
Object.defineProperty(result, n, { value: constants[n] });
return result;
}());
*仅当初始值不可变时,这些属性才是只读的。
JavaScript ES6(重新)引入了所有主流浏览器都支持的const
关键字。
通过声明的变量
const
无法重新声明或重新分配。
除此之外,其const
行为类似于let
。
对于基本数据类型(布尔,空,未定义,数字,字符串,符号),它的行为符合预期:
const x = 1;
x = 2;
console.log(x); // 1 ...as expected, re-assigning fails
注意:请注意有关对象的陷阱:
const o = {x: 1};
o = {x: 2};
console.log(o); // {x: 1} ...as expected, re-assigning fails
o.x = 2;
console.log(o); // {x: 2} !!! const does not make objects immutable!
const a = [];
a = [1];
console.log(a); // 1 ...as expected, re-assigning fails
a.push(1);
console.log(a); // [1] !!! const does not make objects immutable
如果您确实需要一个不变且绝对恒定的对象:只需const ALL_CAPS
使您的意图清楚即可。const
无论如何都要遵循所有声明是一个好习惯,因此请仅依赖它。
另一种选择是:
var constants = {
MY_CONSTANT : "myconstant",
SOMETHING_ELSE : 123
}
, constantMap = new function ConstantMap() {};
for(var c in constants) {
!function(cKey) {
Object.defineProperty(constantMap, cKey, {
enumerable : true,
get : function(name) { return constants[cKey]; }
})
}(c);
}
然后简单地: var foo = constantMap.MY_CONSTANT
如果您这样做,constantMap.MY_CONSTANT = "bar"
那将是无效的,因为我们正尝试将赋值运算符与getter一起使用,因此constantMap.MY_CONSTANT === "myconstant"
将保持不变。
关键字“ const”是较早提出的,现在已正式包含在ES6中。通过使用const关键字,您可以传递将作为不可变字符串的值/字符串。
在JavaScript中引入常量充其量只是一种技巧。
在JavaScript中实现持久和可全局访问的值的一种好方法是声明一个带有一些“只读”属性的对象文字,如下所示:
my={get constant1(){return "constant 1"},
get constant2(){return "constant 2"},
get constant3(){return "constant 3"},
get constantN(){return "constant N"}
}
您会将所有常量归为一个“我的”附件对象,您可以在其中查找存储的值或为此决定放置的其他任何内容。现在让我们测试一下是否可行:
my.constant1; >> "constant 1"
my.constant1 = "new constant 1";
my.constant1; >> "constant 1"
如我们所见,“ my.constant1”属性保留了其原始值。您已经为自己设置了一些不错的“绿色”临时常量...
但是,当然,这只能防止您通过直接访问意外地修改,更改,无效或清空属性常量值,如给定示例所示。
否则我仍然认为常量是假的。我仍然认为,将自己的巨大自由换成一小部分欺骗性安全保障是最糟糕的交易。
Chrome
允许您使用关键字const
来使用常量。例如const ASDF = "asdf"
。但是,由于const
不兼容多浏览器,因此我通常坚持var
声明。