【无标题】JS寒假集训

初识JS

书写位置

1.内嵌式
在html文件里的<head></head><body></body>中加入<script></script>标签
2.行内式
在这里插入图片描述
在这里插入图片描述

双引号中再有引号改用单引号

3.外链式(推荐)
在head中加入<script></script>标签,并在src引用路径
在这里插入图片描述

当引入文件时,<script>中的内嵌代码失效

注释与规范

单行注释:Ctrl+/
多行注释:alt+shift+a
规范:
一、不建议一句代码后面加分号,直接换下一行
二、如果两句代码在同一行,需要分号隔开

JS的变量

变量指的是在程序中保存数据的一个容器,变量是计算机内中存储数据的标识符,根据变量名称可以获取到内纯中存储的数据,也就是说,我们向内存中存储了一个数据,然后要给这个数据起一个名字,为了是我们以后再次找到他

语法

var 变量名=值

定义变量不赋值:
var 变量名
var 变量名,变量名,变量名

定义变量赋值:
var 变量名=值
var 变量名=值,变量名=值,变量名=值

变量命名规则和规范

规则:必须遵守,不遵守就会报错
1.一个变量名字可以由数字,字母,下划线,$组成
2.严格区分大小写
3.不能由数字开头
4.不能是保留字关键字
5.不要出现空格

规范:建议遵守,不遵守不会报错
1.变量名尽量有意义(语义化)可以用拼音或英文
2.遵循驼峰命名规则,由多个单词组成的时候,从第二个单词开始首字母大写
3.不要用中文

注意加引号就是普通字符,不加引号才是变量名

数据类型

简单类型

1.Number(数字类型)
例:整数,小数(浮点数),科学计数法(e=10),十六进制(0x数字),八进制(0数字),二进制(0b数字),NaN(not a number 不是数值)

2e3=2*10^3

2.String(字符串类型)
变量值加引号写的是什么就输出什么

3.Boolean
值一共两个 true (真)、false(假)

4.Undefined
var 变量名(或者var 变量名=undefined)
声明但未负值(当下不知道要赋什么值,也可能以后不赋值)

5.Null
var 变量名=null
未来知道一定会赋值对象,一开始先赋值null

6.Symbol

复杂类型

数据类型的检测判断

typeof关键字判断
法一:
console.log(typeof 变量名)
法二:
console.log(typeof(变量名))
判断结果一定显示是字符串

法一法二区别:
当进行运算判断时
法一会从左往右依次运算
法二会先算括号内的
例:
在这里插入图片描述在这里插入图片描述
法一出来的为number100,而法二出来的是number

数据类型转换——转数值

法一:
var 变量2=Number(变量1)
可以把一个变量值强制转换成数值类型
可以转换小数,会保留小数
可以转换布尔值
遇到不可转换的都会返回显示NaN

强制转换true和false时会显示1和0
null会转成0

法二:
var 变量2=parseInt(变量1)
从第一位开始检查,是数字就开始转换,遇到非数字停止
在这里插入图片描述

在这里插入图片描述

开头不是数字,直接返回显示NaN
int整数型,不认识小数点,只能保留整数
在这里插入图片描述
在这里插入图片描述
法三:
var 变量2=parseFloat(变量1)
从第一位开始检查,是数字就开始转换,遇到非数字停止
开头不是数字,直接返回显示NaN
Float浮点型,认识一次小数点

法四:
非加号运算符
运算符两边必须都为可运算数字,否则返回显示NaN
在这里插入图片描述

数据类型转换——转字符串

法一:
var 变量2=String(变量1)
所有类型都能转成字符串

法二:
var 变量2=变量1.toString()
有一些数据类型不能使用.toString()方法,比如undefined和null

法三:
加号运算符
var 变量2=变量1+“(什么都不加,空字符串)”
只要+任意一边是字符串,就会进行字符串拼接(变成字符串)

数据类型转换——转布尔(Boolean)

Boolean(变量)
在js中,只有 空字符串、0、null、undefined、NaN是false
其余都是true

运算符

数字运算符(从左到右,乘除优先)

1.+:
只有+两边都是数字的时候才进行加法运算

如果是true+数字,true会自动转换成1

只要+任意一边是字符串,就会进行字符串拼接

2.-:
会执行减法运算
会自动把两边都转换成数字进行运算

3.*:
会执行乘法运算
会自动把两边都转换成数字进行运算

4. /除法 %取余
会执行除法运算
会自动把两边都转换成数字进行运算

例:分钟换算成小时:分
在这里插入图片描述在这里插入图片描述

赋值运算符

1.=:
把=右边的赋值给左边的变量名

实现交换两个数
在这里插入图片描述

2.+=
表示变量在自身上加一个数
number=number+1等价于number+=1

3.-=
表示变量在自身上减一个数

4.*=
表示变量在自身上乘一个数

5./= 或 %/
表示变量在自身上除或除余一个数

比较运算符

1.=

2.>

3.<

4.>=

5.<=

6.==:
比较符号两边的值是否相等,不管数据类型

1==“1”
虽然一个是数字一个是字符串,但两个值一样的,所以得到true

6.===:
比较符号两边的值是否相等,需要看数据类型

1===“1”
虽然两个值一样的,但一个是数字一个是字符串,所以得到false

7.!=:
比较两边值是否不等

1!=“1”
因为两边值一样,所以得到false

8.!==:
比较两边值和数据类型是否不等

1!=“1”
因为两边数据类型不一样,所以得到true

逻辑运算符

1.&&:
进行 “且” 的运算
符号左边和右边必须都为true才能返回true
只要有一边不是true,就返回false
在这里插入图片描述

2.||:
进行 “或” 的运算
符号左右都为false才能返回false
只要有一边不是false,就返回true
在这里插入图片描述

3.!:
进行 “取反” 运算
本身是true的,会变成false
本身是false的,会变成true

!!变量,转换成布尔值
短路用法(&&和||)

如果想让代码继续而不出现报错停掉代码
可以运用&&或||实现
且的特殊用法:在这里插入图片描述
在这里插入图片描述y为假的话,不用考虑后面了,不会强制转换进行报错
在这里插入图片描述在这里插入图片描述
或的特殊用法:在这里插入图片描述
在这里插入图片描述z加上赋值之后就为真了,就不用考虑后面的,后面没机会执行
在这里插入图片描述
在这里插入图片描述

自增自减运算符

1.加加
进行自增运算
分成两种,前置++和后置++
前置++,会先把值自动+1,再返回
(先加+1再赋值)
后置++,会先把值返回,在自动+1
(先加赋值再+1)

2.减减
进行自减运算
分成两种,前置–和后置–
和++运算符道理一样

三元运算符

语法:条件? 条件为true 的时候执行 :条件为false 的时候执行
var age = 18
age >= 18 ? alert(‘已经成年’):alert(‘没有成年’)

if条件分支结构

通过一个if语句来决定代码是否执行
语法:
if (条件) {要执行的代码}
通过()里面的条件是否成立来决定{}里面的代码是否执行

if else语句

通过if条件来决定,执行哪一个{}里面的代码
语法:
if (条件) {条件为true 的时候执行}
else {条件为false 的时候执行}

注:两个{}内的代码一定有一个会执行

if else if …语句

可以通过if和eIlse if来设置多个条件进行判断
语法:
if (条件1) {条件1为true的时候执行}
else if (条件2) {条件2为true的时候执行}
else if (条件3) {条件3为true的时候执行}
会从头开始依次判断条件
如果第一个条件为true了,那么就会执行后面的{}里面的内容
如果第一个条件为false,那么就会判断第二个条件,依次类推

注:多个{},只会有一个被执行,一旦有一个条件为true 了,后面的就不再判断了

if else if … else语句

和之前的if else if …基本一致,只不过是在所有条件都不满足的时候,执行最后else后面的{}
if (条件1) {条件1为true的时候执行}
else if (条件2) {条件2为true的时候执行}
else if (条件3) {条件3为true的时候执行}
else(条件){前面if都不满足时执行}

