ECMAScript5 严格模式,JSON,及其它

ECMAScript5 严格模式,JSON,及其它

ECMAScript5 规范自推出以来, 对javascript的发展产生了蛮大的影响。这篇文章是我翻译自John Resig(jQuery作者)的一篇博文  《ECMAScript 5 Strict Mode, JSON, and More》

----------

之前我分析了ES5的对象和属性系统。这是这门语言的一大亮点。

同样有许多其他新特性和API也需要我们注意。最主要的有严格模式(Strict Mode)和原生JSON支持(native JSON support)。

严格模式(Strict Mode)

严格模式在ES5中是个新特性,它允许你在一个“严格”的环境中执行你的代码。严格的环境会阻止采用一些特定的代码行为,抛出更多的异常(总体上说给用户更多的信息和规范编码)。

自ES5对ES3进行兼容后,所有在ES3中可以正常使用,但在ES5中注为“不推荐”的特性将在严格模式下失效(或者抛出异常)。

严格模式将以如下这些方式推进代码规范:

  • 捕获一些常见的代码漏洞,抛出异常

  • 当一些相对“不安全”的代码被执行时,进行阻止或抛出异常(例如获取全局对象访问)

  • 禁掉那些令人疑惑或者欠考虑的特性

大多数关于严格模式的信息可以在ES5规范[PDF]223页找到。

应该注意的是ES5的严格模式与FireFox提供的严格模式不同(可以通过about:config来启动javascript.options.strict)。ES5关注编码规范上的潜在错误。(而FireFox的严格模式只是强调一些最佳实践)。

如何启动严格模式?

很简单。在你的代码前加上"use strict",为你所有代码启动严格模式:

1
"use strict" ;

或者只在一个执行上下文内,如:

1
2
3
4
function  imStrict() {
     "use strict" ;
     // ... your code...
}

看吧,启动严格模式的语法,不能再简单了,就一条语句"use strict"就行了。没有新的语法,不需要什么复杂的配置,并且对老的浏览器也没什么副作用。

ES5并没有对语言语法进行添加或者更改。所以可以在老浏览器中进行优雅降级。

在一个函数中定义严格模式,你可以在其中定义自己的javascript库,而不影响外部的代码。

1
2
3
4
5
6
7
// Non-strict code...
( function () {
     "use strict" ;
     
     // Define your library strictly...
})();
// Non-strict code...

当前很多库用上面的这种包裹技术(把整个库包在一个自动执行的匿名函数中)。

那么当你把脚本置于严格模式后,会发生什么呢?很多事情

变量和属性

尝试赋值foo = 'bar';如果'foo'没有事先定义,那么将失败。在这之前,foo会被赋值,并且foo会作为全局对象window的属性window.foo,现在这会抛出异常。确保避免一些恼人的bug。

对任何writable属性(attribute)为false的属性(property)进行写操作,configurable属性(attribute)为false的属性(property)进行删除操作,extensible属性(attribute)为false的对象进行添加属性(property)都会导致报错。传统上,当尝试这些行为时错误不会被抛出,将静静地失败。

删除变量,一个函数,一个参数将导致错误。

1
2
3
4
5
6
7
8
9
var  foo =  "test" ;
function  test() {}
 
delete  foo;    // Error
delete  test;   // Error
 
function  test2(arg) {
     delete  arg;        // Error          
}

在一个字面对象中不止一次定义一个同名属性,将导致异常抛出

1
2
// Error
{ foo:  true , foo:  false  }

eval

几乎任何尝试使用'eval'这个名称的操作都会被禁止.

1
2
3
4
5
6
7
8
9
// All generate errors...
obj.eval = ...
obj.foo = eval;
var  eval = ...;
for ( var  eval  in  ...) {}
function  eval() {}
function  test(eval) {}
function (eval) {}
new  Function( "eval" )

除此之外,通过eval引入的新变量无效

1
2
eval( "var a = false;" );
print( typeof  a);  // undefined

Functions

试图去覆写arguments对象将导致出错:

1
arguments = [...];  // now allowed

定义同名的参数会导致错误:function(foo, foo)

对arguments.caller和arguments.callee的访问将抛出异常。因此任何你想引用的匿名函数要给个名称,像这样:

1
2
3
4
setTimeout( function  later() {
     // do stuff...
     setTimeout(later, 1000);
}, 1000);

其他函数的arguments和caller属性不在存在,并且定义它们的能力被禁止:

1
2
3
4
5
6
7
function  test() {
     function  inner() {
         // Don't exist, either
         test.arguments = ...;  // Error
         inner.caller = ...;  // Error
     }
}

