1.这是JavaScript

HTML描述页面的结构,CSS展现页面的样式,JS在页面中描述行为、控制交互。

JavaScript里没有Java,就像老婆饼里没有老婆。

JavaScript是解释型语言,既是前端语言,又是后端语言,当它运行在浏览器中时是前端语言,后端语言运行在服务器中也称为服务端语言,NodeJS可以让JS运行在服务端。

JavaScript基础由三部分组成,ECMAScript是语法,DOM和BOM是浏览器提供的API

  1. ECMAScript: JavaScript的语法标准,至少要学习到ES6,它规定了JS最基础的语句、变量、函数、运算等等。
  2. DOM: 文档对象模型(Document Object Model),JS操控网页元素的API。
  3. BOM: 浏览器对象模型(Browser Object Model),JS操控浏览器的API。

2.使用JS

  1. 行内: 写在标签属性中。

    1
    <input type="button" value="点我" href="javascript:;" onclick="alert('你好')" />
  2. 内嵌: 写在标签中。

    1
    2
    3
    <script type=”text/javascript”>
    alert('你好');
    </script>
  3. 外链: 在标签的src属性中写上js文件的链接。

1
<script type="text/javascript" src="main.js"></script>

3.执行顺序

浏览器默认从上至下解析网页,JS的加载默认会阻塞网页的解析,通过JS操控网页元素,需待网页解析完后执行、写在html的最后或写在对应元素后,否则就可能因为DOM树不完整,要操控的对象还未被加载而报出undefined错误。

1
2
3
4
5
6
<!-- 不等待后续网页的解析,到此就加载JS并执行 -->
<script src="main.js"></script>
<!-- 网页的解析与JS的加载异步,但JS在网页解析完后执行 -->
<script defer src="main.js"></script>
<!-- 网页的解析与JS的加载异步,JS加载完后立即执行 -->
<script async src="main.js"></script>
1
2
3
4
5
//待网页解析完、网页中所有资源(图片、css)都加载完毕,执行其中的代码
window.onload = function () {
//js代码
alert('你好');
}

4.输出语句

  1. console.log(): 在控制台输出内容

    1
    2
    3
    console.log('日志'); //普通打印
    console.warn('警告'); //警告打印
    console.error('出错了'); //错误打印
  2. alert(): 警告对话框

  3. confirm(): 确认对话框,返回true或false

    1
    2
    3
    4
    5
    6
    var a = confirm('确认吗');
    if(a){
    alert('你确认了')
    }else{
    alert('未确认')
    }
  4. prompt(): 输入对话框,返回输入内容或空字符串,点取消返回NULL

    1
    2
    3
    4
    5
    6
    7
    8
    var a = prompt('输入内容');
    if(a){
    alert('你输入了:'+ a)
    }else if(a==''){
    alert('你没输入任何东西')
    }else{
    alert('取消')
    }

    5.常量、变量、标识符

    数字常量、字符串常量、布尔常量

    1
    2
    3
    4
    5
    6
    console.log(123); //123是数字
    console.log('123'); //'123'是字符串,''空字符串
    console.log('你好'); //''包裹起来的都是字符串
    if(true){ //true、false布尔常量
    console.log('true');
    }

自定义常量const

1
2
3
const a = '123'; //定义a为常量
a = '321'; //不允许修改常量
const a = '321'; //不允许重新声明

定义变量var、let(ES6)

1
2
3
4
5
6
7
8
var a = '123';
let b = 321;
//重新定义
var a = '321'; //var允许重新定义
let b = 123; //let不允许重新定义
//不允许var和let之间重新定义
var c = 123;
let c = 123;

var可以在声明前使用,值为undefined,而let必须先声明再使用。

var是函数作用域,let是块作用域。

