严格模式 Strict Mode

  • 严格模式 Strict Mode
    • 严格模式的支持
    • 调用严格模式
      • 脚本内调用严格模式
      • 函数体内调用严格模式
      • 自带严格模式代码
        • ES6模块
        • 任何类函数
        • eval函数
        • Function, Generator, AsyncFunction, and AsyncGenerator的构造函数中带有`'use strict'`
      • 特例!块级作用域内使用严格模式无效
    • 严格模式中的变化
      • 将失误转化成异常
        • 未定义的变量
        • 属性改值
          • 不可变属性
          • 给只有 getter 的对象赋值
          • 为不可扩展的对象增加新的属性
        • 删除
          • 一元表达式
          • 不可配置属性
        • 重复参数名称
        • 八进制
        • 原始类型的修改
      • 简化变量的使用
        • 禁用 `with`
        • `eval` 中变量不提升
    • 让eval和arguments变的简单
      • 不能,至少不可以……
      • `arguments` 不再追踪参数的变化
      • `arguments` 无法调用 `callee`
    • "安全的" JavaScript
      • `this` 不再指向全局环境
      • 禁止在函数内遍历JS栈
    • 为未来的ECMAScript版本铺平道路
      • 关键字和保留词
    • 参考
    • ES2020中严格模式文本参考

严格模式 Strict Mode

基本上来说ES2020上的内容全都挖出来了,MDN上没有的也补充的差不多了(泪目( Ĭ ^ Ĭ ))

有一些MDN上写的但是已经修正过的内容没有加上去,例如说一些保留字,例如说对象中现在已经可以接受多个相同名字的属性了。

一些我没有办法复刻的属性也没放进去……例如说 Paving the way for future ECMAScript versions 的第二段,那一段我在node里面跑了下没报错,放到html的script里面跑了下还是没有,就没有加进来了。

arguments.caller 这个问题应该是已经被修正过了,现在 arguments.caller 没有任何的反应,不会报错,在非严格模式下,也不会返回任何值。但是,函数体.caller 依旧还是会报错的,这个也在正文里面列了出来。

严格模式的特性如下:

  • 随意的JS书写方式被禁用了
  • 它的语义和正常/随意的JS代码不同
  • 支持严格模式的浏览器在运行严格模式下的代码,与不支持严格模式的浏览器相比,会有不同的效果
  • 因此在没有做性能支持的测试之前,不要依靠严格模式

本质上理解,严格模式的优势如下:

  • 原本的 静默错误 会被直接 抛出
  • 严格模式修复了一些JS的历史遗留缺陷,对代码进行了优化,所以程序 有时候 能够运行的更快
  • 通过禁用 保留字 ,当前的代码在未来不会报错
  • 禁用了一些 搞人脑筋 的功能
  • 代码更加安全

严格模式的支持

浏览器 最低支持版本
ie 10
edge 12
firefox 4
chrome 13
safari 6
opera 12.1

基本上来说,主流浏览器都支持严格模式很久了,当下流行的浏览器里面,严格模式的支持率有95%以上。

唯一要注意的是Safari,似乎只有老版的Safari部分支持严格模式——当然,5-5.1 这个部分支持的版本,目前的全球占有率只有0.12%。

调用严格模式

严格模式可以在 整个脚本内函数体内 使用,除此之外ES6新增的模块内默认自带严格模式。但是在ES6新增的块级作用域,即用 {} 包住的函数体内无效。

目前标准罗列了六个,下面都包含了:

An ECMAScript Script syntactic unit may be processed using either unrestricted or strict mode syntax and semantics. Code is interpreted as strict mode code in the following situations:

  • Global code is strict mode code if it begins with a Directive Prologue that contains a Use Strict Directive.
  • Module code is always strict mode code.
    All parts of a ClassDeclaration or a ClassExpression are strict mode code.
  • Eval code is strict mode code if it begins with a Directive Prologue that contains a Use Strict Directive or if the call to eval is a direct eval that is contained in strict mode code.
  • Function code is strict mode code if the associated FunctionDeclaration, FunctionExpression, GeneratorDeclaration, GeneratorExpression, AsyncFunctionDeclaration, AsyncFunctionExpression, AsyncGeneratorDeclaration, AsyncGeneratorExpression, MethodDefinition, ArrowFunction, or AsyncArrowFunction is contained in strict mode code or if the code that produces the value of the function’s [[ECMAScriptCode]] internal slot begins with a Directive Prologue that contains a Use Strict Directive.
  • Function code that is supplied as the arguments to the built-in Function, Generator, AsyncFunction, and AsyncGenerator constructors is strict mode code if the last argument is a String that when processed is a FunctionBody that begins with a Directive Prologue that contains a Use Strict Directive.

脚本内调用严格模式

'use strict';
// 会报 a is not defined 的错
a = 'Hello World';

这是不推荐的!

根据官方文档说,某大型网站亚马逊被脚本内调用'use strict';坑了,原因是因为合并都是严格模式的脚本与合并都是非严格模式的脚本不会有问题,但是混合使用就会导致问题。合并代码时,如果 严格模式.concat(非严格模式) ,那么因为头部存在 'use strict'; ,那整个脚本文件都是需要遵循严格模式的。如果用 非严格模式.concat(严格模式) ,那整个脚本文件都是需要遵循非严格模式的。

函数体内调用严格模式

在函数的开始就加入 'use strict';,那么里面包含的代码都是严格模式的。

function strict() {'use strict';// 会报 b is not defined 的错b = 'hello world';function alsoStrict() {}
}
strict();

但是,如果在函数上方在加一行代码,那么就是另外的效果了。

function strict() {a = 'hello';'use strict';b = 'hello world';// 控制台上会输出 hello hello worldconsole.log(a, b);
}
strict();

这就绕回上面 脚本内调用严格模式尾部,合并会产生的问题。

严格模式.concat(非严格模式) ,那么下面的函数都应该遵循严格模式,如果写的不注意就会报错(没有报错更难排查……);而 非严格模式.concat(严格模式) ,就像上面的这个例子一样,'use strict'; 就不会产生任何的效果(但是因为用了 'use strict'; ,觉得会生效)。

尽管官方也说可以用 函数体 将代码包起来,并且进行返回,但是无疑这样就会多了一层数据。

自带严格模式代码

除了 ES6模块 模块之外,其他的都是刚刚从 262.ecma 刨出来的……我看的眼睛都快瞎了,他们怎么这么能写……

ES6模块

模块自带严格模式这个,中文页面还没有……所以怪不得说文档要看英文呢……

当时如果模块就出来了,并且亚麻用上了,大概就不会有上面那些乱七八糟的问题了吧(笑)

function strict() {// 这是ES6模块,所以自带严格模式
}
export default strict;

任何类函数

// 自带严格模式
class Example {constructor() {}
}

eval函数

具体内容在 简化变量的使用 以及 让eval和arguments变的简单 中。

Function, Generator, AsyncFunction, and AsyncGenerator的构造函数中带有'use strict'

原文如下:

Function code that is supplied as the arguments to the built-in Function, Generator, AsyncFunction, and AsyncGenerator constructors is strict mode code if the last argument is a String that when processed is a FunctionBody that begins with a Directive Prologue that contains a Use Strict Directive.

翻译的大概意思就是,提供给Function, Generator, AsyncFunction, 和 AsyncGenerator 的构造函数的 最后一个参数是 作为函数体编译时,开头包含'use strict'; 的字符串。

看代码会比较清晰:

// 可运行
new Function('a', 'b', 'return a + b;');
// undefined:1
// (function anonymous(x,y,return x * y;
// ... 一串报错stack
new Function('x', 'y', 'return x * y;', 'use strict;');// 下面代码也会引发同样的报错信息
new Function('x', 'y', 'return x * y;', 'strict');function strict() {'use strict';console.log('Hello WOrld');
}

