JavaScript严格模式与this、let、const关键词

一、JavaScript严格模式
 
"use strict";定义JavaScript代码应该以“严格模式”执行。"use strict"是JavaScript1.8.5 中的新指令(ECMAScript version 5)。它不算一条语句,而是一段文字表达式,更早版本的 JavaScript 会忽略它。作用是指示JavaScript代码应该以“严格模式”执行。在严格模式中,无法使用未声明的变量。
 
1.声明严格模式
通过在脚本或函数的开头添加 "use strict"; 来声明严格模式。"use strict"指令只能在脚本或函数的开头被识别。
(1)在脚本开头进行声明,拥有全局作用域(脚本中的所有代码均以严格模式来执行)。
(2)在函数中声明严格模式,拥有局部作用域(只有函数中的代码以严格模式执行)。
 
2."use strict";语法
声明严格模式的语法被设计为兼容更早版本的JavaScript。
编译JavaScript程序中的数值文字(比如 4+5)或字符串文字("Bill Gates")不会有负面效果。它只会编译为不存在的变量然后消失。所有"use strict";只会对“理解”其含义的新编译器产生影响。
 
3.为什么使用严格模式?
(1)严格模式使我们更容易编写“安全的” JavaScript。
(2)严格模式把之前可接受的“坏语法”转变为真实的错误。
(3)在普通的JavaScript中,错打变量名会创建新的全局变量。在严格模式中,此举将抛出错误,这样就不可能意外创建全局变量。
(4)在普通JavaScript中,如果向不可写属性赋值,开发者不会得到任何错误反馈。在严格模式中,向不可写的、只能读取的、不存在的属性赋值,或者向不存在的变量或对象赋值,将抛出错误。
 
4.严格模式中不允许的事项
(1)在不声明变量的情况下使用变量,是不允许的
(2)对象也是变量,在不声明对象的情况下使用对象也是不允许的
(3)删除变量(或对象)是不允许的
(4)删除函数是不允许的
(5)重复参数名是不允许的
(6)八进制数值文本是不允许的
(7)转义字符是不允许的
(8)写入只读属性是不允许的
(9)写入只能获取的属性是不允许的
(10)删除不可删除的属性是不允许的
(11)字符串 "eval" 不可用作变量
(12)字符串 "arguments" 不可用作变量
(13)with语句是不允许的
(14)处于安全考虑,不允许eval()在其被调用的作用域中创建变量
(15)在类似f()的函数调用中,this 的值是全局对象。在严格模式中,现在它成为了undefined
(16)严格模式中不允许使用为未来预留的关键词。它们是:implements、interface、let、package、private、protected、public、static、yield
 
二、JavaScript this关键词
 
JavaScript this关键词指的是它所属的对象。它拥有不同的值,具体取决于它的使用位置。
在方法中,this指的是所有者对象。
单独的情况下,this指的是全局对象。
在函数中,this指的是全局对象。
在函数中,严格模式下,this是undefined。
在事件中,this指的是接收事件的元素。
像call()和apply()这样的方法可以将this引用到任何对象。
 
三、JavaScript Let关键词
 
ES2015引入了两个重要的JavaScript新关键词let和const。这两个关键字在JavaScript中提供了块作用域(Block Scope)变量(和常量)。在ES2015之前,JavaScript只有两种类型的作用域:全局作用域和函数作用域。
 
1.全局作用域、局部作用域
全局(在函数之外)声明的变量拥有全局作用域,可以在JavaScript程序中的任何位置访问。局部(函数内)声明的变量拥有函数作用域,局部变量只能在它们被声明的函数内访问。
(1)函数作用域
在函数内声明变量时,使用var和let很相似。它们都有函数作用域。
function myFunction() {
  var carName = "porsche";   // 函数作用域
}
function myFunction() {
  let carName = "porsche";   // 函数作用域
}
(2)全局作用域
如果在块外声明,那么var和let也很相似。它们都拥有全局作用域:
var x = 10;       // 全局作用域
let y = 6;       // 全局作用域
 
2.JavaScript块作用域
(1)首次声明变量
①通过var关键词声明的变量没有块作用域。在块{}内声明的变量可以从块之外进行访问。
  var x = 10; 
}
// 此处可以使用 x
在ES2015之前,JavaScript是没有块作用域的。
②使用let关键词声明拥有块作用域的变量,在块{}内声明的变量无法从块外访问。
  let x = 10;
}
// 此处不可以使用 x
 
(2)重新声明变量
①使用var关键字重新声明变量会带来问题,在块中重新声明变量也将重新声明块外的变量。
var x = 10;
// 此处 x 为 10
  var x = 6;
  // 此处 x 为 6
}
// 此处 x 为 6
②使用let关键字重新声明变量可以解决这个问题。在块中重新声明变量不会重新声明块外的变量。
var x = 10;
// 此处 x 为 10
  let x = 6;
  // 此处 x 为 6
}
// 此处 x 为 10
 