标识符(一切可自主命名的,如变量名、函数名)命名规则:

  1. 区分大小写

  2. 只能由字母(A-Z、a-z)、数字(0-9)、下划线(_)、美元符( $ )组成

  3. 不能以数字开头、不允许出现空格

  4. 不能出现中划线 —

    6.数据类型

    JavaScript是弱类型语言(动态语言),无需声明变量的类型,在程序运行过程中,会根据等号右边的值自动确定类型。

    1
    2
    3
    4
    5
    6
    var a = 123;
    console.log(typeof a);//输出number
    a = '123'//强制将变量a数据类型转换为字符串
    console.log(typeof a);//输出string
    a = Number(a);//强制将字符串'123'转换为数字123
    console.log(a);//输出123

    JS中数据类型分为基本数据类型和引用数据类型

  5. 基本数据类型(值类型): String字符串、Number数值、BigInt(ES6)大型数值、Boolean布尔值、Null空值、Undefined未定义、Symbol(ES6)。

  6. 引用数据类型(引用类型):Object 对象(除了基本数据类型之外,都可称之为Object类型)。

    基本数据类型传数值,引用数据类型传地址。

    1
    2
    3
    4
    5
    var a = 23;
    var b = a;//将a的值23传给b
    a++;
    console.log(a); //24
    console.log(b); //23,改变a的值不影响b
    1
    2
    3
    4
    5
    6
    var a = new Object();//a、b都是引用数据类型
    b.name = '123';
    var b = a;//传的是a的地址,a和b是同一个东西
    a.name = '321';
    console.log(a.name); //321
    console.log(b.name); //321,修改a对象的属性也会修改b

    JS中,所有的变量都保存在栈内存中的。

    基本数据类型直接保存在栈内存中。值与值之间独立存在。

    对象Object保存在堆内存中,创建一个新的对象,在堆内存中开辟一个新的空间,变量在栈内存中保存了对象的内存地址(对象的引用)。

    7.String字符串

    字符串是双引号和单引号中的文本,不同类型引号可以嵌套使用。

    1
    2
    3
    4
    5
    6
    var a = '123';
    console.log(a);//123
    var b = '1"2"3';
    console.log(b);//1"2"3
    var c = '12 3';
    console.log(c);//12 3不忽略连续多个空格

    加入字符串进行拼接,可以被同化为字符串

    1
    console.log(typeof(123+''));//string

转义字符: **

  • 双引号: ",单引号 ’

  • \ 表示\

  • \r 回车,\n 换行

  • \t 缩进

  • \b 空格

    字符的数量就是字符串的长度,获取字符串的长度.length:

    1
    2
    3
    4
    var a = "abc";
    console.log(a.length);//3
    a = "你好";
    console.log(a.length);//2

    使用 + 进行字符串拼接:

1
2
3
4
5
6
7
8
var a = "你好"+"世界";
console.log(a);//你好世界
a = "你好"+ 1;
console.log(a);//你好世界1
a = "你好"+ null;
console.log(a);//你好null
a = "你好"+ true;
console.log(a);//你好true

ES6新增模板字符串:,可以使用${变量名}将其嵌入字符串,使用时需要反引号 包裹。

1
2
3
var a = 2022;
var b = '2023';
console.log(`去年是${a},今年是${b}`); //去年是2022,今年是2023,注意使用反引号

模板字符串中可以换行,不忽略连续的多个空格,保留原有格式。

可以调用函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function getHtml() {
return `<div>
<span>1</span>
<span>2</span>
<span>3</span>
</div>`;
}
console.log(`1${getHtml()}2`);
/*
1<div>
<span>1</span>
<span>2</span>
<span>3</span>
</div>2
*/

可以嵌套使用,进行运算:

1
2
3
4
var a = 1;
var b = 2;
console.log(`${a+`${b}`}`);//12
console.log(`${a+b}`);//3

8.Number数值型

JS中整数和浮点数等所有的数值都是Number类型。

1
2
3
4
var a = 1;
var b = 1.2;
console.log(typeof a);//number
console.log(typeof b);//number

数值范围:

1
2
console.log(Number.MAX_VALUE);//1.7976931348623157e+308
console.log(Number.MIN_VALUE);//5e-324

数值变量超过了最大值,则会返回Infinity,Infinity也是一种数值,代表无穷大。

