JavaScript 是互联网上最流行的脚本语言,这门语言可用于 HTML 和 web,更可广泛用于服务器、PC、笔记本电脑、平板电脑和智能手机等设备。
JavaScript 是脚本语言
JavaScript 是一种轻量级的编程语言。
JavaScript 是可插入 HTML 页面的编程代码。
JavaScript 插入 HTML 页面后,可由所有的现代浏览器执行。
JavaScript 是 web 开发人员必须学习的 3 门语言中的一门:
ECMAScript
:规定了js基础语法核心知识。
比如:变量、分支语句、循环语句、对象等等
Web APIs
:
JavaScript 程序不能独立运行,它需要被嵌入 HTML 中,然后浏览器才能执行
JavaScript 代码。通过 script
标签将 JavaScript 代码引入到 HTML 中,有三种方式:
通过 script
标签包裹 JavaScript 代码
<body>
<script>
alert('欢迎学习JavaScript技术!')
script>
body>
一般将 JavaScript 代码写在独立的以 .js 结尾的文件中,然后通过 script
标签的 src
属性引入
// demo.js
document.write('一起来学习JavaScript技术吧!')
<body>
<script src="demo.js">script>
body>
如果 script 标签使用 src 属性引入了某 .js 文件,那么 标签的代码会被忽略!!!如下代码所示:
<body>
<script src="demo.js">
// 此处的代码会被忽略掉!!!!
alert(666)
script>
body>
<body>
<button onclick="alert('哈哈~逗你玩')">点我月薪过万~button>
body>
通过注释可以屏蔽代码被执行或者添加备注信息,JavaScript 支持两种形式注释语法:
使用 //
注释单行代码
<body>
<script>
// 这种是单行注释的语法
// 一次只能注释一行
// 可以重复注释
document.write('欢迎学习JavaScript技术!')
script>
body>
使用 /* */
注释多行代码
<body>
<script>
/* 这种的是多行注释的语法 */
/*
更常见的多行注释是这种写法
这些可以任意换行
多少行都可以
*/
document.write('欢迎学习JavaScript技术!')
script>
body>
注:编辑器中单行注释的快捷键为
ctrl + /
在 JavaScript 中 ;
代表一段代码的结束,多数情况下可以省略 ;
使用回车(enter)替代。
<body>
<script>
alert(1);
alert(2);
alert(1)
alert(2)
script>
body>
实际开发中有许多人主张书写 JavaScript 代码时省略结束符 ;
输出和输入也可理解为人和计算机的交互,用户通过键盘、鼠标等向计算机输入信息,计算机处理后再展示结果给用户,这便是一次输入和输出的过程。
举例说明:如按键盘上的方向键,向上/下键可以滚动页面,按向上/下键这个动作叫作输入,页面发生了滚动了这便叫输出。
JavaScript 可以接收用户的输入,然后再将输入的结果输出:
alert()
、document.wirte()
以数字为例,向 alert()
或 document.write()
输入任意数字,他都会以弹窗形式或网页形式展示(输出)给用户。
向 prompt()
输入任意内容会以弹窗形式出现在浏览器中,一般提示用户输入一些内容。
<body>
<script>
// 1. 输入的任意数字,都会以弹窗形式展示
document.write('要输出的内容')
alert('要输出的内容')
// 2. 以弹窗形式提示用户输入姓名,注意这里的文字使用英文的引号
prompt('请输入您的姓名:')
script>
body>
变量是计算机中用来存储数据的“容器”,它可以让计算机变得有记忆,通俗的理解变量就是使用【某个符号】来代表【某个具体的数值】(数据)
<script>
// x 符号代表了 5 这个数值
x = 5
// y 符号代表了 6 这个数值
y = 6
//举例: 在 JavaScript 中使用变量可以将某个数据(数值)记录下来!
// 将用户输入的内容保存在 num 这个变量(容器)中
num = prompt('请输入一数字!')
// 通过 num 变量(容器)将用户输入的内容输出出来
alert(num)
document.write(num)
script>
声明(定义)变量有两部分构成:声明关键字、变量名(标识)
<body>
<script>
// let 变量名
// 声明(定义)变量有两部分构成:声明关键字、变量名(标识)
// let 即关键字,所谓关键字是系统提供的专门用来声明(定义)变量的词语
// age 即变量的名称,也叫标识符
let age
script>
body>
关键字是 JavaScript 中内置的一些英文词汇(单词或缩写),它们代表某些特定的含义,如 let
的含义是声明变量的,看到 let
后就可想到这行代码的意思是在声明变量,如 let age;
let
和 var
都是 JavaScript 中的声明变量的关键字,推荐使用 let
声明变量!!!
声明(定义)变量相当于创造了一个空的“容器”,通过赋值向这个容器中添加数据。
<body>
<script>
// 声明(定义)变量有两部分构成:声明关键字、变量名(标识)
// let 即关键字,所谓关键字是系统提供的专门用来声明(定义)变量的词语
// age 即变量的名称,也叫标识符
let age
// 赋值,将 18 这个数据存入了 age 这个“容器”中
age = 18
// 这样 age 的值就成了 18
document.write(age)
// 也可以声明和赋值同时进行
let str = 'hello world!'
alert(str)
script>
body>
JavaScript 使用专门的关键字 let
和 var
来声明(定义)变量,在使用时需要注意一些细节:
以下是使用 let
时的注意事项:
以下是使用 var
时的注意事项:
大部分情况使用 let
和 var
区别不大,但是 let
相较 var
更严谨,因此推荐使用 let
。
关于变量的名称(标识符)有一系列的规则需要遵守:
注:所谓关键字是指 JavaScript 内部使用的词语,如 let
和var
,保留字是指 JavaScript 内部目前没有使用的词语,但是将来可能会使用词语。
<body>
<script>
let age = 18 // 正确
let age1 = 18 // 正确
let _age = 18 // 正确
// let 1age = 18 // 错误,不可以数字开头
let $age = 18 // 正确
let Age = 24 // 正确,它与小写的 age 是不同的变量
// let let = 18 // 错误,let 是关键字
let int = 123 // 不推荐,int 是保留字
script>
body>
概念:使用 const 声明的变量称为“常量”。
使用场景:当某个变量永远不会改变的时候,就可以使用 const 来声明,而不是let。
命名规范:和变量一致
const PI = 3.14
注意: 常量不允许重新赋值,声明的时候必须赋值(初始化)
值类型(基本类型): 字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol。
引用数据类型(对象类型):对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)。
注:Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。
计算机世界中的万事万物都是数据。
计算机程序可以处理大量的数据,为了方便数据的管理,将数据分成了不同的类型:
注:通过 typeof 关键字检测数据类型
<body>
<script>
// 检测 1 是什么类型数据,结果为 number
document.write(typeof 1)
script>
body>
即我们数学中学习到的数字,可以是整数、小数、正数、负数
<body>
<script>
let score = 100 // 正整数
let price = 12.345 // 小数
let temperature = -40 // 负数
document.write(typeof score) // 结果为 number
document.write(typeof price) // 结果为 number
document.write(typeof temperature) // 结果为 number
script>
body>
JavaScript 中的数字类型与数学中的数字是一样的,分为正数、负数、小数等。
通过单引号( ''
) 、双引号( ""
)或反引号包裹的数据都叫字符串,单引号和双引号没有本质上的区别,推荐使用单引号。
注意事项:
\
,输出单引号或双引号<body>
<script>
let user_name = '小明' // 使用单引号
let gender = "男" // 使用双引号
let str = '123' // 看上去是数字,但是用引号包裹了就成了字符串了
let str1 = '' // 这种情况叫空字符串
documeent.write(typeof user_name) // 结果为 string
documeent.write(typeof gender) // 结果为 string
documeent.write(typeof str) // 结果为 string
script>
body>
字符串拼接:数字相加,字符相连
<body>
<script>
let number = 1 + 1
document.write(number) // 2
let age = '刘德华' + '40岁了'
document.write(age) // 刘德华40岁了
let age1 = 50
document.write('成龙今年' + age1 + '岁了') // 成龙今年50岁了
script>
body>
表示肯定或否定时在计算机中对应的是布尔类型数据,它有两个固定的值 true
和 false
,表示肯定的数据用 true
,表示否定的数据用 false
。
<body>
<script>
let isCool = true // 是
isCool = false // 否
document.write(typeof isCool) // 结果为 boolean
script>
body>
未定义是比较特殊的类型,只有一个值 undefined,只声明变量,不赋值的情况下,变量的默认值为 undefined,一般很少【直接】为某个变量赋值为 undefined。
<body>
<script>
// 只声明了变量,并末赋值
let tmp;
document.write(typeof tmp) // 结果为 undefined
script>
body>
null:空类型 表示内容为空
null 和 undefined 区别:
undefined 表示没有赋值
null 表示赋值了,但是内容为空
注:JavaScript 中变量的值决定了变量的数据类型。
某些运算符被执行时,系统内部自动将数据类型进行转换,这种转换称为隐式转换。
<body>
<script>
console.log(11 + 11) // 22
// + 号两边只要有一个是字符串,都会把另外一个转换成字符串
console.log('11' + 11) // 1111
console.log(5 - 5) // 0
// 除了 + 号以外的算术运算符,比如:- 、 * 、 / 等都会把数据转换为数字类型
console.log('5' - 5) //0
// + 号作为正号解析可以转换为数字类型
console.log(typeof +'123') // number
console.log(+'22' + 22) // 44
// 任何数据和字符串相加结果都是字符串
script>
body>
编写程序时过度依靠系统内部的隐式转换是不严禁的,因为隐式转换规律并不清晰,大多是靠经验总结的规律。为了避免因隐式转换带来的问题,通常根逻辑需要对数据进行显示转换。
通过 Number
显示转换成数值类型,当转换失败时结果为 NaN
(Not a Number)即不是一个数字。
<body>
<script>
let t = '12'
let f = 8
// 显式将字符串 12 转换成数值 12
t = Number(t)
// 检测转换后的类型
// console.log(typeof t);
console.log(t + f) // 结果为 20
// 并不是所有的值都可以被转成数值类型
let str = 'hello'
// 将 hello 转成数值是不现实的,当无法转换成
// 数值时,得到的结果为 NaN (Not a Number)
console.log(Number(str))
script>
body>
只保留整数 parseInt(数据)
<body>
<script>
console.log(parseInt(12.33)) // 12
script>
body>
可以保留小数 parseFloat(数据)
<body>
<script>
console.log(parseFloat(12.66)) //12.66
script>
body>
语法:${变量}
<body>
<script>
// 模版字符串
let age = 18
document.write(`我今年${age}岁了`)
script>
body>
数字是用来计算的,比如:乘法 * 、除法 / 、加法 + 、减法 - 等等,所以经常和算术运算符一起。
算术运算符:也叫数学运算符,主要包括加、减、乘、除、取余(求模)等
运算符 | 作用 |
---|---|
+ | 求和 |
- | 求差 |
* | 求积 |
/ | 求商 |
% | 取模(取余数),开发中经常用于作为某个数字是否被整除 |
注意:在计算失败时,显示的结果是 NaN (not a number)
// 算术运算符
console.log(1 + 2 * 3 / 2) // 4
let num = 10
console.log(num + 10) // 20
console.log(num + num) // 20
// 1. 取模(取余数) 使用场景: 用来判断某个数是否能够被整除
console.log(4 % 2) // 0
console.log(6 % 3) // 0
console.log(5 % 3) // 2
console.log(3 % 5) // 3
// 2. 注意事项 : 如果我们计算失败,则返回的结果是 NaN (not a number)
console.log('刘德华' - 2) // NaN
console.log('刘德华' * 2) // NaN
console.log('刘德华' + 2) // 刘德华2
赋值运算符:对变量进行赋值的运算符
= 将等号右边的值赋予给左边, 要求左边必须是一个容器
运算符 | 作用 |
---|---|
+= | 加法赋值 |
-+ | 减法赋值 |
*= | 乘法赋值 |
/= | 除法赋值 |
%= | 取余赋值 |
let num = 1
// num = num + 1
// 采取赋值运算符
// num += 1
num += 3
console.log(num) // 4
符号 | 作用 | 说明 |
---|---|---|
++ | 自增 | 变量自身的值加1,例如: x++ |
– | 自减 | 变量自身的值减1,例如: x– |
自增和自减经常用于计数来使用
// 自增:-- (让变量的值 +1)
let i = 1
i++
console.log(i) // 2
// 自减:-- (让变量的值 -1)
let num = 4
num--
console.log(num) // 3
注意:
- 只有变量能够使用自增和自减运算符
- ++、-- 可以在变量前面也可以在变量后面,比如: x++ 或者 ++x
自增运算符分为前置自增和后置自增
let age1 = 1
++age1
console.log(age1) // 2
let age2 = 1
age2++
console.log(age2) // 2
前置自增和后置自增单独使用时二者并没有差别,都是每执行1次,当前变量数值加1
但参与运算时,两者就有区别
// 前置自增:先自加再使用(记忆口诀:++在前 先加)
let num1 = 1
console.log(++num1 + 2) // 4 (此时num1 是2, num1 先自加1变成2之后, 再跟后面的2相加)
// 后置自增:先使用再自加(记忆口诀:++在后 后加)
let num2 = 1
console.log(num2++ + 2) // 3 (此时num2 是1, num2 先和后面的2相加, 先运算步骤完成之后, num2再自加1, 变成2)
// 面试题:
let a = 1
/*
1. a++还是1,但a完成第一步后,就会自加1,此时a就变为2了
2. ++a就是a再自加1,就是2 + 1 = 3,此时a就变为3了
3. 所以就是 1 + 3 + 3 = 7
*/
console.log(a++ + ++a + a) // 7
使用场景:比较两个数据大小、是否相等,根据比较结果返回一个布尔值(true / false)
运算符 | 作用 |
---|---|
> | 左边是否大于右边 |
< | 左边是否小于右边 |
>= | 左边是否大于或等于右边 |
<= | 左边是否小于或等于右边 |
=== | 左右两边是否类型 和值 都相等(重点) |
== | 左右两边值 是否相等 |
!= | 左右值不相等 |
!== | 左右两边是否不全等 |
console.log(3 > 5) // false
console.log(3 >= 3) // true
console.log(2 == 2) // true
// 比较运算符有隐式转换 把'2' 转换为 2 双等号 只判断值
console.log(2 == '2') // true
console.log(undefined === null) // false
// === 全等 判断 值 和 数据类型都一样才行
console.log(2 === '2') // false
console.log(NaN === NaN) // NaN 不等于任何人,包括他自己
console.log(2 !== '2') // true
console.log(2 != '2') // false
console.log('a' < 'b') // true
console.log('aa' < 'ab') // true
console.log('aa' < 'aac') // true
1.字符串比较,是比较的字符对应的ASCII码。从左往右依次比较,如果第一位一样再比较第二位,以此类推
2.NaN不等于任何值,包括它本身。涉及到 “NaN” 都是false
3.尽量不要比较小数,因为小数有精度问题
4.不同类型之间比较会发生隐式转换。最终把数据隐式转换转成number类型再比较
使用场景:可以把多个布尔值放到一起运算,最终返回一个布尔值
符号 | 名称 | 日常读法 | 特点 | 口诀 |
---|---|---|---|---|
&& | 逻辑与 | 并且 | 符号两边有一个假的结果为假 | 一假则假 |
|| | 逻辑或 | 或者 | 符号两边有一个真的结果为真 | 一真则真 |
! | 逻辑非 | 取反 | true变false false变true | 真变假,假变真 |
// 逻辑与 && (并且) 符号两边都为true,结果才为true。 口诀:一假则假
console.log(true && true) // true
console.log(true && false) // false
// 逻辑或 || (或者) 符号两边有一个true就为true。 口诀:一真则真
console.log(true || false) // true
// 逻辑非 ! (取反) true变false,false变true。 口诀:真变假,假变真
console.log(!true) // false
运算符优先级:
- 一元运算符里面的逻辑非(!)优先级很高
- 逻辑与(&&)比逻辑或(||)优先级高
// false true false
let a = 3 > 5 && 2 < 7 && 3 == 4
console.log(a); // false
// true true true
let b = 3 <= 4 || 3 > 1 || 3 != 2
console.log(b); // true
// false
let c = 2 === "2"
console.log(c); // false
// true false
let d = !c || b && a
console.log(d); // true
逻辑运算符优先级: !> && > ||
表达式:表达式是可以被求值的代码,JavaScript 引擎会将其计算出一个结果。
let num = 3 + 4
语句:语句是一段可以执行的代码。
比如: prompt() 可以弹出一个输入框,还有 if语句 for 循环语句等等
prompt()
程序三大流程控制语句:
分支语句可以根据条件判定真假,来选择性的执行想要的代码
分支语句包含:
语法:
if(条件表达式) {
// 满足条件要执行的语句
}
小括号内的条件结果是布尔值,为 true 时,进入大括号里执行代码;为false,则不执行大括号里面代码
小括号内的结果若不是布尔类型时,会发生类型转换为布尔值,类似Boolean()
如果大括号只有一个语句,大括号可以省略,但是,不提倡这么做
// 当小括号内的条件为true时,进入大括号里执行代码
// 小括号内的结果若不是布尔类型时,会发生隐式转换转为布尔类型
if (true) {
console.log('执行代码')
}
// 0 为假,其他的所有数字都是真,包括负数、小数等。假就不会执行代码
if (0) {
console.log('执行代码')
}
// 空字符串 '' 也是假
if ('') {
console.log('执行代码')
}
// 输入成绩,判断成绩是否优秀
let num = +prompt('请输入成绩:')
if (num > 90) {
alert('您的成绩为优秀!')
}
如果有两个条件的时候,可以使用 if else 双分支语句
if (条件表达式){
// 满足条件要执行的语句
} else {
// 不满足条件要执行的语句
}
例如:
<script>
// 1. 用户输入
let uname = prompt('请输入用户名:')
let pwd = prompt('请输入密码:')
// 2. 判断输出
if (uname === 'admin' && pwd === '123456') {
alert('恭喜登录成功')
} else {
alert('用户名或者密码错误')
}
</script>
使用场景: 适合于有多个条件的时候
/*
f多分支语句:
if (条件1) { // 先判断条件1,若满足条件1就执行代码1,其他不执行
代码1
} else if (条件2) { // 若不满足则向下判断条件2,满足条件2执行代码2,其他不执行
代码2
} else if (条件3) { // 若依然不满足继续往下判断,依次类推
代码3
} else { // ...
...
代码n // 若以上条件都不满足,执行else里的代码n
}
*/
// 判断成绩
let result = +prompt('请输入成绩:')
if (result > 90) {
alert('您的成绩为优秀!')
} else if (result >= 70 && result <= 90) {
alert('您的成绩为良好!')
} else if (result >= 60 && result < 70) {
alert('您的成绩为及格!')
} else {
alert('您的成绩为不及格!')
}
使用场景: 一些简单的双分支,可以使用 三元运算符(三元表达式),写起来比 if else双分支 更简单
符号:? 与 : 配合使用
语法:
条件 ? 满足条件要执行的代码 : 不满足条件执行的代码
例如:
// 三元运算符(三元表达式)
// 1. 语法格式
// 条件 ? 表达式1 : 表达式2
// 2. 执行过程
// 2.1 如果条件为真,则执行表达式1
// 2.2 如果条件为假,则执行表达式2
// 3. 验证
// 5 > 3 ? '真的' : '假的'
console.log(5 < 3 ? '真的' : '假的')
// 判断最大数
let num1 = +prompt('请输入第一个数:')
let num2 = +prompt('请输入第二个数:')
console.log(num1 > num2 ? num1 : num2)
// 1. 用户输入
let num = prompt('请您输入一个数字:')
// 2. 判断输出- 小于10才补0
// num = num < 10 ? 0 + num : num
num = num >= 10 ? num : 0 + num
alert(num)
使用场景: 适合于有多个条件的时候,也属于分支语句,大部分情况下和 if多分支语句 功能相同
注意:
例如:
// switch分支语句
// 1. 语法
// switch (表达式) {
// case 值1:
// 代码1
// break
// case 值2:
// 代码2
// break
// ...
// default:
// 代码n
// }
// 简单计算器
let num1 = +prompt('请输入第一个数:')
let num2 = +prompt('请输入第二个数:')
let operator = prompt('请输入运算符:')
switch (operator) {
case '+':
alert(`结果为:${num1 + num2}`)
break
case '-':
alert(`结果为:${num1 - num2}`)
break
case '*':
alert(`结果为:${num1 * num2}`)
break
case '/':
alert(`结果为:${num1 / num2}`)
break
default:
alert(`请输入+ - * /`)
}
if 多分支语句和 switch的区别:
共同点
- 都能实现多分支选择, 多选1
- 大部分情况下可以互换
区别:
- switch…case语句通常处理case为比较确定值的情况,而if…else…语句更加灵活,通常用于范围判断(大于,等于某个范围)。
- switch 语句进行判断后直接执行到程序的语句,效率更高,而if…else语句有几种判断条件,就得判断多少次
- switch 一定要注意 必须是 === 全等,一定注意 数据类型,同时注意break否则会有穿透效果
- 结论:
- 当分支比较少时,if…else语句执行效率高。
- 当分支比较多时,switch语句执行效率高,而且结构更清晰。
作用: 学习时可以帮助更好的理解代码运行,工作时可以更快找到bug
浏览器打开调试界面
断点: 在某句代码上加的标记就叫断点,当程序执行到这句有标记的代码时会暂停下来
使用场景:重复执行 指定的一段代码。
while : 在…. 期间, 所以 while循环 就是在满足条件期间,重复执行某些代码。
语法:
while (条件表达式) {
// 循环体
}
/*
释义:
1. 跟if语句很像,都要满足小括号里的条件为true才会进入 循环体 执行代码
2. while大括号里代码执行完毕后不会跳出,而是继续回到小括号里判断条件是否满足。若满足又执行大括号里的代码,然后再回到小括号判断条件,直到小括号内条件不满足,即跳出
*/
例如:
// while循环: 重复执行代码
// 页面中打印输出10句“月薪过万”
let i = 1
while (i <= 10) {
document.write('月薪过万
')
i++ // 这里千万不要忘了变量自增否则造成死循环
}
循环三要素:
1.初始值 (经常用变量)
2.终止条件(没有终止条件,循环会一直执行,造成死循环)
3.变量的变化量(用自增或者自减)
例如:
<script>
// 1. 变量的起始值
// let i = 1
2. 终止条件
// while (i <= 3) {
// document.write('我要循环三次
')
// 3. 变量的变化量
// i++
// }
// 1. 变量的起始值
let end = +prompt('请输入次数:')
let i = 1
// 2. 终止条件
while (i <= end) {
document.write('我要循环三次
')
// 3. 变量的变化量
i++
}
</script>
break
退出整个循环,一般用于结果已经得到, 后续的循环不需要的时候可以使用
continue
退出本次循环,一般用于排除或者跳过某一个选项的时候, 可以使用continue
<script>
// break 退出循环
let a = 1
while (a <= 5) {
if (a === 3) {
break
}
document.write(`${a}
`)
a++
}
// continue 结束本次循环,继续下次循环
let b = 1
while (b <= 5) {
if (b === 3) {
b++
continue
}
document.write(`${b}
`)
b++
}
</script>
1.while(true) 来构造“无限”循环,需要使用break退出循环。(常用)
2.for(; ;)
也可以来构造“无限”循环,同样需要使用break退出循环。
// 无限循环
// 需求: 页面会一直弹窗询问你爱我吗?
// (1). 如果用户输入的是 '爱',则退出弹窗
// (2). 否则一直弹窗询问
// 1. while(true) 无限循环
// while (true) {
// let love = prompt('你爱我吗?')
// if (love === '爱') {
// break
// }
// }
// 2. for(;;) 无限循环
for (; ;) {
let love = prompt('你爱我吗?')
if (love === '爱') {
break
}
}
for
是 JavaScript 提供的另一种循环控制的话句,它和 while
只是语法上存在差异。
<script>
// 1. 语法格式
// for(起始值; 终止条件; 变化量) {
// // 要重复执行的代码
// }
// 2. 示例:在网页中输入标题标签
// 起始值为 1
// 变化量 i++
// 终止条件 i <= 6
for(let i = 1; i <= 6; i++) {
document.write(`${i}>循环控制,即重复执行${i}>` )
}
script>
变化量和死循环,for
循环和 while
一样,如果不合理设置增量和终止条件,便会产生死循环。
跳出和终止循环
<script>
// 1. continue
for (let i = 1; i <= 5; i++) {
if (i === 3) {
continue // 结束本次循环,继续下一次循环
}
console.log(i)
}
// 2. break
for (let i = 1; i <= 5; i++) {
if (i === 3) {
break // 退出结束整个循环
}
console.log(i)
}
script>
结论:
JavaScript
提供了多种语句来实现循环控制,但无论使用哪种语句都离不开循环的3个特征,即起始值、变化量、终止条件,做为初学者应着重体会这3个特征,不必过多纠结三种语句的区别。for
循环,当不明确循环的次数的时候推荐使用while
循环注意:
for
的语法结构更简洁,故for
循环的使用频次会更多。
for 循环嵌套: 一个循环里再套一个循环,一般用在for循环里
// for (外部声明记录循环次数的变量; 循环条件; 变化量) {
// for (内部声明记录循环次数的变量; 循环条件; 变化量) {
// 循环体
// }
// }
// 外面执行一次,里面执行五次
for (let i = 1; i <= 3; i++) {
document.write(`第${i}天
`)
for (let j = 1; j <= 5; j++) {
document.write(`今天学习了${j}个单词
`)
}
}
记住,外层循环循环一次,里层循环循环全部
数组:(Array)是一种可以按顺序保存数据的数据类型
使用场景: 如果有多个数据可以用数组保存起来,然后放到一个变量中,管理非常方便
// 1.数组:(Array)是一种可以按顺序保存数据的数据类型,数组可以存储任意类型的数据
let arr = [10,20,30,40]
// 2.声明数组:
// let 数组名 = [数据1, 数据2, ..., 数据n]
// let 数组名 = new Array(数据1, 数据2, ..., 数据n)
// 3.使用数组:数组里面的值都有索引号,索引号是从 0 开始的
console.log(arr[0])
// 4.数组长度:arr.length ,数组中值的个数
console.log(arr.length)
<script>
// 1. 语法,使用 [] 来定义一个空数组
// 定义一个空数组,然后赋值给变量 classes
// let classes = [];
// 2. 定义非空数组
let classes = ['小明', '小刚', '小红', '小丽', '小米']
script>
通过 []
定义数组,数据中可以存放真正的数据,如小明、小刚、小红等这些都是数组中的数据,我们这些数据称为数组单元,数组单元之间使用英文逗号分隔。
使用数组存放数据并不是最终目的,关键是能够随时的访问到数组中的数据(单元)。其实 JavaScript 为数组中的每一个数据单元都编了号,通过数据单元在数组中的编号便可以轻松访问到数组中的数据单元了。
我们将数据单元在数组中的编号称为索引值,也有人称其为下标。
索引值实际是按着数据单元在数组中的位置依次排列的,注意是从 0
开始的。
<script>
let classes = ['小明', '小刚', '小红', '小丽', '小米']
// 1. 访问数组,语法格式为:变量名[索引值]
document.write(classes[0]) // 结果为:小明
document.write(classes[1]) // 结果为:小刚
document.write(classes[4]) // 结果为:小米
// 2. 通过索引值还可以为数组单重新赋值
document.write(classes[3]) // 结果为:小丽
// 重新为索引值为 3 的单元赋值
classes[3] = '小小丽'
document.wirte(classes[3]); // 结果为: 小小丽
script>
数组做为数据的集合,它的单元值可以是任意数据类型
<script>
// 数组单值类型可以是任意数据类型
// a) 数组单元值的类型为字符类型
let list = ['HTML', 'CSS', 'JavaScript']
// b) 数组单元值的类型为数值类型
let scores = [78, 84, 70, 62, 75]
// c) 混合多种类型
let mixin = [true, 1, false, 'hello']
script>
重申一次,数组在 JavaScript 中并不是新的数据类型,它属于对象类型。
<script>
// 定义一个数组
let arr = ['html', 'css', 'javascript']
// 数组对应着一个 length 属性,它的含义是获取数组的长度
console.log(arr.length) // 3
script>
用循环把数组中每个元素都访问到,一般会用for循环遍历
/*
用循环把数组中每个元素都访问到,一般会用for循环遍历
for (let i = 0; i < 数组名.length; i++) {
数组名[i]
}
*/
let arr = ['马超','赵云', '张飞', '关羽','黄忠']
for (i = 0; i < arr.length; i++){
console.log(arr[i])
}
数组做为对象数据类型,不但有 length
属性可以使用,还提供了许多方法:
使用以上4个方法时,都是直接在原数组上进行操作,即成功调任何一个方法,原数组都跟着发生相应的改变。并且在添加或删除单元时 length
并不会发生错乱。
// 重新赋值 数组[下标] = 新值
let arr = []
arr[0] = 20
arr[1] = '刘德华'
console.log(arr) // [20, '刘德华']
arr[1] = '成龙'
console.log(arr) // [20, '成龙']
// 数组添加新的数据
let arr = ['red', 'blue']
// 数组.push(新增的内容) 将一个或多个元素添加到数组的末尾,并返回该数组的新长度
console.log(arr.push('green', 'pink')) // 4
console.log(arr) // ['red', 'blue', 'green', 'pink']
// arr.unshift(新增的内容) 将一个或多个元素添加到数组的开头,并返回该数组的新长度
console.log(arr.unshift('orange', 'black')) // 6
console.log(arr) // ['orange', 'black', 'red', 'blue', 'green', 'pink']
<script>
// 删除数组的元素(数据)
let arr = ['orange', 'black', 'red', 'blue', 'green', 'pink']
// 数组. pop() 从数组中删除最后一个元素,并返回该元素的值
console.log(arr.pop()) // pink
console.log(arr) // ['orange', 'black', 'red', 'blue', 'green']
// 数组. shift() 从数组中删除第一个元素,并返回该元素的值
console.log(arr.shift()) // orange
console.log(arr) // ['black', 'red', 'blue', 'green']
// 数组. splice(start, deleteCount) 方法 删除指定元素
// start:指定删除的开始位置(从0计数)
// deleteCount:表示要删除的数组元素的个数。可选的。 如果省略则默认从指定的起始位置删除到最后
let newArr = [1, 2, 3, 4, 5, 6]
console.log(newArr.splice(2, 1)) // 3
console.log(newArr) // [1, 2, 4, 5, 6]
newArr.splice(3)
console.log(newArr) // [1, 2, 4]
script>
let arr = [4, 2, 5, 1, 3]
// 1.升序排列写法
arr.sort(function (a, b) {
return a - b
})
console.log(arr) // [1, 2, 3, 4, 5]
// 降序排列写法
arr.sort(function (a, b) {
return b - a
})
console.log(arr) // [5, 4, 3, 2, 1]
函数: function,是被设计为执行特定任务的代码块
函数可以把具有相同或相似逻辑的代码“包裹”起来,通过函数调用执行这些被“包裹”的代码逻辑,这么做的优势是有利于精简代码方便复用。
比如我们前面使用的 alert() 、 prompt() 和 console.log() 都是一些 js 函数,只不过已经封装好了,我们直接使用的。
声明(定义)一个完整函数包括关键字、函数名、形式参数、函数体、返回值5个部分
/*
函数的声明语法:
function 函数名() {
函数体
}
函数名命名规范:
1. 和变量命名基本一致
2. 尽量小驼峰式命名法
3. 前缀应该为动词
4. 命名建议:常用动词约定
动词:
can:判断是否可执行某个动作; has:判断是否含义某个值;
is:判断是否为某个值; get:获取某个值
set:设置某个值; load:加载某些数据
*/
声明(定义)的函数必须调用才会真正被执行,使用 ()
调用函数。
<script>
// 函数的调用语法:
// 函数调用,这些函数体内的代码逻辑会被执行
// 函数名()
// 注意:声明(定义)的函数必须调用才会真正被执行,使用 () 调用函数
// 函数一次声明可以多次调用,每一次函数调用函数体里面的代码都会重新执行一次
// 我们曾经使用的 alert() , parseInt() 这种名字后面跟小括号的本质都是函数的调用
// 函数体:
// 函数体是函数的构成部分,它负责将相同或相似代码“包裹”起来,直到函数调用时函数体内的代码才会被执行。
// 函数的功能代码都要写在函数体当中。
function sayHi() { // 声明函数
document.write('Hi~~') // 函数体
}
sayHi() // 函数调用
script>
注:函数名的命名规则与变量是一致的,并且尽量保证函数名的语义。
通过向函数传递参数,可以让函数更加灵活多变,参数可以理解成是一个变量。
<script>
/*
函数传参:
function 函数名(参数列表) {
函数体
}
参数列表:
1. 传入数据列表
2. 声明这个函数需要传入几个数据
3. 多个数据用逗号隔开
调用:
函数名(传递的参数列表)
调用函数时,需要传入几个数据就写几个,用逗号隔开
*/
// 如果用户不输入实参,可以给 形参默认值,可以默认为 0, 这样程序更严谨
// 说明:这个默认值只会在缺少实参参数传递时 才会被执行,所以有参数会优先执行传递过来的实参, 否则默认为undefined
function getSum(x = 0, y = 0) { // 形参:声明函数时写在函数名右边小括号里的叫形参(形式上的参数)
document.write(x + y)
}
getSum(10, 20) // 实参:调用函数时写在函数名右边小括号里的叫实参(实际上的参数)
script>
函数的本质是封装(包裹),函数体内的逻辑执行完毕后,函数外部如何获得函数内部的执行结果呢?要想获得函数内部逻辑的执行结果,需要通过 return
这个关键字,将内部执行结果传递到函数外部,这个被传递到外部的结果就是返回值。
<script>
// 当调用某个函数,这个函数会返回一个结果出来。这个结果就是函数返回的值
// 当函数需要返回数据出去时,用return关键字
// return 数据
function getSum(x = 0, y = 0) {
return x + y
}
let num = getSum(10, 20)
document.write(num)
/*
细节:
1. 在函数体中使用 return 关键字能将内部的执行结果交给函数外部使用
2. return后面不接数据或者函数内不写return,函数的返回值是undefined
3. return能立即结束当前函数, 所以 return 后面的数据不要换行写
*/
script>
总结:
- 在函数体中使用return 关键字能将内部的执行结果交给函数外部使用
- 函数内部只能出现1 次 return,并且 return 下一行代码不会再被执行,所以return 后面的数据不要换行写
- return会立即结束当前函数
- 函数可以没有return,这种情况默认返回值为 undefined
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
/*
作用域分为:
1. 全局作用域:全局有效。作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件
2. 局部作用域:局部有效。作用于函数内的代码环境,就是局部作用域。 因为跟函数有关系,所以也称为函数作用域。
在JavaScript中,根据作用域的不同,变量可以分为:
1. 全局变量:函数外部let 的变量。全局变量在任何区域都可以访问和修改
2. 局部变量:函数内部let的变量。局部变量只能在当前函数内部访问和修改
注意:
变量有一个坑, 特殊情况:
如果函数内部,变量没有声明,直接赋值,也当全局变量看,但是强烈不推荐。
但是有一种情况,函数内部的形参可以看做是局部变量。
*/
let num = 10
function fn() {
let num = 20
console.log(num) // 20
}
fn()
// 变量的访问原则:就近原则。在能够访问到的情况下 先局部, 局部没有在找全局
函数可以分为具名函数和匿名函数
匿名函数:没有名字的函数,无法直接使用。
// 1. 具名函数
function fn() {
}
fn()
// 2. 匿名函数
function () {}
// 匿名函数:没有名字的函数, 无法直接使用。
// 使用方式:
// 1. 函数表达式
// 2. 立即执行函数
// 函数表达式:将匿名函数赋值给一个变量,并且通过变量名称进行调用 我们将这个称为函数表达式
// 声明
let fn = function() {
console.log('函数表达式')
}
// 调用
fn()
// 其中函数的形参和实参使用跟具名函数一致。
// 立即执行函数:避免全局变量之间的污染
// 不需要调用,立即执行
// 方法1
(function () {})();
// 方法2
(function () {} ());
// 注意: 多个立即执行函数要用 ; 隔开,要不然会报错
// 其实类似参数的默认值写法
// 只存在于 && 和 || 中,当满足一定条件后右边代码不执行
function sum(x, y) {
x = x || 0
y = y || 0
console.log(x + y)
}
sum(10, 20)
// &&:左边为false,后面的代码就不看
console.log(false && 22) // false
console.log(false && 3 + 5) // false
let age = 18
console.log(false && age++) // false 后面的age++ 不执行
console.log(age) // 18 没有执行自加1的操作
// ||:左边为true,后面的代码就不看
console.log(true || age++) // true 后面的age++ 也不执行
console.log(age) // 18
console.log(11 && 22) // 22 都是真,这返回最后一个真值
console.log(11 || 22) // 11 输出第一个真值
// ''、0、undefined、null、false、NaN 转换为布尔值后都是false, 其余则为true
console.log(false && 20) // false
console.log(5 < 3 && 20) // flase
console.log(undefined && 20) // undefined
console.log(null && 20) // null
console.log(0 && 20) // 0
console.log(10 && 20) // 20
console.log(false || 20) // 20
console.log(5 < 3 || 20) // 20
console.log(undefined || 2) // 20
console.log(null || 20) // 20
console.log(0 || 20) // 20
console.log(10 || 20) // 10
对象(object):JavaScript里的一种数据类型
可以理解为是一种无序的数据集合, 注意数组是有序的数据集合
声明一个对象类型的变量与之前声明一个数值或字符串类型的变量没有本质上的区别。
<script>
// 1. let 对象名 = {}
// 2. let 对象名 = new Object()
// 声明对象类型变量,使用一对花括号
// user 便是一个对象了,目前它是一个空对象
let user = {}
/*
对象由属性和方法组成:
属性:信息或叫特征(名词)。 比如 手机尺寸、颜色、重量等…
方法:功能或叫行为(动词)。 比如 手机打电话、发短信、玩游戏…
let 对象名 = {
属性名: 属性值,
方法名: 函数
}
*/
script>
数据描述性的信息称为属性,如人的姓名、身高、年龄、性别等,一般是名词性的。
:
分隔,
分隔""
或 ''
,一般情况下省略,除非名称遇到特殊符号如空格、中横线等 <script>
// 通过对象描述一个人的数据信息
// person 是一个对象,它包含了一个属性 name
// 属性都是成对出现的,属性名 和 值,它们之间使用英文 : 分隔
let person = {
name: '小明', // 描述人的姓名
age: 18, // 描述人的年龄
stature: 185, // 描述人的身高
gender: '男', // 描述人的性别
}
script>
声明对象,并添加了若干属性后,可以使用 .
或 []
获得对象中属性对应的值,我称之为属性访问。
<script>
// 通过对象描述一个人的数据信息
// person 是一个对象,它包含了一个属性 name
// 属性都是成对出现的,属性名 和 值,它们之间使用英文 : 分隔
let person = {
name: '小明', // 描述人的姓名
age: 18, // 描述人的年龄
stature: 185, // 描述人的身高
gender: '男', // 描述人的性别
};
// 访问人的名字
console.log(person.name) // 结果为 小明
// 访问人性别
console.log(person.gender) // 结果为 男
// 访问人的身高
console.log(person['stature']) // 结果为 185
// 或者
console.log(person.stature) // 结果同为 185
script>
扩展:也可以动态为对象添加属性,动态添加与直接定义是一样的,只是语法上更灵活。
<script>
// 声明一个空的对象(没有任何属性)
let user = {}
// 动态追加属性
user.name = '小明'
user['age'] = 18
// 动态添加与直接定义是一样的,只是语法上更灵活
script>
let obj = {
uname: '刘德华',
age: '45',
weight: '150kg'
}
// 查:对象名.属性
console.log(obj.uname) // 刘德华
// 查的另外一种写法:对象['属性']
console.log(obj['age']) // 45
// 改:对象名.属性 = 新值
obj.age = '50'
console.log(obj) // {uname: '刘德华', age: '50', weight: '150kg'}
// 增:对象名.新属性 = 新值
obj.gender = '男'
console.log(obj) // {uname: '刘德华', age: '50', weight: '150kg', gender: '男'}
// 改和增语法一样,判断标准就是对象有没有这个属性,没有就是新增,有就是改
// 删:delete 对象名.属性
delete obj.weight
console.log(obj) // {uname: '刘德华', age: '50', gender: '男'}
数据行为性的信息称为方法,如跑步、唱歌等,一般是动词性的,其本质是函数。
,
分隔""
或 ''
,一般情况下省略,除非名称遇到特殊符号如空格、中横线等<script>
let obj = {
uname: '刘德华',
song: function() {
console.log('冰雨')
},
num: function(x, y) {
console.log(x + y)
}
}
// 方法调用
obj.song() // 冰雨
// 对象方法也可以添加形参和实参
obj.num(1, 2) // 3
script>
扩展:也可以动态为对象添加方法,动态添加与直接定义是一样的,只是语法上更灵活。
<script>
// 声明一个空的对象(没有任何属性,也没有任何方法)
let user = {}
// 动态追加属性
user.name = '小明'
user.['age'] = 18
// 动态添加方法
user.move = function () {
console.log('移动一点距离...')
}
script>
注:无论是属性或是方法,同一个对象中出现名称一样的,后面的会覆盖前面的。
null 也是 JavaScript 中数据类型的一种,通常只用它来表示不存在的对象。使用 typeof 检测类型它的类型时,结果为 object
。
let obj = {
uname: '刘德华',
age: '45',
weight: '150kg'
}
for (let k in obj) {
// k 是获得对象的属性名 k = 'uname' [k] = ['uname'] 查的另外一种写法就是 对象['属性']
console.log(k) // uname age weight
// obj[k] 是获得 属性值
console.log(obj[k]) // 刘德华 45 150kg
}
for in 不提倡遍历数组 因为 k 是 字符串
let students = [
{name: '小明', age: 18, gender: '男', hometown: '河北省'},
{name: '小红', age: 19, gender: '女', hometown: '河南省'},
{name: '小刚', age: 17, gender: '男', hometown: '山西省'},
{name: '小丽', age: 18, gender: '女', hometown: '山东省'}
]
for (let i = 0; i < students.length; i++) {
// students[i] 每个对象
console.log(students[i].name) // 小明 小红 小刚 小丽
}
我们曾经使用过的 console.log
,console
其实就是 JavaScript 中内置的对象,该对象中存在一个方法叫 log
,然后调用 log
这个方法,即 console.log()
。
除了 console
对象外,JavaScritp 还有其它的内置的对象
Math
是 JavaScript 中内置的对象,称为数学对象,这个对象下即包含了属性,也包含了许多的方法。
// 圆周率
console.log(Math.PI);
// random:生成0-1之间的随机数(包含0不包括1)
console.log(Math.random()) // 0.7275848132638618 随机的小数
// ceil:向上取整(舍弃小数部分,整数部分加1)
console.log(Math.ceil(1.9)) // 2
console.log(Math.ceil(1.1)) // 2
console.log(Math.ceil(-1.5)) // -1
// floor:向下取整(舍弃小数部分,整数部分不变)
console.log(Math.floor(1.9)) // 1
console.log(Math.floor(1.1)) // 1
console.log(Math.floor(-1.5)) // -2
// round:取整,四舍五入原则
console.log(Math.round(1.5)) // 2
console.log(Math.round(1.4)) // 1
console.log(Math.round(-1.5)) // -1
console.log(Math.round(-1.51)) // -2
// max:找最大数
console.log(Math.max(1, 2, 3, 4, 5)) // 5
// min:找最小数
console.log(Math.min(1, 2, 3, 4, 5)) // 1
// pow:幂运算 2 的 3 次方
console.log(Math.pow(2, 3)) // 8
// sqrt:求某数的平方根
Math.sqrt(16) // 4
// Math.random() 随机数函数, 返回一个0 - 1之间,并且包括0不包括1的随机小数[0, 1)
console.log(Math.random())
// 生成0-10的随机整数
console.log(Math.floor(Math.random() * (10 + 1)))
// 生成5-10的随机整数
console.log(Math.floor(Math.random() * (5 + 1)) + 5)
// 生成N-M之间的随机整数
// Math.floor(Math.random() * (M - N + 1)) + N
function getRandom(N, M) {
return Math.floor(Math.random() * (M - N + 1)) + N
}
console.log(getRandom(4, 8))
// 生成数组中随机一个元素
let arr = ['red', 'blue', 'green']
let ele = Math.floor(Math.random() * arr.length)
console.log(arr[ele])
简单类型又叫做基本数据类型或者值类型,复杂类型又叫做引用类型。
1、栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈; (简单数据类型存放到栈里面)
2、堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。(引用数据类型存放到堆里面)
简单类型的内存分配:
值类型(简单数据类型): string ,number,boolean,undefined,null
值类型变量的数据直接存放在变量(栈空间)中
复杂类型的内存分配:
引用类型(复杂数据类型):通过 new 关键字创建的对象(系统对象、自定义对象),如Object、Array、Date等
引用类型变量(栈空间)里存放的是地址,真正的对象实例存放在堆空间中
// 值类型变量
// 是直接把 num1, num2 的值 10 分别存到栈中的两个空间内,修改了 num1 的值,但 num2 的值不会变
let num1 = 10
let num2 = num1
num1 = 20
console.log(num2) // 10
// 引用类型变量
// obj1 是在栈中的空间里存了一个地址,age: 18 是存在堆中,地址指向的就是这个堆中存 age: 18 的空间
// obj2 = obj1 相当于是把 obj1 的地址给了 obj2,所以 obj2 地址指向的也是这同一个堆中的空间
// 而因为obj1 跟 obj2 的地址相同,指向的是同一个变量空间,所以修改了 obj1 的变量,obj2 自然也就跟着改变了
let obj1 = {
age: 18
}
let obj2 = obj1
obj1.age = 20
console.log(obj2) // {age: 20}