这个知识点真的太偏了……我找了好久才摸到mdn那里……

特例!块级作用域内使用严格模式无效

{'use strict';a = 'hello world';// 控制台上正常输出 hello worldconsole.log(a);
}

严格模式中的变化

将失误转化成异常

未定义的变量

会直接报错,这点在上面的几个例子里面也看到了。

这点可以减少很多的人类错误(human errors)。

'use strict';
// mistypeVariable is not defined
mistypeVariable = 17;

属性改值

全局变量的修改会报错似乎已经没有了,像对 undefined, Infinity 赋值都不会有报错。

不可变属性

Object.defineProperty(),默认用此函数生成的值是不可变的—— 也就是 [[Writable]]: false

'use strict';
var obj1 = {};
Object.defineProperty(obj1, 'x', { value: 42, writable: false });
//TypeError: Cannot assign to read only property 'x' of object '#<Object>'
obj1.x = 9;
给只有 getter 的对象赋值

也就是 [[Set]]: undefined

'use strict';
var obj2 = {get x() {return 17;},
};
// TypeError: Cannot set property x of #<Object> which has only a getter
obj2.x = 5;
为不可扩展的对象增加新的属性

也就是 [[Extensible]]:false

'use strict';
var fixed = {};
Object.preventExtensions(fixed);
// TypeError: Cannot add property newProp, object is not extensible
fixed.newProp = 'ohai'; // throws a TypeError

删除

一元表达式

delete操作的对象如果是一个变量、函数参数或者函数名的引用的话,就会抛出 SyntaxError

'use strict';
// 变量
var test = 1;
// SyntaxError: Delete of an unqualified identifier in strict mode.
delete test;// 函数参数
var test2 = 1;
function tryDelete(a) {// SyntaxError: Delete of an unqualified identifier in strict mode.delete a;
}
tryDelete(test2);// 函数名
function deleteFunc() {}
delete deleteFunc;
不可配置属性

也就是 [[Configurable]]: false

'use strict';
// TypeError: Cannot delete property 'prototype' of function Object() { [native code] }
delete Object.prototype;

重复参数名称

'use strict';
// SyntaxError: Duplicate parameter name not allowed in this context
function sum(a, a, c) {return a + a + c;
}
sum(1, 2, 3);

八进制

被禁用的包括以下两种格式:

  • ‘\07’; LegacyOctalEscapeSequence
  • 015, NonOctalDecimalIntegerLiteral
'use strict';
// SyntaxError: Octal escape sequences are not allowed in strict mode.
var octVal1 = '\09';
// SyntaxError: Octal literals are not allowed in strict mode.
var octVal2 = 010;

可以接受的八进制为以下语法:

'use strict';
// 8
var a = 0o10;

原始类型的修改

'use strict';
false.true = '';         // TypeError
(14).sailing = 'home';   // TypeError
'with'.you = 'far away'; // TypeError

简化变量的使用

禁用 with

出于优化的考虑,严格模式禁用了 with 语法糖,因为 with 语句内部每个变量都被当做局部变量,然后在运行的时候去找对应的值。

'use strict';
var x = 17;
// SyntaxError: Strict mode code may not include a with statement
with (obj) {// If this weren't strict mode, would this be var x, or// would it instead be obj.x?  It's impossible in general// to say without running the code, so the name can't be// optimized.x;
}

eval 中变量不提升

var x = 17;
// x 的作用域提升了
var evalX = eval(" var x = 42; x;");
console.log(x === 17);  // false
console.log(evalX === 42);  // true

在非严格模式下,一旦 evalX 被调用,全局变量中的 x 值也变了:

在严格模式下就不会如此:

var x = 17;
// x 的作用域不会提升
var evalX = eval("'use strict'; var x = 42; x;");
console.log(x === 17);  // true
console.log(evalX === 42);  // true


注,只要严格模式下的 eval(...) 表达式 被调用,那么其代码就会被当作在严格模式下执行,其他函数中的严格模式声明并不是必须的。