1
2
3
4
5
6
var a = Number.MAX_VALUE;
var b = Number.MIN_VALUE;
console.log(a*2);//Infinity
console.log(b/2);//0
console.log(a*(-2));//-Infinity
console.log(typeof Infinity);//number

NaN是一个特殊的数字,表示不是数值(Not a Number),当运算不出数值时就会返回NaN。

1
2
3
console.log(typeof NaN);//number
console.log('abc' / 2);//NaN
console.log('a' * '2');//NaN

Undefined和任何数值计算的结果均为NaN。NaN与任何值都不相等,包括NaN本身。

1
2
3
console.log(undefined + 1);//NaN
console.log(null + 1);//1
console.log(NaN==NaN);//false

隐式转换,当有字符串介入的运算,且字符串可被转换为数值,除了+表示字符串连接,其余都会自动将字符串转为数值后进行运算。

1
2
3
4
5
console.log('1' + '2');//12
console.log('1' * '2');//2
console.log('1' / 2);//0.5
console.log('1' - 2);//-1
console.log('1' + '2' * '3');//16

浮点数的运算精度并不足够准确,当需要进行高精度运算时,最好引入可靠的数学库。

1
2
var a = 0.1 + 0.2;
console.log(a); //0.30000000000000004

9.Null与Undefined

undefined实际上是由null衍生出来的。

undefined表示未定义,应该有值但还未赋值,连null这个值都没有赋予给它。
null代表空值,本身是一个具体的值或空引用。

null和undefined值上相等,但类型不一样。
null是引用类型Object,代表空对象,存的地址为空,而undefined的类型是undefined,代表未定义的值。

1
2
3
4
5
console.log(null == undefined);//true
console.log(null === undefined);//false

console.log(typeof null);//object
console.log(typeof undefined);//undefined

null转为数值是0,undefined转为数值是NaN。
任何值和null运算,null可看做0。任何数据类型和undefined运算,结果都是NaN。

1
2
3
4
5
console.log(Number(null));//0
console.log(Number(undefined));//NaN

console.log(null+1);//1
console.log(undefined+1);//NaN

出现undefined的情况:

变量被声明了,但是没有被赋值

变量未声明(未定义)时

调用函数时,未传参

函数无返回值时

访问一个对象中没有的属性

1
2
3
4
5
6
7
8
9
console.log(a);//undefined
var a;
console.log(a);//undefined

function Fun(item) {
console.log(item);
}
console.log(Fun());//undefined
Fun();//undefined

出现null的情况:

  1. 访问一个不存在的dom节点
  2. 作为对象原型链的终点出现

10.数据类型转换

变量的数据类型转换:将一种数据类型转换为另外一种数据类型。(通常在基本数据类型中互相转换)

  1. 显式类型转换

    toString() 转换为字符串
    String() 强制转换为字符串
    Number() 转为数值,保留小数
    parseInt() 字符串转整数,直接舍去小数部分
    parseFloat() 在parseInt()的基础上可以获得小数部分
    Boolean()

  2. 隐式类型转换
    isNaN()
    自增/自减
    正号/负号
    加号(字符串拼接)
    其它数值运算符
    逻辑运算符:会先非布尔值转换为布尔值,再运算
    关系运算符:运算结果都是布尔值

10.1.转为字符串

toString():

1
2
3
4
5
6
7
8
var a = 123;
console.log(a.toString());//"123"
a = true;
console.log(a.toString());//"true"
a = [1, 2, 3];
console.log(a.toString());//"1,2,3"
a = { name: 'qx', age: 18 };
console.log(a.toString());//"[object Object]"

null和undefined这没有toString()方法,调用会报错

1
2
3
4
var a = null; 
console.log(a.toString());//Cannot read properties of null (reading 'toString')
a = undefined;
console.log(a.toString());//Cannot read properties of null (reading 'toString')

Number类型的变量,在调用toString()时,可以传入一个整数,把数字转换为指定的进制,默认转换为10进制。

1
2
3
4
var a = 8;
a = a.toString(2); //转换为二进制
console.log(a); //"1000"
console.log(typeof a);//string

