数据类型
简介
JavaScript 官方名称是 ECMAScript
是一种属于网络的脚本语言,已经被广泛用于Web应用开发,常用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果
1995年2月Netscape的布兰登.艾奇
开发了针对网景公司的 Netscape Navigator
浏览器的脚本语言LiveScript。之后Netscape与Sun公司联盟后LiveScript更名为JavaScript
微软在javascript发布后为了抢占市场推出了JScript。为了让脚本语言规范不在混乱,根据javascript 1.1版本推出了 ECMA-262的脚本语言标准
ECMA是欧洲计算机制造商协会由Sum、微软、NetScape公司的程序员组成
使用场景
- 浏览器网页端开发
- 做为服务器后台语言使用Node.js
- 移动端手机APP开发,如Facebook的 React Native (opens new window)、
uniapp
、PhoneGap
、IONIC
- 跨平台的桌面应用程序,如使用 electronjs
运行流程
所有内容需要在特定的环境中运行,就像PSD需要在类似PS的软件处理一样。浏览器内置了处理的JS的解析器,但不同浏览器的性能不同,所以JS一般都在浏览器中执行,当然也有可以在服务器后台执行的JS解析器
浏览器的引擎
一个浏览器,通常由两个主要部分组成: 渲染引擎 和 JavaScript引擎
渲染引擎:用来解析 HTML 与 CSS ,俗称内核,比如新版本 Chrome 浏览器的 blink,以及旧版本 Chrome 浏览器的 webkit
JavaScript引擎:也称为 JavaScript 解释器,读取网页中的 JavaScript 代码,逐行解释每一句 JavaScript 代码,将其翻译为机器语言,然后由计算机去执行,比如 Chrome 浏览器的 V8
javascript和HTML结合的方式
1.行内形式
1 |
|
2.内嵌样式表
在页面的 head 里采用 script标签
1 |
|
3.引入外部javascript文件的方式
1 |
|
注释
语法
1 | // 单行注释 |
注意事项
- JS中严格区分大小写
- JS中每一条语句以分号(;)结尾
- 如果不写分号,浏览器会自动添加,但是会消耗一些系统资源,而且有些时候,浏览器会加错分号,所以在开发中分号必须写
- JS中会忽略多个空格和换行,所以我们可以利用空格和换行对代码进行格式化
字面量
定义:一些不可改变的值
例如:1 2 3 4 5
字面量都是可以直接使用,但是我们一般都不会直接使用字面量
变量
定义:可以把变量看做存储数据的容器,而且变量的值是可以任意改变
声明变量
1 | /* |
准则
- 变量必须以字母开头
- 变量也能以 $ 和 _ 符号开头(不过我们不推荐这么做)
- 变量名称对大小写敏感(y 和 Y 是不同的变量)
数据类型
分类
基本(值)类型
类型 | 描述 |
---|---|
字符串(String) | 任意字符串 |
数值(Number) | 任意的数值 |
布尔(Boolean) | true/false |
对空(Null) | null |
未定义(Undefined) | undefined |
表示独一无二的值(Symbol) |
对象(引用)类型
类型 | 描述 |
---|---|
Object(对象) | 任意对象 |
Function(方法) | 特别的对象类型(可以执行) |
Array(数组) | 特别的对象类型(数值下标,内部数据是有序的) |
JS拥有动态类型这意味着相同的变量可用作不同的类型
判断
类型 | 描述 |
---|---|
typeof | 返回数据类型的字符串表达,可以判断:undefined , 数值 , 字符串 ,布尔值,不能判断:null与object 一般object与array |
instanceof | 判断对象的具体类型 |
=== | undefined,null |
1 | <script> |
相关问题
实例
使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类。我们将通过一个构造函数创建的对象,称为是该类的实例
1 | <script> |
undefined与null的区别
undefined代表定义未赋值
null定义并赋值了,只是值为null
1 | <script> |
什么时候给变量赋值为null
初始赋值时,表明将要赋值为对象
结束时,让对象成为垃圾对象(被垃圾回收器回收)
初始化赋值:将要作为引用变量使用, 但对象还没有确定
结束时:将变量指向的对象成为垃圾对象
1 | <script> |
严格区别变量类型与数据类型
js的变量本身是没有类型的,变量的类型实际上是变量内存中数据的类型(js是弱类型的语言)
var a; 判断变量类型,实际上 是判断值的类型
数据的类型(数据对象)
- 基本类型
- 对象类型
变量的类型(变量内存值的类型)
- 基本类型:保存基本类型的数据(保存基本类型数据的变量)
- 引用类型:保存对象地址值(保存对象地址值的变量)
var a={} // a 是一个对象,引用类型、内存引用,a保存的是对象地址值
内存在堆空间中(在堆空间中创建了一个对象),a 在栈空间中
1 | <script> |
数据变量与内存
什么是数据
存储于内存中代表特定信息的“东西”,本质就是0101(二进制)
数据的特点:具有可读、可传递、可运算的基本特性
万物(一切)皆数据,函数也是数据
内存(程序)中所有操作的目标: 数据
* 算术运算
* 逻辑运算
* 赋值
* 运行函数(调用函数传参)
…
什么是内存
内存条通电后产生的可存储数据的空间(临时的)
内存产生和死亡: 内存条(集成电路板)==>通电==>产生一定容量的存储(内存)空间==>存储各种数据==>处理数据==>断电==>内存和数据全部消失
内存的空间是临时的, 而硬盘的空间是持久的
一块内存包含2个数据
- 内部存储的数据(一般数据/地址数据)
- 内存地址值数据
内存分类
- 栈: 全局变量/局部变量 (空间较小)
- 堆: 对象 (空间较大)
什么是变量
值可以变化的量,由变量名与变量值组成
一个变量对应一块小内存,变量名用来查找对应的内存,变量值就是内存中保存的内容
三者之间的关系
内存是一个容器,用来存储程序运行需要操作的数据(内存是用来存储数据的空间)
变量是内存的标识,我们通过变量找到对应的内存,进而操作(读/写)内存中的数据
var a = xxx; a内存中到底保存的是什么?
- 如果xxx 是基本数据,保存的就是这个数据
- 如果xxx 是对象,保存的是对象的地址值
- 如果xxx 是一个变量,保存的xxx的内存内容(可能是基本数据,也可能是地址值)
关于引用变量的赋值问题
2个引用变量指向同一个对象,通过一个变量修改对象内部数据,另一个变量看到的是修改之后的数据
2个引用变量指向同一个对象,让其中一个引用变量指向另一个对象,另一个引用变量依然指向前一个对象
1 | <script> |
在js调用函数时,传递变量参数时,是值传递还是引用传递?
理解1:都是值(基本/地址值)传递
理解2:可能是值传递,也可能是引用传递(内存地址值)
1 | <script> |
js引擎如何管理内存
内存生命周期
- 分配小内存空间,得到它的使用权
- 储存数据,可以反复进行操作
- 释放小内存空间
释放内存
- 释放内存
- 对象:成为垃圾对象–>垃圾回收器回收
Symbol
用于防止属性名冲突而产生的,Symbol 的值是唯一的,独一无二的不会重复的,不可以添加属性
1 | let zhi = Symbol() |
使用description
可以获取传入的描述参数
1 | let di = Symbol("陈若") |
Symbol.for
根据描述获取Symbol,如果不存在则新建一个Symbol
- 使用Symbol.for会在系统中将Symbol登记
- 使用Symbol则不会登记
1 | let di = Symbol.for("陈若") |
Symbol.keyFor
Symbol.keyFor
根据使用Symbol.for
登记的Symbol返回描述,如果找不到返回undefined
1 | let a= Symbol.for("你好") |
对象属性
Symbol 是独一无二的所以可以保证对象属性的唯一
- Symbol 声明和访问使用
[]
(变量)形式操作 - 也不能使用
.
语法因为.
语法是操作字符串属性的
1 | let di = Symbol("陈若") |
String 对象
length
定义:获取字符串长度
1 | <script> |
toUpperCase()方法
定义:用于把字符串转换为大写
1 | var str ="hello, chen ruo" |
toLowerCase()方法
定义:用于把字符串转换为小写
1 | <script> |
trim()方法
定义:用来删除字符串左右的空白字符
1 | <script> |
trimLeft()方法
定义:用来删除字符串左边的空白字符
1 | <script> |
trimRight()方法
定义:用来删除字符串右边的空白字符
1 | <script> |
chartAt()方法
定义:根据从0开始的位置获取字符,获取单字符
1 | <script> |
使用数字索引获取字符串,获取单字符
1 | <script> |
slice()方法
定义:用来提取字符串的某个部分,并以新的字符串返回被提取的部分
start 参数字符串中第一个字符位置为 0, 第二个字符位置为 1, 以此类推,如果是负数表示从尾部截取多少个字符串,slice(-2) 表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)
end 参数如果为负数,-1 指字符串的最后一个字符的位置,-2 指倒数第二个字符,以此类推
1 | <script> |
substring()方法
定义:用来提取字符串中介于两个指定下标之间的字符,返回的子串包括 开始 处的字符,但不包括 结束 处的字符
start参数一个非负的整数,规定要提取的子串的第一个字符在 string Object 中的位置
end参数个非负的整数,比要提取的子串的最后一个字符在 string Object 中的位置多 1
,如果省略该参数,那么返回的子串会一直到字符串的结尾
1 | <script> |
substr()方法
定义:可在字符串中抽取从 开始 下标开始的指定数目的字符
参数指定的是子串的开始位置和长度,因此它可以替代 substring() 和 slice() 来使用
1 | <script> |
indexOf()方法
定义:从开始获取字符串位置,返回位置值,检测不到时返回 -1
1 | <script> |
lastIndexOf()方法
定义:从结尾来搜索字符串位置,返回位置值,检测不到时返回 -1
1 | <script> |
search()方法
定义:用来检索字符串中指定的子字符串,也可以使用正则表达式搜索,返回位置值
1 | <script> |
includes()方法
定义:字符串中是否包含指定的值,第二个参数指查找开始位置
1 | <script> |
startsWith()方法
定义: 用于检测字符串是否以指定的子字符串开始,如果是以指定的子字符串开头返回 true,否则 false,是否是指定位置开始,第二个参数为查找的开始位置,对大小写敏感
1 | <script> |
endsWith()方法
定义:用于检测字符串是否以指定的子字符串开始,如果是以指定的子字符串开头返回 true,否则 false,是否是指定位置结束,第二个参数为查找的结束位置,对大小写敏感
用来判断当前字符串是否是以指定的子字符串结尾的(区分大小写)
如果传入的子字符串在搜索字符串的末尾则返回 true,否则将返回 false
第二参数,设置字符串的长度,默认值为原始字符串长度 string.length
1 | <script> |
replace() 方法
定义:用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串,该方法不会改变原始字符串
1 | <script> |
强制类型转换
将其他类型转换为String
方案一
调用toString()函数
此方式不会影响到原变量,会返回结果
转换对空和未定义,会报错
1 | var bemo = 123 ; |
方案二
调用String()函数
将被转换的数据作为参数传递给函数
1 | var bemo = 123 ; |
将其他类型转换为Number
第一方案
调用Number()函数
1 | /* |
第二方案
调用parseInt()可以将一个字符串中的有效的整数内容去出来,然后转换成Number
parseFloat()和上面的类似,其不同点在于可以获得有效的小数
1 | var bemo = "123.333px" ; |
进制的数字
1 | //十六进制 |
将其他类型转换成Boolean
1 | /* |
引用数据类型
- 对象(Object)
- 数组(Array)
- 函数(Function)
运算符
算术运算符
前提:当对非Number类型的值进行运算时,会将这些值转换成Number再运算
任何值和NaN运算都得NaN
运算符 | 描述 | 注意 |
---|---|---|
+ | 加法 | 1.可以对两个值进行加法运算,并将结果返回;2如果对两个字符串进行加法运算,则会做拼串,会将两个字符串拼接为一个字符串,并返回;任何的值和字符串做加法运算,都会先转换成字符串,再和字符串做拼串的操作 |
- | 减法 | 可以对两个值进行减法运算,并将结果返回 |
* | 乘法 | 可以对两个值进行乘法运算 |
/ | 除法 | 可以对两个值进行除法运算 |
% | 取模(余数) | 取余数 |
++ | 自增 | |
– | 自减 |
任何值做 - * / 运算时都会自动转换成 Number
- 可以利用这一特点做隐式的类型转换
- 可以通过为一个值 -0 *1 /1 来将其转换成Number
一元运算符
正号:不会对数字产生任何影响
负号:可以对数字进行负号取反
对于非Number类型的值
- 会将先转换成Number,再运算
- 可以对一个其他的数据类型使用+ ,来将其转换成Number
1 | var bemo = 1024 ; |
逻辑运算符
逻辑非运算符
定义:首先把数据转化为布尔值,然后取反,结果为 true
或 false
如果对非布尔值进行元素,则会将其转换成布尔值,然后再取反
- 可以利用这一特性,来将其他数据类型转换成布尔类型
- 为任意数据类型取两次反,来做到转换成布尔值
转换情况
1 | // 字符串 转换成 布尔 |
1 | var bemo = 123 ; |
逻辑与运算符
定义:如果第一个操作数为 true
,计算结果就是第二个操作数。如果第一个操作数为 false
,结果就是 false
(特殊数值除外)
1 | var bemo = 1234 , bemo1 = 1024 ; |
逻辑或运算符
定义:如果第一个操作数能够转为 true
(不是 false
),结果就是第一个操作数,否则结果是第二个操作数
1 | var bemo = 1234 , bemo1 = 1024 ; |
非布尔值的情况
定义:会先将其转换为布尔值,进行运算,再返回原值
赋值运算符
定义:将符号右侧的值赋值给符号左侧的变量
1 | // var bemo = 1234 ; |
关系运算符
条件运算符
定义:先算条件表达式,若条件表达式为真则执行语句1,并返回执行结果。如果条件表达式为假false,则执行语句2,并返回执行结果。如果条件表达式的值是非布尔值则会转换成布尔值
语法
1 | //条件表达式 ? 语句1 : 语句2 ; |
复杂的条件,不推荐使用,可读性差
1 | var bemo = 1 , bemo1 = 2 ,bemo3 = 3 ; |
优先级
for语句
语法
1 | for (初始化表达式; 条件表达式; 更新表达式) |
流程
1.执行初始化表达式,初始化变量(只执行一次)
2.执行条件表达式,判断是否执行循环
3.是否执行更新表达式,是则继续重复循环
1 | var i = 0 ; //初始化表达式 |
嵌套for
定义: 外层循环转一次,内层循环转一圈,外层循环控制行数,内层循环控制每行元素个数
1 | for ( 初始化表达式 ; 条件表达式 ; 更新表达式) |
死循环
定义:当循环条件一直为真时,就会陷入死循环,应尽量避免死循环
原因:
1.循环条件不写时,循环条件默认值为true
2.如果循环变量初始值满足循环条件,并且没有更新循环变量
for版
1 | // for循环中不写任何表达式,只写两个; 是一个死循环,会一直执行下去,但谨慎使用 |
break
定义:break出现后,就不再执行循环体,同时结束循环
语法
1 | // break用法 |
continue
定义:continue出现后,会跳出(结束)本次循环,但还会执行下一次循环
1 | // continue用法 |
对象
定义:属于一种复合的数据类型,可以存储多个不同类型的属性
分类
1.内建对象
- 由ES标准中定义的对象,在任何的ES的实现中都可以使用
2.宿主对象
- 由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象
3.自定义对象
- 由开发人员自己创建的对象
创建对象
第一种方式
使用new关键字调用函数,是构造函数constructor,构造函数是专门用来创建对象的函数
1 | var obj = new Object(); |
第二种方式
1 | var obj = { |
添加对象的属性
属性:在对象中保存的值
语法
第一种方式
1 | 对象.属性名 = 属性值 ; |
第二种方式
如果要使用特殊的属性名,不能采用.的方式,还有另一个方式
读取时也需要采用这种方式
使用[]这种方式操作属性,更加灵活,可以直接传递一个变量,这样变量值是多少就会读取那个属性
语法
1 | 对象["属性名"] = 属性值 ; |
读取对象中的属性
语法
1 | 对象.属性名 ; |
注意:如果读取对象中没有的属性不会报错会返回undefined
修改对象的属性值
语法
1 | 对象.属性名 = 新值 ; |
删除对象的属性
语法
1 | delete 对象.属性名 ; |
属性值
定义:JS对象的属性值,可以是任意的数据类型,也可以是一个对象
例子
1 | var obj = new Object() ; //创建对象 |
in 运算符
定义:通过该运算符可以检查一个对象中是否含有指定的属性,有则返回true,反之返回false
语法
1 | "属性名" in 对象 ; |
栈和堆的知识
js中的变量都是保存到栈内存中的,变量和基本数据类型的值直接在栈内存中存储,值与值之间是独立存在的,修改一个变量的值不会影响其他的变量
对象是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的空间,而变量保存的是对象的内存地址(对象的引用),若两个变量保存的是同一个对象的引用,则一个变量改变,另一个也会随之改变
1 | var bemo1 = { |
函数
定义:由一连串的子程序(语句的集合)所组成的,可以被外部程序调用,向函数传递参数之后,函数可以返回一定的值
JavaScript代码是自上而下执行的,不过函数体内部的代码则不是这样,如果只是对函数进行了声明,其中的代码并不会执行,只有在调用函数时才会执行函数体内部的代码,JavaScript中的函数也是一个对象,使用typeof检查一个函数对象时,会返回function
创建
使用函数对象方式
语法
1 | var 函数名 = new Function("执行语句"); |
使用函数声明方式(推荐)
语法
1 | function 函数名([形参1,形参2,...,形参N]) { |
使用函数表达式方式(推荐)
1 | var 函数名 = function([形参1,形参2,...,形参N]) { |
函数调用
无参函数的调用
1 | //函数声明 |
有参函数的调用
1 | // 可以在函数的()中来指定一个或多个形参 |
函数返回值
定义:可以使用 return 来设置函数的返回值,return后的值将会作为函数的执行结果返回,可以定义一个变量,来接收该结果
注意:在函数中return后的语句都不会执行,如果return语句后不跟任何值就相当于返回一个undefined,如果函数中不写return,则也会返回undefined,return后可以跟任意类型的值
1 | function sum (i ,j) |
立即执行函数
定义:函数定义完,立即被调用,往往只会执行一次
1 | (function () { |
枚举对象中的属性
for…in语句
语法
1 | //for...in语句 对象中有几个属性,循环体就会执行几次 |
嵌套函数
定义:在函数中声明的函数就是嵌套函数,只能在当前函数中可以访问,在当前函数外无法访问,类似局部作用域中的局部作用域
1 | function fasther() |
匿名函数
定义:没有名字的函数,它可以让一个变量来接收,也就是用 “函数表达式” 方式创建和接收
1 | var bemo = function () |
对象中的函数
对象的属性值可以是任何的数据类型,也可以是个函数
如果一个函数作为一个对象的属性保存,那么我们称这个函数是这个对象的方法,调用这个函数就说调用对象的方法(method)
注意:方法和函数只是名称上的区别,没有其它别的区别
1 | var bemo = |
this对象
解析器在调用函数每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是this,this指向的是一个对象,这个对象我们称为函数执行的上下文对象,根据函数的调用方式的不同,this会指向不同的对象
- 以函数的形式调用时,this永远都是window
- 以方法的形式调用时,this就是调用方法的那个对象
1 | function bemo () |
作用域
作用域指一个变量的作用的范围
声明提前
- 变量的声明提前:使用var关键字声明的变量,会在所有的代码执行之前被声明(但是不会赋值),但是如果声明变量时不使用var关键字,则变量不会被声明提前
- 函数的声明提前:使用函数声明形式创建的函数 function 函数名(){} ,它会在所有的代码执行之前就被创建,所以我们可以在函数声明前来调用函数。使用函数表达式创建的函数,不会被声明提前,所以不能在声明前调用
全局作用域
直接编写在script标签中的JavaScript代码,都在全局作用域
全局作用域在页面打开时创建,在页面关闭时销毁
在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,它由浏览器创建,我们可以直接使用
在全局作用域中:
创建的变量都会作为window对象的属性保存
创建的函数都会作为window对象的方法保存
全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问的到
函数作用域
调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁
每调用一次函数就会创建一个新的函数作用域,它们之间是互相独立的
在函数作用域中可以访问到全局作用域的变量,在全局作用域中无法访问到函数作用域的变量
在函数中要访问全局变量可以使用window对象
作用域链:当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用,如果没有则向上一级作用域中寻找,直到找到全局作用域,如果全局作用域中依然没有找到,则会报错ReferenceError
作用域链
多个上下级关系的作用域形成的链,它的方向是从下向上的(从内到外),查找变量时就是沿着作用域链来查找的。
查找一个变量的查找规则:
在当前作用域下的执行上下文中查找对应的属性,如果有直接返回,否则进入2
在上一级作用域的执行上下文中查找对应的属性,如果有直接返回,否则进入3
再次执行2的相同操作,直到全局作用域,如果还找不到就抛出找不到的ReferenceError异常
debug
this
解析器在调用函数每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是this,this指向的是一个对象,这个对象我们称为函数执行的上下文对象,根据函数的调用方式的不同,this会指向不同的对象
- 以函数的形式调用时,this永远都是window
- 以方法的形式调用时,this就是调用方法的那个对象
1 | function bemo () |
对象进阶
使用工厂方法创建对象
使用工厂方法创建对象,使用的构造函数都是Object,所以创建的对象都是Object这个类型,就导致我们无法区分多种不同类型的对象
1 | // 使用工厂模式创建对象 |
使用构造函数创建对象
创建一个构造函数,专门用来创建Person对象的
构造函数就是一个普通函数,创建方式和普通函数没有区别
不同的是构造函数习惯首字母大写
之间的区别(调用方式不同)
- 普通函数是直接调用
- 构造函数是需要使用new关键字来调用
构造函数的执行流程
1.立刻创建一个新的对象
2.将新建的对象设置为函数中this
3.逐行执行函数中的代码
4.将新建的对象作为返回值返回
1 | function Person (name ,age ) |
使用同一个构造函数的对象,我们称为一类对象,也将一个构造函数称为一个类
我们将通过一个构造函数创建的对象,称为是该类的实例
this的情况
1.当以函数的形式调用时,this是window
2.当以方法的形式调用时,谁调用方法this就是谁
3.当以构造函数的形式调用时,this就是新创建的那个对象
使用Instanceof可以检查一个对象是否是一个类的实例
语法
1 | 对象 instanceof 构造函数 |
例子
1 | alert (person instanceof Person1); |
原型
创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,这个对象就是我们所谓的原型对象
如果函数作为普通函数调用prototype没有任何作用
当函数以构造函数的形式调用时,所创建的对象中都会有一个隐含属性,指向该构造函数的原型对象,我们可以通过__ proto __来访问属性
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,可以将对象中共有的内容,统一设置到原型对象中
当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用
以后创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,可以减少代码的复用程度,不会影响全局作用域
原型链
访问一个对象的属性时,先在自身属性中查找,找到返回, 如果没有,再沿着__proto__这条链向上查找,找到返回,如果最终没找到,返回undefined,这就是原型链,又称隐式原型链,它的作用就是查找对象的属性(方法)
toString()
垃圾回收(GC)
我们需要一个垃圾回收的机制,来处理程序运行过程中产生的垃圾
当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,此时它便是一个垃圾,会占用大量的内存空间,导致程序运行变慢,因此需要清理程序垃圾
在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,所以不需要手动进行垃圾清理回收的操作,需要做的只是要将不再使用的对象设置null即可
1 | function bemo () |
流程控制
if
当条件为真时执行表达式代码块。
1 | let state = true; |
如果只有一条代码块,可以不用写 {}
1 | let state = true; |
if/else
下面是使用多条件判断密码强度的示例
1 | <body> |
三元表达式
是针对 if
判断的简写形式。
1 | let n = true ? 1 : 2; |
switch
可以将 switch
理解为 if
的另一种结构清晰的写法。
- 如果表达式等于
case
中的值,将执行此case
代码段 break
关键字会终止switch
的执行- 没有任何
case
匹配时将执行default
代码块 - 如果
case
执行后缺少break则接着执行后面的语句
1 | let a = "陈若" |
case 合用示例
1 | switch(a){ |
在switch
与 case
都可以使用表达式
1 | function message(age) { |
下面例子缺少break 后,会接着执行后面的switch代码
1 | switch (1) { |
while
循环执行语句,需要设置跳出循环的条件否则会陷入死循环状态。下面是循环输出表格的示例
1 | let row = 5 |
do/while
后条件判断语句,无论条件是否为真都会先进行循环体
下面通过循环输出三角形示例,要注意设置循环跳出的时机来避免死循环
1 | function demo(row = 5) { |
for
可以在循环前初始化初始计算变量。下面是使用for
打印倒三角的示例
1 | for (let i = 10; i > 0; i--) { |
for的三个参数可以都省略或取几个
1 | let i = 1 |
break/continue
break用于退出当前循环,continue用于退出当前循环返回循环起始继续执行
获取所有偶数,所有奇数使用 continue
跳过
1 | for (let i = 1; i <= 10; i++) { |
获取三个奇数,超过时使用 break
退出循环
1 | let a = 0 |
label
标签(label) 为程序定义位置,可以使用continue/break
跳到该位置
1 | top: |
上面代码为一个双重循环区块,break命令后面加上了top标签(注意,top不用加引号),满足条件时,直接跳出双层循环。如果break语句后面不使用标签,则只能跳出内层循环,进入下一次的外层循环
标签也可以用于跳出代码块
1 | demo:{ |
上面代码执行到break demo,就会跳出区块
continue语句也可以与标签配合使用
1 | top: |
上面代码中,continue命令后面有一个标签名,满足条件时,会跳过当前循环,直接进入下一轮外层循环。如果continue语句后面不使用标签,则只能进入下一轮的内层循环
for/in
用于遍历对象的所有属性,for/in
主要用于遍历对象,不建议用来遍历数组
遍历数组操作
1 | let demo = [{ name: "陈若", age: 18 }, |
遍历对象操作
1 | let demo = { name: "陈若", age: 18 } |
遍历window对象的所有属性
1 | for (name in window) { |
for/of
用来遍历 Arrays(数组), Strings(字符串), Maps(映射), Sets(集合)等可迭代的数据结构
与 for/in
不同的是 for/of
每次循环取其中的值而不是索引
1 | let arr = [1, 2, 3]; |
遍历字符串
1 | let str = 'hahahahahaahhhhh' |
使用迭代特性遍历数组
1 | const demo = ["陈若", "284122"] |
使用for/of
也可以用来遍历DOM元素
1 | <body> |
对象
什么是对象
- 多个数据的封装体
- 用来保存多个数据的容器
- 一个对象代表现实中的一个事物
为什么要用对象
统一管理多个数据
对象的组成
属性:属性名(字符串)和属性值(任意)组成
方法:一种特别的属性(属性值是函数)
如何访问对象内部的数据
属性名: 编码简单,有时不能用
["属性名"]
:编码麻烦,能通用
什么时候使用 [“属性名”] 这种方式
属性名包含特殊字符:- 空格等
属性名不确定
1 | <script> |
数组
数组也是对象的一种,数组是一种用于表达有顺序关系的值的集合的语言结构,也就是同类数据元素的有序集合
数组的存储性能比普通对象要好,在开发中我们经常使用数组来存储一些数据。但是在JavaScript中是支持数组可以是不同的元素,这跟JavaScript的弱类型有关,此处不用纠结,我们大多数时候都是相同类型元素的集合。数组内的各个值被称作元素,每一个元素都可以通过索引(下标)来快速读取,索引是从零开始的整数
使用typeof检查一个数组对象时,会返回object
创建数组
使用对象创建
同类型有序数组创建
1 | var arr= new Array(); |
不同类型有序数组创建
1 | var arr = new Array() ; |
使用字面量创建
同类型有序数组创建
1 | var arr = [1,2,3,4,5,6,7,8,9,10]; |
不同类型有序数组创建
1 | var arr = [1,"2",3,"4",5,"6"]; |
遍历数组
1 | var arr = new Array() ; |
数组属性
constructor属性
定义:返回创建数组对象的原型函数
1 | var arr = [1,2,3,4,5,6,7]; |
length属性
定义:设置或返回数组的长度(元素的个数)
对于连续的数组,使用length可以获取到数组的长度(元素的个数)
对于非连续的数组,使用length会获取到数组的最大的索引+1
注意:尽量不要使用非连续的数组
1 | var arr = [1,2,3,4,5,6,7,8,9,10] ; |
数组方法
push()方法(末尾添加)
定义:向数组的末尾添加一个或多个元素,并返回数组的新长度
1 | var bemo = ["亚当斯密" , "大卫·李嘉图" , "马克斯·韦伯" , "阿尔弗雷德·马歇尔" , "米尔顿·弗里德曼"] ; |
pop()方法(末尾删除)
定义:可以删除数组的最后一个元素,并将被删除的元素作为返回值返回
1 | var pop = ["亚当斯密" , "大卫·李嘉图" , "马克斯·韦伯" , "阿尔弗雷德·马歇尔" , "米尔顿·弗里德曼"] ; |
unshift()方法(开头添加)
定义:向数组开头添加一个或多个元素,并返回新的数组长度
1 | var unshift = ["亚当斯密" , "大卫·李嘉图" , "马克斯·韦伯" , "阿尔弗雷德·马歇尔" , "米尔顿·弗里德曼"] ; |
shift()方法(开头删除)
定义:可以删除数组的第一个元素,并将被删除的元素作为返回值返回
1 | var shift = ["亚当斯密" , "大卫·李嘉图" , "马克斯·韦伯" , "阿尔弗雷德·马歇尔" , "米尔顿·弗里德曼"] ; |
语法
1 | var arr = new Array(); |
Object.keys()方法
定义:遍历对象,并返回对象属性以数组的形式返回
1 | const demo = { |
forEach()方法(用于遍历数组)
定义:数组中有几个元素函数就会执行几次,每次执行时,浏览器会将遍历到的元素,以实参的形式传递进来,我们可以来定义形参,来读取这些内容
参数
- 第一个参数,当前正在遍历的元素
- 第二个参数,当前正在遍历的元素的索引
- 第三个参数,正在遍历的数组
注意:这个方法只支持IE8以上的浏览器,IE8及以下的浏览器均不支持该方法,所以如果需要兼容IE8,则不要使用forEach(),还是使用for循环来遍历数组
1 | var bemo = ["亚当斯密" , "大卫·李嘉图" , "马克斯·韦伯" , "阿尔弗雷德·马歇尔" , "米尔顿·弗里德曼"] ; |
map()方法
定义:使用 map
映射可以在数组的所有元素上应用函数,用于映射出新的值
- 第一个参数,当前正在遍历的元素
- 第二个参数,当前正在遍历的元素的索引
- 第三个参数,正在遍历的数组
获取数组所有name组合的新数组
1 | let a = [{ |
为所有name添加上 迪迦
1 | let a = [{ |
filter()方法
定义:创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素
参数
- 第一个参数,用来测试数组的每个元素的函数,返回 表示该元素通过测试,保留该元素, 则不保留。它接受以下三个参数:
- 数组中当前正在处理的元素(必选)
- 正在处理的元素在数组中的索引(可选)
- 调用了 的数组本身(可选)
- 第二个参数,执行 时,用于 的值
语法:
1 | var newArray = arr.filter(callback(element[, index[, array]])[, thisArg]) |
1 | function isBigEnough(element) { |
slice()方法(提取指定元素)
定义:用于从数组提取指定元素,特点不会改变元素原数组,而是将截取到的元素封装到一个新的数组中返回
参数
- 第一个参数,截取开始位置的索引,包含开始的索引元素
- 第二个参数,截取结束位置的索引,不包含结束的索引元素,可以省略不写,此时会截取从开始索引往后的所有元素
注意事项:索引可以传递一个负值,如果传递一个负值,则从后往前计算,例如,-1代表倒数第一个,-2代表倒数第二个
1 | var bemo = ["亚当斯密" , "大卫·李嘉图" , "马克斯·韦伯" , "阿尔弗雷德·马歇尔" , "米尔顿·弗里德曼"]; |
splice()方法(删除指定元素)
定义:用于从数组删除指定元素,特点会改变元素原数组,并将删除的元素以返回值的方式返回
参数
- 第一个参数,开始位置的索引
- 第二个参数,需要删除的元素数量
- 第三个参数等往后的参数,可以传递一些新的元素,这些元素将会自动插入到开始位置索引前边
1 | var bemo = ["亚当斯密" , "大卫·李嘉图" , "马克斯·韦伯" , "阿尔弗雷德·马歇尔" , "米尔顿·弗里德曼"]; |
concat()方法(连接数组)
定义:连接两个或多个数组,并返回新的数组,并不会影响原数组
1 | var arr = ["亚当斯密" , "大卫·李嘉图"]; |
join()方法(连接字符串数组)
定义:将数组转换为一个字符串,该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回,在join()中可以指定一个字符串作为参数,这个字符串将会成为数组中元素的连接符,如果不指定连接符,则默认使用,作为连接符
1 | var bemo = ["陈平","林毅夫","张维为","朗咸平","李季"]; |
reverse()方法(位置翻转)
定义:将数组的位置进行翻转,修改原数组
1 | var bemo = ["陈平","林毅夫","张维为","朗咸平","李季"]; |
sort()方法(数组元素排序)
定义:用于对数组元素的进行排序,会影响原数组,默认会按照Unicode编码进行排序
注意:即使对于纯数字的数组,使用sort()排序时,也会按照Unicode编码来排序,所以对数字进排序时,可能会得到错误的结果
按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字,比较函数应该具有两个参数 a 和 b
- 若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值
- 若 a 等于 b,则返回 0
- 若 a 大于 b,则返回一个大于 0 的值
总结
- 如果需要升序排列,则返回 a-b
- 如果需要降序排列,则返回 b-a
1 | var bemo = ["陈平","林毅夫","张维为","朗咸平","李季"]; |
函数
什么是函数
实现特定功能的n条语句的封装体
只有函数是可以执行的,其他类型的数据不能执行
如何定义函数
函数声明
表达式
1 | <script> |
如何调用函数?
test(); 函数名(); 直接调用
obj.test(); 通过对象调用
new test(); new调用
test.call/apply(obj); 临时让test成为obj的方法进行调用
回调函数
什么是回调函数
- 自己定义的
- 没有调用的
- 最终执行了(在某个时刻或某个条件下)
常见的回调函数
1.dom事件的回调函数
2.定时器的回调函数
3.ajax请求的回调函数
4.生命周期的回调函数
1 | <button id="btn01">回调函数</button> |
IIFE
IIFE 全称:Immediately-Invoked Function Expression (立即调用函数表达式),别名:匿名函数自调用
特点:
隐藏内部实现
不会干扰到外部(全局)命名空间
主要用它来编码js模块
1 | <script> |
call()和apply()方法
定义:在调用call()和apply()可以将一个对象指定为第一个参数,此时这个对象将会成为函数执行时的this
call()
可以将实参在对象之后依次传递
1 | function fun ( a, b ) { |
注意:默认fun()函数调用,this指向的是window对象,可以使用call()调用函数,在调用的时候传入一个对象,这个对象就是this所指向的对象,也就是说,可以自己指定this的指向,然后从第二个参数开始,实参将会依次传递
apply()
需要将实参封装到一个数组中统一传递
1 | function fun ( a, b ) { |
注意:默认fun()函数调用,this指向的是window对象,可以使用apply()调用函数,在调用的时候传入一个对象,这个对象就是this所指向的对象,也就是说,可以自己指定this的指向,然后从第二个参数开始,需要制定一个实参数组进行参数传递
this
什么是this
- 以函数的形式调用,this永远都是window
- 以方法的形式调用,this永远都是调用方法的对象
- 以构造函数的形式调用,this永远都是新创建的那个对象
- 以call()和apply()的形式调用,this永远都是传入的那个指定对象
如何确定this的值
- test(); window
- p.test(); p
- new test(); 新创建的对象
- p.call(obj); obj
1 | <script type="text/javascript"> |
1 | function ponit(i, j) { |
arguments参数
当在调用函数时,浏览器每次都会传递进两个隐含的参数:
- 函数的上下文对象: this
- 封装实参的对象: arguments
定义:是一个类数组对象,可以通过索引来操作数据,也可以获取长度,在调用函数时,所传递的实参都会在arguments中保存
在这里有一个属性叫做callee,这个属性对应一个函数对象,就是当前正在指向的函数的对象
1 | function fun ( a , b ) |
Date对象
Date是javascript中表示时间的对象,如果直接使用构造函数创建一个Date对象,则会封装为当前代码执行的时间
1 | var bemo = new Date(); |
Math对象
此对象是属于一个工具类,既不用创建对象,也不是构造函数,因为此对象里面封装了数学运算相关的属性和方法
固定值
1 | console.log("PI = "+Math.PI); // 返回欧拉数 |
正数
1 | console.log(Math.abs(2333)); //用来计算一个数的绝对值 |
负数
1 | console.log(Math.abs(-1024)); //用来计算一个数的绝对值 |
随机数
1 | //Math.random():可以用来生成一个0-1之间的随机数 |
数学运算
1 | console.log(Math.pow(2,3));//Math.pow(x,y),是用来返回x的y的次幂 |
还有更多的属性和使用方式,就不一一说明了,参考网站Math对象
RegExp对象
正则表达式用于定义一些字符串的规则,计算机可以根据正则表达式,来检查一个字符串是否符合规则,获取将字符串中符合规则的内容提取出来
简单一点理解,正则表达式就是给计算机看的规则,又称为规则表达式
创建正则对象
字面量创建方式
语法
1 | var 变量名 = /正则表达式/匹配模式; |
1 | //这个正则表达式是用来检查一个字符串中是否含有陈若 |
对象创建方式
语法
1 | var 变量名 = new RegExp("正则表达式","匹配模式"); |
匹配模式:
- i:忽略大小写
- g:全局匹配模式
- ig:忽略大小写且全局匹配模式
注意:可以为一个正则表达式设置多个匹配模式,且顺序无所谓
1 | //这个正则表达式是用来检查一个字符串中是否含有tool |
正则逻辑
创建一个正则表达式,检查一个字符串中是否有陈若或林俊杰或周杰伦
语法:使用 | 表示或者的意思
1 | // 这个正则表达式可以来检查一个字符串中是否含有陈若或林俊杰或周杰伦 |
创建一个正则表达式,检查一个字符串中是否有字母
语法:**[ ] 里的内容也有或的关系
1 | //这个正则表达式可以用来检查一个字符串中是否含有字母 |
或组合
[ab]:等于/a|b/
[a-z]:任意小写字母
[A-Z]:任意大写字母
[A-z]:任意字母
[0-9]:任意数字
创建一个正则表达式,检查一个字符串中是否含有abc或adc或aec
1 | //这个正则表达式可以用来检查一个字符串中是否含有abc或adc或aec |
非组合
[^ab]:等于c除了/a|b/
[^a-z]:除了任意小写字母
[^A-Z]:除了任意大写字母
[^A-z]:除了任意字母
[^0-9]:除了任意数字
创建一个正则表达式,检查一个字符串中是否除了数字还有其它字母
1 | //这个正则表达式,可以检查一个字符串中是否除了数字还有其它字母 |
正则方法
**test()**方法
定义:可以用来检查一个字符串是否符合正则表达式的规则,如果符合则返回true,否则返回false
1 | var reg = new RegExp("陈若","i"); |
**split()**方法
定义:可以用来将一个字符串拆分为一个数组,此方法可以传递一个正则表达式作为参数,会根据正则表达式进行拆分字符串,即使不指定全局匹配,也会全都拆分
1 | var str = "1a2b3c4d5e6f7"; |
**search()**方法
定义:可以用来检查字符串中是否含有指定的内容,如果有,则会返回第一次出现的索引位置,如果没有,则会返回-1,此方法接受一个正则表达式作为其参数,然后会根据正则表达式搜索字符串,但只会检查第一个,即使设置为全局匹配也无效
1 | var str = "This world belongs to the people"; |
**match()**方法
定义:可以用来从一个字符串中查找含有指定内容并提取出来,在默认情况下,只会查找到第一个,找到以后就会停止查找,但我们可以设置全局匹配模式,或多个匹配模式,会将查找到的返回封装到一个数组中,即使只查找到一个结果
1 | var str = "123qwe456rty789uio0p"; |
**replace()**方法
定义:可以用来将字符串指定内容替换成新的内容,默认情况下只会替换第一个,但是可以设置匹配模式
参数:
- 第一个参数,被替换的内容,可以接受一个正则表达式作为其参数
- 第二个参数,新的内容
1 | var str = "123qwe456rty789uio0p"; |
正则量词
通过量词可以设置一个内容出现的次数,量词只对它前边的一个内容起作用,如果有多个内容可以使用 ()
括起来,常见量词如下
{n}
:正好出现n次{m,}
:出现m次及以上{m,n}
:出现m-n次+
:至少一个,相当于{1,}*
:0个或多个,相当于{0,}?
:0个或1个,相当于{0,1}
1 | var str = "我的音乐都是,杰伦杰伦yyds"; |
要检查或者说判断是否以某个字符或者字符序列开头或者结尾就会使用^
和$
^
:表示开头,注意它在[^字符序列]
表达的意思不一样$
:表示结尾
1 | var str = "陈若 ,真是一个品学兼优的优秀青年啊------陈若"; |
要检查一个字符串中是否含有.
和\
就会使用转义字符
\.
:表示.
\\
:表示\
注意:使用构造函数时,由于它的参数是一个字符串,而\
是字符串中转义字符,如果要使用\
则需要使用\\
来代替
1 | var str = "\\迪迦.奥特曼\\"; |
其余的转义字符
\w
:任意字母、数字、,相当于[A-z0-9]\W
:除了字母、数字、,相当于[^A-z0-9]\d
:任意的数字,相当于[0-9]
\D
:除了任意的数字,相当于[^0-9]
\s
:空格\S
:除了空格\b
:单词边界\B
:除了单词边界
要消除用户昵称中字符串的前后空格
1 | var str = prompt("请输入你的昵称:"); |
检查一个字符串中是否含有单词wizard(巫师)
1 | var str ="I'm a wizard "; |
检查一个字符串中是否含有手机号
1 | var str = prompt("请输入你的手机号\:"); //瞎写的电话号码,别妄想,打骚扰电话给我 |
检查一个邮件号是否符合规格
1 | //邮件号思路 |