switch条件分支结构

也是条件判断语句的一种
是对于某一个变量的判断
语法:
switch (要判断的变量) {

case 情况1:
情况1要执行的代码
break

case 情况2:
情况2要执行的代码
break

case情况3:
情况3要执行的代码
break

default:
上述情况都不满足的时候执行的代码
break
}

while循环

语法:
while (条件) {满足条件就执行}

若条件不满足,不会有执行的机会

因为满足条件就执行,所以我们写的时候一定要注意,设定一个边界值,不然就一直循环下去了

do…while循环

语法:
do { 执行的代码 } while (条件);

先执行一次代码,再判断是否满足条件,满足条件继续执行代码,不满足停止执行

for循环

for(语句1;语句2;语句3){执行代码}

执行语句1,然后判断语句2,满足就执行代码,然后执行语句3,若不满足语句2,则结束循环

循环控制语句

break终止循环

在循环没有进行完毕的时候,因为我设置的条件满足,提前终止循环。
要终止循环,就可以使用break关键字
例:

for(var i = 1;i <= 5; i++){
	 console.log(i)
	 if(i===3){
	     break
	 }
}

在这里插入图片描述

continue结束本次循环

在循环中,把循环的本次跳过去,继续执行后续的循环
跳过本次循环,就可以使用continue关键字

 for(var i = 1;i <= 5; i++){
	   if(i===3){
	         continue
	     }
	     console.log(i)
}

在这里插入图片描述

函数

对于js来说,函数就是把任意一段代码放在一个盒子里面
在我想要这段代码执行的时候,直接执行这个盒子里的代码就行

定义函数

1.声明式
function 函数名(参数){一段代码}

注:可以先把调用函数写在声明式前面,会进行预解析

2.赋值式
var 函数名=function(参数){一段代码}

注:不可以先把调用函数写在声明式前面,会报错

调用函数

在js里直接写
定义过函数名+()
在这里插入图片描述

注:函数里面定义的变量,没法在外面调用使用在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

函数的参数

定义函数时()的作用就是放置参数
参数分为两种形参实参

形参定义函数时括号放的

实参调用函数时括号放的
实参对应赋值给形参
(如果只有一个实参,会传给第一个形参)
在这里插入图片描述
形参只能在函数内部使用,没法直接调用,预解析也无法对其作用
在这里插入图片描述
在这里插入图片描述

函数的返回值

函数调用本身也是一个表达式,表达式就应该有一个值
但不加返回值的话函数执行完,结果不会出现
在这里插入图片描述
在这里插入图片描述

注意:1.return看需求使用,不是100%
2.return后面代码无法执行
如果满足 false 直接结束函数(因为已经给函数完成赋值)在这里插入图片描述>3.如果是分支语句(if、switch等)可以写多个return,因为只会匹配到一个return执行

预解析

就是js代码的编译和执行
在代码执行之前,先对代码进行通读和解释,然后在执行代码
js在代码运行时,会有两个环节解释代码执行代码
预解析只会提升到一个script的上面

解释代码(变量声明提升)

在所有代码执行之前进行解释,所以叫做预解析(预解释)
解释内容有两个:
声明式函数

先声明有一个变量名是函数名,并用这个名字代表的内容是一个函数

var关键字

先声明有一个变量

在这里插入图片描述
在这里插入图片描述
因为把声明提前了,告诉js有这样一个变量,第一个log没有赋值,第二个log上面有赋值所以正常显示。

在这里插入图片描述

赋值式同理,var 函数名,会提前,对函数名(等价于undefined)进行调用,但无法被调用执行(不知道要赋函数还是变量)所以函数赋值式,没法进行预处理

函数和变量定义的名称相同时

在这里插入图片描述
在这里插入图片描述

作用域

全局作用域

最大的作用域
全局作用域中定义的变量可以在任何地方使用
页面打开的时候,浏览器会自动给我们生成一个全局作用域window
这个作用域会一直存在,直到网页关闭就销毁了
定义的函数和变量就是全局函数和变量

局部作用域

局部作用域就是在全局作用域下面开辟出来的一个相对小一些的作用域
在局部作用域中定义的变量只能在这个局部作用域中使用
在js中只有函数能生成一个局部作用域,别的都不行
一个函数就是一个局部作用域

访问规则(就近原则)

在想获取一个变量的值的时候,我们管这个行为叫做访问
获取变量的规则:
1.在自己作用域内查找,如果有,直接拿来用
2.如果没有返回上一级作用域查找,如果有,直接拿来用
3.如果没有,就继续去上一级作用域查找,以此类推
4.如果一直到全局作用域都没有这个变量,会直接报错(该变量 is not defined)
在这里插入图片描述

赋值规则

在想给一个变量赋值的时候,那么就先要找到这个变量,再给他进行赋值
变量赋值的规则:
1.在自己作用域内查找,有就直接赋值
2.如果没有返回上一级作用域查找,有就直接赋值
3.如果没有,就继续去上一级作用域查找,以此类推
4.如果一直到全局作用域都没有,那么会把这个变量定义为全局变量,再给他赋值
在这里插入图片描述
在这里插入图片描述
引出函数计算数值
在这里插入图片描述

对象数据类型

对象是一个复杂数据类型
存储了一些基本数据类型的一个集合

var obj={
	num:100,(key:value)
	str:‘hello world’, (key:value)
	boo:true (key:value)
}

在这里插入图片描述

此时的 { } 是写一些数据的
对象就是一个键数对的集合
{ } 里面每一个键都是一个成员
也就是说我们把一些数据放在一个对象里面,他们就互不干扰了

理解:一个房子,把想要的数据放进去,然后把房子的地址给变量名,当我们需要某个数据的时候,可以根据变量名里面存储的地址找到相应的房子,然后去房子里面找对应的数据

创建方式

1.字面量创建一个对象
var 对象名 = { 数据 }

2.内置构造函数
var 对象名 = new Object()
对象名.key = value
在这里插入图片描述

增删改查

查:
document.write(数据+对象名.key)或
console.log(对象名【“key”】)

改:
对要改的对象进行 对象名.key=更改的数据 改动或对象名【“key”】= 更改的数据
该行代码之后,该对象名的该key会变成更改之后的数据

删:
delete 对象名.keydelete 对象名【“key”】
彻底删除

增:
var 对象名 = { }
对象名【“key”】= 增添的数据

若不加 “ ” ,key会变成一个全局变量
在这里插入图片描述

对象的遍历

for关键字
for(var 变量名 in 对象名){
document.write(变量名+数据等+对象名【变量名】)
}

变量,访问的是key;对象名【变量名】,访问的value

不同数据类型的储存(及数据复制更改)

存储空间分为两种
栈:主要存储基本数据类型的内容
堆:主要存储复杂数据类型的内容

基本数据类型情况:
var num=100 会在栈空间内存储一个数据

复杂数据类型情况:
var obj ={
key1:value
key2:value
key3:value
}
var obj ={数据}会在堆内存储

当通过另一个var obj2=obj进行数据复制的时候,更改obj2内数据obj内数据也会变 (相当于房子一样,只是复制了一份钥匙,改的还是一个房子里的东西)
当两个对象内数据一样时,进行===也会返回false(因为堆的地址不一样虽然内容一样)(相当于房子内部一样,但不是同一个房子)

进行数据复制并完成新复制的数据更改不影响旧数据方法:
var obj ={
key1:value
key2:value
key3:value
}

var obj2={}
for(var i in obj){
obj2【i】=obj【1】
}
obj2.key1=新的value
在这里插入图片描述

不会影响obj中数据了

数组

一个数据的集合
把一些数据放在一个盒子里,按顺序排好,一般一个数组数据类型相同

数组分类

