第一章
1 计算机编程基础
什么是编程语言 |
编程语言和标记语言的不同 |
常见的数据存储单位及其换算关系 |
内存的主要作用以及特点 |
2 编程语言
编程:就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结果的过程 |
计算机程序:就是计算机所执行的一系列的指令集合,而程序全部都是用我们所掌握的语言来编写的,所以人们要控制计算机一定要通过计算机语言向计算机发出命令。 |
从事编程的人员,就是程序员,但是一般程序员都比较幽默,为了形容自己的辛苦工作,也称为“码农”,或者“程序猿” / “程序媛” |
注意:上面所定义的计算机指的是任何能够执行代码的设备,可能是智能手机、ATM机、黑莓PI、服务器等等。 |
3 计算机语言
计算机语言指用于人与计算机之间通讯的语言,它是人与计算机之间传递信息的媒介。 |
计算机语言的种类非常的多,总的来说可以分成机器语言、汇编语言和高级语言三大类 |
实际上计算机最终所执行的都是机器语言,它是由“0”和“1”组成的二进制数,二进制是计算机语言的基础 |
4 编程语言
可以通过类似于人类语言的“语言”来控制计算机,让计算机为我们做事情,这样的语言就叫编程语言(Programming Language)
编程语言是用来控制计算机的一系列指令,它有固定的格式和词汇(不同编程语言的格式和词汇不一样),必须遵守。
4.1 如今通用的编程语言有两种形式:汇编语言和高级语言
汇编语言和机器语言实质是相同的,都是直接对硬件操作,只不过指令采用了英文缩写的标识符,容易识别和记忆。 |
高级语言主要是相对于低级语言而言,它并不是特指某一种具体的语言,而是包括了很多编程语言,常用的有C语言、C++、Java、C#、Python、PHP、JavaScript、Go语言、Objective-C、Swift等。 |
4.2 编程语言和标记语言区别
编程语言有很强的逻辑和行为能力。在编程语言里,你会看到很多if else、for、while等具有逻辑性和行为能力的指令,这是主动的。 |
标记语言(html)不用于向计算机发出指令,常用于格式化和链接。标记语言的存在是用来被读取的,它是被动的。 |
4.3 翻译器
高级语言所编写的程序不能直接被计算机识别,必须经过转换才能被执行,为此,我们需要一个翻译器。翻译器可以将我们所编写的源代码转换为机器语言,这也被称为二进制化,记住1和0
4.4 总结:
计算机可以帮助人类解决某些问题
程序员利用编程语言编写程序发出指令控制计算机来实现这些任务
编程语言有机器语言、汇编语言、高级语言
高级语言需要一个翻译器转换为计算机识别的机器语言
编程语言是主动的有很强的逻辑性
5 计算机组成:
组成 | 描述 |
硬件 | 输入设备:鼠标、键盘、手写板、摄像头等 |
输出设备:显示器、打印机、投影仪等 | |
CPU:负责处理数据与运算 | |
硬盘:负责存储数据,硬盘永久存储数据 | |
内存:负责存储数据,暂时存储数据 | |
软件 | 系统软件: Windows、Linux、macOS |
应用软件: 浏览器、QQ、VSCode、Sublime、word |
6 数据存储
计算机内部使用二进制0和1来表示数据。 |
所有数据,包括文件、图片等最终都是以二进制数据(0和1)的形式存放在硬盘中的。 |
所有程序,包括操作系统,本质都是各种数据,也以二进制数据的形式存放在硬盘中。平时我们所说的安装软件,其实就是把程序文件复制到硬盘中。 |
硬盘、内存都是保存的二进制数据。 |
7 数据存储单位
bit<Byte<kb<GB<IB<… |
位(bit):1bit可以保存一个0或者1(最小的存储单位) |
字节(Byte):1B=8b 8个字节是一个字符【一个中文字符相当于2个英文字符】 |
千字节(KB):1KB=1024B |
兆字节(MB):1MB=1024KB |
吉字节(GB):1GB=1024MB |
太字节(TB):1TB=1024GB |
8 程序运行
- 打开某个程序时,先从硬盘中把程序的代码加载到内存中
- CPU执行内存中的代码
- 注意:之所以要内存的一个重要原因,是因为cpu运行太快了,如果只要从硬盘中读数据,会浪费cpu性能,所以,才使用存取速度更快的内存来保存运行时的数据。(内存是电,磁盘是机械)
- JavaScript历史
- 布莱登.艾奇(Brendan Eich.1961~)
- 神奇的大哥在1995年利用10天完成JavaScript设计
- 网景公司最初命名为LiveScript,后来在与Sun合作之后将其改名为JavaScript。
- JavaScript是什么
- JavaScript是世界上最流行的语言之一,是一种运行在客户端的脚本语言(script是脚本的意思)
- 客户端:我们用的电脑
- 服务器端:远程的服务器
- 脚本语言:不需要编译,运行过程中由js解释器(js引擎)逐行来进行解释并执行
- 现在也可以基于Node.js技术进行服务器端编程
- 为了阅读方便,我们后面把JavaScript简称为JS
- JavaScript是世界上最流行的语言之一,是一种运行在客户端的脚本语言(script是脚本的意思)
- JavaScript的作用
- 表单动态校验(密码强度检测)【JS产生最初的目的】
- 网页特效
- 服务器开发(Node.js)
- 桌面程序(Electron)
- App(Cordava)
- 控制硬件-物联网(Ruff)
- 游戏开发(Cocos2d-js)
- HTML/CSS/JS的关系
- HTML/CSS标记语言—描述类语言
- HTML决定网页结构和内容(决定看到什么),相当于人的身体
- CSS决定网页呈现给用户的模样(决定好不好看),相当于给人穿衣服、化妆
- JS脚本语言—编程类语言
- 实现业务逻辑和页面控制(决定功能),相当于人的各种动作
- HTML/CSS标记语言—描述类语言
- 浏览器执行JS简介
- 浏览器分成两个部分:
- 渲染引擎:用来解析HTML与CSS,俗称内核,比如chrome浏览器的blink,老版本的webkit
- JS引擎:也称为JS解释器,用来读取网页中的JavaScript代码,对其处理后运行,比如chrome浏览器的V8
- 浏览器本身并不会执行JS代码,而是通过内置JavaScript引擎(解释器)来执行JS代码。JS引擎执行代码时逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以JavaScript语言归为脚本语言,会逐行解释执行。
- 浏览器分成两个部分:
- JS的组成
- ECMAScript:JavaScript语法
- DOM:页面文档对象模型
- BOM:浏览器对象模型
- ECMAScript
- 是由ECMA国际(原欧洲计算机制造商协会)进行标准化的一门编程语言,这种语言在万维网上应用广泛,它往往被称为JavaScript(网景公司)或Jscript(微软公司),但实际上后两者是ECMAScript语言的实现和扩展。
- 规定了JS的编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套JS语法工业标准
- 更多参看MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/JavaScript_technologies_overview
- DOM——文档对象模型
- 文档对象模型(Document Object Model),是W3C组织推荐的处理可扩展标记语言的标准编程接口。通过DOM提供的接口可以对页面上的各种元素进行操作(大小、位置、颜色等)。
- BOM——浏览器对象模型
- BOM(Browser Object Model,简称BOM)是指浏览器对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等
- JS书写位置
- 行内
- js代码直接写在元素标签内部
- 行内
<input type="text" value="黑恶hi" onclick="alert('你好呀')">
- 内嵌
- Js代码写在script标签中间
- 内嵌
<script>
alert('沙漠骆驼');
</script>
- 外部
- 新建.js的文件,js代码写在里面
- 然后引入js代码
- 外部
<script src="外部js代码路径"></script>
- 行内JS
- 可以将单行或少量JS代码写在HTML标签的事件属性中(以on开头的属性),如:onclick
- 注意单双引号的使用:在HTML中我们推荐使用双引号,JS中我们推荐使用单引号
- 可读性差,在html中编写JS大量代码时,不方便阅读
- 引号易错,引号多层嵌套匹配时,非常容易弄混;
- 特殊情况下使用
- 内嵌JS
- 可以将多行JS代码写到<script>标签中
- 内嵌JS是学习时常用的方式
- 外部JS文件
- 利用HTML页面代码结构化,把大段JS代码独立到HTML页面之外,既美观,也方便文件级别的复用
- 引用外部JS文件的script标签中间不可以写代码
- 适合于JS代码量比较大的情况
- JavaScript注释
- 单行注释:
- // 单行注释内容【默认快捷键:ctrl + /】
- 多行注释
- /* 多行注释内容 */ 【默认快捷键:shift + alt +a】
- 单行注释:
- JavaScript输入输出语句
- 为了方便信息的输入输出,JS中提供了一些输入输出语句,其常用的语句如下
方法 | 说明 | 归属 |
alert(msg) | 浏览器弹出警示框:此网页显示,下面是显示的内容 | 浏览器 |
console.log(msg) | 浏览器控制台打印输出信息,想要输出多个变量值,变量之间用逗号分隔即可 | 浏览器 |
prompt(info) | 浏览器弹出输入框,用户可以输入(输入框保存的数据是字符串类型的) | 浏览器 |
- prompt(“提示文本”,”默认值”);
- 默认值可以省略。
- prompt(“提示文本”,”默认值”);
- 变量
- 什么是变量:
- 白话:变量就是一个装东西的盒子
- 通俗:变量是用于存放数据的容器。我们通过变量名获取数据,甚至数据可以修改。
- 变量在内存中的存储
- 本质:变量是程序在内存中申请的一块用来存放数据的空间。
- 什么是变量:
- 变量的使用
- 变量的使用分为两步:
- 声明变量:
- var 变量名;
- 赋值
- 变量名 = 变量值;
- 声明变量:
- 案例:
- 变量的使用分为两步:
<script>
var age;
age = 18;
console.log(age)
</script>
- var是一个JS关键字,用来声明变量(variable变量的意思)。使用该关键字声明变量后,计算机会自动为变量分配内存空间,不需要程序员管。程序员定义变量名,我们要通过变量名来访问内存中分配的空间
- =用来把右边的值赋给左边的变量空间中 此处代表赋值的意思
- 变量值是程序员保存到变量空间里的值
- 变量的初始化
- 声明变量的同时赋值
- 语法:var 变量名 = 变量值;
- 声明一个变脸并赋值,我们称之为变量的初始化。
- 变量语法扩展
- 跟新变量
- 一个变量被重新赋值后,它原有的值就会被覆盖,变量值将以最后一次赋的值为准。
- 同时声明多个变量
- 同时声明多个变量时,只需要写一个var,多个变量名之间使用英文逗号隔开
- 语法:
- var 变量1名 = 变量1值, 变量2名 = 变量2值,…;
- 跟新变量
- 声明变量的特殊情况
情况 | 说明 | 结果 |
var age; console.log(age); | 只声明,不赋值 程序也不知道里面存放的是什么,所以结果为undefined | undefined |
console.log(age) | 不声明不赋值 直接使用 | 报错 |
age=10; console.log(age); | 不声明 只赋值 | 会当全局变量输出结果 |
- 变量命名规范
- 由字母(A-Z a-z)、数字(0-9)、下划线(_)美元符号($)组成
- 严格区分大小写。var app;和var App;是两个变量
- 不能以数字开头。1age 是错误的
- 不能是 关键字、保留字。例如: var、for、while
- 关键字:js已经赋予特殊功能的单词
- 保留字:js预订可能未来要使用的字
- 变量名必须有意义(见名知意)
- 遵守小驼峰命名法。首字母小写,后面单词的首字母需要大写。myFirstName
- 推荐翻译网站:有道 爱词霸
- Js是编程语言,有很强的逻辑性在里面:实现这个要求的思路 先怎么做后怎么做
- 交换两个变量的值
- 声明一个临时变量
- 将变量1里面存储的变量1值 赋值给 临时变量,此时临时变量存储的值为变量1值
- 将变量2里面存储的变量2值 赋值给 变量1,此时变量1中存储的值为变量2值
- 最后将临时变量里面存放的变量1值 赋值给 变量2,此时变量2中存储的值为变量1值
- 交换两个变量的值案例:
<script>
var temp;
var apple1 = "苹果";
var apple2 = "香蕉";
temp = apple1;
apple1 = apple2;
apple2 = temp;
console.log(apple1, apple2)
</script>
- 小结
- 为什么需要变量
- 我们一些数据需要保存,所以需要变量
- 变量是什么
- 变量是一个容器,用来存放数据的。方便我们以后使用里面的数据
- 变量的本质是什么
- 变量是内存里的一块空间,用来存储数据。
- 变量怎么使用
- 使用变量的时候,一定要声明变量,然后赋值
- 声明变量本质是去内存申请空间。
- 什么是变量的初始化
- 声明变量并赋值我们称之为变量的初始化
- 为什么需要变量
- 数据类型简介
- 为什么需要数据类型
- 在计算机中,不同的数据所需占用的存储空间是不同的,为了便于把数据分成所需内存大小不同的数据,充分利用存储空间,于是定义了不同的数据类型
- 变量的数据类型
- 变量是用来存储值得所在处,它们有名字和数据类型。变量的数据类型决定了如何将代表这些值的位存储到计算机的内存中。JavaScript是一种弱类型或者说动态语言。这意味着不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。
- JS的变量数据类型是只有程序在运行过程中,根据等号右边的值来确定的
- 在代码运行时,变量的数据类型是由JS引擎根据 = 右边变量值的数据类型来判断的,运行完毕之后,变量就确定了数据类型
- JavaScript拥有动态类型,同时也意味着相同的变量可用作不同的类型;
- 为什么需要数据类型
- 数据类型的分类
- JS把数据类型分为两类
- 简单数据类型(值类型)
- 数字(Number)、字符串(String)、布尔(Boolean)、未定义(Undefined)、空(Null)【通常作对象的占位符】 、symbol
- 数字的方法:
- 数字(Number)、字符串(String)、布尔(Boolean)、未定义(Undefined)、空(Null)【通常作对象的占位符】 、symbol
- 简单数据类型(值类型)
- JS把数据类型分为两类
toFixed(小数点后面的位数)
- 复杂数据类型(引用数据类型)
- 对象(Object)
- 数组(Array)
- 函数(function)
- 引用数据类型赋值是将地址给变量保存,简单数据类型赋值就是存复制。
- 复杂数据类型(引用数据类型)
- JavaScript中的简单数据类型及其说明如下:
简单数据类型 | 说明 | 默认值 |
Number | 数字型,包含 整型值和浮点型值,如21、0.21 | 0 |
Boolean | 布尔值类型,如true、false,等价于1和0 | false |
String | 字符串类型,如“张三” 注意咱们js里面,字符串都带引号 | “” |
Undefined | var a;声明了变量a但是没有给值,此时a = undefined | undefined |
Null | var a = null;声明了变量a为空值 | null |
- null不能进行和0的相等判断,结果都为false,其它判断null都会先转换为数字0.
- 数字型Number
- JavaScript数字类型既可以用来保存整数值,也可以保存小数(浮点数)。
- 案例:
- var num = 1.1;
var num = 1;
- 数字型进制
- 最常见的进制有二进制、八进制、十进制、十六进制
- 我们程序里面数字前面加零或零字母o(0、0o、0O)表示八进制,八进制只包含数字0~7
- 数字的前面加0x表示十六进制(十六进制整数可以包含0~9和字母a~f或字母A~F)
- 只有整数才有进制,小数没有进制
- 最常见的进制有二进制、八进制、十进制、十六进制
- 数字型范围
- Number.MAX_VALUE:1.7976931348623157e+308 【数字型最大值】
- Number.MIN_VALUE: 5e-324 【数字型最小值】
- 数字型三个特殊值
- Infinity,代表无穷大,大于任何数值
- -Infinity,代表无穷小,小于任何数值
- NaN,Not a number,代表一个非数值
- 出现算术运算符并且有一个非数字做算术运算时(字符串+操作除外),结果为NaN
- 数字型进制
- isNaN()
- 这个方法用来判断非数字并且返回一个值。如果是数字返回的是false,如果不是数字返回的是true
- NaN一般不作为if语句的条件判断【有NaN作为条件时,相当于false】【有NaN的表达式返回结果都为false】,可以用isNaN来作条件判断
- 语法:isNaN(目标值)
- 该目标值会先进行强制数据类型转换【将字符串类型的数据转换为数字类型】
- 当目标值是非数字时,返回值为true
- 当目标值为数字时,返回值为false
- 字符串型String
- 字符串可以是引号中的任意文本,其语法为双引号””和单引号’’
- 因为HTML标签里面的属性使用的是双引号,JS这里我们更推荐使用单引号。
- 字符串引号嵌套
- JS可以用单引号嵌套双引号,或者用双引号嵌套单引号(外双内单,外单内双)
- 字符串转义符
- 类似HTML里面的特殊字符,字符串中也有特殊字符,我们称之为转义符
- 转义符必须写在引号里面才能被解析
- 转义符都是\开头的,常用的转义符及其说明如下:
转义符 | 解释说明 |
\n | 换行符,n是newline的意思 |
\\ | 斜杠\ |
\’ | ‘单引号 |
\” | “双引号 |
\t | Tab缩进 |
\b | 空格,b是blank的意思 |
- 字符串长度
- 字符串是由若干字符组成的,这些字符的数量就是字符串的长度。通过length属性可以获取整个字符串的长度
- 字符串拼接
- 多个字符串之间可以使用+进行拼接,其拼接方式为字符串 + 任何类型 = 拼接之后的新字符串
- 拼接前会把与字符串相加的后面的任何类型转成字符串,再拼接成一个新的字符串。(前面的算术运算不受影响)
- +号总结口诀:数值相加,字符相连
- 我们经常会将字符串和变量来拼接,因为变量可以很方便地修改里面的值
- 变量是不能添加引号的,因为加引号的变量会变成字符串
- 如果变量两侧都有字符串拼接,口诀“引引加加”,删掉数字,变量写在加号中间
- 字符串长度
- 交互编程三个基本要素
- 用户输入
- 程序内部处理
- 输出结果
- 布尔型Boolean
- 布尔类型有两个值:true和false,其中true表示真(对),而false表示假(错)。
- Boolean类型参与数字加操作时,true的值是1,false的值是0
- undefined和null
- 一个声明后没有被赋值的变量会有一个默认值undefined
- 数字和undefined相加的结果为NaN
- 字符和undefined加操作,结果为 字符串拼接
- undefined和undefined加操作,结果为 NaN
- null和字符串加操作,结果为 null和字符串相连
- null和数字加操作,结果为 数字本身
- null和undefined加操作,结果为 NaN
- NaN不能做判断条件(超级重要,因为NaN出现的比较运算结果都为false)
- NaN不等于自己,不全等于自己
- 数据类型转换
- 获取检测变量的数据类型
- typeof 可用来获取检测变量代表的值的数据类型(结果为变量的数据类型)
- typeof检测数据类型是有限度的,只能区分基本数据类型,不能区分引用数据类型【结果都为object】
- 语法:
- typeof 变量名
- typeof (变量名)
- 控制台中都是用字符串书写变量的数据类型
- typeof 可用来获取检测变量代表的值的数据类型(结果为变量的数据类型)
- 获取检测变量的数据类型
比如typeof 123。控制台中为“number”,表示123是数字类型,但number是字符串书写的。
所以多个typeof连用时,控制台输出的是“string”
- null类型的数据类型为object
- prompt取过来的值是字符串类型的
- 通过控制台打印出的数据颜色判断数值类型
- 蓝色数字 为 数字Number类型
- 黑色数字 为 字符串String类型
- 蓝色布尔值 为 布尔类型Boolean类型
- 黑色布尔值 为 字符串String类型
- 字面量
- 字面量是源代码中一个固定值的表示法,通俗来说,就是字面量表示如何表达这个值(等号右边的值)
- 数字字面量:8,9
- 整数:
- 十进制:普通的数字就是十进制
- 8进制:如果以0(零)、0o(零和字母o)、0O(零和字母O)开头数字字面量是八进制,八进制只包含数字0~7
- 整数:
- 数字字面量:8,9
- 字面量是源代码中一个固定值的表示法,通俗来说,就是字面量表示如何表达这个值(等号右边的值)
注意,八进制只能出现0~7这8中数字,如果表示不合法,那么JS将自动的认为你输入错了,从而用十进制进行显示。但是以0o开头、0O开头的数字,如果后面写错了,控制台报错!
- 十六进制:如果以0x,0X开头数字字面量,十六进制整数可以包含(0~9和字母a~f或A~F)
- 浮点数(小数或指数)
- 小数的字面量也很简单,就是数学上的点。计算机世界中,小数称为“浮点数”。
- 指数就是:允许使用e来表示乘以10的几次幂
- 注意:
只有十进制有小数的字面量,八进制、十六进制没有小数的字面量。所以小数没有进制之分
- NaN:英语全名叫做not a number,不是一个数,但 是数字字面量
- 字符串字面量:“你好”,‘我很好,谢谢’
- 字符串的字面量有限定符,就是必须用双引号或单引号包裹起来。字符串被限定在同种引号之间;也就是说,必须是成对单引号或成对双引号。
- 不加引号是错误的。
- 布尔字面量:true,false
- 特殊字面量:Infinity,NaN
- 数据类型转换
- 什么是数据类型转换
- 使用表单、prompt获取过来的数据默认是字符串类型的,此时就不能直接简单的进行加法运算,而需要转换变量的数据类型。通俗来说,就是把一种数据类型的变量转换成另外一种数据类型。
- 常用的3中方式转换:
- 转换为字符串类型
- 转换为数字型
- 转换为布尔型
- 什么是数据类型转换
- 转换为字符串
方式 | 说明 | 案例 |
变量名.toString() | 转成字符串 | console.log(age.toString()); |
String(变量名) | 转成字符串 | console.log(String(age)); |
加号拼接字符串 | 和字符串拼接的结果都是字符串 | console.log('' + age); |
- 三种转换方式,我们更喜欢用第三种加号拼接字符串转换方式,这一种方式也称之为隐式转换。
- 转换为数字型(重点)
方式 | 说明 | 案例 |
parseInt(string)函数 | 将string类型转换成整数数值型(取整:会去掉后面的非数字符号【小数点及其后面的内容、单位及其后面的内容,特殊符号等等。当没有以数字开头时,结果为NaN】)【如果parsetInt参数是除了数字和字符串意外的基本类型,结果为NaN,转不了的意思】 | parseInt(“78”) |
parseFloat(string)函数 | 将string类型转成浮点数数值型(取浮点数:会去掉后面的非数字符号【单位及其后面的内容,特殊符号等等。当没有以数字开头时,结果为NaN】) | parsetFloat(“78.12”) |
Number(string)强制转换函数 | 将string类型强制转换为数值型【纯数字字符串直接转换为数字。空字符串或者空格字符串转数字为0。其它情况转字符串为NaN】 | Number(“12”) |
Js隐式转换(- * /) | 利用算术运算隐式转换为数值型 | “12” - 0 |
- 注意parseInt和parseFloat单词的大小写
- Number(string)
- 布尔值转数字类型:true为1,false为0
- undefined转数字:NaN
- null转数字:0
- parseInt(string,[进制数])
- parsetInt()不仅能够转为整数,还可以进行进制的转换,把任何进制的数字,都转换为10进制。进制转换的字符串,用逗号隔开。【只取整数部分进制转换为10进制】
- parsetInt如果不能转,那么就返回NaN
- 转换为布尔型
方式 | 说明 | 案例 |
Boolean()函数 | 其他类型转成布尔值 | console.log(Boolean("true")) |
- 代表空、否定的值会被转换为false,如‘’,0,NaN,null,undefined,false
- 其余值都会被转换为true
- 解释型语言和编译语言
- 概述:
- 计算机不能直接理解任何除机器语言以外的语言,所以必须要程序员所写的程序语言翻译成机器语言才能够执行程序。程序语言翻译成机器语言的工具,被称为翻译器。
- 翻译器翻译的方式有两种:一个是编译,另一个是解释。两种方式之间的区别在于翻译的时间点不同。
- 编译器是在代码执行之前进行编译,生成中间代码文件
- 解释器是运行时进行及时解释,并立即执行(当编译器以解释方式运行的时候,也称之为解释器)
- 概述:
- 标识符
- 标识符:就是指开发人员为变量、属性、函数、参数取的名字。
- 标识符不能是关键字和保留字
- 关键字
- 关键字:是指JS本身已经使用了的字,不能再用它们充当变量名、方法名
- 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等。
- 关键字:是指JS本身已经使用了的字,不能再用它们充当变量名、方法名
- 保留字
- 保留字:实际上就是预留的“关键字”,意思是现在虽然还不是关键字,但是未来可能会成为关键字,同样不能使用它们当变量名或方法名。
- 包括:abstract、boolean、byte、char、class、const、debugger、double、enum、export、extends、final、float、goto、implements、import、int、interface、long、mative、native、package、private、protected、public、short、static、super、synchronized、throws、transient、volatile等
- 运算符
- 运算符(operator)也被称为操作符,是用于实现赋值、比较和执行算术运算等功能的符号。
- JavaScript中常用的运算符:
- 算数运算符
- 递增递减运算符
- 比较运算符
- 逻辑运算符
- 赋值运算符
- 算术运算符(数学运算符)
- 概念:算术运算使用的符号,用于执行两个变量或值的算术运算。
运算符 | 描述 | 实例 |
+ | 加 | 10 + 20 = 30 |
- | 减 | 10 – 20 = -10 |
* | 乘 | 10 * 20 = 200 |
/ | 除 | 10 / 20 = 0.5 |
% | 取余数(取模) | 返回除法的余数9 % 2 = 1 |
- 浮点数 算术运算里面会有问题
- 例如0.1 + 0.2
- 避免直接用浮点数参与运算
- 浮点数的精度问题
- 浮点数值的最高精度是17位小数,但在进行算术计算时其精确度远远不如整数。
- 我们不能拿着浮点数(运算后)直接来进行相比较 是否相等
- 算术运算符是有优先级的
- 先乘除,后加减,有小括号先算小括号里面的
- 如果数学运算符两侧有一侧不是数字类型,js会发生隐式类型转换,自动将不是数字类型转为数字类型【Number()方法转换】。注意,但是有一个特例i,+加号 两侧有字符串,不会转为数字类型 会变成字符串拼接【+没有字符串也会有隐式转换】
- 在字符串前面多加一个符号也可以实现隐式转换,即字符型转换为数字型
- 例如:var a=’1’; console.log(1 + +a);【a就会转换为数字型参与运算】
- 在字符串前面多加一个符号也可以实现隐式转换,即字符型转换为数字型
- 无论哪种运算,只要出现了undefined参与运算,结果都是NaN。
- 纯数字字符串,false,true,null,都能进行隐式转换
- 加号比较特殊,面对纯数字字符串没有隐式转换。
- 浮点数 算术运算里面会有问题
- 怎么判断一个数能够被整除呢
- 它的余数是0,就说明这个数能被整除,这就是% 取余运算符的主要用途
- 表达式和返回值
- 表达式:是由数字、运算符、变量等以能求得数值的有意义排列方法所得的组合
- 简单理解:是由数字、运算符、变量等组成的式子
- 表达式最终都会有一个结果,返回给我们,我们称为返回值
- 把右边表达式计算完毕,把返回值赋给左边
- 递增和递减运算符
- 如果需要反复给数字变量添加或减去1,可以使用递增(++)和递减(--)运算符来完成。
- JavaScript中,递增(++)和递减(--)既可以放在变量前面时,也可以放在变量后面。放在变量前面时,我们可以称为前置递增(递减)运算符,放在变量后面时,我们可以称为后置递增(递减)运算符。
- 递增和递减运算符必须和变量搭配使用。
- 前置递增运算符
- ++num前置递增,就是自加1,类似于num = num + 1,但是写起来更简单。
- 变量先自加1,然后自加1的结果参与运算来返回值
- 后置递增运算符
- num++后置递增,就是自加1,类似于num = num + 1,但是写起来更简单
- 变量先返回原值去参与运算,后自加1的结果保存到变量中
- 小结
- 前置递增和后置递增如果单独使用,效果是一样的
- 前置递增和后置递增运算符可以简化代码的编写,让变量的值+1比以前写法更简单。
- 前置:先自加,后运算
- 后置:先原值运算,后自加
- 开发时,大多使用后置递增/递减,并且代码独占一行。
- 比较运算符(关系运算符)
- 概念:比较运算符(关系运算符)是两个数据进行比较时所使用的运算符,比较运算后,会返回一个布尔值(true/false)作为比较运算的结果
运算符名称 | 说明 | 案例 | 结果 |
< | 小于号 | 1 < 2 | true |
> | 大于号 | 1 > 2 | false |
>= | 大于或者等于 | 2 >= 2 | true |
<= | 小于或者等于 | 3 <= 2 | false |
== | 判等号(会转型,会把字符型转换为数字型再比较是否相等) | 37 == 37 | true |
!= | 不等号 | 37 != 37 | false |
=== | 全等 要求值和数据类型都一致 | 37 === 37 | true |
!== | 不全等 | 37 !== 37 | false |
- 关系运算符中同时出现字符串和数字时,并且该字符串可以转换为数字时,会将字符串转换为数字类型(隐式转换),然后进行比较
- 关系运算符中两个字符串比较大小时,从左往右依次比较字母大小【对应的ASCLL码大小】,字母较大的大
- 比较运算符中,出现null,null转换为数字0,但和0做比较时,答案都为false
- 比较运算符中,出现NaN,和任何数作比较答案都为false
- =小结
符号 | 作用 | 用法 |
= | 赋值 | 把右边给左边 |
== | 判断 | 判断两边值是否相等(存在隐式转换:将字符型转换为数字型后再做比较) |
=== | 全等 | 判断两边的值和数据类型是否完全相同 |
- 逻辑运算符
- 概念:逻辑运算符是用来进行布尔值运算的运算符 ,其返回值也是布尔值,后面开发中经常用于多个条件的判断
逻辑运算符 | 说明 | 案例 |
& | 逻辑与,简称”与”,and | true & false |
| | 逻辑或,简称“或”,or | true | false |
! | 逻辑非,简称“非”,not | !true |
- 逻辑与 & 两侧都为true 结果才是true 只要有一侧为false 结果为false
- 逻辑或 | 两侧都为false结果才是false 只要有一侧为true 结果为true
- 短路运算(逻辑中断)
- 短语运算的原理:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值;
- 表达式1 && 表达式2
- 表达式1的值为假 不再执行表达式2 返回表达式1的值
- 表达式1 的值为真 返回表达式2的值 两个表达式都会执行
- 多个表达式进行与运算时,从第一个表达式开始向右找是否有为假的表达式,如果没有返回最后一个表达式的值,如果有为假的表达式,就返回第一个为假的表达式值(多个表达式进行“与“运算时,返回第一个值为假的表达式的值,如果没有就返回最后一个表达式值)
- 表达式1 || 表达式2
- 表达式1的值为真 不再执行表达式2 返回表达式1的值
- 表达式1的值为假 返回表达式2的值 两个表达式都会执行
- 多个表达式进行“或”运算时,返回第一个值为真的表达式的值,如果没有,则返回最后一个值为假的表达式值
- 短路与和短路或同时存在时:
- 短路与在前面
- 短路与执行完后再执行短路或
- 短路或在前面
- 只执行短路或
- 短路与在前面
- 逻辑与 和 短路与的区别:
- 逻辑与&:无论左边是否正确,&两边的表达式都会执行到底
- 短路与&&:只要左边表达式确认错误,右侧的表达式则不会执行
- 利用短路算法处理默认值:
- 利用短路或处理默认值:
- var res=data || {}
- 变量data里面有值,则用变量res保存data里面的值。变量data里面没有值,则变量res返回空对象,这样控制台就不会报错
- var res=data || {}
- 利用短路或处理默认值:
- 赋值运算符
- 概念:用来把数据赋值给变量的运算符。
- 先执行赋值运算符右边的代码,再把得到的值给我们右边的变量保存起来
赋值运算符 | 说明 | 案例 |
= | 直接赋值 | var usrName = “我是值”; |
+= | 加一个数后再赋值 | var age = 10; age += 5; //age=15 |
-= | 减一个数后再赋值 | var age = 10; age -= 5; //age=5 |
*= | 乘后再赋值 | var age = 10; age *= 5; //age=50 |
/= | 除后再赋值 | var age = 10; age /= 5; //age=2 |
%= | 取模后再赋值 | var age = 10; age %= 5; //age=0 |
- 运算符优先级
优先级 | 运算符 | 顺序 |
1 | 小括号 | () |
2 | 一元运算符 | ++ -- ! |
3 | 算术运算符 | 先*/%后+- |
4 | 关系运算符 | > >= < <= |
5 | 相等运算符 | == != === !== |
6 | 逻辑运算符 | 先&& 后 || |
7 | 赋值运算符 | = |
8 | 逗号运算符 | , |
- 一元运算符里面的逻辑非优先级很高
- 逻辑与比逻辑或优先级高
- JavaScript流程控制
- 流程控制
- 顺序流程控制
- 分支流程控制if语句
- 三元表达式
- 分支流程控制switch语句
- 流程控制
- 在一个程序执行的过程中,各条代码的执行顺序对程序的结果是有直接影响的。很多时候我们要通过控制代码的执行顺序来实现我们要完成的功能
- 简单理解:流程控制就是来控制我们的代码按照什么结构顺序来执行
- 流程控制主要有三种结构,分别是顺序结构、分支结构和循环结构,这三种结构代表三种代码执行的顺序。
- 顺序流程控制
- 顺序结构是程序中最简单、最基本的流程控制,它没有特定的语法结构,程序会按照代码的先后顺序,依次执行,程序中大多数的代码都是这样执行的
- 分支流程控制
- 分支结构:由上到下执行代码的过程中,根据不同的条件,执行不同的路径代码(执行代码多选一的过程),从而得到不同的结果
- JS语言提供了两种分支结构语句
- if语句
- switch语句
- if语句
- 语法结构:
//条件成立执行代码,否则什么也不做
if (条件表达式) {
//条件成立执行的代码语句;
}
- 当执行语句只有一条语句时,{}可以不要
- 执行思路
- 如果条件表达式结果为真,执行条件表达式后面大括号{}内的执行语句,如果条件表达式结果为假,不执行大括号里面的语句,而是执行if语句后面的代码
- 条件表达式为假:
- 条件不成立,结果为false
- NaN
- 空‘’
- undefined
- null
- 0
- 拓展用法:
- 条件表达式 && 调用函数
- 如果条件表达式为真,执行后面的调用函数。【短路算法比if语句更好】
- 能不用for循环和if语句的尽量不用。
- for循环和if相对于三目运算和短路算法性能消耗更大
- 条件表达式 && 调用函数
- if else语句(双分支语句)
- 语法结构:
//条件成立 执行if里面的代码,否则执行else里面的代码
if(条件表达式) {
//条件成立执行的代码
} else {
//条件不成立执行的代码
}
- if里面的代码和else里面的代码,最终只能有一个语句执行
- else后面直接跟大括号{}
- if else if语句(多分支语句)
- 利用多个条件来选择不同的语句执行 得到不同的结果 多选一的过程
- 语法结构:
/*
哪个条件表达式最先成立 就执行哪个条件表达式后里面的代码,否则执行else里面的代码
*/
if (条件表达式1) {
//条件表达式1为真的执行代码
} else if (条件表达式2) {
//条件表达2为真的执行代码
} else if (条件表达式3) {
//条件表达式3为真的执行代码
} else {
//条件都不成立的执行代码
}
- 多分支语句还是多选一,最终只有一个语句代码块执行
- 执行思路:
- 如果条件表达式1 满足就执行 语句1 执行完毕后,退出整个if 分支语句
- 如果条件表达式1 不满足就判断条件表达式2 满足就执行 语句2 执行完毕后,退出整个if 分支语句
- …
- 如果条件表达式都不满足,就执行else里面的语句
- 注意点:
- else if中间有个空格
- if是主流的条件分支语句:
- 其它条件分支语句能实现的 if一定能实现,if能实现的,其它条件分支语句并不一定能实现。
- 三元表达式(三目运算符)
- 有三元运算符组成的式子,我们称为三元表达式
- 语法结构:
- 条件表达 ? 表达式1 : 表达式2;
- 执行思路:
- 如果条件表达式结果为真,返回表达式1的值
- 如果条件表达式结果为假,返回表达式2的值
- 简化if else双分支结构,做分支选择
- 优先级低于算术运算符【问号前面的算术运算会先执行】,高于赋值运算符
- 分支流程控制switch语句
- switch语句也是多分支语句,它用于基于不同的条件来执行不同的代码。当要针对变量设置一系列的特定值的选项时,就可以使用switch。
- switch还可以当开关,因为表达式的结果只能是true和false
- 此时case后面的value值只能是true和false
- 语法结构:
switch (表达式) {
case value1:
执行语句1;
break;
case value2:
执行语句2;
break;
...
default:
执行最后的语句;
break;
}
- switch后面的表达式值和case后面的value值去匹配(全等匹配,必须是值和数据类型都一样),匹配成功就执行该value后面的执行语句,遇到break退出整个switch语句,继续执行后面的代码
- 每个case后面的执行语句后面要写上break,否则会出现case穿透,即继续执行下一个case后面的代码,直到遇到break才退出整个switch语句
- switch实现匹配值输出相同结果时可以利用case穿透。【即前面相同输出结果的case 匹配值,输出结果写在最后一个具有相同输出结果的case上然后用break退出switch分支语句】【可以简化代码】
- switch()括号里面的表达式可以为布尔值true或false,case后面的value值也可以为表达式,所以switch也可以用来做条件范围比较,但一般是特定值匹配
- 案例:
<script>
var score = 83
switch (true) {
case score > 90:
console.log('优秀')
break;
case score > 80:
console.log('良好')
break;
default:
console.log('要努力哦')
}
</script>
- if else if语句和switch语句的区别
- 一般情况下,它们两个语句可以相互替换
- switch…case语句通常处理case为比较确定值的情况,而if…else…语句更加灵活,常用于范围判断(大于、等于某个范围)
- switch语句进行条件判断后直接执行到程序的条件语句,效率更高。而if…else语句有几种条件,就得判断多少次
- 当分支比较少时,if…else语句的执行效率比switch语句高。
- 当分支比较多时,switch语句的执行效率比较高,而且结构更清晰。
- 循环
- 循环的目的:反复的执行某段代码
- 在实际问题中,有很多具有规律性的重复操作,因此在程序中要完成这类操作就需要重复执行某些语句
- JS中的循环:
- Js中,主要有三种类型的循环语句:
- for循环
- while循环
- do…while循环
- Js中,主要有三种类型的循环语句:
- 循环的目的:反复的执行某段代码
- for循环
- 在程序中,一组被重复执行的语句被称之为循环体,能否继续重复执行,取决于循环的终止条件。由循环体及循环的终止条件组成的语句,被称之为循环语句
- 语法结构:
//for循环主要用于把某些代码循环若干次,通常跟计数有关系,语法结构如下:
for (初始化变量; 条件表达式; 操作表达式) {
//循环体
}
- 初始化变量 就是用var声明的一个普通变量,通常用于作为计数器使用
- 条件表达式 就是用来决定每一次循环是否继续执行
- 操作表达式 是每次循环最后执行的代码 经常用于我们计数器变量跟新(递增或递减)
- for循环执行的次数算法
- 变量最大值为imax,变量最小值为imin,操作数为a,循环次数为n
- n = 1 + (imax-imin)/a
- 变量最大值为imax,变量最小值为imin,操作数为a,循环次数为n
- 执行思路:
- 先执行初始化变量(只执行一次)
- 然后执行条件表达式
- 不满足就退出循环
- 满足条件表达式再执行循环体
- 然后执行操作表达式
- 再执行条件表达式(不断循环上面的操作)
- for循环的lable
- 语法:
- 循环名: for (初始化变量; 条件表达式; 操作表达式) {
- 语法:
//循环体
}
- break 循环名;用来指定跳出的循环
- 如果只有break则是跳出当前循环。
- 断点调试
- 断点调试是指自己在程序的某一行设置一个断点,调试时,程序运行到这一行就会停止,然后你可以一步一步往下调试,调试过程中可以看各个变量当前的值,出错的话,调试到出错的代码行即显示错误,停下。
- 断点调试可以帮助我们观察程序的运行过程
- 浏览器按F12-->点击“Sources”-->找到需要调试的文件(双击文件即可出现代码)-->在程序的某一行设置断点(鼠标单击那一行前面的行号)
- 点击浏览器左上角的刷新按钮
- 点击箭头或按F11键可以一步一步向下执行(浅蓝色背景代码为执行到的代码)
- 鼠标放到变量上,可以知道变量当前值
- Watch:监视,通过watch可以监视变量的值的变化,非常的常用。(点击watch旁边的加号,输入要监视的变量,即可观察变量值的变化)
- F11:程序单步执行,让程序一行一行的执行,这个时候,观察watch中变量的值的变化。
- 代码调试的能力非常重要,只有学会了代码调试,才能学会自己解决bug的能力,初学者不要觉得调试代码麻烦就不去调试,知识点花点功夫肯定学得会,但是代码调试这个东西,自己不去练,永远都学不会。
- 取消断点:在设置了断点的行的行号上点击一下即可取消断点
- 断点调试可以帮助我们观察程序的运行过程
- for循环执行相同代码,for循环也可以执行不同的代码:因为我们有计数器变量i的存在,在循环体中可以有变量i的存在,每次循环变量i的值都会变化,所以可以执行不同的代码
- 双重for循环
- 很多情况下,单层for循环并不能满足我们的需求,比如我们要打印一个5行5列的图形、打印一个倒三角形等,此时就可以通过循环嵌套来实现。
- 循环嵌套是指在一个循环语句中再定义一个循环语句的语法结构,例如在for循环语句中,可以再嵌套一个for循环,这样的for循环语句我们称之为双重for循环。
- 语法结构:
for(外层的初始化变量;外层的条件表达式;外层的操作表达式){
for(里层的初始化变量;里层的条件表达式;里层的操作表达式){
//执行语句
}
}
- 我们可以把里面的循环看作是外层循环的语句
- 外层循环一次,里面的循环执行全部
- 外层for循环里面的变量和内层for循环里面的变量不能一样,否则会影响循环的次数(内层循环影响外层循环循环的次数,因为改变了变量的值)
- 打印三角形字符案例:
- 字符串拼接写在里层for循环里面
- str=str+’\n’写在双重for循环中间
- 输出换行效果
- console.log(变量)
- 与它同级的for循环内的第一层变量发生变化时会出现换行效果
- 与它同级的for循环内的第一层变量内拼接换行符
- console.log(变量)
- while循环
- while语句可以在条件表达式为真的前提下,循环执行指定的一段代码,直到表达式不为真时结束循环。
- 语法结构:
while (条件表达式) {
//循环体代码
}
- 执行思路:
- 先执行条件表达式,如果结果为true,则执行循环体代码;如果为false,则退出循环,执行后面代码
- 里面应该也有计数器 初始化变量
- 里面应该也有操作表达式,完成计数器的更新 防止死循环
- 执行思路:
- do while循环
- do…while语句其实是while语句的一个变体,该循环会先执行一次代码块,然后对条件表达式进行判断,如果条件为真,就会重复执行循环体,否则退出循环。
- 语法结构:
do {
//循环体
} while (条件表达式)
- 执行思路
- 跟while不同的地方在于do while
- 先执行一次循环体
- 再判断条件表达式, 如果条件表达式结果为真,则继续执行循环体,否则退出循环,继续执行后面的代码
- do while循环语句至少执行一次循环体代码
- do while比while写起来更简单
- 执行思路
- 循环小结:
- JS中循环有for、while、do while
- 如果是用来计次数,跟数字相关的,三者使用基本相同,但是我们更喜欢for
- while和do while可以做更复杂的判断条件,比for循环更灵活
- while和do while执行顺序不一样,while先判断后执行,do while先执行一次,再判断
- do while至少执行一次循环体,while可能一次也不执行
- 实际工作中,我们更常用for循环语句,它写法更简洁直观,所以这个要重点学习
- continue
- continue关键字用于立即跳出本次循环,继续下一次循环(本次循环体中continue之后的代码就会少执行一次)
- continue 循环名;指定跳出的本次循环,继续下一次指定循环
- break
- break关键字用于立即跳出整个循环(循环结束【当前循环】)
- break 循环名;指定跳出的循环
- 标识符命名规范:
- 变量、函数的命名必须要有意义(见名知意)
- 变量的名称一般用名词
- 函数的名称一般用动词
- 操作符规范
- 操作符的左右两侧各保留一个空格
- 单行注释规范
- // 单行注释前面注意有个空格
- 其它规范
- for循环中,左边的大括号要和for在一行上,右边的大括号要和for的第一个字母在一列上
- 关键字与括号,括号与括号之间要有一个空格
- 数组
- 能够知道为什么要有数组
- 能够创建数组
- 能够获取数组中的元素
- 能够对数组进行遍历
- 能够给数组新增一个元素
- 能够独立完成冒泡排序的案例
- 为什么要有数组
- 之前学习的变量,只能存储一个值,如果我们想要存储班级中所有学生的姓名,那么该如何存储呢?
- 我们使用数组(Array)。数组可以把一组相关的数组一起存放,并提供方便的访问(获取)方式。
- 之前学习的变量,只能存储一个值,如果我们想要存储班级中所有学生的姓名,那么该如何存储呢?
- 数组的概念:
- 数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的优雅方式。
- 数组也是一个对象,可以添加属性【数组名.属性名=属性值】
- 数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的优雅方式。
- 创建数组
- 创建数组的方式
- JS中创建数组有两种方式:
- 利用new创建数组
- 利用数组字面量创建数组
- JS中创建数组有两种方式:
- 创建数组的方式
- 利用new关键字创建数组
- var 数组名 = new Array();
- 如果Array不传参数,默认创建一个空数组
- 如果Array传递的参数不为数字,那么每一个参数都是数组的一项数据
- 如果Array传递的参数为数字:
- 两个以上的数字参数:那么每一个参数都为数组的一项数据
- 只有一个数字参数:这个参数表示我们创建的数组有多少项[length属性值为这个数字参数],每一项都是空值【empty】
- var 数组名 = new Array();
- 利用数组字面量创建数组
- 使用数组字面量方式创建空数组
- var 数组名 = []
- 使用数组字面量方式创建带初始值的数组
- var 数组名 = ['元素1值','元素2值',...]
- 数组里面的数据一定用逗号分隔
- 数组里面的数据,我们称为数组元素
- 一眼就可以看出各个元素是什么数据类型
- 数组最后一个分号不要加,不然IE8及以下会多一个undefined【例子:[1,2,]】
- 加尾逗号的好处:方便移动数据
- var 数组名 = ['元素1值','元素2值',...]
- 数组字面量是方括号[]
- 声明数组并赋值称为数组的初始化
- 字面量方式是最多使用的方式
- 使用数组字面量方式创建空数组
- 数组元素的类型
- 数组中可以存放任意类型的数据,例如字符串,数字,布尔值,新数组等
- 数组的作用:把一组有序数据的集合存放在单个变量下
- 什么是数组元素:存放在数组里面的数据
- 数组的索引
- 索引(下标):用来访问数组元素的序号(数组下标从0开始)
- 获取数组元素
- 数组可以通过索引来访问、设置、修改对应的数组元素,我们可以通过'数组名[索引号]'的形式来获取数组中的元素
- 这里的访问就是获取得到的意思
- 数组的长度【数组的属性】
- 使用“数组名.length”或“数组名[‘length’]”
- 数组名.length动态监测数组元素的个数
- 数组的长度是可修改的:因为对象的属性是可修改的,所以数组的长度是可修改的。
- 修改值大于原值,新值多的项会用empty占位符占据
- 修改值小于原值:原值多的项会被删除
- 一般不随意修改length属性:
- 改大了:多几个空项没意义
- 改小了:导致数据丢失,得不偿失。
- 数组的特点:
- length属性表示数组的长度
- 数组的索引从0开始
- 遍历数组
- 规律:从数组中取每个元素时,代码时重复的,有所不一样的是索引值在递增
- 所以遍历数组就用到循环
- 语法:
- 规律:从数组中取每个元素时,代码时重复的,有所不一样的是索引值在递增
for (var i = 0; i <= 数组名.length - 1; i++) {
console.log(数组名[i])
}
- 注意:因为我们的数组索引号从0开始,所以i必须从0开始
- 输出的时候arr[i] i 计数器当索引号来使用
- 遍历:就是把数组中的每个元素从头到尾都访问一次
- 循环对象的for..in可以用,一般用得少,因为数组有数组得高级循环方式,诸如:forEach,map,filter
- 数组中新增元素
- 可以通过修改length长度以及索引号增加数组元素
- 通过修改length长度新增数组元素
- 可以通过修改length长度来实现数组扩容的目的
- length属性是可读的
- 语法:数组名[数组名.length]=新增数组元素值;
- 声明变量未给值,默认就是undefined
- 修改索引号新增数组元素
- arr[新增索引号]=数据值
- 新增索引号如果大于原数组中最大的索引号则为新增数据,而且为最后一个数据,原数组最大索引号到新增索引号之间的索引号里面存的数据都为empty
- 如果新增索引号小于原数组中最大的索引号则为修改数组中的数据
- 不要给数组名直接赋值,否则里面的数组元素都没有了
- arr[新增索引号]=数据值
- 关于应用类型:
- 基本数据类型操作的就是数据的值,比较相不相等,是比较值相不相等
- 引用数据类型操作的是内存地址,所以比较相不相等,是比较内存地址一样不一样
- 所以当将一个引用数据类型a赋值给一个变量b时,实际上是将这个引用数据类型a的内存地址给该变量b,该变量b修改数据会改变引用数据类型a的值。
- [1,2,3] == [1,2,3] 结果为false【值相等,但内存地址不一样】
- 筛选数组
- 声明一个新的空数组newArr用于存放筛选出来的数据
- 遍历原来的旧数组,筛选满足条件的元素
- 依次追加给新数组newArr(即赋值给newArr[newArr.length])
- 法一:
var j = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] > 10) {
newArr[j] = arr[i];
j++;
}
}
- 法二:
var j = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] > 10) {
newArr[newArr.length] = arr[i];
}
}
- 翻转数组
for (var i = arr.length - 1; i >= 0; i--) {
newArr[newArr.length] = arr[i]
}
- 数组排序
- 冒泡排序:
- 冒泡排序是一种算法,把一系列的数据按照一定的顺序进行排列显示(从小到大或从大到小)
- 冒泡排序是一种简单的排序算法,它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
- 冒泡排序案例:
- n个数,从小到大排列:
- 案例分析:
- n个数需要比较n-1趟,每一趟将最大的那个数放在最后(n-1次循环,做外层循环)
- 每趟比较 n-趟数次(n-趟数次循环,做内层循环)
- 代码实现:
- 案例分析:
- n个数,从小到大排列:
- 冒泡排序:
for (var i = 1; i <= arr.length - 1; i++) {
for (var j = 0; j <= arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
var temp = 0,
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
- 这里arr.length相当于n,i相当于第几趟,然后根据循环次数公式计算。(n = 1 + (imax-imin)/a)
- 函数的概念
- 在JS里面,可能会定义非常多的相同代码或者功能相似的代码,这些代码可能需要大量重复使用。虽然for循环语句也能实现一些简单的重复操作,但是比较具有局限性,此时我们就可以使用JS中的函数。
- 函数:就是封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用。
- 函数的使用:
- 函数的使用分为两步:
- 声明函数
- 调用函数
- 函数的使用分为两步:
- 声明函数语法:
function 函数名(){
//函数体
}
- function声明函数的关键字,必须小写
- 由于函数一般是为了实现某个功能才定义的,所以通常我们将函数名命名为动词,比如getsum
- 函数不调用,自己不执行
- 调用函数:
- 函数名();
- 调用函数的时候千万不要忘记加小括号
- 函数不调用,自己不执行。
- 声明函数本身并不会执行代码,只有调用函数时才会执行函数体代码。
- 函数的调用可以作为[另一个]函数的实参
- 函数名();
- 函数的封装:
- 函数的封装是把一个或者多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口
- 简单理解:封装类似于将电脑配件整合组装到机箱中(类似快递打包)
- 函数内部一般不写输出语句,而是return一个返回值结果。
- 函数可以利用函数的参数重复执行不同的代码
- 语法:
- 声明函数:
- 语法:
function 函数名(形参1,形参2,...){
//函数体
}
- 调用函数:
- 函数名(实参1,实参2,...);
- 调用函数:
- 在声明函数的小括号里面是形参(形式上的参数:形参是接收实参的,类似于一个变量)【形参相当于隐式的在函数体内声明一个let 形参名。调用的时候,要把这个变量的真实的值,一起写在括号里,这样随着函数的调用,这个值也传给了形参】
- 定义函数时的参数是形参,调用函数时传递的是实参
- 在函数调用的小括号里面是实参(实际的参数)
- 形参和实参的执行过程:
- 先执行到调用函数
- 通过调用函数的函数名找到声明的函数位置
- 再将调用函数名里面的实参传给声明函数里面的形参
- 函数的参数可以有也可以没有,个数不限的
- 形参和实参
- 在声明函数时,可以在函数名称后面的小括号中添加一些参数,这些参数被称为形参,而在调用该函数时,同样也需要传递相应的参数,这些参数被称为实参。
参数 | 说明 |
形参 | 形式上的参数 函数定义的时候 传递的参数 当前并不知道是什么 |
实参 | 实际上的参数 函数调用的时候传递的参数 实参是传递给形参的 |
- 多个参数之间用逗号隔开
- 形参可以看作不用声明的变量
- 形参个数和实参个数不匹配时:
- 如果实参的个数和形参的个数一致,则正常输出
- 如果实参的个数多于形参的个数 实参会依次去匹配形参,多的实参不起作用(会取到形参的个数)
- 如果实参的个数小于形参的个数 多余的形参定义为undefined 最终的结果就是NaN
- 建议:我们尽量让实参的个数和形参相匹配
参数个数 | 说明 |
实参个数等于形参个数 | 输出正确结果 |
实参个数多于形参个数 | 实参只取到形参的个数,多余的实参无效 |
实参个数小于形参个数 | 多的形参定义为undefined,当多的形参参与运算时结果为NaN |
- 函数的返回值
- return语句
- 有的时候,我们希望函数将值返回给调用者,此时通过使用return语句就可以实现。
- 语法:
- return语句
function 函数名(形参1,形参2,...){
//函数体
return 结果;
}
- 我们函数只是实现某种功能,最终的结果需要返回给函数的调用者:函数名() 通过return实现
- 只要函数遇到return 就把后面的结果 返回给函数的调用者
- 相当于:函数名()=return 后面的结果
- 实际开发中,我们经常用一个变量来接收函数返回的结果 使用更简单
- return只能返回一个值,如果用逗号隔开多个值,以最后一个值为准
- 要想返回多个值,return后面可以用数组来存储数据,然后遍历数组即可
- 函数如果有return 则返回的是return 后面的值,如果函数没有return 则返回undefined
- return终止函数
- return后面的函数体不再执行,直接跳出当前函数,返回结果
- 节流:函数体内写if(条件1) return 值一
- 只要满足条件1,该语句后面的代码就不会执行
- 节流:函数体内写if(条件1) return 值一
- return后面的函数体不再执行,直接跳出当前函数,返回结果
- 一个函数内只会执行一次return,但是可以写多个return
- 函数都是有返回值的
- 如果有return则返回return后面的值
- 如果没有return则返回undefined
- break,continue,return的区别
- break:结束当前的循环体(如for、while)
- continue:跳出本次循环,继续执行下一次循环(如for、while)
- return:不仅可用退出循环,还能够返回return语句中的值,同时还可以结束当前的函数体内的代码(return只能放在函数体里面)
- 看透函数:
function 函数名(参数1,参数2,...){ //输入参数
//函数体 //内部处理
return 返回值; //返回结果
}
- arguments的使用
- 当我们不确定有多少个参数传递的时候,可以用arguments来获取。在JavaScript中,arguments实际上它是当前函数的一个内置对象。所有函数都内置一个arguments对象,arguments对象中存储了传递的所有实参。
- arguments展示形式是一个伪数组,因此可以进行遍历,伪数组具有以下特点:
- 具有length属性
- 按索引方式存储数据
- 不具有数组的push,pop等方法
- 只有函数才有arguments内置对象
- 有了arguments可以不用写形参
- 函数可以调用另外一个函数
- 因为每个函数都是独立的代码块,用于完成特殊任务,因此经常会用到函数相互调用的情况。
- 案例:
function fn1() {
console.log('当前函数')
fn2();
}
fn1();
function fn2() {
console.log('被另一个函数调用的函数')
}
- 函数的两种声明方式:
- 利用函数关键字自定义函数(命名函数)
- 函数表达式声明函数
- 利用函数关键字自定义函数(命名函数)
- 语法:
function 函数名() {
//函数体
}
函数名(); //调用函数
- 函数表达式声明函数(匿名函数)
- 语法:
var 变量名 = function () {
//函数体
}
变量名(); //调用函数
- 函数表达式声明方式跟声明变量差不多,只不过变量里面存的是值,而 函数表达式里面存的是函数
- 函数表达式才可以加括号调用
- 函数可以帮我们简化代码,再复杂的业务逻辑 都是由一个一个小小的功能(函数)拼接而成的。
- 调用栈:
- 调用一个a函数,这个函数里面会继续调用另一个b函数,b函数又会继续调用另一个c函数…
- 则调用栈为a-->b-->c-->…
- 调用位置为倒数第二个调用栈。
- 爆栈:调用栈数目太多【函数调用出现死循环】
- 调用一个a函数,这个函数里面会继续调用另一个b函数,b函数又会继续调用另一个c函数…
- 作用域
- 作用域概述:
- 通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域,作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突
- JavaScript作用域:就是代码名字(变量)在某个范围内起作用和效果,目的是为了提高程序的可靠性 更重要的是减少命名冲突
- 作用域概述:
- Js的作用域:
- 全局作用域:整个<script>标签或一个单独的js文件
- 局部作用域(函数作用域):在函数内部就是局部作用域,这个代码的名字只在函数内部起效果和作用。
- 一个函数定义不执行,函数内部所有的代码将毫无意义。
- 变量作用域分类
- JavaScript中,根据作用域的不同,变量可以分为两种:
- 全局变量:在全局作用域下声明的变量叫做全局变量,在全局下都可以使用
- 在全局作用域下声明的变量是全局变量
- 在函数内部 没有声明直接赋值的变量也属于全局变量(不建议使用)
- 全局变量在代码的任何位置都可以使用
- 局部变量:在局部作用域下声明的变量(在函数内部的变量就是 局部变量)叫做局部变量
- 局部变量在函数外部不能使用,否则会报错
- 在局部作用域下声明的变量是局部变量(函数内部声明的变量)
- 函数的形参也可以看作局部变量
- 局部变量只能在该函数内部使用
- 全局变量:在全局作用域下声明的变量叫做全局变量,在全局下都可以使用
- JavaScript中,根据作用域的不同,变量可以分为两种:
- 从执行效率来看全局变量和局部变量
- 全局变量只有浏览器关闭的时候才会销毁,比较占内存资源
- 局部变量 当我们程序执行完毕就会销毁,比较节约内存资源
- 全局变量和局部变量的区别
- 全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
- 局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存
- Js中没有块级作用域
- Js中没有块级作用域 js的作用域: 全局作用域 局部作用域 现阶段我们js没有块级作用域
- 我们js也是在es6的时候新增的块级作用域
- Js中没有块级作用域 js的作用域: 全局作用域 局部作用域 现阶段我们js没有块级作用域
- 作用域链:
- 只要是代码,就至少有一个作用域
- 写在函数内部的局部作用域
- 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域
- 根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链(内部函数访问外部函数的变量,采取的是链式查找的方式来决定取哪个值 这种结构我们称为作用域链)【站在目标出发,一层一层往外查找】
- Js中:
- 词法作用域:只关心函数声明,函数定义在哪个作用域中,这个函数的父作用域就是谁
- 其他语言中:
- 动态作用域:不关心函数定义,只关心函数执行,函数在哪个作用域中执行,这个函数的父作用域就是谁。
- 预解析
- JavaScript代码是由浏览器中的JavaScript解析器来执行的。JavaScript解析器在运行JavaScript代码的时候分为两步:
- 预解析
- 代码执行
- JavaScript代码是由浏览器中的JavaScript解析器来执行的。JavaScript解析器在运行JavaScript代码的时候分为两步:
- Js引擎运行js分为两步:预解析 代码执行
- 预解析:js引擎会把js里面所有的var 还有function提升到当前作用域的最前面
- 代码执行:按照代码书写顺序从上往下执行
- 注意:函数表达式 调用必须写在函数表达式的下面
- 预解析分为变量预解析(变量提升)和函数预解析(函数提升)
- 变量预解析:
- 就是把所有的变量声明提升到当前的作用域最前面 不提升赋值操作
- 函数预解析:
- 把所有的函数声明提升到当前作用域的最前面 不调用函数
- 变量预解析:
- 预编译(预解析)三部曲:
- 创建全局作用域(所谓的作用域 说白了 就是创建一个仓库,这个仓库就是一个对象)
- 找到变量声明,变量值作为全局作用域Go【window】的属性,默认值为undefined
- 找到函数声明,函数名作为作用域Go【window】的属性,函数体作为属性值
- 执行代码:
- 解析一行执行一行
- Window的属性可以直接使用
- 函数作用域四部曲:
- 创建活跃对象 AO【函数作用域或叫局部作用域】【Active Object】
- 每个作用域中都有this属性,属性值一定是对象,但具体是哪个对象 不一定
- 查询形参和变量,默认值为undefined
- 实参赋值给形参
- 函数声明
- 创建活跃对象 AO【函数作用域或叫局部作用域】【Active Object】
- 垃圾回收机制:
- 我们每一次声明的变量或者函数都会在内存里开辟一块空间存储数据 【当内存满了,就会出现内存溢出】
- JavaScript对象
- 对象:
- 什么是对象:
- 现实生活中:万物皆对象,对象是一个具体的事物,看得见摸得着的实物。例如,一本书、一辆汽车、一个人可以是“对象”,一个数据库、一张网页、一个与远程服务器的连接也可以是“对象”。
- JavaScript什么是对象
- 在JavaScript中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。【属性名也叫键名,属性值也叫做键值】
- 对象是由属性和方法组成的。
- 属性:事物的特征,在对象中用属性来表示(常用名词)
- 什么是对象:
- 对象:
属性由属性名和属性值构成【属性名和属性值用冒号分隔】
- 方法:事物的行为,在对象中用方法来表示(常用动词)
- 为什么需要对象
- 保存一个值时,可以使用变量,保存多个值(一组值)时,可以使用数组,如果保存一个人的完整信息呢?
- Js中的对象表达结构更清晰,更强大。
- 在语句的上下文出现的大括号是 代码块。表达式上下文出现的是对象。
- 创建对象的三种方式
- 在JavaScript中,现阶段我们可以采用三种方式创建对象(object)
- 利用字面量创建对象
- 利用new Object创建对象
- 利用构造函数创建对象
- 在JavaScript中,现阶段我们可以采用三种方式创建对象(object)
- 创建对象常见的几种模式:
- 工厂模式:
- 工厂模式是软件工程邻域一种广为人知的设计模式,这种模式抽象了创建 具体对象的过程。
- 工厂模式虽然解决了创建多个相似对象的问题,但没有解决对象识别的问题(但是工厂模式却无从识别对象的类型,因为全部都是Object,不像Date、Array等,下例中,得到的都是o对象,对象的类型都是Object,因此出现了构造函数模式)
- 例子:
- 工厂模式:
function people(uname, age) {
var o = new Object();
o.name = uname;
o.age = age;
return o
}
console.log(people('xiaomi', 19))
- 构造函数模式:
- 利用构造函数创建对象
- 原型模式:
- 构造函数内为空,给构造函数的原型上添加属性名和属性值
- 语法1:
- function 构造函数名(){}
- 构造函数模式:
构造函数名.prototype.属性1名=属性1值
构造函数名.prototype.属性2名=属性2值
构造函数名.prototype.属性3名=属性3值
…
- 属性值为函数时,属性名又叫方法名。
- 语法2:
- function 构造函数名(){}
构造函数名.prototype={
constructor: 构造函数名,
属性1名: 属性1值,
属性2名: 属性2值
…
}
- 原型模式的好处:所有对象实例共享它的属性和方法(即所谓的共有属性)
- 缺点:省略了为构造函数传递初始值参数,导致所有的实例对象都是相同的属性和方法。【没法处理私有的属性和方法】
- 混合模式:【构造函数模式+原型模式】
- 总结:模式 就是通过构造函数,原型,以及其他的方式来组合不同代码,然后创建对象的时候,对象的属性,方法会在不同地方,以此来达到不同的目的。
- 利用字面量创建对象
- 对象字面量:就是花括号{}里面包含了表达这个具体事物(对象)的属性和方法
- 里面的属性或则方法我们采取键值对的形式 键:属性名;值:属性值
- 多个属性或则方法中间用逗号隔开的
- 方法冒号后面跟的是一个匿名函数
- 利用对象字面量创建空对象:
- var obj = {}
- 利用对象字面量创建对象语法:
- 语法:
var 对象名 = {
属性名1: "属性值",
属性名2: 属性值2,
...,
方法名1: function () {
//函数体
},
方法名2: function () {
//函数体
}
}
- 对象的属性名是字符串类型,如果不是字符串类型,那么js会帮你转为字符串类型【数字会自动转换为字符串的数字属性】
- 对象的属性值可以是任何数据类型
- 如果一个对象的属性值是一个函数,我们称呼这个属性为方法。
- 属性名符合标识符命名规范可以不用加引号,不符合标识符规范需要加引号【纯数字也可以不用加引号,它会自动转换为字符串类型】。
- 使用对象的时候,当属性名用中括号括起来的时候,中括号里面的没有引号的是变量,变量值才是属性名。中括号里面有引号的是属性名。
- 以下属性名需要加引号:
- 属性为特殊字符
- 属性为数字
- 属性中有空格
- 使用对象(对象的调用):
- 调用对象的属性,我们采取 对象名.属性名(这个点理解为为”的”)
- 点操作符只能操作符合标识符规范的属性
- 对象里面属性的另一种调用方式:对象名[‘属性名’],注意方括号里面的属性必须加引号,我们后面会用
- 没有用引号引起来,会当变量解析,将变量值放入。
- 调用对象的方法,我们采取 对象名.方法名(),注意这个方法名字后面一定加括号
- 调用对象的属性,我们采取 对象名.属性名(这个点理解为为”的”)
- 对象名[]
- 中括号里面有三种写法:
- 变量
- 没有用引号引起来的标识符【会解析变量得到变量值放入中括号内,即属性名为这个变量的变量值】
- 变量值为字符串即就是属性名
- 变量值为对象会掉用对象名.toString()方法,得到[object Object],即属性名为[object Object]
- 没有用引号引起来的标识符【会解析变量得到变量值放入中括号内,即属性名为这个变量的变量值】
- 字符串
- 用引号引起来的标识符【即属性名为这个字符串】
- 可以用字符串拼接新的属性名
- 数字
- 会自动转换为字符串【即属性名为这个数字】
- 变量
- 中括号里面有三种写法:
- 获取对象:对象名.属性名
- 我们通过获取一个对象身上的某个属性值为undefined来判断对象身上有没有某个属性,这个判断不准确(可能该对象存在,而属性值刚好就是undefined)
- 设置对象属性:对象名.属性名 = 值
- 对象转换为字符串:
- JSON.stringify(对象名)
- 返回值为对象转换为的字符串
- 不会修改原对象【相当于复制了一个值出来,类似浅拷贝】
- JSON.stringify(对象名)
- 字符串转换为对象【该字符串必须是对象的完整形式(属性必须用引号引起来),否则会报错】:
- JSON.parse(字符串名)
- 返回值为一个对象
- JSON.parse(字符串名)
- 对象属性的增删改查:
- 新增属性:
- 法一:
- 对象名.属性名=新增属性值
- 法二:
- 对象名[“属性名”]=新增属性值
- 法三【也叫对象的计算属性,通过变量计算得到的属性】:
- 对象名[变量名]= 新增属性值
- 法一:
- 删除属性:
- 法一:
- delete 对象名.属性名
- 返回值为true或false【删除为true,没删除为false】
- 修改了原对象,元对象的该属性被删除了
- delete 对象名.属性名
- 法二:
- delete 对象名[“属性名”]
- 法一:
- 修改属性:
- 法一:
- 对象名.属性名=修改属性值
- 法二:
- 对象名[“属性名”]=修改属性值
- 法一:
- 查属性:
- 法一:
- 对象名.属性名
- 法二:
- 对象名[“属性名”]
- 法一:
- 新增属性:
- 变量、属性、函数、方法的区别
- 变量和属性的相同点:
- 都是用来存储数据的
- 变量和属性的区别:
- 变量:单独声明并赋值,使用的时候直接写变量名(单独存在)
- 属性:在对象里面的变量称为属性,不需要声明,用来描述该对象的特征,使用的时候必须是 对象.属性
- 函数和方法的相同点:
- 都是实现某种功能 做某件事
- 函数和方法的区别
- 函数是单独声明 并且 调用的时候 函数名() 单独存在
- 方法:对象里面的函数称为方法,方法不需要声明,调用的时候 对象.方法()方法用来描述该对象的行为和功能
- 变量和属性的相同点:
- 利用new Obiect创建对象
- 语法:
Var 对象名 = new Object();
对象名.属性1名 = '属性1值';
对象名.属性2名 = '属性2值';
...
对象名.方法1名 = function(){
//方法体
}
对象名.方法2名 = function(){
//方法体
}
…
- 我们是利用等号=赋值的方法 添加对象的属性和方法
- 每个属性和方法之间用分号结束
- new Object()构造函数创建方法,它是系统自带的构造函数【每次只能创建一个对象】
- 系统自带的构造函数,彼此独立,加上new操作符,就能给你返回一个对象,用变量接收保存对象
- new Object()方法创建的对象是空对象,我们需要一个一个的添加属性
- 选择字面量创建对象的方式的好处:
- 方便
- 可以在初始化对象时罗列所有的属性
- 利用构造函数创建对象
- 我们为什么需要使用构造函数创建对象
- 就是因为我们前面两种创建对象的方式一次只能创建一个对象,我们一次创建一个对象,里面很多的属性和方法是大量相同的 我们只能复制,因此我们可以利用函数的方法,重复这些相同的代码 我们就把这个函数称为构造函数
- 构造函数:用来创建对象的函数
- 又因为这个函数不一样,里面封装的不是普通代码,而是对象
- 构造函数 就是把我们对象里面一些相同的属性和方法抽象出来封装到函数里面
- 就是因为我们前面两种创建对象的方式一次只能创建一个对象,我们一次创建一个对象,里面很多的属性和方法是大量相同的 我们只能复制,因此我们可以利用函数的方法,重复这些相同的代码 我们就把这个函数称为构造函数
- 构造函数:是一种特殊的函数,主要用来初始化对象,即为对象成员赋初始值,它总与new运算符一起使用,我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面
- 普通函数命名一般遵循小驼峰
- 构造函数命名一般遵循大驼峰
- 我们为什么需要使用构造函数创建对象
- 构造函数的语法格式【自定义的构造函数】:
- function 构造函数名(形参1,形参2,…){
this.属性 = 形参;
this.方法=function(){
}
}
var 对象1名 = new 构造函数名(实参1,实参2,…);
- this.属性 = 值;的值一般是形参,用于接收var 对象1名 = new 构造函数名(实参1,实参2,…);中实参中的数据
- 构造函数必须用new操作符,本来他只是一个普通的函数,加new就能产生构造函数的功能,构造函数的功能就是创建对象。
- 调用的时候:
- 对象名.属性【属性是构造函数里面this.后面的属性】
- 对象名.方法()【方法是构造函数里面this.后面的方法】
- 构造函数注意点:
- 构造函数名字首字母要大写【相当于我们Java中的类,类的本质是用来创建对象的】
- 我们构造函数不需要return就可以返回结果
- 我们调用构造函数 必须使用new
- 只要我们new 构造函数名() 调用函数就创建了一个对象
- 构造函数的本质就是函数,只不过这个函数的作用是专门用来创建对象的。
- 构造函数里面属性和方法前面必须有this.
- 常见的内置构造函数:
- Object
- Array()
- RegExp()
- Function()
- Date()
- 对象有关:
- 对象 特指 是一个具体的事物
- 我们利用构造函数创建对象的过程我们也称为对象的实例化
- new关键字
- new关键字执行过程:
- new构造函数可以在内存中创建一个空的对象(在内存中创建一个新的空对象)
- this就会指向刚才创建的空对象(让this指向这个新的空对象)
- 执行构造函数里面的代码,给这个新空对象添加属性和方法。
- 返回这个新对象(所以构造函数里面不需要return,如果return后面的值是引用数据类型,return后面的值就会覆盖原来的this;如果return后面的值是基本数据类型,不会覆盖原有的this)
- 简单理解构造函数执行过程:
- 隐式的创建一个对象:var this ={}
- 我们也可以显示创建一个对象:var 对象名={}
- 然后设置对象属性:对象名.属性名=属性值
- 最后返回这个对象:return 对象名
- 执行代码
- 返回this对象
- 隐式的创建一个对象:var this ={}
- new关键字执行过程:
- 构造函数的原理:
- JavaScript规定,一个函数可以用new关键字来调用,那么此时将按顺序发生四件事:
- 隐秘的创建一个新的空对象
- 将这个函数里面的this绑定到刚才创建隐秘新对象上
- 执行函数体里面的语句
- 返回这个新的对象
- JavaScript规定,一个函数可以用new关键字来调用,那么此时将按顺序发生四件事:
- 对象的特点:
- 对象的属性名是字符串类型,如果不是,会发生隐式类型转换
- 对象的属性名不能重复,如果重复,后面加的属性值会覆盖之前同名的属性值。
- 对象的操作:
- 点操作
- 对象名.属性名
- []操作
- 对象名[“属性名”]
- 对象名[变量]
- 中括号[]中的变量会被解析为变量值,这个变量值就是对象的属性【该方法给对象添加属性也叫对象的计算属性。】
- 点操作
- 遍历对象
- for…in语句用对数组或者对象的属性进行循环操作。
- for in 语法:
for(变量 in 对象名){
变量 得到的是属性名
对象名 得到的是对象值
对象名[变量] 得到的是属性名对应的属性值
}
- 我们使用for in里面的变量 我们喜欢写 k 或者 key
- 用for in语法变量的对象会把其原型上的对象属性也遍历出来
- in运算符
- 语法:“对象属性名“ in 对象名
- 返回一个布尔值,表示这个属性是不是对象的属性。
- 返回值为true:有这个属性
- 返回值为false:没有这个属性
- 返回一个布尔值,表示这个属性是不是对象的属性。
- in操作符没法确定那个属性是这个对象自己的属性,还是对象原型上面的属性。
- 语法:“对象属性名“ in 对象名
- hasOwnProperty方法:
- 这个方法定义在了Object.prototype对象上面,所以任何一个Object都能够拥有这个方法。
- 这个方法返回值为true、false,表示自己是否拥有这个属性,不考虑原型链,就看自己身上有没有这个属性,不进行原型链查找。
- 语法:目标对象名.hasOwnProperty(“属性名”)
- 如果目标对象有参数中的属性名,则返回值为true,否则返回值为false
- instanceof运算符
- 语法:A instanceof B
- 判断A是不是B构造函数实例化出来的对象
- 是返回值为true否则返回false【B只要是原型链上的构造函数,都返回true】
- 判断A是不是B构造函数实例化出来的对象
- Instanceof运算符的机制:遍历A这个对象的原型链上的每个原型对象,如果遍历到这个原型对象 是某个构造函数的prototype,那么A就认为是这个构造函数的实例,返回true
- 语法:A instanceof B
- 对象属性描述:
- 定义属性Object.defineProperty()
- Js引擎允许对属性操作的控制,需要使用方法Object.defineProperty()来实现。这个方法接收三个参数:
- 第一个参数:属性所在的对象【目标对象】
- 第二个参数:属性的名字【对象添加的属性名】
- 第三个参数:描述符对象【属性的描述对象】
- get方法:获取对象添加属性名的属性值
- set方法:设置对象添加属性名的属性值
- 其他属性见JavaScript高级word文档
- Js引擎允许对属性操作的控制,需要使用方法Object.defineProperty()来实现。这个方法接收三个参数:
- 定义属性Object.defineProperty()
- 检测数据类型的方法:
- Object.prototype.toString.call(检测值)
- 当检测值为字符串类型,返回值为[object String]
- 当检测值为数字类型,返回值为[object Number]
- 当检测值为true或false,返回值为[object Boolean]
- 当检测值为undefined,返回值为[object Undefined]
- 当检测值为null,返回值为[object Null]
- 该方法返回值都为字符串类型
- Object.prototype.toString.call(检测值)
- 小结
- 对象可以让代码结构更清晰
- 对象是复杂数据类型object
- 本质:对象就是一组无序的相关属性和方法的集合
- 构造函数泛指某一大类,比如苹果,不管是红苹果还是绿苹果,都统称为苹果
- 对象实例特指一个事物,比如这个苹果、正在给你们讲课的刘老师等。
- for…in语句用于对象的属性进行循环操作。
- JavaScript内置对象
- JavaScript中的对象分为3种:自定义对象、内置对象、浏览器对象
- 前两种对象是JS基础内容,属于ECMAScript;第三个浏览器对象属于我们JS独有的,我们JS API讲解
- 内置对象就是指JS语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法)
- 内置对象最大的优点就是帮助我们快速开发
- JavaScript提高了多个内置对象:Math、Date、Array、String等
- 查文档
- MDN
- 学习一个内置对象的使用,只要学会其常用成员的使用即可,我们可以通过查文档学习,可以通过MDN/W3C来查询
- Mozilla开发者网络(MDN)提供了有关开放网络技术(Open Web)的信息,包括HTML、CSS和万维网及HRML5应用的API。
- 官方网址:https://developer.mozilla.org/zh-CN/
- MDN
- 如何学习对象中的方法:
- 查阅该方法的功能
- 查看里面参数的意义和类型
- 查看返回值的意义和类型
- 通过demo进行测试
- Math对象
- Math数学对象 不是一个构造函数,所以我们不需要new来调用 而是直接使用里面的属性和方法即可。
- 数学对象是用来操作数字的,也就是说这些方法的参数本质都必须传数字,如果你传的参数不是数字,js会帮你把这些参数转为数字类型,转不了返回NaN
- Math概述:
- Math对象不是构造函数,它具有数学常数和函数的属性和方法。跟数学相关的运算(求绝对值,取整、最大值等)可以使用Math中的成员
- Math.PI
- 圆周率
- Math.max(value1[,value2,[value3, …]])
- 如果没有参数返回-Infinity
- 如果参数全是数字,返回参数中的最大值
- 如果参数中有非数字,返回NaN
- Math.min(value1[,value2,[value3, …]])
- 如果没有参数返回Infinity
- 如果参数全是数字,返回参数中的最小值
- 如果参数中有非数字,返回NaN
- 取数组的最小值:var min=Math.min.apply(null,数组名)
- Math.floor(value1)
- 向下取整【取刚好小于或等于当前数字的整数】
- 不传参数返回NaN
- Math.ceil(value1)
- 向上取整【取刚好大于或等于当前数字的整数】
- 不传参数返回NaN
- Math.round(value1)
- 四舍五入 就近取整【数的绝对值先四舍五入(.5除外,这个向上取整),再添加原来的符号】
- 简单理解:先就近取整,就近取整有两个值就只向上取整
- 四舍五入 就近取整【数的绝对值先四舍五入(.5除外,这个向上取整),再添加原来的符号】
- Math.abs(value1)
- 绝对值
- 当出现字符串时,有隐式转换,不能转换为数字结果就是NaN
- 接收多个参数时,后面的参数会被忽略掉
- 不传参数,返回NaN
- 绝对值
- Math.pow(value1,value2)
- 处理幂的方法
- value1:底数
- value2:指数
- Math.sqrt(value)
- 开根号方法【即根号下面是value】
- Math.sin(弧度)
- 该弧度下对应的正弦值
- Math.cos(弧度)
- 该弧度下对应的余弦值
- 随机数方法random()
- 语法:
- Math.random()
- 这个方法不跟参数
- Math.random()
- 函数返回一个浮点,随机数在范围[0,1) ,也就是说,从0【包括0】往上,但是不包括1(排除1),然后您可以缩放到所需的范围,实现将初始种子选择到随机数生成算法,它不能被用户选择或重置。
- Math.random()不能提供像密码一样安全的随机数字,不能使用它们来处理有关安全的事情。使用Web Crypto API来代替,和更精确的window.crypto.getRandomValues()方法。
- 语法:
- 得到一个两个数之间的随机整数(大于等于min,小于max)
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min
}
- 得到一个两个数之间的随机整数.包括两个数在内
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min
}
- Date()日期对象
- 是一个构造函数 必须使用new 来调用创建我们的日期对象(实例化后才能使用)
- 只能通过调用Date构造函数来实例化日期对象,以常规函数调用它(即不加new操作符)将会返回一个字符串,而不是一个日期对象,而不是一个日期对象,另外,不像其他JavaScript类型,Date对象没有字面量格式
- 使用Date 如果没有参数 返回当前系统的当前时间(Date实例用来处理日期和时间,获取当前时间必须实例化)
var now = new Date()
console.log(now)
- 参数常用写法(括号里面有时间就返回参数里面的时间):
- 数字型【按照 年,月,日,时,分,秒 接收参数,时分秒没有的参数当作0处理月份参数比实际月份小1】:
- 案例:2019,10,01,08,08,08
- 字符串型:
- 案例:
- ’1998-11-02 02:02:02’
- 案例:
- 数字型【按照 年,月,日,时,分,秒 接收参数,时分秒没有的参数当作0处理月份参数比实际月份小1】:
- 参数常用写法(括号里面有时间就返回参数里面的时间):
写成:new Date('1998-11-2 02:02:02')
- ’2019/10/1 8:8:8’
写成:new Date('1998/11/2 02:02:02')
- 日期本地格式:
- 第一步 创建日期对象:
- var 日期对象名 = new Date()
- 第二步 获取日期本地格式:
- 格式一:
- 年/月/日 上午时:分:秒
- 年/月/日 下午时:分:秒
- 格式一:
- 第一步 创建日期对象:
- 日期本地格式:
语法:日期对象名.toLocaleString()
- 格式二:
- 年/月/日
- 格式二:
语法:日期对象名.toLocaleDateString()
- 格式三:
- 下午时:分:秒
- 上午时:分:秒
- 格式三:
语法:日期对象名.toLocaleTimeString()
- 日期格式化
- 我们想要1998-11-02 02:02:02格式的日期,需要获取指定的部分,所以我们要手动的得到这种格式
方法名 | 说明 | 代码 |
getFullYear() | 获取当年 | var date = new Date('1998/11/2 14:32:01') console.log(date.getFullYear()) |
getMonth() | 获取当月(0-11)比实际月份小1[获取月份的时候需要加1] | var date = new Date('1998/11/2 14:32:01') console.log(date.getMonth()+1) |
getDate() | 获取当天日期(几号) | var date = new Date('1998/11/2 14:32:01') console.log(date.getDate()) |
getDay() | 获取星期几(周日0到周六6) | var date = new Date('1998/11/2 14:32:01') console.log(date.getDay()) |
getHours() | 获取当前小时 | var date = new Date('1998/11/2 14:32:01') console.log(date.getHours()) |
getMinutes() | 获取当前分钟 | var date = new Date('1998/11/2 14:32:01') console.log(date.getMinutes()) |
getSeconds() | 获取当前秒钟 | var date = new Date('1998/11/2 14:32:01') console.log(date.getSeconds()) |
getTime() | 获取当前时间的毫秒数 | |
getTimezoneOffset() | 获取当前时区的偏移时间 |
- 获取日期的总的毫秒形式(时间戳)
- Date对象是基于1970年1月1日(世界标准时间)起的毫秒数
- 为什么计算机起始时间从1970年开始?
- 我们经常利用总的毫秒数来计算时间,因为它更精确
- 获取Date总的毫秒数 不是当前时间的毫秒数 而是距离1970年1月1号过了多少毫秒
- 通过valueof() 或getTime()方法得到总的毫秒数
- 语法:
- var 时间对象名1 = new Date();
- 语法:
时间对象名1.valueof();
时间对象名1.getTime();
- 案例:
var date = new Date();
console.log(date.valueOf())//就是我们现在时间 距离1970.1.1 总的毫秒数
console.log(date.getTime())//就是我们现在时间 距离1970.1.1 总的毫秒数
- 简单写法获取总的毫秒数(实际开发中最常用的写法):
- 语法:
- 简单写法获取总的毫秒数(实际开发中最常用的写法):
var 时间对象名 = +new Date();
- 案例:
var date = +new Date();
console.log(date)
- H5新增的获取总的毫秒数
- 语法:
- Date.now()
- 案例:
- console.log(Date.now())
- 语法:
- H5新增的获取总的毫秒数
- 设置日期的方法【需要在设置本地日期时间对象之前设置】:
- setFullYear():设置年份
- setMonth():设置月份(0-11)【对应的月份为1-12】
- setDate():设置日,几号(1-31)
- setHours():设置小时
- 当设置的小时为0时,toLocaleString对应的时间为上午12时
- 当设置的小时为12时,toLocaleString对应的时间为下午12时
- setMinutes:设置分钟
- setSeconds:设置秒钟
- setMilliseconds:设置毫秒
- 倒计时案例:
- 案例分析:
- 核心算法:输入的时间减去现在的时间就是剩余的时间,即倒计时,但是不能拿着时分秒相减,比如05分减去25分,结果会是负数
- 用时间戳来做,用户输入时间总的毫秒数减去现在时间的总的毫秒数,得到的就是剩余时间的毫秒数。
- 把剩余时间总的毫秒数转换为天、时、分、秒(时间戳转换为时分秒)
- 转换公式如下:
- D=parseInt(总秒数/60/60/24); //计算天数
- H=parseInt(总秒数/60/60%24); //计算小时
- M=parseInt(总秒数/60%60); //计算分钟
- S=parseInt(总秒数%60); //计算当前秒数
- 1秒等于1000毫秒
- 案例分析:
- 数组对象:
- 数组对象的创建:
- 创建数组对象的两种方式:
- 字面量方式
- new Array()
- 没有参数表示创建一个空的数组
- 有一个数字参数,表示创建了一个长度为该参数的数组,但里面全是空的数组元素
- 有多个参数,参数字间用逗号隔开,创建了一个数组,分别存里面的参数值数组(形参就存的是形参接收过来的实参值,实参就直接是该值)
- 创建数组对象的两种方式:
- 检测是否为数组:
- instanceof(运算符)
- 语法:数组名 instanceof Array
- 如果是数组,返回结果为true
- 如果不是数组,返回结果为false
- 案例:
- var arr1 = new Array(1);
- 语法:数组名 instanceof Array
- instanceof(运算符)
- 数组对象的创建:
console.log(arr1 instanceof Array)
- Array.isArray()用于确定传递的值是否是一个Array(数组)【H5新增的方法 ie9以上版本支持】
- 语法:Array.isArray(数组名)
- 如果对象是数组,则为true,否则为false
- 这个方法属于Array这个构造函数
- 这个方法叫静态方法【静态方法:挂载到构造函数上面的方法叫静态方法,它的调用主体永远不会发生变化】
- 语法:Array.isArray(数组名)
- Array.isArray()用于确定传递的值是否是一个Array(数组)【H5新增的方法 ie9以上版本支持】
- instanceof和isArray
- 当检测Array实例时,Array.isArray优于instanceof,因为Array.isArray能检测iframes
- instanceof也可以检测对象:
- 对象名.instanceof Object
- instanceof可以检测实例对象来自于哪个构造函数:
- 实例名.instanceof 构造函数名
- 添加删除数组元素的方法:
方法名 | 说明 | 返回值 |
push(参数1…) | 末尾添加一个或多个元素,注意会修改原数组(参数顺序整体放在原数组末尾) | 并返回数组新的长度(新增数组元素后,现在数组元素的长度) |
pop() | 删除数组最后一个元素,把数组长度减1 无参数、会修改原数组【不接收参数】 | 返回它删除的元素的值 |
unshift(参数1…) | 向数组的开头添加一个或更多元素,注意会修改原数组(参数顺序整体放在数组开头) | 并返回数组新的长度 |
shift() | 删除数组的第一个元素,数组长度减1 无参数、会修改原数组【不接收参数】 | 并返回原数组第一个元素的值(删除元素的值) |
- push()
- 在我们数组的末尾 添加一个或者多个数组元素
- 修改了原对象,返回值为数组的长度,即length属性值。
- 语法:数组名.push(新增数组元素1,…)
- push()参数直接写 数组元素就可以了
- push()完毕之后,原数组末尾新增了数组元素。
- 数组名.push(新增数组元素1,…)返回的结果是新数组的长度
- 在我们数组的末尾 添加一个或者多个数组元素
- unshift(参数1…)
- 向数组的开头添加一个或更多元素
- 语法:数组名.unshift(新增数组元素1,…)
- unshift()参数直接写 数组元素就可以了
- unshift()完毕之后,原数组开头新增了数组元素。
- 数组名.unshift(新增数组元素1,…)返回的结果是新数组的长度
- pop()
- 删除数组的最后一个元素,一次只能删除一个元素
- 语法:数组名.pop()
- push()没有参数
- push()完毕之后,原数组最后一个元素被删除了
- 数组名.pop()返回的结果是删除的那个数组元素(原数组最后一个元素)
- shift()
- 删除数组的第一个元素 记住一次只能删除一个元素
- 语法:数组名.shift()
- shift没有参数
- shift完毕之后,原数组第一个元素被删除了
- 数组名.shift()返回的结果是删除的那个元素(原数组第一个元素)
- push()
- 翻转数组
- 语法:数组名.reverse();
- 原数组会翻转,返回的结果也是翻转后的数组【会改变原数组】
- 语法:数组名.reverse();
- 数组排序:
- 语法:数组名.sort()
- 原数组里面的元素会从按每个元素的首字符开始从小到大排序,返回的结果也是排序好后的新数组【会改变原数组】
- 是数字就按每个数字的首数字开始从小到大排序
- 是字符就按每个字符的首字符开始从小到大排序
- sort参数:
- 不传参:
- 将数据类型转换为字符串类型,然后依次比较每个字符的ascii码,由小到大排序。
- 不传参:
- 原数组里面的元素会从按每个元素的首字符开始从小到大排序,返回的结果也是排序好后的新数组【会改变原数组】
- 语法:数组名.sort()
常见ASCII码的大小规则:0~9<A~Z<a~z
- 参数为函数,函数有两个形参【依次取数组两项出来(索引号为0和1;索引号为1和2;…)】,函数语句中return 数字
- return后面的数字大于等于0:这两个形参的对应的数值不交换位置
- return后面的数字小于0:这两个形参对应的数值交换位置
- 参数为函数,函数有两个形参【依次取数组两项出来(索引号为0和1;索引号为1和2;…)】,函数语句中return 数字
- 冒泡排序【数字有效,字符串位置不变】:
- 语法:
数组名.sort(function (a, b) {
return a - b; //数组项升序
/* return b - a;//数组项降序 */
})
- 数组中数据对象内的某个属性值大小排序语法:
数组名.sort(function (a, b) {
return a.属性 – b.属性; //数组项升序
/* return b - a;//数组项降序 */
})
- 数组索引方法:
方法名 | 说明 | 返回值 |
indexOf() | 数组中查找给定元素的第一个索引 | 如果存在返回索引号 如果不存在,则返回-1. |
lastIndexOf() | 在数组中的最后一个的索引 | 如果存在返回索引号 如果不存在,则返回-1 |
- indexOf()使用方法:
- 数组名.indexOf(‘目标元素值’[,开始索引号])
- 返回的结果为目标元素值的第一个索引号(返回第一个满足条件的索引号)【从开始索引号开始查找,包括开始索引号这个元素】
- 如果没有目标元素,返回的结果为-1
- 不会修改原数组
- 数组名.indexOf(‘目标元素值’[,开始索引号])
- lasrIndexOf()使用方法:
- 数组名.indexOf(‘目标元素值’)
- 返回的结果为目标元素值的第一个索引号(返回第一个满足条件的索引号,倒着查找)【最后一个满足条件的索引号】
- 可以有第二个参数,第二个参数为开始查找位置索引号,由该位置开始往前查找。
- 不会修改原数组。
- 数组名.indexOf(‘目标元素值’)
- 如果没有目标元素,返回的结果为-1
- indexOf()使用方法:
- 方法研究:
- 这个方法被哪个对象调用(函数,数组,对象还是包装类)
- 这个方法的参数(有无参数,参数的含义)
- 这个方法的返回值
- 是否会修改原来操作对象。
- 数组去重
- 案例分析:
- 目标:把旧数组里面不重复的元素取出来放到新数组中,重复的元素只保留一个,放到新数组中去重。
- 核心算法:我们遍历旧数组,然后拿着我们旧数组元素去查询新数组,如果该元素在新数组中没有,就添加进去,否则不添加
- 我们怎么知道该元素在新数组中存不存在:利用新数组.indexOf(数组元素) 如果返回结果为-1就说明新数组里面没有该元素
- 语法:
- 案例分析:
var arr = [value1,…]
var newArr = []
for (var i = 0; i < arr.length; i++) {
if (newArr.indexOf(arr[i]) == -1) {
newArr.push(arr[i])
}
}
- 获取数组中指定值对应的所有的下标:
arr = [1, 2, 3, 4, 5, 6, 7, 2, 3, 4, 5, 2, 3, 4]
var indexs = []
var index = arr.indexOf(2)
while (index >= 0) {
indexs.push(index)
index = arr.indexOf(2, index + 1)
}
console.log(indexs)
- 数组转换为字符串
方法名 | 说明 | 返回值 |
toString() | 把数组转换成字符串,逗号分隔每一项 | 返回一个字符串 |
join(‘分隔符’) | 方法用于把数组中所有元素转换为一个字符串 | 返回一个字符串 |
- toString()
- 语法:数组名.toString()
- 将数组转化为字符串,各元素用逗号连接起来构成这个字符串
- 不会修改原数组
- 语法:数组名.toString()
- join(‘分隔符’)
- 语法:数组名.join(‘分隔符’)
- 将数组转换为字符串,各元素由分隔符连接起来构成这个字符串
- 当join方法没有参数(即没有分隔符时),数组的每一项通过逗号分隔符来拼接为字符串
- 不会修改原数组
- 语法:数组名.join(‘分隔符’)
- toString()
- 数组其他方法:
方法名 | 说明 | 返回值 |
concat() | 连接两个或多个数组 不改变原数组 | 返回一个新的数组 |
slice() | 数组截取slice(begin,end) 不改变原数组 | 返回被截取项目的新数组 |
splice() | 数组删除splice(第几个开始,要删除个数) 改变原数组 | 返回被删除项目的新数组 注意,这个会影响原数组 |
- concat()
- 语法:左数祖名.concat(右数组名)
- 将左数组里面的数组元素和右数组名里面的数组元素连接起来放在新数组里面
- 返回的结果为多个数组里面的元素连接起来的新数组
- 原数组不会发生变化(单独使用原数组时还是以前的数)【不改变原对象。】
- concat方法可以有多个参数,会先将左数祖名对应的数组去掉数组字面量[],返回一个去掉[]字面量新的左字符串,concat方法中的参数对应的参数值是数组,就将该数组去掉字面量[],返回一个去掉[]字面量新的右字符串,其他参数用逗号分隔后再通过字符串拼接起来,最后将所有字符串依次拼接得到最终字符串,然后加上数组字面量[]得到新数组。
- 当concat没有参数时,相当于复制数组【浅拷贝】
- 语法:左数祖名.concat(右数组名)
- slice()
- 语法:数组名.slice(开始元素索引号,结束索引号)
- 返回值为截取数组元素(区间:[开始元素下标,结束元素下标))
- 下标为正数时和索引一一对应
- 下标为负数时,原数组可以看作最后一个元素索引为-1,前面索引依次递减
- 结束下标必须大于开始下标,否则截取的为空数组
- 第二个参数可以不传,不传表示从数组的开始下标截取到数组的最后一项。
- 数组值拷贝:newArr=arr.slice(0) 或: newArr=arr.slice(0,arr.length)
- 数组内存地址拷贝:newArr=arr
- 原数组不会发生变化
- 返回值为截取数组元素(区间:[开始元素下标,结束元素下标))
- 语法:数组名.slice(开始元素索引号,结束索引号)
- splice()
- 语法:数组名.splice(被删除元素的开始元素索引号,删除元素个数)
- 返回值为删除的元素(区间:[开始元素下标,开始元素下标+删除元素个数-1))
- 原数组发生变化,被删除的元素不会在原数组里面
- 不传参数:
- 表示截取空项,不会删除数组元素,返回值为空数组
- 一个参数
- 从数组的开始下标截取到数组的最后一项。【】
- 两个参数:
- 第一个参数为开始元素下标,第二个参数为删除元素的个数【截取元素的个数】
- 三个参数及以上:
- 第一个参数为截取数组开始元素下标
- 第二个参数为截取元素的个数【删除元素个数】
- 第三个参数及以上 为截取元素位置替换为新元素。
- 应用:
- 新增数组元素:
- 数组名.splice(‘新增数组元素下标位置’,0,‘新增数组元素’)
- 删除数组元素:
- 数组名.splice(‘删除数组元素开始下标位置’,删除个数)
- 修改数组元素:
- 修改一个元素:
- 新增数组元素:
- 语法:数组名.splice(被删除元素的开始元素索引号,删除元素个数)
- concat()
数组名.splice(‘修改数组元素下标位置’,1,‘修改后的数组元素’)
- 修改多个元素:
数组名.splice(‘修改数组元素开始下标位置’,修改元素个数,‘修改后的数组元素’)
- 字符串对象
- 对象 才有 属性和方法 复杂数据类型才有 属性和方法
- 简单数据类型为什么会有length属性呢?
- 按道理基本数据类型是没有属性和方法的,而对象才有属性和方法,但是字面量的字符串类型却有length属性,这是因为js会把基本数据类型包装为复杂数据类型。
- 基本包装类型:
- 就是把简单数据类型包装成为了 复杂数据类型
- 基本包装类型:
- 把简单数据类型包装为复杂数据类型放在临时变量里面存储
- 把临时变量的值给存储这简单数据类型的变量
- 例如:var str = ‘andy’; 就相当于以下三步【隐式包装类】:
- 生成临时变量,把简单数据类型包装为复杂数据类型:
- var temp = new String(‘andy’)
- 赋值给我们声明的字符变量
- str = temp
- 销毁临时变量
- temp = null;
- 生成临时变量,把简单数据类型包装为复杂数据类型:
- 例如:var str = ‘andy’; 就相当于以下三步【隐式包装类】:
- 基本包装类型
- 为了方便操作基本数据类型,JavaScript还提供了三个特殊的引用类型:String、Number和Boolean.
- 基本包装类型就是把简单数据类型包装成为复杂数据类型,这样基本数据类型就有了属性和方法
- 包装类【现阶段的包装类有:数字,字符串,布尔值】:
- 前提:只有对象才有属性和方法(只有对象才能调用属性和方法)
- 包装类:就是说数字,字符串在调用属性和方法的时候,其实会先将数字字符串包装成对象,这个包装的过程就是包装类。
- 例如:
- 显示数字包装类:
- 例如:
var num = 10;
var numObj = new Number(10)
console.log(numObj)
- 显示字符串包装类:
var str = "大家好";
var strObj = new String(str)
console.log(strObj)
- 显示布尔包装类:
var bol = "大家好";
var bolObj = new Boolean(str)
console.log(bolObj)
- 包装类属性用完即删:所以包装类中 设置属性无效
- 包装类的好处:简化我们写代码的复杂度
- 包装类,其实就是在基本数据类型(string,number,boolean)身上调用属性时,js自动帮你把基本数据类型包装为对象
- 字符串包装类,会有数字索引属性。还有length属性
- 字符串的不可变
- 指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中新开辟了一个内存空间。
- 所有字符串都在内存中,只是地址变了
- 因为字符串的不可变,不要大量的拼接字符串,大量拼接字符串的时候会有效率问题
- 字符串的所有的方法,都不会修改字符串本身(字符串是不可变的【字符串是基本数据类型,字符串操作方法都是通过包装类操作的,包装类对象用完就删除了】),操作完成会返回一个新的字符串。
- 指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中新开辟了一个内存空间。
- 根据字符返回位置
方法名 | 说明 |
indexOf(‘要查找的字符’,开始的位置) | 返回指定内容在原字符中的位置索引,如果找不到就返回-1,开始的位置是index索引号(包括该索引号字符) |
lastIndexOf() | 从后往前找,只找第一个匹配的 |
- search()获取字符串中的位置:
- 语法:数组名.search(‘要查找的字符’)
- 结果和indexOf结果一样,但不接收第二个参数。【返回第一个查找到的目标字符的索引号。查不到就返回-1】
- 语法:数组名.search(‘要查找的字符’)
- search()获取字符串中的位置:
- 查找字符串中某个字符出现的位置以及次数:
- 思路:
- 核心算法:先查找第一个目标字符出现的位置
- 然后 只要indexOf返回的结果不是-1就继续往后查找
- 因为indexOf只能查找到第一个,所以后面的查找,利用第二个参数,当前索引加1,从而继续查找。
- 案例:
- 思路:
var str = 'abcoefoxyozzopp';
var num = 0;
var index = str.indexOf('o');
while (index !== -1) {
num++
console.log(index);
index = str.indexOf('o', index + 1)
}
console.log('o出现的次数是:' + num)
- 查找数组元素出现的位置和次数
var arr = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 5, 4, 3, 2, 1]
index = arr.indexOf(1);
num = 0;
while (index !== -1) {
num++
console.log(index)
index = arr.indexOf(1, index + 1)
}
console.log('1出现的次数是' + num + '次')
- 根据位置返回字符
方法名 | 说明 | 使用 |
charAt(index) | 返回指定位置的字符(index字符串的索引号) | 字符串.charAt(index) |
charCodeAt(index) | 获取指定位置处字符的ASCI码(index索引号) | Str.charCodeAt(0) |
str[index] | 获取指定位置处字符 | HTML5,IE8支持和charAt等效 |
- charAt(index)
- 语法:数组名.charAt(index)
- 返回索引号为index的字符串中的字符
- 没有该索引号,则返回值为空字符
- 包装类也可以实现该方法【更常用】:
- 语法:字符串名[index]
- 没有该索引号,则返回值为undefined
- 语法:字符串名[index]
- 语法:数组名.charAt(index)
- charCodeAt(index)
- 返回相应索引号的字符ASCI码值
- 语法:字符串名.charCodeAt(索引号)
- 返回值为字符串该索引号属性所对应的字符
- 目的:判断用户按下了那个键
- fromCharCode()获取对应字符编码的字符:
- 该方法属于构造函数String
- 语法:String.fromCharCode(ASCII码值)
- 返回值为该ASCII码值对应的字符
- 可以通过charCodeAt(index)和fromCharCode()方法实现加密和解密字符。
- charAt(index)
- 遍历字符串中的字符
var str = '1234567'
for (var i = 0; i < str.length; i++) {
console.log(str.charAt(i))
}
- 判断一个字符串中次数最多的字符,并统计其次数
- 思路:
- 核心算法:利用charAt()遍历这个字符串
- 把每个字符都存储给对象,如果对象没有该属性,就为1,如果存在了就+1
- 遍历对象,得到最大值和该字符
- 思路:
- 判断对象里面有无该属性
if (对象名[‘属性名’]) {
//有该属性执行语句
} else {
//没有改属性执行语句
}
- 判断一个字符串中次数最多的字符,并统计其次数案例:
var str = 'abcoefoxyozzopp';
var obj = {};
for (var i = 0; i < str.length; i++) {
var chars = str.charAt(i); //chars得到的是字符串的每一个字符
if (obj[chars]) { //obj[chars]是判断obj对象里面有无chars属性
obj[chars]++;
} else {
obj[chars] = 1;
}
}
var max = 0;
for (var key in obj) { //遍历obj对象。key为obj对象的属性名
if (obj[key] > max) {
max = obj[key]
ch = key; //用ch变量保存obj对象中属性值最大的属性名
}
}
console.log(obj)
console.log(max)
console.log('最多的字符是' + ch)
- 字符串操作方法
方法名 | 说明 |
concat(str1,str2,…) | concat()方法用于连接两个或多个字符串。拼接字符串,等效于+,+更常用 |
substr(start,length) | 从start位置开始(索引号),length取的个数 重点记这个 |
slice(start,end) | 从start位置开始,截取到end位置,end取不到(他俩都是索引号) |
substring(start,end) | 从start位置开始,截取到end位置,end取不到 基本和slice相同 但是不接受负值 |
- substr()截取字符串:
- 语法:字符串名.substr(数字参数)
- 所属对象:字符串【每个字符对应的索引号有两个[一个正的,一个负的]】
- 不改变原字符串对象【字符串的不可变】
- 返回值:返回截取的字符串
- 数字参数:
- 一个参数【可以为负数,为负数时最后一个字符的索引号为-1】:
- 语法:字符串名.substr(数字参数)
- substr()截取字符串:
参数为开始截取字符串的索引号,默认截取到字符串的最后一个字符。
- 两个参数:
第一个参数为截取字符串的开始位置索引号
第二个参数为截取的字符个数【负数会当0处理】
- substring()截取字符串:
- 语法:字符串名.substring(数字参数)
- 所属对象:字符串【每个字符对应的索引号是唯一的】
- 不改变原字符串对象【字符串的不可变】
- 返回值:返回截取的字符串
- 数字参数:
- 一个参数:
- 语法:字符串名.substring(数字参数)
- substring()截取字符串:
参数为开始截取字符串的索引号【负数等价于索引号0】,默认截取到字符串的最后一个字符。
- 两个参数:
第一个参数为截取字符串的开始位置索引号【负数会当0处理】
第二个参数为截取字符串的结束位置索引号【截取区间[开始索引号,结束索引号)】
- slice()截取字符串:
- 语法:字符串名.slice(数字参数)
- 所属对象:字符串【每个字符对应的索引号有两个[一个正的,一个负的]】
- 不改变原字符串对象【字符串的不可变】
- 返回值:返回截取的字符串
- 数字参数:
- 一个参数:
- 语法:字符串名.slice(数字参数)
- slice()截取字符串:
参数为开始截取字符串的索引号【可以为负数,为负数时最后一个字符的索引号为-1】,默认截取到字符串的最后一个字符。
- 两个参数:
第一个参数为截取字符串的开始位置索引号
第二个参数为截取字符串的结束位置索引号【截取字符区间[开始索引号,结束索引号)】
- 替换字符replace(‘被替换的字符’,’替换为的字符’)
- 语法:目标字符串名.replace(‘被替换的目标字符串中的字符’,’替换为的字符’)
- 返回值为一个新字符串且不会修改原字符串【字符串不可变】,并且只会替换第一个目标字符,所以需要用其他变量来接收返回值
- 所以替换原字符串中的目标字符:
- 目标字符串名=目标字符串名.replace(‘被替换的目标字符串中的字符’,’替换为的字符’)【只会替换第一个目标字符】
- 语法:目标字符串名.replace(‘被替换的目标字符串中的字符’,’替换为的字符’)
- 替换字符串中的所有的某个字符
- 思路:
- 字符串中用indexOf查找是否有该字符
- 有该字符就替换
- 思路:
- 替换字符串中的所有的某个字符案例:
var str = 'abcoefoxyozzopp'
while (str.indexOf('o') !== -1) {
str = str.replace('o', '1')
}
console.log(str)
- 字符串转换为数组split(‘分隔符’)
- 语法:字符串名.split(‘原字符串中的目标字符’)
- 原字符串中的目标字符 都会变为逗号分隔符,并且字符串会变为数组
- 如果目标字符为空,则会把字符串的每一个字符都当作数组的每一项。
- 转换好的数组如果第一个元素为空字符串,则原字符串是以参数中的目标字符分隔符开头的。
- 转换好的数组如果最后一个元素为空字符串,则原字符串是以参数中的目标字符分隔符结尾的
- 如果原字符串中没有目标字符这个分隔符,则原字符串会看作数组的一项。
- split不传参数的话,原字符串整体会看作数组的一项
- 不会改变原字符串
- 原字符串中的目标字符 都会变为逗号分隔符,并且字符串会变为数组
- 语法:字符串名.split(‘原字符串中的目标字符’)
- toUpperCase()
- toUpperCase() 方法将调用该方法的字符串转为大写形式并返回(如果调用该方法的值不是字符串类型会被强制转换)。 str.toUpperCase() 一个新的字符串,表示转换为大写的调用字符串。
- toLowerCase()
- toLowerCase() 会将调用该方法的字符串值转为小写形式,并返回。 str.toLowerCase() 一个新的字符串,表示转换为小写的调用字符串。 toLowerCase 会将调用该方法的字符串值转为小写形式,并返回。…
- …toLowerCase 不会影响字符串本身的值。…
- 英文中,将每一个单词的首字母变为大写输出:
<script>
var str = 'hello boy'
//字符串转换为数组,字符串中的空格为数组每一项的分隔符
var arr = str.split(' ')
//newArr用于存放大写单词的每一项
var newArr = []
console.log(arr)
for (var i = 0; i < arr.length; i++) {
var arrTemp = arr[i]
//字符串中每个单词首字母大写
var newstr = arrTemp[0].toUpperCase() + arrTemp.substr(1)
//首字母大写的单词作为数组newArr的每一项
newArr.push(newstr)
}
//将数组newArr转换为字符串,逗号分隔符变为空格分隔符
var newArrStr = newArr.join(' ')
console.log(newArrStr)
</script>
- 字符串其他方法:
- 字符串名.trimLeft()
- 去掉字符串开始的空格
- 字符串名.trimRight()
- 去掉字符串结束的空格
- 字符串名.trim()
- 去掉字符串开始和结束的空格
- 字符串名.trimLeft()
- 简单数据类型与复杂数据类型
- 简单类型又叫基本数据类型或者值类型,复杂类型又叫做引用类型
- 值类型:简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型
- string、number、boolean、undefined、null
- 特殊null返回的是object对象类型
- 如果有个变量我们以后打算存储为对象,暂时没想好放啥,这时候就给null
- 引用类型:复杂数据类型,在存储时 变量中存储的仅仅是地址(引用),因此叫做引用数据类型,通过new关键字创建对象(系统对象、自定义对象),如Object、Array、Date等
- 值类型:简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型
- 简单类型又叫基本数据类型或者值类型,复杂类型又叫做引用类型
- 总结数组的方法:
- 不改变数组原对象且属于该数组对象的方法:
- 数组连接:concat()
- 数组截取:slice()
- 数组转换为字符串:join(),toString()
- 元素查找:indexOf(),lastIndexOf()
- 改变数组原对象且属于该数组对象的方法:
- 添加数组元素:push(),unshift()
- 删除数组元素:pop(),shift()
- 数组排序:sort()
- 翻转数组:reverse()
- 数组截取:splice()
- 不改变数组原对象且属于该数组对象的方法:
- 堆和栈
- 堆栈空间分配区别:
- 栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;简单数据类型存放到栈里面
- 堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收,复杂数据类型存放到堆里面
- 注意:JavaScript中没有堆栈的概念,通过堆栈的方式,可以让大家更容易理解代码的一些执行方式,便于将来学习其他语言
- 堆栈空间分配区别:
- 简单数据类型的内存分配
- 值类型(简单数据类型):string、number、boolean、undefined、null
- 值类型变量的数据直接存放在变量(栈空间)中
- 简单数据类型 是存放在栈里面 里面直接开辟一个空间 存放的是值
- 复杂数据类型 是首先在栈里面存放地址(十六进制表示)然后这个地址指向堆里面的数据。
- 复杂类型的内存分配
- 引用类型(复杂数据类型):通过new关键字创建对象(系统对象、自定义对象),如Object、Array、Date等
- 引用类型bianl(栈空间)里面存放的是地址,真正的对象实例存放在堆空间中
- 简单类型传参
- 函数的形参也可以看作一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到外部变量。
- 复杂类型传参
- 函数的形参也可以看作是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所有操作的是同一个对象。