数字不允许直接调用toString()

1
2
3
1.toString()//不允许,会把.看成小数点,小数点后面出现非数字是不允许的
1..toString()//允许
(1).toString()//允许

使用String()强制转换为字符串。
对于非null和undefined的数据类型而言,实际上就是调用toString()。
对于null和undefined,直接转换为”null”和”undefined”。

1
2
3
4
5
6
var a = 123;
console.log(String(a));//"123"
a = null;
console.log(String(a));//"null"
a = undefined;
console.log(String(a));//"undefined"

字符串拼接,隐式转换:

1
2
var a = 123;
console.log(a+'');//"123"

10.2.转为数值

Number()转为数值类型

  1. 字符串转数字
    字符串中是纯数字,直接将其转换为数字
    空字符串或全是空格,转换为0
    字符串中包含了非数字的内容,转为NaN
  2. 布尔值转数字:true —> 1,false —> 0
  3. null —> 0,undefined —> NaN

加上正负号隐式转换。规则和Number()一样,但是改变正负性,0也会带上负号:

1
2
3
4
5
6
7
var a = '123';
console.log(+a); //123
console.log(-a); //-123
console.log(typeof +a);//number
a = null
console.log(+a); // 0
console.log(-a); // -0

parseInt() 字符串转整数,布尔、null等非字符串、非数值类型都转为NaN,逐个字符转,碰见非数字字符就停止,没有提取到数值,就返回NaN。

1
2
3
4
5
6
7
parseInt('123abc'); //123
parseInt('abc123'); //NaN
parseInt(''); //NaN
parseInt(' '); //NaN
parseInt(null); //NaN
parseInt(undefined); //NaN
parseInt(true); //NaN

parseInt()会自动截断、舍弃小数,而Number()不会。

1
2
3
4
5
6
var a = parseInt('5.1') + parseInt(5.9);
console.log(a);//10
a = Number('5.1') + Number(5.9);
console.log(a);//11
a = parseInt(5.1 + 5.9);
console.log(a);//11

parseInt()可以多带一个进制参数,把数值看成对应进制,再转成10进制返回。无论parseInt()里面的进制参数是多少,最终的转换结果是十进制。

1
2
3
4
5
var a = parseInt('101', 2);
console.log(a);//5 二进制101就是十进制的5

a = parseInt('3', 2);
console.log(a);//二进制中没有3,所以转换失败返回NaN

parseFloat() 字符串转小数,与parseInt()相似。

1
2
3
parseFloat('123.321abc'); //123.321
parseFloat('12.1a3.321'); //12.1
parseFloat('12.13.321'); //12.13

10.3.转为Boolean

任何数据类型都可以转为 Boolean 布尔型。

  1. 数值型: 0 和 NaN的转为 false,其它都是 true
  2. 字符串: 空串转为 false,其它都是 true。全是空格的字符串,转换结果也是 true。”0”也是 true。
  3. null 和 undefined 都转为 false
  4. 引用数据类型都转为 true,因为地址永不为空或0。空数组[]和空对象{},也是 true
1
2
3
4
5
6
7
8
var a;
Boolean(a);//false,a未赋值,undefined
a = '';
Boolean(a);//false
a = [];
Boolean(a);//true
a = {};
Boolean(a);//true

使用!!或!显式转换为 Boolean 类型:

1
2
3
4
5
var a = 1;
a = !a
console.log(a);//false
a = !!2;
console.log(a);//true

isNaN()判断是否是非数值类型,任何不能直接转为数值类型的数据类型都可以让这个函数返回true

1
2
3
4
isNaN('123');//可以转为123,返回false
isNaN(null);//转为0,false
isNaN('123abc');//true
isNaN(undefined);//true

11.运算符和运算

各种编程语言的运算符功能都大差不差,只介绍JS中比较特殊的运算或特例。

浮点数值的最高精度是 17 位小数,会有丢失精度的风险,不要直接判断两个浮点数是否相等