基本数据类型:number、string、Boolean、undefined、null
复杂数据类型:object、function、array

数组创建

1.字面量
var 数组名 = 【】

2. array
var 数组名= new Array()

数组的基本操作

1.获取数组长度
console.log(数组名.length)

2.设置数组长度
数组名.length = 设置长度

如果长度小于数组数据,会从后往前减去
多用于清空数组 长度=0

3.索引
索引从0开始,0,1,2,3,4,5…
数组名【索引数】

索引的数大于真实数据个数时,显示undefined

4.修改
数组名【索引数】=修改数据

索引的数大于真实数据个数时,会在后面索引数对应的位置自动增加数据(前面若还有位置,会自动变成空位置)

5.遍历
for(var i=0;i<数组名.length;i++){
console.log(数组名【i】)
}

for(var i=0;i<=数组名.length-1;i++){
console.log(数组名【i】)
}

进行数据复制并完成新复制的数据更改不影响旧数据方法:
在这里插入图片描述

冒泡排序法

先遍历数组,让挨着的两个进行比较,如果前一个比后一个大,那么就把两个换个位置。
一遍过后,最大的数会到最后,二遍后第二大的数会到倒数第二的位置
第一遍(最大的在最后)
在这里插入图片描述
最终冒泡排序结构:
在这里插入图片描述

选择排序法

先假定数组中第0个就是最小的数字的索引
然后遍历数组,只要有一个数字比假设的小,就替换之前记录的索引,结束一遍后,找到最小的数,让最小的数换到第0个位置(最小的数在第一个),第二遍找第二小的数在第1个位置(第二个)
在这里插入图片描述

数组常用方法

在数组最后追加元素:
数组名.push(元素)

返回值为数组长度

删除数组最后一个元素:
数组名.pop(元素)

返回值为删除的那个元素

从前面追加元素:
数组名.unshift(元素)

返回值为数组长度

从前面删除元素:
数组名.shift(元素)

返回值为删除的元素

从中间删除元素:
数组名.splice(索引值,从索引值开始删几个)

返回值为删除的【数组】

从中间加元素:
数组名.splice(索引值,从索引值开始删几个(可写0),增加的元素,增加的元素…)

如果删0个,增加的元素会在该索引值对应元素的前面
返回值为删除的【数组】

元素倒叙:
数组名.reverse()

排序:
从小到大:
数组名.sort(function(a,b){
return a-b
})
从大到小:
数组名.sort(function(a,b){
return b-a
})
拼接:
var 新建数组3=数组1.concat(数组2,不同数据类型)

会在数组1后面加上拼接内容
var 新建数组3=数组1.concat()复制数组

数组转成字符串:
数组.join()

若括号里不加东西,每个数据会用逗号连接,加空字符串,逗号消失

截取字符串:
数组.slice(开始索引值,结束索引值)

包前不包后

在这里插入图片描述

如果是只写一个索引值,指的是从该索引值开始一直到最后

在这里插入图片描述
var 新建数组2=数组1.slice()复制数组

返回查找内容索引值:
从前面开始查:
数组名.indexof(查询内容,从某索引值开始查找)
如果查不到显示-1,查到会显示索引值,但如果两个数据重复,只会显示第一个查到的数据的索引值

从后面开始查:
数组名.lastIndexof(查询内容,从某索引值开始查找)
如果查不到显示-1,查到会显示索引值,但如果两个数据重复,只会显示第一个查到的数据的索引值

foreach回调函数进行遍历

在这里插入图片描述
第一个参数,数组里的数据,第二个参数,索引值,第三个参数,数组整体

map回调函数进行映射

在这里插入图片描述

新数组arr2中的每个数据为arr对应数据的立方

filter回调函数进行过滤

在这里插入图片描述
返回条件 true数据返回到新数组中,false不返回

数据里为对象时,形参打印出来显示每一个对象
需要用对象里面某个具体的key进行过滤在这里插入图片描述

every回调函数进行整体判断

在这里插入图片描述
全部数据都满足时才能输出为true

some回调函数进行个别判断

在这里插入图片描述
只要有一个数据满足就为true

reduce叠加运算

在这里插入图片描述
prev(第一个参数)代表上一次return的返回值,item(第二个参数代表数组里每一个数据)
0代表设置的初始值(即第一次的prev)

数组去重

法一:
在这里插入图片描述
法二:
在这里插入图片描述

因为原数组是数字类型数据,对象会把key自动变成字符串类型,需要强制转换(i-0等操作)

法三:
var set结构名字 =new Set(要去重的数组)
var 新数组名 = Array.from(set结构名字)
在这里插入图片描述

字符串的基本操作和常用方法

对字符串.length会在瞬间变成数组,然后又变回字符串
(length在此为只读属性,不能更改)
在这里插入图片描述
字符串【索引值】,用来显示字符串中我需要的那个字符
(只读属性,不能更改)
在这里插入图片描述
对字符串进行遍历
在这里插入图片描述

索引

chartAt(索引值),返回索引对应的字符

在这里插入图片描述

若索引值大于字符串最大索引值,会输出空字符串

charCodeAt(索引值),返回索引对应字符的字符编码(ASCLL码)
在这里插入图片描述

fromcharcode指的是把字符编码返回为字符在这里插入图片描述

转换字符大小写(只转换英文)

字符串名.toUpperCase()
把字符串所有改成大写
字符串名.toLowerCase()
把字符串所有改成小写

实现首字母大写(运用到截取):
在这里插入图片描述

截取

法一:
字符串名.substr(开始索引值,截取长度)

法二:
字符串名.substring(开始索引值,结束索引值)

包前不包后
如果是只写一个索引值,指的是从该索引值开始一直到最后

法三:
slice和substring用法一样

替换

字符串名.replace(要替换的字符,替换成的字符)

只替换从开始遇到的第一个

字符串转换成数组

split 分割
字符串名.split(以某字符分割)
在这里插入图片描述
在这里插入图片描述

返回查找字符串中字符索引值

从前面开始查:
字符串.indexof(查询内容,从某索引值开始查找)
如果查不到显示-1,查到会显示索引值,但如果两个数据重复,只会显示第一个查到的数据的索引值

从后面开始查:
字符串.lastIndexof(查询内容,从某索引值开始查找)
如果查不到显示-1,查到会显示索引值,但如果两个数据重复,只会显示第一个查到的数据的索引值

连接字符串

字符串.concat(要加的字符串)
也可以用+号拼接
在这里插入图片描述

去掉首尾空格

字符串.trim()去掉收尾空格
trimStart()、 trimLeft()去掉首空格
trimEnd()、trimRight()去掉尾空格

json格式字符串(解析成对象)

JSON.parse
格式非常严格,只能是‘ { “ key ”:value,“ key ”:value,…} ’的字符串形式
在这里插入图片描述

对象解析成字符串传递给后端:
JSON.stringify(对象名)
在这里插入图片描述

模板字符串

如果字符串想换行,把外面的引号改成反引号(英文输入法下tab上面的键)

当字符串外面加反引号时,可以在字符串里面加上${ 变量名 }
进行外部数据赋给该字符串字符
在这里插入图片描述
在这里插入图片描述


在这里插入图片描述
在这里插入图片描述

若图中bbb、aaa未加引号会报错,因为会当成变量,但没有定义变量aaa、bbb

数字常用方法

数字变量名.toFixed(保留几位小数)
返回类型为字符串

会自动进行四舍五入
设置保留位数大于实际位数,会自动补0

Math对象

随机数(random)

Math.random()返回0-1的随机数
包0不到1

四舍五入取整(round)

Math.random(数字)

向上向下取整(ceil、floor)

Math.ceil(数字)向上取整
Math.floor(数字)向下取整

绝对值(abs)

Math.abs(数字)

平方根(sqrt)

Math.sqrt(数字)

指数运算(pow)

Math.pow(底数,指数)

取最大值max

