(目录)
JavaScript 的组成
对于运行在浏览器上的 JS 来说,可以视为分成三个部分: 1、JS 核心语法 2、DOM API:浏览器提供的一组,操作页面元素的API 3、BOM API:浏览器提供的一组,操作浏览器窗口的API。
这两组 API,其实就是给 JS 核心语法 打下手的。 换句话说:你光有一个语法核心,缺少API,是很难实现一些有实际价值的程序的。 在后面,我讲的 Servlet 和 spring,这些就是复合框架。
第一个程序 hello world
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
alert("hello")
</script>
</body>
</html>
JavaScript 的书写形式
1、内嵌式
也就是把
js 写到 script 标签中
我们下面的讲解主要就是用这一种方式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
alert("hello")
</script>
</body>
</html>
2、行内式
把 js 写到 HTML 元素的内部
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button onclick="alert('heeeeee')">
按钮
</button>
</body>
</html>
3、外部式
把 js 写到一个单独的 .js 文件中,再通过
scrip <> 标签引入
。
这种方式,是实际开发中最长用的一种引入 js 代码的方式。
因为这种方式,可以把 js 代码分成多个文件来去分别表示。
拓展:
如果
script 标签中,既有 src 属性,内部又有 JS 代码
,会怎么样?
就会导致里面的代码不会被执行的效果。
需要分开写👇
JS 输入输出
输入: prompt
弹出一个输入框
这个操作,类似 Java 语言的 Scanner 。
但是在实际开发中,很少会用到,比较小众。
因为我们可以借助 input 标签进行输入,借助用户点击按钮也能进行输入。
输出: alert
输出:console.log
在控制台打印一个 日志
JavaScript 语法
变量
定义变量
格式:
var 变量名 = 初始值;
你会发现:不管你创建的变量是什么类型,此时都是统一使用 var 这个关键字来表示的。
至于你变量具体是什么类型,取决于初始化的值是什么类型。
JS 是不区分 整形 和 浮点型数据的。 统一认为是数字类型的数据。 另外,JS的变量可以不初始化,但是不初始化的时候,变量是一个特殊的值:“undefined”,类型也是 undefined。
但是!你不能创建一个未初始化的变量,同时指定它是一个 字符串 / 数字 / 数组 类型。 这种操作是不被允许的!!!!
使用变量
var、 let
如果
a 本来是一个 数字类型,在赋值的时候,可以给它赋一个数字类型,也可以赋一个字符
串类型,也可以赋一个数组类型…
总得来说,你可以
给它赋任意类型的数据
此时,a 变量的类型,就会随之发生改变
比如: a 是数字类型的变量,我给它赋一个 字符串的数据,这是可以成功的 而且 a 变量的类型 也变成了字符串类型
因此,得出一个结论:变量的类型,可以在运行的过程中,随着赋值而发生改变
这种行为,称为
“动态类型”’
。 像 Java 这种语言,是不支持这种 运行时 类型发生改变的情况
Java的这种行为,被称为“静态类型”
支持“动态类型”的编程语言还有:Python,PHP,Ruby… 支持“静态类型”的编程语言还有:C/C++,Go,Rust… 有的人可能基础扎实,认为 Java 也是支持 动态类型。因为 Java 里面存在着 很多类型转换的方法。
注意!如果你有这种想法,那么你的Java基础肯定是有缺陷的!
你要明白Java类型转换,是将一个类型的值,转换后(旧的变量类型没有发生改变),赋给一个新的,并且
与转换后的数据类型是对应的变量对象。【不然是进行转换的,必须类型是对应的】 而 JS 初始化 确定了 var 的类型,将一个与初始化指定类型,不相符的类型数据,强行塞给它。
非但没有出现类型的排斥,反而还把 var 初始化指定的数值类型给改变了!!
由此,就能看出
js 和 java ,关于 变量修改的区别了
从侧面来思考,为什么写 var,而不是去写一个具体类型?
因为 它的类型老变嘛,你一开始是整形,回头它就给一个 字符串。
整形 对 字符串,不就很尴尬嘛……
那就引出这个问题 : 动态类型 和 静态类型 谁更好?
其实最开始的时候,这个是有争议的。 但是,随着时间的推移,至现今。 在 2022 年,这样视角来看待,静态类型的阵营完胜!
现在业界基本达成共识,认为静态类型比动态类型更好!
因为
静态类型,编译器就可以做更多的检查
,让有些 问题/错误 被提前发现了。 开发工具(IDE),也可以基于类型做更多的分析,提供更加丰富的支持。 当然不是说,动态类型就没有优点!动态类型的优点: 1、代码更灵活。
2、用最少的代码,解决复杂的问题
比如: 写一个函数,就可以同时支持多种不同的类型参数 完全不需要“重载 / 泛型”,这样语法 因为 JS 天生就自带这种功能。 虽然有这个优势,,但是整体来说,利大于弊 静态类型,哪怕说我多写一点 泛型 / 重载 类型的代码,也不要紧。
因为我的编译器都有充分的检查,所以我写完之后,也不会特别慌。
但是要是动态类型的话,很可能你写完代码,都不知道它对不对。
因为无论你输入什么样的参数,它都能接收。
因此,只要你一个参数错了,可能你就要在电脑面前坐几天。
随着时间推移,关于 JS 变量的类型,出现了一个新的类型 let
从效果上来看,var 和 let 的效果是一样的。
但是我们
更倾向于使用 let
,为什么呢?
这是因为 var 是 旧版本(早期的设计),有很多的地方,其实是违背直觉的!
比如,下面的这个例子
得出结论:
var定义的变量,并不会收到大括号的限制。【作用域不会被限制】
数据类型
JS 中内置的几种类型
number: 数字. 不区分整数和小数.
boolean: true 真, false 假.
string: 字符串类型.
undefined: 只有唯一的值 undefined. 表示未定义的值.
null: 只有唯一的值 null. 表示空值
上面三个类型,这个相比很熟悉。
而下面的两个类型,就是独属于 js 了。
undefined:可以作为一个类型,同时表示唯一的值,也是 undefined。表示这个变量没有被定义;或者这个变量定义了,但是没有赋予初值的情况。
null:表示控制,虽然也是表示唯一的值,但是与 undefined 还有一定区别的。
而且这个空值 和 Java中 空值也是不一样的
Java中的空值,是一个 Object 类型的。
而 JS 的空值的类型,和 undefined的情况一样,与表示的值一样,也是null类型。
数字类型
像下面这种,
8,16,2进制数
let a = 07; // 八进制整数, 以 0 开头
let b = 0xa; // 十六进制整数, 以 0x 开头
let c = 0b10; // 二进制整数, 以 0b 开头
特殊数字值
Infinity: 无穷大,
大于任何数字. 表示数字已经超过了 JS 能表示的范围.-Infinity: 负无穷大
, 小于任何数字. 表示数字已经超过了 JS 能表示的范围.NaN
: 表示当前的结果不是一个数字.
什么时候会出现 NaN ?
如果 运算结果,得到的不是数字的值,就会出现 NaN。
另外, JS 中 提供了一个
isNaN
的方法,用于判断 得到数据是否是一个数字。返回数值类型 是 布尔类型。
如果是数字,返回false
反之,返回true
字符串类型
字符串类型,这里的很多操作和Java是类似的。
字符串 可以通过单引号定义,也可以通过双引号定义
如果字符串本身就包含了 引号,这种情况是被允许的。
这个时候,就可以通过 单双引号 灵活搭配的形式,来避免使用
转义字符
JS中的转义字符,不仅仅是 +单双引号,还有其它的转义字符,也是支持的。 像 \t(水平制表符),\n(换行符),\f(换页符)…这些转义字符,也是同样支持的。
字符串求长度
JS 求字符串长度,是通过 length 属性
Java 里面求字符串长度,是通过 length() 方法。
字符串拼接
通过直接使用 + 号,拼接
boolean 布尔类型
JS 中的 布尔类型,会当成 0 和 1 来处理
Java的 boolean 类型,取值能使 false 和 true
上面的代码中,js 把 true 当成 1 来处理了
这种设定方式,认为其实并不科学
!
其中涉及到 隐式类型转换
,因为 隐式类型转换 本就是不科学的设定。
拓展:
如果一个编程语言,越支持隐式类型转换,就认为类型越弱。
如果一个编程语言,越不支持隐式类型转换,就认为类型越强。
Java,Go,Python 认为是强类型的编程语言
C,JS,PHP 认为是弱类型的编程语言
注意:
静态类型 / 动态类型 vs 强类型 / 弱类型
这两者是没有关系的,是两个不同的体系
undefined 未定义数据类型
是 JS 的一种特殊情况
是值未定义,是非法的
undefined 这个类型,就只有 undefined 这一个值
null 空值类型
null 表示 当前值没有意义 , 是合法的
运算符
JavaScript 中的运算符和 Java/C++ 用法基本相同. 此处不做详细介绍了
比较运算符 - 不同点
先说, == 和 != 这一组。
只是比较两个变量的值,不比较 两个变量的类型。
如果两个变量能够通过隐式类型转换,转换相同的值,
那么,此时就认为 两个变量 是相等的。
再来看,=== 和 !== 这一组。
既要比较 两个变量的值,又要比较两个变量的类型。
如果类型不相同,就直接认为两个变量不相等。
比较的过程中,就不存在隐式类型转换的说法。
逻辑运算符 - 不同点
用于计算多个 boolean 表达式的值.
&& 与: 一假则假 || 或: 一真则真 !: 非
&& || ,这两个行为,和Java中 && 和 || 差别就挺大的。
Java 中的 && 和 || 行为非常简单! 效果就是返回一个布尔类型的值: true,或者 false。 JS 中的 && 和 || ,返回是其中的表达式。
数组
创建数组
1、使用 new 关键字创建
和 Java 创建数组很像,但不完全一样。 更像 Java中创建对象的写法。 注意!这种写法
很少用
,因为比较麻烦。
2、使用字面量方式创建
JS定义一个数组的时候,不需要声明数组类型,以及容量。
JS 针对数组初始化,使用的是中括号,将元素括起来。
而且,我们 JS 数组,还可以像下面这么写。
打印数组
JS 中直接通过 console.log
就可以打印数组的内容。
获取数组元素
JS 也是通过下标来获取元素
下标也是从 0 开始计算
注意:
在Java中要求数组下标,是 0 - 数组长度-1。 如果 超出这个范围,就会抛出一个数组越界异常。 但是,在 JS 中,就不是这样了
总得来说,JS 的数组,就不是一个正经的数组。
除了
能接数组的活,还能接 Map 的活(表示键值对)
进一步的来说,
与其说数组是 Map,不如说是一个“对象”
在JS里,是可以在运行时,给对象新增属性的。
arr[‘hello’] = 10,这个操作其实就是在给 arr 这个对象,新增了一个属性。
属性的名字是hello,属性的值是 10
获取数组的长度
通过
.length
就能获取到
数组中新增元素 push
最常见的插入操作,是通过
push 方法
,能够给 数组末尾 追加一个元素。 就相当于 Java 中 ArrayList 里面的 add 操作。
删除数组中的元素 splice
JS中删除数组中的元素,叫
splice
方法,准确的说是针对 数组中的某讴歌片段,进行替换所以,这个方法既可以用来
插入元素,又可以用来删除元素
删除操作
替换操作
函数
语法格式
// 创建函数/函数声明/函数定义
function 函数名(形参列表) {
函数体
return 返回值;
}
// 函数调用
函数名(实参列表) // 不考虑返回值
返回值 = 函数名(实参列表) // 考虑返回值
注意:
在 创建函数/函数声明/函数定义 的时候,形参列表不用写形参类型。
其实也很好理解,因为
JS 是动态类型语言
,写类型不好使!形参的类型,完全取决于程序运行时,你给函数传的什么参数。 同样的, 函数也不必写返回值类型,因为没意义
不带参数函数定义、调用:
带参数函数定义、调用:
函数表达式
所谓的函数表达式,其实就是把一个函数赋值给一个变量了。
使用变量调用函数
类似C语言中的函数指针
上述代码还可以简化 , 定义赋值两个操作 一起
作用域
其实在
ES6 之前,就没有 let 这个东西。
let 是在 ES6之后 才引入的。
也就是说,在ES6版本之前,只有 var。
即 变量 只会被函数划分作用域,而函数里面的代码块,是不会影响到作用域的。
也就是说,
在ES6之前,只有 全局 + 函数 作用域,没有块级作用域(大括号挂起来的区域)。
JS 支持 逐级向上查找,找不到报错 undefined
对象
基本概念
对象,就是一些属性 和 方法的集合。
这个概念,与传统意义上的Java对象的概念是类似的。 但是有一个比较大的区别。
在 Java中,我们的对象是需要先有类,然后针对类进行实例化才能产生对象。
等于就是说,类就是一个模具,可以批量生产相同规格的产物。而在 JS 中,对象 是不依托于 类的。
就是说:在 JS 中,无需借助类,就能创建一个对象。 另外,Java 中的类,可以视为是一种 自定义类型的类。例如: Cat 类 和 Dog 类,是两个不同类型。
在 JS 中,所有的对象,都是一个类型【object类型】
创建对象 && 对象的使用
通过 { } 的方式,就可以创建对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// {} 就是 一个 匿名对象
// 将这个对象赋予 变量 student
let student = {
// 属性
name: 'cxk',
age: 20,
height: 178,
weiight: 120,
// 方法
sing: function(){
console.log('kunkun')
},
jump: function(){
console.log('dance');
},
};
</script>
</body>
在 js 对象中,我们可以很直观的看到 js的对象是有方法 和 变量。
js的对象,与其说是一个对象,不如说是一个 键值对 结构 更加合适
js对象中的每个属性和方法,其实都是通过“键值对” 这样的方式来表达的
{} 表示这是一个对象
键值对之间,采用 逗号 进行分割。 键和值之间,采用 冒号 进行分割。 定义出这样的一个对象之后,我们就可以采用
student.属性名 / 方法名 的方式 来进行访问
。
上面创建的对象的方式,是属于 使用字面量创建对象
在JS 中,还有两种创建对象的方式。
第二种: 使用 new Object 创建对象
通过创建一个 Object 的空对象,再把创建好的对象赋予 一个变量。
通过
变量名.属性名 = 值
的方式,进行动态创建对象属性
。 在 JS 中,一个对象里面有哪些成员,也是动态可以改变的。也就是说,假设本来 这个对象只有 2个属性(name 和 age),但是执行代码之后,感觉还可以加上一些属
性,
通过 变量名.属性名 = 值 的方式,就可以添加新的属性
更不用说,可以去修改属性的值了。
let student = new Object(); // 和创建数组类似
student.name = "蔡徐坤";
student.height = 175;
student['weight'] = 170;
student.sayHello = function () {
console.log("hello");
}
第三种:使用 构造函数 创建对象。
当前我们所说的构造函数,其实是一种特殊的函数
该构造函数,目的是为了
批量的创建出一组 类似的对象
function 构造函数名(形参) {
this.属性 = 值;
this.方法 = function...
}
let obj = new 构造函数名(实参);
注意!对象里面 的 属性和方法,是通过 this. 的方式来创建的。 换个说法,当我们看到函数内部,通过 this.方式来创建属性和方法的时候,此时这个函数大概率就是构造函数了。 使用的时候, new + 构造函数名 +(实参)的方式来使用的
这个就跟Java的带参的构造方法很相似。