function strict1(str) {"use strict";return eval(str); // 无论什么情况,str中的代码在严格模式下运行
}

让eval和arguments变的简单

不能,至少不可以……

严格模式下,argumentseval 不能

  • 出现在 赋值操作符 的左边
  • 不能与 更新表达式 (UpdateExpression) 连用
    更新表达式 包括:自增自减的加号/减号前置后置,即:++val;, --val, val++, val--
  • 不能作为声明 (BindingIdentifier)
    这个基本就把 变量名、参数、形参 都砍了吧……从 ++eval; 之后的代码都属于这个范畴了。
'use strict';
// 以下代码都会报错
// SyntaxError: Unexpected eval or arguments in strict mode
eval = 17;
arguments++;
++eval;
var obj = { set p(arguments) { } };
var eval;
try { } catch (arguments) { }
function x(eval) { }
function arguments() { }
var y = function eval() { };
var f = new Function('arguments', "'use strict'; return 17;");

arguments 不再追踪参数的变化

不使用 'use strict'; 的情况下,传入 arguments 的参数变化时, arguments 会追踪其变化

function f(a) {// a 是 arguments 里第一个参数// 值变化后 arguments里的值也从 17 更新为42a = 42;return [a, arguments[0]];
}
// pair的值为 [42, 42]
var pair = f(17);
console.log(pair[0] === 42); // true
console.log(pair[1] === 17); // false

开启 'use strict'; 后,arguments 不再追踪参数的变化

function f(a) {'use strict';// a 仍然是 arguments 里第一个参数// 但是值变化后 arguments 将不会追踪参数的变化// 依旧会维持原本传进来的值,也就是 42a = 42;return [a, arguments[0]];
}
var pair = f(17);
console.log(pair[0] === 42); // true
console.log(pair[1] === 17); // true

arguments 无法调用 callee

出于以下两个考虑:

  • 没用,argumentscallee 就是当前函数——直接调用当前函数不香吗?
  • 优化问题,这种内联函数,GC应该没法判定引用的数量为0然后删除吧。
'use strict';
// TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
function test() {test.arguments.caller;
}
test();

“安全的” JavaScript

用严格模式可以减少信息的暴露。

this 不再指向全局环境

非严格模式下,this 会指向全局变量。

function getThis() {return this;
}
console.assert(getThis() === window);

严格模式下,this 会指向 undefined

function getThis() {'use strict';return this;
}
console.assert(getThis() === undefined);
// Assertion failed
console.assert(getThis() === window);

在严格模式下,this 不用被自动转换成对象能够提升性能;也不会在浏览器中暴露全局对象,减少安全隐患。

禁止在函数内遍历JS栈

在函数体内调用一些常见的ES扩展可以获得函数的调用信息,如 caller (函数本体), arguments (参数)。

function restricted() {'use strict';// TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to themrestricted.caller;restricted.arguments;
}restricted();

为未来的ECMAScript版本铺平道路

关键字和保留词

关键字与保留词,ES2020版 里根据 ES2020 的定义整理了一下。

参考

  • MDN官方文档的Strict mode
  • Can I Use上strict mode的支持率
  • ECMAScript® 2020 Language Specification
  • MDN官方文档的Function

ES2020中严格模式文本参考

MDN的文档和ECMAScript® 2020 Language Specification两个来回参考的,不过ES2020看的头真的快炸了……

The Strict Mode of ECMAScript

