JS语言基础

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

目录

语法

关键字与保留字

变量

 var关键字

let声明

暂时性死区

全局变量

for循环中的let声明

条件声明

 const声明


语法


1. 区分大小写
无论是变量、函数名还是操作符都区分大小写。

2. 标识符
所谓标识符就是变量、函数、属性或函数参数的名称。
标识符可以由一或多个下列字符组成第一个字符必须是一个字母、下划线_或美元符号$剩下的其他字符可以是字母、下划线、美元符号或数字。
按照惯例ECMAScript 标识符使用驼峰大小写形式即第一个单词的首字母小写后面每个单词的首字母大写

3. 注释

ECMAScript 采用C 语言风格的注释包括单行注释和块注释。单行注释以两个斜杠字符开头如

// 单行注释

块注释以一个斜杠和一个星号/*开头以它们的反向组合*/结尾如

/* 这是多行
注释 */

4. 严格模式
ECMAScript 5 增加了严格模式strict mode的概念。

严格模式是一种不同的JavaScript 解析和执行模型ECMAScript 3 的一些不规范写法在这种模式下会被处理对于不安全的活动将抛出错误。

要对整个脚本启用严格模式在脚本开头加上这一行
 

"use strict";

任何支持的JavaScript引擎看到它都会切换到严格模式。选择这种语法形式的目的是不破坏ECMAScript 3 语法。也可以单独指定一个函数在严格模式下执行只要把这个预处理指令放到函数体开头即可

function doSomething() {
"use strict";
// 函数体
}

语句

ECMAScript 中的语句以分号结尾。省略分号意味着由解析器确定语句在哪里结尾如下面的例子所示

let sum = a + b // 没有分号也有效但不推荐
let diff = a - b; // 加分号有效推荐

多条语句可以合并到一个C 语言风格的代码块中。代码块由一个左花括号 { 标识开始一个右花括号}标识结束 

if (test) {
test = false;
console.log(test);
}

关键字与保留字


ECMA-262 描述了一组保留的关键字关键字有特殊用途比如表示控制语句的开始和结束或者执行特定的操作。按照规定保留的关键字不能用作标识符或属性名。

规范中也描述了一组未来的保留字同样不能用作标识符或属性名。虽然保留字在语言中没有特定用途但它们是保留给将来做关键字用的。

    break         do             in                typeof
    case          else          instanceof         var
    catch         export        new                void
    class         extends      return              while
    const         finally     super               with
    continue     for           switch          yield
    debugger     function     this
    default      if           throw
    delete       import        try
    始终保留
    enum
    严格模式下保留
    implements   package      public
    interface    protected    static
    let           private
    模块代码中保留
    await

变量

Window 对象描述
Window 对象表示一个浏览器窗口或一个框架。在客户端 JavaScript 中Window 对象是全局对象所有的表达式都在当前的环境中计算。也就是说要引用当前窗口根本不需要特殊的语法可以把那个窗口的属性作为全局变量来使用。例如可以只写 document而不必写 window.document。
同样可以把当前窗口对象的方法当作函数来使用如只写 alert()而不必写 Window.alert()。
除了上面列出的属性和方法Window 对象还实现了核心 JavaScript 所定义的所有全局属性和方法。


变量是程序在内存中申请的一块用来存放数据的空间。即存放数据的一个容器。通过变量名获取数据并修改。变量值是存入变量空间内的值。

ECMAScript 变量是松散类型的意思是变量可以用于保存任何类型的数据。每个变量只不过是一个用于保存任意值的命名占位符。

有3 个关键字可以声明变量var、const 和 let。其中var 在ECMAScript 的所有版本中都可以使用而 const 和 let 只能在ECMAScript 6 及更晚的版本中使用。

 var关键字

var 操作符注意var 是一个关键字后跟变量名即标识符如前所述

这行代码定义了一个名为message 的变量可以用它保存任何类型的值。可以同时定义变量并设置它的值

var message = "hi";

 

var声明作用域

使用var 操作符定义的变量会成为包含它的函数的局部变量。比如使用var在一个函数内部定义一个变量就意味着该变量将在函数退出时被销毁

function test() {
var message = "hi"; // 局部变量
}
test();
console.log(message); // 出错

而在函数内定义变量时省略var 操作符可以创建一个全局变量

function test() {
message = "hi"; // 全局变量
}
test();
console.log(message); // "hi"

去掉之前的var 操作符之后message 就变成了全局变量。只要调用一次函数test()就会定义这个变量并且可以在函数外部访问到。

注意
虽然可以通过省略var 操作符定义全局变量但不推荐这么做。在局部作用域中定义的全局变量很难维护也会造成困惑。这是因为不能一下子断定省略var 是不是有意而为之。在严格模式下如果像这样给未声明的变量赋值则会导致抛出ReferenceError。

如果需要定义多个变量可以在一条语句中用逗号分隔每个变量及可选的初始化

var message = "hi",
	found = false,
	age = 29;

为ECMAScript 是松散类型的所以使用不同数据类型初始化的变量可以用一条语句来声明。插入换行和空格缩进并不是必需的但这样有利于阅读理解。
在严格模式下不能定义名为eval 和arguments 的变量否则会导致语法错误。

用 var 声明的变量的作用域是它当前的执行上下文它可以是嵌套的函数或者对于声明在任何函数外的变量来说是全局。
如果你重新声明一个JavaScript 变量它将不会丢失其值。 当赋值给未声明的变量, 则执行赋值后, 该变量会被隐式地创建为全局变量它将成为全局对象的属性。但在函数内部对已经var声明过的变量赋值操作不会将它变为全局变量。

var声明提升

使用var 时下面的代码不会报错。这是因为使用这个关键字声明的变量会自动提升到函数作用域顶部

