JS Ⅰ

218 阅读18分钟

JavaScript基础

JavaScript的组成部分

文档对象模型
	DOM:document(页面,文档) object(对象) model(模型)
	文档对象模型就是咱们页面中的一系列标签,元素,隐藏元素
浏览器对象模型
	BOM:browser(浏览器) object(对象) model(模型)
	浏览器对象模型就是浏览器窗口中的一系列的操作:弹窗,地址栏,浏览器的所有的相关信息
ECMAscript
	js一个开发语法的规范,规定了js语法到底是如何编写,如何执行的

js的编写位置

  • 行内式(不推荐使用)

    <div onclick="alert('我是一个div标签')">文本</div>
    
    • 优点: 直接对元素进行操作
    • 缺点: 直接书写在行内,代码显示比较乱 没有做到结构样式行为的分离 不易于维护
  • 内嵌式

    • 基本语法格式:将所有的js代码放在一个script标签里面

      <script>
      	//js语句
      </script>
      
    • 书写位置:放在head里面或者是body里面,或者是任何位置都可以

    • js里面的代码是从上到下执行的

  • 外链式

    <script src="js文件的路径"></script>
    
    • 一个页面中可以引入多个外部js文件

js的注释

  • 单行注释: 直接使用双斜杠 // ctrl+/
  • 多行注释: /* */ shift+alt+a

js的输出形式

alert('')	弹窗输出,以浏览器弹窗进行显示
console.log()	以控制台形式进行输出的
console.log()	打印属性和方法
document.write()	页面输出

打断点

debugger

实现点击页面中的元素

  • 单机事件 onclick

    1. 超链接

      <a href="js语句">文本</a>
      
    2. 非超链接

      <div onclick="alert('我是一个div标签')">文本</div>
      

注意: 如果元素是一个非a标签,则需要触发一个js点击事件

变量

含义:变量指的是程序中存储输入的一个容器
	计算机存储数据的过程中以一个标识符代表这个数据,
	可以通过这个标识符找到对应的数据
	
标准语法:var 空格 变量名 = 值
	var   关键词,声明变量的时候必须使用的
	空格	  分割关键词和变量
	变量名  个容器,标识符
	=   赋值
	值  变量的数据内容

变量声明

  • 声明并赋值 var num = 100

  • 先声明,使用时再赋值 var num1;num1 = 200

  • 直接声明,不赋值 var num2 声明变量不赋值,直接打印,返回undefined

  • 不声明直接使用变量 没有声明的变量直接使用,程序报错 js里面只要程序报错,后面的程序将不会被运行,阻断程序运行

  • 同时声明多个变量 var num4,num5,num6 变量与变量直接使用逗号隔开

    ​ 一起打印,在一行中输出,输出的值是以空格隔开的 console.log(num4,num5,num6)

  • 同时声明多个变量并直接赋值 var num7=700,num8=800

变量的命名规则和规范

  • 命名规则:具有强制性,必须遵守

    1、字母,数字,下划线(_),$组成
    2、严格区分大小写:num,NUM
    3、不能以数字开头
    4、不能使用关键字和保留字
    	关键字:程序中已经规定的关键词,var,for,if,else,break,contniu...
    	保留字:有可能以后出现的内容变成关键字top.left.right.bottom.center,position...
    5、不能出现空格
    
  • 命名规范:

    1、见名知意
    2、驼峰命名法:从第二个单词开始,首字母大写myName,shopCar
    

数据类型

  • 基本数据类型

    • 数值类型--Number类型

      所有的数字都是数值类型(10,2,8,16进制的数值也算)
      NaN不是一个数字的数值类型
      控制台打印呈蓝色
      
    • 字符串类型--String类型

      任何带引号的都算作字符,包括空格
      控制台打印呈黑色
      
    • 布尔类型--Boolean类型

      true真和false假,主要应用在判断里面
      
    • null类型--空类型

      空的意思
      只有一个就是null  要想显示,出现的话,必须赋值一个空才能显示
      
    • undefined类型--未定义类型

      只有一个,代表的是没有定义的意思
      变量声明没有赋值,没有值的意思
      
  • 复杂数据类型

    • 函数Function
    • 数组Array
    • 对象Objest
    • 日期Date
    • 正则RegExp

检测数据类型

  • typeof(变量/检测的内容)

  • typeof 变量

    ​ document.write(typeof null)返回值为特殊值,object对象

  • typeof 返回值

    • number
    • string
    • boolean
    • object
    • function
    • undefined
typeof(typeof(124))
//注意:无论嵌套多少个typeof检测数据类型最终返回的结果必然是string

判断变量是否是数字

isNaN() -- is not a number  "是的,它不是一个数字"
语法:isNaN(变量)
	不是数字返回 ture
	是数字返回 false
	注意:isNaN方法,会将变量中的值隐式转换成数值类型再进行检测

Number.isNaN(变量)
	不是数字返回 ture
	是数字返回 false
	注意:检测前没有隐式转换

数据类型转换

  • 转换成数值类型

    • Number(变量)

      1)可以把一个变量强制转换成数值类型
      2)可以接收小数
      3)可以转换布尔类型,true=1 false=0
      4)null转换数值0
      5)强制转换成数值时,如果不能转换将返回NaN(不是一个数字),数据类型是数值类型
      

      **注意:**所有其他数据类型转为数值的隐式转换。都是使用Number方法进行转换

    • 浮点整型转换**parseInt(变量)**

      1)不允许接收小数
      2)从第一位开始检查,是数字就保留,直到遇到不是数字的就结束
      3)如果第一位就不是数字,直接结束返回NaN
      
    • 浮点型转换**parseFloat(变量)**

      1)只认一个小数点
      2)转换时,除小数点之外,遇到其他的字符都直接结束
      3)转换时,从第一位开始识别,直到遇到非数字的值
      4)如果第一位就不是数字,直接结束返回NaN
      
    • 除了+号以外的数学运算符

      数学运算符: + - * / %
      加号两侧都是为数值类型,则返回数值
      加号任意一侧是字符串类型则实现的拼接
      其他的数学运算符 返回值为数值类型的内容
      
    • 转为数值的隐式转换

      除了加法以外的 数学运算符  -  * /  %
      自操作 -- 运算
      isNaN()
      == 比较的时候 有一边是数值类型,则另一边会隐式转为数值
      > >= < <= 的比较,如果有一边是数值类型,则另一边会隐式转为数值
      
  • 转换成字符串类型

    • 变量.toString( )

      使用的时候,不能转换null,undefined,其余的都可以强制转换
      
    • String(变量)

      都可以转换
      

      **注意:**其他数据类型转为字符串的隐式转换,都是使用的String方法进行转换

    • 转为字符串的隐式转换

      +前后只要有一个数据类型为字符串,都会返回字符串类型,实现拼接
      数据当做对象的属性名的时候,会隐式转为字符串
      
  • 转换成boolean类型

    • Boolean(变量)

      只有""(空字符串)、null、undefined、0、NaN会转换成false,其余的都转换成true
      

      **注意:**其他数据类型转换为布尔的隐式装换,都是使用的boolean方法进行

    • 转为布尔隐式转换

      !取反
      逻辑运算的时候,会先隐式转换为布尔,然后校验
      条件判断的时候(条件分支,循环分支)
      

进制的表示

十六进制:0x 或 0X
八进制:0 或 0o 或0O
二进制:0b 或 0B

数学运算符

+ - * / %

做数学运算时,除了+以外所有的-*/%都会针对于一个纯数字的字符串进行隐式转换
布尔类型做运算的时候会转换成数值类型--隐式转换(true--1,false--0)
数学运算时,null隐式转换成0,undefined做数学运算的时候返回NaN
  • 数学+

    本质:求和,能做拼接
    +两侧都为数值类型,求和
    +的任意一侧是字符串,则实现拼接
    
  • 数学-

    本质:求差值
    -两侧都为数值类型,则进行数学运算
    -任意一侧不是数值,将返回NaN
    注意:布尔类型做运算的时候会转换成数值类型--隐式转换(true--1,false--0)
    
  • 数学*

    本质:求乘积
    
  • 除号/

    注意:null做除法运算的时候,返回Infinity
    
  • 取余%

    取余数运算的时候,不会涉及null,undefined
    

赋值运算

= += -= *= /= %=

赋值= :	var a = 100	将右侧的值赋值给左侧的变量
赋值+=:	a+=1   <=> 	a = a + 1
赋值-=:	a+=1   <=> 	a = a - 1
赋值*=:	a+=2   <=> 	a = a * 2
赋值/=:	a+=2   <=> 	a = a / 2
赋值%=:	a+=2   <=> 	a = a % 2

比较运算符

> >= < <= == === != !==

大于>
	大于,条件成立返回true否则返回false
大于等于>=
	大于或等于,条件成立返回true否则返回false	
小于<
	小于,条件成立返回true否则返回false	
小于等于<=
	小于或等于,条件成立返回true否则返回false	
等于==
	两个数值相等即可
	注意:纯数字的字符串会隐式转换,先转换成数值,然后再比较	
全等于===
	要求值和类型都相等	
不等于!=
	只要值不相等就返回true	
不全等!==
	要求值和类型都不相等

逻辑运算符

&&||!

逻辑与&&
	同时满足
	同真则真,遇假则假
逻辑或||
	满足一个即可
	有真则真,同假则假
逻辑非!
	取反

注意: 逻辑运算符具有短路逻辑,如果条件1不满足,条件2则不进行运算

自运算

前置++a	<==>  a += 1  <==>  a = a + 1
后置a++	<==>  a += 1  <==>  a = a + 1
赋值情况:
	b=++a	先运算++a,在赋值
	b=a++	先赋值,再运算a++

位运算

转二进制运算
&	按位与:同1则1
|	按位或:有1则1
^	异或:一个数异或另一个数两次回到自己本身

三目运算符

x = 表达式1 ? 值1 :  值2
判断表达式1是否为真,如果为真则将值1赋值给x,否则将值2赋值给x
例:max = a > b ? a : b;

弹窗

  • 提示框**alert()**

    点击确定,弹窗自动关闭
    
  • 可输入的弹窗**prompt(参数1,参数2)**

    参数1:提示文本
    参数2:输入框中的默认值
    

    注意:返回值为字符串类型

  • 确认取消框**confirm()**

js程序三大执行结构

顺序结构、选择结构、循环结构

  • 顺序结构:

    代码自上而下执行
    
  • 选择结构(分支语句):

    • if语句:

      1)if语句:
      	if(判断条件/表达式){
      		条件满足执行的代码块
      	}
      	
      2)if else语句
      	if(判断条件){
      		条件满足执行的代码块
      	}else{
      		条件不满足执行的代码块
      	}
      	
      3)if else if语句
      	if(判断条件1){
      		条件1满足执行的代码块
      	}else if(判断条件2){
      		条件2满足执行的代码块
      		条件2不满足将直接跳出
      	}
      	
      4)if else if else语句
      	if(判断条件1){
      		条件1满足执行的代码块
      	}else if(判断条件2){
      		条件2满足执行的代码块
      	}else{
      		条件都不满足执行的代码块
      	}
      
    • switch语句:

      switch (变量){
      	case 情况1:
      		满足情况1执行的代码块
      		break
      	case 情况2
      		满足情况2执行的代码块
      		break
      	case 情况3
      		满足情况3执行的代码块
      		break
      	default:
      		情况都不满足,执行default语句
      }
      

      注意:如果有一部分需要执行的语句是一样的,可以把break放在所有相同情况的结束位置

      ​ 如果没有break,会继续执行下面的代码块,不会再进行比较,直到遇见break(没有break的时候case情况具有穿透性)

循环

组成部分: 1、初始变量 2、判断条件 3、执行的循环体 4、改变循环条件(自增自减)

  • while循环语句

    while(判断条件){
    	循环体
    }
    
  • do while循环语句(至少执行一次)

    do{
    	循环体
    }while(判断条件)
    
  • for循环

    for(初始变量;判断条件;改变循环条件){
        循环体
    }
    for(表达式1;表达式2;表达式3){
        循环体
    }
    执行原理:表达式1→表达式2→循环体→表达式3→表达式2→循环体→......
    

break和continue

break: 打断循环 让程序不在执行 ​ continue: 跳出本次循环,继续执行下一次循环

双重循环

for(var i= 1; i< =9 ; i++){
    for(var j =1; j<=9 ;j++){
        循环体
        console.log("内容")
    }
}

外层循环执行1次,内容循环执行一轮 建议:大的循环在里边,小的循环在外面(性能问题)

函数

函数就是一个盒子,盒子里面放置了一些代码片段
盒子不使用,代码就不会执行
    function	声明函数的关键词
    空格			隔开声明和名字
    box			盒子名、变量名,(遵循变量命名规则规范)
    ( )			必须存在,一般用来放参数
    { }			函数封装的代码片段

函数定义

  • 声明式函数

    function box(a){
        执行的代码片段;
    }
    
  • 赋值式函数(表达式)

    var box = function(a){
        执行的代码片段;
    }
    

函数调用

  • 声明式函数调用

    函数名( )

  • 赋值式函数调用

    变量名( )

  • 区别:

    ​ 声明式函数调用时,在函数前面或函数后面都可以调用执行 ​ 赋值式函数调用时,只能在函数后面调用

函数中的参数

函数调用和声明过程中参与执行的变量与变量的值
形参:形式参数
	放在函数定义的( )里,多个形参之间用逗号隔开,形参相当于变量
实参:实际参数
	放在函数调用的( )里,用来给形参赋值
[多个参数问题]
	形参和实参一一对应
	若形参比实参多,多出来的形参为undefined(声明变量未赋值)
	若形参比实参少,多出来的实参没有变量去接收

return

本质:返回 函数中实现的作用:终止函数,返回一个值

  • 终止函数:

    ​ 函数体里面遇到return,return后面的程序不再执行

  • 返回值:

    ​ 表达式执行完毕后,返回一个值 ​ return 返回值

注意函数本身没有返回值,默认返回undefined

​ **注意:**后置操作在函数内遇见return,则会先返回变量的值,再进行自增或自减

arguments

函数内部保存了一个arguments对象,类数组
对象里面保存的是实参的内容
    console.log(arguments);
    console.log(arguments[0]);
    arguments[下标]	下标从0开始
    arguments.length	长度
    获取arguments中的每一项,需要使用arguments[下标]访问获取

预解析

js在浏览器编译:js解析,js执行

  • js解析:预(提前)解析

    ​ js执行时会把所有代码通读一遍,再执行 ​ 变量提前(预解析只解析了变量的变量名,值还保留在原地)

    ​ 在代码执行之前,将var声明变量及声明式函数,提升到当前作用域的最前面

    ​ 赋值式函数只有变量提升,没有函数提升

    ​ 在主流浏览器中,条件分支中定义的函数,预解析只能将函数名提升,但是没有值

    **注意:**如果声明式函数名和var 变量同名,则以函数为准(函数是一等公民)

    **注意:**函数调用,会先完成形参赋值,再预解析

    **注意:**赋值式定义的函数,赋值的函数如果有名字,则此函数名只能在函数内使用var ff=function fn(){};

    console.log(num)		//undefined
    var num = 66;
    console.log(num)	//66
    
    相当于:
    
    var num
    console.log(num)
    num = 66
    console.log(num)
    
  • js执行:

    ​ 代码自上而下运行

作用域

作用域指变量可执行的范围

全局作用域:
	任何一个地方都能使用的变量
	最大的变量widow
局部作用域:
	在全局作用域的基础上,开辟了一个小的作用区域,变量只能在这个小的独立区域中使用
	在函数的内部会形成一个独立的作用域,但是如果你变量的声明的时候,
		没有加var,声明的变量仍然是全局的变量
		添加了var,声明的变量只会在function函数中起作用

注意: 做函数封装的时候,定义的变量建议添加var 如果函数未调用,代码不执行,函数内的全局变量不存在变量提升