The strict mode restriction and exceptions

  • implements, interface, let, package, private, protected, public, static, and yield are reserved words within strict mode code. (11.6.2).
  • A conforming implementation, when processing strict mode code, must not extend, as described in B.1.1, the syntax of NumericLiteral to include LegacyOctalIntegerLiteral, nor extend the syntax of DecimalIntegerLiteral to include NonOctalDecimalIntegerLiteral.
  • A conforming implementation, when processing strict mode code, may not extend the syntax of EscapeSequence to include LegacyOctalEscapeSequence as described in B.1.2.
    Assignment to an undeclared identifier or otherwise unresolvable reference does not create a property in the global object. When a simple assignment occurs within strict mode code, its LeftHandSideExpression must not evaluate to an unresolvable Reference. If it does a ReferenceError exception is thrown (6.2.4.9). The LeftHandSideExpression also may not be a reference to a data property with the attribute value { [[Writable]]: false }, to an accessor property with the attribute value { [[Set]]: undefined }, nor to a non-existent property of an object whose [[Extensible]] internal slot has the value false. In these cases a TypeError exception is thrown (12.15).
  • An IdentifierReference with the StringValue “eval” or “arguments” may not appear as the LeftHandSideExpression of an Assignment operator (12.15) or of an UpdateExpression (12.4) or as the UnaryExpression operated upon by a Prefix Increment (12.4.6) or a Prefix Decrement (12.4.7) operator.
  • Arguments objects for strict functions define a non-configurable accessor property “callee” which throws a TypeError exception on access (9.4.4.6).
  • Arguments objects for strict functions do not dynamically share their array-indexed property values with the corresponding formal parameter bindings of their functions. (9.4.4).
  • For strict functions, if an arguments object is created the binding of the local identifier arguments to the arguments object is immutable and hence may not be the target of an assignment expression. (9.2.10).
  • It is a SyntaxError if the StringValue of a BindingIdentifier is “eval” or “arguments” within strict mode code (12.1.1).
    Strict mode eval code cannot instantiate variables or functions in the variable environment of the caller to eval. Instead, a new variable environment is created and that environment is used for declaration binding instantiation for the eval code (18.2.1).
  • If this is evaluated within strict mode code, then the this value is not coerced to an object. A this value of undefined or null is not converted to the global object and primitive values are not converted to wrapper objects. The this value passed via a function call (including calls made using Function.prototype.apply and Function.prototype.call) do not coerce the passed this value to an object (9.2.1.2, 19.2.3.1, 19.2.3.3).
  • When a delete operator occurs within strict mode code, a SyntaxError is thrown if its UnaryExpression is a direct reference to a variable, function argument, or function name (12.5.3.1).
  • When a delete operator occurs within strict mode code, a TypeError is thrown if the property to be deleted has the attribute { [[Configurable]]: false } (12.5.3.2).
    Strict mode code may not include a WithStatement. The occurrence of a WithStatement in such a context is a SyntaxError (13.11.1).
  • It is a SyntaxError if a CatchParameter occurs within strict mode code and BoundNames of CatchParameter contains either eval or arguments (13.15.1).
    It is a SyntaxError if the same BindingIdentifier appears more than once in the FormalParameters of a strict function. An attempt to create such a function using a Function, Generator, or AsyncFunction constructor is a SyntaxError (14.1.2, 19.2.1.1.1).
  • An implementation may not extend, beyond that defined in this specification, the meanings within strict functions of properties named “caller” or “arguments” of function instances.

