JavaScript学习03
函数
声明、调用
-
函数:执行特定任务的代码块,精简代码,方面调用
-
声明语法:
function 函数名(参数1,参数2, ... ,参数n) { // 形参
函数体
}
// 默认参数值 用户未输入参数生效
function getSum(x = 0, y = 0) {
console.log(x + y)
}
- 函数调用
函数名(参数1,参数2, ... ,参数n) // 实参,可以是变量
带返回值的函数
// 带返回值的函数 常用变量接受
function myFunction(a,b)
{
return a*b;
}
// let re = myFunction(3,4)
// console.log(re)
console.log(myFunction(3,4))
遇到 return 则结束函数 ,return 后面代码不会再被执行
return 语句不能换行写
若函数没有 return 返回值默认undefined
- 函数命名规范:
- 和变量命名基本一致
- 尽量小驼峰式命名法
- 前缀应该为动词
- 命名建议:常用动词约定
常用动词
动词 | 含义 |
---|---|
can | 判断是否可执行某一个操作 |
has | 判断是否含义某个值 |
is | 判断是否为某个值 |
get | 获取某个值 |
set | 设置某个值 |
load | 加载某些数据 |
数组求和函数
function getArrSum(arr = []) {
let sum = 0
for (let i = 0; i < arr.length; i++) {
sum += arr[i]
}
console.log(sum)
}
getArrSum([1,2,3,4,5])
// 输出15
函数细节
-
具名函数的调用可以写在声明前,也可以写在声明后
-
两个相同的函数后面的会覆盖前面的函数
-
在JavaScript中 实参的个数和形参的个数可以不一致
-
如果形参过多 会自动填上undefined (了解即可)
-
如果实参过多 那么多余的实参会被忽略 (函数内部有一个arguments,里面装着所有的实参),
-
函数一旦碰到return就不会在往下执行了,函数的结束用return
break 只能结束循环或者switch,return结束的是函数
函数的作用域
函数的形参、内部定义的参数为局部变量,函数外部不能访问
只要是代码,就至少有一个作用域
写在函数内部的是局部作用域
如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域
全局变量在任何区域都可以访问和修改
局部变量只能在当前函数内部访问和修改
变量特殊情况
如果函数内部,变量没有声明,直接赋值,也当全局变量来看,但是强烈不推荐
function fn() {
num = 10
}
fn()
console.log(num)
// 能输出10
变量的访问原则
在能够访问到的情况下 先局部, 局部没有再找全局
function f1() {
let num = 123
function f2() {
console.log( num )
}
f2()
}
let num = 456
f1()
// 输出123
function f1() {
let num = 123
function f2() {
let num = 0
console.log(num)
}
f2()
}
let num = 456
f1()
// 输出0
作用域链:采取就近原则的方式来查找变量最终的值
匿名函数
没有名字的函数,无法直接使用
使用方式:
- 函数表达式
let fn = function (x, y) {
console.log('我是函数表达式')
console.log(x + y)
}
fn(1, 2)
页面输出:
函数的调用必须在声明之后,否则会报错
fn(1, 2)
let fn = function (x, y) {
console.log('我是函数表达式')
console.log(x + y)
}
- 立即执行函数
// function 后面可以加名字
// 第一种写法
(function (形参列表) {
函数体
})(实参列表);
// 第二种写法
(function (形参列表){
函数体
}(实参列表));
转换时间案例
案例是来自b站pink老师JavaScript课程
parseInt()函数的参数是string类型,但例子中传入的实参为number类型,我把参数转为了字符串或使用Math.round()函数
这只是一个简单却不太严谨的案例
需求: 用户输入秒数,可以自动转换为时分秒
分析:
①: 用户输入总秒数 (注意默认值)
②:计算时分秒(封装函数) 里面包含数字补0
③:打印输出
计算公式:
小时:h = parseInt(总秒数 / 60 / 60 % 24) // 我改为 h = parseInt(‘总秒数 / 60 / 60 % 24’)
分钟:m = parseInt(总秒数 / 60 % 60) // 我改为 m = parseInt(‘总秒数 / 60 % 60’)
小时: s = parseInt(总秒数 % 60) // 我改为 s = parseInt(‘总秒数 % 60’)
// 1. 用户输入
let second = +prompt('请输入秒数:')
// 2. 封装函数
function getTime( t ){
// 3. 转换
// 计算公式:计算时分秒
// 小时: h = parseInt(总秒数 / 60 / 60 % 24)
// 分钟: m = parseInt(总秒数 / 60 % 60 )
// 秒数: s = parseInt(总秒数 % 60
let h = Math.round(t / 60 / 60 % 24)
let m = Math.round(t / 60 % 60)
let s = Math.round(t % 60)
h = h < 10 ? '0' + h : h
m = m < 10 ? '0' + m : m
s = s < 10 ? '0' + s : s
return `转换之后:${h}小时${m}分钟${s}秒`
}
let time = getTime(second)
console.log(time)
逻辑中断介绍
下面例子中的“age++”都未执行
let age = 18
console.log(false && age++) // false
console.log(age) // 18
console.log(true || age++) // true
console.log(age) // 18
// 逻辑与结果都为真,返回最后一个真值
console.log(11 && 22) // 22
// 逻辑或结果都为真,返回第一个真值
console.log(11 || 22) // 11
&&:如果第一个操作数是 true(或者能够转为 true),计算结果就是第二个操作数,如果第一个操作数是 false,结果就是 false(短路计算),但不一定返回的值是false,可能是undefined、null等
||:如果第一个操作数不是 false,结果就是第一个操作数,否则结果是第二个操作数。如果第一个操作数能够转为 true,结果就是第一个操作数(短路计算)
逻辑中断应用:类似参数的默认值写法
function getSum(x, y) {
x = x || 0
y = y || 0
console.log(x + y) // 0
console.log(typeof x) // number
}
getSum()
转为boolean类型
显示转换
‘’(空串) 、0、undefined、null、false、NaN 转换为布尔值后都是false, 其余则为 true
隐式转换
- 有字符串的加法 “” + 1 ,结果是 “1”
- 减法 - (像大多数数学运算一样)只能用于数字,它会使空字符串 “” 转换为 0
- null 经过数字转换之后会变为 0
- undefined 经过数字转换之后会变为 NaN
console.log('' - 2) // -2
console.log(null + 3) // 3
console.log(undefined +3) //NaN
console.log(null == undefined) // true
console.log(null === undefined) // false
console.log('2' == 2) //true
console.log(null - 3) // -3
console.log(undefined -3) //NaN
页面输出:
对象
对象是什么
-
对象(object):JavaScript中的一种数据类型
-
可以理解为一种无序的数据集合,注意数组是一种有序的数据集合
-
用来描述某一事物,例如描述一个人
- 人有姓名、年龄、性别等信息,还有吃饭睡觉打代码等行为
- 如果用多个变量保存比较散,用对象比较统一
-
静态特征:可以使用数字、字符串、数组、布尔类型等表示
-
动态行为:使用函数表示
对象的使用
-
对象有属性和方法组成
属性:信息或叫特征(名词)。比如 手机尺寸、颜色、重量等
方法:功能或叫行为(动词)。比如 手机打电话、发短信、玩游戏等
let 对象名 = {
属性名: 属性值,
方法名: 函数
}
属性
属性都是成对出现的,包括属性名和值,它们之间使用英文“:”分隔
多个属性之间使用英文“,”分隔
属性就是依附在对象上的变量(外面是变量,对象内是属性)
属性名可以加双引号""或单引号’',一般情况下省略,除非名称遇到特殊符号如空格、中横线等
-
对象查: 对象名.属性
对象名[‘属性名’]
若属性带有字符串只能使用第二种方式
-
属性改: 对象名.属性 = 新值
-
属性增: 对象名.新属性名 = 新值
-
属性删: delete 对象名.属性
// 1.定义一个对象
let obj = {
'goods-name': '小米10',
num: '100012816024',
weight: '0.55kg',
address: '中国大陆',
}
// 2. 增加属性color
obj.color = 'pink'
// 3. 修改属性的值
obj['goods-name'] = '小米10 青春版'
// 4. 访问对象的属性
console.log(obj.num)
// console.log(obj.goods-name) 书写错误
// 使用对象名['属性名']
console.log(obj['goods-name'])
// 对象属性名没有字符串也可以使用对象名['属性名']
console.log(obj['address'])
console.log(obj)
页面输出
方法
document.write()就是一个方法
方法是由方法名和函数两部分构成,它们之间使用英文“:”分隔
方法之间也使用英文“,”分隔
方法是依附在对象上的函数
方法名可以加双引号""或单引号’',一般情况下省略,除非名称遇到特殊符号如空格、中横线等
方法的声明和调用
let person = {
'per-name': 'Andy',
// 相当于匿名函数赋值给一个变量
sayHi: function () {
console.log('Hi')
},
sleep: function (x = 0) {
console.log(`我睡了${x}h`)
}
}
// 方法调用 对象名.方法名
person.sayHi()
person.sleep(8)
页面输出
对象的遍历
- 先来看一种数组的遍历
// 定义数组
let arr = ['red', 'black', 'blue']
for (let arrKey in arr) {
// arrKey 是数组的下标(索引号) 是string类型
console.log(arrKey)
console.log(typeof arrKey)
console.log(arr[arrKey])
}
页面输出
- 对象遍历
// 1.定义一个对象
let obj = {
'goods-name': '小米10',
num: '100012816024',
weight: '0.55kg',
address: '中国大陆',
}
for (let objKey in obj) {
// objKey是字符串
console.log(objKey) // string 'num' 'weight'
// 遍历打印属性值
console.log(obj[objKey])
}
页面输出
一般不用这种方式遍历数组,主要用来遍历对象
for in 语法中的 k 是一个变量,在循环的过程中依次代表对象的属性名
由于 k 变量是 string 类型,所以必须使用 对象名[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++) {
// 打印数组对象
console.log(students[i])
// 打印数组对象的名字
console.log('数组对象的名字')
console.log(students[i].name)
// 打印对象的所有属性值
console.log('对象的所有属性值')
for (let k in students[i]) {
console.log(students[i][k])
}
}
页面输出
渲染学生信息表格
需求:将上面的数组中的数据渲染成为表格
分析:
打印表格 头部和尾部
中间的行遍历数组,然后填充对象数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
table {
width: 600px;
text-align: center;
}
table,
th,
td {
border: 1px solid #ccc;
border-collapse: collapse;
}
caption {
font-size: 18px;
margin-bottom: 10px;
font-weight: 700;
}
tr {
height: 40px;
cursor: pointer;
}
table tr:nth-child(1) {
background-color: #ddd;
}
table tr:not(:first-child):hover {
background-color: #eee;
}
</style>
</head>
<body>
<table>
<caption>学生列表</caption>
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
<td>家乡</td>
</tr>
<script>
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++) {
document.write(`
<tr>
<td>${i+1}</td>
<td>${students[i].name}</td>
<td>${students[i].age}</td>
<td>${students[i].gender}</td>
<td>${students[i].hometown}</td>
</tr>
`)
}
</script>
</table>
</body>
</html>
页面输出
内置对象
什么是内置对象
- JavaScript内部提供的对象,包含各种属性和方法给开发者调用
- 思考:我们之前用过内置对象吗?
- document.write()
- console.log()
内置对象-Math
-
Math.ceil(x) :向上取整 不小于x的最大整数
-
Math.floor(x) :向下取整 不大于x的最大整数
-
Math.round(x) :四舍五入取整
-
Math.max(x, … ,y) :取最大值
-
Math.min(x, … , y) :取最小值
-
Math.abs(x) :取绝对值
-
Math.pow(x, y) : x的y次幂
// Math内置对象的属性
console.log(Math.PI) // 3.141592653589793
// Math内置对象的方法
// ceil 天花板 Math.ceil(x) 向上取整 不小于x的最大整数
console.log(Math.ceil(1.0)) // 1
console.log(Math.ceil(1.2)) // 2
console.log(Math.ceil(1.5)) // 2
console.log(Math.ceil(1.8)) // 2
console.log(Math.ceil(2)) // 2
console.log('-------------------')
// floor 地板 Math.floor(x)向下取整 不大于x的最大整数
console.log(Math.floor(1.0)) // 1
console.log(Math.floor(1.2)) // 1
console.log(Math.floor(1.5)) // 1
console.log(Math.floor(1.8)) // 1
console.log(Math.floor(2)) // 2
console.log('-------------------')
// Math.round() 四舍五入取整
console.log(Math.round(1)) // 1
console.log(Math.round(1.3)) // 1
console.log(Math.round(1.5)) // 2
console.log(Math.round(1.9)) // 2
console.log(Math.round(-20.1)) // -20
console.log(Math.round(-20.5)) // -20
console.log(Math.round(-20.51)) // -21
console.log('-------------------')
// 取最大值、最小值
console.log(Math.max(4, 3, 5, 2, 1)) // 5
console.log(Math.min(4, 3, 5, 2, 1)) // 1
// 取绝对值
console.log(Math.abs(-2.2)) // 2.2
// 幂运算
console.log(Math.pow(2,4)) // 16
- Math.random():返回一个0 -1之间,并且包括0不包括1的随机小数 [0, 1) 左闭右开
-
生成 0 - 10 整数随机数
console.log(Math.floor(Math.random()*(10 + 1)))
-
生成 5 - 10 整数随机数
console.log(Math.floor(Math.random()*(5 + 1) + 5))
-
生成 N - M 整数随机数
console.log(Math.floor(Math.random()*(M - N + 1) + N))
随机数案例
随机点名案例
需求:请把 [‘赵云’, ‘黄忠’, ‘关羽’, ‘张飞’, ‘马超’, ‘刘备’, ‘曹操’] 随机显示一个名字到页面中
分析:
①:利用随机函数随机生成一个数字作为索引号
②: 数组[随机数] 生成到页面
// 数组下标[0, arr.length - 1]
// N-M 随机整数:Math.floor(Math.random()*(M - N + 1) + N))
let arr = ['赵云', '黄忠', '关羽', '张飞', '马超', '刘备', '曹操']
let randow = Math.floor(Math.random()*(arr.length)) // arr.length + 1 -1
// 删除已经抽取的名字 : arr.splice(random, 1)
document.write(arr[randow])
猜数字游戏
需求:程序随机生成 1~10 之间的一个整数,用户输入一个数
分析:
①:如果大于该数字,就提示,数字猜大了,继续猜
②:如果小于该数字,就提示,数字猜小了,继续猜
③:如果猜对了,就提示猜对了,程序结束
用while循环
// 1. 随机生成 0 - 10 之间的整数
let random = Math.floor(Math.random() * (10 + 1))
while (true) {
// 2. 用户输入
let num = +prompt('请输入一个 0 - 10 的整数:')
// 3. 给出提示
if (num > random) {
alert('猜大了,请继续')
} else if (num < random) {
alert('猜小了,请继续')
} else {
alert('恭喜你猜对了!')
// 4. 猜对结束
break
}
}
用for循环
// 1. 随机生成 0 - 10 之间的整数
let random = Math.floor(Math.random() * (10 + 1))
let flag = true
for (let i = 1; i <= 3; i++) {
// 2. 用户输入
let num = +prompt('请输入一个 0 - 10 的整数:')
// 3. 给出提示
if (num > random) {
alert('猜大了,请继续')
} else if (num < random) {
alert('猜小了,请继续')
} else {
flag = false
alert('恭喜你猜对了!')
// 4. 猜对结束
break
}
}
if (flag) {
alert('次数用完了~')
}
随机颜色案例
需求:该函数接收一个布尔类型参数,表示颜色的格式是十六进制还是rgb格式。
分析:
提示: 16进制颜色格式为: ‘#ffffff’ 其中f可以是任意 0-f之间的字符,需要用到数组,
let arr = [‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’, ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’]
提示: rgb颜色格式为: ‘rgb(255,255,255) ’ 其中255可以是任意0-255之间的数字
步骤:
①:如果参数为true或者无参数,则处理16进制颜色,核心思想是循环6次,生成随机的6个数字(取 值范围0~15),根据这个数字去找数组的值,然后和 # 拼接起来,并且返回值。
②:如果参数为false,随机生成一个0~255的数给三个变量,分别作为 r g b 三个颜色,之后拼接字 符串rgb(255,255,255)格式
该案例主要是学习思维,在后面我又添加了个盒子显示颜色变化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>随机颜色</title>
<style>
#color {
width: 300px;
height: 300px;
background-color: black;
}
</style>
</head>
<body>
<div id = "color">
</div>
<script>
// 1. 自定义一个随机颜色函数
function getRandomColor(flag = true) {
// 3. 根据参数选择颜色格式
if (flag) {
// true则生成#fffff 格式
let str = '#'
let arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
// 利用for循环6次
for (let i = 1; i <=6; i++) {
let temp = arr[Math.floor(Math.random()*arr.length)]
str += temp
}
return str
} else {
// false 则生成rgb(255, 255, 255)格式
let r = Math.floor(Math.random()*(255 + 1))
let g = Math.floor(Math.random()*(255 + 1))
let b = Math.floor(Math.random()*(255 + 1))
return `rgb(${r}, ${g}, ${b})`
}
}
// 2. 调用生成随机颜色
let color = getRandomColor(true)
let div = document.getElementById('color')
div.style.backgroundColor = color
</script>
</body>
</html>
术语扩展
术语 | 解释 | 举例 |
---|---|---|
关键字 | 在JavaScript中有特殊意义的词汇 | let、var、function、if、else、 switch、case、break |
保留字 | 在目前的JavaScript中没意义,但未 来可能会具有特殊意义的词汇 | int、short、long、char |
标识(标识符) | 变量名、函数名的另一种叫法 | 无 |
表达式 | 能产生值的代码,一般配合运算符出 现 | 10 + 3、age >= 18 |
语句 | 一段可执行的代码 | If ()、 for() |
扩展:基本数据类型和引用数据类型
目标:了解基本数据类型和引用数据类型的存储方式
简单类型又叫做基本数据类型或者值类型,复杂类型又叫做引用类型。
-
值类型:简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型 string ,number,boolean,undefined,null
-
引用类型:复杂数据类型,在存储时变量中存储的仅仅是地址(引用),因此叫做引用数据类型
通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date
堆栈空间分配区别:
-
栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;
简单数据类型存放到栈里面
-
堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。
引用数据类型存放到堆里面
let num = 10
let num1 = num
num2 = 20
console.log(num) // 10
let obj = {
age: 20
}
let obj1 = obj
obj1.age = 20
// obj 与 obj2指向同一堆空间
console.log(obj.age) // 20