最后一个长期困扰的(并且很恼人的)bug被解决了:像如下用例中,null或者undefined被强制转换为全局对象。严格模式现在阻止这样的事情发生,并会抛个异常。

1
( function () { ... }).call( null );  // Exception

with

with语句在严格模式中完全被干掉了,事实上它的出现会作为语法错误。

ES5严格模式对代码的改变是多样的。观察开发者如何开始采用这些规范和它如何改变javascript开发,将是个有趣的过程。

JSON

ECMAScript语言第二个主要的特性是加入了对JSON的原生支持。

我已经拥护此项推进很久了,如今我很高兴的看到它被写入了规范。

有2个主要的方法用于处理JSON:JSON.parse(把一个JSON字符串转成一个javascript对象)和JSON.stringify(把一个javascript对象转成一个序列化的字符串)。

JSON.parse(text)

把一个序列化的JSON字符串转成一个javascript对象。

1
2
3
var  obj = JSON.parse( '{"name": "John"}' );
// Prints 'John'
print(obj.name);

JSON.parse(text, translate)

使用一个转换函数 转换值或者进行移除

1
2
3
4
5
6
7
8
9
10
11
12
function  translate(key, value) {
     if ( key ===  "name" ) {
         return  value +  " Resig" ;
     }
}
 
var  obj = JSON.parse( '{"name": "John", "last": "Resig"}' , translate);
// Prints 'John Resig'
print( obj.name );
 
// Undefined
print( obj.last );

JSON.stringify(obj)

把一个对象转成一个序列化的JSON字符串

1
2
3
var  str = JSON.stringify({name:  "John" });
// Prints {"name": "John"}
print( str );

JSON.stringify(obj, ["white", "list"])

只序列化白名单指定的属性

1
2
3
4
var  list = [ "name" ];
var  str = JSON.stringify({name:  "John" , last:  "Resig" }, list);
// Prints {"name": "John"}
print( str );

JSON.stringify(obj, translate)

用转换函数来序列化对象

1
2
3
4
5
6
7
8
9
function  translate(key, value) {
     if (key ===  "name" ) {
         return  value +  " Resig" ;
     }
}
 
var  str = JSON.stringify({ "name" "John" "last" "Resig" }, translate);
// Prints {"name": "John Resig"}
print( str );

JSON.stringify(obj, null, 2)

给输出增加指定的空格数

1
2
3
4
5
6
var  str = JSON.stringify({ name:  "John"  },  null , 2);
// prints
// {
//   "name": "John"
// }
print( str );

JSON.stringify(obj, null, "\t")

使用特定的字符来做分隔

1
2
3
4
var  str = JSON.stringify({ name:  "John"  },  null "\t" );
// Prints:
// {\n\t"name": "John"\n}
print( str );

另外,一些基础类型添加了新的通用方法,但是,恕我直言,它们并不有趣。来自String,Boolean和Number的结果等同于调用valueOf(), Date的结果等同于调用toISOString()

1
2
3
4
5
// Yawn
String.prototype.toJSON
Boolean.prototype.toJSON
Number.prototype.toJSON
Date.prototype.toJSON

.bind()

内置bind()方法的引入很受欢迎,它可以使一个函数的执行环境得到改变(几乎等同于prototype framework中的bind实现)

1
Function.prototype.bind(thisArg, arg1, arg2...)

使得函数的this关键字指向一个特定的对象,并传入任何你要指定的参数。

1
2
3
4
5
6
7
var  obj = {
     method:  function (name) {
         this .name = name;
     }
};
 
setTimeout(obj.method.bind(obj,  "John" ), 100);

Date

首先,如果所给的值是ISO格式,Date构造函数会试图去解析该日期,接着再处理它接受的其他输入。

1
2
3
4
var  date =  new  Date( "2009-05-21T16:06:05.000Z" );
 
// Prints 2009-05-21T16:06:05.000Z
print( date.toISOString() );

另外,date对象现在有个新的toISOString()方法,以ISO格式输出日期

.trim()

一个原生,内置的trim()方法被String对象支持,和我们自己实现的trim方法功能一样,但是原生的效率更高。

Array

JavaScript Array扩展方法包括: indexOf, lastIndexOf, every, some, forEach, map, filter, reduce 和 reduceRight

另外一个新方法Array.isArray(译者注:可以理解为Array的static方法)被包含了进来, 提供和下面这段代码同样地功能:

1
2
3
Array.isArray =  function ( array ) {
     return  Object.prototype.toString.call( array ) ===  "[object Array]" ;
}

你可能感兴趣的:(json,static,mode,js5,ECMAScript5)