变量的使用规则

  • 定义规则

    在局部作用定义的变量就是 局部变量,只能在该局部作用域或后代作用域中使用
    
  • 访问规则

    1)就近原则,如果函数内部有自己的变量,优先使用自己的
        如果自己没有,找父级函数,如果父级没有,继续往外层函数查找
        如果都没有,则使用全局变量
        如果全局变量也没有,则程序报错
    2)只能向外部访问
    
  • 赋值规则

    先找到变量位置,如果自己作用域中有变量,则优先对自己作用域中的变量赋值
    否则给外层的变量赋值
    

递归函数

函数内部嵌套自己本身,就会形成递归,递归类似于循环

基本语法:

function fun(){		//外部函数
    fun()	//内部调用自己本身
}
fun()

具备的条件: 函数,判断条件,必须得有(递归出口:程序结束条件) 没有递归出口就是死递归,类似于死循环

自调函数(自执行函数)

自身可以执行的函数,在函数定义好后立即执行
赋值式函数的一种特殊使用
语法1:
	(function(形参){
		函数体;
	})(实参);
很多时候,会将分号写在自调函数的最前面
	;(function () {})()

语法2:
	!function(形参){
		函数体;
	}(实参);

语法3:
	~function(形参){
		函数体;
	}(实参);

对象

对象:对象相当于一个内容,这个内容里面包括了该内容的所有的属性

基本语法:

var  obj = {
    id:"001",
    name:"乐乐",
    sex:"男",
    age:18
}
var    声明变量的关键词
obj    对象名
=      赋值符
{ }    对象的基本内容,{}里存储的内容为:键值对
	键:属性	值:属性值

注意:

  • 赋值的不是对象的值,而是对象的地址
  • 每个键值对之间用逗号隔开
  • 键不需要带引号
  • 值如果是数值就不需要带引号,字符串需要带引号
  • 值不一定非得是基本数据类型
  • 字面量对象中,当属性名中有特殊符号的时候,会使用引号包裹
  • 对象中的属性名只能为字符串数据类型(或者Symbol)
  • 对象的属性名在对象中是唯一的(不重复)

声明对象

  • js声明对象的方式有两种

    • 字面量声明方法: var obj1 = { }
    • 通过构造函数的方法声明对象: var obj2 = new Object( ) //使用new创建
  • 声明并赋值

    var obj1 = {
        name:"乐乐",
        age:18
    }
    
  • 先声明,后赋值

    var obj1 = {}	//空的对象
    obj1.name = "乐乐"	//点语法
    obj1['age'] = 18	//数组关联法
    

    **注意:**点"."表示"的" 中括号赋值,属性名需要带引号

    ​ 如果在操作数据成员的时候,属性名存储在变量中,需要通过对象来操作变量的方式获取新增数据,则只能使用数组关联法

    ​ 使用数组关联法的时候,如果中括号中是变量,则不能用引号包裹,否则不能识别

操作对象

  • 给现有对象添加键值对

    ​ 同上赋值方法

  • 修改现有对象的键值对 同上赋值方法,覆盖

  • 删除对象中的内容 方法: delete delete obj.age

  • 查对象中的属性的值

    obj.age

对象补充

1、对象的属性名只能是字符串
2、字面量对象的属性名是变量则需要使用中括号包裹
3、对象的属性名如果是字符串拼接起来的则也需要用中括号包裹
4、如果对象的属性名有特殊符号比如 border-style, 在访问的时候需要用数组关联法
5、访问对象属性值的时候,如果属性名不存在则返回undefined
6、对象的属性名 如果有数字属性名,则先按数字排序,然后按写入的顺序排序
7、对象转为字符串
	语法: String(对象)
	返回值: '[object Object]'
	注意: 所有对象通过String方法转为字符串的返回值都以样

数据存储的相关地址

  1. 数据存储过程中的数据分为:基本数据类型、复杂数据类型
  2. 存储空间分为:栈内存空间、堆内存空间
    • 栈内存空间:存储基本数据类型的变量以及变量值, 复杂数据类型的变量名,变量名字的值是复杂数据类型在堆内存中的一个地址
    • 堆内存空间:存储复杂数据类型的值

所以:就算对象值是一样的变量的名字不一样,两个地址也是不一样的

数组

  • 是js中的一个复杂数据类型(引用数据类型)

  • 数组:一个有序的数据集合

  • 数组中的每一个元素(数据) 都有对应的 序号 也就是索引

  • 索引是以0开始的连续自然数

  • 使用符号: [ ]

例:arr=[1,"111","你好",true,null]

数组里面的内容:

​ 之间使用逗号分割 ​ 数值、布尔值不需要带引号,字符串需要带引号

多维数组

  • 数组可以存储任何数据类型

  • 数组也可以存储数组

  • 数组中是数组多层嵌套的我们称之为 多维数组

  • 数组中嵌套数组两层,就是二维数组

    var arr = [
    	['江西', '广东'],
    	['南昌', '赣州', '吉安'],
    	['广州', '深圳', '东莞'] 
    ];
    