function foo() {
console.log(age);
var age = 26;
}
foo(); // undefined
之所以不会报错是因为ECMAScript 运行时把它看成等价于如下代码
function foo() {
var age;
console.log(age);
age = 26;
}
foo(); // undefined

 

这就是所谓的“提升”hoist也就是把所有变量声明都拉到函数作用域的顶部。
用var声明的变量会被提升到其作用域的顶部并使用 undefined 值对其进行初始化。
此外反复多次使用var 声明同一个变量也没有问题

function foo() {
var age = 16;
var age = 26;
var age = 36;
console.log(age);
}
foo(); // 36

let声明

let 跟var 的作用差不多但有着非常重要的区别。
最明显的区别是let 声明的范围是块作用域而var 声明的范围是函数作用域

例子
var声明

if (true) {
var name = 'Matt';
console.log(name); // Matt
}
console.log(name); // Matt

let声明

if (true) {
let age = 26;
console.log(age); // 26
}
console.log(age); // ReferenceError: age 没有定义

age 变量之所以不能在if 块外部被引用是因为它的作用域仅限于该块内部。块作用域是函数作用域的子集因此适用于var 的作用域限制同样也适用于let。

let也不允许同一个块作用域中出现冗余声明。这样会导致报错

var name;
var name;
let age;
let age; // SyntaxError标识符age 已经声明过了

但不在同一个块中时不会报错

let age = 30;
console.log(age); // 30
if (true) {
let age = 26;
console.log(age); // 26
}

对声明冗余报错不会因混用let 和var 而受影响。这两个关键字声明的并不是不同类型的变量它们只是指出变量在相关作用域如何存在。

var name;
let name; // SyntaxError
let age;
var age; // SyntaxError
即声明冗余会报错不同的声明只是表示了它的作用域的不同。

暂时性死区

与var声明的另一个区别是let声明的变量在作用域中不会被提升

// age 不会被提升
console.log(age); // ReferenceErrorage 没有定义
let age = 26;

 

在解析代码时JavaScript 引擎也会注意出现在块后面的let 声明只不过在此之前不能以任何方式来引用未声明的变量。在let声明之前的执行瞬间被称为“暂时性死区”temporal dead zone在此阶段引用任何后面才声明的变量都会抛出ReferenceError。

全局变量

使用let 在全局作用域中声明的变量不会成为window 对象的属性var 声明的变量则会。
Window 对象表示浏览器中打开的窗口。

var name = 'Matt';
console.log(window.name); // 'Matt'
let age = 26;
console.log(window.age); // undefined

不过let 声明仍然是在全局作用域中发生的相应变量会在页面的生命周期内存续。因此为了避免SyntaxError必须确保页面不会重复声明同一个变量。

for循环中的let声明

在let 出现之前for 循环定义的迭代变量会渗透到循环体外部

for (var i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // 5

改成使用let 之后这个问题就消失了因为迭代变量的作用域仅限于for 循环块内部

for (let i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // ReferenceError: i 没有定义

在使用let 声明迭代变量时JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量。每个setTimeout 引用的都是不同的变量实例所以console.log 输出的是我们期望的值也就是循环执行过程中每个迭代变量的值。

for (let i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 会输出0、1、2、3、4

这种每次迭代声明一个独立变量实例的行为适用于所有风格的for 循环包括for-in 和for-of循环。

for (var i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 你可能以为会输出0、1、2、3、4
// 实际上会输出5、5、5、5、5

之所以会这样是因为在退出循环时迭代变量保存的是导致循环退出的值5。在之后执行超时逻辑时所有的i 都是同一个变量因而输出的都是同一个最终值

条件声明

因为let 的作用域是块所以不可能检查前面是否已经使用let 声明过同名变量同时也就不可能在没有声明的情况下声明它(即使检查到没有使用let声明也只是在检查块作用域中)。

try {
console.log(age); // 如果age 没有声明过则会报错
}
catch(error) {
let age;
}
// age 被限制在catch {}块的作用域内

比如上面例子声明的age会被限制在catch块中在下面这个外部调用时会报错。

因为let声明局限于块中外部的修改也只是相当于重新声明了一个变量。
if (typeof name === 'undefined') {
let name;
}
// name 被限制在if {} 块的作用域内
// 因此这个赋值形同全局赋值
name = 'Matt';

 const声明

const 的行为与let 基本相同唯一一个重要的区别是用它声明变量时必须同时初始化变量且尝试修改const 声明的变量会导致运行时错误。

const age = 26;
age = 36; // TypeError: 给常量赋值

// const 也不允许重复声明
const name = 'Matt';
const name = 'Nicholas'; // SyntaxError

// const 声明的作用域也是块
const name = 'Matt';
if (true) {
const name = 'Nicholas';
}
console.log(name); // Matt

const 声明的限制只适用于它指向的变量的引用。换句话说如果const 变量引用的是一个对象那么修改这个对象内部的属性并不违反const 的限制。

const person = {};
person.name = 'Matt'; // ok

JavaScript 引擎会为for 循环中的let 声明分别创建独立的变量实例虽然const 变量跟let 变量很相似但是不能用const 来声明迭代变量因为迭代变量会自增

for (const i = 0; i < 10; ++i) {} // TypeError给常量赋值

 不过如果你只想用const 声明一个不会被修改的for 循环变量那也是可以的。也就是说每次迭代只是创建一个新变量。这对for-of 和for-in 循环特别有意义

let i = 0;
for (const j = 7; i < 5; ++i) {
console.log(j);
}
// 7, 7, 7, 7, 7
for (const key in {a: 1, b: 2}) {
console.log(key);
}
// a, b
for (const value of [1,2,3,4,5]) {
console.log(value);
}
// 1, 2, 3, 4, 5

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6