3.循环作用域
(1)在循环中使用var:
var i = 7;
for (var i = 0; i < 10; i++) {
  // 一些语句
}
// 此处,i 为 10
(2)在循环中使用let
let i = 7;
for (let i = 0; i < 10; i++) {
  // 一些语句
}
// 此处 i 为 7
在第一个例子中,在循环中使用的变量使用var重新声明了循环之外的变量。
在第二个例子中,在循环中使用的变量使用let并没有重新声明循环外的变量。
如果在循环中用let声明了变量i,那么只有在循环内,变量i才是可见的。
 
4.HTML中的全局变量
(1)使用JavaScript的情况下,全局作用域是JavaScript环境。在HTML中,全局作用域是window对象。通过var关键词定义的全局变量属于window对象:
var carName = "porsche";
// 此处的代码可使用 window.carName
 
(2)通过let关键词定义的全局变量不属于window对象:
let carName = "porsche";
// 此处的代码不可使用 window.carName
 
(3)重新声明:允许在程序的任何位置使用var重新声明JavaScript变量:
var x = 10;
// 现在,x 为 10
var x = 6;
// 现在,x 为 6
 
①在相同的作用域,或在相同的块中,通过let重新声明一个var变量是不允许的:
var x = 10;       // 允许
let x = 6;       // 不允许
{
  var x = 10;   // 允许
  let x = 6;   // 不允许
}
②在相同的作用域,或在相同的块中,通过let重新声明一个let变量是不允许的:
实例
let x = 10;       // 允许
let x = 6;       // 不允许
{
  let x = 10;   // 允许
  let x = 6;   // 不允许
}
③在相同的作用域,或在相同的块中,通过var重新声明一个let变量是不允许的:
let x = 10;       // 允许
var x = 6;       // 不允许
{
  let x = 10;   // 允许
  var x = 6;   // 不允许
}
④在不同的作用域或块中,通过let重新声明变量是允许的:
let x = 6;       // 允许
{
  let x = 7;   // 允许
}
{
  let x = 8;   // 允许
}
通过var声明的变量会提升到顶端;通过let定义的变量不会被提升到顶端。
 
四、JavaScript Const
 
ES2015引入了两个重要的JavaScript 新关键词:let和const。通过const定义的变量与let变量类似,但不能重新赋值:
const PI = 3.141592653589793;
PI = 3.14;      // 会出错
PI = PI + 10;   // 也会出错
 
1.块作用域
在块作用域内使用const声明的变量与let变量相似。在本例中,x在块中声明,不同于在块之外声明的x:
var x = 10;
// 此处,x 为 10
  const x = 6;
  // 此处,x 为 6
}
// 此处,x 为 10
 
2.在声明时赋值
JavaScript const变量必须在声明时赋值:const PI = 3.14159265359;
关键字const有一定的误导性。它没有定义常量值。它定义了对值的常量引用。因此,不能更改常量原始值,但可以更改常量对象的属性。
(1)案例1:
①如果将一个原始值赋给常量,就不能改变原始值:
const PI = 3.141592653589793;
PI = 3.14;      // 会出错
PI = PI + 10;   // 也会出错
②可以更改常量对象的属性:
// 您可以创建 const 对象:
const car = {type:"porsche", model:"911", color:"Black"};
// 您可以更改属性:
car.color = "White";
// 您可以添加属性:
car.owner = "Bill";
③但是您无法重新为常量对象赋值:
const car = {type:"porsche", model:"911", color:"Black"};
car = {type:"Volvo", model:"XC60", color:"White"};    // ERROR
 
(2)案例2:
①可以更改常量数组的元素:
// 您可以创建常量数组:
const cars = ["Audi", "BMW", "porsche"];
// 您可以更改元素:
cars[0] = "Honda";
// 您可以添加元素:
cars.push("Volvo");
②但是无法重新为常量数组赋值:
const cars = ["Audi", "BMW", "porsche"];
cars = ["Honda", "Toyota", "Volvo"];    // ERROR
 
3.重新声明
①在程序中的任何位置都允许重新声明JavaScriptvar变量:
var x = 2;    //  允许
var x = 3;    //  允许
x = 4;        //  允许
②在同一作用域或块中,不允许将已有的var或let变量重新声明或重新赋值给const:
var x = 2;         // 允许
const x = 2;       // 不允许
{
  let x = 2;     // 允许
  const x = 2;   // 不允许
}
③在同一作用域或块中,为已有的const变量重新声明或赋值是不允许的:
const x = 2;       // 允许
const x = 3;       // 不允许
x = 3;             // 不允许
var x = 3;         // 不允许
let x = 3;         // 不允许
{
  const x = 2;   // 允许
  const x = 3;   // 不允许
  x = 3;         // 不允许
  var x = 3;     // 不允许
  let x = 3;     // 不允许
}
④在另外的作用域或块中重新声明const是允许的:
const x = 2;       // 允许
{
  const x = 3;   // 允许
}
{
  const x = 4;   // 允许
}
通过var定义的变量会被提升到顶端。通过const定义的变量不会被提升到顶端。