声明数组

  1. 字面量创建(声明)数组: var arr1 = [ ] //空数组

    • 声明并赋值:

      var arr1 = [1, 2, 3, true]
      
    • 先声明,再赋值:

      var arr1 = []	//空数组
      arr1[0] = "乐乐"
      arr1[1] = 18
      
  2. 构造函数的方法创建(声明)数组: var arr2 = new Array( ) //使用new创建,Array首字母必须大写

    • Array 内置构造函数

      var arr = new Array() 空数组
      var arr = new Array(5) 得到一个长度为5的数组,但是每一个元素数据是empty
      

    var arr = new Array(1,2,3,4,5) 得到一个有数据的数组

    
    - 声明并赋值:
    
    ```javascript
    var arr2 = new Array("1","乐乐",18)
    
    • 先声明,再赋值:(一般实际开发的时候设置个数)

      var arr2 = new Array()	//括号中传入数组中的项目个数
      arr2[0] = "乐乐";
      arr2[1] = "18";
      

数组的特性

  • 数组索引

    • 索引都是从0开始的连续自然数

    • 索引就是 数组元素对应的 序号,也叫做 下标

    • 数组的索引属性,是可读可写的属性

    • 读(获取)

      语法: 数组[索引]
      得到: 索引对应的 数组数据
      如果索引对应位置没有数据,则返回 undefined
      
    • 语法: 数组[索引] = 值
      	如果 索引 和 数组的长度 一样,则添加了一个数组元素在数组的最后面
      	如果 索引 比 数组的长度 小,则就是覆盖式修改索引对应数据
      	如果 索引 比 数组的长度 大,则对应的索引添加数据,空出来的索引位置都用empty替代
      
  • 数组的长度属性

    • 这是一个可读可写的属性

    • 数组的长度就是 数组元素的个数

    • 读取

      语法: 数组.length
      
    • 语法: 数组.length = 数字
      	如果数字 比原来 数组长度 更小, 则会删除多余的数组元素
      	如果数字 和原来 数组长度 一样, 则没有变化
      	如果数字 比原来 数组长度 更大, 则新的索引位置的都是empty
      
    • 数组长度和数组索引的关系

      • 数组长度-1,就是数组索引的最大值

遍历

遍历:循环访问到每一个内容,专门用来遍历复杂数据类型(遍历数组,遍历对象)

  • 遍历数组(循环打印数组中的每一项)

    • for方法:

      for (var i = 0; i < arr.length; i++) {	//i  代表的是下标
          console.log(arr[i])
      }
      
    • for in方法:

      //循环次数为:arr.length,数组的长度
      for(var i in arr){  //通过for in方法在arr中进行数据的遍历,i当做的是下标
          console.log(arr[i])
      }
      
  • 遍历对象

    • for方法:

      ​ 对象不是纯数值的下标,所以for循环不能使用

    • for in方法:

      //使用for in方法循环遍历obj对象,i当做的是下标索引
      for (var i in obj) {
          console.log(i); //获取到的是键
          console.log(obj[i]);
      }
      

数组的常用操作方法

1、push-向数组尾部添加数据

  • 数组.push(参数)
作用: 将参数追加到数组的末位--追加数组元素
返回值: 返回追加元素后数组的 长度
注意: 会改变原数组

2、pop-删除数组尾部一项数据

  • 数组.pop()
作用: 将数组的最后一个元素删除
返回值: 返回删除的元素
注意: 会改变原数组

3、unshift-向数组头部添加数据

  • 数组.unshift(参数)
作用: 将参数添加到数组的最前面--添加数组元素
返回值: 返回添加元素后数组的 长度
注意: 会改变原数组

4、shift-删除数组头部一项数据

  • 数组.shift()
作用: 将数组的第一个元素删除
返回值: 返回删除的元素
注意: 会改变原数组

5、reverse-数组的反转

  • 数组.reverse()
作用: 数组元素位置反转
返回值: 是反转后的数组
注意:会改变原数组

6、splice-数组的删除、截取

  • 数组.splice(参数1,参数2,参数3)
语法1: 数组.splice(起始索引,个数)
作用: 从 起始下标开始删除数组中的多个(传入的个数)元素,将删除的元素组成一个新的数组返回

语法2: 数组.splice(起始索引,个数,在删除的开始位置添加的元素...)
作用: 从 起始下标开始删除数组中的多个(传入的个数)元素,将删除的元素组成一个新的数组返回,并从第三个参数开始作为数组的新元素从删除位置开始写入原数组

参数1:起始下标
参数2:截取删除的个数
	如果第二个参数不传,则默认删除从起始索引开始到最后一个元素
参数3:被替换的内容(可不写)
	如果参数3没有参数,则只对数组删除,不进行添加新内容
	如果参数3有参数,则会在删除的基础上,添加替换新的内容
	有参数3,不一定是删除;不一定删除多少个就得添加多少个
注意:如果参数2为0,代表不删除,添加替换的内容的下标为起始下标

返回值: 返回一个新数组
改变原数组  

7、sort-排序方法

  • 数组.sort()
作用: 数组元素排序,如果数组元素都是数字,或数字字符串,则按位比较大小排序
如果不是数组的话,按照Unicode编码排序
返回值: 排序完成的数组
会改变原数组

升序:

arr.sort(function(a,b){
	return a - b;
})
参数必须是一个函数,函数要有两个形参,且函数返回两个形参的差值
返回值: 排序完成的数组
会改变原数组

降序:

arr.sort(function(a,b){
	return b - a;
})
参数必须是一个函数,函数要有两个形参,且函数返回两个形参的差值
返回值: 排序完成的数组
会改变原数组

8、fill-填充数组

  • 数组.fill(要填充的数据,起始索引,结束索引)
作用: 填充数组, 从开始索引到结束索引填充数据
如果不写起始索引,则从[0]开始
如果不写结束索引,则到最后结束
特点: 填充的时候,包前不包后(包含前面的索引,不包含后面的索引)
会改变原数组

9、flat-拍平数组(多维数组)

  • 数组.flat(参数)
作用:拍平数组(多维数组)
如果传入的参数是数字,参数是几就拍平几层的数组
如果传入的是Infinitiy 则拍平所有层级
返回值: 拍平后的数组
不会改变原数组

10、find-查找返回符合条件的第一个元素

  • 数组.find(function(item,index,arr){回调函数})
作用: 查找数组中符合条件的第一个元素并返回
条件在回调函数中以 return的形式书写
返回值: 符合条件的元素,如果没有则是undefined
不会改变原数组

例:var res = arr.find(function (a,b,c) {
	return a > 7;
})

11、查找返回符合条件的第一个元素索引

  • 数组.findIndex(function(item,index,arr){回调函数})
作用: 查找数组中符合条件的第一个元素的索引并返回
条件在回调函数中以 return的形式书写
返回值: 符合条件的元素索引,如果没有则是返回值 -1
不会改变原数组

例:var res = arr.findIndex(function (a,b,c) {
	return a > 7;
})

12、reduce-数组累加方法

  • 数组.reduce(function(prev,item,index,arr){ 回调函数 },初始值)
作用: 数组累计方法

1、如果没有传入初始值:
	1) 第一次执行回调函数的时候, prev就是数组的第一个元素,item是数组的第二个元素,index就是item的索引,arr就是原数组
	2) 第二次之后执行回调函数的时候,prev就是上一次函数执行的返回值return的结果, item就是当前循环执行的数组元素,index就是item的索引,arr就是原数组

2、如果有传入初始值:
	1) 第一次执行回调函数的时候, prev就是初始值,item是数组的第一个元素,index就是item的索引,arr就是原数组
	2) 第二次之后执行回调函数的时候,prev就是上一次函数执行的返回值就是return的结果, item就是当前循环执行的数组元素,index就是item的索引,arr就是原数组

回调函数最后一次执行的返回值,就是return的内容,就是reduce方法的返回值

例:var res = arr.reduce(function (prev, item, index, arr) {
	return prev + item;
}, 0)

13、slice-截取数组

  • 数组.slice(起始索引,结束索引)
参数:(起始索引,结束索引)包前不包后,可以传负数
作用: 根据起始和结束索引,截取数组中的元素组成新数组返回
返回值: 一个截取的新数组
不会改变原数组

14、join-数组转字符串

  • 数组.join(参数)
如果参数不传递,则默认使用逗号拼接
作用: 函数中元素拼接,按照传入的参数拼接为字符串
返回值: 拼接好的字符串
不会改变原数组

例:
var arr= [1,2,2,3,4]	arr.jojn()	==>  1,2,2,3,4  字符串
var arr= [1,2,2,3,4]	arr.join('-')  ==>  1-2-2-3-4  字符串

15、concat-合并数组

  • 数组.concat(数组,数据....)
会将传入的参数和原始数组中的数据合并在一个新的数组中,如果参数是数组,则会将数组中的元素合并在新数组中
作用: 合并数组
返回值: 合并后的新数组
不会改变原数组

16、indexOf-查找第一次出现的索引

  • 数组.indexOf(参数,起始索引)
如果没有传参数2:
	从[0]开始 查找参数在数组中第一次出现的索引,如果不存在返回-1
如果有传参数2:
	从[起始索引]]开始 查找参数在数组中第一次出现的索引,如果不存在返回-1
返回值: 索引或-1

17、lastIndexOf-反向查找第一次出现的索引

  • 数组.lastIndexOf(参数,起始索引)
如果没有传参数2:
	从后往前开始 查找参数在数组中第一次出现的索引,如果不存在返回-1
如果有传参数2:
	从[起始索引]开始往前 查找参数在数组中第一次出现的索引,如果不存在返回-1
返回值: 索引或-1

18、forEach-数组遍历方法

  • 数组.forEach(funciton(item,index,arr){ 回调函数 })
数组有多个元素,回到函数执行多少次
参数1:循环中数组的每一个元素
参数2:循环中每个元素对应数组索引
参数3:调用方法的原数组
作用: 遍历数组
返回值: 没有返回值--undefined
forEach方法重构:
function myForEach(cb) {
	for (var i = 0; i < this.length; i++) {
		cb(this[i],i,this)      
	}
}
var arr1 = ['a', 'b', 'c', 'd'];
Array.prototype.myForEach = myForEach;
arr1.myForEach(function b(item,index,arr) {
	console.log( item,index,arr );
})

19、map-数组映射方法

  • 数组.map(function(item,index,arr){ 回调函数 })
参数1:循环中数组的每一个元素
参数2:循环中每个元素对应数组索引
参数3:调用方法的原数组
映射操作 需要写在函数内的 return 后
作用: 将数组的每一个元素通过映射操作为新数组的元素
返回值: 和原数组长度一样的新数组
新数组的元素,都是通过映射操作后的数据
不会改变原数组
map方法重构:
Array.prototype.myMap = myMap;
function myMap(cb) {
	var ary = [];
	for (var i = 0; i < this.length; i++) {
		var res = cb(this[i], i, this);
		ary.push(res);
	}
	return ary;
}
var arr = [100, 200, 300, 400, 500];
var newArr = arr.myMap(function (v, i, ar) {
	return v + 10;
})
console.log(newArr);

20、filter-数组过滤

  • 数组.filter(function(item,index,arr){ 回调函数 })
参数1:循环中数组的每一个元素
参数2:循环中每个元素对应数组索引
参数3:调用方法的原数组
过滤操作的过滤条件 需要写在函数内的 return 后
作用: 根据过滤条件 将满足条件的元素数据,组成新的数组并返回
返回值: 返回一个新数组,新数组中的元素都是满足过滤条件的数据
不会影响原数组
filter方法重构:
Array.prototype.myFilter = function (cb) {
	var ary = [];
	for (var i = 0; i < this.length; i++) {
		var r = cb(this[i], i, this);
		r && ary.push(this[i]);
	}
	return ary;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var newArr = arr.myFilter(function (v, i, ar) {
	return v % 2 === 0;
})
console.log(newArr)

21、some/every-数组判断方法

  • some

    数组.some(function(item,index,ar){回调函数})

    如果 数组中 某一个元素满足条件 则返回 true
    如果 数组中 所有元素都不满足条件 则返回 false
    条件书写在回调函数的return 后;
    如果 元素满足条件则循环结束
    返回值: 布尔值
    
    some方法重构:
    Array.prototype.mySome = function (cb) {
    	for (var i = 0; i < this.length; i++) {
    		var r = cb(this[i], i, this);
    		if (r) return true;
    	}
    	return false;
    }
    var arr = [1, 2, 3, 4, 5];
    var res = arr.mySome(function (k) {
    	console.log(k)
    	return k > 10;
    })
    console.log(res)
    
  • every

    数组.every(function(item,index,arr){回调函数})

    如果 数组中 所有元素都满足条件 则返回 true
    如果 数组中 某一个元素不满足条件 则返回 false
    条件书写在回调函数的return 后;
    如果 元素不满足条件则循环结束
    返回值: 布尔值
    
    every方法重构:
    Array.prototype.myEvery = function (cb) {
    	for (var i = 0; i < this.length; i++) {
    		var r = cb(this[i], i, this);
    		if (!r) return false;
    	}
    	return true;
    }
    var arr = [1, 2, 3, 4, 5];
    var res = arr.myEvery(function (k) {
    	console.log(k);
    	return k < 3;
    })
    console.log(res);
    

22、includes是否包含

  • 数组.includes(参数)

    作用: 查询数组是否包含参数
    返回值: 布尔值
    

数组塌陷

  • 遍历数组,通过splice删除数组元素,则会发生数组元素塌陷

  • 因为删除了数组元素,则数组的索引和长度发生变化,所用遍历的时候会塌陷

  • 解决方案1: 在splice删除元素后i--

  • 解决方案2: 倒序遍历删除

    var arr = [1, 2, 5, 5, 5, 6, 7];
    // 要求删除数组中的所有5
    
    //方案一:
    for (var i = 0; i < arr.length; i++) {
    	if(arr[i]===5){ // 判断数组元素是否是5
    		arr.splice(i,1);
    		i--;
    	}    
    }
    console.log( arr )
    
    //方案二:
    for (var i = arr.length - 1; i >= 0; i--) {
    	if (arr[i] === 5) { // 判断数组元素是否是5
    		arr.splice(i, 1);      
    	}
    }
    console.log(arr)
    

数组去重

  • 方法一:
    • 将arr数组中的元素逐个添加新数组中,如果该元素在新数组中存在则不添加
  • 方法二:
    • 将arr数组中的元素逐个添加新数组中,如果该元素在新数组中存在则不添加
    • 使用数组方法 includes
    • 语法: 数组.includes(参数)
    • 作用: 判断参数在数组中是否存在
    • 返回值:布尔值 true表示存在,false不存在
  • 方法三:
    • 将数组的元素当做对象的属性名使用,然后遍历对象,将属性名转为数组
    • 因为对象的属性名是唯一的(不重复)
  • 方法四:
    • 使用Set数据集合完成去重
    • 伪数组转为真数组
    • 将数组作为创建set集合的参数使用
    • set数据集合最大的特点数里面的数据不能重复
    • 语法:Array.from(伪数组)
    • 返回真数组
方法一:
var newArr = [arr[0]];
for (var i = 0; i < arr.length; i++) {
var flag = true; // 定义flag变量赋值为true,表示arr[i]在新数组中不存在
	for (var j = 0; j < newArr.length; j++) {
		if (arr[i] == newArr[j]) {
			flag = false;
			break;
		}
	}
	if (flag == true) newArr.push(arr[i]);
}
console.log(newArr)
方案二:
var newArr = [arr[0]];
for (var i = 0; i < arr.length; i++) {
    // 遍历新数组,判断arr[i]在数组中是否存在
	if (!newArr.includes(arr[i])) newArr.push(arr[i]);
}
console.log( newArr )
方案三:
var obj = {};
	for (var i = 0; i < arr.length; i++) {
    	// 将数组元素arr[i]  当做对象的属性名使用
    	// 当数组元素 找对象的属性名中第一次出现则作为属性名,且值为1
		obj[arr[i]] = 1;
	}
var newArr = [];
	// 遍历对象,将属性名写到newArr中
for (var key in obj) {
	newArr.push(key-0)
}
console.log( newArr )
方法四:
var s = new Set(arr);
// set数据也是一个伪数组集合
var newArr = Array.from(s);
console.log( newArr );

数组的注意事项

  • 索引 都是 从0开始的自然数
  • 数组长度 是数组元素的个数
    • 数组长度-1就是索引最值
    • arr['66']=999 数字字符串会默认转为数值当做数组索引
    • arr['六十六']=888 不会将'六十六'当做数组索引使用,而是当做属性名使用

伪数组

  • 和数组一样具有数组的 索引和长度特性

  • 但是不能够使用数组方法

    function fn(){
    	Array.from(arguments).forEach(function(){})
    	// arguments
    	// 函数内的arguments--实参集合--伪数组
    }
    
  • 将伪数组转为真数组

    • Array.from(伪数组)

冒泡排序

  • 原理:

    1. 以数组为例,两两进行比较,前一位和后一位进行比较
    2. 如果前一位比后一位大,则二者进行交换,这一轮比较会实现最大值在最后
    3. 接着进行下一轮循环遍历,再次两两比较,两两交换,得到第二大的数值在倒数第二位
    4. 再进行下一轮循环遍历...
  • 代码:

    for (var j = 0; j < arr.length-1; j++) { //循环的次数
        for (var i = 0; i < arr.length-1-j; i++) { //比较的次数
            //判断:前面的一项是否大于后面的一项
            //如果大于则进行交换,不大于则不交换
            if (arr[i] > arr[i + 1]) {
                var a = arr[i]; //第三变量用于承接做交换
                arr[i] = arr[i + 1];
                arr[i + 1] = a;
            }
        }
    }
    //双重循环外侧打印arr
    console.log(arr)
    

选择排序

  • 原理

    1. 先假定数组中的第 0 个就是最小的数字的索引
    2. 然后遍历数组,只要有一个数字比我小,那么就替换之前记录的索引
    3. 知道数组遍历结束后,就能找到最小的那个索引,然后让最小的索引换到第 0 个的位置
    4. 再来第二趟遍历,假定第 1 个是最小的数字的索引
    5. 在遍历一次数组,找到比我小的那个数字的索引
    6. 遍历结束后换个位置
    7. 依次类推,也可以把数组排序好
  • 代码

    for (var j = 0; j < arr.length - 1; j++) {
    	var minIndex = j; //假设下标[j]就是最小值
    	for (var i = j + 1; i < arr.length; i++) { //遍历数组,逐个比较
    		if (arr[i] < arr[minIndex]) { //如果有更小的数据
          		minIndex = i; // 则将下标记录在minIndex中
        	}
      	}
        //循环结束后,minIndex就是最小值的索引
        //判断minIndex中和一开始假设的最小索引是否一致
    	if (minIndex !== j) { //如果不一致,则交换数据
        	var temp = arr[minIndex];
        	arr[minIndex] = arr[j];
        	arr[j] = temp;
    	}
    }
    

计数排序

  • 原理

    将原数组中的数据当做新数组中的索引使用(数组索引的自动排序)
    将新数组中的值 作为计数器(累计元素中相同元素的个数)
    遍历新数组
    将新数组中有值的索引 一次写入到原数组中
    前提: 清空原数组
    
  • 代码

    var arr = [10, 20, 3, 5, 6, 1, 9, 3, 4, 5, 7]
    var newArr = [];
    // 遍历原数组,将数组中的数据作为newArr的索引
    for (var i = 0; i < arr.length; i++) {
    	// arr[i] 数组的数据 作为新数组的索引
    	// 值: 如果第一次出现则赋值为1,后续还有则累加
    	!newArr[arr[i]] ? newArr[arr[i]] = 1 : newArr[arr[i]]++;
    }
    // console.log( newArr )
    // 清空原数组
    arr.length = 0;
    // 遍历新数组,可将有值的索引 写入原数组
    for (var j = 0; j < newArr.length; j++) {
    	// 如果 该索引没有值,表示不是原数组中的数据,则结束本次循环,直接到下一次
    	if (!newArr[j]) continue;
    	// 遍历(累计的次数),将索引写入原数组
    	for (var i = 0; i < newArr[j]; i++) arr.push(j);
    }
    console.log(arr)
    

插入排序

  • 原理

    1. 取一个数组元素,和之前的元素逐个比较,如果比他更小,则交换位置
    2. 直到找到比这个元素大的,则将这个元素放到该元素后
    
  • 代码

    var arr = [3, 1, 5, 6, 4, 9, 7, 2, 8]
    // 1. 遍历数组
    for (var i = 1; i < arr.length; i++) {
    	// 2.将第i个元素存到临时变量中
    	var temp = arr[i];
    	// 3. 将arr[i] 依次和前面的所有数据比较
    	var j = i - 1;// j就是i前一个元素的所用
    	while (arr[j] > temp) {
    		arr[j + 1] = arr[j]
    		j--;
    	}
    	// 循环结束的时候,说明 arr[j]>temp 为fasle
    	// 说明 arr[j]<temp,则将temp的值放到[j+1]的位置
    	arr[j + 1] = temp;
    }
    console.log(arr)
    

快速排序(递归二分法)

function quickSort(arr) {
	// arr 形参接收到 一个乱序的数组
	// 1. 先书写暂停条件
	if (arr.length == 1 || arr.length == 0) return arr;
	// 2. 获取数组的中间数
	// 2.1 获取中间数的索引
	var centerIndex = parseInt(arr.length / 2);
	// 使用splice取出数组中间数-----注意 splice返回值是一个数组
	var center = arr.splice(centerIndex, 1)[0];
	// 3. 循环arr数组
	var small = []; // 接受比中间数小的数据
	var big = []; // 接受比中间数大的数据
	for (var i = 0; i < arr.length; i++) {
		arr[i] > center ? big.push(arr[i]) : small.push(arr[i]);
	}
	// 形成递进关系  small 和 big 也需要二分法排序
	return [].concat(quickSort(small), center, quickSort(big));
}

var arr1 = [6, 1, 2, 9, 3, 5, 7, 4, 8]
// 调用函数 进行排序
console.log(quickSort(arr1))

回调函数

  • 概念:

    • 将函数a 作为函数b 的实参传递
    • 在函数b内部,通过形参的方式调用函数a
    • 此处我们 将函数a称之为 回调函数
    function b(cb) {
        // cb 接收的就是全局函数a的地址
        // cb() 就是调用了全局函数a
    	cb();
    }
    function a() {
    	console.log('全局函数a')
    }
    // 变量a中存储的是一个函数地址
    // 将这个作为实参传递到b函数内
    b(a)
    
  • 回调函数作用

    • 封装异步相关的内容
    • 封装遍历相关的内容
例:利用回调函数仿写一个sort方法
function mySort(cb) {
	var arr = [7, 5, 3, 1, 2, 4, 6];
	// 使用冒泡排序
	for (var k = 0; k < arr.length - 1; k++) {
		for (let i = 0; i < arr.length - 1 - k; i++) {
			// cb() 就是调用了 函数b
			var res = cb(arr[i], arr[i + 1])
			if (res >= 0) {
				var temp = arr[i];
				arr[i] = arr[i + 1];
				arr[i + 1] = temp;
			}
		}
	}
	console.log(arr)
}
function b(param1, param2) {
	// return param1 - param2; // 升序
	return param2 - param1; // 降序
}
mySort(b)

复杂数据类型的赋值

复杂数据类型赋值过程中赋值的是地址,
每一个变量都可以通过这个地址访问到该数据,
只要有一个与之相关的变量修改了对应的数据,其他变量再访问的也是修改后的结果

深浅拷贝

拷贝: 将一个变量中的数据赋值一份

一般我们说拷贝的时候,都是值对象或数组类型数据

拷贝分为三个等级:
赋值
	就是将一个变量中的值赋值一份给到另一个变量
	如果复杂数据类型则,两个变量操作同一个存储空间
浅拷贝
	将对象中的第一层数据都 复制一份 赋值给另一个空对象
	两个对象 中的第一层值都一样
	for-in 遍历对象完成浅拷贝
	通过 展开运算符 ... 实现浅拷贝
深拷贝
	对象无论多少层 都将数据拷贝到新的对象中
	拷贝完成后,无论怎么改变新对象中的数据 都不会影响原来的对象

函数中的赋值

  • 实参为基本数据类型
    • 赋值的是值,一个变量修改不影响其他变量
  • 实参为复杂数据类型
    • 赋值的是地址,一个变量的修改会影响其他变量
    • 因为变量能通过地址访问到数据

this

this的英文含义:这是一个**,指代的是某一个东西 程序里是一个关键词,不是变量

  • this在全局使用的时候代表的是:window
  • this在局部使用的时候代表的是:
    • 使用 函数名() 进行调用,this始终代表的是window
    • 使用 对象.键名() 进行调用,this代表的是当前对象
  • 事件函数中的this:
    • this就代表的是触发事件函数的对象,也就是这个元素

严格模式

开启严格模式:在代码的最前方,输入字符串 'use strict'

严格模式状态下:

  1. 声明变量的时必须添加var
  2. 严格模式下,函数中没有this指向的问题
  3. 函数传递参数过程中的形参,不能使用相同的名字 使用相同的形参名字,只会保留最后一个的值

字符串

  • 字符串在存储中是基本数据类型

  • 在js中 字符串 包装数据类型

    包装数据类型: 
    	当字符串调用方法,访问数据的时候
    	会将基本数据类型的字符串,临时的转为复杂数据类型
    	当方法或属性使用完毕后,将字符串转为基本数据类型
    	包装数据类型是为了便于使用字符串
    
  • 字符串创建

    • 字面量创建 var str = 'qwert'
    • 内置构造函数创建**var str = new String('qwert')**
  • 字符串的索引属性

    • 只读
    • 语法: 字符串[索引]
    • 作用: 通过索引找到字符串中对应的字符
    • 字符串[索引] 就是将字符串是包装数据类型使用
  • 字符串的长度属性

    • 只读
    • 语法: 字符串.length
    • 作用: 获取字符串中字符个数
  • 遍历字符串

    • 通过 for循环,索引当做循环变量 ,条件:索引<长度

按照字符串中存储的内容来进行适当的分类

普通字符串: 'qwert'
数字字符串: '12436'
html格式字符串: '<div></div>'
查询字符串: 'key1=value1&key2=value2..'
json格式字符串: '{"name":"zs","age":18}';
	作用: 用于前后交互使用 

字符串的常用方法

1、charAt()

  • 字符串.charAt(索引)
作用: 在字符串中查找传入索引对应的字符
返回值: 索引对应的字符,如果索引不存在,则返回空字符串''

2、charCodeAt()

  • 字符串.charCodeAt(索引)
作用: 在字符串中查找传入索引对应字符的编码
返回值: 传入索引对应的字符编码,如果索引不存在,则返回 NaN

3、toUpperCase()/toLowerCase()

  • 所有字符大写 字符串.toUpperCase()

  • 所有字符小写 字符串.toLowserCase()

作用: 将字符串中的字母转为都转为小写
返回值: 转换后的字符串

4、substr()

  • 字符串.substr(起始索引,截取个数)
作用: 截取字符串
返回值: 截取的字符串

5、substring()

  • 字符串.substring(索引,索引)
会自动将大的索引当做结束索引
会自动将小的索引当做起始索引
包前不包后(不包含结束索引)
#注意如果不书写结束索引则是从开始索引到最后
作用: 截取字符串
返回值: 截取的字符串

6、slice()

  • 字符串.slice(起始索引,结束索引)
包前不包后(不包含结束索引)
注意如果不书写结束索引则是从开始索引到最后
#结束索引可以使用负数,-1表示最后一个,-2倒数第二个,-3.....
作用: 截取字符串
返回值: 截取的字符串

7、indexOf()

  • 语法1:字符串.indexOf(字符片段)

  • 语法2:字符串.indexOf(字符片段,起始索引)

语法1: 
字符串.indexOf(字符片段)
作用: 从开头开始查找传入的字符片段 在原字符串中的位置,并返回索引,结束查找
返回值: 索引 或 -1 (在字符串中不存在)

语法2: 
字符串.indexOf(字符片段,起始索引)
作用:从起始索引开始查找
返回值: 索引 或 -1 (在字符串中不存在)

8、lastIndexOf()

  • 语法1:字符串.lastIndexOf(字符片段)

  • 语法2:字符串.lastIndexOf(字符片段,起始索引)

语法1: 
字符串.lastIndexOf(字符片段)
作用: 从尾部开始往前查找传入的字符片段 在原字符串中的位置,并返回索引,结束查找
返回值: 索引 或 -1 (在字符串中不存在)

语法2: 
字符串.lastIndexOf(字符片段,起始索引)
从起始索引开始往前查找
返回值: 索引 或 -1 (在字符串中不存在)

9、replace()

  • 字符串.replace(替换下的字符片段,替换上的字符片段)
作用: 字符串替换
返回值: 替换后的字符串

10、search()

  • 字符串.search(字符片段)
作用: 在原字符串中查找存入的字符片段,并返回索引 (只会从前往后查找)
返回值: 索引 或 -1(不存在)

11、trim()

  • 字符串.trim()
作用: 清除字符串前后两边的空白字符
返回值: 清除空白后的字符串 

12、trimLeft()/trimRight()

  • 字符串.trimLeft()

  • 字符串.trimRight()

作用: 清除字符串左/右边空白字符
返回值: 清除空白后的字符串 

13、split()

  • 字符串.split(分隔符号)
如果不传参数或者传递的分隔符在原字符串中不存在,则将原字符串当做数字的一个元素返回
如果传入空字符串,则会将原字符串的每一个字符 都进行分隔,都作为数组的元素
作用: 按照传入的分隔符号,将字符串分割为多段,当做数组元素
返回值: 字符串分割后 组成的数组

14、startsWith()

  • 字符串1.startsWith(字符串2)
作用:判断`字符串1`是否以`字符串2`开头
返回值:布尔值

15、endsWith()

  • 字符串1.endsWith(字符串2)
作用:判断`字符串1`是否以`字符串2`结尾
返回值:布尔值

所有字符串方法都不能改变原字符串内容

Math

Math数学常用方法

1、random-生成0~1随机数

  • Math.random()

    生成一个随机数:0-1之间的随机数;包括0但不包括1
    

2、abs-绝对值方法

  • Math.abs(数字)

    作用: 取绝对值
    返回值: 正数/ 0
    

3、max-一组数中的最大值

  • Math.max(一组数)

    Math.max(1,9,3,11)
    传入的是一组数,不是一数组
    一组数不能带引号,多个数字之间用逗号隔开
    如果传入数组,则返回NaN
    作用: 取多个数字中的最大值
    返回值: 数字
    

4、min-一组数中的最小值

  • Math.min(一组数)

    Math.min(1,9,3,11)
    传入的是一组数,不是一数组
    一组数不能带引号,多个数字之间用逗号隔开
    如果传入数组,则返回NaN
    作用: 取多个数字中的最小值
    返回值: 数字
    

5、ceil-向上取整

  • Math.ceil(数字)

    无论小数点后面是几都向前进1
    作用: 对数字进行向上取整操作
    返回值: 整数
    

6、floor-向下取整

  • Math.floor(你要操作的数字)

    无论小数点后面是几,直接把小数点后面的省略掉
    作用: 对数字进行向下取整操作
    返回值: 整数
    

7、round-四舍五入

  • Math.round(数字)

    51
    作用: 对数字进行四舍五入操作
    返回值: 整数
    

8、pow-平方,次方

  • Math.pow(底数,指数)

    作用: 取底数的多少次幂(次方)
    返回值: 数字
    

9、sqrt-开平方

  • Math.sqrt(数字)

    作用: 取数字的平方根
    返回值: 数字
    

10、PI-π的值

  • Math.PI

    返回值:3.1415926......
    注意:PI是大写,后面没有小括号
    作用: 获取圆周率
    

11、toFixed-保留几位小数

  • 变量.toFixed(参数)

    保留小数点后几位,遵循四舍五入的原则
    

生成一个区间随机数

Math.floor(Math.random()*(max-min+1)+min)
例:生成3~15的区间随机数,含头含尾
	Math.floor(Math.random()*(13)+3)

Date

Date时间对象

  • Date在js中是一个复杂数据类型

  • Date 是js内置的用于创建时间对象的 构造函数

  • 一般创建的时间对象都是终端的时间为准(有时区)

  • 创建时间对象

    • 语法1: new Date()
  • 返回当前的时间对象

  • 语法2: new Date(参数)

    1、参数是数值
    	1)只有一个数字参数
    		会将该数字当做时间戳来创建时间对象
    		时间戳: 格林尼治时间,1970年 1月1日0:0:0到某一个时刻的毫秒数
    	2)有两个以上的数字参数
    		YYYY  年份
    		MM    月份 0~11(0表示1月,11表示12)
    		DD    日期 
    		hh    小时
    		mm    分钟
    		ss    秒
    		注意: 数字超出范围会自动递进
    2、参数是字符串: 一个时间格式的字符串
    	new Date('2022-07-21 09:50:00')
    	new Date('2022/07/21 09:50:00')
    	new Date('2022.07.21 09:50:00')
    	注意: 在字符串中的月份 1表示1月份
    

Date时间日期对象常用方法

  • 获取当前的本地(客户端)时间:
    • var t = new Date()
  • 设置将来时间:
    • var t = new Date("2022-05-01 00:00:00")
    • var t = new Date(2022,04,01,00,00,00)

Date方法

  • 就是操作时间对象的方法

  • 主要有两套时间方法

    • get一套
    • set一套
  • 关键单词

    FullYear  年份
    Month     月份
    Date      日期
    Day       星期
    Hours     小时
    Minutes   分钟
    SecondsMilliseconds 毫秒
    Time      时间戳
    UTC       世界时间 
    
  • 获取年份

    t.getFullYear()

  • 获取月份

    t.getMonth()

    返回值:0-11
    
  • 获取日期

    t.getDate()

  • 获取星期

    t.getDay()

    0表示星期天
    1表示星期一
    6表示星期六
    
  • 获取小时

    t.getHours()

  • 获取分钟

    t.getMinutes()

  • 获取秒

    t.getSeconds()

  • 获取毫秒

    t.getMilliseconds()

  • 获取时间戳

    t.getTime()

  • 获取世界时间

    t.getUTCHours()

  • 设置年份

    t.setFullYear(2035)

  • 设置月份

    t.setMonth(2)

    输入的参数:0表示1月,11表示12月
    
  • 设置时间戳

    t.setTime(20000000000)

js操作CSS样式

元素.style.CSS属性 = 值

**注意:**CSS属性如果是单一属性的话, 需要使用驼峰法转换 例:box.style.backgroundColor="yellow"

数字转换成进制

  1. 数字.toString(参数)

    参数: 2~36的数字, 表示将数字转为多少进制的字符串
    	不传参数则默认 转为十进制的数字字符串显示
    作用: 将数字转为字符串(多少进制的字符串显示)
    返回值: 字符串
    
  2. 变量.parseInt(参数1,参数2)

    参数1:要转换的内容
    参数2:转换成的进制数
    含义:(参数2)的(参数1)转成十进制显示
    作用: 将字符串为十进制数字显示,将字符串当做几进制的数看待
    返回值: 转换后的10进制数字,如果无法转换则为NaN
    

BOM

  • BOM -- Browser Object Model 浏览器 对象 模型
  • BOM操作 就是浏览器提供了的API来操作浏览器这个软件的相关内容
  • 也就是说 BOM操作都是对象操作
  • BOM中的顶级对象 是 window
  • BOM操作 都可以省略 window.
  • 全局中的 this和top关键字都是指向 window
  • 在全局中通过var 关键字定义的变量或声明式定义的函数 默认是挂载在window对象上
  • window对象中name是一个比较特殊的属性,name属性的值必须是字符串对象,设置别的类型会默认转为字符串类型

获取可视窗口大小

窗口大小包含滚动条
宽:width.innerWidth
高:window.innerHeight

BOM弹窗

  1. 提示框:

    alert("弹出内容")

    表现: 提示信息 + 确定按钮
    没有返回值
    
  2. 可输入的弹窗:

    prompt(提示内容,默认值)

    参数1:提示语
    参数2:输入框的默认值
    表现: 提示信息 + 输入框 + 确定按钮 + 取消按钮
    如果想要使用输入弹窗中的值需要使用一个变量去接收
    返回值:
    	确定:返回内容(字符串类型)
        取消:返回null
    注意:输入框中获取的数据默认是字符串类型
    
  3. 确认取消框:

    confirm("提示语")

    表现: 提示信息 + 确定按钮 + 取消按钮
    返回值:
    	确认:true(真)
    	取消:false(假)
    

注意: 所有弹窗都会终止浏览器的渲染

浏览器的标签页

  1. 开启一个新的标签页
window.open(url)
open(url,窗口名,参数)
  1. 关闭当前标签页
window.close()

地址栏

  • 浏览器访问页面的url
http://www.baidu.com:80/search/error.html?name=zs&age=18#123
	http 超文本传输协议;https 安全的超文本传输协议
    www.baidu.com  域名 一个域名对应了一个IP地址,一个IP地址就是远程服务器
	80  是端口号,http默认80,https默认 443
	/search/error.html  请求地址
    name=zs&age=18 查询字符串  发起请求携带给请求地址的数据
    #123  哈希字符串 页面(锚点)定位
    
{
	hash: "#123"
	host: "www.baidu.com"
	hostname: "www.baidu.com"
	href: "http://www.baidu.com/search/error.html?name=zs&age=18#123"
	origin: "http://www.baidu.com"
	pathname: "/search/error.html"
	port: ""  端口
	protocol: "http:"
	search: "?name=zs&age=18"
}

location

  • 如何获取到浏览器的地址?

  • window中有一个属性location,是一个对象

    • href属性-获取设置地址

      可以获取设置浏览器的地址栏
      获取: location.href
      设置: location.href = 地址
      	设置浏览器的地址栏,页面会自动刷新请新的地址
      
    • reload 方法-刷新浏览器

      可以刷新浏览器
      location.reload()
      注意: 不要写在全局中
      
    • 直接给 location赋值也可刷新页面请求新的地址

      location = 地址
      
    • assign 刷新页面请求新地址

history历史记录

history是window中的一个对象
histoty对象中默认会存在一个length属性:
	在不同的浏览器中lentgh显示的数值不一样
	谷歌浏览器和火狐浏览器里面默认的长度属性值为1
	低版本的ie浏览器里面lentgh默认的取值为0
  • 前进:

    • history.forward()
  • 后退:

    • history.back()
  • 前进后退 go方法:

    • history.go(参数)
    • 参数>0表示前进
    • 参数<0表示后退
    • 参数==0刷新当前页面
    • 参数==2代表前进两个页面

浏览器对象

window下有一个navigator属性
这个属性对象中存储了浏览器的信息

load加载事件

在页面所有资源加载完毕后执行

基本语法: 
window.onload = function(){
	执行的js代码片段
}
应用位置:
	1)head标签内部
	2)</body>位置的前面
位置不同实现的作用都是一样的:让页面所有资源(页面结构,css,js,图片..)加载完毕之后,再去执行load事件函数
注意:
	如果将js代码放在</body>的前面的话,window.onload可以不添加,直接写js代码即可,因为代码自上而下运行
	如果在头部(head标签)获取元素,并且进行修饰的话,则需要在头部添加window.onload方法
	给script标签添加defer="defer",defer代表延迟加载

scroll滚动事件

当浏览器的滚动条发生滚动的时候,触发对应的事件函数,执行代码片段

基本语法:

window.onscroll=function(){代码片段}

  • 获取浏览器卷去的距离:

    获取方法:
    	没有!doctype:
    		document.body.scrollTop
    		document.body.scrollLeft
    	有!doctype:
    		document.documentElement.scrollTop
    		document.documentElement.scrollLeft
    IE浏览器中没有!doctype的时候,两个方法都行
    谷歌浏览器中没有!doctype的时候,使用(短的方法)document.body.scrollTop
    谷歌浏览器中有!doctype的时候,使用(长的方法)document.documentElement.scrollTop
    同时兼容:
    	var aa= 长的方法 || 短的方法
    scroll还能使用scrollLeft(左右滚动)
    

resize窗口变化事件

当浏览器的页面大小发生变化的时候,触发对应的事件函数,执行代码片段

基本语法: 
	window.onresize=function(){
        代码片段
    }

设置页面滚动到某个位置

  • 通过给scrollTop/scrollLeft赋值

    • 没有DOCTYPE声明

      document.body.scrollTop = 值
      document.body.scrollLeft = 值
      
    • 有DOCTYPE声明

      document.documentElement.scrollTop = 值
      document.documentElement.scrollLeft = 值
      
    • 注意: 瞬间到达目标位置

  • 通过scrollTo() 方法

    • window.scrollTo(参数)
      • 参数是一个对象
      • 对象中有top属性和left属性
      • 是瞬间到达,可以添加参数对象属性
        • ehavior,默认值为instant 就是瞬间到达
        • 可以选参数 smooth 可以平滑到达目标位置
window.scrollTo(水平坐标, 垂直坐标)
	例:	window.scrollTo(100, 200)
	例:	window.scrollTo({top: 200,left: 100,behavior: "smooth"})
behavior: "smooth"	匀速

定时器

  • 一次性定时器
    • setTimeout(function(){执行代码},2000,实参1...)
    • 表示2000毫秒==2秒后执行代码
    • 只执行一次程序
    • 第三个参数开始往后的参数,都是函数执行的实参
  • 周期性定时器
    • setInterval(function(){执行代码},3000,实参1...)
    • 每隔多长时间让程序执行一次,会反复执行
    • 第三个参数开始往后的参数,都是函数执行的实参
定时器的返回值:
	与页面中定时器的个数有关系(返回第几个定时器),可用于关闭定时器
	往往实际开发的时候,定时器使用完毕之后,降低内存消耗
	把定时器函数的返回值清空掉tim1=null
	
定时器函数的执行顺序:
	所有的定时器函数中的内容,都是等待主程序跑完之后,再执行(异步执行)
  • 清空定时器
    • 清空一次性定时器:clearTimeout()
    • 清空周期性定时器:clearInterval()

​ 一般情况下,两种清空定时器方法,建议一一对应使用,但可以混用

DOM

  • DOM ---- Document Object Model 文档对象模型
  • 在DOM操作中 docuemnt是DOM中的顶级对象
  • DOM 操作 就是操作浏览器的文档流内容
  • DOM操作 基本都是操作页面元素(标签)
    • 页面元素的 增删改查
    • 页面元素的属性操作(id type class...)
    • 页面元素的样式
    • 页面元素的内容
    • .....
  • DOM中一些特殊的元素
    • document 文档流 承载了页面所有内容,也是window对象的一个属性
    • html 页面根元素节点 页面中最大的标签
    • head 头部元素标签, 此标签中的内容一般都是对页面的设置
    • body 页面中显示的内容都是在这个标签中的

标签属性分类

  • 原生属性
    • 在W3C规范中有的属性名
    • 比如: id、class、style、type、src、href、checked....
  • 自定义属性
    • 在W3C规范中没有的属性名,是我们自己书写在标签上的
  • H5自定义属性
    • 目的: 就是为了区分和原生属性在标签上的形式
    • 要求: 书写H5 自定义属性的时候,都得以 data- 开头
    • 比如: data-index=666
      • data- 表示这个就是 H5自定义属性
      • index 表示属性名
      • '666'表示属性值

操作元素的样式

  • 标签属性:元素.HTML自身属性
  • CSS样式:元素.style.CSS样式名

​ 通过js操作的CSS属性都是属于行内样式,获取的样式也是操作后的行内样式

  • 获取内部、外部样式表中样式(包含了行内和非行内样式):

    • 非IE浏览器:window.getComputedStyle(元素).样式名

      window.getComputedStyle(元素)['样式名']

      • computed:计算属性,里面存储的是该元素能设置的所有的属性
    • IE浏览器(IE8及以下):元素.currentStyle.样式名

      元素.currentStyle['样式名']

#注意: 涉及到带中划线的样式名的时候
	#转为驼峰写法:  ele.style.backgroundColor
	#使用数组关联法:  ele.style['background-color']

输入、获取页面标签中的内容

  • 元素.innerHTML

    可读可写
    
    获取(读):
    	如果标签内的内容为代码片段,使用该方法,会将代码片段获取到
    	如果标签内没有代码只有文本,则会把文本获取到
    设置(写):
    	元素.innerHTML="赋值"
    	赋值的时候,如果你元素中有内容,则新内容会将原内容覆盖
    	如果新赋值的内容,是代码片段,则会被运行,不是代码片段则不影响
    
    作用: 完全覆盖式的书写标签的超文本内容
    注意: 可以识别解析 html格式字符串
    
  • 元素.innerText

    只能获取标签中的文本
    可读可写
    
    获取(读): 
    	无论标签中是否有代码,或者只有文本,只能获取到文本
    设置(写):
    	元素.innerText="赋值"
    	
    作用: 完全覆盖式的书写标签文本内容
    注意: 没有办法识别解析 html格式字符串
    
  • 表单元素.value

    这是表单标签的原生属性操作
    可读可写
    
    获取(读):
    	表单元素.value
    	得到: 该标签元素的value值
    设置(写):
    	表单元素.value = '值'
    	作用: 设置标签元素的value值
    

操作元素的类名

  • 目的: 批量的修改元素的样式

  • className

    • 元素.属性名
    其实就是原生属性操作
    因为 js中有一个关键字 calss,为了避开改名叫做 className
    注意: 类名的值 是字符串,可能是多个类名一起的
    
  • classList

    每一个元素身上都有一个属性叫 classList
    该属性对应的值是一个类似于数组的数据结构,方法是该元素的所有类名
    类名的增删改查 都是对元素的classList操作的,有专门的方法
    
    方法:
    	增: 元素.classList.add(类名)
    	删: 元素.classList.remove(类名)
    	切换: 元素.classList.toggle(类名)
    		原来元素有该类名则删除,没有则添加
    

获取页面中的元素

  1. 通过元素id名获取

    document.getElementById("id属性值")

    document----页面文档
    get---------得到
    Element-----元素
    By----------通过某种方式
    Id----------id的名字获取元素
    返回值:
    	返回 页面中id属性和传入的id值一致的第一个标签元素
    	如果页面中没有 传入的id属性值的标签, 则返回null 
    特殊情况:如果给元素添加了id属性,id属性值就代表了这个元素
    
  2. 通过元素class名获取

    document.getElementsByClassName("class名")

    返回值:
    	返回 页面中 具有传入类名的 所有那标签元素组成的一个伪数组
    	如果页面中没有 具有传入类名的标签元素, 则返回空的伪数组
    想要访问对应的元素,则需要使用下标
    
  3. 通过元素的标签名获取

    document.getElementsByTagName("标签名")

    返回值:
    	返回 页面中所有对应相同标签名的页面元素元素组成的一个伪数组
    	如果页面中没有 没有对应的标签, 则返回空的伪数组
    访问则需要使用下标
    
  4. 通过元素的name属性获取

    document.getElemntsByName("name属性值")

    应用在:获取表单元素中
    返回的是一个类数组,访问需使用下标
    

获取页面中的元素-选择器方法

  • 方法1:document.querySelector("选择器")
    • 只会取一个元素
    • 返回值:
      • 返回 页面中 第一个满足选择器的标签元素
      • 如果选择器 没有选中页面元素 返回null
  • 方法2:document.querySelectorAll("选择器")
    • 返回的是一个类数组,访问内容需要使用下标
  • 返回值
    • 返回 页面中 所有满足选择器的标签元素 组成的伪数组
    • 如果选择器 没有选中页面元素 返回空的伪数组
    • 通过此方法获取页面元素返回的伪数组 实现了forEach遍历方法
    • 此方法和数组的forEach遍历方法用法一致
  • 注意: 选择器一定要带符号 .box #box ul>li

获取元素尺寸

  • 第一套语法:

    元素.offsetWidth	(内容 + padding + border 区域的宽度)
    元素.offsetHeight	(内容 + padding + border 区域的高度)
    
  • 第二套语法:

    元素.clientWidth	(内容 + padding 区域的宽度)
    元素.clientHeight	(内容 + padding 区域的高度)
    

获取元素的偏移量

  1. 获取元素的偏移参考元素

    元素.offsetParent

    得到: 该元素的偏移量参考父级
    	就是该元素的定位父级
    	如果到body都没有定位父级,那么这里的offsetParent就是body 
    
  2. 第一套语法

    元素.offsetLeft
    	获取元素相对于offsetParent(定位父级) 的左侧距离
    元素.offsetTop
    	获取元素相对于offsetParent(定位父级) 的上方距离
    
  3. 第二套语法

    元素.clientLeft
    	获取元素(内容+padding区域) 相对于该元素border左边的尺寸
        就是左边框的宽度
    元素.clientTop
    	获取元素(内容+padding区域) 相对于该元素border上边的尺寸
    	就是上边框的宽度
    
  • 元素.offsetWidth

    计算的是元素的内容,内边距和边框的实际距离
    
  • 元素.offsetHeight

    计算的是元素的内容,内边距和边框的实际距离
    

获取可视窗口的尺寸

  • DOM级别获取: 不包含滚动条
    • document.documentElement.clientWidth
    • document.documentElement.clientHeight

获取和修改标签自身的属性

  • 元素.属性 获取属性的值
  • 元素.属性=值 修改属性对应值

获取和设置HTML标签属性

  • 元素.attributes
    • 返回一个存储所有属性的对象
  • 元素.attributes.id
    • 返回标签中的id属性和属性值
  • 元素.attributes[0]
    • 也可以使用数组下标的方法访问对应的内容

获取和设置HTML标签属性的值

  • 元素.getAttribute("属性名")

    作用:直接获取到HTML标签属性的值
    get---------得到
    Attribute---一个属性
    
  • 元素.setAttribute("参数1","参数2")

    作用:修改对应的属性的值
    参数1:对应的属性名
    参数2:更换后的属性值
    注意:如果参数2没有值,代表的清空属性的值
    

删除属性

  • 元素.removetAttribute("属性名")

    获取到元素才能删除
    经常应用在选项卡切换的过程中
    

获取节点

节点:页面进行渲染的时候,都是将所有的标签、文本、属性、注释,都当做一个DOM树进行加载渲染

  • 节点的分类:

    • 元素节点
    • 文本节点
    • 空节点
    • 属性节点
    • 注释节点
  • 获取非常规元素节点

    html:	document.documentELement
    head:	document.head
    body:	document.body
    
  • 获取常规元素节点

    document.getElementById()
    document.getElementsByClassName()
    document.getElementsByTagName()
    document.querySelector()
    document.querySelectorAll()
    
  1. 获取元素里面所有的节点

    父节点.childNodes

    得到: 该父节点下的所有子一级节点
    
  2. *获取元素内部的所有元素节点

    父节点.children

    得到: 该父节点下的所有子一级元素节点
    
  3. 获取第一个子节点

    父节点.firstChild

    得到: 该父节点下的第一个子节点
    
  4. *获取第一个子元素节点

    父节点.firstElementChild

    得到: 该父节点下的第一个子元素节点
    
  5. 获取最后一个子节点

    父节点.lastChild

    得到: 该节点下的最后一个子节点
    
  6. *获取最后一个子元素节点

    父节点.lastElementChild

    得到: 该节点下的最后一个子元素节点
    
  7. 获取当前元素的后面一个兄弟节点

    节点.nextSibling

    得到: 该节点的下一个兄弟节点
    
  8. *获取当前元素的后面一个兄弟元素节点

    节点.nextElementSibling

    得到: 该节点的下一个兄弟元素节点
    
  9. 获取当前元素的前面一个兄弟节点

    节点.previousSibling

    得到: 该节点的上一个兄弟节点
    
  10. *获取当前元素前面一个兄弟元素节点

    节点.previousElementSibling

    得到: 该节点的上一个兄弟元素节点
    
  11. 获取当前元素的父节点

    节点.parentNode

    得到: 该节点的父节点
    
  12. 获取当前元素的所有属性节点

    节点.attributes

    得到: 该节点的所有属性节点,包括自定义的属性
    
  13. 获取该节点的父节点

    节点.parentElemen

    得到: 该节点的父元素节点
    

节点属性

  • 属性节点: 节点类型的一种

  • 节点属性: 描述节点的信息

  • 所有的节点都共有的内容,只是不同节点值不一样

  • 节点类型

    节点.nodeType

    返回值:
        元素节点: 1
        属性节点: 2
        文本节点: 3
        注释节点: 8
    
  • 节点名字

    节点.nodeName

    返回值:
        元素节点: 大写的标签名
        属性节点: 属性名
        文本节点: #text
        注释节点: #comment
    
  • 节点内容

    节点.nodeValue

    返回值:
        元素节点: null
        属性节点: 属性值
        文本节点: 返回文本内容
        注释节点: 返回注释的内容
    

操作节点

创建节点

  1. 创建一个dom元素节点

    document.createElement("标签名")

    返回值: 一个被创建的标签
    
  2. 创建一个文本节点

    document.createTextNode("文本")

    返回值: 文本节点
    

追加节点

  • 向后追加

    父节点.appendChild(追加节点)

    作用: 将子节点插入到父节点内,并放在最后的位置
    
  • 向前追加

    父节点.insertBefore(参数1,参数2)

    参数1:追加节点
    参数2:插入在哪一个子节点前面
    作用: 将子节点插入到父节点内,并指定放在那个节点之前    
    
  • 注意:

    节点输出的时候,只能使用追加,不能使用document.wirte(),不能使用innerHTML,因为节点是一个对象
    创建一个元素节点只能使用一次,只能追加一次
    

删除节点

  • 直接删除自身节点

    节点.remove()

    作用: 把节点自己移除
    
  • 删除某个元素节点

    父节点.removeChild(子节点)

    作用: 把子节点从父节点中移除
    例:	ul.removeChild(ul.children[1])
    

替换节点

  • 父元素节点.replaceChild(新节点,旧节点)

    作用: 在父节点内容,新节点 替换掉 旧节点
    

克隆节点

  • 节点.cloneNode(布尔值)

    复制一模一样的节点
    	如果没有任何参数的话,则只克隆当前节点
        取值为false的话,表示不克隆后代节点,则克隆当前节点
        取值为true的话,表示克隆后代节点 ,则克隆当前节点及以内的所有节点
    

创建文档碎片

  • document.createDocumentFragment();

字符串的拼接

  • 创建文档碎片
    • 语法: document.createDocumentFragment()

将数据拼接到表格

例:var arr = [
	{name: "Jack",age: 18,gender: "男",},
	{name: "Rose",age: 20,gender: "女",},
	{name: "Top",age: 22,gender: "男",},
	{name: "申帅",age: 18,gender: "未知",},
	{name: "静雅",age: 16,gender: "女",}
]

[for方法]
	var str = "<table>";
	for (var i = 1; i <= 3; i++) {
		str += "<tr>";
		for (var j = 1; j <= 3; j++) {
			str += "<td>" + "234" + "</td>";
		}
		str += "</tr>";
	}
	str += "</table>";
	document.write(str)

[for in方法]
	var str = "<table>";
	for (var i = 0; i < arr.length; i++) {
		str += "<tr>";
		for (var a in arr[i]) {
			//console.log(arr[i])//对象
			//console.log(a)//键
			str += "<td>"+arr[i][a]+"</td>";
		}
		str += "</tr>";
	}
	str += "</table>";
	document.write(str);

事件

事件:需要通过鼠标、键盘、滚动等一系列行为才能实现的效果,这种触发效果称之为事件
事件的组成部分:
	1)事件对象:触发事件的事件源
	2)事件类型:触发事件的事件类型,click、scroll
	3)触发事件执行的事件函数
	例:div.onclick=function(){}
		div		事件源
		on		添加、绑定
		click	事件类型
		function(){}	事件函数
	
[提示]循环绑定单击事件定义变量用let

鼠标事件

  1. 单机事件

    元素.onclick = function(){}

    点击一次,鼠标按下,鼠标抬起,形成一次单机
    
  2. 双击事件

    元素.ondblclick = function(){}

    连续点击鼠标两次
    
  3. 鼠标按下事件

    元素.onmousedown = function(){}

    按下的那一瞬间触发事件函数
    
  4. 鼠标抬起事件

    元素.onmouseup = function(){}

    松开鼠标的那一瞬间触发事件函数
    
  5. 鼠标移动事件

    元素.onmousemove = function(){}

    当鼠标移动的时候触发事件函数
    
  6. 鼠标移入移出事件

    • 第一对

      mouseover 鼠标进入 mouseout 鼠标离开

      如果是父子元素的话,鼠标移入到子元素的时候,会再一次触发事件函数
      有事件冒泡
      
    • 第二对

      mouseenter 鼠标进入 mouseleave 鼠标离开

      如果是父子元素的话,鼠标移入到子元素的时候,不会再次触发事件函数
      有事件捕获
      #注意:此对事件天生获取不到事件目标
      
  7. 右击事件

    元素.oncontextmenu = function(){}

  8. 鼠标滚动事件

    wheel

    向下滚动  e.deltaY>0
    向上滚动  e.deltaY<0
    

键盘事件

  1. 键盘按下抬起事件keypress

    元素.onkeypress=function(){}

    输入框输入的时候,执行对应的事件函数
    如果一直按着不放的话,则会一直触发事件函数
    不是实时获取输入框中的值,因为第一次按下的时候触发了,获取的是空
    只有数字和字母,和部分的符号键可以触发
    上下左右,回车,tab,ctrl都不会触发
    注意:获取的字母按键的编码区分大小写
    
  2. 键盘按下事件keydown

    元素.onkeydown=function(){}

    按下的那一瞬间触发
    获取值的时候,也会轮空一轮
    能支持键盘上的所有按键
    注意:获取的字母按键的编码不区分大小写
    
  3. 键盘抬起事件keyup

    元素.onkeyup=function(){}

    松开键盘的那一瞬间触发
    获取值不会轮空,获取实时的值
    支持大部分的键盘摁键
    

UI表单事件

  1. focus获取焦点事件

    元素.onfocus=function(){}

    获取到焦点的那一瞬间,触发事件
    
  2. blur失去焦点事件

    元素.onblur=function(){}

    失去焦点的那一瞬间,触发事件
    
  3. input修改值事件(输入事件)

    元素.oninput=function(){}

    每修改一次值的时候,触发事件
    一般用于输入框
    
  4. change修改值并失去焦点事件(改变事件)

    元素.onchange=function(){}

    修改值,并失去焦点的时候,触发事件
    一般用于select,input=file
    
  5. submit提交事件

    onsubmit="return true"可以提交
    onsubmit="return false"不可提交
    需要绑定给form标签
    当点击submit按钮的时候,会触发form标签的默认提交
    
  6. reset重置事件

    需要绑定给form标签
    当点击reset按钮的时候,会触发form标签的默认重置行为
    页面会刷新
    

浏览器事件

加载事件:load
	window.onload = function(){}
滚动事件:scroll
	window.onscroll = function(){}
页面大小改变事件:resize
	window.onresize=function(){}

触摸事件

  • 专门用于触摸屏幕设备
    1. touchstart 触摸开始
    2. touchmove 触摸移动
    3. touchend 触摸结束

其他事件

  1. selectstart 选中开始
  2. visibilitychange 切换页面
    • document有一个属性**visibilityState** 可视状态
      • 值为**visible** 标识课件
      • 值为**hidden** 标识不可见

拖曳事件

至少需要三个事件组合完成:鼠标按下事件、鼠标移动事件、鼠标抬起事件
关系:鼠标按下的时候才能拖动,移动事件需要在按下事件里面
	抬起鼠标的时候,不在移动,直接让移动事件函数为空(页面的鼠标移动事件解绑)

事件绑定

  • 绑定事件的基本方法(DOM 0级别):

    • 事件源.on事件类型=事件处理函数
    • 元素.onclick=function(){}
    • **弊端:**如果绑定多个相同的单击事件,后面的事件把前面的事件覆盖掉了,两个事件不能同时执行
    • 特点: 同一个事件源的同一个事件类型只能绑定一个事件处理函数
  • DOM 2级别使用事件监听的方法:

    非IE浏览器(标准浏览器):
    	元素.addEventListener("参数1",参数2,参数3)
    	元素		绑定事件的目标
    	add		添加
    	Event	事件
    	Listener	监听
    	参数1:事件类型,没有on,只有事件名
    	参数2:事件函数function(){}
    	参数3:冒泡还是捕获,事件触发的行为机制,要不要均可
    		true/false
    		捕获/冒泡 
        [小健]特点: 同一个事件源的同一个事件类型可以绑定多个事件处理函数,按照绑定顺序执行
    	这种绑定方式,解决多个相同事件同时被覆盖的问题:顺序绑定,顺序执行
    IE浏览器(低版本IE):
    	元素.attachEvent("参数1",参数2)
    	元素		绑定事件的目标
    	attach	添加、绑定
    	Event	事件
    	参数1	事件类型,事件类型需要带on
    	参数2	事件函数function(){}
    	注意:IE浏览器里面只支持冒泡,不支持捕获
    	注意:IE11不支持该方法
    		在IE10,IE9里面是顺序绑定,顺序执行
    		但是在IE8以下顺序绑定倒叙执行
        [小健]特点: 同一个事件源的同一个事件类型可以绑定多个事件处理函数,按照绑定顺序倒序执行
    

事件解绑

  • DOM 0级 事件解绑

    • 语法: 事件源.on事件类型 = null
    因为 "=" 赋值符号 覆盖的原因,就可以实现解绑
    
  • DOM 2级 事件解绑 - 标准浏览器

    • 语法: 事件源.removeEventListener('事件类型',解绑的事件函数)
    注意: 2级事件,如果你要解绑,那么在绑定的时候,需要把函数单独书写,以函数名的形式绑定
    
  • DOM 2级 事件解绑 - 低版本IE

    • 语法: 事件源.detachEvent('on事件类型',解绑的事件函数)
    注意: 2级事件,如果你要解绑,那么在绑定的时候,需要把函数单独书写,以函数名的形式绑定
    

事件对象

事件对象--Event
触发事件函数的同时,对于这个事件的一个描述
比如,点击这个盒子的时候,点击的是什么位置,坐标等等这些都是事件对象中的内容
鼠标事件对象跟键盘事件对象一样,只不过在不同的事件中e代表的内容不一样
获取触发的事件对象:
	标准浏览器:
		直接在事件处理函数位置接受一个形参,形参就是事件对象
		会在事件触发的时候,浏览器自动传递的实参
	低版本IE:
		在事件处理函数内,通过window.event获取
获取对象中的值:
	window.event.键(属性)
	e.键(属性)
	例:console.log(window.event)、console.log(window.event.x)、console.log(window.event.y)
兼容问题:
	可以直接通过函数传递参数的方法去获取事件对象
	例:
		box.onclick=function(e){	//形参e代表了事件对象,e是event的简写,方便理解
			//兼容
			e = e || window.event
			console.log(e)
		}
事件对象.type 就可以获取到本次事件的事件类型


键盘事件对象:
e打印的结果:
	KeyboardEvent {isTrusted: true, key: '1', code: 'Digit1', location: 0, ctrlKey: false, …}
	keyboard	键盘
	event		事件
	{  }		对象
事件对象中必须知道的几个属性:
	key		"1/空格/enter/control"  代表的是按下的哪一个键
	keyCode	"键盘按键的键码"
		向左:37,向上:38,向右:39,向下:40,回车:13
	target	触发事件函数的目标
	type	事件类型
    currentTarget	事件绑定对象
    
获取键码:
	语法:事件对象.keyCode
	考虑键码获取的兼容性的问题:
		语法:事件对象.keyCode || 事件对象.which (兼容火狐浏览器)
	得到: 一个编码,每一个按键有的一个自主的独立编码(Unicode)
	#注意: 
		keydown事件对象获取的字母按键的编码不区分大小写
		keypress事件对象获取的字母按键的编码区分大小写

鼠标坐标信息

获取事件对象中的内容

  • 事件对象.offsetX,事件对象.offsetY

    鼠标在元素内部的坐标位置
    边框里面的位置,不包括边框,包括内边距的位置
    不受滚动条的影响
    鼠标光标相对于 事件目标 左上角的坐标位置
    console.log(e.offsetX)
    
  • 事件对象.clientX事件对象.clientY

    鼠标距离浏览器可视窗口的坐标
    不受滚动条的影响
    始终都是鼠标落点与浏览器左上角之间的距离
    
  • 事件对象.screenX,事件对象.screenY

    鼠标落点,距离显示器左上角的坐标位置
    
  • pageX,pageY

    距离左上角body(文档流)的坐标位置
    页面就算有滚动条,始终都是计算鼠标落点与左上角body的坐标位置
    

鼠标按键信息按键

事件对象.button

返回值:
    0	(左键)
    1	(滚轮键)
    2	(右键)

组合键

组合键一般需要配合键盘上面的ctrl,alt,shift等这些键一起使用
事件对象中为我们提供了三个属性,用来检测组合键
	事件对象.ctrlKey
	事件对象.altKey
	事件对象.shiftKey
	事件对象.metaKey  (win: win键,mac:command)
使用的时候必须配合这三个键来使用
以上四个按键的值都是布尔值: true表示按下,false表示没有按下
例:
    ipt.onkeyup = function (e) {
        if (e.keyCode == 13 && e.ctrlKey && e.altKey) {
            console.log(this.value);
        }
    }

事件抛发(自定义事件)

  • 之前的事件绑定中,绑定的事件类型,都是浏览器已经有的

  • 还有一个事件绑定的方式,可以给DOM元素绑定任意的自定义事件,就是

    1. 创建事件对象
      • 语法: var evt = new Event('自定义的事件类型');
    2. 绑定事件---事件绑定的方式和常见的事件绑定方式一样
      • 语法: 事件源.addEventListener('自定义的事件类型',事件处理函数)
    3. 将绑定的事件 抛发----手动触发
      • 语法: 事件源.dispatchEvent(事件对象)
    例:
    // 1. 创建事件对象
    var evt = new Event('hello');
    // 2. 绑定自定义的hello事件
    document.addEventListener('hello', function () {
    	console.log('你好!')
    	console.log(this)
    })
    // 3. 事件抛发---手动触发事件
    document.dispatchEvent(evt);
    
    DOM对象之可以绑定事件并事件抛发.由于DOM元素对象继承了EventTarget这个类
    其实addEventListener,removeEventListener,dispatchEvent三个是EventTarget的方式
    

事件目标

  • 事件目标:当事件触发的时候,那个准确触发事件的元素
  • 当你给一个元素绑定事件后
    • 在该元素上触发行为,是可以触发事件处理函数
    • 在该元素的后代元素身上触发行为,也可以触发事件处理函数
  • 获取事件目标
    • 标准浏览器: 事件对象.target
    • 低版本IE: 事件对象.srcElement
  • 注意: mouseenter和mouseleave 天生获取不到事件目标

事件传播(冒泡和捕获)

  • 概念: 当用户在浏览器中触发指定行为的时候,会按照 结构父级 向上传递行为
  • 事件目标 开始,传递到 **window**为止
    • 事件目标->....-> bady -> html -> document -> window
  • 在事件函数中,可以通过 事件对象.path 获取到 事件目标开始的传播路径
  • 在事件传播的过程中,任何浏览器都只能在一个阶段触发
  • 在低版本IE中,只能在冒泡阶段触发事件,不能在捕获阶段触发事件
  • 其他浏览器中,默认会在冒泡阶段触发事件,保留了在捕获阶段触发事件的能力
事件触发的时候,代码执行(事件传播)机制问题
主要是在非IE浏览器中才能实现
	事件冒泡:
		从事件目标开始 顺着结构父级 一直到window都触发同类型的事件
		父子关系中,给父元素,和子元素绑定了对应的事件函数,
		点击子元素的时候,会你默认的触发到你的父元素上面,这种事件的执行机制被称之为事件冒泡
		事件执行从内向外触发
	事件捕获:
		先触发 window上的同类型事件,最后触发 事件目标的同类型事件
		父子关系中,,给父元素,和子元素绑定了对应的事件函数,
		执行顺序是,事件从外向内依次触发
		
在标准浏览器下,如何进行事件捕获触发行为
	DOM 0级事件,没有捕获,只有冒泡
	只有 addEventListener 是可以修改触发阶段
		设置完参数3,就决定了代码执行是冒泡阶段还是捕获阶段
			如果没有参数3,则默认是在冒泡阶段触发
			如果参数3为false,则为冒泡阶段触发(子=>父)
			如果参数3为true,则为捕获阶段触发(父=>子)
	注意: 同一个元素的同一个事件类型的事件处理函数,先进行捕获然后进行冒泡执行

阻止事件传播

IE浏览器阻止事件传播:
	e.stopPropagation()
IE浏览器阻止事件传播(冒泡):
	e.cancelBubble=true

事件委托

  • 把自己的事件委托给别人来做
循环绑定事件:
	缺点:
		给太多的元素绑定事件,DOM性能浪费
		对动态操作的元素不友好
事件委托:
	事件绑定过程中,通过利用事件冒泡原理,让父元素去做一些事情,
		把原本子元素上面应该干的事情,直接放在父元素上面去做
		使用是DOM2事件监听的方法完成
		需要使用e.target
	优点:
		只给一个元素绑定了一次事件
		对动态操作的元素友好
	核心: 利用了绑定事件的 默认事件行为的传播
		比如: a元素的事件,绑定给a元素的 结构父级
		在结构父级的事件内,通过 事件目标 判断 你准确点击的是 a元素

this和e.target
	使用循环事件绑定,this表示当前元素
	使用事件委托,e.target表示当前元素
例:
    ul.addEventListener("click",function(e){
        if(e.target.innerHTML=="+"){
            e.target.previousElementSibling.value++
        }else if(e.target.innerHTML=="-"){
            e.target.nextElementSibling.value--
        }
    })

阻止默认行为

默认行为:
	不需要事件绑定,天生自带的行为
	比如:
		a 标签的点击,只要点击了,会默认跳转或锚点定位
		表单提交,只要点击submit按钮,那么表单会自动提交
		鼠标右键点击,只要行为发生,会默认出现菜单
阻止默认行为:
	不让本身应该发生的事情发生
	在同类型的事件中,进行默认事件的阻止

标准浏览器: 
	事件对象.preventDefault()
低版本IE: 
	事件对象.returnValue = falseDOM 0级事件中 也可以通过 在事件处理函数中return false;阻止默认行为
注意: 
	return false; 一定要写在处理函数的最后面,因为return 还会终断函数代码的执行
	保证前面的代码不报错,因为js中代码报错,抛出异常,则 后续代码不会执行
阻止表单默认提交:
    document.querySelector('form').addEventListener('submit',function(e){
        e.preventDefault();
        console.log( '已经阻止了表单的默认提交行为' );
    })

阻止默认选中:
    document.querySelectorAll('p')[0].onselectstart = function () {
        console.log( '别想选中内容了' );
        return false;
    }

放大比例公式(放大镜案例)

-x*(大图宽度-大盒子宽度)/(中图宽度-遮罩层宽度)
-y*(大图高度-大盒子高度)/(中图高度-遮罩层高度)

this指向

  • 官方: 指当前代码执行的上下文环境(context) 也就是执行上下文

  • 私人解释:

    • 就是在一个作用域中(全局/局部)的关键字
    • 全局作用域 this
      • 在全局作用域中,this就是 window
    • 函数作用域 this
      • 定义: 函数中的this 和函数定义在哪里没有关系,和函数的调用(执行)方式有关(箭头函数除外)
    1.普通调用
    	函数名()
    	函数内的 this 指向 window
    2. 对象调用
    	对象.函数名()
    	函数内的this 指向 调用函数的对象
    3. 事件处理函数
    	事件源.on事件类型 = 函数
    	事件源.addEventListener('事件类型',函数)
    	事件触发的时候,执行的函数中 this 指向 事件源(绑定事件的元素)
    4. 定时器处理函数
    	setTimeout(函数,毫秒)
    	setInterval(函数,毫秒)
    	函数内的this 指向 window
    5. 自调用函数(立即执行函数)
    	;(函数)()
    	!(函数)()
    	~(函数)()
    	函数调用后会立即执行,而且函数内的this 指向window
    
    总结:
    1)全局里面:this=>window
    2)普通函数:this=>window
    3)对象里面的函数:this=>与函数调用有关系
    	函数名()=>window
    	对象.键()=>对象
    	数组[索引]()=>数组
    4)事件函数:this=>事件源
    5)定时函数:this=>window
    6)自调用函数:this=>window
    7)箭头函数中的this:#箭头函数中的`this`就是 定义箭头函数作用域中的 `this`
    	1、箭头函数中没有自己的this指向
    	2、箭头函数中的this,根据上下文来决定this指向
    	3、如果单机事件中有一个箭头函数,箭头函数中的this指向单机事件的事件源
    	4、如果单机事件中有一个定时器函数,定时函数使用箭头函数,定时器函数中的this指向单机事件的事件源
    	5、箭头函数中this与代码调用没有关系
    	6、箭头函数的this指向箭头函数所在作用域的上一级作用域的this
    

强行改变this指向

  • 强行改变this的指向

    • this的指向 是由函数的调用方式决定的
    • 就是在本次调用函数的时候,改变函数内 this 的指向
  • all

    • 函数名.call(指向,实参)对象.函数名.call(指向,实参)
    第一个参数: 此次执行函数内 this 的指向
    第二个参数开始: 依次给该函数的实参
    直接附加在函数后面直接调用使用,可以让他忽略原有函数中的this指向
    特点: 立即调用函数
    
  • apply

    • 函数名.apply(指向,实参数组)对象.函数名.apply(指向,实参数组)
    第一个参数: 此次执行函数内 this 的指向
    第二个参数: 是一个数组或伪数组集合,集合中的每一个数据,按照顺序依次作为函数执行的实参
    直接附加在函数后面直接调用使用,可以让他忽略原有函数中的this指向
    特点: 立即调用函数
    
  • bind

    • 函数名.bind(指向,实参)对象.函数名.bind(指向,实参)
    第一个参数: 新函数的内 this 的指向
    第二个参数开始: 依次给新函数调用的实参
    bind直接使用则返回代码片段,需要让代码片段执行所以需要用变量接收,调用这个变量
    特点: 不会立即中执行函数,而是返回一个新函数,新函数和原函数代码一模一样,只不过新函数中的this指向第一个参数,而且新函数中的this指向锁死了
     新函数中的this指向已经锁死,任何方式不能修改
    

ECMAScript

  • ES 就是 ECMAScript的简称

  • ES 就是 javascript的语法标准规范

    1997 ES1
    1998 ES2
    1999 ES2.1
    2000 ES3(目前我们使用的大部分语法都是ES3的标准语法)
    2001 (ES4版本夭折,因为ES4版本的语法有太多颠覆性的修改,这一版没有通过)
    2013 ES5 主要添加了一些数组方法
    2014 ES5.1版本已经被大部分浏览器兼容
    2015 ES2015(ES6)版本 推出了比较多的新语法 let const 箭头函数 展开运算符 promise...
    2016 ES2016(ES7) async/await语法
    2017 ES2017(ES8)
    2018 ES2018(ES9)
    2019 ES2019(ES10)
    2020 ES2020(ES11)  replaceAll    间隔数字写法 10-0000-0000
    2021 ES2021(ES12) 
    2022 ES2022(ES13)
    

动态表格

获取一个 table
var tr= table.insertRow()  插入行  <=>	document.createElement("tr")
        行有一个 rowIndex 属性 动态显示行号
var td=   tr.insertcell();  插入单元格 <=> document.createElement("td")
table.deleteRow(index); index 行号

ES5新增的数组方法

  • forEachmapfilter

    原理、例:
    	数组.forEach(function(x,y,z){})
    	arr.forEach(function (x, y, z) {
    		console.log(x);
    		console.log(y);
    		console.log(z);
    	})
    	==等价于==
    	for (var i = 0; i < arr.length; i++) {
    		fun(arr[i], i, arr)
    	}
    	function fun(x, y, z) {
    		console.log(x);
    		console.log(y);
    		console.log(z);
    	}
    

JSON

JSON:特殊字符串,字符串里有特定的格式
	一般里面放数组、数组对象、对象
格式:
	对象		var json1={}
	json格式字符串	var json2='{}'
	数组,数组里面存储对象		var json3=[{},{}]
	json格式字符串	var json4='[{},{}]'
注意:
	1. json格式的字符串中 只能 由 单引号包裹
    2. json格式的字符串中 只能 有 数组或对象类型结构的数据
    3. json格式的字符串中 不要有函数(自动过滤函数)
    4. json格式的字符串中 对象的属性名只能使用双引号包裹,文本内容也是只能由双引号包裹
	5. json格式的字符串中 对象或数组最后一项数据后不能有逗号

字符串和JSON数据转换

  • 将json格式的数据,转换成数组、对象
    • JSON.parse(json格式字符串)
    • 返回值: 转换后的数组或对象
  • 将数组、对象转换成json数据格式
    • JSON.stringify(数组或对象)
    • 返回值: json格式的字符串
  • 注意: 如果报错信息是 Unexpected token XXX in JSON at position 则说明JSON.parse中数格式错误
  • 实现深度拷贝
    • var obj2 = JSON.parse(JSON.stringify(obj))

JSON文件

以 .json 为后缀的文件,文件内容必须满足JSON字符串格式
可以把.json文件当成一个JavaScript文件来处理
	例:	<script src="./person.json"></script>

ES6

ES6-变量声明

除了使用var之外,还可以使用:let、const
变量声明:var、let
常量声明:const
变量:可以更改变化的量
常量:不可以更改的量,声明之后不能修改
  • let、const声明变量和var的区别

    1)let,const不能重复声明一个变量
    2)let,const不存在声明提前(预解析)
    3)let,const存在一个独立的块级作用域(也称之为‘暂时性死区’)
    	花括号{}就代表了一个块,只会在{}里起作用
    
  • let和const区别

    1)let可以重新赋值;const不能重新赋值
    	如果const声明基本数据类型,值不可修改
    	如果const声明复杂数据类型,可以修改内容,不可修改引用地址
    2)let可以先声明后赋值;const是不能先声明后赋值,只能声明并赋值
    

ES6-箭头函数

属于函数的一种,只是函数的一种简单的表达形式
只能应用在表达式声明的函数中简写
语法:var box=()=>{}
	()用来书写形参
    => 箭头函数的标志
	{}用来放函数体代码
对象中的函数:
	fn:()=>{console.log("乐乐")}
    
简写注意事项:
	1、()可以简写
    	箭头函数中只有一个行参时,()可以省略
        没有或者有多个行参时必须添加()
		var box=a=>{}
	2、{}可以简写
    	箭头函数中,只有一句表达式时,{}可以省略
        自动返回该行结果,自动把这句话的结果当做函数的返回值,所以不写 return
		var box=()=>console.log("乐乐")
		var box=a=>console.log("乐乐"+a)
		let fun1 = (a, b) => a + b; console.log(fun1(10, 20));


#箭头函数中的this
	箭头函数中的`this`就是 定义箭头函数作用域中的 `this`
    注意:事件函数中的代码片段,不推荐转换成箭头函数,改成箭头函数之后,this指向了window
箭头函数中的this:
		1)箭头函数中没有自己的this指向
		2)箭头函数中的this,根据上下文来决定this指向
		3)如果单机事件中有一个箭头函数,箭头函数中的this指向单机事件的事件源
		4)如果单机事件中有一个定时器函数,定时函数使用箭头函数,定时器函数中的this指向单机事件的事件源
		5)箭头函数中this与代码调用没有关系
		6)箭头函数的this指向箭头函数所在作用域的上一级作用域的this
        
#箭头函数中的arguments
	箭头函数中没有arguments对象
	不能使用 arguments

ES6-对象的简写

  • 对象的属性名和变量名同名,可以只写一次(值是变量)

    例:
    	let age = 20;
    	var obj = {
    		name: "张三",
    		age, // 等价于age:age
    		sex: "男"
    	};
    	console.log(obj);
    
  • 如果对象的属性是一个函数,function可以省略(不能是箭头函数)

     例:
    	var obj = {
            name: "张三",age:18,
            fun1: function () { console.log("普通函数") },
            fun2() { console.log("普通函数简写形式") }
        }
    

ES6-解构和赋值

解构:分解拆分结构
赋值:拆分完毕结构之后进行赋值
语法: 解构 = 数组/对象
赋值等号 左边的叫做: 解构
赋值等号 右边的叫做: 数组/对象
在[]内按照索引位置书写变量即可
在{}内书写对象结构的键名
解构和赋值使用的符号{}[]
	解构对象:{}
	解构数组:[]
多维数组解构:把原数组复制一份一模一样的放在结构的位置
对象的多维解构:
	结构多维对象数据
	直接把对象数据类型复制一遍,放到结构位置    
对象解构可以起别名:在解构中,除了书写可以获取的键名外,可以 `键名:别名`
例:
	var obj = {name: "乐乐",sex: "男",age: 100}
	var arr=["勇哥",'浠浠','鹏哥']
	解构对象	let { name, sex, age} = obj;
	解构数组	let [a,,c]=arr
注意:解构的变量中可以比原来少,也可以比原来多
	多的情况没有对应的键值,获取不到对应的值返回的为undefined
	变量的名字要与对象中的键保持一直
注意:解构的时候没有必要完全的解构出来,如果想要中间的不结构,一定要空开
	
如果对象或者是数组是多层结构,解构的时候也需要多层嵌套,格式必须一致
例:var brr=[1,[3],4]
	let [a,[b],c]=brr
		
例:对象解构起别名
let obj = {objname:'zs',userage:17}
let {objname:username} = obj;// 等价于 let username = obj.objname;
console.log( username ) // 'zs'

[交换变量]
	var a=3,b=4
	var [b,a]=[a,b]	右侧赋值给左侧

ES6-扩展运算符

也叫做展开运算符,主要是用来展开数组和对象
使用的符号:	...
用就是用来打散一数组,打散一对象
伪数组也可以
注意:
	展开的对象需要放在 {}
	展开的数组需要放在 [] 或 方法函数实参位置
    
	例:console.log(...arr)
	var brr=[...arr,"乐乐","申帅","静雅"]
	例:var obj = {name: "小张",sex: "男",age: 100}
	var obj1 = {...obj,love: "乐乐"}
如果用在形参上,会把实参的值合并成一个数组
	例:function fn(...a) {console.log(a);}	// 输出[10,20,30,40]
		fn(10, 20, 30, 40);
	例:function fun(a, b, ...c) {console.log(a, b, c);} // 输出 10 20 [30,40]
		fun(10, 20, 30, 40)
伪数组通过展开运算符转为真数组
	例:let lis = document.getElementsByTagName('li');
		let arrLis = [...lis]
[面试题]
	求最大值的方法:
	1)循环冒泡排序
	2)sort(function(a,b){return a-b})
	3)Math.max(...arr) 参数不能为数组,参数为一组数
	4)非得要从Math.max()传入数组:修改this指向
		var a=Math.max.apply(Math,arr);  console.log(a)

ES6-展开运算符

  • ... 既可以展开数组,也可以合并多个数据,得到数组
  • ...用于函数形参位置的时候,就是一个合并运算符,可以将多个实参合并起来得到一个数组
  • 合并运算符,可以适当的弥补箭头函数中没有arguments的缺陷

ES6-模块化语法

  • 模块化语法

    • 利用自身语法规则,在自己文件中引入其他文件
  • **(前提)**当你需要按照模块化语法进行开发的时候

    1. 当前页面的script标签需要一个type属性,值设置为module
      • 只有这样,浏览器在js语句的时候,才会按照模块化语法来解析
    2. 当前页面必须在服务器上打开,本地打开不能使用模块化语法
      • 在vscode中可以使用 Live Server 插件
  • 模块化语法规则

    • 当你开始使用模块化语法的时候
      • 每一个js文件都会变成一个独立js文件,互相之间没有任何联系和关系
      • 文件和文件之间不共通
      • 我们把每一个独立文件叫做 文件作用域(模块作用域)
    • 当你需要互通数据的时候
      • 需要使用导入导出语法
  • 导出语法:

    • 当前文件中,需要把一些数据向外暴露

      语法1: 
      	export default 数据
      语法2: 
      	export 数据
      
      例:
      //这是a.js模块
      // 这个文件就是一个 独立模块
      const num = 666;
      const str = 'hello';
      let fn = ()=>console.log( '我是a.js文件中的函数' );
      
      // 我希望别的文件引入 a.js 之后可以使用 某一些内容
      // 那么 我来导出,向外暴露
      const obj = {
        num,
        str
      }
      console.log( 'a.js执行了' )
      // 导出语法1
      export default obj;
      //export default function ff() {};
      
      // 导出语法2
      export const msg = 'ok';
      export const code = 1;
      
      /* 
        相当于向外暴露了
        {
          default: {num,str}
          msg,
          code
        }
      */
      
  • 导入语法:

    • 在当前自己文件中,把某一些文件导入自己内容

    • 目的: 为了使用该文件中暴露的数据,执行该文件

    • 导入文件的时候,会执行该文件

      语法1:
      	import 变量名 from 文件名
      语法2:
      	import { } from 文件名
      语法3:
      	import 文件名
      #注意: 
      	# 导入语法1 只能导入 导出语法1 的内容
      	# 导入语法2 只能导入 导出语法2 的内容
      
      例:
      // 这是b.js模块,我要导入a.js文件
      
      // 对应的导入语法1
      // ModuleA 得到的是 a.js中导出的那个default
      import ModuleA from './a.js';
      
      // 导入语法2
      import {msg} from './a.js'
      
      // 同时使用导入语法1,导入语法2
      import ModuleA,{msg,code} from './a.js'
      
      console.log( ModuleA );
      // console.log( msg );
      // console.log( code );
      

ES6-模板字符串

把一块代码当做模板来使用
基本语法:``  反引号
(``)和("")的区别:
	1)普通的引号使用多字符串的时候需要多次拼接而且不能换行
	2)使用模板字符串,不用再次换行拼接,默认里面就支持内容
注意:模板字符串里面任何内容都能显示出来,如 空格,tab等等
模板字符串拼接内容:
	不打断拼接,使用${}的形式直接获取,直接放在模板字符串中即可,可直接访问变量的值
	例:	${name}
	3)可以调用函数,可以拆分参数
		例: fun`JS${num}你好${num2}世界`  <=>  fun([JS,你好,世界],num,num2)
			形参1:[JS,你好,世界]
			${}将以此传给其他形参

正则

作用: 经验字符串是否符合规则
返回是布尔值 true,false
正则的基本语法:
	把一些特殊符号放在两个斜杠符号中间,代表一个正则
	正则也是复杂数据类型
创建方式有两种:
	1)字面量直接定义:
		var reg1=/abcd/
	2)构造函数的定方法:
		var reg2=new RegExp('abcd')

两种创建正则的区别

  • 书别标识符的区别

    字面量: 直接书写在正则的后面
    	例:let r1 = /qwer/ig;
    内置构造函数: 以第二个参数的形式书写
    	例:let r2 = new RegExp('qwer','ig')
    
  • 拼接变量的能力

    字面量: 不能进行变量拼接
    	let reg = '/^'+str+'$/';
    	拼接后的reg是字符串,不是正则
    内置构造函数: 可以拼接变量
    	因为内置构造函数的第一个参数就是字符串类型
        例:let reg2 = new RegExp('^'+str+'$')
    
  • 书写基本元字符

    字面量: /\d\w/
    内置构造函数: new RegExp('\\s\\w\\d')
    	在字符串中 \ 具有转义含义
        `\\` 前一个 \ 是将后一个 \ 转为一个普通文本字符
    

正则的常用方法

  • test() 匹配

    基本语法:正则.test(字符串)
    如果满足正则规则,则返回true
    如果不满足正则规则,则返回false
    
  • exec() 捕获

    基本语法:正则.exec(字符串)
    作用:把字符串中符合规则的内容筛选出来
    返回:一个数组 或 null
    返回的:['你好', index: 0, input: '你好我叫乐乐,你好,helloworld', groups: undefined]
    		"你好"	捕获的内容
    		groups: undefined
    		index: 0	该查找内容在字符串中的下标
    		input: "..."	查找的是哪一个字符串
    		length: 1	查找到数组内容的长度
    
    返回值:
    	1. 原字符串中没有符合规则的字符片段
        	返回值:null
    	2. 原字符串中有符合规则的字符片段
        	返回值:一个数组,[0]的位置就是从原字符串中捕获到的内容
            a)正则中没有(),也没有全局标识g
    			返回值:只有[0] 捕获到的内容
                不管捕获多少次,正则都是从原字符串开始的位置进行检索捕获
    		b)正则中有全局标识g
            	返回值:数组,[0]依旧是正则捕获到的内容
                但是从第二次捕获开始,会从上一次捕获结束位置开始检索
                以此类推,直到找不到了为止,返回值null
                再下一次又从原字符串的开始位置进行检索
    		c)正则中有()
    			返回值:数组,为[0]依旧是捕获捕获的内容
                从[1]开始 依次是每一个小括号的单独捕获内容
    

基本元字符

正则中具有特殊意义的处理字符
a)	.     任意的一个非换行(换行:\n)字符都可以
b)	\     反斜杠:转义字符,将一些有意义的符号转换成没有意义的字符
				把你的没有意义的字符转换成有意义的符号
			\. 原因:.是匹配所有字符, \. 就代表的了一个点
c)	\s    作用:匹配的是空白字符(包括 空格(\n),回车,tab(\t)) 
d)	\S    作用:匹配的是非空白字符串
e)	\d    作用:匹配的是数字
f)	\D    作用:匹配的是非数字
g)	\w    作用:匹配的是字母数字下划线
h)	\W    作用:匹配的是非字母数字下划线
总结:小写的使用频率比较高

限定符--限定元字符

限定元字符:用来限定前一个符号连续出现的次数
a)	*		作用:至少匹配0次,0~正无穷次
b)	+		作用:至少匹配1次,1~正无穷次
c)	?		作用:匹配的是0次或者是1次,最少0次,最多就1次
d)	{n}		作用:限定为n次
e)	{n,}	作用:匹配的是至少n次,n~正无穷次
f)	{n,m}	作用:匹配的是至少n次,最多m次

边界符--边界元字符

限定字符串的开始,限定了字符串的结尾
限定开始 ^
限定结尾 $
注意:
	如果^和$一起添加,则限定了次数
	没有^和$ 叫做'包含'
	有^和$ 叫做'只能'

特殊元字符

任何的一个符号,字母,空格,数字等等都算作一个字符
a)	()	作用:限定一组元素,把一些东西放在一组里面,
			一般情况下需要配合|来使用
			表示一个整体
			单独捕获(捕获方法中) 
b)	|	作用:表示或者,几个里面选择一个,
			一般和 () 联用
			只有() ^ $ 能区分'或'的边界
			例如:123@qq.com  123@sina.com  567@163.com  999@yahoo.cn
				假如:前面就限定:3为数字
				/^\d{3}\@(qq|sina|163|yahoo)\.(com|cn)$/
c)	[]	作用:代表的是一个字符集;从中括号里选择一个
		注意: 一个[]只占一个位置
			[13579]从奇数里面拿一个
			\d等价于[0123456789]
d)	[^]	作用:代表的是一个字符集,排除掉中括号中的内容
		注意: 一个[^]只占一个位置
			\D等价于除了中括号里面数字的所有内容[^0123456789]
e)	-	作用:连续的意思,一个范围
			一般和[]联用
		注意: 匹配中文必须保证 Unicode 码是连续的
			表示0~9:		[0-9]
			表示小写字母:	[a-z]
			匹配大写字母:	[A-Z]
			匹配小写的a-z和大写的A-Z:	[a-zA-Z]
			匹配一位中文:[\u4e00-\u9fa5]

重复元字符

语法: \n   比如: \1 \2  \3 ....
重复出现
需要第n个小括号的内容一模一样的重复
#注意: 不是重复多少次,而是重复第n个小括号匹配的内容

如何区分正则表达式中第几个小括号:
	在正则内,按照'开始小括号''(' 开始括号
	')' 结束括号
例:
	(a(b(c)))(d)(e)
	\2:表示重复(b(c))的内容

断言符--断言元字符

断言(预查)
需要匹配前后跟特定模式的内容
分为`前瞻断言``后瞻断言`

前瞻断言
	1. 前瞻肯定断言
		语法: x(?=y)
		作用: 匹配x,且x后面必须跟着y
    2. 前瞻否定断言
		语法: x(?!y)
		作用: 匹配x,且x后面必须不跟着y
后瞻断言
	1. 后瞻肯定断言
    	语法: (?<=y)x
		作用: 匹配x,且x必须跟在y后面
    2. 后瞻否定断言
    	语法: (?<!y)x
		作用: 匹配x,且x必须不跟在y后面

标识符

书写在正则表达式后面
用来修饰整个正则表达式
匹配全局: g	(global单词的缩写)
忽略大小写: i  (ignore单词的缩写)
匹配全局:正则表达式后面加g
		/\d{2}/g
		查找字符串中有符合条件的内容
		和捕获方法一起使用才有效果
匹配忽略大小写:正则表达式后面加i
		/\d{2}/i
		无论输入大写还是小写都行

正则的两大特性

  • 懒惰性

    当你捕获内容的时候,每次默认从字符串的开始位置检索
    解决方案: 加一个全局标识g
    
  • 贪婪性

    贪婪匹配:
    	能拿'多少''多少',尽量可能多的捕获
    非贪婪匹配:
    	能拿多'少'拿多'少',尽量可能少的捕获
    
    贪婪限定符:	*  +  ?  {n,}  {n,m}
    非贪婪限定符:	*?  +?  ??  {n,}?  {n,m}?
    例:
    	let reg = /<p.*>/
    	let reg = /<p.*?>/
    

字符串方法

  • search()

    基本语法: 字符串.search(正则)
    返回值:
    	如果有符合的字符片段,则返回该字符片段的起始索引
    	没有查找到,则返回的是-1
    
  • match()

    基本语法:字符串.match(正则)
    返回一个数组
    g(匹配全局)查找字符串中所有符合条件的内容,否则只查找一个
    返回值:
    	如果传入的参数是字符片段,或者是没有全局标识g的正则,则返回值和正则的exec方法一模一样
    	如果传入的参数是正则且有全局标识g,则返回一个数组,数组内的数据都是捕获到的内容
    
  • replace(参数1,参数2)

    用法1:
        参数1:正则
        参数2:替换上的字符
        返回值:替换好的字符串
        当你传递的是正则表达式,且有全局标识g,则会全部替换
    用法2:
    	参数1:正则
    	参数2:回调函数(返回替换上的)
    		参数1:元字符串
    		参数2:匹配到字符串第一段
    		参数3:匹配到字符串第二段
    		参数4:匹配到字符串第三段
    

函数节流和函数防抖

函数节流:n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
	节流阀,开关
    在单位时间内只触发一次内容
	从开始的时候,就固定了结束的时候
函数防抖:n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
	在单位时间内只触发一次内容
	开始之后,当第二次开始的时候,重新计时

函数传参时的默认值

使用逻辑或||的短路逻辑,如果||前面为真则取前面的值,前面值为假则取后面的值
如果不传递实参则使用默认值
例:
	function box1(){
		x=x||20
		console.log(x)
	}
	box1(30)
ES6中和箭头函数中可以直接在()中写默认值:
	var fun1=(a=10)=>console.log(a)
	fun1(30)

检查数据类型

  • typeof(变量)方法:

    typeof主要应用在检查基本数据类型中
    如果检查复杂数据类型时:
    	检查函数则返回function
    	检查其他复杂数据类型则返回object
    
  • 精准检测

    Object.prototype.toString.call(内容)

    返回值:       
    	[object Number]
    	[object String]
    	[object Boolean]
    	[object null]
    	[object undefined]
    	[object Function]
    	[object Array]
    	[object Objest]
    	[object RegExp]
    	[object Date]
    
    扩展:
    	打印分组开始:console.group()
    	打印分组结束:console.groupEnd()
    

运动函数

实现运动函数的必要参数:
	1)运动属性:top、left
	2)判断条件的目标值:运动到什么位置
	3)运动元素
  • 简单运动函数

    例:
    /**
     * @description: 简单的运动函数
     * @param {Object} ele 运动的元素
     * @param {String} type  运动的样式
     * @param {Number} target 运动的目标样式值
    */
    function move(ele, type, target) {
        // 获取到元素的当前left样式值(获取非行内样式是带单位的字符串)
        let current = parseInt(window.getComputedStyle(ele)[type]);
        let timer = setInterval(() => {
            current += 5; // 每过一段时间,将current累加5的距离,然后显示在div上      
            // 判断是否到达目标位置 type: target
            if (current >= target) { // 到达目标位置
                // 关闭定时器
                clearInterval(timer);
                ele.style[type] = target + 'px' // 重新将目标位置的值赋值
            } else {
                // 每过一段事件运动后显示的效果
                ele.style[type] = current + 'px'
            }
        }, 20)
    }
    
  • 多元素运动函数(直线运动)

    例:
    document.querySelector('div').onclick = function () {
        move(this, { left: 400, top: 200 })
    }
    /**
     * @description: 简单的运动函数
     * @param {Object} ele 运动的元素   
     * @param {Object} options 多个运动样式和目标值组成的对象
     */
    function move(ele, options) {
        // 因为是多样式的运动, 遍历options对象--for-in
        for (const type in options) {
            // type 就是元素运动的样式名
            // options[type] 运动样式对应的目标值
    
            // 让元素运动到目标位置的代码  
            // 获取到元素的当前运动样式的 样式值(获取非行内样式是带单位的字符串)
            let current = parseInt(window.getComputedStyle(ele)[type]);
            let timer = setInterval(() => {
                // 获取目标值和当前样式值的差,然后获取百分之10
                let goLength = (options[type] - current) / 10
                // goLength 就是本次定时器,需要移动的距离,应该是一个整数
                goLength = goLength > 0 ? Math.ceil(goLength) : Math.floor(goLength);
                current += goLength; // 每过一段时间,将current累加goLength的距离,然后显示在元素上
                // 判断是否到达目标位置 type: options[type]
                if (current === options[type]) { // 因为每次运动剩下的百分之10,并取整,这样就保证了一定会到达目标位置
                    // 关闭定时器
                    clearInterval(timer);
                    ele.style[type] = options[type] + 'px' // 重新将目标位置的值赋值
                } else {
                    // 每过一段事件运动后显示的效果
                    ele.style[type] = current + 'px'
                }
            }, 20)
        }
    }
    
  • 透明度运动函数

    例:
    document.querySelector('div').onclick = function () {
        move(this, { left: 500, top: 400, opacity: .1 })
    }
    
    /**
     * @description: 简单的运动函数
     * @param {Object} ele 运动的元素   
     * @param {Object} options 多个运动样式和目标值组成的对象
     */
    function move(ele, options) {
        // 因为是多样式的运动, 遍历options对象--for-in
        for (const type in options) {
            // type 就是元素运动的样式名
            // options[type] 运动样式对应的目标值
    
            // 判断是否是透明度运动样式
            let current;
            if (type === 'opacity') { // 放大一百倍
                current = parseInt(window.getComputedStyle(ele)[type] * 100);
                options[type] *= 100;
            } else { // 不是透明度
                current = parseInt(window.getComputedStyle(ele)[type]);
            }
            let timer = setInterval(() => {
                // 获取目标值和当前样式值的差,然后获取百分之10
                let goLength = (options[type] - current) / 10
                // goLength 就是本次定时器,需要移动的距离,应该是一个整数
                goLength = goLength > 0 ? Math.ceil(goLength) : Math.floor(goLength);
                current += goLength; // 每过一段时间,将current累加goLength的距离,然后显示在元素上
                // 判断是否到达目标位置 type: options[type]
                if (current === options[type]) { // 因为每次运动剩下的百分之10,并取整,这样就保证了一定会到达目标位置
                    // 关闭定时器
                    clearInterval(timer);
                } else {
                    // 每过一段事件运动后显示的效果
                    if (type === 'opacity') { // 如果是透明度运动,则缩小100倍赋值
                        ele.style[type] = current / 100;
                    } else {
                        ele.style[type] = current + 'px';
                    }
    
                }
            }, 20)
        }
    }
    
  • 运动后回调

    例:
    document.querySelector('div').onclick = function () {
        // left = 400 top = 200  opacity .3
        // 运动结束后,需要在div中添加 一段文字 作为内容
        // 调用封装的move函数实现 运效果
        move(this, { left: 500, top: 400, opacity: 1 }, () => {
            this.innerText = '666';
            this.style.backgroundColor = 'red';
        })
    }
    
    /**
     * @description: 简单的运动函数
     * @param {Object} ele 运动的元素   
     * @param {Object} options 多个运动样式和目标值组成的对象
     * @param {Function} cb 运动结束后执行的回调函数
     */
    function move(ele, options, cb = () => { }) {
        let count = 0;// 定义一个计数器 为0
    
        // 因为是多样式的运动, 遍历options对象--for-in
        for (const type in options) {
            // type 就是元素运动的样式名
            // options[type] 运动样式对应的目标值
    
            // 判断是否是透明度运动样式
            let current;
            if (type === 'opacity') { // 放大一百倍
                current = parseInt(window.getComputedStyle(ele)[type] * 100);
                options[type] *= 100;
            } else { // 不是透明度
                current = parseInt(window.getComputedStyle(ele)[type]);
            }
            // 开启一个定时器 计数器++
            count++;
            let timer = setInterval(() => {
                // 获取目标值和当前样式值的差,然后获取百分之10
                let goLength = (options[type] - current) / 10
                // goLength 就是本次定时器,需要移动的距离,应该是一个整数
                goLength = goLength > 0 ? Math.ceil(goLength) : Math.floor(goLength);
                current += goLength; // 每过一段时间,将current累加goLength的距离,然后显示在元素上
                // 判断是否到达目标位置 type: options[type]
                if (current === options[type]) { // 因为每次运动剩下的百分之10,并取整,这样就保证了一定会到达目标位置
                    // 关闭定时器
                    clearInterval(timer);
                    // 关闭定时器 计数器--
                    count--
                    // 判断计数器是否回0
                    if (count === 0) { // 所有定时器都关闭了,则运动完全结束
                        if (type === 'opacity') { // 
                            ele.style[type] = current / 100;
                        } else {
                            ele.style[type] = current + 'px';
                        }
                        cb(); // 执行传入的回调函数
                        return;//
                    }
                }// else {
                // 每过一段事件运动后显示的效果
                if (type === 'opacity') { // 如果是透明度运动,则缩小100倍赋值
                    ele.style[type] = current / 100;
                } else {
                    ele.style[type] = current + 'px';
                }
    
                // }
            }, 20)
        }
    }
    

面向对象

OOP面向对象不是语法,是一个思想,是一种编程思想
核心:高内聚低耦合(性能)、抽象(类)
特性:封装、多态、继承

创建对象的方式

  • 系统内置的构造函数创建对象:

    js内置了一个Object构造函数,用来创造对象
    当构造函数与new关键字连用时,就可以创造一个对象
    例:
    	var aa = new Object() //空对象
    	aa.name = 'Jack'	//正常操作对象
    
  • 字面量创建对象:

    字面量形式创建,也就是直接写{}
    直接添加成员,也可以动态添加
    var aa={ name = 'Jack'}
    
  • 工厂函数创建对象:

    工厂函数里可以创造一个对象,并且给对象添加属性,还能把对象返回
    	手动创建对象
    	手动添加成员
    	手动返回对象
    例:
    	function createObj() {	//创建工厂函数
    		var obj = new Object()  //手动创建对象
    		obj.name = 'Jack'  //手动向对象添加成员
    		return obj  //手动返回对象
    	}
    	//使用这个工厂函数创建对象
    	var a1 = createObj()
    	var a2 = createObj()
    
  • 自定义构造函数创建对象:

    自动创建对象
    自动添加成员
    自动返回对象
    先写一个构造函数
    构造函数内向对象添加成员
    使用构造函数创造对象(和new连用)
    构造函数可以创建对象,并且创建一个带有属性和方法的对象
    面向对象就是想办法找到一个有属性和方法的对象
    面向对象就是自己制造构造函数的过程
    
    例:
    	function Person(name, gender) {	//先创造一个构造函数
    		this.name = name
    		this.gender = gender
    	}
    	//使用构造函数创建对象
    	var p1 = new Person('Jack', 'man')
    	var p2 = new Person('Rose', 'woman')
    

构造函数的基本使用

1)和普通函数一样,但是调用的时候要和new连用,不写new就是普通函数调用
	function Person() {}
	var obj1 = new Person()  // 空对象
	var obj2 = Person()      // undefined,普通函数调用
2)首字母大小(潜规则)
3)调用时如果不传参可以不写(),建议写上,如果需要传参就必须写上
4)构造函数内部的this,由于和new连用的关系,指向当前实例对象
	function Person() { console.log(this) }
	var obj1 = new Person()  // this => obj1
	var obj2 = new Person()  // this => obj2
5)因为构造函数会自动返回一个对象,所以构造函数内部不要写return
	return基本数据类型	return无意义
	return复杂数据类型	构造器无意义

原型 prototype

原型是为了解决构造函数的缺点
属性放到函数内,方法放到prototype里
prototype是每个函数天生自带的成员,是一个对象空间
这个prototype可以由函数名来访问
例:
function Person() {}
Person.prototype.name = 'prototype'
Person.prototype.sayHi = function () {}

ES6 class声明类

为了避免:
	1、自定义构造函数毕竟还是函数,可能会 Person() 调用
	2、自定义构造器函数需要和 new 配合调用
ES6通过class来避免这个问题:
	例:
		class  类名{
			/* 类的构造器  */
			constructor(){
				this.属性名=值,
				...
			}
			方法名(){
			}
		}
class 语法:
	类和构造函数的作用是一样的(ES6中的类就是ES5中构造函数的语法糖)
	作用:创建对象
    语法:new 类名()
	'类'只能用于创建对象(只能通过new语法创建对象),不能像构造函数一样,当做函数调用
    类的原型链和构造函数一样
类语法:
	class 类名{
        constructor(){
            
        }
    }
注意:
	1. 在类的大括号中书写方法,不能写function,而且写的方法是添加在原型中
    2. '类'默认有一个constructor方法--构造器方法
    	类在new 实例化对象的时候,默认执行构造器方法
        构造器方法中的关键字this指向'实例对象'
		在实例化对象的时候,需要给实例对象添加属性方法,则在构造器方法中通过this添加
    3. 类中的字段,就是相当于给实例对象添加的属性
    	字段名 = 值
		实例化对象的时候,不能修改值
    4. 静态属性和静态方法
    	static 字段 = 值
		static 字段 = 函数
		静态的属性和方法是 给类添加