Math.max(数字,数字,数字,…)

取最小值min

Math.min(数字,数字,数字,…)

圆周率(PI)

Math.PI

时间对象

var 变量名 = new Date()

自动转为字符串

1个参熟 毫秒数
2个参数 年、月(月的参数从0开始,0为1月)
3个参数 年、月、日
4,5,6个参数 年、月、日、时、分、秒

字符串
var 变量名 = new Date(“2023-10-10 10:10:10”)

-可以改成/
在这里插入图片描述

时间对象常用方式

获取年份:
时间对象名.getFullYear()

获取月份:
时间对象名.getMonth()

参数从0开始,0为1月

获取日数:
时间对象名.getDate()

获取周数:
时间对象名.getDay()

周日0,周一到周六 1-6

获取当前时、分、秒、毫秒:
时间对象名.getHours()
时间对象名.getMinutes()
时间对象名.getSeconds()
时间对象名.getMilliseconds()

获取时间戳(距离1970年1月1号0点的毫秒数):
时间对象名.getTime()

设置年、月、日、小时、分钟、秒:
时间对象名.setFullYear()
时间对象名.setMonth()
时间对象名.setDate()
时间对象名.setHours()
时间对象名.setMinutes()
时间对象名.setSeconds()

时间戳变回对应日期:
时间对象名.setTime()

计时器

倒计时

注册定时器:
var 变量名= setTimeout(function(){ },ms)

ms指过多少ms进行设置好的函数
返回值就为第几个定时器

清除定时器:
clearTimeout(变量名)

注册间隔定时器:
setInterval(function(){ },ms)

ms指每隔多少ms进行函数
返回值就为第几个定时器

清除间隔定时器:
cleartInterval(变量名)

异步执行

因为有的函数等会延时触发,造成异步执行
在这里插入图片描述
先执行同步代码(注册定时器回调函数),再执行异步代码,延迟0s触发

BOM

浏览器对象模型,操作浏览器的一些能力(“ window. ”可以省略)

获取浏览器窗口尺寸

页面内容能显示的大小(包含滚动条)
window.innerHeight
window.innerWidth

浏览器的弹出层

必须点掉弹出层才能进行后续代码
1.提示框:
window.alert(提示内容)

2.询问框:
confirm(询问内容)
在这里插入图片描述
点确定返回true 取消返回false
3.输入框:
prompt(输入内容)
在这里插入图片描述
取消返回null,不输入点确定返回空字符串

浏览器的地址信息

location
存储浏览器地址栏内的信息的

location.href
拿到浏览器地址信息

location.href = “地址”
让浏览器访问网址,到下一页面(当前网页覆盖掉打开新网页)
在这里插入图片描述

reload()
刷新网页

浏览器常见事件

页面所有资源加载完毕后执行(图片、DOM、视频)
widow.onload = function(){ }

页面大小改变后执行一次
onresize = function(){ }

计算窗口条滚动条滚动距离
onscroll = function(){ }

从顶部开始滚动条的距离
widow.document.documentElement.scrollTop

最多只能计算到底部时移上去的距离
在这里插入图片描述

有时候浏览器版本过低不支持该代码需要写成
widow.document.documentElement.scrollTop | | document.body.scrollTop

从左边开始滚动条的距离
document.documentElement.scrollLeft

滚动到指定位置
scrollTo()
写法一:
两个数字,x轴,y轴数据
写法二:
在里面传一个对象

scrollTo({
	left:
	top:
})

浏览器打开标签页

window.open(“网页地址”)
会新建一个网页打开,而不是在当前网页覆盖掉打开

window.close()
关掉自己网页

浏览器的历史记录

返回上一个访问页面:
history.back()

必须历史记录里有上一个访问页面

前进下一个访问页面:
history.forward()

必须历史记录里有下一个访问页面

history.go(正负整数n),正数就是前进n个页面,负数就是返回n个页面

必须历史记录

浏览器本地存储

存:
localStorage.setItem(“key”,“value”)

只能存字符串

取:
localStorage.getItem(“key”)

删:
localStorage.removeItem(“key”)

清:
localStorage.clear()

sessionStorage.setItem(“key”,“value”)
sessionStorage.getItem(“key”)
sessionStorage.removeItem(“key”)
sessionStorage.clear()

区别:localStorage永久存储,sessionStorage临时存储,关掉浏览器消失

DOM☆

获取元素,移除元素,创建元素,添加元素,获取元素属性,加css样式,绑定事件…

获取元素的方式

document.documentElement 获取html部分
document.head 获取head部分
document.body 获取body部分

document.getElementById(“id名”)通过id获取元素

document.getElementByClassName(“class名”)通过class获取元素

长得像数组,但不是,有长度,有索引值
变量名【索引值】.innerHTML = “更改内容”
可以用array.from(变量名)转换成数组

document.getElementByTagName(“标签名”) 通过标签获取

长得像数组,但不是,有长度,有索引值
变量名【索引值】.innerHTML = “更改内容”
可以用array.from(变量名)转换成数组

document.getElementByName(“name名”)

