深入理解javascript严格模式(Strict Mode)_javascript技巧

ECMAScript5中引入的严格模式,通过让JavaScript运行环境对一些开发过程中最常见和不易发现的错误做出和当前不同的处理,来让开发者拥有一个”更好”的JavaScript语言。很长一段时间内,由于只有Firefox支持严格模式,我曾对严格模式表示怀疑。但到了今天,所有主流的浏览器都在他们的最新版本中支持了严格模式(包括IE10,Opera12和Android4,IOS5)是时候开始使用严格模式了。

严格模式能起到什么作用?

严格模式为JavaScript引入了很多变化,我把他们分为两类(明显的和细微的)。细微改进的目标是修复当前JavaScript中的一些细节问题,对于这些问题我不在这里进行深入介绍;如果你有兴趣,请阅读Dmitry Soshnikov撰写的精彩文档ECMA-262-5 in Detail Chapter 2 Strict Mode。 我在这里主要介绍严格模式引入的明显变化,那些在你使用严格模式前应该知道的概念和那些对你帮助最大的改变。

在开始学习具体特性前,请记住严格模式的一大目标是让你能更快更方便的调试。运行环境在发现问题时显性的抛出错误比默不做声的失败或怪异行事(未开启严格模式的JavaScript运行环境经常这样)要好。严格模式会抛出更多错误,但这是好事,因为这些错误会唤起你注意并修复很多以前很难被发现的潜在问题。

去除WITH关键词

首先,严格模式中去除了with语句,包含with语句的代码在严格模式中会抛出异常。所以使用严格模式的第一步:确保你的代码中没有使用with。

复制代码 代码如下:

// 在严格模式中以下JavaScript代码会抛出错误
with (location) {
    alert(href);
}

防止意外为全局变量赋值

其次,局部变量在赋值前必须先进行申明。在启用严格模式之前,为一个未申明的局部变量复制时会自动创建一个同名全局变量。这是Javacript程序中最容易出现的错误之一, 在严格模式中尝试这么做时会有显性的异常抛出。

复制代码 代码如下:

// 严格模式下会抛出异常
(function() {
    someUndeclaredVar = "foo";
}());

函数中的THIS不再默认指向全局

严格模式中另一个重要的变化是函数中未被定义或为空( null or undefined)的this不在默认指向全局环境(global)。这会造成一些依赖函数中默认this行为的代码执行出错,例如:

复制代码 代码如下:

window.color = "red";
function sayColor() {
    alert(this.color);
}
// 在strict模式中会报错, 如果不在严格模式中则提示 “red"
sayColor();
// 在strict模式中会报错, 如果不在严格模式中则提示 “red"
sayColor.call(null);

this在被赋值之前会一直保持为undefined,这意味着当一个构造函数在执行时,如果之前没有明确的new关键词,会抛出异常。

复制代码 代码如下:

function Person(name) {
    this.name = name;
}
//在严格模式中会报错
var me = Person("Nicholas");

在上面的代码中,Person构造函数运行时因为之前没有new,函数中的this会保留为undefined, 由于你不能为undefined设置属性,上面的代码会抛出错误。 在非strict模式环境中,没有被复制的this会默认指向window全局变量,运行的结果将是意外的为window全局变量设置name属性。

防止重名

当编写大量代码时,对象属性和函数参数很容易一不小心被设置成一个重复的名字。严格模式在这种情况下会显性的抛出错误

复制代码 代码如下:

//重复的变量名,在严格模式下会报错
function doSomething(value1, value2, value1) {
    //code
}
//重复的对象属性名,在严格模式下会报错:
var object = {
    foo: "bar",
    foo: "baz"
};

以上的代码在严格模式中都会被认为是语法错误而在执行前就让你能得到提示。

安全的 EVAL()

虽然eval()语句最终没有被移除,但在严格模式中仍然对它进行了一些改进。最大的改变是在eval()中执行的变量和函数申明不会直接在当前作用域中创建相应变量或函数,例如:

复制代码 代码如下:

(function() {
    eval("var x = 10;");
    // 非严格模式中,alert 10
    // 严格模式中则因x未被定义而抛出异常,
    alert(x);
}());

任何在eval()执行过程中创建的变量或者函数保留在eval()中。但你能明确的从eval()语句的返回值来获取eval()中的执行结果,例如:

复制代码 代码如下:

(function() {
    var result = eval("var x = 10, y = 20; x + y");
    // 在strict或非strict模式中都能正确的运行余下的语句.(resulst为30)
    alert(result);
}());

对只读属性修改时抛出异常

ECMAScript5中还引入为对象的特定属性设为只读,或让整个对象不可修改的能力。 但在非严格模式中,尝试修改一个只读属性只会默不做声的失败。 在你和一些浏览器原生API打交道过程中,你很可能遇到这种情况。严格模式会在这种情况下明确的抛出异常,提醒你修改这个属性是不被允许的。

复制代码 代码如下:

var person = {};
Object.defineProperty(person, "name" {
    writable: false,
    value: "Nicholas"
});
// 在非严格模式时,沉默的失败,在严格模式则抛出异常.
person.name = "John";

上面的例子中,name属性被设为只读,非严格模式中执行对name属性的修改不会引发报错,但修改不会成功。但严格模式则会明确的抛出异常。

NOTE: 强烈建议你在使用任何ECMAScript属性特性指定时开启严格模式。

如何使用?

在现代浏览器中开启严格模式非常容易,只需要在JavaScript代码中出现以下指令即可

"use strict";
 

虽然看上去上面的代码仅仅只是未赋予某个变量的字符串,它实际上起到指示JavaScript引擎切换到严格模式的作用(不支持严格模式的浏览器会忽略以上代码,不会对后续的执行产生任何影响)。虽然你能把这个指令作用到全局或某个函数中,但这里还是要提醒,不要在全局环境下启用严格模式。

复制代码 代码如下:

// 请不要这么使用
"use strict";
function doSomething() {
    // 这部分代码会运行于严格模式
}
function doSomethingElse() {
    // 这部分代码也会运行于严格模式
}

 
虽然上面的代码看起来不算一个大问题。但当你不负责维护页面中引入的全部代码时,这样使用strict模式会让你面临由于第三方代码没有为严格模式做好准备而引发的问题。

因此,最好把开启严格模式的指令作用于函数中,例如:

复制代码 代码如下:

function doSomething() {
    "use strict";
    // 这个函数中的代码将会运行于严格模式
}
function doSomethingElse() {
    // 这个函数中代码不会运行于严格模式
}

 
如果你想让严格模式在不止一个函数中开启,请使用立即执行函数表达式 (immediately-invoked function expression ,IIFE):

复制代码 代码如下:

(function() {
    "use strict";
    function doSomething() {
        // 这个函数运行于严格模式
    }
    function doSomethingElse() {
        // 这个函数同样运行于严格模式
    }
}());

结论

我强烈建议你从现在开始就启用JavaScript严格模式,它能帮你发现代码中未曾注意到的错误。不要在全局环境中启用,但你能尽量多的使用IIFE(立即执行函数表达式)来把严格模式作用到多个函数范围内。一开始,你会遇到之前未曾碰到过的错误提示,这是正常的。当启用严格模式后,请确保在支持的浏览器中做了测试,以发现新的潜在问题。一定不要仅仅在代码中添加一行”use strict”就假定余下的代码能正常工作。最后,请在严格模式下开始编写更好的代码。

注:
这里有各款浏览器对严格模式支持情况的一个汇总。
可以在这个页面对当前浏览器的严格模式支持度进行测试。

严格模式的优势:

使JavaScript更牢固
1.      This不再被封装,在normal mode下,this一直是对象。
2.      Fun.caller和fun.arguments即不是可以删除的属性,也不能被set或retrieved。
3.      Arguments.caller也是不可以删除的属性,也不能set或retrieved。

为将来的ECMAScript版本铺平道路
1.      增加了下列保留字:implements, interface, let,package, private, protected, public, static和yield 。
2.      方法声明应该放在脚本或方法的最前面,不能放在if或for等语句中间。

时间: 2024-12-25 03:03:27

深入理解javascript严格模式(Strict Mode)_javascript技巧的相关文章

JavaScript严格模式详解_javascript技巧

如我们所知,JavaScript 是一门灵活的语言.其灵活性同样也带来了很多坑,当然也有一些是 设计缺陷 .比如 一个变量没有声明就赋值,默认是全局变量,如 (function () { a = 3; })(); console.log(window.a); // 输出3 对象有多个重名属性,最后赋值的那个属性会覆盖前面的值.如 var obj = { c: 3, c: 4 } // obj 为 {c:4} 还有什么 == , typeof 之类的坑,数不胜数.毕竟 JavaScript 之父设

