
01、JavaScript基础知识
JavaScript(缩写:JS)是一种具有面向对象能力的、解释型的程序语言,基于对象和事件驱动,具有相对安全性的客户端脚本语言。JavaScript是一门完备的 动态编程语言,当应用于 HTML 文档时,可为网站提供动态交互特性,是前端开发最主要、正式的编程语言。

ECMAScript 是由 ECMA 国际标准化组织 制定的一套脚本语言的标准化规范,JavaScript算是他的实现,作为基础语法规范,构成了JavaScript的核心。再加收浏览器提供的DOM(HTML网页内容)操作API、浏览器BOM操作API,共同组成了 JavaScript。
1.1、语法规范
JS代码以行为单位,(半角)分号;结尾。
🔸注释://
- 单行注释:
//开头。 - 多行注释:
/*多行注释*/(同css)
🔸代码风格:
- 区分大小写,字母、数字、下划线组成,不能数字开头,不能是关键字。
- 小驼峰命名(推荐):
initialColor
🔸关键字: 内置的关键词:如var、do、else、enum、eval、false、for、if、void、function、switch...
🔸语句块:花括号 { 代码块 }
1.2、引用方式
- 行内JS:元素标签内部的JS代码。
- 内部JS:定义在
<script>标签里的JS代码,可以放到head中、body中、body后,推荐body后,先加载html再执行JS。 - 外部JS(推荐):单独的JS文件,通过script标签引入,
src属性指定JS文件地址,此时标签中写的代码就无效了。 - 动态加载:通过DOM的API动态加载JS脚本资源,用JS创建
<script>标签并引入资源。
<script>属性 |
描述 | 值/备注 |
|---|---|---|
| src | 外部资源地址,与嵌入脚本代码不可同时使用 | <script src="js1.js" async></script> |
| type | 定义脚本语言类型,可空,默认为JavaScript类型 | 支持的MIME类型包括text/javascript、 text/ecmascript、 application/javascript 和application/ecmascript |
| async | 异步并行加载,只针对外部JS资源 | 多个async脚本加载完成的顺序不确定 |
| defer | 等HTML解析完成再执行JS,在DOMContentLoaded之前执行,只针对外部JS资源 | 多个脚本资源顺序加载 |
🔸脚本加载策略:
- 如果脚本无需等待页面解析,且无依赖独立运行,那么应使用
async。 - 如果脚本需要等待页面解析,且依赖于其它脚本,应使用
defer,将关联的脚本按所需顺序置于 HTML 中。
<body> <div> <h1>基础语法</h1> <input type="button" value="行内JS" onclick="alert('Hello world!');"/> <input type="button" value="外部JS调用" onclick="hello();"/> </div><hr/> </body> <script> console.log("内部js:网页加载完成!"); </script> <!-- 引入外部js文件,设置了src属性,script内部的代码就无效了 --> <script src="../tstudy/js/js1.js" type="text/javascript" async></script>
02、变量申明var/let/const
变量,就是一个用于存放数值的容器,比如年龄=20,“年龄”就是变量,“20”是他的树值。JS是一种弱类型语言,不需要指明数据类型,用var或 let关键字申明即可。
🔸申明方式:
- 申明并赋值,1步完成:
var str="hello world"; - 先申明,再赋值,2步完成。
var str1; str1="hello world";// 默认值为undefined
🔸动态数据类型:JavaScript 是一种“动态类型语言”,意味着一个变量可以被赋值为各种类型数据值,通过typeof判断数据类型。
let age; console.log(age); //undefined age =20; console.log(typeof age); //number age='年芳二十'; console.log(typeof age); //string
| var | let (IE11 ES6) | const (IE11 ES6) | |
|---|---|---|---|
| 说明 | 变量申明 | 变量申明 | 只读常量申明:申明时必须初始化值,不可更改 |
| 作用域 | 全局(整个文档)或整个函数体内 | 块级作用域{}包含的区域 |
块级作用域{} |
| 命名规范 | 推荐:小驼峰命名 | 同var | 推荐:全大写+下划线,const MAX_SPEED |
| 默认值 | undefined |
undefined |
必须赋值 |
| 变量提升 | 提升所有var申明的变量,可以先使用后申明(不推荐),把var变量申明提升到代码头部,⚠️注意不包括赋值 | 不会提升,顺序执行:必须先申明,后使用。存在暂时性死区let foo=(foo+55)第二个foo未申明报错 |
不会提升,顺序执行:必须先申明,后使用。 |
| 全局属性 | 在全局环境时,会成为顶级对象的属性(不可配置属性),作为全局变量存在。var age=3; //this.age;window.age |
无 | 无 |
| 重复申明 | 可以重复申明,覆盖前面的,有点太随意了 | 不可重复申明,作用域内重复申明会报错 ● 包括var、const申明的变量 ● 子块可重新申明let,不同的作用域了 ● 子块中用var变量会重复,var会提升 |
不可重复申明,会提示错误,同let |
| 申明多个 | 支持:var s1=1,st=2; |
支持:let s1,s2=2; |
支持:const s1=1,s2=2; |
| 性能 | 一般 | 一般 | 编译器会做常量替换优化,提升代码效率 |
| 总结 | 🚫有点粗犷,不推荐 | 💛更严谨,推荐使用 | 💚不仅更严谨,性能还好,优先推荐!!! |
暂时性死区:由于没有了变量提升,及块级作用域,let、const变量只能在申明后才能用,在这之前不可用,称为“暂时性死区”。
2.1、作用域
特别注意的是 var 作用域在整个文档或函数内,整个文档也可认为是一个特殊的顶级函数。
- 如下经典的for循环示例,
var的变量提升导致输出结果诡异。
for (var i = 1; i <= 5; i++) { setTimeout(function () { //setTimeout为异步执行函数 console.log(i); //输出6 6 6 6 6 }, 0); } //换成let,则输出:1 2 3 4 5 //换成const,输出1,然后报错 Assignment to constant variable
- var作用域在整个函数
function foo() { var x = 1; //x作用域在foo函数体内,包括嵌套函数bar也可以访问 function bar() { var y = 2; //y作用域只在函数体bar console.log(x); // 1 console.log(y); // 2 } bar(); console.log(x); // 1 (`x` 在作用域内) console.log(y); // Uncaught ReferenceError: y is not defined } foo(); console.log(x); // Uncaught ReferenceError: x is not defined console.log(y); // Uncaught ReferenceError: y is not defined
- let作用域仅限
{}块,可以是函数的块function{}、循环的块for{},或者就一个孤独的块{}。
let s1; let s1; //Uncaught SyntaxError: Identifier 's1' has already been declared let x = 1; //后面块内的 var x会被变量提升,导致重复变量定义报错 { var x = 2; //Uncaught SyntaxError: Identifier 'x' has already been declared }
2.2、变量提升
变量提升:JS引擎是先解析代码,获取所有被var申明的变量,然后再逐行执行。只提升用var显示申明的变量,会把所有var的申明提升到全局代码的顶部先执行,⚠️注意只提升申明,不包括赋值。
console.log(sname); //undefined 只提升了x的变量申明,值为默认值 var sname = "sam"; var x=1; function print() { console.log(sname); // sam console.log(window.sname); //sam 全局文档中申明的var变量,会作为 window 的全局变量属性 console.log(this.sname); //sam 这里的this 指向 全局对象window } print();
🔸隐式全局变量:无申明变量(
str="hello";),自动提升为隐式全局变量(不论在什么地方),类似var变量,除了没有变量提升。so,🚫尽量不要这么使用,在严格模式下('use strict';)这样写是会报错的。
x = 0; //未申明变量,成为隐式全局变量 function f() { y = 1; //当执行该函数时,未申明变量,成为隐式全局变量 var z = 2; //z是函数内部申明的变量,作用域只在函数体内 } f(); console.log(x, y); // 0 1 console.log(window.x, window.y); // 0 1 console.log(z); //Uncaught ReferenceError: z is not defined
2.3、解构赋值
解构赋值是ES6新增的语法,可以一次性给多个变量赋值,提高了编程效率,赋值操作更简洁。具体方式就是:将属性/值从对象/数组中取出,赋值给其他变量的一种赋值方式。有两种解构赋值的语法形式:
- 数组解构:类似数组的写法,从数组中按顺序赋值,这里数组可以是其他可迭代数据。
- 对象解构:类似对象的写法,从对象中按属性名赋值。
//变量一个个赋值 let x1 = 1, x2 = 2, x3 = 3, x4 = 4; // 用数组解构赋值 let [y1, y2, y3, y4] = [1, 2, 3, 4]; [x1, x2] = [x2, x1]; //用来交换x1、x2的值,不用第三方变量 // 从对象解构赋值 let { c, d } = { a: 0, c: 1, d: 2 };
03、基础数据类型
ECMAScript 有 6 种基本类型,Undefined、Null、Boolean、Number、String、Symbol(符号),其他就是都是Object对象类型了,如Array、object、Map、Date、function等。
| 数据类型 | 描述 | |
|---|---|---|
| Number | 数值:整数、小数(浮点型) ● 都是64位浮点类型存储的,最高精度17位,所以1和1.0是相等的。 ● 浮点数计算时(小数位)可能不准确,不建议用浮点数做判断。 ● 存储时会自动转换整数的浮点数值,如1.0转换为1。 |
let myAge = 17; |
| Boolean | 布尔类型:有两个值true、false |
let isFirstBlood=true; |
| null | 空值关键字,表示空缺、空值,其类型为object,表示一个空对象的指针。undefined继承自null,等值比较时返回true。 |
注意判断object类型时须排除null。 |
| Undefined | 未定义:只有一个值undefined,表示未定义或不存在● 未赋值的变量默认为 undefined。● 调用函数时未传递必须参数,则为 undefined。● 函数没有返回值,默认返回 undefined。 |
|
| String | 字符串:单引号、双引号括起来,用加号+连接字符串。● 不可变:JS的字符串一旦创建不可变,所有更改都会创建新的字符串 ● 每一个字符元素是16 位的无符号整数值 |
|
| Symbol ES6 | 符号类型,具有唯一性和不变性,常用于对象属性名 | const fooSym = Symbol('foo') |
| bigint | 新添加的数据类型(ES2020) | |
| object对象 | 对象:引用类型,各种值的组合 | |
| Array | 数组对象 | var list1=[1,2,3]; |
| JSON对象 | 对象:var jobj={name:"zhang",age:1}; |
|
| function | 函数,本身也是对象 | function f1(){/*...*/} |
⚠️注意不要将基本类型中的布尔值 true / false 与值为 true/false 的 Boolean 对象弄混了,基本类型Boolean是一个对象。
console.log(typeof 1); //number console.log(typeof true); //boolean console.log(typeof null); //object console.log(typeof undefined); //undefined console.log(typeof 'abc'); //string console.log(null == undefined); //true 值比较 console.log(null === undefined); //false 恒等比较 //boolean const x = new Boolean(false); //new Boolean()创建了基本类型Boolean的对象,就不是一个平平无奇的值类型了。 console.log(typeof x); //object console.log(x.valueOf()); //false valueOf()方法获取对象的基本数据的值 console.log(Boolean(undefined)); //false console.log(Boolean(null)); //false console.log(Boolean(NaN)); //false console.log(Boolean(0)); //false console.log(Boolean("")); //false console.log(Boolean(1)); //true console.log(Boolean(-100)); //true console.log(Boolean("abc")); //true
3.1、Number数字
Number的属性、方法:
| 属性/方法 | 描述 | 示例 |
|---|---|---|
| 🔖静态属性/方法 | ||
| Number.NaN | NaN是一个特殊的Number值,即非数值(Not a Number) ● NaN和任何值都不相等,包括它自己,和任何值计算都为NaN ● Math、parseInt函数执行失败会返回NaN |
同window.NaN |
| Number.MAX_VALUE | 最大数值(静态属性),值接近于 1.79E+308 | |
| Number.MIN_VALUE | 最接近 0 的正值,而不是最小的负值,约为 5E-324 | |
| Number.isNaN() IE🚫 | 判断是否等于NaN,window.isNaN是判断是否非数值,坑! |
只有NaN才返回true |
| Number.isInteger() IE🚫 | 是否为整数 | |
| Number.parseFloat() IE🚫 | 解析浮点数,从第一个非空字符解析获取数字,识别第一个小数点 | 同window.parseFloat() |
| Number.parseInt() IE🚫 | 解析整数,从第一个非空字符解析获取数字,支持进制参数 | 同window.parseInt() |
| 🔖构造函数 | ||
| Number() | 转换为数字(忽略空格)。Number()转换数据不同于parseint、parseFloat,要求必须为合法数字,要求更严格,不成功便成仁。 | Number(true) //1 |
| 🔖实例属性/方法 | ||
| toFixed(小数位数) | 转换为指定小数位数的字符,多了会四舍五入,不足用0补位 | n1.toFixed(2) |
| toString() | 转字符串,参数可以指定基数(进制) | n2.toString(2) //2进制 |
📢注意浮点数的精度:
0.1+0.2 //输出 0.3000000000000000**4**。由于浮点数的精度问题,永远不要用浮点数值去做条件判断。这种错误是由于IEEE 754标准导致的。
Number.parseFloat("123.4a5"); //123.4 Number.parseInt("123.4a5"); //123 //注意,两个方法是不同的,全局的window.isNaN()是判断是否非数值。 window.isNaN("a") //true Number.isNaN("a") //false //这属于JS坑爹的设计,两个含义完全不同 console.log(Number("")); //0 console.log(Number("123abc")); //NaN,不同于parseint、parseFloat console.log(Number("12.12.12")); //NaN,不同于parseint、parseFloat console.log(Number.parseFloat("12.12.12")); //12.12 let n1=1.336,n2=100; n1.toFixed(2) //1.34 n2.toFixed(2) //100.00
window.parseFloat(string):从字符串的第一位(空字符会被忽略)开始,如果是数字(正号+、负号-、数字0-9、第一个小数点.、科学计数法e/E)则转数字,直到非数字或结束。
console.log(parseFloat("123abc")); //123 console.log(parseFloat("abc123")); //NaN console.log(parseFloat("11.11")); //11.11 console.log(parseFloat("11.11.33")); //11.11
window.parseint(string):同parseFloat,除了不识别小数点。
console.log(parseInt("123abc")); //123 console.log(parseInt("abc123")); //NaN console.log(parseInt("11.11")); //11
3.2、String字符串
String:字符串对象,提供各种字符串操作。
| 属性/方法 | 描述 | 示例 |
|---|---|---|
| 🔖构造函数 | ||
| String() | 支持任意值转换为字符串,包括null、undefined,都是直接加引号,很粗暴!📢可以用来判断null、undefined |
String(null) //"null" |
| 🔖实例属性/方法 | ||
| length | 字符串长度 | "abc".length; // 3 |
| charAt(index) | 返回指定位置的字符 | |
| indexOf(char) | 返回字符的索引位置,从前往后找,lastIndexOf是从后往前找 |
s1.indexOf("12") |
| substr(start,length?) | 截取字符串:指定起始位置、长度,无length到结尾(下同) |
s1.substr(2) |
| substring(start,end?) | 截取字符串:指定起始位置、结束位置 | |
| slice(start,end?) | 截取字符串:起始位置、结束位置,同substring,区别是支持负数(倒数),(slice /slaɪs/ 切片) |
str.slice(0,-1);//截取0到倒数第二位置的字符 |
| split(separator,limit?) | 按照分隔符分割字符串为数组 | (split /splɪt/ 分裂) |
| trim() | 移除首尾的空白字符,返回新字符,不会改变原有字符。 | |
| trimStart() | 同上,值移除开头的空白字符,还有移除末尾的trimEnd() |
|
| padStart(len,str) | 从头补齐字符长度到len,str为去替补的字符,没有则空格 |
"12".padStart(5,'0') |
| padEnd(len,str) | 补齐字符长度,从尾部开始 | |
| replace(old, new) | 字符替换,str.replace("台湾","台湾省"),支持正则和函数 |
|
| repeat(n) | 创建一个重复n次的新字符串 | "12".repeat(2) //1212 |
| toLowerCase() | 字符转小写,大写是toUpperCase() |
|
| includes(str) | 判断是否包含指定的字符串 | |
| startsWith(str) | 判断是否以指定字符开头,endsWith()判断结尾 | |
| search(str) | 字符搜索或正则匹配搜索 | |
| match(regexp) | 正则匹配搜索字符 |
🔸字符串的不变性:字符串一经创建不会改变。 let str="abc"; str="123";
- 这里的不改变,不是字符变量
str不能修改,是指字符串"abc"本身不可更改,修改str会创建新的字符。所以,字符的操作都不会影响原来的字符串值,而是创建新的字符串。 - 字符连接创建新字符:字符的连接,如
+,会创建新的字符串。
🔸模板字符串(IE🚫):${var}+反引号 `` 包装
板字符串可以包含特定语法(${expression})的占位符,由一个内置函数负责计算表达式并输出最终的字符串。
let x=1,y=2; console.log(`sum: ${x} + ${y} = ${x+y}`); //sum: 1 + 2 = 3
🔸JavaScript 特殊/转义字符:在字符串中使用的特殊符号
| 字符 | 描述 |
|---|---|