严格模式

严格模式
  • ECMAScript 5的严格模式是采用具有限制性JavaScript变体的一种方式,从而使代码隐式地脱离“马虎模式/稀松模式/懒散模式“(sloppy)模式。

目的

  1. 消除JS语法中一些不合理、不严谨之处。
  2. 修复了一些导致 JavaScript引擎难以执行优化的缺陷:有时候,相同的代码,严格模式可以比非严格模式下运行得更快。
  3. 严格模式禁用了在ECMAScript的未来版本中可能会定义的一些语法,为未来的版本做铺垫。

调用

1、脚本
  • 为整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句 "use strict"; (或 'use strict';)
// 整个脚本都开启严格模式的语法
"use strict";
var v = "Hi!  I'm a strict mode script!";

注: 盲目的合并严格和非严格模式的脚本可能会出现巨大的问题,建议按照一个个函数去开启严格模式,或者将整个脚本文件放在一个立即执行的匿名函数之中。

(function (){
  "use strict";
  // some code here
})();
2、函数
  • 要给某个函数开启严格模式,得把 "use strict"; (或 'use strict'; )声明一字不漏地放在函数体所有语句之前。
function strict() {
  // 函数级别严格模式语法
  'use strict';
  function nested() {
    return "And so am I!";
  }
  return "Hi!  I'm a strict mode function!  " + nested();
}

function notStrict() {
  return "I'm not strict.";
}

语法和行为改变

1. 全局变量显式声明
  • 正常模式下,如果一个变量没有声明就赋值,则默认为全局变量。但严格模式禁止该做法,必须显式声明。
"use strict";

v = 1; // 报错,v未声明
for(i = 0; i < 2; i++) { // 报错,i未声明
}
2. 静态绑定
  • Javascript语言的一个特点,就是允许"动态绑定",即某些属性和方法到底属于哪一个对象,不是在编译时确定的,而是在运行时(runtime)确定的。
  • 严格模式对动态绑定做了一些限制。某些情况下,只允许静态绑定。也就是说,属性和方法到底归属哪个对象,在编译阶段就确定。这样做有利于编译效率的提高,也使得代码更容易阅读,更少出现意外

2.1 禁止使用with语句

"use strict";
var v = 1;
with (o){ // 语法错误
  v = 2;
}

2.2 创设eval作用域

  • 正常模式下,Javascript语言有两种变量作用域(scope):全局作用域和函数作用域。严格模式创设了第三种作用域:eval作用域。
  • 正常模式下,eval语句的作用域,取决于它处于全局作用域,还是处于函数作用域。严格模式下,eval语句本身就是一个作用域,不再能够生成全局变量了,它所生成的变量只能用于eval内部。
"use strict";
var x = 2;
console.info(eval("var x = 5; x")); // 5
console.info(x); // 2
3. 增强安全措施

3.1 禁止this关键字指向全局对象

function f(){
  return !this;
}// 返回false,因为"this"指向全局对象,"!this"false

function f(){
  "use strict";
  return !this;
}// 返回true,因为严格模式下,this的值为undefine,所以"!this"true
  • 在使用构造函数时,如果没有加new,this不再指向全局对象,而是报错
function f(){
  "use strict";
  this.a = 1;
};
f();// 报错,this未定义

3.2 禁止函数内部遍历调用栈

function f1(){
    "use strict";
    f1.caller; // 报错
    f1.arguments; // 报错
}
f1();
4. 禁止删除变量
  • 严格模式下无法删除变量。只有configurable设置为true的对象属性,才能被删除。
"use strict";

var x;
delete x; // 语法错误
var o = Object.create(null, {'x': {
  value: 1,
  configurable: true
}});
delete o.x; // 删除成功
5. 显示报错
  • 正常模式下,对一个对象的只读属性进行赋值,不会报错,只会默默地失败。严格模式下,将报错。
"use strict";

var o = {};
Object.defineProperty(o, "v", { value: 1,writable: false });
o.v = 2; // 报错
  • 严格模式下,对一个使用getter方法读取的属性进行赋值,会报错。
"use strict";

var o = {
    get v() { return 1; }
};
o.v = 2; // 报错
  • 严格模式下,对禁止扩展的对象添加新属性,会报错。
"use strict";

var o = {};
Object.preventExtensions(o);
o.v = 1; // 报错
  • 严格模式下,删除一个不可删除的属性,会报错。
"use strict";

delete Object.prototype; // 报错
6. 重名错误

6.1 对象不能有重名的属性

  • 正常情况下重名,后一个的值会覆盖前一个的值。但严格模式不允许。
"use strict";

var o = {
  p: 1,
  p: 2
};            //语法错误

6.1 函数不能有重名的参数

  • 正常模式下,如果函数有多个重名参数,可以用arguments[i]读取。严格模式下,这属于语法错误。
"use strict"
function fun(a,a,b){   //语法错误
    
}
7. 禁止八进制
  • ECMAScript并不包含八进制语法, 但所有的浏览器都支持这种以零(0)开头的八进制语法: 0644 === 420 还有 "\045" === "%".在ECMAScript 6中支持为一个数字加"0o"的前缀来表示八进制数.
  • 严格模式不支持八进制
var a = 0o10    // ES6支持八进制

"use strict"
var sum = 015 + // 语法错误
          100;
8. arguments对象的限制
  • arguments是函数的参数对象,严格模式对其进行了限制。

8.1 不允许对arguments对象赋值

"use strict";

arguments++; // 语法错误
var obj = { set p(arguments) { } }; // 语法错误
try { } catch (arguments) { } // 语法错误
function arguments() { } // 语法错误
var f = new Function("arguments", "'use strict'; return 17;"); // 语法错误

8.2 arguments不再追踪参数的变化

function f(a) {
  a = 2;
  return [a, arguments[0]];
}
f(1); // 正常模式为[2,2]

function f(a) {
  "use strict";
  a = 2;
  return [a, arguments[0]];
}
f(1); // 严格模式为[2,1]

8.3 禁止使用arguments.callee

  • 正常模式下,arguments.callee 指向当前正在执行的函数。这个作用很小:直接给执行函数命名就可以了!
  • 此外,arguments.callee 十分不利于优化,例如内联函数,因为 arguments.callee 会依赖对非内联函数的引用。在严格模式下,arguments.callee 是一个不可删除属性,而且赋值和读取时都会抛出异常:
  • 这意味着无法在匿名函数内部调用自身了
"use strict";

var f = function() { return arguments.callee; };
f(); // 抛出类型错误
9. 函数必须声明在顶层
  • 严格模式禁止不在脚本或者函数层面上的函数声明。在浏览器的普通代码中,在所有地方的函数声明都是合法的。
"use strict";
if (true) {
  function f() { } // !!! 语法错误
  f();
}

for (var i = 0; i < 5; i++) {
  function f2() { } // !!! 语法错误
  f2();
}

function baz() { // 合法
  function eit() { } // 同样合法
}
10. 保留字
  • 在严格模式下,不能用以下名作作为变量名或者参数名
  • implements
  • interface
  • let
  • package
  • private
  • public
  • static
  • yield
posted @   Arica-ss  阅读(90)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示