笔者是基于视频做出的整理与总结,方便日后查看与复习。
1、JavaScript简介
1.1、JavaScript历史
首先要知道Java
和JavaScript
没有一点关系!
JavaScript 与 Java 是两种完全不同的语言,无论在概念上还是设计上。
Java(由 Sun 发明)是更复杂的编程语言。
ECMA-262 是 JavaScript 标准的官方名称。
JavaScript 由 Brendan Eich 用时10天发明。它于 1995 年出现在 Netscape 中(该浏览器已停止更新),并于 1997 年被 ECMA(一个标准协会)采纳。
网景公司最初命名为LiveScript
,后来在与Sun合作之后将其改名为JavaScript
。
1.2、JavaScript是什么
JavaScript
是一个运行在客户端的脚本语言(Script是脚本的意思)!也是互联网上最流行的脚本语言,这门语言可用于 HTML 和 web,更可广泛用于服务器、PC、笔记本电脑、平板电脑和智能手机等设备。
- JavaScript 是一种轻量级的编程语言。
- JavaScript 是可插入 HTML 页面的编程代码。
- JavaScript 插入 HTML 页面后,可由所有的现代浏览器执行。
- JavaScript 很容易学习。
脚本语言:不需要编译,运行过程中由js解释器(js引擎)逐行来进行解释并执行。
JavaScript发展至今,现在也可以基于Node.js
技术进行服务端编程。
1.3、JavaScript的作用
1、表单动态校验(密码强度检测)(JS产生最初的目的)
2、网页特效
3、服务端开发(Node.js)
4、桌面程序(Electron)
5、APP(Cordova)
6、控制硬件 - 物联网(Ruff)
7、游戏开发(cocos2d-js)
1.4、浏览器执行JS简介
浏览器分成两个部分:分别是渲染引擎
与JS引擎
:
- 渲染引擎:用来解析HTML与CSS,俗称内核。比如chrome浏览器的blink,老版本的webkit等
- JS引擎:也称为JS解释器。用来读取网页中的
JavaScript
代码,对其处理后运行,比如chrome浏览器的V8。
浏览器本身并不会执行JavaScript
代码,而是通过内置的JavaScript引擎(解释器)
来执行JS代码。JS引擎执行代码时逐行解释(转换为机器语言),然后由计算机去执行,所以JavaScript语言归为脚本语言,会逐行解释执行。
2、初识JavaScript
2.1、JavaScript的组成
JavaScript由三个部分组成如图所示:
以下概念先有一个简单的认识,后面会学习具体的使用方式。
2.1.1、ECMAScript
ECMAScript
是由ECMA国际(原欧洲计算机制造商协会)进行标准化的一门编程语言,这种语言在万维网上应用广泛,它往往被称为JavaScript或JScript,但实际上后两者是ECMAScript语言的实现和扩展。
ECMAScript
:ECMAScript规定了JS的编程语法和基础核心知识,是所有浏览器产商共同遵守的一套JS语法工业标准。
2.1.2、DOM - 文档对象模型
文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标记语言的标准编程接口。通过DOM提供的接口可以对页面上的各种元素进行操作(大小、位置、颜色等)。
2.1.3、BOM - 浏览器对象模型
BOM(Browser Object Model,简称BOM)
是指浏览器对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等。
2.2、JS的三种书写位置
JavaScript有3种书写位置:行内、内嵌和外部。例如:
<!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>
<!-- 1、内嵌式的 js -->
<script>
alert("对酒当歌,人生几何?");
</script>
</head>
<body>
<!-- 2、行内式的js,直接写在元素的内部 -->
<div class="box">
<input type="submit" value="昨夜西风凋碧树" onclick="alert('望尽天涯路')">
</div>
<!-- 3、外部js ,注意引入外部js时是双标签-->
<script src="./js/index.js"></script>
</body>
</html>
1、行内式js
<input type="button" value="点我试试" onclick="alert('Hello World')"/>
小结:
- 可以将单行或少量js代码写在HTML标签的事件属性中(以on开头的属性)。如:
onclick
- 注意单引号的使用:在HTML中我们推荐使用双引号,在js中使用单引号。
- 可读性差,在HTML中编写大量js代码时,不方便阅读。
- 引号易错,音高多层嵌套是,非常容易弄混
- 建议在特殊情况下在使用内嵌式的js。
2、内嵌式js
<script>
alert("hello world");
</script>
小结:
- 可以将多行js代码写到
<script>
标签中 - 内嵌js是学习时常用的方式
3、外部js
<script src="./js/index.js"></script>
小结:
- 利于HTML页面代码结构化,把大量js代码独立到HTML页面之外既美观,也方便文件级别的复用。
- 引用外部js文件的
<script>
标签中间不可以写代码 - 适合于js代码量较大的情况
2.3、JavaScript的注释
JavaScript的注释与Java的一样:
- 单行注释:
// ...
- 多行注释 :
/* ... */
如:
<script type="text/javascript">
// 单行注释
/*
多行注释1
多行注释2
*/
</script>
2.4、JavaScript输入输出语句
为了方便信息的输入输出,JavaScript提供了一些输入输出语句,器常用的语句如下:
方法 | 说明 | 归属 |
alert(message) | 浏览器弹出警示框 | 浏览器 |
| 浏览器控制台打印输出信息 | 浏览器 |
prompt(info) | 浏览器弹出输入框,用户可以输入 | 浏览器 |
如:
<!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 type="text/javascript">
// 这是一个输入框
let name = prompt("请输入姓名:");
// alert 弹出警示框 输出的 展示给用户的
alert("您输入了" + name);
// 浏览器控制台输出(给开发人员使用)
console.log("用户输入了" + name);
</script>
</body>
</html>
查看输出:
3、JavaScript变量
3.1、什么是变量?
变量的概念:
- 内存中的存储区域(变量本质:内存中申请的一块用来存放数据的空间)
- 该区域的数据可以不断变化
- 变量是程序中最基本的存储单元。包含变量名和存储的值。
通俗来讲变量
就是用于存放数据的容器。我们通过变量名
获取数据,甚至数据可以修改。如果变量值是基本数据类型,那么他的内存结构是这样的:
3.2、变量的使用
变量的使用分为两步:
- 声明变量
- 赋值
1、声明变量
var age; // 声明一个名称为age的变量
注意:
-
var
是一个js关键字,用来声明变量(variable变量的意思)。使用该关键字声明变量后,计算机会自动为变量分配内存空间,不需要程序员管理。 -
age
是开发人员定义的变量名,我们要通过变量名来访问内存中分配的空间。
2、赋值
age = 10; // 给 age 这个变量赋值为10
注意:
-
=
用来把右边的赋值给左边的变量空间中,此处代表赋值的意思 - 变量值 是开发人员保存到变量空间里的值
<script type="text/javascript">
// 1、声明了一个 age 变量
var age;
// 2、赋值,把值存入这个变量中
age = 18;
// 3、输出结果
console.log("age = " + age);
// 4、变量的初始化
var username = "alex";
</script>
3.3、变量语法的扩展
1、更新变量
一个变量被重新赋值后,它原有的值就会被覆盖,变量值将以最后一次赋的值为准。
<script type="text/javascript">
var word = "JavaScript";
console.log("welcome to the world of " + word);
word = "java";
console.log("welcome to the world of " + word);
</script>
2、同时赋值多个变量
// 同时声明多个变量
var id = 1,username = "alex",age = 18;
3、声明变量特殊情况
情况 | 说明 | 结果 |
var age; console.log(age); | 只声明 不赋值 | undefined |
console.log(age) | 不声明 不赋值 直接使用 | 报错 |
age = 10; console.log(age); | 不声明 只赋值 | 10 |
3.4、变量的命名规范
变量的命名需要有讲究,不能随意命名要见名知意,并遵循以下规则:
- 由字母(A-Za-z)、数字(0-9)、下划线(_)、美元符号($),组成。如userAge,number01,_name等
- 严格区分大小写。
var app;
和var App;
是两个变量。 - 不能以数字开头。
18age
是错误的 - 不能是关键字、保留字。例如:var、for、while。
- 遵守驼峰命名法。首字母小写,后面单词的首字母需要大写。myFirstName
案例:交换两个变量的值。
var num1 = 1;
var num2 = 2;
console.log("交换前")
console.log("num1 = " + num1,", num2 = " + num2); // num1 = 1 , num2 = 2
var temp = num1; // 临时变量
num1 = num2;
num2 = temp;
console.log("交换后")
console.log("num1 = " + num1,", num2 = " + num2); // num1 = 2 , num2 = 1
4、JavaScript基本数据类型
4.1、数据类型简介
1、为什么需要数据类型
在计算机中,不同的数据所需占用的存储空间是不同的,为了便于把数据分成所需内存大小不同的数据,充分利用存储空间,于是定义了不同的数据类型。例如:在Java中byte
类型数据占1个字节、short
占2个字节、int
占4个字节、long
占8个字节。
2、变量的数据类型:
变量是用来存储值的所在处,它们有名字和数据类型。变量的数据类型决定了如何将代表这些值的位存储到计算机的内存中。JavaScript是一种弱类型或者说动态语言。这意味着不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。
// int number = 10; Java写法
// var number; 这里的number是不确定属于那种数据类型的
var number = 10; // number 数据数字型
/*
js的变量数据类型是只有程序在运行过程中,根据等号右边的值来确定
*/
在代码运行时,变量的数据类型是由JS引擎根据=
右边变量值的数据类型来判断的,运行完毕后,变量就确定了数据类型。
JavaScript拥有动态类型,同时也意味着相同的变量可用作不同的类型:
var x = 6; // x 为int
var x = "alex"; // x 为string
3、数据类型的分类
JS把数据类型分为两类:
- 简单数据类型:
Number、String、Boolean、Undefined、Null
- 发杂数据类型:
Object
4.2、简单(基本)数据类
JavaScript中的基本数据类型说明如下:
基本数据类型 | 说明 | 默认值 |
Number | 数字型,包含了整型值和浮点型值,如21、0.2 | 0 |
Boolean | 布尔值类型,如true、false,等价于1和0 | false |
String | 字符串类型,如 |
|
Undefined | var a; 声明了变量 a 但是没有给值,此时 | undefined |
Null | var a = null; 声明了变量 a 为空值 | null |
1、Number型
JavaScript数字类型既可以用来保存整数值,也可以保存小数(浮点数)。
var age = 22; // 整数
var num = 0.25; // 小数
console.log(typeof age); // number
console.log(typeof num); // number
① 数字型进制:
最常见的进制有二进制、八进制、十进制、十六进制:
// 1、八进制 0 ~ 7 我们程序里面数字前面加0 表示八进制
var num1 = 010;
console.log(num1); // 8
var num2 = 012;
console.log(num2); // 10
// 2、十六进制 0 ~ 9 a ~ f #fff。数字前面加 0x 表示十六进制
var num3 = 0x9;
console.log(num3); // 9
var num4 = 0xa;
console.log(num4); // 10
现阶段我们只需记住,在JavaScript中八进制前面加0
,十六进制前面加0x
。
② 数字型范围:JavaScript中数值的最大和最小值。
console.log(Number.MAX_VALUE); // 1.7976931348623157e+308
console.log(Number.MIN_VALUE); // 5e-324
③ 数字型三个特殊值
console.log(Infinity); // Infinity
console.log(-Infinity); // -Infinity
console.log(NaN); // Nan
- Infinity:代表无穷大,大于任何数值
- -Infinity:代表无穷小,小于任何数值
- NaN,Not a number,代表一个非数值
④ isNaN()
这个方法用来判断是否是非数字。
如果是数字返回的是 false,如果不是数字返回的是true。
var username = "alex";
if (isNaN(username)) {
console.log(isNaN(username)); // true
console.log("这个是一个非数字类型");
}
2、字符串型String
字符串型可以是引号中的任意文本,器语法为双引号""
和单引号''
。
// 字符串:"alex" "12" "true"
var message1 = "welcome to the world of JavaScript."; // 双引号
var message2 = 'welcome to the world of JavaScript.'; // 单引号
// var message3 = hello world; 常见错误
因为HTML标签
里面的属性使用的是双引号,JS这里我们更推荐使用单引号。
① 字符串引号嵌套
JS可以用单引号嵌套双引号
,或者用双引号嵌套单引号(外双内单,外单内双)
var message1 = "昨夜西风'凋碧树'";
var message2 = '昨夜西风"凋碧树"';
// 常见错误
// var message3 = 'hello world"; 报错不能单双引号搭配
② 字符串转义符
类似HTML里面的特殊字符,字符串中也有特殊字符,我们称之为转义符。转义符都是\
开头的,常用的转义符及其说明如下:
转义符 | 解释说明 |
| 换行符,n是newline的意思 |
| 斜杆 |
|
|
|
|
| tab缩进 |
| 空格,b是blank的意思 |
如:
// 字符串转义字符,都是用 \ 开头,并且这些转义字符写到引号里面
var message = "人生苦短\nJava是岸!";
console.log(message);
/*
人生苦短
Java是岸!
*/
③ 字符串长度
字符串是由若干个字符组成的,这些字符的数量就是字符串的长度,通过字符串的length属性可以获取整个字符串的长度。
var username = "alex";
console.log("字符串长度:" + username.length); // 字符串长度:4
var num = "123";
console.log(num.length); // 3
var message = "welcome to the world of JavaScript.";
console.log(message.length); // 35
④ 字符串的拼接
- 多个字符串之间可以使用
+
进行拼接,其拼接方式为字符串 + 任何类型 = 拼接之后的新字符串
- 拼接前会把与字符串相加的任何类型转成字符串,再拼接成一个新的字符串。
var word1 = "hello";
var word2 = "world";
var message = word1 + " " + word2 + ".";
console.log(message); // hello world.
console.log(12 + 12); // 24
console.log("12" + 12); // 1212
/*
只要有字符串和其他类型相拼接,最终的结果都是字符串类型。
*/
3、布尔型 Boolean
布尔类型有两个值:true
和 false
,其中 true 表示真(对),而 false表示假(错)。常常在条件判断,循环结构中使用。
var flag1 = true;
// true 参与加法运算当 1 来看
console.log(flag1 + 1); // 2
var flag2 = false;
// false 参与加法运算当 0 来看
console.log(flag2 + 1); // 1
4、Undefined 和 Null
一个声明后没有被赋值的变量会有一个默认值undefined
(如果进行相连或者相加时,注意结果)
// 如果一个变量声明未赋值,就是 undefined 未定义数据类型
var message;
console.log(message); // undefined
var variable = undefined;
console.log(variable + "alex"); // undefinedalex
console.log(variable + 1); // NaN
/*
undefined 和数字相加,最后的结果是 NaN(Not a number)
*/
var space = null;
console.log(space + "alex"); // nullalex
console.log(space + 1); // 1
5、获取变量数据类型
typeof
可用来获取检测变量的数据类型。typeof
使用也有点特殊如:
var num = 10;
console.log(typeof num); // number
var username = "alex";
console.log(typeof username); // string
var flag = true;
console.log(typeof flag); // boolean
var age = undefined;
console.log(typeof age); // undefined
var timer = null;
console.log(typeof timer); // object(对象类型,后面会详细说明)
var info = prompt("请输入信息:"); // 无论输入什么,都接收为 string 类型
console.log(info); // xxx
console.log(typeof info); // string
6、字面量
字面量是在源代码中一个固定值的表示法,通俗来说,就是字面量表示如何表达这个值。
- 数字字面量:8,9,10
- 字符串字面量:
"alex"
,"JavaScript"
- 布尔字面量:
true
,false
4.3、数据类型的转换
使用表单,prompt()
获取过来的数据默认是字符串类型的,此时就不能直接简单的进行加法运算,而需要转换变量的数据类型。通俗来说,就是把一种数据类型的变量转换成另外一种数据类型。
我们通常会实现3种方式的转换:
- 转换为字符串类型
- 转换为数字型
- 转换为布尔型
1、转换为字符串
方式 | 说明 | 案例 |
| 转成字符串 |
|
| 转成字符串 |
|
加号拼接字符串 | 和字符串拼接的结果都是字符串 |
|
如:
var num = 1;
console.log(typeof num); // number
// 1、利用toString()方法把数字型转成字符串型
num = num.toString();
console.log(typeof num); // string
// 2、利用String()把数字型转成字符串型
var age = 20;
console.log(typeof age); // number
age = String(age);
console.log(typeof age); // string
// 3、利用字符串拼接的方法转换
var id = 101;
console.log(typeof id); // number
id = "" + id;
console.log(typeof id); // string
小结:
-
toString()
和String()
使用方式不一样 - 三种转换方式,我们更喜欢使用
+
拼接,这种方式也称隐式转换。
2、转换为数字型(重点)
方式 | 说明 | 案例 |
| 将string类型转成整数数值型 |
|
| 将string类型转成浮点数数值型 |
|
| 将string类型转换为数值型 |
|
js隐式转换 | 利用算数运算隐式转换为数值型 | “12” - 0 |
var age = "18";
console.log(typeof age); // string
// 1、parseInt(变量); 可以把字符型转换为数字型。注意:必须是可以转换为数字型的字符串
age = parseInt(age);
console.log(typeof age); // number
var date = "a22";
date = parseInt(date);
console.log(date); // NaN
// 2、取整
var num1 = "2.1";
var num2 = "2.7";
console.log(parseInt(num1)); // 2
console.log(parseInt(num2)); // 2
// 3、会去掉 px 单位
console.log(parseInt("120px")); // 120
// 4、parseFloat(变量) 可以把字符型的转换为数字型,得到的是小数或浮点数
var price = "9.9";
console.log(parseFloat(price)); // 9.9
var marginLeft = "120px";
console.log(parseFloat(marginLeft)); // 120
// 5、使用 NUmber() 强制转换为数字型
var sum= "20";
console.log(typeof sum); // string
sum = Number(sum);
console.log(typeof sum); // number
// 6、利用算数运算(- * /)进行转换,我们称之为隐式转换
var size = "20";
// 先自动转成数字型再做运算
console.log(size - 0); // 20
console.log(typeof (size - 0));
案例1:计算年龄,我们输入出生年份后,能够计算出我们的年龄。
var year = prompt("请输入您的出生日期(如:2020):");
var date = new Date();
var locationTime = date.getFullYear();
// console.log(date.getFullYear());
alert("您的的年龄是:" + (locationTime - parseInt(year)));
3、转换为布尔型
方式 | 说明 | 案例 |
| 其他类型转成布尔值 |
|
- 代表空、否定的值会被转换为false,如:
""、0、NaN、null、undefined
- 其余值都会被转换为true
console.log(Boolean("")); // false
console.log(Boolean(0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean("alex")); // true
console.log(Boolean(20)); // true
4.4、标识符、关键字、保留子
1、标识符
标识(zhi)符
:就是开发人员为变量。属性、函数、参数去的名字。
记住:标识符不能是关键字或保留子。
2、关键字
关键字:是指JS本身已经使用了的字,不能再用它们充当变量名和方法名等。包括:break、case、catch、continue、default、delete、do、else、finally、for、function、if、in.instanceof、new、return、switch、this、throw、try、typeof、var、void、while、with
等。
3、保留字
保留字:实际上就是预留的"关键字"
,意思是现在虽然还不是关键字,但是未来可能会成为关键字,同样不能使用它们当变量名或方法名。
包括:boolean、byte、char、class、const、debugger、double、enum、export、extends、fimal、 float、goto、implements、import、int、interface、long、mative、package、private、protected、public、short、static、super、synchronized、throws、transient、volatile
等。
5、JavaScript运算符
运算符(operator)也称为操作符,是用于实现赋值,比较和执行算数运算等功能的符号。
JavaScript中常见的运算符有:
- 算数运算符
- 递增和递减运算符
- 比较运算符
- 逻辑运算符
- 赋值运算符
5.1、算术运算符
算数运算符就是算术使用的符号,用于执行两个变量或值的算术运算。常用的算术运算符有:
运算符 | 描述 | 实例 |
| 加 | 10 + 20 = 30 |
| 减 | 20 - 10 = 10 |
| 乘 | 10 * 20 = 200 |
| 除 | 20 / 10 = 2 |
| 取余(取模) | 返回除法的余数 |
如:
console.log(1 + 1); // 2
console.log(1 - 1); // 0
// 1、取模
var m = 10,n = 3;
console.log(m % n) // 1
// 补充:结果的符号与被模数符号相同(如这里 m 是 -10 的话,结果就是 -1)
// 2、我们不能直接拿着浮点数来进行相比较是否相等
var num = 0.1 + 0.2;
console.log(num); // 0.30000000000000004 浮点数相加会有问题(具体原因可以自行查询)
console.log(num == 0.3); // false
表达式与返回值:
表达式:是由数字、运算符、变量等以能求得数值的有意义排列方法所得的组合。简单理解就是由数字、运算符、变量等组成的式子。
表达式最终都会有一个结果,返回给我们,我们成为返回值。
// 由数字、运算符、变量等组成的式子
var sum = 1 + 1;
console.log(sum); // 2
5.2、递增和递减运算符
// 想要一个变量自增 1 我们有很多书写方式
var num = 1;
num = num + 1;
num += 1;
num ++;
++ num;
console.log(num); // 5
如果需要反复给数字变量添加或减去1,为了简便与代码简洁可以使用递增( ++ )
和递减( -- )
运算符来完成。
在JavaScript中,递增( ++ )和递减( – )既可以放在变量前面,也可以放在变量后面。放在变量前面时,我们可以称为前置递增(递减)运算符,放在变量后面时,我们可以称为后置递增(递减)运算符。
注意:递增和递减运算符必须和变量配合使用。
// 1、前置递增(递减)运算符 ++或-- 写在变量的前面
var flag = 1;
++ flag;
-- flag;
console.log(flag); // 1
console.log(++flag + 1); // 3
// 2、后置递增(递减)运算符 ++或-- 写在变量的后面
var sum = 1;
sum ++;
sum --;
console.log(sum); // 1
console.log(sum++ + 1); // 2
console.log(sum); // 2
// 前置与后置似乎都能达到一样的效果,那么它们有什么区别,不知道你们有没有看出来呢?
// 3、前置递增(递减)与后置递增(递减)的区别
var num1 = 1;
if (++num1 == 2) {
console.log("前置递增(递减)是先自增或自减1,在做表达式运算。");
console.log(num1) // 2
}
var num2 = 2;
if (num2-- == 2) {
console.log("后置递增(递减)先做表达式运算,再进行自增或自减1。");
console.log(num2); // 1
}
/*
小结:
1.后置自增(自减):先返回原值,后自加1或自减1。
2.前置自增(自减):先自加1或自减1,在把新值返回。
3.前置递增和后置递增运算符可以简化代码的编写,让变量的值+1,比以前写法更简单。
4.开发时,大多使用后置递增/减,并且代码独占一行,例如:num++;或者num--;
*/
5.3、比较运算符
比较运算符(关系运算符):是两个数据进行比较时所使用的运算符,比较运算后,会返回一个布尔值(true/false)作为比较运算的结果。
运算符 | 说明 | 案例 | 结果 |
| 小于号 | 1 < 2 | true |
| 大于号 | 1 > 2 | false |
| 小于等于号(小于或者等于) | 1 <= 2 | true |
| 大于等于号(大于或者等于) | 1 >= 2 | false |
| 判等号(会转型) | 1 == 1 | true |
| 不等号 | 1 != 1 | false |
| 全等要求值和数据类型都一致 |
| false |
如:
console.log(1 >= 2); // false
console.log(1 <= 2); // true
// 我们程序里面的等于符号是 ==
console.log(1 == 1); // true
console.log("alex" == "alex"); // true
// 默认转换数据类型,会把字符串型的数据转换为数字型,只要求值相等即可
console.log("18" == 18); // true
console.log("18" != 18); // false
// 全等判断:要求两侧的值还有数据类型完全一致
console.log(18 === "18"); // false
5.4、逻辑运算符
逻辑运算符是用来进行布尔值运算的 运算符,其返回值也是布尔值。后面开发中经常用于多个条件的判断。
逻辑运算符 | 说明 | 案例 |
| 逻辑与,简称 | true && false |
| 逻辑或,简称 | true || false |
| 逻辑非,简称 | ! true |
如:
// console.log(3 > 5 & 1 > 2);
// 1、逻辑与(&& and)两侧都为 true,结果才是 true,只要有一侧为 false,结果就为 false。
console.log(3 > 5 && 1 > 2); // false
// 2、逻辑或(|| or)两侧都为 false,结果才是 false,只要有一侧为 true,结果就是 true。
console.log(3 > 5 || 2 > 1); // true
// 3、逻辑非(! not)
console.log(!(1 > 2)); // true
短路运算(逻辑中断):
短路运算的原理:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值。
var num = 1;
console.log(true || num++); // true
console.log(num); // 1
1、逻辑与
- 语法:
表达式1 && 表达式2
- 如果第一个表达式的值为真,则返回表达式2
- 如果第一个表达式的值为假,则返回表达式1
// 1、第一个表达式为 true,则返回表达式2
var res1 = 123 && 12;
console.log(res1); // 12
// 2、第一个表达式为 false,则返回表达式1
var res2 = (1 < 0) && 12; // false
console.log(res2);
// 如果有空的或者否定的为假,其余是真的。0 "" null undefined NaN
2、逻辑或
- 语法:
表达式1 || 表达式2
- 如果表达式1结果为真,则返回表达式1
- 如果表达式1结果为假,则返回表达式2
console.log(123 || 21); // 123
console.log(0 || 1); // 1
5.5、赋值运算符
用来把数据赋值给变量的运算符。
赋值运算符 | 说明 | 案例 |
| 直接赋值 |
|
| 加、减一个数后在赋值 |
|
| 乘、除、取模后在赋值 |
|
如:
var num = 18;
num += 2; // num = num + 2;
console.log(20); // 20
5.6、运算符优先级
优先级 | 运算符 | 顺序 |
1 | 小括号 | () |
2 | 一元运算符 | ++ – ! |
3 | 算数运算符 | 先 * / % 后 + - |
4 | 关系运算符 |
|
5 | 相等运算符 |
|
6 | 逻辑运算符 | 先 && 后 || |
7 | 赋值运算符 | = |
8 | 逗号运算符 | , |
- 一元运算符里面逻辑非优先级很高
- 逻辑与比逻辑或优先级高
console.log(4 >= 6 || "18" != "alex" && !(12 * 2 == 144) && true); // true
var num = 10;
console.log(5 == num / 2 && (2 + 2 * num).toString() === "22"); // true
6、JavaScript流程控制
流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块。简单理解:流程控制就是来控制我们的代码按照什么顺序来执行。
其流程控制方式采用结构化程序设计中规定的三种基本流程结构,即:
- 顺序结构
- 分支结构
- 循环结构
6.1、顺序结构
程序从上到下逐行的执行,中间没有任何判断和跳转。顺序结构是程序中最简单、最基本的流程控制,它没有特定的语法结构,程序会按照代码的先后顺序,依次执行。程序中大多数的代码都是这样执行的。
6.2、分支结构
1、分支结构
由上到下执行代码的过程中,根据不同的条件,执行不同的路径代码(执行代码多选一的过程),从而得到不同的结果。
JavaScript语言提供了两种分支结构语句:
- if - else语句
- switch语句
2、if -else 语句
首先 if 语句有三种结构(语法),分别是:
// 1、语法结构1(单分支结构)
if (条件表达式) {
// 执行语句
}
// 条件成立执行代码,否则什么也不做。
//案例1:进入网吧(18岁的判断)
var age = prompt("请输入您的年龄:");
if (parseInt(age) >= 18) {
alert("您可以进入网吧哦");
}
// 2、语法结构2(双分支结构)
if (条件表达式) {
// 执行语句1
} else {
// 执行语句2
}
// 案例2:案例1的改进
var age = prompt("请输入您的年龄:");
if (parseInt(age) >= 18) {
alert("您可以进入网吧哦");
} else {
alert("您未满18岁,不可以进入网吧。");
}
// 案例3:判断闰年。闰年就是能被4整除且不能整除100的为闰年(如2004年就是闰年,19901年不是闰年)或者能够被400整除的就是闰年。
var year = prompt("请输入测试的年份:");
if (parseInt(year) % 4 == 0 && parseInt(year) % 100 != 0 || year % 400 == 0) {
alert(year + "是闰年哦");
} else {
alert(year + "是平年哦");
}
// 3、语法结构3(多分支结构)
if (条件表达式1) {
// 执行语句1
} else if (条件表达式2) {
// 执行语句2
} else {
// 执行语句3
}
// 案例4:判断成绩级别
var score = prompt("请输入您的C语言考试成绩:");
if (score >= 90) {
alert("您的考试等级是A");
} else if (score >= 80) {
alert("您的考试等级是B");
} else if(score >= 60) {
alert("您的考试等级是C");
}else {
alert("您的考试等级是D");
}
语句可以理解为一个行为,循环语句和分支语句就是典型的语句。一个程序由很多个语句组成,一般情况下,会分割一个一个的语句。
3、三元表达式
三元表达式能做一些简单的条件选择。有三元运算符组成的式子称为三元表达式。
语法结构:条件表达式 ? 表达式1 : 表达式2
- 如果条件表达式结果为真则返回表达式1的值。
- 如果条件表达式结果为假则返回表达式2的值。
如:
var userType = 1;
var userGrade = userType == 3 ? "VIP用户" : "普通用户";
console.log(userGrade); // 普通用户
if (userType == 2) {
userGrade = "VIP用户";
} else {
userGrade = "普通用户";
}
案例:数字补0。用户输入数字,如果数字小于10,则在前面补0,比如01、09,如果数字大于10,则不需要补,比如20。
var num = prompt("请输入一个数字:");
alert("您输入的数字是[" + (num < 10 ? "0" + num : num) + "]");
4、switch语句
switch语句也是多分支语句,它用于基于不同的条件来执行不同的代码。当要针对变量设置一系列的特定值的选项时,就可以使用switch。switch(转换、开关的意思)
语法结构:
switch (表达式) {
case value1:
// 执行语句1;
break;
case value2:
// 执行语句2;
break;
// ...
default:
// 执行最后的语句
}
/*
执行思路,利用我们的表达式的值和 case 后面的选项值相匹配,如果匹配上,就执行该 case 里面的语句。
如果都没有匹配上,那么执行 default里面的语句。
*/
案例1:体会switch语句的使用。
var grade = 3;
switch (grade) {
case 1:
alert("您的段位是青铜");
break;
case 2:
alert("您的段位是黄金");
break;
case 3:
alert("您的段位是钻石");
break;
default:
alert("您的段位是王者");
}
注意:
- 我们开发里面,表达式我们经常写成变量。
- 我们 grade 的值和 case 里面的值相匹配的时候是全等,必须是值和数据类型一致才可以。
- case的穿透现象:break 如果当前的 case 里面没有 break,则不会退出switch 是继续执行下一个 case,直到遇见 break。
案例2:用户弹出框里面输入一个水果,如果有就弹出该水果的价格,如果没有就弹出“没有此水果”。
var fruitName = prompt("请输入水果名称:");
switch (fruitName) {
case "苹果":
alert("[" + fruitName + "]的价格是10/斤");
break;
case "橘子":
alert("[" + fruitName + "]的价格是15/斤");
break;
case "香蕉":
alert("[" + fruitName + "]的价格是5/斤");
break;
default:
alert("没有此水果");
}
小结:switch 语句和 if else if 语句的区别。
- 一般情况下,它们两个语句可以相互替换
- switch case语句通常处理 case为比较确定值的情况,而if else 语句更加灵活,常用于范围判断(大于、等于等某个范围)
- switch 语句进行条件判断后直接执行到程序的条件语句,效率更高。而 if else语句有几种条件,就得判断多少次。
- 当分支比较少时,if else语句的执行效率比switch语句高
- 当分支比较多时,switch语句的执行效率比较高,而且结构更清晰
6.3、循环结构
1、循环
循环的主要目的:重复的执行某段代码。
在JavaScript中,主要有三种类型的循环语句:
-
for
循环 -
while
循环 -
do while
循环
2、for 循环
在程序中,一组被重复执行的语句被称之为循环体
,能否继续重复执行,取决于循环的终止条件
。由循环体级循环的终止条件组成的语句,被称之为循环语句
。
for 循环语法结构:
// 1. for 重复执行某些代码,通常跟技术有关系
/*
2. 循环结构的四个要素:
1-初始化条件
2-循环条件 --> 是boolean类型
3-循环体
4-迭代循环
*/
// 3. 语法结构如下
for (初始化变量; 条件表达式; 操作表达式) {
// 循环体
}
// 初始化变量:就是用 var 声明的一个普通变量,通常用于作为计数器使用
// 条件表达式:就是用来决定 每一次循环是否继续执行,就是终止的条件
// 操作表达式:是每次循环最后执行的代码,经常用于我们计数器变量
// 如:打印100次
for (var i = 0; i < 100; i++) {
console.log("我喜欢JavaScript")
}
// i -> index
案例1:输出100以内的偶数。
// for 循环重复执行不同的代码,因为我们有计数器变量 i 的存在,i 每次循环值都会变
for (var i = 0; i < 100; i++) {
if (i % 2 == 0) {
console.log(i); // 偶数
}
}
案例2:求 1~ 100 之间的整数累加和
var sum = 0;
for (var i = 1; i < 101; i++) {
sum += i;
}
console.log("1 + 2 + 3 + 4 + ... + 100 = " + sum); // 5050
案例3:打印倒直角三角形(双重 for 循环),如图所示。
代码实现:
var str = "";
for (var i = 10; i >= 1; i--) {
for (var n = 1; n <= i; n++){
str += "*";
}
str += "\n";
}
console.log(str);
案例4:打印九九乘法表,如图所示。
代码实现:
var str = "";
for (var i = 1; i <= 9; i++){
for (var n = 1;n <= i; n++){
str += n + " * " + i + " = " + (i * n) + " ";
// console.log(n + " * " + i + " = " + (i*n));
}
str += "\n"
// console.log("\n")
}
console.log(str);
for 循环小结:
- for循环可以重复执行某些相同代码
- for循环可以重复执行某些不同的代码,因为我们有计数器
- for循环可以重复执行某些操作,比如算术运算符加法操作
- 随着需求增加,双重for循环可以做更多,更好看的效果
- 双重for循环,外层循环一次,内层for循环全部执行
- for循环是循环条件和数字直接相关的循环
- 分析要比写代码更重要
3、while 循环
while 语句可以在条件表达式为真的前提下,循环执行指定的一段代码,直到表达式不为真时结束循环。
while 语句的语法结构如下:
while (条件表达式) {
// 循环体代码
}
// 执行思路:只要条件表达式一直为 true,循环体代码就会一直被执行
/*
1、循环结构的四个要素:
1-初始化条件
2-循环条件 --> 是boolean类型 关注点
3-循环体
4-迭代循环
说明:通常情况,循环的结束都是因为‘循环条件’中条件返回false
2、while循环结构:
1.初始化条件
while(2.循环条件){
3.循环体
4.迭代循环
}
3、说明:
①写程序要避免出现死循环(迭代条件丢失)
②for循环与while循环是可以相互转换的
区别:初始化条件作用域范围不一样
*/
如:10以内的偶数,我们可以这样写。
var num = 1;
while (num <= 10) {
if (num % 2 == 0) {
console.log("偶数:" + num);
}
num++;
}
案例:你爱我吗?
var flag = true;
while (flag) {
var isLoveMe = prompt("你爱我吗?");
if(isLoveMe == "爱") {
flag = false
}
}
4、do while 循环
do while 语句其实是 while 语句的一个变体。该循环会先执行一次代码块,然后对条件表达式进行判断,如果条件为真,就会重复执行循环体,否则退出循环。
/*
1、循环结构的四个要素:
1.初始化条件
2.循环条件 --> 是boolean类型 关注点
3.循环体
4.迭代循环
说明:通常情况,循环的结束都是因为‘循环条件’中条件返回false
2、do-while循环结构:
①初始化条件
do {
③循环体;
④迭代循环;
} while(②循环条件);
3、执行过程
① -> ③ -> ④ -> ② -> ③ -> ④ ... ②
4、说明:
1.do-while循环至少会执行一次循环体
2.开发中使用 for while 使用较多,而do-while比较少
*/
案例:
// 遍历100以内的偶数,并计算所有偶数的和及偶数的个数
var i = 1;
var sum = 0;
var count = 0;
do{
if(i % 2 == 0){
// console.log(i+","); 输出所有的偶数
sum += i;
count++;
};
i++;
}while(i <= 100);
console.log("所有偶数的和 = " + sum);
console.log("所有偶数的个数 = " + count);
5、循环小结
- JavaScript中循环有for、while、do while
- 三个循环很多情况下都可以互相代替与使用
- 如果是用来计次数,跟数字相关的,三者使用基本相同,但是我们更喜欢用for
- while 和 do while 可以做更复杂的判断条件,比 for 循环灵活一些
- while 和 do while 执行顺序不一样,while 先判断后执行,do while 先执行一次,再判断执行。
- while 和 do while 执行次数不一样,do while至少会执行一次循环体,而 while 可能一次也不执行。
6、continue 与 break 关键字的使用
continue 关键字:用于立即跳出本次循环,继续下一次循环
(本次循环中 continue 之后的代码就会执行一次)。
如:
// 输出:1 3 4 5 6 7 8 9 10
var str = "";
for(var i = 1;i <= 10; i++){
if(i == 2){
continue; // 退出本次循环,直接跳到 i++
}
str += i + " ";
}
console.log(str);
break 关键字:循环结构中结束当前循环
或在 switch-case语句中跳出结构体。
如:
while(true) {
var sum = prompt("1 + 1 = ");
if (sum == 2) {
alert("恭喜你回答正确!");
break; // 结束循环
} else {
alert("回答错误,请重试!");
}
}
7、JavaScript 数组
7.1、数组的概念
问:之前学习的变量,只能存储一个值。如果我们想存储班级中所有学生的姓名,那么该如何存储呢??
可以使用数组(Array)。数组可以把一组相关的数据一起存放,并提供方便的访问(获取)方式。
数组(Array):就是一组数据的集合,存储在单个变量下的优雅方式。注意在JavaScript
中不同类型的数据类型也可以存储在数组中。然而在Java和C语言等中,数组中元素只能是同一种类型的。
数组中又包含以下概念:
- 数组名
- 下标(或索引)
- 元素
- 数组的长度:元素的个数
数组的分类:
- 按照维度:一维数组,二维数组,三维数组
- 按照元素的数据类型分:基本数据类型元素的数组,复杂数据类型元素的数组
数组的特点:
- 数组是有序排列的
- 数组属于引用类型的变量。数组的元素,既可以是基本数据类型,也可以是复杂数据类型
- 创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址
- 数组的长度一旦确定,就不能修改
- 我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快
7.2、数组的基本使用
1、数组的创建方式
JavaScript中创建数组有两种方式:
- 利用 new 关键字创建数组
- 利用数组字面量([])创建数组
如:
// 1、利用 new 关键字创建数组
var array = new Array(); // 创建了一个空的数组
array.push("1");
array.push(2);
array.push(true);
console.log(array);
// 2、使用数组字面量方式创建空的数组
var 数组名 = [];
// 3、使用数组字面量方式创建带初始值的数组
var 数组名 = [1, 2, 3, 4, 5];
小结:
- 数组的字面量是方括号[]
- 声明数组并赋值称为数组的初始化
- 这种字面量方式也是我们以后使用最多的方式
- 数组中可以存放
任意类型
的数据,例如字符串,数字,布尔值等。
2、数组的索引
索引(下标):用来访问数组元素的序号(数组下标从 0 开始)
数组可以通过索引
来访问、设置、修改对应的数组元素,我们可以通过数组名[索引值]
的形式来获取数组中的元素。
这里的访问
就是获取得到的意思,如:
// 数组的角标(或索引)从0开始的
var array = ["Java","Python","C/C++","JavaScript"]; // 初始化数组
console.log(array); // ["Java", "Python", "C/C++", "JavaScript"]
array[4] = "PHP"; // 通过角标(索引)设置指定位置的元素
console.log(array); // ["Java", "Python", "C/C++", "JavaScript", "PHP"]
// 通过角标(索引)调用数组里元素
console.log(array[3]); // JavaScript
// 通过角标(索引)修改数组里元素
array[0] = "MySQL";
console.log(array); // ["MySQL", "Python", "C/C++", "JavaScript", "PHP"]
3、数组的长度与扩容
如何获取数组的长度?通过数组的属性:length
var array = ["Java","Python","C/C++","JavaScript"]; // 初始化数组
console.log(array.length); // 4
数组中新增元素:可以通过修改length
长度以及索引增加数组元素。另外为实现扩容也可以修改length
长度,数组length
属性是可以读写的。
var array = new Array(4,2,1,78,21,20);
console.log(array.length); // 6
array.length = 5;
console.log(array.length); // 5
// 当数组长度减小时,默认是去除最后一个元素
console.log(array); // [4, 2, 1, 78, 21]
4、遍历数组
问:数组中的每一项我们怎么取出来?
答:可以通过数组名[索引号]
的方式一项项的取出来
var array = ["a", "b", "c"];
console.log(array[0]); // a
console.log(array[1]); // b
console.log(array[2]); // c
在问:怎么把数组里面的元素全部取出来?
从代码中我们可以发现,从数组中取出每一个元素时,代码时重复的,有所不一样的是索引值在递增
,因此我们可以通过循环语句遍历数组,如:
var array = ["Java","Python","C/C++","JavaScript"]; // 初始化数组
// 1、通过 for循环遍历数组
for (var i = 0; i < array.length; i++) {
console.log(array[i]);
}
// 2、通过 while 循环遍历数组
var n = 0;
while (n < array.length) {
console.log(array[n]);
n++;
}
// 3、数组对象的 forEach 方法遍历数组
array.forEach((item,index) => {
console.log("元素:" + item);
console.log("索引:" + index);
})
5、数组元素的默认初始化值
var array = new Array(5);
console.log(array.length); // 5
for (var i = 0;i < array.length; i++) {
console.log(array[i]); // undefined * 5
}
6、数组经典案例
求数组中最大的值:
var array = new Array(4,2,1,78,21,20);
console.log(array); // [4, 2, 1, 78, 21, 20]
var max = array[0];
for (var i = 0;i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
console.log("最大值 = " + max); // 最大值 = 78
翻转数组:
var array = [1,2,3,4,5,6,7,8,9,10];
// 1、第一种方法
/*var newArray = [];
for (var i = array.length - 1; i >= 0; i--) {
newArray[newArray.length] = array[i];
}*/
console.log(array.length); // 10
console.log(array.length / 2 - 1); // 4
// 2、第二种方法
for (var i = array.length - 1;i > array.length / 2 - 1;i--) {
// newArray[newArray.length] = array[i];
var temp = array[array.length - i - 1];
array[array.length - i - 1] = array[i];
array[i] = temp;
}
console.log(array);
// 3、第三种方法
for(var i = 0;i < array.length / 2; i++) {
var temp = array[i];
array[i] = array[array.length - i - 1];
array[array.length - i - 1] = temp;
}
冒泡排序:
var array = [1,20,15,46,11,2,5,7,9,500,123];
console.log(array); // 排序前
for(var i = 0; i < array.length - 1; i++) {
for (var n = 0; n < array.length - i - 1; n++) {
if (array[n] > array[n + 1]) {
var temp = array[n];
array[n] = array[n + 1];
array[n + 1] = temp;
}
}
}
console.log(array); // 排序后
关于数组的学习远没有结束,上面介绍的只是一维数组的使用,还有二维数组等并没有介绍。在实际工作中,我们使用二维数组的情况也相对较少,所以关于更多二维数组的使用,可自行学习。
8、JavaScript函数
8.1、函数的概念
首先需要明白的一点是,类里面的函数称为方法,类之外的函数才叫函数。
在JavaScript里面,可能会定义非常多的相同代码或者功能相似的代码,这些代码可能需要大量重复使用,虽然for循环
语句也能实现一些简单的重复的操作,但是比较具有局限性,此时我们就可以使用JavaScript的函数
。
函数
:就是封装了一段可被重复调用执行的代码块
,通过此代码块可以实现大量代码的重复使用。目的就是让代码重复使用。
JavaScript函数语法:
// 1、无参
function functionName() {
// 函数体
}
// 2、有参
function functionName(p1, p2...) {
// 函数体
}
当调用该函数时,会执行函数内的代码。
可以在某事件发生时直接调用函数(比如当用户点击按钮时),并且可由 JavaScript 在任何位置进行调用。
注意: JavaScript 对大小写敏感。关键词 function 必须是小写的,并且必须以与函数名称相同的大小写来调用函数。
8.2、函数的基本使用
1、基本使用
函数的使用分为两步:声明函数
和调用函数
。
// 1、声明函数
function sayHello(username) {
alert("[ " + username + " ],你好呀!")
}
// 2、调用函数
sayHello("alex");
/*
1、function 声明函数的关键字,全部小写。
2、函数时做某件事情,函数名一般是动词 sayHello
3、函数不调用自己不执行
*/
配合前端代码:
<!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>
<div>
<!--调用sayHello()函数-->
<button onclick="sayHello('alex')">你好</button>
</div>
<script type="text/javascript">
// 1、声明函数
function sayHello(username) {
alert("[ " + username + " ],你好呀!")
}
// 2、调用函数
// sayHello("alex");
</script>
</body>
</html>
函数封装的理解:
- 函数的封装是把一个或者多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口(隐藏内部实现细节)。
- 简单理解:封装类似于将电脑配件整合组装到机箱中(类似快递打包)。
案例:利用函数计算1-100之间的累加和。
function getSum(num1,num2) {
var sum = 0;
for (var i = num1; i <= num2; i++) {
sum += i;
}
return sum;
}
// 计算 1 - 100 之间的累加和
var sum = getSum(1,100);
console.log(sum);
2、形参与实参数
在声明函数时
,可以在函数名称后面的小括号中添加一些参数,这些参数被称为形参
,而在调用该函数时
,同样也需要传递相应的参数,这些参数被称为实参
。
// 1、在声明函数的小括号里面是形参
function functionName(形参1, 形参2, ...) {
// 函数体
}
// 2、在函数调用的小括号里面是实参
functionName(实参1, 实参2, ...);
function hello(username) {
// 形参是接收实参的。 username = "alex" 形参类似与一个变量
console.log("hello " + username);
}
hello("alex");
// 函数的参数可以有,也可以参数个数不限
参数的作用:在函数内部
某些值不固定,我们可以通过参数在调用函数时传递
不同的值进去。
函数的形参与实参匹配问题:
function getSum (a, b) {
return a + b;
}
// 1、如果实参的个数和形参的个数一致,则正常输出结果
var sum1 = getSum(1, 2);
console.log(sum1); // 3
// 2、如果实参的个数多余形参的个数,会取到形参的个数,多余的实参不会参与运算
var sum2 = getSum(1, 2, 3);
console.log(sum2); // 3
// 3、如果实参的个数小于形参的个数
// 形参可以看做是不用声明的变量,b 是一个变量但是没有接收值,结果就是undefined
var sum3 = getSum(1);
// 1 + undefined = NaN
console.log(sum3); // NaN
函数参数小结:
- 函数可以带参也可以不带参数
- 声明函数的时候,函数名括号里面的是形参,形参的默认值为undefined
- 调用函数的时候,函数名括号里面的是实参
- 多个参数中间使用英文逗号分隔
- 形参的个数可以和实参个数不匹配,但是结果不可预计,我们尽量要匹配
3、函数的返回值
return
语句:有的时候,我们会希望函数将值返回个调用者,此时通过使用return语句就可以实现。
函数返回值格式:
function functionName() {
return 需要返回的结果;
}
/*
需要注意的是,我们函数只是实现某种功能,最终的结果需要返回给函数的调用者。只要函数遇到return就会把后面的
结果返回给函数的调用者并结束函数的执行(终止函数)。在js中一个函数可以有返回值,也可以没有返回值。完全根据业务而定。
*/
// 如
function getSum(a, b) {
return a + b;
}
var sum = getSum(1, 2);
console.log(sum); // 3
案例1:利用函数求任意两个数的最大值
function getMax(a, b) {
return a > b ? a : b;
}
var max = getMax(1,9);
console.log(max); // 9
案例2:利用函数求任意数组中的最大值
function getArrayMaxValue(array) {
var max = array[0];
for (var i = 0; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
return max;
}
console.log(getArrayMaxValue([1,20,3,45,8,2,26])); // 45
注意:函数都是由返回值的
- 如果return则返回return后面的值
- 如果没有return则返回undefined
break、continue、return的区别:
-
break
:结束当前的循环体(如for、while) -
continue
:跳出本次循环,继续执行下次循环(如for、while) -
return
:不仅可以退出循环,还能够返回return语句中的值,同时还可以结束当前的函数体内的代码
8.3、arguments的使用
当我们不确定有多少个参数传递的时候,可以用arguments
来获取。在JavaScript中,arguments实际上它是当前函数的一个内置对象
。所有函数都内置了一个arguments对象,arguments对象中存储了传递的所有实参
。
arguments展示形式是一个伪数组
,因此可以进行遍历。伪数组具有以下特点:
- 具有length属性
- 按索引方式存储数据
- 不具有数组的
pushu()、pop()
等方法
如:
function hello() {
// arguments 是一个伪数组
console.log(arguments); // Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
console.log(arguments.length); // 3
console.log(arguments[0]); // 1
// 我们还可以按照数组的方式遍历 arguments
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
hello(1, 2, 3);
案例:利用函数求任意个数的最大值
function getMaxValue() {
var max = arguments[0];
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
console.log(getMaxValue(1,20,3,15)); // 20
8.4、函数的嵌套
因为每个函数都是独立的代码块,用于完成特殊任务,因此经常会用到函数互相调用的情况。
如:
function f1() {
console.log("hello");
f2();
}
f1();
function f2() {
console.log("world");
}
8.5、函数的两种声明方式
// 函数的2种声明方式
// 1、利用函数关键字自定义函数(命名函数)
function functionName() {
// 函数体
}
// 2、函数表达式(匿名函数)
var 变量名 = function() {
// 函数体
}
/*
1. 函数表达式中声明的是变量,不是函数民
2. 函数表达式声明方式跟声明变量差不多,只不过变量里面存的是值,而函数表达式里面存的是函数
3. 函数表达式也可以进行参数的传递
*/
9、JavaScript作用域
9.1、作用域
1、作用域概述
通常来说,一段程序代码中所用到的名字并不总是有效的,而限定这个名字的可用性的代码范围
就是这个名字的作用域
。作用域的使用提高了程序逻辑的局限性,增强了程序的可靠性,减少了名字冲突。
JavaScript的作用域(es6)之前有,全局作用域和局部作用域:
- 全局作用域:整个
script
标签或者是一个单独的js文件。 - 局部作用域:在函数内部就是局部作用域,这个变量或名字只在函数内部起效果和作用
如:
// JavaScript作用域:就是代码名字(变量)在某个范围内起作用和效果,目的是为了提高程序的可靠性。减少命名冲突。
var username = "alex"; // 全局作用域
function functionName() {
// age只在函数内部有效
var age = "18"; // 局部作用域
}
console.log(age); // 报错
2、变量的作用域
在JavaScript中,根据作用域的不同,变量可以分为两种:全局变量与局部变量
① 在全局作用域下声明的变量叫做全局变量
(在函数外部定义的变量)
- 全局变量在代码的任何位置都可以使用
- 在全局作用域下 var声明的变量是全局变量
- 特殊情况下,在函数内不使用 var 声明的变量也是全局变量(不建议使用)
② 在局部作用域下声明的变量叫做局部变量
(在函数内部定义的变量)
- 局部变量只能在该函数
内部
使用 - 在函数内部 var 声明的变量是局部变量
- 函数的形参实际上就是局部变量
如:
var username = "alex"; // username就是一个全局变量,全局作用域下的变量,在全局下都可以使用
function functionName() { // 注意:函数的形参也可以看做是局部变量
console.log(username);
// age只在函数内部有效
var age = "18"; // age是一个局部变量
price = 100; // 并没有声明
}
functionName();
// 注意:如果在函数内部,没有声明直接赋值的变量也属于全局变量
console.log(price);
console.log(age); // 报错
/*
1、全局变量只有浏览器关闭的时候才会销毁,比较占内存资源
2、局部变量,当我们程序执行完毕就会销毁,比较节约内存资源
*/
9.2、作用域链与预解析
1、作用域链
// 作用域链:内部函数访问外部函数的变量,采取的是链式查找的方式决定取那个值,这种结构我们称为作用域链
var num = 10;
function f1() {
var num = 20;
f2();
function f2() {
var num = 30;
console.log(num); // 就近原则
f3();
function f3() {
console.log(num); // 就近原则
}
}
}
f1();
2、JavaScript预解析
我们都知道JavaScript在执行时,是从上到下逐步解释执行。并且还可以这样执行(把变量或函数的调用写在声明之前):
console.log(age); // undefined
var age = 18;
var message = f1();
console.log(message); // hello world
function f1() {
return "hello world";
}
亲测在Python中是不可以这样书写的。那么为什么会这样呢?因为预解析。
JavaScript代码由浏览器中的JavaScript解析器
来执行。JavaScript解析器在运行JavaScript代码的时候分为两步:预解析和代码执行。
预解析
:JavaScript引擎会把js里面所有的 var
还有 function
提升到当前作用域的最前面。然后在按照代码书写的顺序从上往下执行。
JavaScript预解析分为变量预解析
(变量提升)和 函数预解析
(函数提升):
- 变量提升:就是把所有的变量声明提升到当前的作用域最前面,不提升赋值操作
- 函数提升:就是把所有的函数声明提升到当前作用域的最前面,不调用函数
// 1、变量提升
console.log(age);
var age = 10;
// 以上代码通过 预解析机制 后相当于与执行了以下代码
var age;
console.log(age);
age = 10;
// 2、函数提升
var message = f1();
console.log(message); // hello world
function f1() {
return "hello world";
}
// 通过预解析机制后,相当于执行了以下代码
function f1() {
return "hello world";
}
var message;
message = f1();
console.log(message); // hello world
10、JavaScript对象
10.1、对象
1、什么是对象
现实生活中:万物皆对象,对象是一个具体的事物
,看得见摸得着的实物。例如,一本书、一辆汽车、一个人都可以是对象
。
在JavaScript中,对象是一组无序的相关属性和方法的集合,所有的事务都是对象。例如字符串、数值、数组、函数等。
对象是由属性
和方法
组成的:
- 属性:事物的
特征
,在对象中用属性
来表示(常用名词) - 方法:事物的
行为
,在对象中用方法
来表示(常用动词)
2、为什么需要对象
保存一个值时,可以使用变量
,保存多个值(一组值)时,可以使用数组
。如果需要保存一个人的完整信息呢?
例如,将关羽
的个人信息保存在数组中的方式为:
var guanyu = ["关羽", "男", "130", "180"];
这样的个人信息表达,完全没有规律,也不好对信息进行识别。所有为了使表达结构更清晰,对于复杂的信息我们使用对象表达的方式去描述与存储。
3、创建对象的方式
在JavaScript中,现阶段我们可以采用三种方式创建对象(object):
- 利用
字面量
创建对象 - 利用
new Object
创建对象 - 利用
构造函数
创建对象
1、利用字面量创建对象
:就是利用花括号{}
表达这个具体事物(对象)的属性和方法。
// 利用读写字面量创建对象 {}
// var obj = {}; // 创建了一个空的对象
var person = {
name: "关羽",
"age": "22",
"sex": "男",
eat: function() {
console.log("吃饭");
},
sleep: function() {
console.log("睡觉");
}
}
/*
1.里面的属性或者方法我们采取键值对的形式 属性名 : 属性值
4. 多个属性或者方法中间用逗号隔开的
5. 方法冒号后面跟的是一个匿名函数
*/
console.log(typeof person); // object
console.log(person); // {name: "关羽", age: "22", sex: "男", eat: ƒ, sleep: ƒ}
// 1、调用对象的属性:对象名.属性民
console.log(person.name); // 关羽
// 2、调用属性的另一种方法:对象名["属性名"]
console.log(person["age"]); // 22
// 3、调用对象的方法:对象名.方法名()
person.eat(); // 吃饭
2、利用new Object创建对象
:和我前面学的new Array()
原理一致。
// 利用 new Object 创建对象
var person = new Object(); // 创建了一个空的对象
person.name = "alex";
person.age = "18";
person.sex = "男";
person.eat = function() {
console.log("eat");
}
person.sleep = function() {
console.log("sleep");
}
/*
1. 我们利用等号 = 赋值的方法添加对象的属性和方法。
2. 每个属性和方法之间用分号结束
*/
console.log(typeof person); // object
console.log(person); // {name: "alex", age: "18", sex: "男", eat: ƒ, sleep: ƒ}
console.log(person.name); // alex
console.log(person["age"]); // 18
person.eat(); // eat
person.sleep(); // sleep
3、利用构造函数创建对象
:为什么要使用构造函数创建对象?因为我们前面两种创建对象的方式只能创建一个对象!我们一次创建一个对象,里面很多的属性和方法大量相同的,因此我们可以利用函数的方法,重复这些相同的代码。我们把这个函数就称为构造函数。构造函数:就是把我们对象里面一些相同的属性和方法抽象出来封装到函数里面。
// 构造函数格式
function functionName() {
this.属性 = 属性值;
this.方法 = function() {
// 方法体
}
}
// 构造对象
var object = new functionName();
如:
// 利用构造函数创建对象
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.eat = function() {
console.log("会吃饭");
};
this.breath = function() {
console.log("呼吸");
}
}
/*
1. 构造函数名首字母要大写
2. 我们构造函数不需要 return 就可以返回结果
3. 我们调用构造函数必须使用 new
4. 我们的属性和方法前面必须添加 this
*/
var person = new Person("alex", 18, "男");
console.log(person); // {name: "alex", age: 18, sex: "男", eat: ƒ, breath: ƒ}
person.breath(); // 呼吸
扩展:new
关键字的执行过程
-
new
构造函数可以在堆区内存中创建了一个空的对象 -
this
就会指向刚才创建的空对象 - 执行构造函数里面的代码,给这个空对象添加属性和方法
- 自动返回这个对象
10.2、遍历对象
遍历对象的属性:for in 语句
用于对数组或者对象的属性进行遍历操作。
如:
var array = new Array(1,2,4,8,20,3);
/*for (var index in array) {
console.log(array[index]);
}*/
for (const key in array) {
if (Object.hasOwnProperty.call(array, key)) {
const element = array[key];
console.log(element);
}
}
遍历对象属性:
// 1、初始化对象
var alex = {
name: "alex",
age: 18,
sex: "男",
breath: function() {
console.log("会呼吸~");
},
code: function() {
console.log("会写代码~");
}
}
console.log(alex);
// 2、遍历对象属性
for (var key in alex) {
console.log(typeof key); // string
// console.log(alex.key);
console.log(alex[key]);
}
对象小结:
- 对象可以让代码结构更清晰
- 对象是复杂数据类型
object
- 本质:对象就是一组无序的相关属性和方法的集合
- 构造函数泛指某一大类,比如苹果,不管是红色苹果还是绿色苹果,都统称为苹果
- 对象实例特指一个事物,对象的创建也称为对象的实例化
-
for in
语句用于对象的属性进行循环操作
10.3、常用的内置对象
1、内置对象
JavaScript中的对象分为3种:自定义对象、内置对象、浏览器对象。前面两种对象是JavaScript基础内容,属于ECMAScript
,第三个浏览器对象属于我们JavaScript独有的。
内置对象
:就是指JavaScript语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是基本而必要的功能(属性和方法)。
内置对象最大的优点就是帮助我们快速开发。JavaScript提供了多个内置对象:Math、Date、Array、String
等,内置对象会有很多的属性与方法,在这里我们不可能全部学习完,正确的方法是根据自己的需求学会在搜索引擎查阅资料。
2、Math对象
Math
是一个内置对象,它拥有一些数学常数属性和数学函数方法。Math
不是一个函数对象。与其他全局对象不同的是,Math
不是一个构造器。Math
的所有属性与方法都是静态的。引用圆周率的写法是 ·Math.PI·,调用正余弦函数的写法是 ·Math.sin(x)·,x 是要传入的参数。Math 的常量是使用 JavaScript 中的全精度浮点数来定义的。
Math对象常用属性:Math.PI
:圆周率,一个圆的周长和直径之比,约等于 3.14159
var PI = Math.PI;
console.log(PI); // 3.141592653589793
Math对象常用方法:
Math.max()
函数返回一组数中的最大值
console.log(Math.max(1,2,54,60,20)); // 60
console.log(Math.max(1,2,"alex")); // NaN
console.log(Math.max()); // -Infinity
// 由于 max 是 Math 的静态方法,所以应该像这样使用:Math.max(),而不是创建的 Math 实例的方法
Math.min()
返回零个或更多个数值的最小值
console.log(Math.min(1,2,54,60,20,-1)); // -1
Math.random()
函数返回一个浮点数, 伪随机数在范围从0到小于1,也就是说,从0(包括0)往上,但是不包括1(排除1),然后您可以缩放到所需的范围。实现将初始种子选择到随机数生成算法,它不能被用户选择或重置。
var num = Math.random();
console.log(num); // 0.6998581311366221
Math.round()
函数返回一个数字四舍五入后最接近的整数,就近取整,注意 -3.5,结果是 -3
// 生成随机数(0 < num < 10)
// 公式:[a,b] --> (int)(Math.random() * (b-a+1) +a)
var num = Math.random() * 9 + 1;
var number = Math.round(num);
console.log(number);
// console.log(parseInt(num));
// 准确写法:获取两数之间的随机整数
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max); // 向下取整
return Math.floor(Math.random() * (max - min)) + min; //不含最大值,含最小值
}
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min; //含最大值,含最小值
}
Math.abs()
取绝对值
console.log(Math.abs(-1)); // 1
更多属性与方法查看:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math
3、日期对象
创建一个 JavaScript Date 实例,该实例呈现时间中的某个时刻。Date 对象则基于 Unix Time Stamp,即自1970年1月1日(UTC)起经过的毫秒数。
- 如果没有输入任何参数,则Date的构造器会依据系统设置的当前时间来创建一个Date对象。
- 如果提供了至少两个参数,其余的参数均会默认设置为 1(如果没有指定 day 参数)或者 0(如果没有指定 day 以外的参数)。
- JavaScript的时间由世界标准时间(UTC)1970年1月1日开始,用毫秒计时,一天由 86,400,000 毫秒组成
- Date 对象的范围是 -100,000,000 天至 100,000,000 天(等效的毫秒值)。
- Date 对象为跨平台提供了统一的行为。时间属性可以在不同的系统中表示相同的时刻,而如果使用了本地时间对象,则反映当地的时间。
- Date 对象支持多个处理 UTC 时间的方法,也相应地提供了应对当地时间的方法。UTC,也就是我们所说的格林威治时间,指的是time中的世界时间标准。而当地时间则是指执行JavaScript的客户端电脑所设置的时间。
- 以一个函数的形式来调用 Date 对象(即不使用 new 操作符)会返回一个代表当前日期和时间的字符串。
创建date实例方式:通过构造函数
// 1、无参,如果没有提供参数,那么新创建的Date对象表示实例化当前时刻的日期和时间。
new Date();
// 2、value:Unix时间戳
new Date(value);
// 3、dateString:时间戳字符串
new Date(dateString);
// 4、分别提供日期与时间的每一个成员
new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]]);
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);
如:
var date = new Date();
console.log(date); // Sat May 01 2021 17:21:47 GMT+0800 (中国标准时间)
var date2 = new Date(2021,10,1);
console.log(date2); // 返回的是 11月 不是 10月(因为在js中月份是从0开始的)
var date3 = new Date("2021-10-1 12:00:00");
console.log(date3); // Fri Oct 01 2021 12:00:00 GMT+0800 (中国标准时间)
以上输出的日期格式,并不是我们想要的。我们想要的格式是类似2020-5-20 20:20:20
的日期格式化。要想变成这样的格式就必须把日期格式化(获取日期指定的部分)成我们想要的样子。
日期对象常用方法:
方法名 | 说明 | 代码 |
getFullYear() | 获取当前年份 |
|
getMonth() | 获取当前月(0 - 11) |
|
getDate() | 获取当天日期 |
|
getDay() | 获取星期几(周日0 - 周六6) |
|
getHours() | 获取当前小时 |
|
getMinutes() | 获取当前分钟 |
|
getSeconds() | 获取当前秒钟 |
|
格式化日期:
// 格式化日期
var date = new Date();
// 获取当前日期的年份
console.log(date.getFullYear()); // 2021
// 获取当前日期的月份(0 - 11)
console.log(date.getMonth() + 1); // 5
// 获取当前当天日期
console.log(date.getDate()); // 1
// 获取星期几
console.log(date.getDay()); // 6 (周六)
var dayArray = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"];
var dateString = date.getFullYear() + "年" + (date.getMonth() + 1) + "月" + date.getDate() + "日 " + dayArray[date.getDay()];
console.log(dateString); // 2021年5月1日 星期六
格式化时分秒:
var date = new Date();
console.log(date.getHours());
console.log(date.getMinutes());
console.log(date.getSeconds());
// 要求封装一个函数返回当前的时分秒,格式 08:02:12
function getMyTime() {
var date = new Date();
var timeStr = "";
var h = date.getHours();
h = h < 10 ? "0" + h : h;
var m = date.getMinutes();
m = m < 10 ? "0" + m : m;
timeStr += h + ":" + m + ":" + (date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds());
return timeStr;
}
console.log(getMyTime()); // 19:59:44
时间戳:
// 1、获得Date总的毫秒数,不是当前时间的毫秒数,而是距离1970年1月1号过了多少毫秒数
// 2、可以通过 valueOf() getTime() 获取
var date = new Date();
console.log(date.valueOf()); // 1619871288938
console.log(date.getTime()); // 1619871288938
// Date的静态方法 now()
console.log(Date.now()); // 1619871288938
案例:倒计时效果
代码实现:
/*
d = parseInt(总秒数/60/60/24) // 计算天数
h = parseInt(总秒数/60/60%24) // 计算小时
m = parseInt(总秒数/60%60) // 计算分数
s = parseInt(总秒数%60) // 计算当前秒数
*/
function countDown(time) {
var nowTime = Date.now();
var inputTime = new Date(time).getTime();
// 1s = 1000ms
var times = (inputTime - nowTime)/1000; // 剩余时间总的秒数
var d = parseInt(times / 60 / 60 / 24) // 计算天数
d = d < 10 ? "0" + d : d;
var h = parseInt(times / 60 / 60 % 24) // 计算小时
h = h < 10 ? "0" + h : h;
var m = parseInt(times / 60 % 60) // 计算分数
m = m < 10 ? "0" + m : m;
var s = parseInt(times % 60) // 计算当前秒数
s = s < 10 ? "0" + s : s;
return d + "天" + h + "时" + m + "分" + s + "秒";
}
var time = prompt("请输入倒计时结束时间(如2021-05-20 12:00:00):");
// console.log(new Date(time).getTime());
var countTime = countDown(time);
console.log(countTime);
4、数组对象
数组对象描述:数组是一种类列表对象,它的原型中提供了遍历和修改元素的相关操作。JavaScript 数组的长度和元素类型都是非固定的。因为数组的长度可随时改变,并且其数据在内存中也可以不连续,所以 JavaScript 数组不一定是密集型的,这取决于它的使用方式。一般来说,数组的这些特性会给使用带来方便,但如果这些特性不适用于你的特定使用场景的话,可以考虑使用类型数组 TypedArray。
首先是创建数组对象的方式,在前面我们也已经学习过了有两种方式:
- 字面量方式
[]
- 构造函数
new Array()
// var array = new Array(); 创建了一个空数组
// var array = new Array(5); 表示数组的长度为 5,里面有 5 个空的数组元素
var array = new Array(1,2,3); // 等价于 [1,2,3]
console.log(array); // [1, 2, 3]
① 检测是否为数组:
/*
检测是否为数组:
1.instanceof 它是一个运算符,可以用来检测是否为数组
2.Array.isArray() 用于确定传递的值是否是一个 Array
*/
var array1 = new Array(1,2,3);
console.log(array1 instanceof Array); // true
var obj = {};
console.log(obj instanceof Array); // false
console.log(obj instanceof Object); // true
Array.isArray([1, 2, 3]); // true
Array.isArray({foo: 123}); // false
Array.isArray("foobar"); // false
Array.isArray(undefined); // false
② 数组元素的增删改:
/*
数组元素的增删改:
1.push()方法在我们数组的末尾,添加一个或者多个数组元素,添加成功后返回新数组的长度
2.unshift()方法在我们数组的开头,添加一个或者多个数组元素,添加成功后返回新数组的长度
3.pop()方法删除数组的最后一个元素,并返回删除的元素
4.shift()方法删除数组的第一个元素,并返回删除的元素
5.对于修改数组的元素,我们都是采用索引(角标)的方式,如 array[0] = xxx;
*/
var array = new Array(1,2,3);
console.log(array); // [1,2,3]
console.log(array.push(4)); // 4
console.log(array); // [1,2,3,4]
console.log(array.unshift(0)); // 5
console.log(array); // [0, 1, 2, 3, 4]
console.log(array.pop()); // 4
console.log(array); // [0, 1, 2, 3]
console.log(array.shift()); // 0
console.log(array); // [1, 2, 3]
array[0] = 100;
console.log(array); // [100, 2, 3]
③ 数组排序:
方法名 | 说明 | 是否修改原数组 |
reverse() | 数组翻转,无需参数 | 该 方法会改变原来的数组,返回新数组 |
sort() | 对数组的元素进行排序 | 该方法会改变原来的数组,返回新数组 |
验证如下:
var array = new Array(1,2,3);
// 1、数组翻转
console.log(array); // [1,2,3]
console.log(array.reverse()); // [3,2,1]
// 2、数组排序
console.log(array.sort()); // [1,2,3]
// sort()方法还可以子定义排序规则(降序/升序)
var arr = [1,52,45,3,12];
// 升序
console.log(arr.sort(function(a, b) {
return a - b;
})); // [1, 3, 12, 45, 52]
// 升序
console.log(arr.sort(function(a,b) {
return -(a - b); // b - a 也行
})); // [52, 45, 12, 3, 1]
④ 数组索引方法:
方法名 | 说明 | 返回值 |
indexOf() | 数组中查找给定元素的第一个索引 | 如果存在返回索引号,如果不存在,则返回-1 |
lastIndexOf() | 在数组中的最后一个的索引 | 如果存在返回索引号,如果不存在,则返回-1 |
代码验证:
// 返回数组元素索引号方法
var array = [1,2,3,3];
// 1.indexOf(数组元素) 返回该数组元素的索引号(注意是第一个满足条件的索引号),从前往后查找
console.log(array.indexOf(3)); // 2
// 2.lastIndexOf(数组元素) 返回该数组最后一个元素的索引号,从后往前查找
console.log(array.lastIndexOf(3)); // 3
console.log(array.lastIndexOf(4)); // -1
⑤ 数组去重:
// 数组去重的原理:我们遍历旧数组,然后拿着旧数组去查询新数组,如果该元素在新数组里面没有出现过,我们就添加,否则不添加。
function distinct(array) {
if (Array.isArray(array)) {
var newArray = new Array();
array.forEach(item => {
if (newArray.indexOf(item) === -1) {
newArray.push(item);
}
});
return newArray;
}else {
throw new TypeError("你应该传入一个数组哦");
}
}
var array = distinct([1,2,2,2,3,3,3]);
console.log(array); // [1,2,3]
⑥ 数组转换为字符串
方法名 | 说明 | 返回值 |
toString() | 把数组转换成字符串,逗号分隔每一项 | 返回一个字符串 |
| 方法用于把数组中的所有元素转换为一个字符串 | 返回一个字符串 |
如:
// 数组转换为字符串
var array = [1,2,3];
// 1. toString() 把数组转换成字符串,逗号分隔每一项
var strArray = array.toString();
console.log(typeof strArray); // string
console.log(strArray); // 1,2,3
// 2. join("分隔符") 方法用于把数组中的所有元素转换为一个字符串
var str = array.join("-");
console.log(str); // 1-2-3
// 注意没有指定分隔符时,效果与toString是一样的。
数组是我们比较常用的内置对象,它的内置属性与方法远不止上面那些,更多属性与方法的使用可查看MDN等网站。
5、字符串对象
① 基本包装类型
为了方便操作基本数据类型,JavaScript还提供了三个特殊的引用类型:String、Number、Boolean。
var str = "alex";
console.log(str.length); // 4
// 问:复杂的数据类型才有属于与方法,那么这里的 str 为什么会有 length 属性呢?
/*
基本包装类型:就是把简单数据类型包装成为了复杂数据类型。
1. 如 var str = "alex"; => 先用临时变量保存:var temp = new String("alex");
2. 再把临时变量赋值给 str。 str = temp;
3. 销毁临时变量。temp = null;
*/
基本包装类型
:就是把简单数据类型包装成为复杂数据类型,这样基本数据类型就有了属性和方法。
② 字符串对象
关于字符串前面我们已简单接触过,然而开发中字符串类型也是我们使用最多的。字符串对于保存可以以文本形式表示的数据非常有用。 一些常用的字符串操作有:查询字符串长度,使用 +
和 +=
运算符来构建和连接字符串,使用 indexOf
方法检查某一子字符串在父字符串中的位置,又或是使用 substring
方法提取从父字符串中提取子字符串等,这些都是开发中会遇到的场景。
首先是字符串的不可变性:指的是里面的值不可变,虽然看上去可以改变内容,单其实是内存地址变了,内存中新开辟了一个内存空间。
var str = "abc";
str = "hello";
/*
1.当重新给 str赋值的时候,常量 "abc" 不会被修改,依然在内存中。
2.重新给字符串赋值,会重新在内存中开辟空间,这个特点就是字符串的不可变
3.由于字符串的不可变,在大量拼接字符串的时候会有效率问题
*/
var str = "";
for (var i = 0; i < 1000000; i++) {
str += i;
}
console.log(str); // 这个结果需要花费大量时间来显示,因为需要不断的开辟新的空间。
② 根据字符串返回位置
字符串所有的方法,都不会修改字符串本身(字符串是不可变得),操作完成会返回一个新的字符串。
方法名 | 说明 |
| 返回指定内容在元字符串的位置,如果找不到就返回-1,开始的位置是index索引号。 |
lastIndexOf() | 从后往前找,只找第一个匹配的 |
如:
// 获取字符串的索引号
// 1.indexOf("要查找的字符",[起始位置]) 根据指定字符返回索引号,如果不存在则返回 -1
var str = "大话设计模式,设计";
console.log(str.indexOf("设")); // 2
// 从索引号是3的位置开始查找
console.log(str.indexOf("设",3)); // 7
// 2.lastIndexOf() 从后往前查找根据指定字符返回索引号,如果不存在则返回 -1
console.log(str.lastIndexOf("设")); // 7
案例:查找字符串abcoefoxyozzopp
中所有o
出现的位置以及次数。
function countIndexAndSite(str, target) {
if (typeof str == "string" && typeof target === "string") {
var array = new Array();
var sum = 0;
for (var i = 0; i < str.length; i++) {
var index = str.indexOf(target, i);
if (index != -1) {
array.push(index);
i = array[sum] + 1;
sum++;
}
}
// 注意:site是目标值出现的索引位置,以数组的形式保存。sum就是目标值出现的次数
return {
site: array,
sum: sum
};
} else {
throw new TypeError("参数类型错误:请检查参数是否是String类型?");
}
}
var str = "abcoefoxyozzopp";
var demo = countIndexAndSite(str, "o");
console.log(demo);
③ 根据指定位置返回字符(重点)
方法名 | 说明 | 使用 |
charAt(index) | 返回指定位置的字符(index 字符串的索引号) | str.charAt(0) |
charCodeAt(index) | 获取指定位置处字符的ASCLL码(index索引号) | str.charCodeAt(0) |
str[index] | 获取指定位置处字符 | HTML5,IE8+支持和charAt()等效 |
如:
// 根据指定位置返回字符
// 1.charAt(index) 根据位置返回字符
var str1 = "欢迎来打对抗路";
console.log(str1.charAt(0)); // 欢
// 遍历所有的字符
for (var i = 0;i < str1.length;i++) {
console.log(str1.charAt(i));
}
// 2.charCodeAt(index) 返回相应索引号的字符ASCLL值。目的:判断用户按下了那个键
var str2 = "abc";
console.log(str2.charCodeAt(0)); // 97
// 3.str[index] H5新增,效果与charAt()一致
console.log(str1[0]); // 欢
④ 字符串操作方法(重点)
方法名 | 说明 |
concat(str1,str2,str3) | concat()方法用于连接两个或多个字符串。拼接字符串,等效于+,并且+更常用 |
substr(start,length) | 从start位置开始(索引号),length取的个数,重点记住这个 |
slice(start,end) | 从start位置开始,截取到end位置,end娶不到(他们俩都是索引号) |
substring(start,end) | 从start位置开始,截取到end位置,end娶不到,基本和slice()方法相同,但是不接受负值 |
如:
// 字符串操作方法
// 1.concat()拼接字符串。与 + 效果一致
var str1 = "hello ";
str1 = str1.concat("world");
console.log(str1); // hello world
// 2.substr("截取的起始位置","截取几个字符") 截取字符串
var str2 = "helloworld";
console.log(str2.substr(0,5)); // hello
console.log(str2.substr(5,5)); // world
// 3.substring(start,end) 根据指定索引截取字符串
var str3 = "abcd123efg";
console.log(str3.substring(4,7)); // 123
// 4.替换字符串 replace("被替换的字符","替换为的字符") 它只会替换第一个字符
str3 = str3.replace("123","456");
console.log(str3); // abcd456efg
// 5.字符转换为数组 split("分隔符")。
var str4 = "a/b/c/d/e";
var array = str4.split("/");
console.log(array); // ["a", "b", "c", "d", "e"]
var str5 = array.join("/");
console.log(str5); // a/b/c/d/e
字符串对象的方法还有很多,这里是讲不完了,所以大家有需求时要学会查阅文档与资料。
11、数据类型的内存模型
11.1、简单类型与复杂类型
简单类型又叫做基本数据类型或值类型
,复杂类型又叫做引用类型
。
- 值类型:简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型
(string,number,boolean,undefined,null)
- 引用类型:引用数据类型,在存储时变量中存储的仅仅是地址(引用),因此叫做引用数据类型。通过 new 关键字创建的对象(系统对象、自定义对象),如
Object、Array、Date、String
。
// 简单数据类型 null 返回的是一个空的对象 object
var obj = null;
console.log(typeof obj); // object
// 如果有个变量我们以后打算存储为对象,暂时没有想好放啥,这个时候就给 null
11.2、堆和栈
堆栈空间分配区别:
- 栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。器操作方式类似于数据结构中的栈。注意:
简单数据类型存放到栈里
- 堆(操作系统):存储复杂类型(对象),一般由开发人员分配释放,若不释放,由垃圾回收机制回收。注意:
复杂数据类型存放到堆里面
- 注意:JavaScript中没有堆栈的概念,通过栈堆的方式,可以让大家更容易理解代码的一些执行方式,便于将来学习其他语言。
数据类型的内存分配:
值类型(简单数据类型):string、number、boolean、undefined、null
。它们的值直接存放在变量(栈空间)中。
引用类型(复杂数据类型):Object、Array、Date、String
。变量中存储的是地址值。注意,每次 new
的时候都是在堆区中创建实例。
如图所示:
11.3、简单类型传参
函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到外部变量。
function add(num) {
num++;
console.log(num); // 11
}
var num = 10;
add(num);
console.log(num); // 10
11.4、复杂类型传参
将实参引用数据类型变量的地址值
传递给形参。
注意:函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。
function Person(name) {
this.name = name;
}
function f1(x) {
console.log(x.name); // 2、这里输出?韩信
x.name = "李白";
console.log(x.name); // 3、这里输出?李白
}
var p = new Person("韩信");
console.log(p.name); // 1、这里输出?韩信
f1(p);
console.log(p.name); // 4、这里输出?李白
End
Thank you for watching
End