JavaScript基础语法和简单数据结构
WHAT IS JavaScript (I 基础语法)
@jarringslee
文章目录
- WHAT IS JavaScript (I 基础语法)
- js书写基础和术语规范
- 变量、常量、数据类型运算符
- 变量 let
- 常量 const
- 数据类型
- 运算符
- 逻辑中断 / 逻辑短路
- Boolean型的转换
- 分支语句
- 单分支 `if`
- 双分支 `if-else`
- 三元运算符 `? :`
- switch分支
- 循环语句
- while循环
- continue & break
- for循环
- 数组
- 函数
- 对象
js书写基础和术语规范
js是一种在客户端(浏览器)运行的编程语言,可实现人机交互的效果。
js组成:
js由两部分组成:
- ECMAScript:js的语言基础,js遵循其语言逻辑。它规定了js的基础语法核心知识,如变量、分支、循环等;
- Web APIs:分为DOM(页面文档对象型:操作文档,比如对页面元素进行移动、大小、添加删除等操作)和BOM(浏览器对象型:操作浏览器,比如页面弹窗、检测窗口宽度、存储数据到浏览器等)。
js书写位置:
-
**行内js:**略。
-
**内部js:**直接写在html文件中(通常写在
</body>
标签上面),用<script>
标签包裹住 -
**外部js:**通过link链接
<body><script src="js文件地址"></script> </body>
js结束符:
可以用分号结尾,也可以不写,统一格式即可。
输入和输出语法:
-
输出语法
-
向body内输出内容:
document是文档的意思,输出内容也可以用标签包裹。
document.write('输出内容') document.write('<h1>我是标题</h1>')
-
页面弹出警示框:
alert('输出内容')
-
控制台输出(用户无法看到,在控制到console中):
console.log('控制台输出') //简写为log
-
-
输入语法
-
显示对话框和文字信息
promot('请输入姓名')
-
被引号包裹的内容可以用单引号’’、双引号""或反引号``
执行顺序:
- 按文档流顺序执行代码;
- alert()和promot()会跳过页面渲染先被执行
js字面量
字面量literal在计算机中描述事/物
- 月薪是30000 此时30000是数字变量
- ‘泥嚎’ 泥嚎是字符串字面量
- [] 是数组字面量 {} 是对象字面量
术语解释
术语 | 解释 | 举例 |
---|---|---|
关键字 | 在 JavaScript 中有特殊意义的词汇 | let、var、function、if、else、switch、case、break |
保留字 | 在当前 JavaScript 中无意义,但未来可能具有特殊意义 | int、short、long、char |
标识符 | 变量名、函数名的另一种叫法 | 无 |
表达式 | 能产生值的代码,通常配合运算符出现 | 10 + 3、age >= 18 |
语句 | 一段可执行的代码 | if () {}、for () {} |
变量、常量、数据类型运算符
变量的访问原则: 先找局部,再找全局
变量 let
变量是计算机中用来存储数据的容器,并不是数据本身。
变量的声明/定义/创建: 声明关键字 变量名
let age = 18
**变量的本质:**是程序在内存中申请的一块用来存放数据的小空间
存储输入的数据:
let uname =prompt('请输入姓名')document.write('姓名:', uname, '。')//或者const age = prompt('请输入您的年龄')document.write('年龄:${age}<br>')
**数组变量:**直接声明,等号后写中括号,元素间用逗号隔开。
数组长度:变量名+点+length(最大元素的下标+1)
let uname = [111, 222, 'num', 231]document.write('姓名:', uname[2], '。')document.write('数组长度:', uname.length, '。')
常量 const
声明时必须赋值,且不允许再次赋值,无法被修改。 const PI = 3.14
数据类型
基本数据类型:
-
值类型,在存储变量中时存储的是
-
**数字类型Number:**变量声明后直接创建。可以是整数、小数、正数、负数。
js、Python是弱数据类型的语言:一个关键字可以声明任意类型的数字(整数、小数…)。
而c、java就是强数据类型的语言:int整数、float或者double为浮点数。
数字的运算符:算术运算符:
- 优先级最大的是括号中或者次方(
**
):4**2表示4的4次方 - 乘 除 取余
- 加 减
如果碰到非数字进行了算术运算,则会输出:NaN。
NaN也属于数字类型,代表非数字,即一个计算错误。它是粘性的:任何和其有关的操作都会返回NaN。“NaN==NaN”的命题也是错的。
- 优先级最大的是括号中或者次方(
-
**字符串类型string:**变量声明后用引号(单引号、双引号、反引号)包裹创建内容。注意若数字被引号包裹了,那它也是字符串类型。
空字符串:
let str = ''
console'log('')
字符串拼接:加号+ 可以把相邻的两个字符串或相邻的字符串和数字相连在一起。
document.write('我今年' + 19 + '岁了') //等价于 document.write('我今年', 19, '岁了') //或者 let age = 19 document.write('我今年' + age + '岁了') //或者 let age = 19 let aa = '我今年' let bb = '岁了' document.write(aa + age + bb)
直接在字符串的引号中书写变量名:模版字符串
字符串用反引号包裹,引号中的变量名用**
${}
**包裹document.write(`我今年${age}岁了`)
-
**布尔类型boolean:**判断真假的数据类型,有true(真)和false(假)两个数据类型
let mybool = true document.write(mybool)
若直接在输出内容中放一个判断问题(不加引号),也可以直接输出true或false
document.write(99 < 1000)
-
未定义类型undefined: 值直接为undefined。在不声明变量、不赋值的情况下默认值为undefined。一般不直接把某个变量赋值为undefined。
let buy document.write(buy) //输出值为undefined
**使用场景:**若后端有一个变量传过来,可以通过判断这个值是不是undefined来确定这个值是否有效。
-
空类型null: null是对象数据类型(object),表示创建了变量但是没有赋值,代表“无”“空”“未知”的一个特殊值
let obj = null
undefined是没有赋值(什么也不是,不能参与运算),null表示赋值了但是内容为空(没有值,参与运算时默认为0)
document.write(undefined + 1) //输出NaN document.write(null + 1) //输出值为1
**使用场景:**如果一个变量中确定存放的是对象,但还没有准备好该对象,可以先放null
引用数据类型: 对象object、数组Array、Date等
基本数据类型 vs 引用数据类型
-
值类型(简单类型 / 基本类型)
变量里直接存放“值本身”。
代表:string
、number
、boolean
、undefined
、null
。 -
引用类型(复杂类型 / 对象类型)
变量里只存放一条“地址”,真正的对象实体在别处。
代表:Object
、Array
、Date
以及所有用new
创建的系统或自定义对象。
内存模型(堆 & 栈)
-
栈(Stack)
操作系统自动分配/回收,存函数参数、局部变量。
特点:容量小、速度快、连续内存。
⇒ 基本类型数据直接塞栈里。 -
堆(Heap)
容量大、速度慢、非连续内存,需手动或垃圾回收释放。
⇒ 引用类型的真实对象住在堆里;
栈里只保留一个指向堆地址的“门牌号”。
栈空间 堆空间
┌────────────┐ ┌────────────┐
│ usrAge = 12│ ─┐ │ Person对象 │
│ usrSex=true│ │ │ { age:18 } │
│ objRef │───┘ └────────────┘
└────────────┘
- 基本类型:栈里就是值。
- 引用类型:栈里是堆的地址,堆里是对象。
赋值 & 共享陷阱
// 基本类型示例
let num = 10;
let num2 = num; // 把 10 拷贝一份给 num2
num = 20; // 把 num 改成 20
console.log(num2); // 10 (num2 不受影响)// 引用类型示例
let obj1 = { age: 18 }; // 新建对象,存在堆里
let obj2 = obj1; // 只把“地址”给 obj2
obj1.age = 20; // 通过地址改堆里的对象
console.log(obj2.age); // 20 (obj2 指向同一块内存)
① 基本类型(值拷贝)
步骤 | 栈内存示意图 | 解释 |
---|---|---|
let num = 10 | num → 10 | 变量里直接存值 |
let num2 = num | num → 10 num2 → 10 | 把 10 再复制一份 |
num = 20 | num → 20 num2 → 10 | 只改 num ,num2 还是旧值 |
console.log(num2) | 输出 10 | 互不影响 |
② 引用类型(地址共享)
步骤 | 栈内存 + 堆内存示意图 | 解释 |
---|---|---|
let obj1 = { age: 18 } | 栈:obj1 → 0x1001 堆: 0x1001 → { age: 18 } | 对象在堆里,变量里只存地址 |
let obj2 = obj1 | 栈:obj1 → 0x1001 obj2 → 0x1001 | 把同一地址给 obj2 |
obj1.age = 20 | 堆:0x1001 → { age: 20 } | 通过地址改堆里的数据 |
console.log(obj2.age) | 输出 20 | obj2 指向同一对象,值已变 |
- 基本类型 = 值拷贝 → 互不影响
- 引用类型 = 地址共享 → 一改全改
因为 obj1
和 obj2
指向同一块堆内存,一改全改。
基本类型“值随身”,引用类型“值在堆,地址随身”。
检测数据类型 typeof
在输出中使用,可以直接输出变量类型名
书写方法:
typeof + 空格 + 变量名
(常用)typeof + (变量名)
let num = 10console.log(typeof num) //输出numberlet str = 'pink'console.log(typeof str) //输出stringlet no = ''console.log(typeof no) //输出stringlet flag = falseconsole.log(typeof flag) //输出booleanlet unconsole.log(typeof un) //输出undefinedlet obj = nullconsole.log(typeof obj) //输出object
数据类型的两种转换
利用prompt让用户输入的值统一被认为是字符串的值。若要对用户输入的数值进行运算操作,需要进行转换。
-
隐式转换 某些运算符被执行时,系统自动将某些数据类型进行转换。
- 加号+ 只要加号两边有一个是字符串,都会把另一个也变成字符串(直接拼接)。即任何数据和字符串相加结果都是字符串。
- 除加号以外的运算符 如 - * / 等都会把数据转成数字类型并进行算术运算,空字符串被转换成0(碰到非数字直接NaN)
- 正号+ 在字符串前面(引号之前)加正号+,自动把字符串类型变为数字类型(若转换了非数字直接NaN)
-
**显式转换 **
-
Number(变量名或字符串)(后面统称为“数据”)
直接转换为数字(一般在输出中直接使用)。遇到非数字直接NaN
let str = '123' console.log(Number(str)) //或者 console.log(Number('123')) //或者 let num = Number(prompt('请输入数字')) //等价于 let num = +prompt('请输入数字')
-
parseInt(数据) 只保留最前面的整数部分并转换为数字型(遇到非数字或小数点就截断,开头直接是非数字那就NaN)
-
parseFloat(数据) 可保留小数部分
-
输入两数,输出其和:
let num1 = +prompt('give me the first nummber')
let num2 = Number(prompt('give me the second number'))
alert(`${num1} plus ${num2} equals ${num1 + num2}`)
运算符
-
*赋值运算符 = += -= = /= 对变量进行赋值的运算符,用于简化代码。左边是容器,右边是值
-
一元运算符
-
正号+ 符号- 赋予数据正值、负值
-
自增++ 自减–
前置和后置:++i和i++:一般情况下习惯使用后置i++,两者在单独使用时没有区别。
两者区别:在一行运算中,++i先给自身加完之后再参与运算,i++先参与运算之后在自加。
let i = 1; console.log(++i + 1) //i值先变为2再参与运算,输出值为3
let i = 1; console.log(i++ + 1) //i先参与运算,输出值为2,自身再自加变为2
let i = 1; console.log(i++ + ++i + i) /* i++:先用后加值是 1,然后 i 变成 2++i:先加后用i 从 2 变成 3,值是 3i:此时 i 已经是 3所以整个表达式就是:1 + 3 + 3 = 7因此打印结果是 7。 */
-
-
比较运算符 < > <= >= == === != !== 比较结果为boolean类型的值(只有true或者false)
- == 左右两边值是否相等
- === 左右两边值和类型是否都相等(全等,常用)
- != 左右两边是否值不相等
- !== 左右两边是否不全等
- NaN不等于任何值,包括它自己
隐式转换下,常常会有值相等但类型不相同的例子。
在做
==
比较时会隐式转换,所以经常出现 “值看起来一样,但类型不同” 的情况,例如:'1' == 1 // true 字符串 '1' 被转成数字 1 0 == false // true 布尔值 false 被转成 0 null == undefined // true 规范规定这对特殊值相等 ' \n ' == 0 // true 空格字符串被转成 0
而
===
不做任何类型转换,只要类型不同就直接返回false
:'1' === 1 // false 0 === false // false null === undefined // false
所以:
==
比较转换后的值===
比较值 + 类型
- 全等/不全等(=== / !==)先看类型,类型不同直接判 false / true。
- 相等/非相等(== / !=)先转换再比较。
- 字符串比较按字典序(Unicode 码点),逐位比,直到发现大小不同的值,前缀相同则短的小。
console.log(2 === '2'); // false (类型不同) console.log(NaN === NaN); // false (NaN !== NaN) console.log(2 !== '2'); // true (类型不同) console.log(2 != '2'); // false (转换后相等)console.log('a' < 'b'); // true (97 < 98) console.log('aa' < 'ab'); // true (第二位 a < b) console.log('aa' < 'aac'); // true (前缀相同,aa 更短)
-
逻辑运算符 &&与(一假则假) ||或(一真则真) !非(真变假,假变真)
-
运算符优先级
优先级 运算符 顺序 1 小括号 () 2 一元运算符 ++ -- ! 3 算术运算符 * / % 先于 + - 4 关系运算符 > >= < <= 5 相等运算符 == != === !== 6 逻辑运算符 && 先于 || 7 赋值运算符 = += -= … 8 逗号运算符 ,
逻辑中断 / 逻辑短路
符号 | 短路条件 |
---|---|
&& | 左边为false就短路 |
|| | 左边为ture就短路 |
&& “与”:一假则假
如果前面有被判定为假的语句,则直接中断,不会再看后面。
let n = 18
document.write(false && n++) // 遇到false直接截断,只会输出false,n++的操作也不会执行
document.weite(n) //输出18,因为上面n++的操作并未被执行
document.weite(11 && 22) //输出22,,若都为真,则返回最后一个真值
|| “真”:一真则真
用于赋予形参默认值。
function sum(x, y){x = x || 0 //未赋值的形参是undefined,被判断为假,被跳过并寻找真值y = y || 0 //若都为真,则返回第一个值......
}
(function flexible(window, document) {var dpr = window.devicePixeRatio || 1//用于获取客户端(pc端/移动端)窗口比例。若设备不支持这种写法(没有这个函数,就是undefined,被判断为false),则为默认值1。} (window, document) )
Boolean型的转换
-
显示转换:字符串中空字符串‘’、数字类型中0、undefined、false、NaN转换为布尔值都是false,其余为true
//表达式判断正误,输出false或true console.log(5 < 3 && 20) //输出false //被显示转换为false的值,直接输出值 console.log(null && 20) //输出null
-
隐式转换
- 字符串加法:直接拼接。
' ' + 1 变为 '1'
- 字符串减法:把空字符串转换为0
' ' - 1 值为-1
- null经过数字转换后变成0
null + 1 值为1
- undefined经过数字转换后变成NaN
- 字符串加法:直接拼接。
分支语句
单分支 if
只判断一次,条件为真就执行,为假直接跳过。
if (条件) {// 条件为真时执行
}
let age = 18;
if (age >= 18) {console.log('成年');
}
双分支 if-else
条件为真执行 A,否则执行 B。
if (条件) {// 条件为真
} else {// 条件为假
}
let score = 59;
if (score >= 60) {console.log('及格');
} else {console.log('完蛋');
}
三元运算符 ? :
把双分支 if-else 缩成一行,必须有 else,并返回一个值。
条件 ? 值A : 值B
let num = prompt('请输入一个数字')
num = num < 10 ? 0 + num : num
//0 + num是字符串相加的形式,给个位数补一个0
形式 | 关键字 | 行数 | 返回值 | 使用场景 |
---|---|---|---|---|
单 if | if | 多 | 无 | 只做一件事 |
if-else | if...else | 多 | 无 | 二选一 |
三元运算符 | ? : | 1 | 有 | 简单二选一,要返回值 |
- 三元运算符必须有 else;
if
可以没有。 - 三元运算符不能写多条语句;复杂逻辑用 if-else。
switch分支
switch 就是“多选一”的快捷 if-else 链——把同一个变量/表达式的不同取值,一一对照执行。
基本语法
switch (表达式) {case 值1:语句块1;break; // 记得 break,否则会继续往下“穿透”case 值2:语句块2;break;...default: // 相当于最后的 else默认语句;
}
let day = 3;
switch (day) {case 1:console.log('周一');break;case 2:console.log('周二');break;case 3:console.log('周三');break;default:console.log('未知');
}
// 输出:周三
几个注意点
-
全等比较
switch
用的是===
,不会自动类型转换。switch ('2') {case 2: // 不会命中,因为 '2' !== 2... }
-
break 穿透
忘写break
会把下面所有 case 都执行一遍。
有时故意利用穿透做“合并”:switch (score) {case 5:case 4:console.log('优秀'); // 4 和 5 都会走这里break; }
-
default 可省
如果所有 case 都不匹配且没有 default,就什么都不做。
何时用 switch?
场景 | 推荐写法 |
---|---|
同一个变量的离散值 | switch |
区间判断(> <) | if-else |
复杂逻辑 / 多条件 | if-else / 对象映射 |
“变量等值多选一,switch 比 if-else 更清爽;记得 break 防穿透,default 兜底别忘掉。”
循环语句
while循环
while (判断条件) {循环命令条件增量
}
continue & break
break
直接跳出整个循环(或 switch),循环结束;
continue
立即跳过本次迭代,继续下一轮循环。
关键字 | 作用范围 | 效果描述 | 常见场景 |
---|---|---|---|
break | 循环 / switch | 立即终止当前结构,后续不再执行 | 找到目标值后提前结束 |
continue | 仅循环 | 跳过本次剩余代码,继续下一轮 | 过滤/跳过不想要的值 |
代码示例
// break:找到 5 就停
for (let i = 1; i <= 10; i++) {if (i === 5) break; // 遇到 5 立即跳出console.log(i); // 1 2 3 4
}// continue:跳过 5
for (let i = 1; i <= 5; i++) {if (i === 3) continue; // 跳过 3console.log(i); // 1 2 4 5
}
break “炸” 整个循环,continue “跳过” 这一回。
for循环
for (let i = 0; i < 3; i++) {console.log(i); // 0 1 2
}
- 三个格子:
起点; 条件; 步长
- let 代替 C 的
int
,用完就丢(不会泄漏出来)。
坑 | 例子 | 结果 |
---|---|---|
忘更新 | for(let i=0; i<3; ) { ... } | 死循环 |
用 var | for(var i=0; i<3; i++) { } console.log(i) | 循环外还能打印 i(3) |
条件写错 | for(let i=0; i>-1; i++) | 死循环 |
let sum = 0;
for (let i = 1; i <= 5; i++) {sum += i;
}
console.log(sum); // 15
明确循环次数用for,不明确用while
数组
声明方式
// 字面量(最常用)
let a = [10, 20, 30];
let aaa = [] //(等后面添加)// Array 构造器(不常用,可读性差)
let b = new Array(10, 20, 30);// 静态方法:把“类数组”或迭代对象变成真数组
let c = Array.from('abc'); // ['a','b','c']
let d = Array.of(3); // [3] 而不是 new Array(3) 生成空数组
类型 & 特点
点 | 说明 |
---|---|
动态长度 | arr.length 可读写,改大留空,改小截断 |
元素任意 | 数字、字符串、对象、函数、甚至数组套数组 |
索引 | 从 0 开始,最大索引 = length-1 |
取值 / 赋值
a[0]; // 10
a[2] = 99; // 改
a[5] = 77; // 自动扩容,中间留空位
数组的修改
想给字符串类型的元素前面或者后面加个什么东西,直接用加号+“拼接"即可。
arr[i] = arr[i] + ‘元’
数组的新增
-
数组.push() (常用) 将一个或多个元素加到数组末尾,并返回该数组的新长度。
arr.push(元素1, ..., 元素n) //将该函数直接输出,得到数组的新长度。 let arr = [1, '342r', 'adsa', 3333] document.write(arr.push('233', 23132,'d32')) //更新数组内容并输出“7”
-
数组.unshift() 将一个或多个元素加到数组开头,并返回该数组的新长度。
arr.unshift(元素1, ..., 元素n) //使用方法和push相同
数组求最值 遍历数组、设置最值变量,不断比较并更新最值即可。
数组的筛选 新建一个数组,遍历原有数组,将符合条件的放入新的数组
数组的删除
-
数组.pop() 删除一个尾部元素,并返回被删除的元素
-
数组.shift() 删除一个头部元素,并返回被删除的元素
-
增删改万能工具 数组.splice() 删除指定的一段元素,并可在该位置添加一段新的元素。
arr.splice(起始位置index, 要删除几个元素(不删就是0)count(后面可以接新添加的元素1,2,...,n))
- 要是只想添加,那就在第二个位置写0
- 如果只写了第一个数字,则会把该下标后面的元素全部删除
操作 | 方法 | 是否改变原数组 | 备注 |
---|---|---|---|
增 | push(...items) | ✅ | 末尾追加,返回新长度 |
unshift(...items) | ✅ | 头部追加 | |
splice(index,0,...items) | ✅ | 任意位置插入 | |
删 | pop() | ✅ | 删末尾,返回被删元素 |
shift() | ✅ | 删头部 | |
splice(index,n) | ✅ | 删任意连续 n 个 | |
slice(start,end) | ❌ | 返回切片,左闭右开 | |
改 | fill(value,start,end) | ✅ | 批量改值 |
查 | indexOf/lastIndexOf | ❌ | 找不到返回 -1 |
includes(value) | ❌ | 布尔版查找 | |
排序 | sort((a,b)=>a-b) | ✅ | 默认字典序,需传比较器 |
反转 | reverse() | ✅ | 直接倒序 |
最值 | Math.max(...arr) / Math.min(...arr) | ❌ | 需配合展开运算符 |
高阶函数
let nums = [3, 1, 4];let doubled = nums.map(n => n * 2); // [6, 2, 8]
let total = nums.reduce((s, n) => s + n, 0); // 8
let evens = nums.filter(n => n % 2 === 0); // [4]
空位 & 稀疏数组
let arr = [1, , 3]; // 索引 1 是 empty
arr[5] = 6; // 长度 6,但 2~4 都是 empty
遍历时空位会被 for...of
、forEach
跳过,但 map
会保留空位。
数组是“动态列表”,push/pop/splice
改长度,map/filter/reduce
玩数据。
简单排序方法 arr.sort()
默认按字符串字典序排序;想按数字大小排,必须给它一个“比较函数”。
默认行为
[3, 21, 7].sort(); // [21, 3, 7] —— 按字符串比较,'21'<'3'
比较数字:传比较函数
// 升序
arr.sort((a, b) => a - b);
//或者
arr.sort(function (a, b){return a - b})// 降序
arr.sort((a, b) => b - a);
//或者
arr.sort(function (a, b){return b - a})
- 返回值 < 0:a 排前面
- 返回值 = 0:顺序不动
- 返回值 > 0:b 排前面
复杂对象排序示例
const list = [{name:'Tom', age:20}, {name:'Bob', age:15}];
list.sort((x, y) => x.age - y.age); // 按年龄升序
原地修改 & 返回值
- 直接改原数组,同时返回排序后的同一数组(不是新数组)。
需求 | 写法示例 |
---|---|
随机打乱 | arr.sort(() => Math.random() - 0.5) |
中文拼音 | arr.sort((a,b)=>a.localeCompare(b,'zh-CN')) |
无参字典序,数字记得传函数;升序减,降序反,对象排序取属性。
函数
function 被设计为执行特定任务的代码块。我们将代码中重复的公共部分抽取并封装到代码中进行重复使用,以提高开发效率。
函数的使用: 先声明,后调用
//声明函数
function 函数名(形参列表,逗号隔开,可为空){函数体
}//调用函数
函数名(传入实参,没有形参就为空)
//示例 声明函数
function sum(start, end){let n = 0;for (let i = start; i <= end; i++){n += i;}document.write(n)}
//调用函数
sum(50, 100)
//返回值也会返回给函数的调用者
默认参数
如果用户未输入参数,那么参数默认为undefined。
如果函数中参数运算时有undefined,那么结果将为NaN。
我们可以在声明函数时给形参一个默认值。
function sum(start = 0, end = 50){}
也可以使用逻辑中断:
function sum(x, y){x = x || 0y = y || 0......
}
具名函数和匿名函数
具名函数就是普通的有名字的函数。匿名函数一般不能被直接使用。
匿名函数的使用:
-
函数表达式 将匿名函数赋值给一个变量,我们将其称为函数表达式
这种方式的函数必须先声明,后使用!(具名函数可以写在任何位置)
//声明函数 let fn = function() { }//调用函数 fn()
-
立即执行函数 避免全局变量之间的污染,可以在自己的局部变量内使用全局变量用过的变量名。
(function (形参) {函数体 } ) (实参); // 必须加上分号,也可以在最开头也加上一个//或者 (function (形参) {函数体 } (实参) );
注意事项
- 两个函数名相同的函数,后面的函数会覆盖前面的函数
- js中形参和实参的个数可以不一致。如果实参过少,那未被赋值的形参会自动填上undefined;如果实参过多,那么多余的实参会被忽略。
- 函数内部有一个arguments,里面装着所有实参
- 若在函数内部有变量没有声明就直接被赋值,则会被认为是全局变量()被认为是var。但是不常用。
- 只要是代码,就至少有一个作用域
- 函数内部为局部作用域,如果函数中还有函数,那就会再成一个局部作用域
- 变量的访问原则:先找局部,再找全局
对象
对象(object)是js的一种引用数据类型,是一种无序的数据集合“ul”(类比于数组,有序的数据集合“ol”)。
基本上等于结构体。
对象的声明
//基本方法
let 对象名 = {声明元素
}
对象中的元素一般由属性和方法组成
-
属性:对象的信息、特征。一般为名词性的键值对(
属性名:属性值
),多个键值对之间用逗号分隔。属性就是依附在对象上的变量(门面是变量,对象内就是属性)。
属性名可以用单、双引号包裹(一般情况下省略),除非遇到特殊符号如空格、中横线作为属性名时。
let obj = {name:'ljl',age:18,gender:'man',sing: function(){document.write('lalalala')}//若属性名为字符串、带有下划线则需带上单引号'best-friend':'lihua' }
-
方法:对象的功能、行为。
方法名:函数
对象的增删改查
查找、访问元素 对象.属性名
或者 对象.['属性名']
(中括号中不管是不是字符串都必须带上单引号)
修改元素 直接重新赋值即可
增加元素 对象.新建属性名 = 赋值
删除元素 delete delete 对象.属性名
遍历对象 for(in)语法
for(in)语法遍历数组:(输出的下标是字符串类型)
let arr = ['aa', 'b', 'ccc'] for (let k in arr) { console.log(k) //顺序遍历数组的下标,即输出:012。 //注意:这里输出的下标是字符串类型 document.write(arr[k]) }
一般不用这个方法遍历数组。
该语法中,输出属性值的方法必须是对象.['属性名']
let obj = {name:'ljl',age:18,gender:'man','ex-bf':'cjx'
}
for (let k in obj){console.log(k) //顺序打印出属性名document.write(obj[k])
}
对象数组
let people = [{name:'ljl', age:18, gender:'man', 'ex-bf':'cjx'},{name:'ljl', age:18, gender:'man', 'ex-bf':'cjx'},{name:'ljl', age:18, gender:'man', 'ex-bf':'cjx'},{name:'ljl', age:18, gender:'man', 'ex-bf':'cjx'}
]
//遍历对象数组
for (let i = 0; i < people.length; i++) {console.log(people[i].age)document.write(people[i]['ex-bf'])
}
内置对象
js内置对象,方便我们调用,提高开发效率
例如console.log
document.write
内置对象Math 类似于C语言中提供数学运算函数的函数库,这里我们通过调用对象元素的形式进行调用
方法 | 作用 | 示例 |
---|---|---|
Math.PI | 圆周率 π | 3.141592653589793 |
Math.E | 自然常数 e | 2.718281828459045 |
Math.LN2 | 2 的自然对数 | 0.6931471805599453 |
Math.LN10 | 10 的自然对数 | 2.302585092994046 |
Math.LOG2E | 以 2 为底 e 的对数 | 1.4426950408889634 |
Math.LOG10E | 以 10 为底 e 的对数 | 0.4342944819032518 |
Math.SQRT2 | 2 的平方根 | 1.4142135623730951 |
Math.SQRT1_2 | 1/2 的平方根 | 0.7071067811865476 |
Math.random() | 生成 [0, 1) 之间的随机小数 | 0.72634… |
Math.ceil(x) | 向上取整 | Math.ceil(4.2) → 5 |
Math.floor(x) | 向下取整 | Math.floor(4.9) → 4 |
Math.round(x) | 四舍五入 | Math.round(4.5) → 5 |
Math.max(a,b,...) | 取最大值 | Math.max(3, 7, 2) → 7 |
Math.min(a,b,...) | 取最小值 | Math.min(3, 7, 2) → 2 |
Math.pow(base, exp) | 幂运算 base^exp | Math.pow(2, 3) → 8 |
Math.abs(x) | 绝对值 | Math.abs(-5) → 5 |
随机生成函数Math.random()
-
Math.random()
永远返回[0, 1)
区间内的随机小数,即 含 0 不含 1。 -
0 → 10 的随机整数
Math.floor(Math.random() * (10 + 1))
先放大 11 倍,再向下取整 → 得到 0‒10 共 11 个值。
-
5 → 10 的随机整数
Math.floor(Math.random() * (10 - 5 + 1)) + 5
区间长度
(10-5+1)=6
,再加偏移量 5 → 得到 5‒10。 -
随机数组下标
const idx = Math.floor(Math.random() * arr.length); const randomItem = arr[idx];
其中arr.length已经是下标最大值加一了
-
通用公式:N → M 的随机整数
Math.floor(Math.random() * (M - N + 1)) + N
// 生成 N~M 之间的随机整数(包含 N 和 M) function getRandom(N, M) {return Math.floor(Math.random() * (M - N + 1)) + N; }console.log(getRandom(4, 8)); // 示例:输出 4~8 之间的随机整数
“区间长度乘随机,再向下取整,最后加起点”。