严格模式 Strict Mode,与ES2020同步相关推荐

  1. mysql同步row模式_ROW模式的SQL无法正常同步的问题总结

    ROW模式的SQL无法正常同步的问题总结 最近处理数据库问题时遇到一起mysql从机ROW模式的SQL无法正常同步的问题,今天刚好有时间,将整个过程总结一下,方便后面的同学学习! 一.问题起因 最近有 ...

  2. mysql strict_关于mysql 严格模式 Strict Mode的说明讲解

    1.开启与关闭Strict Mode方法 找到mysql安装目录下的my.cnf(windows系统则是my.ini)文件 在sql_mode中加入STRICT_TRANS_TABLES则表示开启严格 ...

  3. mysql 主主模式优缺点_mysql主主同步模式

    主192.168.56.20 和 从都新建数据库db1 db2 db3(如果数据库在用,需要上锁后手动从主备份,然后在从恢复) mysql> create database db1; Query ...

  4. mysql strict_mysql 严格模式 Strict Mode说明(转)

    1.开启与关闭Strict Mode方法 找到mysql安装文件夹下的my.cnf(windows系统则是my.ini)文件 在sql_mode中增加STRICT_TRANS_TABLES则表示开启严 ...

  5. MySQL严格模式Strict Mode说明

    何为MySQL的严格模式,简单来说就是MySQL自身对数据进行严格的校验(格式.长度.类型等),比如一个整型字段我们写入一个字符串类型的数据,在非严格模式下MySQL不会报错,同样如果定义了char或 ...

  6. mysql 严格模式 Strict Mode说明

    1.开启与关闭Strict Mode方法 找到mysql安装目录下的my.cnf(windows系统则是my.ini)文件 在sql_mode中加入STRICT_TRANS_TABLES则表示开启严格 ...

  7. redis踩坑:redis哨兵开启了保护模式导致主从切换不同步

    故障表现 哨兵只存在两个的时候,当哨兵模式的redis主节点挂掉以后,业务组件不能切换到新主节点 故障原因 redis哨兵依旧认为旧主为主节点,没有触发failover 故障原因定位 哨兵集群部署方式 ...

  8. 分布式图处理系统同步异步执行模式

    分布式图处理系统(GraphLab.PowerGraph以及同步BSP模型的Pregel)主要有两种执行模式.一种是同步执行模式,还有一种是异步执行模式.同步模式即相邻两步迭代之间存在同步控制,所有任 ...

  9. Linux网络编程 | 并发模式:半同步/半异步模式、领导者/追随者模式

    文章目录 同步与异步 半同步/半异步模式 变体:半同步/半反应堆模式 改进:更高效的半同步/半异步模式 领导者/追随者模式 组件 :句柄集.线程集.事件处理器 并发模式是指I/O处理单元和多个逻辑单元 ...

  10. Linux服务器 | 服务器模型与三个模块、两种并发模式:半同步/半异步、领导者/追随者

    文章目录 两种服务器模型及三个模块 C/S模型 P2P模型 I/O处理单元.逻辑单元.存储单元 并发 同步与异步 半同步/半异步模式 变体:半同步/半反应堆模式 改进:高效的半同步/半异步模式 领导者 ...

最新文章

  1. 朱晔的互联网架构实践心得S1E2:屡试不爽的架构三马车
  2. c++ const 转 非const
  3. 【转】 Android - LayoutInflate用法
  4. java.util.List学习笔记
  5. IDEA 学习笔记之 安装和基本配置
  6. jdbc存储过程mysql_JDBC对MySQL数据库存储过程的调用
  7. 【Shell】for循环
  8. matlab2c使用c++实现matlab函数系列教程-max函数
  9. Java获取字符串的MD5值和根据邮箱获取Gravatar头像
  10. windows下微信多开
  11. 我和腾讯不得不说的故事
  12. arcgis 10.8 for win10安装教程
  13. 豪饮舍得酒,郭广昌刀口舔血
  14. 怎么成为一个优秀的面试官
  15. 区块链在个性化推荐系统中的应用研究综述
  16. uboot2021.10-nandflash-3.initr_nand
  17. 递归全排列 python实现
  18. informatica 许可_informatica 常见问题及解决方案
  19. 人散后,一钩新月天如水----丰子恺的漫画人生
  20. 大数据可视化多个模板案例(前端)

热门文章

  1. 为Windows Live Writer写一个简单的插件
  2. js外链跳转_给网站外链进行重定向跳转
  3. 华科计算机硕士毕业论文,华中科技大学硕士毕业论文要求_华中科技大学2020年硕士招生简章_华中科技大学研究生院...
  4. 最新win10重装系统官方纯净版——2022家庭版多图详细
  5. php的aes加密解密算法,PHP实现的简单AES加密解密算法实例
  6. 名词用作动词举例_名词活用作动词
  7. java自学-常见的API(String、ArryList)
  8. 拒绝访问病毒解决方法
  9. java 手机端开发步骤_移动端页面开发流程
  10. 零基础入门:基于开源WebRTC,从0到1实现实时音视频聊天功能