JavaScript
JavaScript 是什么
JavaScript 是世界上最流行的语言之一,是一种运行在客户端的脚本语言 (Script 是脚本的意思),它不需要编译,运行过程中由 js 解释器( js 引擎)逐行来进行解释并执行。
JavaScript 的作用
- 表单动态校验(密码强度检测)
- 网页特效
- 服务端开发(Node.js)
- 桌面程序(Electron)
- App(Cordova)
- 控制硬件-物联网(Ruff)
- 游戏开发(cocos2d-js)
浏览器执行 JS 简介
浏览器分成两部分:渲染引擎和 JS 引擎
**渲染引擎:**用来解析HTML与CSS,俗称内核,比如 chrome 浏览器的 blink ,老版本的 webkit
JS 引擎:也称为 JS 解释器。 用来读取网页中的JavaScript代码,对其处理后运行,比如 chrome 浏览器的 V8
其实浏览器本身并不会执行JS代码,而是通过内置 JavaScript 引擎(解释器) 来执行 JS 代码 。JS 引擎执行代码时逐行解释 每一句源码(转换为机器语言),然后由计算机去执行,所以 JavaScript 语言归为脚本语言,会逐行解释执行。
JS 的组成
ECMAScript
ECMAScript 是由ECMA 国际( 原欧洲计算机制造商协会)进行标准化的一门编程语言,这种语言在万维网上应用广泛,它往往被称为 JavaScript 或 JScript,但实际上后两者是 ECMAScript 语言的实现和扩展。
DOM ——文档对象模型
文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标记语言的标准编程接口。 通过 DOM 提供的接口可以对页面上的各种元素进行操作(大小、位置、颜色等)。
BOM ——浏览器对象模型
BOM (Browser Object Model,简称BOM) 是指浏览器对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等。
JS书写位置
行内
- 可以将单行或少量 JS 代码写在HTML标签的事件属性中(以 on 开头的属性),如:onclick
- 注意单双引号的使用:在HTML中我们推荐使用双引号, JS 中我们推荐使用单引号
- 可读性差, 在html中编写JS大量代码时,不方便阅读;
- 引号易错,引号多层嵌套匹配时,非常容易弄混;
- 特殊情况下使用
内嵌
- 利于HTML页面代码结构化,把大段 JS代码独立到 HTML 页面之外,既美观,也方便文件级别的复用
- 引用外部 JS文件的 script 标签中间不可以写代码
- 适合于JS 代码量比较大的情况
### JavaScript 注释
#### 单行注释
```javascript
// 我是一行文字
多行注释
JavaScript 输入输出语句
为了方便信息的输入输出,JS中提供了一些输入输出语句,其常用的语句如下:
方法 | 说明 | 作用于 |
---|
alert(msg) | 浏览器弹出警示框 | 浏览器 | console.log(msg) | 浏览器控制台打印输出信息 | 浏览器 | prompt(info) | 浏览器弹出输入框,用户可以输入 | 浏览器 |
**注意:**alert() 主要用来显示消息给用户,console.log() 用来给程序员自己看运行时的消息。
变量
什么是变量
变量是用于存放数据的容器。 我们通过 变量名 获取数据,甚至数据可以修改,变量是程序在内存中申请的一块用来存放数据的空间。
变量的使用
变量在使用时分为两步: 1. 声明变量 2. 赋值
声明变量
var age;
var 是一个 JS关键字,用来声明变量( variable 变量的意思 )。使用该关键字声明变量后,计算机会自动为变量分配内存空间,而age 是程序员定义的变量名,我们要通过变量名来访问内存中分配的空间。
赋值
age = 10;
变量的初始化
声明一个变量并赋值, 我们称之为变量的初始化。
var age = 18;
更新变量
一个变量被重新复赋值后,它原有的值就会被覆盖,变量值将以最后一次赋的值为准。
var age = 18;
age = 81; // 最后的结果就是81因为18 被覆盖掉了
同时声明多个变量
同时声明多个变量时,只需要写一个 var, 多个变量名之间使用英文逗号隔开。
var age = 10, name = 'zs', sex = 2;
声明变量特殊情况
情况 | 说明 | 输出结果 |
---|
var age ; console.log (age); | 只声明 不赋值 | undefined | console.log(age) | 不声明 不赋值 直接使用 | 报错 | age = 10; console.log (age); | 不声明 只赋值 | 10 |
变量命名规范
- 由字母(A-Za-z)、数字(0-9)、下划线(_)、美元符号( $ )组成,如:usrAge, num01, _name
- 严格区分大小写。var app; 和 var App; 是两个变量
- 不能 以数字开头。 18age 是错误的
- 不能 是关键字、保留字。例如:var、for、while
- 变量名必须有意义。 MMD BBD nl → age
- 遵守驼峰命名法。首字母小写,后面单词的首字母需要大写。 myFirstName
数据类型
数据类型简介
变量是用来存储值的所在处,它们有名字和数据类型。变量的数据类型决定了如何将代表这些值的位存储到计算机的 内存中。JavaScript 是一种弱类型或者说动态语言。这意味着不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。
var age = 10;
var areYouOk = '是的';
在代码运行时,变量的数据类型是由 JS引擎 根据 = 右边变量值的数据类型来判断 的,运行完毕之后, 变量就确定了数据类型。
JavaScript 拥有动态类型,同时也意味着相同的变量可用作不同的类型:
var x = 6;
var x = "Bill";
为什么需要数据类型
在计算机中,不同的数据所需占用的存储空间是不同的,为了便于把数据分成所需内存大小不同的数据,充分利 用存储空间,于是定义了不同的数据类型。 简单来说,数据类型就是数据的类别型号。比如姓名“张三”,年龄18,这些数据的类型是不一样的。
数据类型的分类
- 值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol。
- 引用数据类型(对象类型):对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)。
数字型 Number
JavaScript 数字类型既可以用来保存整数值,也可以保存小数(浮点数)。
var age = 21;
var Age = 21.3747;
不过,我们也可以数据进制型数据:
var num1 = 07;
var num2 = 019;
var num3 = 08;
var num = 0xA;
我们也可以输入一个数字型范围:
alert(Number.MAX_VALUE);
alert(Number.MIN_VALUE);
此外,还有三个特殊值:
alert(Infinity);
alert(-Infinity);
alert(NaN);
isNaN()
isNaN()用来判断一个变量是否为非数字的类型,返回 true 或者 false
var usrAge = 21;
var isOk = isNaN(userAge);
console.log(isNum);
var usrName = "andy";
console.log(isNaN(userName));
字符串型 String
字符串型可以是引号中的任意文本,其语法为 双引号 “” 和 单引号’’
var strMsg = "我爱北京天安门~";
var strMsg2 = '我爱吃猪蹄~';
var strMsg3 = 我爱大肘子;
字符串引号嵌套
JS 可以用单引号嵌套双引号 ,或者用双引号嵌套单引号 (外双内单,外单内双
var strMsg = '我是"高帅富"程序猿';
var strMsg2 = "我是'高帅富'程序猿";
var badQuotes = 'What on earth?";
字符串转义符
类似HTML里面的特殊字符,字符串中也有特殊字符,我们称之为转义符。 转义符都是 \ 开头的,常用的转义符及其说明如下:
转义符 | 解释说明 |
---|
\n | 换行符,n 是 newline 的意思 | \ \ | 斜杠 \ | ’ | ’ 单引号 | \” | ”双引号 | \t | tab 缩进 | \b | 空格 ,b 是 blank 的意思 |
字符串长度
字符串是由若干字符组成的,这些字符的数量就是字符串的长度。通过字符串的 length 属性可以获取整个字符 串的长度。
var strMsg = "我是帅气多金的程序猿!";
alert(strMsg.length);
字符串拼接
多个字符串之间可以使用 + 进行拼接,其拼接方式为 字符串 + 任何类型 = 拼接之后的新字符串, 拼接前会把与字符串相加的任何类型转成字符串,再拼接成一个新的字符串。
alert('11' + 12);
console.log('我' + 18);
var age = 18;
console.log('我' + age);
console.log('我' + age + '岁啦');
布尔型 Boolea
布尔类型有两个值:true 和 false ,其中 true 表示真(对),而 false 表示假(错)。 布尔型和数字型相加的时候, true 的值为 1 ,false 的值为 0。
console.log(true + 1);
console.log(false + 1);
Undefined 和 Null
一个声明后没有被赋值的变量会有一个默认值 undefined ( 如果进行相连或者相加时,注意结果)
var variable;
console.log(variable);
console.log('你好' + variable);
console.log(11 + variable);
console.log(true + variable);
一个声明变量给 null 值,里面存的值为空
var vari = null;
console.log('你好' + vari);
console.log(11 + vari);
console.log(true + vari);
获取变量数据类型
typeof 可用来获取检测变量的数据类型
var num = 18;
console.log(typeof num)
不同类型的返回值:
类型 | 结果 |
---|
Undefined | "undefined" | Null | "object" | Boolean | "boolean" | Number | "number" | BigInt(ECMAScript 2020 新增) | "bigint" | String | "string" | Symbol (ECMAScript 2015 新增) | "symbol" | 宿主对象(由 JS 环境提供) | 取决于具体实现 | Function 对象 (按照 ECMA-262 规范实现 [[Call]]) | "function" | 其他任何对象 | "object" |
数据类型转换
类型转换可以分为两种:隐式类型转换 和 显式类型转换 。
显式类型强制转换 是指当开发人员通过编写适当的代码用于在类型之间进行转换,比如:Number(value)。
隐式类型转换 是指在对不同类型的值使用运算符时,值可以在类型之间自动的转换,比如0 == null
需要注意的是:
- NaN 的数据类型是 number
- 数组(Array)的数据类型是 object
- 日期(Date)的数据类型为 object
- null 的数据类型是 object
- 未定义变量的数据类型为 undefined
如果对象是 JavaScript Array 或 JavaScript Date ,我们就无法通过 typeof 来判断他们的类型,因为都是 返回 object。
在 JavaScript 中只有 3 种类型的转换:
**String 类型:**String() / toString()
**Number 类型:**Number() / parseFloat() / parseInt()
Boolean 类型: Boolean()
String 类型
方式 | 说明 | 示例 |
---|
toString() | 转成字符串 | var num=1;console.log(num.toString()); | String()强制转换 | 转成字符串 | var num=1;console.log(String(num); | 使用+ 拼接字符串 | 该方式属于隐式转换,和字符串拼接的结果都是字符串 | var num=1;console.log(num + ‘字符串’); |
转换为数字型
方式 | 说明 | 示例 |
---|
parseInt(String) | 将String类型转换为整数数值类型 | parseInt(‘99’) | parseFloat(String) | 将String类型转换为浮点数数值类型 | parseFloat(‘99.99’) | Number() | 将String转换为数值型 | Number(‘99’) | 隐式转换( - * /) | 利用算术运算隐式转换为数值型 | console.log(‘99’-0); |
注意: Number()函数会将空字符串转换为 0,其他的字符串会转换为 NaN (不是个数字)。
转换为布尔型
方式 | 说明 | 示例 |
---|
Boolean() | 将其他类型转换为布尔型 | Boolean(true) |
PS:
- 代表
空 、否定的值 会被转换为 false ,如 ‘’、0、NaN、null、undefined - 其余值都会被转换为 true
示例:
console.log(Boolean(''));
console.log(Boolean(0));
console.log(Boolean(NaN));
console.log(Boolean(null));
console.log(Boolean(undefined));
console.log(Boolean('小白'));
console.log(Boolean(12));
运算符
运算符(operator)也被称为操作符,是用于实现赋值、比较和执行算数运算等功能的符号。
JavaScript常用运算符
- 算数运算符
- 递增和递减运算符
- 比较运算符
- 逻辑运算符
- 赋值运算符
算数运算符
算术运算使用的符号,用于执行两个变量或值的算术运算。
运算符 | 说明 | 示例 |
---|
+ | 加 | 1 + 1 | - | 减 | 1 - 1 | * | 乘 | 1 * 1 | / | 除 | 1 / 1 | % | 取余 | 9 % 2 = 1 |
浮点数的精度问题
浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数。所以:不要直接判断两个浮点数是否相等 。
var result = 0.1 + 0.2;
console.log(0.07 * 100);
递增和递减运算符
如果需要反复给数字变量添加或减去1,可以使用递增(++)和递减( --)运算符来完成。
在 JavaScript 中,递增(++)和递减( – )既可以放在变量前面,也可以放在变量后面。放在变量前面时,我们可以称为前置递增(递减)运算符,放在变量后面时,我们可以称为后置递增(递减)运算符。
**注意:**递增和递减运算符必须和变量配合使用。
前置递增运算符
++num 前置递增,就是自加1,类似于 num = num + 1,它是先自加,后返回值。
var num = 10;
alert(++num + 10);
后置递增运算符
num++ 后置递增,就是自加1,类似于 num = num + 1 ,它是先返回原值,后自加。
var num = 10;
alert(10 + num++);
比较运算符
比较运算符(关系运算符)是两个数据进行比较时所使用的运算符,比较运算后,会返回一个布尔值 (true / false)作为比较运算的结果。
运算符名称 | 说明 | 示例 | 结果 |
---|
< | 小于 | 1 < 2 | true | > | 大于 | 1 > 2 | false | <= | 小于等于 | 2 <= 2 | true | >= | 大于等于 | 3 >= 2 | true | == | 判断(会转型) | 1 == 1 | true | != | 不等于 | 1 != 1 | false | === !== | 全等,要求数据与类型都一致 | 1 === ‘1’ | false |
逻辑运算符
逻辑运算符是用来进行布尔值运算的运算符,其返回值也是布尔值。
运算符 | 说明 | 示例 |
---|
&& | 逻辑与,简称与 and | true && false | || | 逻辑或,简称或 or | true || false | ! | 逻辑非,简称非 not | ! true |
赋值运算符
运算符 | 说明 | 示例 |
---|
= | 直接赋值 | var num = 1 | +=、-= | 加、减一个数后再赋值 | var num =10;num += 5 | *=、/=、%= | 乘、除、取模后再赋值 | var num =10;num *= 5 |
示例:
var age = 10;
age += 5;
age -= 5;
age *= 10;
运算符优先级
下面的表格将所有运算符按照优先级的不同从高(19)到低(1)排列。
流程控制
在一个程序执行的过程中,各条代码的执行顺序对程序的结果是有直接影响的。很多时候我们要通过控制代码 的执行顺序来实现我们要完成的功能。 流程控制主要有三种结构,分别是顺序结构 、分支结构 和循环结构 ,这三种结构代表三种代码执行的顺序。
顺序流程控制
顺序结构是程序中最简单、最基本的流程控制,它没有特定的语法结构,程序会按照代码的先后顺序,依次执行。
分支流程控制
由上到下执行代码的过程中,根据不同的条件,执行不同的路径代码(执行代码多选一的过程),从而得到不同的结果,JS 语言提供了两种分支结构语句:if 语句 、switch 语句 。
if 语句
语法结构
if (条件表达式) {
}
if else语句(双分支语句)
语法结构
if (条件表达式) {
} else {
}
if else if 语句(多分支语句)
语法结构
if (条件表达式1) {
语句1;
} else if (条件表达式2) {
语句2;
} else if (条件表达式3) {
语句3;
....
} else {
}
三元表达式
三元表达式也能做一些简单的条件选择。 有三元运算符组成的式子称为三元表达式。
**语法结构:**表达式1 ? 表达式2 : 表达式3;
执行过程:如果表达式1为 true ,则返回表达式2的值,如果表达式1为 false,则返回表达式3的值。
switch 语句
switch 语句也是多分支语句,它用于基于不同的条件来执行不同的代码。当要针对变量设置一系列的特定值 的选项时,就可以使用 switch。
switch( 表达式 ){
case value1:
break;
case value2:
break;
default:
}
switch 语句和 if else if 语句的区别
- 一般情况下,它们两个语句可以相互替换
- switch…case 语句通常处理 case为比较确定值的情况, 而 if…else…语句更加灵活,常用于范围判断(大于、等 于某个范围)
- switch 语句进行条件判断后直接执行到程序的条件语句,效率更高。而if…else 语句有几种条件,就得判断多 少次。
- 当分支比较少时,if… else语句的执行效率比 switch语句高。
- 当分支比较多时,switch语句的执行效率比较高,而且结构更清晰。
循环
在实际问题中,有许多具有规律性的重复操作 ,因此在程序中要完成这类操作就需要重复执行某些语句 。
在Js 中,主要有三种类型的循环语句:
- for 循环
- while 循环
- do…while 循环
for 循环
在程序中,一组被重复执行的语句被称之为循环体 ,能否继续重复执行,取决于循环的终止条件 。由循环体 及循环的终止条件组成的语句,被称之为循环语句 。
for 循环主要用于把某些代码循环若干次,通常跟计数有关系。其语法结构如下:
for(初始化变量; 条件表达式; 操作表达式 ){
}
- **初始化变量:**通常被用于初始化一个计数器,该表达式可以使用 var 关键字声明新的变量,这个变量帮我们来记录次数。
- 条件表达式:用于确定每一次循环是否能被执行。如果结果是 true 就继续循环,否则退出循环。
- **操作表达式:**每次循环的最后都要执行的表达式。通常被用于更新或者递增计数器变量。当然,递减变量也是可以的。
执行过程:
- 初始化变量,初始化操作在整个 for 循环只会执行一次。
- 执行条件表达式,如果为true,则执行循环体语句,否则退出循环,循环结束。
- 执行操作表达式,此时第一轮结束。
- 第二轮开始,直接去执行条件表达式(不再初始化变量),如果为 true ,则去执行循环体语句,否则退出循环。
- 继续执行操作表达式,第二轮结束。
- 后续跟第二轮一致,直至条件表达式为假,结束整个 for 循环。
while 循环
while 语句可以在条件表达式为真的前提下,循环执行指定的一段代码,直到表达式不为真时结束循环。 while语句的语法结构如下:
while (条件表达式) {
}
执行过程:
- 先执行条件表达式,如果结果为 true,则执行循环体代码;如果为 false,则退出循环,执行后面代码
- 执行循环体代码
- 循环体代码执行完毕后,程序会继续判断执行条件表达式,如条件仍为true,则会继续执行循环体,直到循 环条件为 false 时,整个循环过程才会结束
do while 循环
do… while 语句其实是 while 语句的一个变体。该循环会先执行一次代码块,然后对条件表达式进行判断,如 果条件为真,就会重复执行循环体,否则退出循环。
do {
} while(条件表达式);
执行思路:
- 先执行一次循环体代码
- 再执行条件表达式,如果结果为 true,则继续执行循环体代码,如果为 false,则退出循环,继续执行后面 代码
continue break
continue 关键字
continue 关键字用于立即跳出本次循环,继续下一次循环(本次循环体中 continue 之后的代码就会少执行一 次)
for (var i = 1; i <= 5; i++) {
if (i == 3) {
console.log('跳出循环...');
continue;
}
console.log('正在执行第' + i + '次循环');
}
break 关键字
break 关键字用于立即跳出整个循环(循环结束)。
for (var i = 1; i <= 5; i++) {
if (i == 3) {
console.log('退出循环...');
break;
}
console.log('正在执行第' + i + '次循环');
}
命名规范
标识符命名规范
- 变量、函数的命名必须要有意义
- 变量的名称一般用名词
- 函数的名称一般用动词
操作符规范
for (var i = 1; i <= 5; i++) {
if (i == 3) {
console.log('跳出循环...');
continue;
}
console.log('正在执行第' + i + '次循环');
}
单行注释规范
for (var i = 1; i <= 5; i++) {
if (i == 3) {
console.log('跳出循环...');
continue;
}
console.log('正在执行第' + i + '次循环');
}
数组
数组是指一组数据的集合 ,其中的每个数据被称作元素 ,在数组中可以存放任意类型的元素 。数组是一种将一组数据存储在单个变量名下 的优雅方式。
var num = 10;
var arr = [1, 2, 3, 4, 5];
创建数组
new 创建数组
var 数组名 = new Array();
var arr = new Array();
数组字面量创建数组
var 数组名 = [];
var 数组名 = ['小白','小黑','大黄','瑞奇'];
数组元素的类型
数组中可以存放任意类型的数据,例如字符串,数字,布尔值等。
var arrStus = ['小白',12,true,28.9];
获取数组中的元素
**索引 (下标) :**用来访问数组元素的序号(数组下标从 0 开始),数组可以通过索引来访问、设置、修改对应的数组元素,我们可以通过“数组名[索引]”的形式来获取数组中的元素。
var arrStus = [1,2,3];
alert(arrStus[1]);
数组的长度
使用“数组名.length”可以访问数组元素的数量(数组长度)。
var arrStus = [1,2,3];
alert(arrStus.length);
数组中新增元素
通过修改 length 长度新增数组元素
可以通过修改 length 长度来实现数组扩容的目的 ,length 属性是可读写的
var arr = ['red', 'green', 'blue', 'pink'];
arr.length = 7;
console.log(arr);
console.log(arr[4]);
console.log(arr[5]);
console.log(arr[6]);
通过修改数组索引新增数组元素
可以通过修改数组索引的方式追加数组元素
var arr = ['red', 'green', 'blue', 'pink'];
arr[4] = 'hotpink';
console.log(arr);
JavaScript 函数
函数的概念
在 JS 里面,可能会定义非常多的相同代码或者功能相似的代码,这些代码可能需要大量重复使用。 虽然 for循环语句也能实现一些简单的重复操作,但是比较具有局限性,此时我们就可以使用 JS 中的函数。
**函数:**就是封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用。
函数的使用
函数在使用时分为两步:声明函数 和调用函数 。
声明函数
function 函数名() {
}
- function 是声明函数的关键字,必须小写
- 由于函数一般是为了实现某个功能才定义的, 所以通常我们将函数名命名为动词,比如 getSum
调用函数
函数名();
**注意:**声明函数本身并不会执行代码,只有调用函数时才会执行函数体代码。
函数的封装
函数的封装是把一个或者多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口,封装类似于将电脑配件整合组装到机箱中 ( 类似快递打包)。
function getSum() {
var sumNum = 0;
for (var i = 1; i <= 100; i++) {
sumNum += i;
}
alert(sumNum);
}
getSum();
函数的参数
在声明函数时,可以在函数名称后面的小括号中添加一些参数,这些参数被称为形参 ,而在调用该函数时, 同样也需要传递相应的参数,这些参数被称为实参 。
参数 | 说名 |
---|
形参 | 形式上的参数,函数定义的时候传递的参数,当前并不知道是什么 | 实参 | 实际上的参数,函数调用的时候传递的参数,实参是传递给形参的 |
参数的作用 : 在函数内部某些值不能固定,我们可以通过参数在调用函数时传递不同的值进去。
function 函数名(形参1, 形参2 , 形参3...) {
}
函数名(实参1, 实参2, 实参3...);
示例:
function getSum(num1, num2) {
console.log(num1 + num2);
}
getSum(1, 3);
getSum(6, 5);
函数形参和实参个数不匹配问题
参数个数 | 说明 |
---|
实参个数等于形参个数 | 结果正常 | 实参个数多余形参个数 | 只取到形参的个数,多余的将会被忽略 | 实参个数小余形参个数 | 多的形参定义为undefined |
栗子:
function sum(num1, num2) {
console.log(num1 + num2);
}
sum(100, 200);
sum(100, 400, 500, 700);
sum(200);
**注意:**在JavaScript中,形参的默认值是undefined。
函数的返回值
有的时候,我们会希望函数将值返回给调用者,此时通过使用 return 语句就可以实现:
function 函数名(){
...
return 需要返回的值;
}
函数名();
注意:
- 在使用 return 语句时,函数会停止执行,并返回指定的值
- 如果函数没有 return ,返回的值是 undefined
- return 只能返回一个值。如果用逗号隔开多个值,以最后一个为准。
return 终止函数
return 语句之后的代码不被执行:
function add(num1,num2){
return num1 + num2;
alert('我不会被执行,因为前面有 return');
}
var resNum = add(21,6);
alert(resNum);
break ,continue ,return 的区别
- break :结束当前的循环体(如 for、while)
- continue :跳出本次循环,继续执行下次循环(如 for、while)
- return :不仅可以退出循环,还能够返回 return 语句中的值,同时还可以结束当前的函数体内的代码
arguments
当我们不确定有多少个参数传递的时候,可以用 arguments 来获取。在 JavaScript 中,arguments 实际上它 是当前函数的一个内置对象 。所有函数都内置了一个 arguments 对象,arguments 对象中存储了传递的所有 实参 。
arguments展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点:
- 具有 length 属性
- 按索引方式储存数据
- 不具有数组的 push , pop 等方法
arguments的使用
function maxValue() {
var max = arguments[0];
for (var i = 0; i < arguments.length; i++) {
if (max < arguments[i]) {
max = arguments[i];
}
}
return max;
}
console.log(maxValue(2, 4, 5, 9));
console.log(maxValue(12, 4, 9));
函数的两种声明方式
自定义函数方式(命名函数)
- 因为有名字,所以也被称为命名函数
- 调用函数的代码既可以放到声明函数的前面,也可以放在声明函数的后面
示例:
function fn() {...}
fn();
函数表达式方式(匿名函数)
- 因为函数没有名字,所以也被称为匿名函数
- 这个fn 里面存储的是一个函数
- 函数表达式方式原理跟声明变量方式是一致的
- 函数调用的代码必须写到函数体后面
var fn = function(){...};
fn();
作用域
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这 个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
JavaScript(es6前)中的作用域有两种:
- 全局作用域
- 局部作用域(函数作用域)
全局作用域
作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件。
局部作用域 (函数作用域)
作用于函数内的代码环境,就是局部作用域。 因为跟函数有关系,所以也称为函数作用域。
块级作用域
块作用域由 { } 包裹,在其他编程语言中(如 java、c#等),在 if 语句、循环语句中创建的变量,仅仅只能在本 if 语句、本循 环语句中使用,如下面的Java代码:
if(true){
int num = 123;
system.out.print(num);
}
system.out.print(num);
但Js中没有块级作用域(在ES6之前)的,例如:
if(true){
var num = 123;
console.log(123);
}
console.log(123);
变量的作用域
在中,根据作用域的不同,变量可以分为两种:
- 全局变量
- 局部变量
全局变量
在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)。
- 全局变量在代码的任何位置都可以使用
- 在全局作用域下 var 声明的变量 是全局变量
- 特殊情况下,在函数内不使用 var 声明的变量也是全局变量(不建议使用)
局部变量
在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)
- 局部变量只能在该函数内部使用
- 在函数内部 var 声明的变量是局部变量
- 函数的形参实际上就是局部变量
全局变量和局部变量的区别
- 全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
- 局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被 销毁,因此更节省内存空间
作用域链
在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。
作用域链决定了哪些数据能被函数访问。当一个函数创建后,它的作用域链会被创建此函数的作用域中可访问的数据对象填充。
说直白一点就是 作用域的集合就是作用域链(子集可以访问父集,父集不能访问子集)
function fn(){
var a=10;
function fn1(){
var b=20;
alert(a)
function fn2(){
alert(b)
alert(a)
}
fn2()
}
fn1()
}
fn()
alert(b)
上面这个案例就说明了作用域链的概念,它就是作用域的集合组合起来的一个东西
从作用域链的结构可以看出,函数在执行的过程中,先从自己内部寻找变量,如果找不到,再从创建当前函数所在的作用域去找,从此往上,也就是向上一级找,直到找到全局作用域还是没找到。
作用域链代码优化
在运行期上下文的作用域链中,标识符所在的位置越深,读写速度就会越慢。如上面案例所示,因为全局变量总是存在于运行期上下文作用域链的最末端,因此在标识符解析的时候,查找全局变量是最慢的。
所以,在编写代码的时候应尽量少使用全局变量,尽可能使用局部变量。
执行顺序
当在作用域内访问 变量/方法 的时候,会找离自己最近的那个 变量/方法 (就近原则)
var a=10;
function fn(){
var a=20;
console.log(a)
}
fn()
总结
1、函数在执行的过程中,先从自己内部寻找变量 2、如果找不到,再从创建当前函数所在的作用域去找,从此往上,也就是向上一级找。 当在作用域内访问 变量/方法 的时候,会找离自己最近的那个 变量/方法 (就近原则)
预解析
JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的时 候分为两步:预解析和代码执行。
**预解析:**在当前作用域下, JS 代码执行之前,浏览器会默认把带有 var 和 function 声明的变量在内存中 进行提前声明或者定义。
代码执行: 从上到下执行JS语句。
变量预解析(变量提升)
预解析也叫做变量、函数提升。
变量提升: 变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升
函数预解析(函数提升)
函数提升: 函数的声明会被提升到当前作用域 的最上面,但是不会调用函数。
需要注意的是:函数表达式在调用的时候必须写在的下面
var fun = function fn(){
}
fn();
fn();
var fun = function fn(){
}
对象
现实生活中:万物皆对象,对象是一个具体的事物,看得见摸得着的实物。例如,一本书、一辆汽车、一个人 可以是“对象”,一个数据库、一张网页、一个与远程服务器的连接也可以是“对象”
在 JavaScript 中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、 函数等。
对象是由属性 和方法 组成的。
- 属性:事物的
特征 ,在对象中用属性 来表示(常用名词) - 方法:事物的
行为 ,在对象中用方法 来表示(常用动词)
创建对象的三种方式
- 利用字面量创建对象
- 利用 new Object 创建对象
- 利用构造函数创建对象
利用字面量创建对象
对象字面量:就是花括号 { } 里面包含了表达这个具体事物(对象)的属性和方法。 { } 里面采取键值对的形式表示
- 键:相当于属性名
- 值:相当于属性值,可以是任意类型的值(数字类型、字符串类型、布尔类型,函数类型等)
var star = {
name: 'pink',
age: 18,
sex: '男',
sayHi: function () {
alert('大家好啊~');
}
};
利用new Object创建对象
var andy = new Obect();
andy.name = 'zhangsan';
andy.age = 18;
andy.sex = '男';
andy.sayHi = function(){
alert('大家好啊~');
}
注意:
- Object() :第一个字母大写
- new Object() :需要 new 关键字
- 使用的格式:对象.属性 = 值
利用构造函数创建对象
**构造函数 :**是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 运算符一起 使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
在 js 中,使用构造函数要时要注意以下两点:
- 构造函数用于创建某一类对象,其首字母要大写
- 构造函数要和 new 一起使用才有意义
示例:
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.sayHi = function () {
alert('我的名字叫:' + this.name + ',年龄:' + this.age + ',性别:' + this.sex);
}
}
var bigbai = new Person('大白', 100, '男');
var smallbai = new Person('小白', 21, '男');
console.log(bigbai.name);
console.log(smallbai.name);
注意:
- 构造函数约定首字母大写。
- 函数内的属性和方法前面需要添加 this ,表示当前对象的属性和方法。
- 构造函数中不需要 return 返回结果。
- 当我们创建对象的时候,必须用 new 来调用构造函数。
构造函数和对象的区别:
- 构造函数,如 Stars(),抽象了对象的公共部分,封装到了函数里面,它泛指某一大类(class)
- 创建对象,如 new Stars(),特指某一个,通过 new 关键字创建对象的过程我们也称为对象实例化
对象的调用
- 对象里面的属性调用 : 对象.属性名 ,这个小点 . 就理解为“ 的 ”
- 对象里面属性的另一种调用方式 : 对象[‘属性名’],注意方括号里面的属性必须加引号,我们后面会用
- 对象里面的方法调用:对象.方法名() ,注意这个方法名字后面一定加括号
console.log(star.name)
console.log(star['name'])
star.sayHi();
变量、属性、函数、方法总结
**变量:**单独声明赋值,单独存在
**属性:**对象里面的变量称为属性,不需要声明,用来描述该对象的特征
**函数:**单独存在的,通过“函数名()”的方式就可以调用
**方法:**对象里面的函数称为方法,方法不需要声明,使用“对象.方法名()”的方式就可以调用,方法用来描述该对象的 行为和功能。
new关键字
new 在执行时会做四件事情:
- 在内存中创建一个新的空对象。
- 让 this 指向这个新的对象。
- 执行构造函数里面的代码,给这个新对象添加属性和方法。
- 返回这个新对象(所以构造函数里面不需要return)
遍历对象属性
for…in 语句用于对数组或者对象的属性进行循环操作。 其语法如下:
for (变量 in 对象名字) {
}
语法中的变量是自定义的,它需要符合命名规范,通常我们会将这个变量写为 k 或者 key。
for (var k in obj) {
console.log(k);
console.log(obj[k]);
}
JavaScript 内置对象
JavaScript 中的对象分为3种:自定义对象 、内置对象、 浏览器对象。内置对象就是指 JS 语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法)其优点就是帮助我们快速开发 ,JavaScript 提供了多个内置对象:Math、 Date 、Array、String等。
Math对象
Math 对象不是构造函数,它具有数学常数和函数的属性和方法。跟数学相关的运算(求绝对值,取整、最大值 等)可以使用 Math 中的成员。
常用方法:
Math.PI
Math.floor()
Math.ceil()
Math.round()
Math.abs()
Math.max()/Math.min()
随机数方法 random()
random() 方法可以随机返回一个小数,其取值范围是 [0,1),左闭右开 0 <= x < 1
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
日期对象
Date 对象和 Math 对象不一样,他是一个构造函数,所以我们需要实例化后才能使用,Date 实例用来处理日期和时间。
Date()方法的使用
var now = new Date();
console.log(now);
Date() 构造函数的参数
如果括号里面有时间,就返回参数里面的时间。例如日期格式字符串为‘2019-5-1’,可以写成new Date(‘2019-5-1’) 或者 new Date(‘2019/5/1’)。
如果Date()不写参数,就返回当前时间,如果Date()里面写参数,就返回括号里面输入的时间。
日期格式化
方法 | 描述 |
---|
getDate() | 返回月中的第几天(从 1 到 31)。 | getDay() | 返回星期几(0-6)。 | getFullYear() | 返回年份。 | getHours() | 返回小时(从 0-23)。 | getMilliseconds() | 返回毫秒(0-999)。 | getMinutes() | 返回分钟(从 0-59)。 | getMonth() | 返回月份(从 0-11)。 | getSeconds() | 返回秒数(从 0-59)。 | getTime() | 返回自 1970 年 1 月 1 日午夜以来与指定日期的毫秒数。 | getTimezoneOffset() | 返回 UTC 时间与本地时间之间的时差,以分钟为单位。 | getUTCDate() | 根据世界时,返回月份中的第几天(从 1 到 31)。 | getUTCDay() | 根据世界时,返回星期几(0-6)。 | getUTCFullYear() | 根据世界时,返回年份。 | getUTCHours() | 根据世界时,返回小时(0-23)。 | getUTCMilliseconds() | 根据世界时,返回毫秒数(0-999)。 | getUTCMinutes() | 根据世界时,返回分钟(0-59)。 | getUTCMonth() | 根据世界时,返回月份(0-11)。 | getUTCSeconds() | 根据世界时,返回秒数(0-59)。 | getYear() | 已弃用。请改用 getFullYear() 方法 | now()] | 返回自 1970 年 1 月 1 日午夜以来的毫秒数。 | parse() | 解析日期字符串并返回自 1970 年 1 月 1 日以来的毫秒数。 | setDate() | 设置 Date 对象中月的某一天。 | setFullYear() | 设置日期对象的年份 | setHours() | 设置日期对象的小时。 | setMilliseconds() | 设置日期对象的毫秒数。 | setMinutes() | 设置日期对象的分钟数。 | setMonth() | 设置日期对象的月份。 | setSeconds() | 设置日期对象的秒数。 | setTime() | 将日期设置为 1970 年 1 月 1 日之后/之前的指定毫秒数。 | setUTCDate() | 根据世界时,设置 Date 对象中月份的一天。 | setUTCFullYear() | 根据世界时,设置日期对象的年份。 | setUTCHours() | 根据世界时,设置日期对象的小时。 | setUTCMilliseconds() | 根据世界时,设置日期对象的毫秒数。 | setUTCMinutes() | 根据世界时,设置日期对象的分钟数。 | setUTCMonth() | 根据世界时,设置日期对象的月份。 | setUTCSeconds() | 根据世界时,设置日期对象的秒数。 | setYear() | 已弃用。请改用 setFullYear() 方法 | toDateString() | 将 Date 对象的日期部分转换为可读字符串。 | toGMTString() | 已弃用。请改用 toUTCString() 方法 | toISOString() | 使用 ISO 标准将日期作为字符串返回。 | toJSON() | 以字符串形式返回日期,格式为 JSON 日期。 | toLocaleDateString() | 使用区域设置约定将 Date 对象的日期部分作为字符串返回。 | toLocaleTimeString() | 使用区域设置约定将 Date 对象的时间部分作为字符串返回。 | toLocaleString() | 使用区域设置约定将 Date 对象转换为字符串。 | toString() | 将 Date 对象转换为字符串。 | toTimeString() | 将 Date 对象的时间部分转换为字符串。 | toUTCString() | 根据世界时,将 Date 对象转换为字符串。 | UTC() | 根据 UTC 时间,返回自 1970 年 1 月 1 日午夜以来的日期中的毫秒数。 | valueOf() | 返回 Date 对象的原始值。 |
创建一个日期对象的多种方法
var today = new Date();
var birthday = new Date('December 17, 1995 03:24:00');
var birthday = new Date('1995-12-17T03:24:00');
var birthday = new Date(1995, 11, 17);
var birthday = new Date(1995, 11, 17, 3, 24, 0);
数组对象
检测是否为数组
- instanceof 运算符,可以判断一个对象是否属于某种类型
- Array.isArray()用于判断一个对象是否为数组,isArray() 是 HTML5 中提供的方法
var arr = [1, 23];
var obj = {};
console.log(arr instanceof Array);
console.log(obj instanceof Array);
console.log(Array.isArray(arr));
console.log(Array.isArray(obj));
添加删除数组元素的方法
方法名 | 说明 | 返回值 |
---|
push(element1, …, elementN) | 向数组末尾添加一个或多个元素 | 返回新的长度 | pop() | 删除数组最后一个元素 | 返回被删除元素的值 | unshift(element1, …, elementN) | 将一个或多个元素添加到数组的开头 | 返回新的长度 | shift() | 删除数组的第一个元素 | 返回被删除元素的值 |
数组排序
方法名 | 说明 | 是否修改原数组 |
---|
reverse() | 颠倒数组中元素的顺序,无参数 | 会改变原来的数组,并返回新数组 | sort() | 对数组的元素进行排序 | 会改变原来的数组,并返回新数组 |
示例:
function compare(a, b) {
if (a < b ) {
return -1;
}
if (a > b ) {
return 1;
}
return 0;
}
数组索引方法
方法名 | 说明 | 返回值 |
---|
indexOf(searchElement[, fromIndex]) | 数组中查找给定元素的第一个元素 | 如果存在返回索引号,如果不存在,则返回-1 | lastIndexOf(searchElement[, fromIndex]) | 在数组中的最后一个索引 | 如果存在返回索引号,如果不存在,则返回-1 |
参数:
**searchElement:**要查找的元素
**fromIndex:**可选参数,开始查找的位置。如果该索引值大于或等于数组长度,意味着不会在数组里查找,返回 -1。如果参数中提供的索引值是一个负值,则将其作为数组末尾的一个抵消,即 -1 表示从最后一个元素开始查找,-2 表示从倒数第二个元素开始查找 ,以此类推。 注意:如果参数中提供的索引值是一个负值,并不改变其查找顺序,查找顺序仍然是从前向后查询数组。如果抵消后的索引值仍小于 0,则整个数组都将会被查询。其默认值为 0。
数组转换为字符串
方法名 | 说明 | 返回值 |
---|
toString() | 把数组转换成字符串,逗号分隔每一项 | 字符串 | join(‘分隔符’) | 所有的数组元素被转换成字符串,再用一个分隔符将这些字符串连接起来。 | 字符串 |
数组的其他方法
方法名 | 说明 | 返回值 |
---|
concat() | 并两个或多个数组。此方法不会更改现有数组 | 新数组 | slice() | 数组截取,slice(begin,end) | 新数组 | splice() | 数组删除,splice(开始位置,删除个数) | 新数组,但会影响原数组 |
字符串对象
基本包装类型
为了方便操作基本数据类型,JavaScript 还提供了三个特殊的引用类型:String、Number和 Boolean。
基本包装类型就是把简单数据类型包装成为复杂数据类型,这样基本数据类型就有了属性和方法。
var str = 'andy';
console.log(str.length);
按道理基本数据类型是没有属性和方法的,而对象才有属性和方法,但上面代码却可以执行,这是因为 js 会 把基本数据类型包装为复杂数据类型,其执行过程如下 :
var temp = new String('andy');
str = temp;
temp = null;
字符串的不可变
字符串的不可变指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中新开辟了一个内存空间。
var str = 'abc';
str = 'hello';
var str = '';
for (var i = 0; i < 100000; i++) {
str += i;
}
console.log(str);
根据字符返回位置
方法名 | 说明 |
---|
indexOf(‘要查找的字符串’,开始的位置) | 返回指定内容在元字符串中的位置,如果找不到就返回-1,开始的位置是index索引号 | lastIndexOf() | 从后往前找,只找到第一个匹配的 |
根据位置返回字符
方法名 | 说明 | 示例 |
---|
charAt(index) | 返回指定位置的字符(index字符串的索引号) | str.charAt(0) | charCodeAt(index) | 获取指定位置处字符的ASCII码(index索引号) | str.charCodeAt(0) | srt(index) | 获取指定位置处字符 | str.srt(0) |
字符串操作方法
方法名 | 说明 | 示例 |
---|
charAt(index) | 返回指定位置的字符(index字符串的索引号) | str.charAt(0) | charCodeAt(index) | 获取指定位置处字符的ASCII码(index索引号) | str.charCodeAt(0) | concat(str1,str2…strn) | 连接多个字符串,相当于拼接字符串 | | substr(start[, length]) | 返回一个字符串中从指定位置开始到指定字符数的字符。 | | slice(start,end) | 从开始位置,截取到end位置 | | substring(start,end) | 从开始位置,截取到end位置 | | replace(被替换的字符串, 要替换为的字符串) | 用于在字符串中用一些字符替换另一些字符 | | split() | split()方法用于切分字符串,它可以将字符串切分为数组。 | str.split(‘,’) | toUpperCase() | 转换大写 | | toLowerCase() | 转换小写 | |
简单类型与复杂类型
简单类型又叫做基本数据类型或者值类型,复杂类型又叫做引用类型。
**值类型:**简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型 string ,number,boolean,undefined,null
**引用类型:**复杂数据类型,在存储时变量中存储的仅仅是地址(引用),因此叫做引用数据类型 通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等
堆和栈
堆栈空间分配区别:
**栈(操作系统):**由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈; 简单数据类型存放到栈里面
**堆(操作系统):**存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。 复杂数据类型存放到堆里面
|