学习笔记2—JavaScript语言基础

1 ECMAScript和JavaScript的区别与联系

1、ECMAScript是JavaScript的规格,JavaScript是ECMAScript的一种实现,在日常场合,这两个词是可以互换的。
JavaScript的创造者Netscape公司,将JavaScript提交给国际标准化组织ECMA,希望这种语言能够成为国际标准,后来ECMA发布标准文件的第一版(ECMA-262),规定了浏览器脚本语言的标准,并将这种语言称为ECMAScript。该标准从一开始就是针对JavaScript语言制定的,之所以不叫JavaScript,有两个原因:一是商标,Java是Sun公司的商标,根据授权协议,只有Netscape公司可以合法地使用JavaScript这个名字,且JavaScript本身也已经被Netscape公司注册为商标;二是想体现这门语言的制定者是ECMA,不是Netscape,有利于保证这门语言的开放性和中立性。

2、但事实上,JavaScript比ECMA-262的含义多得多,一个完整的JavaScript实现应该由以下三个部分组成:

  1. ECMAScript:核心

  2. DOM:文档对象模型

  3. BOM:浏览器对象模型

2 语法

(1)标识符:变量、函数、属性或函数参数的名称。第一个字符必须是一个字母、下划线 _、或美元符号 $,剩下的其他字符可以是字母、下划线、美元符号或数字。
按照惯例,ECMAScript标识符使用驼峰大小写形式,即第一个单词首字母小写,后面每个单词的首字母大写。
(2)注释:ECMAScript采用C语言风格的注释,包括单行注释和块注释。单行注释以两个斜杠字符开头,如:

//单行注释

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

/*
这是多行注释
*/

(3)关键字与保留字
ECMA-262描述了一组保留的关键字,这些关键字有特殊用途,比如表示控制语句的开始和结束,或者执行特定的操作。按照规定,保留的关键字不能用作标识符或属性名。
规范中也描述了一组未来的保留字,同样不能用作标识符或属性名。虽然保留字在语言中没有特定的用途,但它们是保留给将来做关键字用的。
(4)语句
ECMAScript中的语句以分号结尾,如:

let sum = a+b
let diff = a-b;

即使语句末尾的分号不是必须的,也应该加上。加分号便于开发者通过删除空行来压缩代码,加分号也有助于在某些情况下提升性能,因为解析器尝试在合适的位置补上分号以纠正语法错误。

3 变量

ECMAScript变量是松散的,意思是变量可以用于保存任何类型的数据,有3个关键字可以声明变量:var、const和let。其中var在ECMAScript的所有版本中都可以使用,而const和let只能在ECMAScript6及更晚的版本中使用。

3.1 var

var message; //变量定义

在不初始化的情况下,变量会保存一个特殊值undefined。

var message = "hi"; //变量定义同时设置值

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

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

这里message变量是在函数内部使用var定义的。函数叫test(),调用它会创建这个变量并给他赋值。调用之后变量随即被销毁,因此报错。不过在函数内定义变量时省略var操作符,可以创建一个全局变量。

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

去掉之前的var操作符之后,message就变成了全局变量,只要调用一次函数test(),就会定义这个变量,并且可以在函数外部访问。
如果需要定义多个变量,可以在一条语句中用逗号分隔每个变量:

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

因为ECMAScript是松散类型的,所以使用不同数据类型初始化的变量可以用一条语句来声明。
(2)var声明提升
在使用var时,下面的代码不会报错,因为使用这个关键字声明的变量会自动提升到函数作用域顶部:

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

之所以不会报错,是因为ECMAScript运行时把它看成等价于如下代码:

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

这就是提升(hoist),也就是把所有变量声明拉到函数作用域的顶部。此外反复多次使用var声明同一个变量也没有问题:

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

3.2 let

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

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

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

age变量之所以不能在if块外部被引用,是因为它的作用域仅限于该块内部。块作用域是函数作用域的子集,因此适用于var的作用域限制同样也适用于let。
(2) 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

(3) 暂时性死区
let与var的另一个重要的区别,就是let声明的变量不会在作用域中被提升

//name会被提升
console.log(name); //undefined
var name = 'Matt'//age不会被提升
console.log(age); //ReferenceError:age没有定义
let age = 26;

(4)全局声明
与var关键字不同,使用let在全局作用域中声明的变量不会成为window对象的属性(var声明的变量则会)。

        var name = 'Matt';
        console.log(window.name); //'Matt'

        let age = 26;
        console.log(window.age); //undefined

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没有定义

3.3 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 person = {
    
    };
person.name = 'Matt';

3.4 声明风格及最佳实践

(1)不使用var
有了let和const,大多数开发者会发现自己不再需要var了。限制自己只使用let和const有助于提升代码质量,因为变量有了明确的作用域、声明位置,以及不变的值。
(2)const优先,let次之
使用const声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作。因此,很多开发者认为应该优先使用const来声明变量,只在提前知道未来会有修改时,再使用let。这样可以让开发者更有信心地推断某些变量的值永远不变,同时也能迅速发现因意外赋值导致的非预期行为。

总结:

var let const
作用域 函数作用域 块作用域 块作用域
是否被hoist
能否重复声明 可以 不可以 不可以

猜你喜欢

转载自blog.csdn.net/qq_43599049/article/details/112757665