第一章 JS语法基础

93 阅读9分钟

JS语言概述

JS语言之父:Brendan Eich

JS是一门弱类型的,单线程的解释型语言

  • 弱类型:同一个变量所存放的数据的类型是可变的
  • 单线程:执行JS代码的线程只有一个

编译型语言和解释型语言

编译型语言:编译程序在执行前需要经过一次通篇翻译的过程,负责翻译的叫做翻译器,翻译的结果叫做翻译结果,而真正执行的其实是这个翻译结果,当二次执行同一个编译程序时,只需要执行它之前所翻译出的翻译结果即可,而无需重新翻译

解释型语言:解释程序是在执行时翻译一行执行一行,而不会生成一个翻译的结果,因此每次重新执行时都需要重新翻译程序

编译型语言的特点:

  • 优点:执行速度快

  • 缺点:跨平台性差,部署繁琐

解释型语言的特点:

  • 优点:跨平台性好,部署简单
  • 缺点:执行速度慢

以上的特点都是相对而言的

第一个JS程序

引用方式

浏览器环境中,代码书写的位置:

  1. 直接书写在页面中的script元素内部

  2. 书写到外部的JS文件,并在页面中引用(推荐)

    有利于浏览器缓存

    有利于代码分离:内容、样式、功能三者相分离,更加容易维护和阅读

注意:

  • 页面中可以存在多个script元素,执行顺序为从上到下依次执行

  • 如果一个script元素引用了外部文件,则其内部不能书写任何代码

    书写了也会被忽略

  • script元素有一个可选的属性type,该属性用于指定代码的类型,属性值为MIME的格式,不指定时默认为text/javascript

    <script type="text/javascript"></script>
    

基本语法

  • 语法部分必须都是英文符号

  • JS代码由多条语句构成,每条语句可以使用用英文分号代表结束

    并非强制要求

  • 除异步JS代码外,JS代码都是从上到下一条语句一条语句依次执行

输出语句

所有输出语句都不是ES标准

  • document.write

    将数据作为一个dom节点添加到文档流中

    添加的dom节点可以是元素节点、注释节点等,具体看write的文本是什么格式的

    若当前文档流仍正在生成中,则执行该语句时会直接将数据作为dom节点加入到该文档流中

    若当前文档流已经生成完成,则执行该语句时会先将已生成完成的文档流清空,并创建一个新的文档流,然后再将数据加入到该文档流中

  • alert

    将数据用弹窗的形式显示到页面

    该语句具有阻塞代码执行的作用

  • console.log

    将数据显示到控制台

输入语句

所有输入语句都不是ES标准

  • prompt("提示文本")

    该函数的返回值为用户输入的内容或null

    null:表示用户点击了取消

    用户输入的字符串:表示用户点击了确定,得到用户输入的结果

注释

注释提供给代码阅读者使用,不会参与执行

单行注释://

// 注释内容...

多行注释:/* */

/* 
	注释内容...
	注释内容...
*/

VSCode注释快捷键:

  • 单行注释:ctrl + /
  • 多行注释:alt + shift + a

数据和数据类型

数据:有用的信息

数据类型:数据的分类

JS中的数据类型分为两大类:原始类型和引用类型

原始类型(基本类型)

指不可再细分的类型

  1. 数字类型:number

    数字类型可以加上前缀,表示不同进制的数字:

    0o:表示8进制

    0x:表示16进制

    0b:表示2进制

  2. 字符串类型:string

    字符串使用''或""或``包裹

    模版字符串:使用``包裹的字符串,其内部字符串可以直接换行

    使用转义符\可以表示在字符串中表示一个特殊字符

  3. 布尔类型:boolean

  4. undefined

    表示未定义

  5. null

    表示空,不存在

引用类型

  • 对象:Object

    属性:对象的成员

  • 函数:Function

得到数据的类型

使用typeof得到数据的类型,typeof表达式返回类型为string

console.log(typeof xxx);

注意:typeof null得到的是"object",这实际上是JS中的一个bug

typeof undefined得到的是"undefined"

字面量

直接书写的具体的数据,叫做字面量

数字字面量:1

对象字面量:{}

变量

变量是一块内存空间,用于保存数据或数据的地址

定义变量

  1. 声明变量

    var 变量名;
    

    仅对变量进行声明时,其值为undefined

  2. 给变量赋值

    变量名 = 值;
    

    变量可以被重新赋值,新的值会覆盖原来的值

  3. 声明和赋值合并

    var 变量名 = 值;
    

    这实际上是一个语法糖

    语法糖仅仅是为了方便代码书写,并不会有实质性的改变,也就是说,上面的代码最终还是会被转换为

    var 变量名;
    变量名 = 值;
    
  4. 多个变量合并声明、赋值(语法糖)

    var 变量1 = 值1, 变量2 = 值2, 变量3 = 值3;
    

变量的名称

在开发中,凡是需要自行命名的位置,叫做标识符

变量就是一种标识符