Boolean + 数字 = 数字,true按1来算,false按0。
null + 数字 = 0 + 数字
undefined + 数字 = NaN
任何值和 NaN 运算的结果都是 NaN
任何非数值类型进行除加法以外的运算-、*、/、%时,都会自动用Number()转成数值类型再参与运算

1
2
3
4
true + 1; //2
null + 1; //1
var a = 2 - '1'; //1
var a = '2'/'1'; //2

非布尔值进行与或运算(&&、||)时,会先将其转换为布尔值,然后再运算,但返回结果是原值。

与运算 &&的返回结果:从左到右依次运行语句,找到第一个为 false 的值,返回原值,不再往后执行。如果所有的值都为 true,则返回最后一个值。

1
2
3
4
5
6
var a = '' && 123;
console.log(a);//'',空字符串转为布尔型为false,只执行第一条语句并返回原值
var a = [] && 0;
console.log(a);//0,[]转为布尔型为true,直接返回第二个语句的值
var a = "0" && 0 && 1;
console.log(a);//0

或运算 ||的返回结果:从左到右依次运行语句,找到第一个为 true 的值,返回原值,不再往后执行。如果所有的值都为 false,则返回最后一个值。

1
2
3
4
5
6
var a = '' || null;
console.log(a);//null
var a = 0 || [];
console.log(a);//[]
var a = "0" || 0 || 1;
console.log(a);//"0"

比较运算符 >、<、==、!= 等,得到的结果都是布尔值:要么是 true,要么是 false,非数值进行比较,会将其转换为数值类型。

特殊情况:如果参与比较的都是字符串,则不会将其转换为数字进行比较,比较的是字符串的Unicode编码。
比较字符编码时,从左到右逐位进行比较,一样大则继续比较下一位,直到比较出大小。

1
2
console.log('100' > 9 );//true,将'100'转为数值100进行比较
console.log('100' > '9' );//false,两个字符串逐位比较,9比1大,返回false

== 、=== ==进行比较时,会做隐式转换,将不同的数据类型,转为相同类型进行比较,而全等符号===不会进行转换,不同类型的数据比较一定是false。

1
2
3
4
5
6
7
8
9
10
11
12
console.log('1' == 1); //true
console.log('1' === 1); //false

console.log(1 == true); //true
console.log(1 === true); //false

console.log(undefined == null); //true
console.log('1a' > 1); // false。'1a'转成NaN

//NaN不和任何值相等,包括它本身
console.log(NaN == NaN); //false
console.log(NaN === NaN); //false

null与数字进行比较有一个Bug,不必在意,当特性就行:

1
2
3
4
5
6
console.log(null < 0); //false
console.log(null == 0); //false
console.log(null > 0); //false

console.log(null <= 0); //true。这是一个bug
console.log(null >= 0); //true。同上

日期大小比较

1
2
3
4
5
6
var date1 = new Date(2023, 3, 28)
console.log(date1);//Fri Sep 08 2023 00:00:00 GMT+0800 (中国标准时间)
var date2 = '2023-03-27';
var date3 = '2023/03/29';
console.log(date1 > date2);//false,date1和date2字符串格式很不相同,比较无意义
console.log(date3 > date2);//true,格式基本相同,分割位置一样,字符串逐位比较大小

12.if和switch

这部分各大语言也大差不差,只记录值得注意的点。

case的判断逻辑是===,不是==

switch中的default无论放到什么位置,都会等到所有case都不匹配再执行,但一般放在最后

当case或default匹配到一个值后,会执行后续所有的case,除非遇到break或执行到switch的末尾。

13.循环

这部分各大语言也大差不差,只记录值得注意的点。

break会立即终止离它最近的循环语句,continue跳过当次循环,继续下一次循环。

可以为循环语句创建一个label,来标识当前的循环。使用break、continue语句时,break label将会结束指定的循环,而不是最近的。

1
2
3
4
5
6
7
8
one: for (var i = 0; i < 100; i++) {
for (let j = 0; j < 100; j++) {
if(i>j) {
break one;
}
}
}
console.log(i);//1