document.querySelector(“#id或标签或标签.class或.class”)

只返回一个对象,如果有多个相同的只返回遇到的第一个

document.querySelectorAll(“#id或标签或标签.class或.class”)

可返回多个对象

操作元素属性

元素自带属性(原生)
自定义属性
在这里插入图片描述
变量.attributes【索引值】,查找属性

操作原生属性
元素.innerHTML=“更改内容”
元素.原生属性(type等)= “更改属性”

操作自定义属性
增加:元素.setAttribute(“属性”,属性值)
获取:元素.getAttribute(“属性”)
删除:元素.removeAttribute(“属性”)
如果自定义属性前面加data-需要使用
获取:元素.dataset
修改增加:元素.dataset.自定义属性=属性
删除:delete 元素.dataset 自定义属性

操作元素文本内容

innerHTML拿到标签内完整内容

innerText拿到标签内文本

不解析html

value表单标签拿到value值

操作元素样式

style 获取行内样式
只能访问行内样式
直接更改样式即可

例:无法访问height
在这里插入图片描述

getComputedStyle获取内部样式,外部样式,行内样式
在这里插入图片描述

只能获取,不能赋值

操作元素类名

获取class的类名.className
可赋值

获取class的类名.classList(获取显示成成数组)
.classList.add(“增加的类名”)(会自动去重)
.classList.remove(“删除的类名”)

toggle切换类名是否存在
.classList.toggle(“类名”)

DOM节点

元素节点,文本节点,属性节点,document(根节点,最大的节点),注释节点(一段注释)

获取节点的方法

.childNodes获取父元素中所有节点
.children获取父元素中所有标签节点

.firstChild获取父元素中第一个节点
.firstElementChild获取父元素中第一个标签节点

.lastChild获取父元素中最后一个节点
.lastElementChild获取父元素中最后一个标签节点

.previousSibling获取该元素上面的一个节点
.previousElementSibling获取该元素上面的一个标签节点

.nextSibling获取该元素下面的一个节点
.nextElementSibling获取该元素下面的一个标签节点

.parentNode获取该元素的父元素的节点
.parentElement获取该元素的父元素的标签节点

通常是一样的,但.parentElement找不到document节点

.attributes拿到标签内所有属性可加索引值.attributes【索引值】

操作节点

创建一个元素节点
.document.createElement

父元素插入节点
.appendChild(创建的节点)

位置在最后面

在某个元素节点之前插入
.insertBefore(要插入的节点,谁的前面)

删除节点
.removeChild(删除的节点)子元素删除
.remove(删除的节点)整个父元素本身删除

替换节点
.replaceChild(新的节点,老的节点)

克隆节点
.cloneNode(true)克隆后代
.cloneNode()不可隆后代(默认为false)

节点属性

每一个节点都有不同nodeType

元素节点为1,文本节点为3

.nodeType

遍历所有的元素节点
在这里插入图片描述

获取元素尺寸

offset获得宽高为border+padding+content
.offsetWidth
.offsetHeight

获得值为数字类型
box-sizing不影响计算宽高方法border+padding+content
display:none无法拿到宽高值

client获得宽高为padding+content
.clientWidth
.clientHeight

获得值为数字类型
box-sizing不影响计算宽高方法border+padding+content
display:none无法拿到宽高值

获取元素的偏移量

.offsetLeft .offsetTop偏移量

参考值为定位父级,即遇到的第一个有定位的父级,如果父级元素都没有定位,偏移量相对于body

.clientLeft .clientTop偏移量(相对于自身,即边框宽度)

获取可视窗口尺寸(不包含滚动条)

document.documentElement.clientWidth
document.documentElement.clientHeight

初识事件

在这里插入图片描述
dom0:
.触发事件=function(){}
不可以分开创建多个函数任务,会被覆盖

dom2:
.addEventListener(“事件类型”,function(){ } )
可以分开复制多份任务,从上到下按照顺序执行

在这里插入图片描述

事件解绑

dom0:
.onclick = null

dom2:
.removeEventListener(“事件类型”,函数名)

此时函数应该创建在removeEventListener和addEventListener之外在这里插入图片描述

事件类型

鼠标事件
btn.onclick单机事件

btn.ondblclick双击绑定执行

btn.contextmenu 右键单击(自定义右键菜单)

btn.mousedown/mousemove/mouseup鼠标按下这一刻/鼠标移动在指定区域/鼠标抬起

btn.mouseover/mouseout鼠标移入(对子元素也成立)/鼠标移出

btn.mouseenter鼠标移入(对子元素不产生效果)

键盘事件

window.onkeydown按下键盘/onkeyup抬起键盘

表单事件

input.onfocus获得焦点/onblur失去焦点

input.onchange获取焦点和失去焦点的时候对比内部条件不一样才会触发

username.oninput内容不同就会触发

// 必须创建表单结构

form.submit提交/reset重置

触摸事件(只针对移动端)

box.ontouchstart开始接触

box.ontouchmove开始移动

box.ontouchend松开

事件对象

在这里插入图片描述

每一个字符都有keycode

事件对象-鼠标事件

cilentX/cilentY 鼠标所在位置距离浏览器可视窗口的左上角的坐标值

pageX/pageY距离页面文档流的左上角的坐标值

offsetX/offsetY距离触发元素的左上角的坐标值
在这里插入图片描述

DOM事件流

在这里插入图片描述
标准的dom事件流:

捕获:window=>document=>body=>outer

目标:inner

冒泡:outer=>body=>document=>window

默认情况下,只在冒泡触发回调函数

阻止事件流

evt.stopPropagation()停止冒泡现象
在这里插入图片描述

阻止默认行为

dom0:return false
在这里插入图片描述

在这里插入图片描述
dom2:evt.preventDefault()
在这里插入图片描述

事件委托

冒泡机制中,点击子元素父元素也会触发相同事件,所以可以直接把子元素的事件委托给父元素来做,用事件委托的时候,根本就不需要去遍历元素的子节点,只需要给父级元素添加事件就好了,其他的都是在js里面的执行,这样可以大大的减少dom操作。

正则表达式

js复杂类型的一种,检测输入框是否符合设定的规范

表达式建立:
1.字面量
var 变量名 = /abc/(检测输入内容是否包含“abc”)

2.内置构造函数
var 变量名 = new RegExp(“abc”)(检测输入内容是否包含“abc”)

打印检验:
在这里插入图片描述

元字符

基本元字符

\d 包含至少一位数字(0-9)

\d\d… 包含至少n位数字

\D 包含至少一位非数字

\D\D\D… 至少包含n位非数字

在这里插入图片描述
必须有“非数字 k 非数字 ”

\s 至少包含一位空白(空格 缩进(Tab) 换行(\n))

\S 至少包含一位非空白(空格 缩进(Tab) 换行(\n))

\w 至少包含一位字母 数字 下划线

\W 至少包含一位非字母数字下划线

. 至少包含一位任意内容(换行不算)

\ 转义字符

主要用于把代表任意内容的 **.**字符转义成小数点用法
在这里插入图片描述

边界符

1.^开头边界限制
^\d 代表开头必须是一个数字

2.$ 结尾边界限制
\d$ 代表结尾必须是一个数字

3.^开头结尾都是$
^abc$开头结尾都是abc

限定符

*包含规定内容0~多次
+包含规定内容1~多次
?包含规定内容0~1次
{n}指定次数

特殊符号

1.()整体

var reg = /(abc){2}/

2.| 或

var reg = /a|b/

3.[ ]代表1个

4.[a-zA-Z0-9]相当于\w

5.[0-9]相当于\d

6.[^abc] 取反

捕获exec

<script>
var reg = /\d{3}/
console.log(reg.exec("aa123aa "))
</script>

只能捕获遇到的第一个

标识符

g 全局
i 忽略大小写

var reg = /\d{4}-\d{1,2}-\d{1,2}/g

this指向

this可以用在构造函数之中,表示实例对象。除此之外,this还可以用在别的场合。但不管是什么场合,this都有一个共同点:它总是返回一个对象。简单说,this就是属性或方法“当前”所在的对象。(被谁调用指向谁)
例:

var person = {
  name: '张三',
  describe: function () {
    return '姓名:'+ this.name;
  }
};
person.describe()
// "姓名:张三"

上面代码中,this.name表示name属性所在的那个对象。由于this.name是在describe方法中调用,而describe方法所在的当前对象是person,因此this指向person,this.name就是person.name。

由于对象的属性可以赋给另一个对象,所以属性所在的当前对象是可变的,即this的指向是可变的。

var A = {
  name: '张三',
  describe: function () {
    return '姓名:'+ this.name;
  }
};

var B = {
  name: '李四'
};

B.describe = A.describe;
B.describe()

上面代码中,A.describe属性被赋给B,于是B.describe就表示describe方法所在的当前对象是B,所以this.name就指向B.name。

绑定this的方法

this的动态切换,固然为 JavaScript 创造了巨大的灵活性,但也使得编程变得困难和模糊。有时,需要把this固定下来,避免出现意想不到的情况。JavaScript 提供了call、apply、bind这三个方法,来切换/固定this的指向。

var obj = {};
var f = function () {
  return this;
};
f() === window // true
f.call(obj) === obj // true

上面代码中,全局环境运行函数f时,this指向全局环境(浏览器为window对象);call方法可以改变this的指向,指定this指向对象obj,然后在对象obj的作用域中运行函数f。

call方法的参数,应该是一个对象。如果参数为空、null和undefined,则默认传入全局对象。

var n = 123;
var obj = { n: 456 };
function a() {
  console.log(this.n);
}
a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
a.call(window) // 123
a.call(obj) // 456

上面代码中,a函数中的this关键字,如果指向全局对象,返回结果为123。如果使用call方法将this关键字指向obj对象,返回结果为456。可以看到,如果call方法没有参数,或者参数为null或undefined,则等同于指向全局对象。

如果call方法的参数是一个原始值,那么这个原始值会自动转成对应的包装对象,然后传入call方法。

ES6

在这里插入图片描述

let和const关键字

我们以前都是使用 var 关键字来声明变量的
在 ES6 的时候,多了两个关键字 let 和 const,也是用来声明变量的
只不过和 var 有一些区别
1.
let 和 const 不允许重复声明变量

// 使用 var 的时候重复声明变量是没问题的,只不过就是后面会把前面覆盖掉
var num = 100
var num = 200
// 使用 let 重复声明变量的时候就会报错了
let num = 100
let num = 200 // 这里就会报错了
// 使用 const 重复声明变量的时候就会报错
const num = 100
const num = 200 // 这里就会报错了

let 和 const 声明的变量不会在预解析的时候解析(也就是没有变量提升)

// 因为预解析(变量提升)的原因,在前面是有这个变量的,只不过没有赋值
console.log(num) // undefined
var num = 100
// 因为 let 不会进行预解析(变量提升),所以直接报错了
console.log(num) // undefined
let num = 100
// 因为 const 不会进行预解析(变量提升),所以直接报错了
console.log(num) // undefined
const num = 100

let 和 const 声明的变量会被所有代码块限制作用范围

// var 声明的变量只有函数能限制其作用域,其他的不能限制
if (true) {
  var num = 100
}
console.log(num) // 100
// let 声明的变量,除了函数可以限制,所有的代码块都可以限制其作用域(if/while/for/...)
if (true) {
  let num = 100
  console.log(num) // 100
}
console.log(num) // 报错
// const 声明的变量,除了函数可以限制,所有的代码块都可以限制其作用域(if/while/for/...)
if (true) {
  const num = 100
  console.log(num) // 100
}
console.log(num) // 报错

let 和 const 的区别

let 声明的变量的值可以改变,const 声明的变量的值不可以改变

let num = 100
num = 200
console.log(num) // 200
const num = 100
num = 200 // 这里就会报错了,因为 const 声明的变量值不可以改变(我们也叫做常量)

let 声明的时候可以不赋值,const 声明的时候必须赋值

let num
num = 100
console.log(num) // 100
const num // 这里就会报错了,因为 const 声明的时候必须赋值

箭头函数

箭头函数是 ES6 里面一个简写函数的语法方式

重点: 箭头函数只能简写函数表达式,不能简写声明式函数

function fn() {} // 不能简写
const fun = function () {} // 可以简写
const obj = {
  fn: function () {} // 可以简写
}

语法: (函数的行参) => { 函数体内要执行的代码 }

const fn = function (a, b) {
  console.log(a)
  console.log(b)
}
// 可以使用箭头函数写成
const fun = (a, b) => {
  console.log(a)
  console.log(b)
}
const obj = {
  fn: function (a, b) {
    console.log(a)
    console.log(b)
  }
}
// 可以使用箭头函数写成
const obj2 = {
  fn: (a, b) => {
    console.log(a)
    console.log(b)
  }
}
箭头函数的特殊性

箭头函数内部没有 this,箭头函数的 this 是上下文的 this

// 在箭头函数定义的位置往上数,这一行是可以打印出 this 的
// 因为这里的 this 是 window
// 所以箭头函数内部的 this 就是 window
const obj = {
  fn: function () {
    console.log(this)
  },
  // 这个位置是箭头函数的上一行,但是不能打印出 this
  fun: () => {
    // 箭头函数内部的 this 是书写箭头函数的上一行一个可以打印出 this 的位置
    console.log(this)
  }
}

obj.fn()
obj.fun()

按照我们之前的 this 指向来判断,两个都应该指向 obj
但是 fun 因为是箭头函数,所以 this 不指向 obj,而是指向 fun 的外层,就是 window

箭头函数内部没有 arguments 这个参数集合

const obj = {
  fn: function () {
    console.log(arguments)
  },
  fun: () => {
    console.log(arguments)
  }
}
obj.fn(1, 2, 3) // 会打印一个伪数组 [1, 2, 3]
obj.fun(1, 2, 3) // 会直接报错

函数的行参只有一个的时候可以不写 () 其余情况必须写

const obj = {
  fn: () => {
    console.log('没有参数,必须写小括号')
  },
  fn2: a => {
    console.log('一个行参,可以不写小括号')
  },
  fn3: (a, b) => {
    console.log('两个或两个以上参数,必须写小括号')
  }
}

函数体只有一行代码的时候,可以不写 {} ,并且会自动 return

const obj = {
  fn: a => {
    return a + 10
  },
  fun: a => a + 10
}

console.log(fn(10)) // 20
console.log(fun(10)) // 20

函数传递参数的时候的默认值

我们在定义函数的时候,有的时候需要一个默认值出现

就是当我不传递参数的时候,使用默认值,传递参数了就使用传递的参数

function fn(a) {
  a = a || 10
  console.log(a)
}
fn()   // 不传递参数的时候,函数内部的 a 就是 10
fn(20) // 传递了参数 20 的时候,函数内部的 a 就是 20

在 ES6 中我们可以直接把默认值写在函数的行参位置

function fn(a = 10) {
  console.log(a)
}
fn()   // 不传递参数的时候,函数内部的 a 就是 10
fn(20) // 传递了参数 20 的时候,函数内部的 a 就是 20

这个默认值的方式箭头函数也可以使用

const fn = (a = 10) => {
  console.log(a)
}
fn()   // 不传递参数的时候,函数内部的 a 就是 10
fn(20) // 传递了参数 20 的时候,函数内部的 a 就是 20

注意: 箭头函数如果你需要使用默认值的话,那么一个参数的时候也需要写 ()

解构

解构赋值

解构赋值,就是快速的从对象或者数组中取出成员的一个语法方式

解构对象

快速的从对象中获取成员

// ES5 的方法向得到对象中的成员
const obj = {
  name: 'Jack',
  age: 18,
  gender: '男'
}
let name = obj.name
let age = obj.age
let gender = obj.gender
// 解构赋值的方式从对象中获取成员
const obj = {
  name: 'Jack',
  age: 18,
  gender: '男'
}

// 前面的 {} 表示我要从 obj 这个对象中获取成员了
// name age gender 都得是 obj 中有的成员
// obj 必须是一个对象
let { name, age, gender } = obj
解构数组

快速的从数组中获取成员

// ES5 的方式从数组中获取成员
const arr = ['Jack', 'Rose', 'Tom']
let a = arr[0]
let b = arr[1]
let c = arr[2]
// 使用解构赋值的方式从数组中获取成员
const arr = ['Jack', 'Rose', 'Tom']

// 前面的 [] 表示要从 arr 这个数组中获取成员了
// a b c 分别对应这数组中的索引 0 1 2
// arr 必须是一个数组
let [a, b, c] = arr

注:
{} 是专门解构对象使用的
[] 是专门解构数组使用的
不能混用

模版字符串

ES5 中我们表示字符串的时候使用 ‘’ 或者 “”

在 ES6 中,我们还有一个东西可以表示字符串,就是 ``(反引号)

let str = `hello world`
console.log(typeof str) // string
反引号和单引号好友双引号的区别

1.反引号可以换行书写

// 这个单引号或者双引号不能换行,换行就会报错了
let str = 'hello world' 

// 下面这个就报错了
let str2 = 'hello 
world'
let str = `
	hello
	world
`

console.log(str) // 是可以使用的

2.反引号可以直接在字符串里面拼接变量

// ES5 需要字符串拼接变量的时候
let num = 100
let str = 'hello' + num + 'world' + num
console.log(str) // hello100world100

// 直接写在字符串里面不好使
let str2 = 'hellonumworldnum'
console.log(str2) // hellonumworldnum
// 模版字符串拼接变量
let num = 100
let str = `hello${num}world${num}`
console.log(str) // hello100world100

注:在 `` 里面的 ${} 就是用来书写变量的位置

展开运算符

ES6 里面号新添加了一个运算符 ... ,叫做展开运算符

作用是把数组展开

let arr = [1, 2, 3, 4, 5]
console.log(...arr) // 1 2 3 4 5

合并数组的时候可以使用

let arr = [1, 2, 3, 4]
let arr2 = [...arr, 5]
console.log(arr2)

也可以合并对象使用

let obj = {
  name: 'Jack',
  age: 18
}
let obj2 = {
  ...obj,
  gender: '男'
}
console.log(obj2)

在函数传递参数的时候也可以使用

let arr = [1, 2, 3]
function fn(a, b, c) {
  console.log(a)
  console.log(b)
  console.log(c)
}
fn(...arr)
// 等价于 fn(1, 2, 3)

面向对象

首先,我们要明确,面向对象不是语法,是一个思想,是一种 编程模式
面向: 面(脸),向(朝着)
面向过程: 脸朝着过程 =》 关注着过程的编程模式
面向对象: 脸朝着对象 =》 关注着对象的编程模式
实现一个效果

在面向过程的时候,我们要关注每一个元素,每一个元素之间的关系,顺序,。。。
在面向过程的时候,我们要关注的就是找到一个对象来帮我做这个事情,我等待结果

我们以前的编程思想是,每一个功能,都按照需求一步一步的逐步完成

创建对象的方式

调用系统内置的构造函数创建对象

js 给我们内置了一个 Object 构造函数

这个构造函数就是用来创造对象的

当 构造函数 和 new 关键字连用的时候,就可以为我们创造出一个对象

因为 js 是一个动态的语言,那么我们就可以动态的向对象中添加成员了

// 就能得到一个空对象
var o1 = new Object() 

// 正常操作对象
o1.name = 'Jack'
o1.age = 18
o1.gender = '男'
字面量的方式创建一个对象

直接使用字面量的形式,也就是直接写 {}

可以在写的时候就添加好成员,也可以动态的添加

// 字面量方式创建对象
var o1 = {
  name: 'Jack',
  age: 18,
  gender: '男'
}

// 再来一个
var o2 = {}
o2.name = 'Rose'
o2.age = 20
o2.gender = '女'
使用工厂函数的方式创建对象

先书写一个工厂函数

这个工厂函数里面可以创造出一个对象,并且给对象添加一些属性,还能把对象返回

使用这个工厂函数创造对象

// 1. 先创建一个工厂函数
function createObj() {
  // 手动创建一个对象
  var obj = new Object()

  // 手动的向对象中添加成员
  obj.name = 'Jack'
  obj.age = 18
  obj.gender = '男'

  // 手动返回一个对象
  return obj
}

// 2. 使用这个工厂函数创建对象
var o1 = createObj()
var o2 = createObj()
使用自定义构造函数创建对象

工厂函数需要经历三个步骤:

1.手动创建对象

2.手动添加成员

3.手动返回对象

构造函数会比工厂函数简单

1.自动创建对象
2.手动添加成员
3.自动返回对象

先书写一个构造函数

在构造函数内向对象添加一些成员

使用这个构造函数创造一个对象(和 new 连用)

构造函数可以创建对象,并且创建一个带有属性和方法的对象

面向对象就是要想办法找到一个有属性和方法的对象

面向对象就是我们自己制造 构造函数 的过程

// 1. 先创造一个构造函数
function Person(name, gender) {
  this.age = 18
  this.name = name
  this.gender = gender
}

// 2. 使用构造函数创建对象
var p1 = new Person('Jack', 'man')
var p2 = new Person('Rose', 'woman')

构造函数详解

构造函数的基本使用

和普通函数一样,只不过 调用的时候要和 new 连用,不然就是一个普通函数调用

function Person() {}
var o1 = new Person()  // 能得到一个空对象
var o2 = Person()      // 什么也得不到,这个就是普通函数调用

注意: 不写 new 的时候就是普通函数调用,没有创造对象的能力

首字母大写

function person() {}
var o1 = new person() // 能得到一个对象

function Person() {}
var o2 = new Person() // 能得到一个对象

注意: 首字母不大写,只要和 new 连用,就有创造对象的能力

当调用的时候如果不需要传递参数可以不写 (),建议都写上

function Person() {}
var o1 = new Person()  // 能得到一个空对象
var o2 = new Person    // 能得到一个空对象 

注意: 如果不需要传递参数,那么可以不写 (),如果传递参数就必须写

构造函数内部的 this,由于和 new 连用的关系,是指向当前实例对象的

function Person() {
  console.log(this)
}
var o1 = new Person()  // 本次调用的时候,this => o1
var o2 = new Person()  // 本次调用的时候,this => o2

注意: 每次 new 的时候,函数内部的 this 都是指向当前这次的实例化对象

因为构造函数会自动返回一个对象,所以构造函数内部不要写 return

你如果 return 一个基本数据类型,那么写了没有意义
如果你 return 一个引用数据类型,那么构造函数本身的意义就没有了

使用构造函数创建一个对象

我们在使用构造函数的时候,可以通过一些代码和内容来向当前的对象中添加一些内容

function Person() {
  this.name = 'Jack'
  this.age = 18
}

var o1 = new Person()
var o2 = new Person()

我们得到的两个对象里面都有自己的成员 name 和 age

可以添加方法进去

function Person() {
  this.name = 'Jack'
  this.age = 18
  this.sayHi = function () {
    console.log('hello constructor')
  }
}

var o1 = new Person()
var o2 = new Person()

显然是可以的,我们的到的两个对象中都有 sayHi 这个函数
也都可以正常调用

function Person() {
  this.name = 'Jack'
  this.age = 18
  this.sayHi = function () {
    console.log('hello constructor')
  }
}

// 第一次 new 的时候, Person 这个函数要执行一遍
// 执行一遍就会创造一个新的函数,并且把函数地址赋值给 this.sayHi
var o1 = new Person()

// 第二次 new 的时候, Person 这个函数要执行一遍
// 执行一遍就会创造一个新的函数,并且把函数地址赋值给 this.sayHi
var o2 = new Person()

这样的话,那么我们两个对象内的 sayHi 函数就是一个代码一摸一样,功能一摸一样
但是是两个空间函数,占用两个内存空间
也就是说 o1.sayHi 是一个地址,o2.sayHi 是一个地址
所以我们执行 console.log(o1 === o2.sayHi) 的到的结果是 false
缺点: 一摸一样的函数出现了两次,占用了两个空间地址

原型

原型的出现,就是为了解决构造函数的缺点
也就是给我们提供了一个给对象添加函数的方法
不然构造函数只能给对象添加属性,不能合理的添加函数就太 LOW 了

prototype

每一个函数天生自带一个成员,叫做 prototype,是一个对象空间

即然每一个函数都有,构造函数也是函数,构造函数也有这个对象空间

这个 prototype 对象空间可以由函数名来访问

function Person() {}

console.log(Person.prototype) // 是一个对象

即然是个对象,那么我们就可以向里面放入一些东西

function Person() {}
Person.prototype.name = 'prototype'
Person.prototype.sayHi = function () {}

prototype 的空间是和函数有关联的
并且可以向里面存储一些东西
重点: 在函数的 prototype 里面存储的内容,不是给函数使用的,是给函数的每一个实例化对象使用的

__proto__

每一个对象都天生自带一个成员,叫做 __proto__,是一个对象空间

即然每一个对象都有,实例化对象也是对象,那么每一个实例化对象也有这个成员

这个 __proto__ 对象空间是给每一个对象使用的

当你访问一个对象中的成员的时候

如果这个对象自己本身有这个成员,那么就会直接给你结果
如果没有,就会去 proto 这个对象空间里面找,里面有的话就给你结果

那么这个 __proto__ 的指向
这个对象是由哪个构造函数 new 出来的
那么这个对象的 __proto__ 就指向这个构造函数的 prototype

function Person() {}

var p1 = new Person()

console.log(p1.__proto__ === Person.prototype) // true

我们发现实例化对象的 __proto__ 和所属的构造函数的 prototype 是一个对象空间
我们可以通过构造函数名称来向 prototype 中添加成员
对象在访问的时候自己没有,可以自动去自己的 __proto__ 中查找
那么,我们之前构造函数的缺点就可以解决了
我们可以把函数放在构造函数的 prototype 中
实例化对象访问的时候,自己没有,就会自动去 __proto__ 中找
那么也可以使用了

function Person() {}

Person.prototype.sayHi = function () {
  console.log('hello Person')
}

var p1 = new Person()
p1.sayHi()

p1 自己没有 sayHi 方法,就会去自己的 __proto__ 中查找
p1.__proto__ 就是 Person.prototype
我们又向 Person.prototype 中添加了 sayHi 方法
所以 p1.sayHi 就可以执行了

当我们实例化多个对象的时候,每个对象里面都没有方法
都是去所属的构造函数的 protottype 中查找
那么每一个对象使用的函数,其实都是同一个函数
那么就解决了我们构造函数的缺点

function Person() {}
Person.prototype.sayHi = function () {
  console.log('hello')
}

var p1 = new Person()
var p2 = new Person()

console.log(p1.sayHi === p2.sayHi)

p1 是 Person 的一个实例
p2 是 Person 的一个实例
也就是说 p1.__proto__ 和 p2.__proto__ 指向的都是 Person.prototype
当 p1 去调用 sayHi 方法的时候是去 Person.prototype 中找
当 p2 去调用 sayHi 方法的时候是去 Person.prototype 中找
那么两个实例化对象就是找到的一个方法,也是执行的一个方法

结论:

当我们写构造函数的时候
属性我们直接写在构造函数体内
方法我们写在原型上

原型链

我们刚才聊过构造函数了,也聊了原型
那么问题出现了,我们说构造函数的 prototype 是一个对象
又说了每一个对象都天生自带一个 __proto__ 属性
那么 构造函数的 prototype 里面的 __proto__ 属性又指向哪里呢?

一个对象所属的构造函数

每一个对象都有一个自己所属的构造函数
比如: 数组

// 数组本身也是一个对象
var arr = []
var arr2 = new Array()

以上两种方式都是创造一个数组
我们就说数组所属的构造函数就是 Array

比如: 函数

// 函数本身也是一个对象
var fn = function () {}
var fun = new Function()

以上两种方式都是创造一个函数
我们就说函数所属的构造函数就是 Function

constructor

对象的 __proto__ 里面也有一个成员叫做 constructor
这个属性就是指向当前这个对象所属的构造函数

链状结构

当一个对象我们不知道准确的是谁构造的时候,我们呢就把它看成 Object 的实例化对象
也就是说,我们的 构造函数 的 prototype 的 __proto__ 指向的是 Object.prototype
那么 Object.prototype 也是个对象,那么它的 __proto__ 又指向谁呢?
因为 Object 的 js 中的顶级构造函数,我们有一句话叫 万物皆对象
所以 Object.prototype 就到顶了,Object.prototype 的 __proto__ 就是 null

原型链的访问原则

我们之前说过,访问一个对象的成员的时候,自己没有就会去 __proto__ 中找
接下来就是,如果 __proto__ 里面没有就再去 __proto__ 里面找
一直找到 Object.prototype 里面都没有,那么就会返回 undefiend

对象的赋值

赋值的时候,就是直接给对象自己本身赋值
如果原先有就是修改
原先没有就是添加
不会和 __proto__ 有关系

继承

构造函数继承

function Student(name,age,classroom){
            Person.call(this,name,age)
            this.classroom = classroom
}

原型继承

Student.prototype = new Person()

组合继承
构造函数继承+原型继承

function Person(name,age){
    this.name = name
    this.age = age
}

Person.prototype.say = function(){
    console.log("hello")
}

function Student(name,age,classroom){
    Person.call(this,name,age)
    this.classroom = classroom
}

Student.prototype = new Person()

var obj = new Student("kerwin",100,"1班")

ajax

ajax=async javascript and xml
所拥有的优点:
1.不需要插件支持原生js就可使用
2.用户体验好,无需刷新页面就可以更新数据
3.减轻服务端和带宽的负担
缺点
搜索引擎容易搜索不到
ajax状态码:
readyState0:表示未初始化完成,也就是open方法还没有执行
readyState1:表示配置信息已经完成,也就是执行完open之后
readyState2:表示send方法已经执行完成
readyState3:表示正在解析响应内容
readyState==4:表示响应内容已经解析完毕,可以在客户端使用了

<script>
//请求服务端
//1、创建XHR(对象) new XMLHttpRequest()
var xhr = new XMLHttpRequest()
//2、配置 open(请求方式,请求地址,是否异步)
//localhost本机域名 127.0.0.1 本机ip
xhr.open(GET“,”ip地址“)
//3、拨出 send
xhr.send()
//4、接受数据,注册一个事件
xhr.onreadystatechange=function(){
	if(xhr.readyState===4{
		console.log("数据解析完成",xhr.responseText/*拿内容*/)
	}
}

</script>

请求方式

get 偏向获取数据
post 偏向提交数据
put 偏向更新
delete偏向删除信息
patch偏向部分修改

封装

<script>
ajax({
	url:"http://localhost:300/users",
	method:"GET",
	async:true
	data:{
		username:"kerwin",
		password:"123"
	}
	headers:{}
	success:function(res){
		console.loh(res)
	}
	error:function(err){
		console.log(err)
	}
})

</script>

回调地狱

当一个回调函数嵌套一个回调函数的时候,就会出现一个嵌套结构
当嵌套的多了就会出现回调地狱的情况
比如我们发送了三个ajax请求
第一个正常发送
第二个请求需要第一个请求的结果的某一个值作为参数
第三个请求需要第二个请求的结果中的某一个值作为参书

<script>
//tiechui已经登录
ajax({
	url:"http://localhost3000/news",
	data:{
		author:"tiechui"
	},
	success:function(res){
		console.log(res[0])
		ajax({
			url:"http://loclhost:3000/comments",
			data:{
				
			},
			success:function(res){//二层的回调地狱,代码维护性不好
				newsId:res[0].id
			}
		})
	}

})

</script>

解决回调地狱的方法 promise

解决回调地狱
promise

promise基础语法

<script>
var q = new Promise(function(resolve,reject){
	//放异步
	settimeout(()=>{
		//成功兑现承诺
		resolve()

		//失败拒绝承诺
		//reject()
	},2000})
//pending 执行中
//fulfilled 兑现承诺
//reject 拒绝承诺

//q是promise对象
q.then(function(){
//兑现承诺,这个函数被执行
}).catch(function(){
//拒绝承诺,这个函数被执行  
})

</script>

promise封装ajax

<script>
function pajax(){
	var q = new Promise(function(resolve,reject){
		ajax({
			success:function(res){resolve(res)
			},
			error:function(err){
				reject(err)
			}
		})
	
	})
	return q
}

</script>

async和await语法

async/await是es7的语法
这个语法是回调地狱的终极解决方案

asnyc function fn(){
	const res = await promise
}

此函数功能:
1.可以await一个promise对象
2.可以把异步代码写的看起来像同步代码
3.只要是一个promise对象,我们就可以用asnyc/await来写

asnyc function fn(){
	const res = new Promise(function(resolve,reject){
		ajax({
			url:'',
			success(res){
				resolve(res)
			}
		})
	})
}

fetch

XMLHttpRequest是一个设计粗糙的API,配置和调用方式非常混乱,而且基于事件的异步模型写起来不友好

<script>
fetch("http://localhost:3000/users")
	.then(res=>res.json())
	.then(res=>{
		console.loh(res)
	})

</script>

jsonp

sonp是json的一种“使用方式”,可以让王爷从别的域名(网站)那获取资料,即跨域读取数据
同源策略:同域名 同端口号 同协议
不符合同源策略,浏览器为了安全,会阻止请求

解决:
1、cors 有后端设置,Access-Control-Allow-Origin:*
2、jsonp:前后端必须协作

const script = document.creatElement('script')
script.src='./kerwin.txt'
document.body.appendChild(script)

闭包

函数内部返沪i一个函数,被外界所引用
这个内部函数就不会被销毁回收
内部函数所用到的外部函数的变量也不会被销

优点:
让临时变量永驻内存
缺点
内存泄漏(解决 func=null)

<script>
function outer(){
	var name="kerwin"
	return function(){
		return name+"1111111"
	}
}
var func=outer()
console.log(func())

</script>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值