标识符的命名规范:

  • 只能以英文字母、下划线、$符号开头

  • 其它位置可以出现英文字母、数字、下划线、$

  • 不可以与关键字、保留字重名

  • 区分大小写

    上面几条是必须遵守的,下面几条是可选的

  • 标识符应该做到望文知义

  • 标识符若为多个单词组成,则建议使用驼峰命名法

    大驼峰命名:每个单词的首字母大写

    小驼峰命名:除第一个单词外,其它单词首字母大写

注意:

  • 若访问一个声明但未赋值的变量,得到的是undefined

  • 若访问一个未定义的变量,会导致错误

    xxx is not defined

  • 使用typeof得到类型时,允许是未定义的变量

    typeof 未定义的变量得到的是"undefined",而不会报错

  • JS中存在变量提升

    所有使用var定义的变量,变量的声明部分会提升到当前作用域的最顶部

    JS中所有的提升(包括函数提升),都不会超越脚本块(不会跨越script元素)

  • JS允许在一个作用域中使用var定义多个同名变量

    由于变量提升的原因,在一个作用域下的多个同名变量,最终都会被提升合并成为同一个变量

  • 任何一个变量,不管在哪个作用域中,只要它从没被声明过就赋了值,就会成为全局对象上的属性

    浏览器环境以及node环境中都适用

变量和对象

读取对象属性

读取对象中的某个属性,使用.操作符

var obj = {
 	a: 1,
    b: "2"
};

console.log(obj.a);

当读取的属性不存在时,会得到undefined,不会报错

undefinednull中读取属性时,会导致错误Cannot read property 'xxx' of undefined(null)

当访问未定义的全局变量时会报错,但如果你是使用访问window对象上的属性的方式访问未定义的全局变量则会返回undefined

更改对象属性

类似变量的更改,对象属性的更改直接对对象属性重新赋值即可

var obj = {
 	a: 1,
    b: "2"
};

obj.a = 3;

当给对象中不存在的属性赋值时,会在对象中增加一个属性

删除属性

使用delete关键字删除属性

var obj = {
 	a: 1,
    b: "2"
};

delete obj.a;

属性表达式

当访问属性时,可以使用对象["属性名"]的格式进行操作

var obj = {
 	a: 1,
    b: "2"
};

obj["a"] = 2;

属性名中可以包含特殊字符

当属性名中包含特殊字符时,需要给属性名加上引号,并且当访问该属性时,也必须使用属性表达式的形式

当属性名为数字时,可以直接书写属性名为一个数字,并且当访问该属性时,允许使用对象[数字]的形式(数字部分可以没有引号)

属性名也属于标识符,但JS对属性名的命名要求并不严格,属性名可以为任何形式

var obj = {
    0: 1,
    "?": 2,
    " ": "3"
};

console.log(obj[0], obj["?"]);

注意:对象属性名只能是字符串,因此无论是哪种形式的属性名,宿主环境最终都会将它们转换为字符串形式

访问成员时,使用对象.属性名以及对象[数字]访问属性,宿主环境最终也会将其转换为对象["属性名"]的形式

[]会对内部的值强制类型转换为字符串

const obj1 = {
    toString(){
        return "tostring";
    },
    valueOf(){
        return "valueof";
    }
};

const obj2 = {};

obj2[obj1] = "abc";

console.log(obj2);				// { "tostring": "abc" }

细节:设置对象属性时,属性会按照被加入的先后顺序排序,但如果属性的键是数字形式,则属性会按照键的数值的大小依次排序,并且数字键始终在普通键之前,如果有Symbol键,则Symbol始终在最后

const obj = {
    [Symbol(2)]: 1,
    [Symbol(1)]: 2,
    b: 3,
    4: 4,
    a: 5,
    3: 6
}

console.log(obj);	// { '3': 6, '4': 4, b: 3, a: 5, [Symbol(2)]: 1, [Symbol(1)]: 2 }

全局对象

JS大部分的宿主环境,都会提供一个特殊的对象,该对象可以直接访问,叫做全局对象

在浏览器环境中,全局对象为window对象

全局对象中的所有属性,都可以直接使用,而不需要加上对象名(加上也没事)

在浏览器环境下,使用var在全局作用域下定义的变量,会成为window对象上的一个属性,而直接访问该var全局变量时,实际上访问的是window对象上相应的属性

在模块的全局下使用var定义的变量,不会成为window对象的属性

<script type="module">
var a = 10;
console.log(window.a);			// undefined
</script>

在window对象上有一个特殊的属性name,为其赋值的任何内容,最终都会转换为字符串形式

// 全局环境

var name = undefined;
console.log(name, typeof name);

JS中,允许给一个未经声明过的变量直接赋值

对于这种变量,不管出现在哪个作用域中,都会成为window对象上的属性

function method(){
    a = 10;
}

method();

console.log(window.a);		// 10

引用类型

原始类型的变量,存放的是具体的原始值

引用类型的变量,存放的是引用值所在的内存地址

JS中的垃圾回收

JS引擎会定期检查内存中无法访问到的对象(即没有被变量或属性引用起来的对象),该对象称之为垃圾

JS引擎中的垃圾回收器会在合适的时间将其占用的内存空间释放