JS基础知识js相关基础及规范es6

JS中严格格式的使用--'use strict'

2018-04-25  本文已影响1人  安静的牛蛙

一:简单介绍

严格模式是在ES5中引入的,它可以视为JS的一个子集,在严格模式下,限制了JS的标准使用下一些行为。

但是需要注意的是:不支持严格模式的浏览器将会执行与支持严格模式的浏览器不同行为的严格模式代码。所以不要依靠严格模式,而是应当加强自己代码的鲁棒性

二:使用方法

严格模式可以应用于整个脚本或单个函数中。其中的脚本不仅仅包括了单个文件,还包括了dom中事件处理,eval(),Function(),以及window.setTimeOut()中的字符串

1:为某个脚本使用严格模式

需要在所有代码前,声明

"use strict";

PS:注意,必须为"use strict";或者'use strict';,且必须带分号结束。
但这种使用方式在存在代码引用和合并的时候,会无法正常激活严格模式。因为,当一个声明了严格模式的脚本,被引入合并到一个新的未使用严格模式的脚本中的时候,由于声明并没有在所有代码前使用,从而导致严格模式声明失败。
为了保证严格模式的正常使用,一般的做法是用一个外部匿名函数将使用严格模式的脚本封装,然后执行。代码一般如下

(function () {
  'use strict';
  /**** 原有脚本代码 ****/
})()

但需要注意的是,这种方法,会将原有的代码封装到一个全局环境的函数中,原有脚本代码的作用域由全局变为了函数内部作用域,因此在使用的时候,务必注意。
PS:一个变通的方法是,将内部脚本需要全局的变量,直接声明为全局变量,即不用var或者let定义,比如a,不适用var a;或者let a;,而是直接 a = xxx

2:单函数使用严格模式

单函数使用严格模式,只需要在函数代码开头声明

"use strict";

即可

三:严格模式带来的具体差异

1:消除了静默错误,改为抛出错误
"use strict";
v = 1; // 报错,v未声明
for(i = 0; i < 2; i++) { // 报错,i未声明
}
function sum(a, a, c){ // !!! 语法错误
  "use strict";
  return a + a + c; // 代码运行到这里会出错
}
"use strict";
var o = { p: 1, p: 2 }; // !!! 语法错误
var a = 015; // 错误
var a = 0o10; // ES6: 八进制
"use strict";
NaN = 1; // 不可复制的全局变量
var o = {
  get v() {
    return this.v
  }
};
Object.defineProperty(o, "v", { value: 1, writable: false }); // 不可写的属性
o.v = 2; // 报错

var o1 = {
  get v() { return 1; }  // 只读属性
};
o1.v = 2; // 报错

// 给不可扩展对象的新属性赋值
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // 抛出TypeError错误
"use strict";
delete Object.prototype; // 抛出TypeError错误
2:修复了JS的随意性,提升了优化能力

在标准模式下,JS的随意性,或者灵活性,是的很多变量,只有在运行时才能确切知道具体指向,这就使得变量名到内存的映射也只有到运行时才能完成。严格模式修复了大部分这种行为,使得所有的变量名在编译的时候,就已经可以一起进行优化,从而提升了执行速度。

"use strict";
var x = 17;
with (obj) // !!! 语法错误
{
  // 如果没有开启严格模式,with中的这个x会指向with上面的那个x,还是obj.x?
  // 如果不运行代码,我们无法知道,因此,这种代码让引擎无法进行优化,速度也就会变慢。
  x;
}
var x = 17;
var evalX = eval("'use strict'; var x = 42; x");
console.log(x === 17); // true  未能引入x,所以还是原来的x,但如果去掉 use strict,那么为false
console.log(evalX === 42); // true 

但在严格格式下,eval不在为上层作用域引入新的局部变量和全局变量。所有的eval中出现的变量,只在eval的字符串代码块中有效。
另外如果判定eval是否为严格模式,也存在各种复杂的情况。
-- 如果直接调用eval(...)代码的代码块显式使用了严格格式,那么eval()也执行严格格式。如下面代码

function test () {
  'use strict';
  eval(...)  // 无论eval中的字符串是否包含 use strict; 都会进入严格格式
}

-- 如果直接调用eval的代码块未使用严格模式,而是更上级别的代码块使用了严格模式,则eval代码按照标准模式执行,如下面代码

function test () {
  'use strict';
  f(){} // 无论eval中的字符串是否包含 use strict; 都会进入严格格式
}

-- 如果eval(...)的字符串中显式使用了'use strict'; 则必然进入严格模式

"use strict";
var x;
delete x; // !!! 语法错误
eval("var y; delete y;"); // !!! 语法错误
3:让eval和arguments变的更加简单
"use strict";
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的复制,指的是arguments这个变量,而不是指的其中的元素,比如

function test (a, b) {
  'use strict';
  a = 42;
  arguments[1] = 17;  // 可以通过语法检测,但并不会修改b的值
}

依然是允许的,也可以通过语法检测。

4:更加安全的JS
function test () {
  console.log(typeof this);
  return this;
}
var t = new test()
console.log(t)  // this 为新建的对象

-使用call,apply,bind传入this,如果传入的是数字,字符串,布尔值等,那么就会将这些基本数据的this转换为Number,String,Boolean对象类型。如果传入的是null和undefined,则为全局变量window,默认调用下,this也为window

function fun() {
  console.log(typeof this)
  return this; 
}
console.log(fun());  // window  需要注意,单独的此类 fun(),等价于window.fun()。所以为window
console.log(fun.call(2)); // Number
console.log(fun.call('2018-01-01 10:00:00')); // String
console.log(fun.apply(null)); // window
console.log(fun.call(undefined)); // window
console.log(fun.bind(true)()); // Boolean

上面的这种模式既增加了转换为对象的对象的开销,又因为将全局对象window暴露出来造成安全性问题。
因此在严格模式下指定的this不再被封装为对象,而且如果没有指定this的话它值是undefined,上面的结果如下:

'use strict';
function fun() {
  console.log(typeof this)
  return this; 
}
console.log(fun());  // undefined
console.log(fun.call(2)); // 2
console.log(fun.call('2018-01-01 10:00:00')); // '2018-01-01 10:00:00'
console.log(fun.apply(null)); // null
console.log(fun.call(undefined)); // undefined
console.log(fun.bind(true)()); // true
5:对未来的兼容
"use strict";
if (true){
  function f() { } // !!! 语法错误
  f();
}
for (var i = 0; i < 5; i++){
  function f2() { } // !!! 语法错误
  f2();
}
function baz() { // 合法
  function eit() { } // 同样合法
}
上一篇 下一篇

猜你喜欢

热点阅读