深入理解JavaScript作用域和作用域链_javascript技巧

作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望能帮助大家更好的学习JavaScript. JavaScript作用域 任何程序设计语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期.在JavaScript中,变量的作用域有全局作用域和局部作用域两种. 1. 全局作用域(Global Sc

理解Javascript图片预加载_javascript技巧

预加载图片是提高用户体验的一个很好方法.图片预先加载到浏览器中,访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度.这对图片画廊及图片占据很大比例的网站来说十分有利,它保证了图片快速.无缝地发布,也可帮助用户在浏览你网站内容时获得更好的用户体验.本文将分享三个不同的预加载技术,来增强网站的性能与可用性. 方法一:用CSS和JavaScript实现预加载 实现预加载图片有很多方法,包括使用CSS.JavaScript及两者的各种组合.这些技术可根据不同设计场景设计出相应的解决方案,十分高效.

深入理解JavaScript程序中内存泄漏_javascript技巧

垃圾回收解放了我们,它让我们可将精力集中在应用程序逻辑(而不是内存管理)上.但是,垃圾收集并不神奇.了解它的工作原理,以及如何使它保留本应在很久以前释放的内存,就可以实现更快更可靠的应用程序.在本文中,学习一种定位 JavaScript 应用程序中内存泄漏的系统方法.几种常见的泄漏模式,以及解决这些泄漏的适当方法. 一.简介 当处理 JavaScript 这样的脚本语言时,很容易忘记每个对象.类.字符串.数字和方法都需要分配和保留内存.语言和运行时的垃圾回收器隐藏了内存分配和释放的具体细节. 许

深入理解javascript构造函数和原型对象_javascript技巧

常用的几种对象创建模式 使用new关键字创建 最基础的对象创建方式,无非就是和其他多数语言一样说的一样:没对象,你new一个呀! var gf = new Object(); gf.name = "tangwei"; gf.bar = "c++"; gf.sayWhat = function() { console.log(this.name + "said:love you forever"); } 使用字面量创建 这样似乎妥妥的了,但是宅寂的

理解Javascript的动态语言特性_javascript技巧

Javascript是一种解释性语言,而并非编译性,它不能编译成二进制文件. 理解动态执行与闭包的概念 动态执行:javascript提供eval()函数,用于动态解释一段文本,并在当前上下文环境中执行. 首先我们需要理解的是eval()方法它有全局闭包和当前函数的闭包,比如如下代码,大家认为会输出什么呢? var i = 100; function myFunc() { var i = 'test'; eval('i = "hello."'); } myFunc(); alert(i

深入理解javascript函数参数与闭包_javascript技巧

最近在学习javascript的函数,函数是javascript的一等对象,想要学好javascript,就必须深刻理解函数.本人把学习的过程整理成文章,一是为了加深自己函数的理解,二是给读者提供学习的途径,避免走弯路.内容有些多,但都是笔者对于函数的总结. 1.函数参数 1.1:参数是什么 1.2:参数的省略 1.3:参数默认值 1.4:参数传递方式 1.5:同名参数 1.6:arguments对象 2.闭包 2.1:闭包定义 2.2:立即调用的函数表达式(IIFE, Immediately

理解Javascript文件动态加载_javascript技巧

Javascript文件动态加载一直是比较困扰的一件事情,像网络上传的比较常见的做法: function loadjs(fileurl){ var sct = document.createElement("script"); sct.src = fileurl; document.head.appendChild(sct); } 然后我们来测试一下结果: <html> <head> <link rel="stylesheet" typ

JavaScript组合模式学习要点_javascript技巧

组合模式:将一组对象组合成树形结构,并统一对待组合对象和叶对象,忽略它们之间的不同(因为叶对象也可以也可以包含叶对象而成为组合对象),组合模式中的对象只能是一对多的关系,不能出现多对一. 基本单元:一个组合对象包含多个叶对象.每个基本单元又可以是别的组合对象的叶对象类似文件夹与它里面的内容的关系网,一个文件夹或文件又可以是其它文件夹的内容,但一个文件夹或文件不能同时属于多个上级文件夹. 在JavaScript中实现组合模式时,要保证组合对象和叶对象拥有相同的接口方法,对同一组叶对象的操作必须具有