JavaScript笔记总结

目录

Js的概念

js组成

变量

变量的命名规范

基本数据类型

输出方式(浏览器中的显示方式)

字符串类型

运算符

赋值运算符

算术运算

关系运算符

类型转换

转换为数字类型

四种方法的总结

 转换字符串

转换为布尔型

隐式转换

自增++自减--运算(一元运算符)

对象

对象数据类型基本使用

数组

 数组的长度和索引

数据类型之间存储的区别(重点)

数据类型之间的比较

不同数据类型变量的赋值区别(函数参数传递基本数据类型和复杂数据类型的区别)

 数组常用方法

严格模式(了解)

ES5中新增地数组方法

字符串特性

字符串长度特性

 比较运算符

字符串常用方法

数学方法 (Math)

Date日期对象

进制转换

BOM

浏览器事件

 获取浏览器的可视窗口尺寸 (包含滚动条)

获取浏览器的信息,都是通过window中的navigator对象

1.浏览器的综合信息(了解)

2.获取浏览的名称

3. 获取浏览器版本

4. 获取平台信息

浏览器弹窗

浏览器的地址信息

浏览器的历史记录

浏览器滚动的距离

 获取浏览器的滚动距离

定时器

倒计时定时器

间隔定时器

关闭定时器

定时器的异步执行

DOM

获取页面元素

操作属性

 3. value   操作表单标签的内容

 元素的属性操作

  三个元素的样式操作

操作元素类名

获取节点

 将伪数组转为真数组

节点属性:

 创建节点

 插入节点

节点克隆

删除节点

节点替换(修改)

获取元素尺寸

 获取元素偏移量

获取浏览器可视窗口尺寸

事件

事件类型

1. 鼠标事件

键盘事件

表单事件

触摸事件

其他事件

事件绑定有两种方式  

事件解绑定

事件对象

鼠标事件的按键信息

 鼠标事件的坐标信息

键盘事件信息

事件目标

事件传播

 阻止事件传播

事件委托

阻止默认行为

创建文档碎片

ES5&ES6

this 关键字

call 和 apply 和 bind

万能检测数据类型

JSON 方法

let 和 const 关键字

箭头函数

模版字符串

展开运算符

解构赋值

对象简写

正则

创建一个正则表达式

 正则表达式方法

1. test()   检测方法

2. exec()  捕获方法

正则表达式的组成

基本元字符

元字符--边界符

元字符-限定符

元字符---特殊字符

标识符

 字符串方法配合正则使用的

面向对象 

介绍面向对象

创建对象的方式

使用工厂函数的方式创建对象

工厂函数创建对象的问题

使用自定义构造函数创建对象

自定义构造函数的缺陷

自定义构造函数缺陷解决方案

原型---原型对象

prototype

__proto__

原型链

一个对象所属的构造函数

constructor

链状结构

ES6中创建对象新增语法class语法

ES6模块化语法

在使用模块化语法的时候(前提)

使用模块化语法

浏览器本地存储---------storage

localStorage的操作API

2. 获取方法

sessionStorage的操作API


Js的概念

概念:支持面向对象的跨平台脚本语言(弱类型语言)

理解:

  • 脚本语言:依赖别的语言才能运行
  • 跨平台:windows、linux、安卓、ios
  • 支持面向对象:使用面向对象的思想

历史

发明者:布兰登·艾奇

js组成

  • ECMAScript :基础语法(规范)
  • BOM:提供了操作浏览器对象的一套方法 (浏览器对象)
  • DOM:文档对象

变量

变量是内存中的一个空间,用来存放一些结果。

变量的命名规范

  • 变量区分大小写:小写a与大写A为两个不同变量。
  • 可以声明多个变量:用一个var,变量名用逗号隔开。
  • 变量名也可以省略(隐式声明)。
  • 命名变量:以字母、下划线开头,后面跟数字、字母、下划线。

基本数据类型

  • bumber :数字类型
  • string:字符串型
  • boolean:布尔型
  • undefined:未定义(未赋值)
  • object:对象 (数组、对象、null、日期对象、函数)

输出方式(浏览器中的显示方式)

  • alert():浏览器下面的系统弹窗 window.alert()
  • document.write():页面中显示,还可以解析标签
  • console.log():浏览器控制台打印显示(浏览器日志)
  • confirm():提示消息
  • prompt():交互方式,用户手动的设置内容,可选参数
  • dir():查看当前输出的对象详细信息
  • 数值.toFixed(3):保留3位小数

字符串类型

  • \n————换行
  • \t————制表符
  • \b————空格
  • \————斜杠
  • '————单引号
  • "————双引号

注意:引号可以嵌套,但是不能嵌套自己,需要交叉嵌套(单引号嵌套双引号或者双引号嵌套单引号)

运算符

赋值运算符

在编程中=不叫‘等于号’,叫‘赋值符’

算术运算

+ ——————加

- ——————减

* ——————乘

/ ——————除法

% ——————求余数

+可以作为字符串的拼接

关系运算符

>—————— 大于

>=—————— 小于

<———————小于

<=——————小于等于

==——————等于

===——————全等于(先判断两边类型是否相等后判断值)

!=———————不相等

!==——————不全等于

类型转换

转换为数字类型

1.Number(转换的数据) 强制转换

2.parseInt(转换的数据)转换为整数类型

3.parseFloat(转换的数据)转换为浮点数型/保留小数

4.Math.round() 转换为数字类型并且四舍五入,小数点后一位影响

四种方法的总结

parse/parseFloat 可以‘转换数字类型

了解:字符串有非数字的字符也可以正常转换

Number/Math.round 方法转换为字符串的时候字符串不能有非数字字符否则转换为NaN

扩展

1.将布尔类型转换为数字类型

Namber/Math.round 转换的时候   true为1  false为0

2.将undefined转换为数字类型:结果为NaN

3.null转为数字

Number/Math.round 结果为0

parseInt/parseFloat 结果为NaN

 转换字符串

1.string(转换的数据)

2.转换的数据.to string()

扩展

1.将undefined 转换为字符串

        string 可以转换

        to string 会报错

2.null 转换为字符串

        string 可以转换

        to string 会报错

转换为布尔型

语法:
    Boolean(arg)

1.非0数字转换为布尔型为true,0转换为布尔型为false

2.非空字符串转换为布尔型为true,空字符串转换为布尔型为false

3.undefined转换为布尔型false

4.null转换为布尔型为false

隐式转换

一、字符串之间的隐式转换

在加号的一侧只要有字符串默认就会进行字符串的拼接

二、数学运算

1. “+”拼接

2.除了加号以外的符号:转换为数字类型

三、比较运算

1.字符串和数字:默认会把字符串的值转换为数字型

2.字符串和字符串:如果字符串的值都是数字的情况,默认转换为数字类型进行比较

四、NaN a number 属于数字类型

自增++自减--运算(一元运算符)

++放前面或者后面意思一样

当递增运算碰到赋值或者输出的时候就有区别

放后面:先输出后自增

放前面:先自增后输出

--自减与自增同理

注意:递增递减需要使用变量,不能使用数字

对象

对象数据类型基本使用

对象是一个无序的数据集合

对象是复杂数据类型

对象数据存储: 键值对存储,多个键值对逗号分隔

注意: 键名不能重复,键名只能为字符串,键值可以是任意数据类型

对象的创建

 ! 注意1: 对象中的键名只能是字符串(或Symbol)数据类型

 ! 注意2: 对象中的键值可以是任意数据类型

 ! 注意3: 对象中的键名不能重复

 ! 注意4: 对象的书写 {} 就是对象数据,在{}中的键值对就是对象的数据,多个键值对通过逗号分隔

字面量

var obj = {}

内置构造函数

var obj = new Object()

对象的成员操作语法

点语法

数组关联法

获取

对象.键名

 对象['键名']

添加修改

对象.键名 = 值

对象['键名'] = 值

删除

delete 对象.键名

delete 对象['键名']

对象的遍历for-in

遍历: 通过循环的方式获取数据内容

语法: for(var 变量 in 对象){ // 变量就是对象的每一个键名   }

对象成员有多少个,则循环执行多少次

数组

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

- 数组中数据的存储方式: 数据直接存放在 [] 中,多个数据使用逗号分隔

- 有序指的是: 数组中的数据都是按顺序排列的(索引下标排序)

- 数组中的数据,可以是任意数据类型的数据

数组的创建

1. 字面量的方式创建

// 创建一个空数组
var arr1 = []

// 创建一个有内容的数组
var arr2 = [1, 2, 3]

2. 系统内置构造函数创建数组

// 创建一个空数组
var arr1 = new Array()

// 创建一个长度为 10 的数组
var arr2 = new Array(10)

// 创建一个有内容的数组
var arr3 = new Array(1, 2, 3)

 数组的长度和索引

数组的长度特性

数组的长度就是数组中成员的个数

可以通过数组的length属性获取

        - 语法: 数组.length

        - 返回值: 数组的长度的数值

! 注意:数组长度减1就是  数组的索引最大值

! 注意:数组长度是可变的,就是可以操作的

数组的索引特性

  • 索引,也叫做下标,是指一个数据在数组里面排在第几个的位置

  • 注意: 在所有的语言里面,索引都是从 0 开始的

  • 在 js 里面也一样,数组的索引从 0 开始

  • 数组可以通过索引操作数组对应的成员

            - 语法: 数组[索引]

var arr = ['hello', 'world']

console.log(arr[0]) // hello
console.log(arr[1]) // world

数组的遍历 

for循环遍历,循环变量就是数组索引,条件变量小于数组长度

也可以使用for-in来遍历数组

! 一般不会使用for-in语法来遍历数组,for-in语法设计之处就是用来遍历对象的

二维数组

数组中的数据成员也是数组

 遍历二维数组,使用双层循环 

数据类型之间存储的区别(重点)

  • 既然我们区分了基本数据类型和复杂数据类型

  • 那么他们之间就一定会存在一些区别

  • 他们最大的区别就是在存储上的区别

  • 我们的存储空间分成两种

  • 栈: 主要存储基本数据类型的内容

  • 堆: 主要存储复杂数据类型的内容

不同数据类型在内存中存储的位置不一样

1. 基本数据类型是 直接将数据存储在栈内存中

基本数据类型在内存中的存储情况

var num = 100,在内存中的存储情况

 直接在 栈空间 内有存储一个数据

2. 复杂数据类型,将数据存储在堆内存空间中,存储空间的地址存储在对应的栈内存空间中

复杂数据类型在内存中的存储情况

var obj = {
  name: 'Jack',
  age: 18,
  gender: '男'
}

复杂数据类型的存储

  1. 在堆里面开辟一个存储空间

  2. 把数据存储到存储空间内

  3. 把存储空间的地址赋值给栈里面的变量

数据类型之间的比较

基本数据类型是 之间的比较

var num = 1
var str = '1'

console.log(num == str) // true

 复杂数据类型是 地址 之间的比较

var obj = { name: 'Jack' }
var obj2 = { name: 'Jack' }

console.log(obj == obj2) // false
  • 因为我们创建了两个对象,那么就会在 堆空间 里面开辟两个存储空间存储数据(两个地址)

  • 虽然存储的内容是一样的,那么也是两个存储空间,两个地址

  • 复杂数据类型之间就是地址的比较,所以 objobj2 两个变量的地址不一样

  • 所以我们得到的就是 false

不同数据类型变量的赋值区别(函数参数传递基本数据类型和复杂数据类型的区别)

      1. 基本数据类型的变量之间 赋值 是值的赋值,赋值后两个变量互不影响

      2. 复杂数据类型的变量之间 赋值 是地址的赋值,赋值后两个变量操作的是同一个存储空间

      ! 注意 函数调用时的实参给形参赋值也是变量赋值的一种

 数组常用方法

1. push()

push 是用来在数组的末尾追加一个元素

var arr = [1, 2, 3]

// 使用 push 方法追加一个元素在末尾
arr.push(4)

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

 2. unshift()

unshift 是在数组的最前面添加一个元素

var arr = [1, 2, 3]

// 使用 unshift 方法向数组的最前面添加一个元素
arr.unshift(4)

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

 3. pop()

pop 是用来删除数组末尾的一个元素

var arr = [1, 2, 3]

// 使用 pop 方法删除末尾的一个元素
arr.pop()

console.log(arr) // [1, 2]

4. shift() 

shift 是删除数组最前面的一个元素

var arr = [1, 2, 3]

// 使用 shift 方法删除数组最前面的一个元素
arr.shift()

console.log(arr) // [2, 3

 5. splice()

splice 是截取数组中的某些内容,按照数组的索引来截取

语法: splice(从哪一个索引位置开始,截取多少个,替换的新元素) (第三个参数可以不写)

var arr = [1, 2, 3, 4, 5]

// 使用 splice 方法截取数组
arr.splice(1, 2)

console.log(arr) // [1, 4, 5]
  • arr.splice(1, 2) 表示从索引 1 开始截取 2 个内容

  • 第三个参数没有写,就是没有新内容替换掉截取位置

var arr = [1, 2, 3, 4, 5]

// 使用 splice 方法截取数组
arr.splice(1, 2, '我是新内容')

console.log(arr) // [1, '我是新内容', 4, 5]
  • arr.splice(1, 2, '我是新内容') 表示从索引 1 开始截取 2 个内容

  • 然后用第三个参数把截取完空出来的位置填充

6. sort()  

sort 是用来给数组排序的

var arr = [2, 3, 1]

// 使用 sort 方法给数组排序
arr.sort()

console.log(arr) // [1, 2, 3]

语法2: 数组.sort(参数) 

参数必须是一个函数,函数必须要有两个形参, 并且函数要return这连个形参的差值

作用: 给数组排序

返回值: 排序后的数组

数组.sort(function(a,b){
        // return a-b;  // 升序排序
        return b-a;     // 降序排序
      })

7. reverse() 

reverse 是用来反转数组使用的

var arr = [1, 2, 3]

// 使用 reverse 方法来反转数组
arr.reverse()

console.log(arr) // [3, 2, 1]

!注意 :上面的几个数组方法会改变原数组

8. concat() 

concat 是把多个数组进行拼接

和之前的方法有一些不一样的地方,就是 concat 不会改变原始数组,而是返回一个新的数组

var arr = [1, 2, 3]

// 使用 concat 方法拼接数组
var newArr = arr.concat([4, 5, 6])

console.log(arr) // [1, 2, 3]
console.log(newArr) // [1, 2, 3, 4, 5, 6]

 9. join()

  • join 是把数组里面的每一项内容链接起来,变成一个字符串

  • 可以自己定义每一项之间链接的内容 join(要以什么内容链接)

  • 不会改变原始数组,而是把链接好的字符串返回

var arr = [1, 2, 3]

// 使用 join 链接数组
var str = arr.join('-')

console.log(arr) // [1, 2, 3]
console.log(str) // 1-2-3

严格模式(了解)

  • 我们都知道 js 是一个相对不很严谨的语言

  • 而且开发的时候,一些代码也不是很严格要求

  • 而严格模式就是对开发的时候写的一些内容做了要求

开启严格模式

想开启严格模式,直接在代码最开始的位置写上字符串 use strict

<script>
	'use strtic'
	// 下面代码书写就要按照严格模式来书写
</script>

严格模式的规则

  1. 在严格模式下,声明变量必须要有关键字

2. 函数定义的时候,不能定义同名形参

3. 在函数中不能使用  arguments.callee

4. 在严格模式下,普通调用函数的方式,函数中的this不在是window

5. 在严格模式下,不能使用0开头表示八进制

ES5中新增地数组方法

1. indexOf(参数)

  • indexOf 用来找到数组中某一项的索引

  • 语法: indexOf(你要找的数组中的项)

var arr = [1, 2, 3, 4, 5]

// 使用 indexOf 超找数组中的某一项
var index = arr.indexOf(3)

console.log(index) // 2
  • 我们要找的是数组中值为 3 的那一项

  • 返回的就是值为 3 的那一项在该数组中的索引

var arr = [1, 2, 3, 4, 5]

// 使用 indexOf 超找数组中的某一项
var index = arr.indexOf(10)

console.log(index) // -1
  •  你要找的值在数组中不存在,那么就会返回 -1

2. forEach(参数)

  • 和 for 循环一个作用,就是用来遍历数组的

  • 语法:arr.forEach(function (item, index, arr) {})

var arr = [1, 2, 3]

// 使用 forEach 遍历数组
arr.forEach(function (item, index, arr) {
  // item 就是数组中的每一项
  // index 就是数组的索引
  // arr 就是原始数组
  console.log('数组的第 ' + index + ' 项的值是 ' + item + ',原始数组是', arr)
})
  • forEach() 的时候传递的那个函数,会根据数组的长度执行

  • 数组的长度是多少,这个函数就会执行多少回

3. map(参数)

和 forEach 类似,只不过可以对数组中的每一项进行操作,返回一个新的数组

var arr = [1, 2, 3]

// 使用 map 遍历数组
var newArr = arr.map(function (item, index, arr) {
  // item 就是数组中的每一项
  // index 就是数组的索引
  // arr 就是原始数组
  return item + 10
})

console.log(newArr) // [11, 12, 13]

 4. filter()

  • 和 map 的使用方式类似,按照我们的条件来筛选数组

  • 把原始数组中满足条件的筛选出来,组成一个新的数组返回.

var arr = [1, 2, 3]

// 使用 filter 过滤数组
var newArr = arr.filter(function (item, index, arr) {
  // item 就是数组中的每一项
  // index 就是数组的索引
  // arr 就是原始数组
  return item > 1
})

console.log(newArr) // [2, 3]

 5. some()

语法: 数组.some(参数)

作用: 数组判断方法

执行: 数组中只要有一个元素满足条件,则最终的返回值为true

返回值: 布尔值

数组.some(function(item,index,arr){
        // item 表示数组中的元素
        // index 表示元素对应的索引
        // arr 表示的是调用some方法的数组
        // some方法有返回值,但是必须在此函数中return
        // 此函数如果return true的时候,则遍历结束,而且some方法的返回值也为true
        // 如果遍历结束,此函数返回的全都是false,则some方法的返回值为false
      })

6. every() 

语法: 数组.every(参数)

参数必须是一个函数,函数有三个形参

作用: 数组判断方法

执行: 数组中每一个都元素满足条件,则最终的返回值为true,否则返回false

返回值: 布尔值

数组.every(function(item,index,arr){
        // item 表示数组中的元素
        // index 表示元素对应的索引
        // arr 表示的是调用every方法的数组
        // every方法有返回值,但是必须在此函数中return
        // 此函数如果return false的时候,则遍历结束,而且every方法的返回值也为false
        // 如果遍历结束,此函数返回的全都是true,则every方法的返回值为true
      })

 7. reduce()

语法1: 数组.reduce(函数)

参数必须是一个函数,函数有四个形参

作用: 数组累计

执行: 数组有多少元素,函数就执行多少次,而且函数最后一次执行的返回值就是此方法返回值

返回值: 取决于传入函数最后一次执行的结果

数组.reduce(function(prev,item,index,arr){
        // 数组元素有多少个,则此函数执行少一次
        // prev 第一次执行的时候,表示的是数组的第一个元素,后续函数执行的时候,prev就是上一次函数执行的返回值
        // item 表示数组中第二个元素开始的每一个元素
        // index 表示元素对应的索引
        // arr 表示的是调用reduce方法的数组
        // reduce方法有返回值,但是必须在此函数中return
        // 此函数执行return的结果是给下一次执行此函数的prev形参
        // 此函数最后一次执行return的结果是reduce方法的最终结果
      })

语法2: 数组.reduce(函数,初始值) 

参数必须是一个函数,函数有四个形参

作用: 数组累计

执行: 数组有多少元素,函数就执行多少次,而且函数最后一次执行的返回值就是此方法返回值

返回值: 取决于传入函数最后一次执行的结果

数组.reduce(function(prev,item,index,arr){
        // 数组元素有多少个,则此函数执行多少次
        // prev 第一次执行的时候,表示的是init的值,后续函数执行的时候,prev就是上一次函数执行的返回值
        // item 表示数组中的每一个元素
        // index 表示元素对应的索引
        // arr 表示的是调用reduce方法的数组
        // reduce方法有返回值,但是必须在此函数中return
        // 此函数执行return的结果是给下一次执行此函数的prev形参
        // 此函数最后一次执行return的结果是reduce方法的最终结果
      },init)  

字符串特性

1.普通字符串

2.数字字符串

3.html字符串

4.查询字符串(key=value&key2=value)

字符串、数值、布尔值类型地数据是包装数据类型

包装数据类型:当数据调用某一个方法或属性的时候,或莫将数据临时的包装为对应的对象的形式,来使用方法和属性,当使用完毕,则默认转为基本数据类型。

字符串长度特性

字符串的长度特性---可以通过length属性获取

字符串还有索引---索引是字符串中字符对应的下标

可以通过字符串的索引访问对应的字符---使用数组关联法

注意:字符串的中的字符内容是只读,不可修改的,字符串的length属性也是只读属性

 比较运算符

      如果两边都是数值,则直接比较

      如果有一个边是数值,则会将另一边的值转为数值(隐式转换),然后比较

      如果两边都是数字字符串,则比较的时候是按位比较(逐位比较大小)

      如果两边都是字符串,则会转为ascii码然后比较大小  

字符串常用方法

1.charAt()

语法:字符串.charAt(索引)

作用:查找传入的索引在字符串中的字符,如果不存在则返回空字符

返回值:对应的字符。或空字符。

var str = 'Jack'

// 使用 charAt 找到字符串中的某一个内容
var index = str.charAt(2)

console.log(index) // c

// 因为字符串也是按照索引进行排列的,也是同样从 0 开始
// 所以索引 2 的位置就是 c
var str = 'Jack'

// 使用 charAt 找到字符串中的某一个内容
var index = str.charAt(10)

console.log(index) // ''

// 这个字符串根本没有索引 10 的位置
// 所以就会返回一个空字符串 `''`

2.charCodeAt()

语法:字符串.charCodeAt(索引)

作用:查找传入的索引在字符中字符的ASCll码,如果不存在则返回NaN

返回值:对应的ASCll码,或者NaN.

var str = 'Jack'

// 使用 charAt 找到字符串中的某一个内容
var index = str.charCodeAt(0)

console.log(index) // 74
//因为 `J` 在 unicode 对照表里面存储的是 74,所以就会返回 74

3. substring()

  语法: 字符串.substring(起始索引,结束索引)

  作用: 从起始索引开始,截取字符串中字符片段(注意: 不包含结束索引)

var str = 'hello'
//         01234

// 使用 substring 截取字符串
var newStr = str.substring(1, 3)

console.log(newStr) // el

// 从索引 1 开始,到索引 3 截止,包含前面的索引不包含后面的索引
// 所以返回的是 el

 4. substr()

  语法: 字符串.substr(起始索引,截取的个数)

  作用: 从起始索引开始,截取字符串中字符片段

  返回值: 截取的字符片段

var str = 'hello'
//         01234

// 使用 substr 截取字符串
var newStr = str.substr(1, 3)

console.log(newStr) // ell

// 这个方法和 `substring` 不一样的是,第二个参数是截取多少个
// 从索引 1 开始,截取 3 个,所以得到的是 `ell`

 5. slice()

  语法: 字符串.slice(起始索引,结束索引)

  作用: 从起始索引开始,截取字符串中字符片段(注意: 不包含结束索引)

  注意: 结束索引可以是负数,-1表示最后一个字符,-2表示倒数第二个字符串.....

  返回值: 截取的字符片段

6.split()

语法:字符串.split(参数)

作用:按照传入的参数将字符串分隔为多个字符,然后组成数组返回

如果没有参数,则将整个字符串当做数组返回

如果传入空字符串,则将字符串的每个字符当做数组元素返回

返回值:数组

7.indexOf()

语法1:字符串.indexOf(参数)

作用:检索参数在字符串中的索引位置(从左往右检索,找到则返回索引)找不到则返回-1。

语法2:字符串.indexOf(参数,起始索引)

作用:从起始索引开始检索参数在字符串中索引位置(从左往右)找不到则返回-1。

8.slice()

语法: 数组.slice(起始索引,结束索引)    不包含结束索引

作用: 截取数组中一段数据,作为新数组的元素

 返回值: 新数组

 不会改变原数组

var str = 'Jack'

// 使用 indexOf 找到对应的索引
var index = str.indexOf('J')

console.log(index) // 0

// 因为字符 `J` 在字符串 `Jack` 中的索引位置是 0
//   所以会返回 0

8.lastindexOf()

语法:字符串.lastindexOf(参数)

作用:检索参数在字符中的索引位置(从右往左)找不打则返回-1

返回值:索引或者-1

9.toLowerCase()  和  toUpperCase()

语法:字符串.toLowerCase()  和 字符串.toUpperCase()

作用:将字符串中的所有字符转为小写 和 将字符串转为大写

10.replace()

语法:字符串.replace(要被替换的内容,要替换上的内容)

注意:只能替换从左往右‘匹配的第一个内容,后面的内容不会进行替换

作用:替换字符处不能中的内容

返回值:替换后的字符串

数学方法 (Math)

1.PI :获取圆周率

2.round(数值):四舍五入取整

3.floor(数值):向下取整

4.ceil(数值):向上取整

5.max(多个数值):获取多个值的最大值

6.min(多个数值):获取多个值的最小值

7.abs(数值):获取绝对值

8.sqrt(数值):获取阿胡子的平方根

9.pow(底数,指数) 求底数的次幂

10.random():获取0~1的随机数(可以取到0,但是没有1)

11. 数值变量.toFixed(数值) 数值转为字符串,并且小数点保留几位(默认舍弃内容四舍五入)

Date日期对象

// 获取当前的时间对象
  var time = new Date();

   //时间对象的方法有两套
  //分别是get一套 --- 获取时间信息
      //set一套 ---- 设置时间对象

   get一套时间对象的方法
   1. getFullYear()  获取时间对象的年份
   console.log( time.getFullYear() ) // 2022

   2. getMonth()  获取时间对象的月份 获取的数值+1才是真实的月份
   console.log( time.getMonth() ) // 5表示6月份

   3. getDate() 获取时间对象的日期
   console.log( time.getDate() )  // 15号

   4. getHours() 获取时间对象的小时
   console.log( time.getHours() ) // 16

  5. getMinutes() 获取时间对象的分钟
   console.log( time.getMinutes() ) // 30

  6. getSeconds() 获取时间对象的秒
   console.log( time.getSeconds() ) // 30

  var time = new Date('2022-6-12 00:00:00');
   7. getDay()  获取时间对象的星期几
  console.log( time.getDay() ) //  0 表示星期天  6表示星期六

进制转换

 1. 变量.toString(参数)    

  • 将变量转为字符串
  •   参数: 将变量中的值,转为多少进制的数字字符串
  •    如果不传参数,则默认转为10进制的数字字符串
  •   参数范围: 2~36
  •    返回值: 转换后的字符串
  console.log( num.toString() )  //'10'
   console.log( num.toString(2) )  //'1010'
   console.log( num.toString(8) )  //'12'
   console.log( num.toString(3) )  //'101'

 2. parseInt(变量,参数)    

  • 转为十进制的整数,或者NaN
  • 第二个参数是数值, 将变量中的值当做多少进制的数看待
  • 如果不传参数,则默认当做十进制数看待

  •  返回值: 十进制的整数,或者NaN

console.log( parseInt('10') ) // 10
console.log( parseInt('10',2) ) // 2
console.log( parseInt('abc',2) ) // NaN
console.log( parseInt('abc',16) ) // 2748
console.log( parseInt('1f',16) ) // 31

BOM

  • BOM(Browser Object Model): 浏览器对象模型

  • 其实就是操作浏览器的一些能力

  • 我们可以操作哪些内容

    • 获取一些浏览器的相关信息(窗口的大小)

    • 操作浏览器进行页面跳转

    • 获取当前浏览器地址栏的信息

    • 操作浏览器的滚动条

    • 浏览器的信息(浏览器的版本)

    • 让浏览器出现一个弹出框(alert/confirm/prompt)

  • BOM 的核心就是 window 对象

  • window 是浏览器内置的一个对象,里面包含着操作浏览器的方法

浏览器事件

1. onload事件  页面加载事件

只有当页面中的所有资源(页面结构,css,js,图片,音频...)

都加载完毕的时候,load事件才触发

 window.onload = function() {
            console.log(666)
            console.log(dv)
        }
        console.log(dv) // 报错 此时页面结构还没有加载

 2. onscroll事件

浏览器滚动条滚动事件,只要滚动就触发

3. onresize事件

 浏览器可视窗口尺寸变化触发的事件

window.onresize = function () {
           console.log( 666 )
         }

 获取浏览器的可视窗口尺寸 (包含滚动条)

 1. window.innerHeight    获取浏览器的可视窗口高度

  2. window.innerWidth     获取浏览器的可视窗口宽度

var windowHeight = window.innerHeight
console.log(windowHeight)

var windowWidth = window.innerWidth
console.log(windowWidth)

获取浏览器的信息,都是通过window中的navigator对象

console.log( window.navigator )
   console.log( navigator )

1.浏览器的综合信息(了解)

  • window 中有一个对象叫做 navigator

  • 是专门用来获取浏览器信息的

navigator.userAgent

  • navigator.userAgent 是获取的浏览器的整体信息

console.log(window.navigator.userAgent)
// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) 
//AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36

2.获取浏览的名称

console.log( navigator.appName ) // Netscape

3. 获取浏览器版本

console.log( navigator.appVersion );// 77.0.

4. 获取平台信息

console.log( navigator.platform ) // Win32

浏览器弹窗

      1. alert()  提示弹窗

        没有返回值

      2. confirm() 确认弹窗

        点击确定返回值true 点击取消返回值false

      3. prompt()  提问弹窗---输入框 确定 取消

        点击取消则返回 null

        点击确定则返回 输入的内容(数据类型为字符串)

浏览器的地址信息

  • 在 window 中有一个对象叫做 location

  • 就是专门用来存储浏览器的地址栏内的信息的

location.href

location.href 这个属性存储的是浏览器地址栏内 url 地址的信息

console.log(window.location.href)

会把中文编程 url 编码的格式

location.href 这个属性也可以给他赋值

window.location.href = './index.html'
// 这个就会跳转页面到后面你给的那个地址

location.reload

location.reload() 这个方法会重新加载一遍页面,就相当于刷新是一个道理

window.location.reload()

注意: 不要写在全局,不然浏览器就会一直处在刷新状态

浏览器的历史记录

  • window 中有一个对象叫做 history

  • 是专门用来存储历史记录信息的

1. history.forward()

 作用: 让页面前进到浏览器历史记录的下一个页面(前提是要有历史记录)

window.history.forward()

2.history.back

作用: 让页面后退到浏览器历史记录的上一个页面(前提是要有历史记录)

window.history.back()

3. history.go()

作用:可以传递数值,如果是正数,则前进到历史记录的后第几个页面

如果是负数,则后退到历史记录的前第几个页面

如果不传或传递0,则刷新页面

浏览器滚动的距离

  • 浏览器内的内容即然可以滚动,那么我们就可以获取到浏览器滚动的距离

  • 思考一个问题?

    • 浏览器真的滚动了吗?

    • 其实我们的浏览器是没有滚动的,是一直在那里

    • 滚动的是什么?是我们的页面

    • 所以说,其实浏览器没有动,只不过是页面向上走了

  • 所以,这个已经不能单纯的算是浏览器的内容了,而是我们页面的内容

  • 所以不是在用 window 对象了,而是使用 document 对象

 获取浏览器的滚动距离

1. 页面中没有DOCTYPE声明的时候

document.body.scrollTop 获取垂直滚动条滚动的距离

 document.body.scrollleft 获取水平滚动条滚动的距离

 console.log( document.body.scrollTop )
  console.log( document.body.scrollLeft )

2.页面中有DOCTYPE声明的时候

document.docuemntElement.scrollTop 获取垂直滚动条滚动的距离

 document.docuemntElement.scrollleft 获取水平滚动条滚动的距离

 console.log(document.documentElement.scrollTop)
 console.log(document.documentElement.scrollLeft)

 可以使用 短路写法进行兼容获取

 var scrollTop = document.body.scrollTop||document.documentElement.scrollTop
  console.log( scrollTop )

定时器

  • 在 js 里面,有两种定时器,倒计时定时器间隔定时器

倒计时定时器

  • 倒计时多少时间以后执行函数

  • 语法: setTimeout(要执行的函数,多长时间以后执行)

  • 会在你设定的时间以后,执行函数

var timerId = setTimeout(function () {
  console.log('我执行了')
}, 1000)
console.log(timerId) // 1
  • 时间是按照毫秒进行计算的,1000 毫秒就是 1秒钟
  • 所以会在页面打开 1 秒钟以后执行函数
  • 只执行一次,就不在执行了

  • 返回值是,当前这个定时器是页面中的第几个定时器

间隔定时器

  • 每间隔多少时间就执行一次函数

  • 语法: setInterval(要执行的函数,间隔多少时间)

var timerId = setInterval(function () {
  console.log('我执行了')
}, 1000)
  • 时间和刚才一样,是按照毫秒进行计算的

  • 每间隔 1 秒钟执行一次函数

  • 只要不关闭,会一直执行

  • 返回值是,当前这个定时器是页面中的第几个定时器

关闭定时器

  • 语法1: clearInterval(定时器标识)
  •   语法2: clearTimeout(定时器标识)
  •   不管是什么定时器  两个语法都可以使用
var timerId = setTimeout(function () {
  console.log('倒计时定时器')
}, 1000)
clearTimeout(timerId)

//关闭以后,定时器就不会在执行了

var timerId2 = setInterval(function () {
  console.log('间隔定时器')
}, 1000)
coearInterval(timerId2)

//关闭以后,定时器就不会在执行了

定时器的异步执行

js是单线程的执行的: 在同一个时间只能做一个事情

  异步: 代码不按顺序执行,跳过执行;异步代码要先等所有的同步代码都执行完毕后才会 执行异步代码

  同步: 按顺序执行

DOM

获取页面元素

DOM(Document Object Model): 文档对象模型

 操作DOM就是操作页面中的元素

document对象其实也是window中的属性对象

   console.log( document )
   console.log( window )
   console.log( window.document === document )  // true

 1. document.getElementById(标签的id值)

 返回值: 页面中对应id值的标签元素(DOM对象)

  如果页面中没有对应的id标签则返回值 null

<body>
  <div id="box"></div>
  <script>
  	var box = document.getElementById('box')
  	console.log(box) // <div></div>
  </script>
</body>

2. document.getElementsByTagName(标签名)

返回值: 页面中对应标签元素组成的 集合  是一个伪数组

如果页面中没有对应的标签,则返回一个空的伪数组

伪数组:也就是和数组一样都是具有索引和length属性的集合

但是不具有数组的方法

<body>
  <div></div>
  <script>
  	var box = document.getElementsByTagName('div')
  	console.log(box) // [<div></div>]
    console.log(box[0]) // <div></div>
  </script>
</body>

 3. document.getElementsByClassName(类名)

 返回值: 页面中对应具有该类名标签元素组成的 集合  是一个伪数组

 如果页面中没有对应具有该类名标签的元素,则返回一个空的伪数组

<body>
  <div calss="box"></div>
  <script>
  	var box = document.getElementsByClassName('box')
  	console.log(box) // [<div></div>]
    console.log(box[0]) // <div></div>
  </script>
</body>

4. document.querySelector(选择器)

返回值: 页面中对应选择器的第一个标签元素

如果页面中没有对应选择器的标签元素, 则返回 null

console.log(document.querySelector('div')) // 获取页面中的第一个 div 元素 
console.log(docuemnt.querySelector('.box')) // 获取页面中第一个有 box 类名的元素
console.log(document.querySelector('#box')) // 获取页面中第一个 id 名为 box 的元素

 5. document.querySelectorAll(选择器)

返回值: 页面中所有 对应选择器的标签元素组成的元素集合 伪数组

 如果页面中没有对应选择器的标签元素, 则返回 空的伪数组

通过此方法获取返回的伪数组,实现了forEach的遍历方法

console.log(document.querySelectorAll('div')) // 获取页面中的所有的 div 元素 
console.log(docuemnt.querySelectorAll('.box')) // 获取页面中所有有 box 类名的元素

操作属性

  • 通过我们各种获取元素的方式获取到页面中的标签以后

  • 我们可以直接操作 DOM 元素的属性,就能直接把效果展示在页面上

1. innerHTML  操作元素的超文本内容

   获取: 元素.innerHTML

  console.log( dv.innerHTML )  // <span>666</span>

  设置: 元素.innerHTML = 内容   (可以识别html字符串)

 2. innerText  操作元素的文本内容

   获取: 元素.innerText

   console.log( dv.innerText )  // 666

   设置: 元素.innerText = 内容   (不可以识别html字符串)

 3. value   操作表单标签的内容

获取: 表单标签元素.value

 input 表单的输入事件----当输入框内容变化的时候就是触发

 标签的属性:  属性名=属性值

    标签属性的分类

      1. 原生属性

        - 在W3C规范中定义好的属性名

        - 比如: id,class,style, 表单标签中 value,name,checked

      2. 自定义属性

        - 我们自己写到标签上的属性

        - 比如: 页面中div的index属性

      3. H5自定义属性

        - 目的: 为了规范自定义属性的写法

        - 在标签的H5自定义属性:  data-属性名 = 属性值        

 元素的属性操作

1.原生属性的操作(直接通过点语法操作)

获取属性值:元素.属性名

设置属性:元素.属性名=值

2.自定义属性的操作

获取:元素.getAttribute('属性名')

设置修改: 元素.setAttribute('属性名','值')

移除: 元素.removeAttribute(属性名)

 // 自定义属性
   console.log( div.getAttribute('age') ) // 17
   console.log( div.getAttribute('data-id') ) // 7
   div.setAttribute('index','789')
   div.setAttribute('age','20')
   div.removeAttribute('age')

3. H5自定义属性操作

每一个标签元素都有一个dataset属性

这个属性的值是一个对象,此对象可以操作这个标签的所有H5自定义属性

元素.dataset会得到一个操作标签H5自定义属性的对象

 + 获取: 元素.dataset.属性名

 + 设置: 元素.dataset.属性名 = 值

 + 移除: delete 元素.dataset.属性名

 // H5自定义属性
   console.log( div.dataset )
  
   获取
   console.log( div.dataset.id )
   设置修改
   div.dataset.age = 20
   div.dataset.index = '666'
   删除
   delete div.dataset.name; 

  三个元素的样式操作

      1. 获取行内样式

      2. 获取行内非行内样式(行内,非行内都可以获取)

      3. 设置样式(只能设置行内样式)  

    注意: 如果是多个单词组成的样式名,

      1. 在js中使用驼峰写法    backgroundColo

      2. 使用数组关联法中字符串表示 ['background-color']

 1. 获取行内样式

  语法: 元素.style.样式名

console.log( div.style.border ) // 1px solid red

2. 获取非行内样式(行内也能获取)

  语法1: window.getComputedStyle(元素).样式名   低版本ie不能使用

console.log( window.getComputedStyle(div).border ) // 1px solid rgb(255, 0, 0)

语法2: 元素.currentStyle.样式名    只能在低版本ie中使用(只能获取非行内)

 3. 设置元素样式

语法: 元素.style.样式名 = 样式值

div.style.width = '100px';
div.style['border-radius'] = '50%'
div.style.borderRadius = '50%'

操作元素类名

1. className

      - 语法: 元素.className

      - 本质上就是元素的原有属性操作

      - 因为class是js中的关键字,所以改为className使用

2. classList

      - 元素.classList返回一个可以操作元素所有类名的 伪数组的集合

        - 这个集合对象有操作类名的方法

        - add(类名)  添加类名

        - remove(类名) 移除类名

        - toggle(类名) 类名切换

          + 如果存在则移除,不存在则添加

 var dv = document.querySelector('div');
   className
   //获取
   console.log( dv.className ) // 获取到所有的类名字符串
   设置类名
   dv.className = 'c1 orange'
   classList
   console.log( dv.classList ) // 得到一个类名组成为伪数组
   console.log( dv.classList[0] )
  // 添加
   dv.classList.add('orange');
  // 删除
   dv.classList.remove('c2');
  // 切换
   document.onclick = function () {
     dv.classList.toggle('orange');
   }

获取节点

1. 父节点.childNodes  获取父节点的所有子节点​​​​​​

<body>
  <div>
    <p>hello</p>
  </div>
  
  <script>
    // 这个 oDiv 获取的是页面中的 div 元素,就是一个元素节点
  	var oDiv = document.querySelector('div')
    
    console.log(oDiv.childNodes) 
    /*
    	NodeList(3) [text, p, text]
      0: text
      1: p
      2: text
      length: 3
      __proto__: NodeList
    */
  </script>
</body>

​​​

  • 我们会发现,拿到以后是一个伪数组,里面有三个节点
  • 一个 text:从 <div> 一直到 <p> 中间有一个换行和一堆空格,这个是第一个节点,是一个文本节点

  • 一个 p:这个 p 标签就是第二个节点,这个是一个元素节点

  • 一个 text:从 </p> 一直到 </div> 中间有一个换行和一堆空格,这个是第三个节点,是一个文本节点

  • 这个时候就能看到我们有不同的节点类型了

 2. 父节点.children    获取父节点的所有子元素节点

<body>
  <div>
    <p>hello</p>
  </div>
  
  <script>
    // 这个 oDiv 获取的是页面中的 div 元素,就是一个元素节点
  	var oDiv = document.querySelector('div')
    
    console.log(oDiv.children) 
    /*
    	HTMLCollection [p]
      0: p
      length: 1
      __proto__: HTMLCollection
    */
  </script>
</body>
  • 我们发现只有一个节点了,因为 children 只要元素节点

  • div 下面又只有一个元素节点,就是 p

  • 所以就只有一个,虽然只有一个,但是也是一个 伪数组

 3. 父节点.firstChild  获取父节点中的第一个子节点

<body>
  <div>
    <p>hello</p>
  </div>
  
  <script>
    // 这个 oDiv 获取的是页面中的 div 元素,就是一个元素节点
  	var oDiv = document.querySelector('div')
    
    console.log(oDiv.firstChild) // #text 
  </script>
</body>
  • 这个是只获取一个节点,不再是伪数组了

  • 获取的是第一个

  • 第一个就是 <div> 一直到 <p> 的那个换行和空格,是个文本节点

4. 父节点.lastChild  获取父节点中的最后一个子节点

<body>
  <div>
    <p>hello</p>
  </div>
  
  <script>
    // 这个 oDiv 获取的是页面中的 div 元素,就是一个元素节点
  	var oDiv = document.querySelector('div')
    
    console.log(oDiv.lastChild) // #text 
  </script>
</body>
  • 只获取一个节点,不再是伪数组

  • 获取的是最后一个

  • 最后一个就是 </p> 一直到 </div> 之间的换行和空格,是个文本节点

 5. 父节点.firstElementChild  获取父节点中的第一个子元素节点

<body>
  <div>
    <p>hello</p>
  </div>
  
  <script>
    // 这个 oDiv 获取的是页面中的 div 元素,就是一个元素节点
  	var oDiv = document.querySelector('div')
    
    console.log(oDiv.firstElementChild) // <p>hello</p>
  </script>
</body>
  • 只获取一个节点,不在是伪数组

  • 获取的是第一个 元素节点

  • 第一个元素节点就是 p 标签,是一个元素节点

6. 父节点.lastElementChild  获取父节点中的第一个子元素节点

<body>
  <div>
    <p>hello</p>
    <p>world</p>
  </div>
  
  <script>
    // 这个 oDiv 获取的是页面中的 div 元素,就是一个元素节点
  	var oDiv = document.querySelector('div')
    
    console.log(oDiv.lastElementChild) // <p>world</p>
  </script>
</body>
  • 只获取一个节点,不在是伪数组

  • 获取的是最后一个 元素节点

  • 最后一个元素节点是 <p>world</p>,是一个元素节点

 7. 节点.previousSibling     获取上一个兄弟节点

<body>
  <ul>
    <li id="a">hello</li>
    <li id="b">world</li>
    <li id="c">!!!</li>
  </ul>
  
  <script>
    // 这个 oLi 获取的是页面中的 li 元素,就是一个元素节点
  	var oLi = document.querySelector('#b')
    
    console.log(oLi.previousSibling) // #text
  </script>
</body>
  • 只获取一个节点,不在是伪数组

  • 获取的是 id="b" 这个 li 的下一个兄弟元素节点

  • 因为 id="b" 的下一个兄弟元素节点就是 id="c" 的 li,是一个元素节点

 8. 节点.previousElementSibling     获取上一个兄弟元素节点

<body>
  <ul>
    <li id="a">hello</li>
    <li id="b">world</li>
    <li id="c">!!!</li>
  </ul>
  
  <script>
    // 这个 oLi 获取的是页面中的 li 元素,就是一个元素节点
  	var oLi = document.querySelector('#b')
    
    console.log(oLi.previousElementSibling) // <li id="a">hello</li>
  </script>
</body>
  • 只获取一个节点,不在是伪数组

  • 获取的是 id="b" 这个 li 的上一个兄弟元素节点

  • 因为 id="b" 的上一个兄弟元素节点就是 id="a" 的 li,是一个元素节点

9. 节点.nextSibling     获取下一个兄弟节点

<body>
  <ul>
    <li id="a">hello</li>
    <li id="b">world</li>
    <li id="c">!!!</li>
  </ul>
  
  <script>
    // 这个 oLi 获取的是页面中的 li 元素,就是一个元素节点
  	var oLi = document.querySelector('#b')
    
    console.log(oLi.nextSibling) // #text
  </script>
</body>
  • 只获取一个节点,不在是伪数组

  • 获取的是 id="b" 这个 li 的下一个兄弟节点

  • 因为 id="b" 的下一个节点,是两个 li 标签之间的换行和空格,所以是一个文本节点

10. 节点.nextElementSibling     获取下一个兄弟元素节点

<body>
  <ul>
    <li id="a">hello</li>
    <li id="b">world</li>
    <li id="c">!!!</li>
  </ul>
  
  <script>
    // 这个 oLi 获取的是页面中的 li 元素,就是一个元素节点
  	var oLi = document.querySelector('#b')
    
    console.log(oLi.nextElementSibling) // <li id="c">!!!</li>
  </script>
</body>

11. 节点.parentNode       获取父节点

<body>
  <ul>
    <li id="a">hello</li>
    <li id="b">world</li>
    <li id="c">!!!</li>
  </ul>
  
  <script>
    // 这个 oLi 获取的是页面中的 li 元素,就是一个元素节点
  	var oLi = document.querySelector('#b')
    
    console.log(oLi.parentNode) // <ul>...</ul>
  </script>
</body>
  • 只获取一个节点,不在是伪数组

  • 获取的是当前这个 li 的父元素节点

  • 因为这个 li 的父亲就是 ul,所以获取到的就是 ul,是一个元素节点

 12. 节点.parentElement       获取父元素节点

 console.log( ele.parentElement )

13. 节点.attributes       获取节点的所有属性节点

console.log( ele.attributes )
   console.log( ele.attributes[0] )
   console.log( ele.attributes[1] )

 将伪数组转为真数组

     语法: Array.from(伪数组)

     返回值: 一个和伪数组中的数据一样的真

语法2: Array.prototype.slice.call(伪数组)

   返回值: 一个真数组

节点属性:

        - 属性节点: 是节点的一个类型

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

        - 每一类节点都有公共的内容

      - 节点属性一般有三个来描述

        - 节点名称,节点类型,节点值

      节点名称:  节点.nodeName 获取

        + 元素节点: 大写的标签名

        + 属性节点: 属性名

        + 文本节点: #text

        + 注释节点: #comment

      节点类型:  节点.nodeType 获取

        - 节点类型通过数值来表示不同的节点

          + 元素节点:  1

          + 属性节点:  2

          + 文本节点:  3

          + 注释节点:  8

      节点值:  节点.nodeValue 获取

          + 元素节点:  null

          + 属性节点:  属性值

          + 文本节点:  文本内容

          + 注释节点:  注释内容

 创建节点

 1. 创建文本节点

语法: document.createTextnode(文本)

// 创建一个文本节点
var oText = document.createTextNode('我是一个文本')

console.log(oText) // "我是一个文本"

2. 创建元素节点

语法: document.createElement(标签名)

// 创建一个 div 元素节点
var oDiv = document.createElement('div')

console.log(oDiv) // <div></div>

 插入节点

      - 向父节点内插入一个子节点

1. 父节点.appendChild()  向父节点内最后添加一个子节点

// 创建一个 div 元素节点
var oDiv = document.createElement('div')
var oText = document.createTextNode('我是一个文本')

// 向 div 中追加一个文本节点
oDiv.appendChild(oText)

console.log(oDiv) // <div>我是一个文本</div>

2. 父节点.insertBefore(要插入的子节点,在哪一个子节点之前)

<body>
  <div>
    <p>我是一个 p 标签</p>
  </div>
  
  <script>
  	var oDiv = document.querySelector('div')
    var oP = oDiv.querySelector('p')
    
    // 创建一个元素节点
    var oSpan = document.createElement('span')
    
    // 将这个元素节点添加到 div 下的 p 的前面
    oDiv.insertBefore(oSpan, oP)
    
    console.log(oDiv)
    /*
    	<div>
    		<span></span>
    		<p>我是一个 p 标签</p>
    	</div>
    */
  </script>
</body>

节点克隆

节点.cloneNode()

默认参数就是false 表示不克隆子节点

如果传入一个true 则表示克隆子节点

返回值: 克隆的新节点

 var div = document.querySelector('div') 
console.log( div.cloneNode() )
console.log( div.cloneNode(false) )
console.log( div.cloneNode(true) )

删除节点

 1. 节点.removeChild(子节点)  删除父节点中的子节点

<body>
  <div>
    <p>我是一个 p 标签</p>
  </div>
  
  <script>
  	var oDiv = document.querySelector('div')
    var oP = oDiv.querySelector('p')
    
    // 移除 div 下面的 p 标签
    oDiv.removeChild(oP)
    
    console.log(oDiv) // <div></div>
  </script>
</body>

 2. 节点.remove()  删除节点自己

div.remove()

节点替换(修改)

父节点.replaceChild(替换上的节点,替换下的节点)

<body>
  <div>
    <p>我是一个 p 标签</p>
  </div>
  
  <script>
  	var oDiv = document.querySelector('div')
    var oP = oDiv.querySelector('p')
    
    // 创建一个 span 节点
    var oSpan = document.createElement('span')
    // 向 span 元素中加点文字
    oSpan.innerHTML = '我是新创建的 span 标签'
    
   	// 用创建的 span 标签替换原先 div 下的 p 标签
    oDiv.replaceChild(oSpan, oP)
    
    console.log(oDiv)
    /*
    	<div>
    		<span>我是新创建的 span 标签</span>
    	</div>
    */
  </script>
</body>

获取元素尺寸

    两套语法

    1. client一套

      元素.clientWidth   获取元素的内容+padding的宽度

      元素.clientHeight  获取元素的内容+padding的高度

    2. offset一套

      元素.offsetWidth   获取元素的内容+padding+border的宽度

      元素.offsetHeight  获取元素的内容+padding+border的高度

 获取元素偏移量

    1. 元素.offsetParent  获取元素的定位父级

    2. offset一套

      - 元素.offsetLeft    获取元素相对于定位父级的左边距离

      - 元素.offsetTop     获取元素相对于定位父级的上边距离

    3. client一套

      - 元素.clientLeft    获取元素左边框的宽度

      - 元素.clientTop     获取元素上边框的宽度

<body>
    <div>
        <p><span>678</span></p>
    </div>
</body>
<script>
 var div = document.querySelector('div');
    var p = document.querySelector('p');
    var span = document.querySelector('span');
    offsetParent
    console.log(div.offsetParent)
    console.log(p.offsetParent)
    console.log(span.offsetParent)

    offset
    console.log(p.offsetLeft) // 30
    console.log(p.offsetTop) // 50

    console.log(span.offsetTop) // 0
    console.log(span.offsetTop) // 0

    console.log(div.offsetTop) // 100
    console.log(div.offsetTop) // 100

    client
    console.log(span.clientTop) // 10
    console.log(span.clientLeft) // 10
</script>

获取浏览器可视窗口尺寸

在BOM中获取浏览器可视窗口的尺寸   包含滚动条

window.innerWidth   获取窗口的宽度

window.innerHeight  获取窗口的高度

在DOM中获取浏览器可视窗口的尺寸  不包含滚动条

document.documentElement.clientWidth

document.documentElement.clientHeight

事件

什么是事件

事件---就是和浏览器约定好的事情

事件三要素

 1. 事件源         绑定事件的页面元素

  2. 事件类型       事件触发的行为

  3. 事件处理函数   当行为触发的时候要做的事情(函数)

! 事件处理函数中的this 就是事件源

! 只要绑定的事件行为触发了,就会执行绑定的事件处理函数

 ! 键盘事件可以给所有页面元素绑定,但是不是所有元素都可以触发键盘行为(一般绑定给docuemnt,表单元素...)

事件类型

1. 鼠标事件

      1. click       鼠标左键单击事件

      2. dblclick    鼠标左键双击事件

      3. contextmenu 鼠标右键单击事件

      4. wheel       鼠标滚轮事件

      5. mousedown   鼠标按下事件

      6. mouseup     鼠标松开事件

      7. mousemove   鼠标移动事件

      8. mouseover   鼠标移入事件

      9. mouseout    鼠标移出事件

      10. mouseenter 鼠标移入事件

      11. mouseleave 鼠标移出事件

      ! mouseover和mouseout是一套鼠标移入移出事件 事件源的子元素也会触发这一套的移入移除事件

      ! mouseenter和mouseleave是一套鼠标移入移出事件 事件源的子元素不触发

键盘事件

1. keydown  键盘按下事件

2. keypress 键盘按下事件(绑定键盘码)

3. keyup    键盘抬起事件 

- 键盘事件可以给所有页面元素绑定,但是不是所有元素都可以触发键盘行为(一般绑定给docuemnt,表单元素...)

- 键盘按下事件: 当键盘按键按下的时候,一直按着,则一直触发键盘按下事件

 - keypress的键盘按下事件---一些键盘的功能按键不能触发

 - keyup 键盘按键抬起的时候触发一次

表单事件

不是一定要绑定给form标签

1. blur   失去焦点事件

2. focus  获取焦点事件

3. input  输入事件

4. change 内容改变事件

- 只有当失去焦点的时候,内容和之前有变化才会触发

- 所以一般change事件给 select下拉选框和type为file的文件上传绑定

5. reset  重置事件

- 表单中的type是reset的按钮会触发默认的表单重置行为

     - 此事件需要绑定给form标签

6. submit 提交事件

- 此事件需要绑定给form标签

 - 表单中  type是submit的按钮的点击 默认触发表单的提交行为

- 表单输入框的的回车 会触发表单的默认提交行为

触摸事件

1. touchstart   触摸开始的时候触发

 2. touchmove    触摸移动的时候触发

 3. touchend     触摸结束的时候触发

其他事件

1. selectStart  鼠标选中事件

2. visibilitychange  页面选项卡切换 (离开页面事件)

  • 此事件中的document的visibilityState属性记录了当前页面是否可见的情况
  • 此属性值为visible 表示当前页面是可见的
  • 此属性值为hidden  表示当前页面是不可见的(离开页面)

事件绑定有两种方式  

1. DOM 0 级事件

- 通过 事件源.on+事件类型 = 事件处理函数 方式绑定的都是DOM 0 级事件

- 特点: 相同事件源的同一个事件类型只能绑定一个事件处理函数

2. DOM 2 级事件 (事件监听/事件侦听)

- 语法1: 元素.addEventListener('事件类型',事件处理函数)   低版本IE不兼容

- 特点: 相同事件源的同一个事件类型可以绑定多个事件处理函数,事件触发的时候,事件处理函数按照绑定顺序执行

语法2: 元素.attachEvent('on+事件类型',事件处理函数)   低版本IE中才可已使用

特点: 相同事件源的同一个事件类型可以绑定多个事件处理函数,事件触发的时候,事件处理函数按照绑定顺序倒序执行

事件解绑定

 DOM 0级 事件

语法: 事件源.on+事件类型 = null

因为 DOM0级是通过赋值的方式绑定的事件处理函数,也可以通过赋值的方式解绑事件处理函数

赋值 会覆盖

DOM 2级 事件

主流浏览器

语法: 事件源.removeEventListenter('事件类型',要解绑的事件处理函数)

oDiv.addEventListener('click', function () {
  console.log('我是第一个事件')
}, false)

oDiv.addEventListener('click', function () {
  console.log('我是第二个事件')
}, false)

//当你点击 div 的时候,两个函数都会执行,并且会按照你注册的顺序执行
// 先打印 `我是第一个事件` 再打印 `我是第二个事件`

注意: 事件类型的时候不要写 on,点击事件就是 click ,不是 onclick  

低版本IE

语法: 事件源.detachEvent('on+事件类型',要解绑的事件处理函数)

oDiv.attachEvent('onclick', function () {
  console.log('我是第一个事件')
})

oDiv.attachEvent('onclick', function () {
  console.log('我是第二个事件')
})

// 当你点击 div 的时候,两个函数都会执行,并且会按照你注册的顺序倒叙执行
// 先打印 `我是第二个事件` 再打印 `我是第一个事件`

! 如果绑定的是 匿名函数 则不能解绑,只能解绑 有名函数(事件绑定的时候,最好通过函数名绑定事件)

事件对象

什么是事件对象

    事件信息: 描述事件的信息,比如鼠标的事件,鼠标位置,鼠标是触发的是哪一个按键,事件类型.....

    事件对象: 就是在事件处理函数中可以获取的描述事件信息的对象

获取事件对象

在事件处理函数的形参可以来获取到事件对象

在每一个事件处理函数的行参位置,默认第一个就是 事件对象

oDiv.onclick = function (e) {
  // e 就是和 IE 的 window.event 一样的东西
  console.log(e.X轴坐标点信息)
  console.log(e.Y轴坐标点信息)
}

在低版本IE中获取不到

window.event 可以在事件处理函数中 获取到事件对象(可以兼容低版本IE)

综上所述,我们以后在每一个事件里面,想获取事件对象的时候,都用兼容写法

document.onclick = function (e) {
    // 处理函数的形参,在事件触发的时候,浏览器会自动将事件信息对象传递给这个形参
    // console.log( e )
    // console.log( window.event )
    // 兼容获取  短路写法
    e = e || window.event;
    // console.log( e )
    // 事件对象.type  可以获取到本次的事件类型
    // console.log( e.type )
  }

鼠标事件的按键信息

在事件处理函数中,通过 事件对象.button  可以获取到按键信息

按键的信息通过数字表示 哪一个按下的

鼠标事件的按键

      事件对象的button值: 0  表示是鼠标左键触发

      事件对象的button值: 1  表示是鼠标滚轮触发

      事件对象的button值: 2  表示是鼠标右键触发

 鼠标事件的坐标信息

触发事件时,鼠标相对于页面,浏览器,事件触发的元素的坐标信息

1. 事件对象.offsetX和事件对象.offsetY

- 获取鼠标相对于事件触发的元素坐标信息(鼠标相对于事件触发的元素左边和上边距离)

2. 事件对象.clientX和事件对象.clientY

   - 获取鼠标相对于浏览器的坐标信息(鼠标相对于浏览器左边和上边距离)

3. 事件对象.pageX和事件对象.pageY

- 获取鼠标相对于页面的坐标信息(鼠标相对于页面左边和上边距离)

键盘事件信息

键盘按键键码获取

通过 事件对象.keyCode 可以获取键盘事件按键的键码

键盘的组合键

事件对象.shiftKey  如果是true 则表示按下了shift键

事件对象.ctrlKey   如果是true 则表示按下了ctrl键

事件对象.altKey    如果是true 则表示按下了alt键

事件对象.mateKey   如果是true 则表示按下了window(mac中的command)键

键盘事件的注意事项

键盘按下事件有两个

keydown

 - 字母按键的键码,不区分大小写

keypress

  - 系统功能按键不会触发

事件目标

- 事件触发是对应的事件行为发生了,在事件源的后代元素上发生了该事件的行为,也会触发对应的事件,执行函数

- 事件触发的时候,准确触发该行为的元素就是该事件的目标事件目标获取

- 事件触发后,在事件处理函数中,可以通过事件对象获取事件目标

+ 语法: 事件对象.target     不兼容低版本IE

+ 语法: 事件对象.srcElement 低版本IE

注意: 鼠标移入移出事件 mouseenter和mouseleave 天生获取不到事件目标

事件传播

事件传播: 事件行为发生的时候,会将事件的行为在 结构父级上进行传播

 在事件处理函数中,可以通过事件对象来获取事件传播的结构父级

事件对象.path

事件传播机制

  • 事件目标: 准确触发事件行为的元素
  • 在低版本IE浏览器中,只有事件冒泡,没有事件捕获的能力
  • 在主流浏览器中,事件默认是在事件冒泡阶段执行,保留了在事件捕获阶段执行的能力
  • 事件执行,只能可能在冒泡阶段执行,或者捕获阶段执行

事件冒泡:

事件行为的传播,从事件目标开始,到window结束

事件捕获:

事件行为的传播,从window开始,到事件目标结束

DOM 0级 事件

- 只会在事件冒泡阶段执行,不可能在事件捕获阶段执行

DOM 2级 事件

- 因为低版本IE中只有冒泡没有捕获

- 主流浏览器,默认是在事件冒泡阶段执行,但是可以修改执行的阶段

 语法: 事件源.addEventListener(事件类型,处理函数, 决定执行阶段)

第三个参数默认为false,表示该事件在 事件冒泡阶段执行

如果传递为true,表示该事件在 事件捕获阶段执行

 阻止事件传播

DOM 0 级事件和低版本IE中的事件事件冒泡

DOM 2 级事件中才有可能是事件捕获阶段执行

在事件处理函数中 事件对象.stopPropagation

 -只能在DOM 0级事件中和主流 浏览器的事件传播中 可以使用

低版本IE浏览器

 + 事件对象.cancelBubble = true

事件委托

- 将某元素要绑定的事件,委托给结构父级上的元素绑定

 - 利用了使用冒泡的元素

循环事件绑定

1. 多次事件绑定,浪费了DOM性能

2. 对动态元素的事件绑定不友好

事件委托

- 比如: 要给a标签绑定点击事件,不会直接给a标签绑定,而是将事件绑定为a标签结构父级上的元素,并且在事件处理函数中,通过事件目标 来判断  点击的是a标签

 优点:

        + 减少元素事件绑定,和DOM操作提高性能

        + 对动态添加的元素 事件绑定 更友好

循环事件绑定中

        - this指向 绑定事件元素,事件源

事件委托

    - 事件目标 就是我们触发事件元素

阻止默认行为

浏览器的默认行为: 不需要我们绑定的事件,默认会触发的行为事件

- 比如:

        + a标签的点击 跳转或锚点

        + 页面中的鼠标右键 弹出菜单

        + 表单的submit按钮的点击事件,默认提交

        + 鼠标按下拖拽,默认选中文本

        + .....

阻止浏览器的默认行为: 当该行为发生的时候,不会执行默认的事情

1. 事件对象.preventDefault()  不能在低版本IE中使用

2. 事件对象.returnValue = false  只能在低版本IE中使用

3. 在事件处理函数中 return false 只能在DOM 0 级使用中使用

    + return false;只能写在函数代码最后,在return false; 之前代码不能有会报错

创建文档碎片

语法 document.createDocumentFragment()

解释:看做一个收纳袋(可以帮我们收纳节点元素,然后一次性的倒入需要插入的页面元素中---可以减少DOM操作)

作用:可以减少DOM操作

ES5&ES6

this 关键字

  • 每一个函数内部都有一个关键字是 this

  • 可以让我们直接使用的

  • 重点: 函数内部的 this 只和函数的调用方式有关系,和函数的定义方式没有关系

  • 函数内部的 this 指向谁,取决于函数的调用方式

  • - 函数中的this指向和函数定义的位置无关

    - 只和函数的调用执行方式有关(注意: 箭头函数除外)

1. 函数的普通调用就是  函数名() ------>  this指向window

function fn() {
  console.log(this)
}
fn()
// 此时 this 指向 window

2. 事件触发调用执行函数 -------------->  this指向事件源

div.onclick = function () {
  console.log(this)
}
// 当你点击 div 的时候,this 指向 div

3. 定时器调用函数 --------------------> this指向window

setTimeout(function () {
  console.log(this)
}, 0)
// 此时定时器处理函数里面的 this 指向 window

4. 对象调用-------------------------->  this调用该方法的对象

var obj = {
  fn: function () {
    console.log(this)
  }
}
obj.fn()
// 此时 this 指向 obj

5. 数组调用 数组[下标]() ------------->  this调用该方法的数组

function fn() {console.log( this )}
  function ff() {return this}
  var arr = [fn,ff]
  // arr[0]()
  console.log( arr[1]()===arr ) // true

6. 自调用函数------------------------->  this指向window

(function () {
  console.log(this)
})()
// 此时 this 指向 window

call 和 apply 和 bind

  • 我们还有三个可以忽略函数本身的 this 指向转而指向别的地方

  • 这三个方法就是 call / apply / bind

  • 是强行改变 this 指向的方法

1. call

call 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向

语法: 函数名.call(要改变的 this 指向,要给函数传递的参数1,要给函数传递的参数2, ...)

var obj = { name: 'Jack' }
function fn(a, b) {
  console.log(this)
  console.log(a)
  console.log(b)
}
fn(1, 2)
fn.call(obj, 1, 2)
  • fn() 的时候,函数内部的 this 指向 window

  • fn.call(obj, 1, 2) 的时候,函数内部的 this 就指向了 obj 这个对象

  • 使用 call 方法的时候

    1. 会立即执行函数

    2. 第一个参数是你要改变的函数内部的 this 指向

    3. 第二个参数开始,依次是向函数传递参数

2. apply

  • apply 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向

  • 语法: 函数名.apply(要改变的 this 指向,[要给函数传递的参数1, 要给函数传递的参数2, ...])

var obj = { name: 'Jack' }
function fn(a, b) {
  console.log(this)
  console.log(a)
  console.log(b)
}
fn(1, 2)
fn.call(obj, [1, 2])
  • fn() 的时候,函数内部的 this 指向 window

  • fn.apply(obj, [1, 2]) 的时候,函数内部的 this 就指向了 obj 这个对象

  • 使用 apply 方法的时候

    1. 会立即执行函数

    2. 第一个参数是你要改变的函数内部的 this 指向

    3. 第二个参数是一个 数组,数组里面的每一项依次是向函数传递的参数

3. bind

  • bind 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向

  • 和 call / apply 有一些不一样,就是不会立即执行函数,而是返回一个已经改变了 this 指向的函数

  • 语法: var newFn = 函数名.bind(要改变的 this 指向); newFn(传递参数)

var obj = { name: 'Jack' }
function fn(a, b) {
  console.log(this)
  console.log(a)
  console.log(b)
}
fn(1, 2)
var newFn = fn.bind(obj)
newFn(1, 2)
  • bind 调用的时候,不会执行 fn 这个函数,而是返回一个新的函数

  • 这个新的函数就是一个改变了 this 指向以后的 fn 函数

  • fn(1, 2) 的时候 this 指向 window

  • newFn(1, 2) 的时候执行的是一个和 fn 一摸一样的函数,只不过里面的 this 指向改成了

注意: 如果bind方法调用的时候, 只传递了一个参数, 则新函数调用的时候, 可以传递实参作为新函数执行中形参的值, 如果bind方法中传递了第二个参数 则新函数调用的时候传递的实参无效

万能检测数据类型

语法: Object.prototype.toString.call(要检测类型的数据)

JSON 方法

json 是一种特殊的字符串个是,本质是一个字符串

var jsonObj = '{ "name": "Jack", "age": 18, "gender": "男" }'
var jsonArr = '[{ "name": "Jack", "age": 18, "gender": "男" }, { "name": "Jack", "age": 18, "gender": "男" }, { "name": "Jack", "age": 18, "gender": "男" }]'

JSON格式的字符串: 数字或对象,使用单引号包裹的字符串,对象中的属性名必须使用双引号包裹,值为字符的也是只能使用双引号包裹

json格式的字符串,一般用于前后端交互进行数据传输的时候使用

JSON的两个方法

我们有两个方法可以使用 JSON.parse、JSON.stringify

json.stringify 是将 js 的对象或者数组转换成为 json 格式的字符串

JSON.parse

JSON.parse 是将 json 格式的字符串转换为 js 的对象或者数组

返回值: 数组或对象

var jsonObj = '{ "name": "Jack", "age": 18, "gender": "男" }'
var jsonArr = '[{ "name": "Jack", "age": 18, "gender": "男" }, { "name": "Jack", "age": 18, "gender": "男" }, { "name": "Jack", "age": 18, "gender": "男" }]'

var obj = JSON.parse(jsonObj)
var arr = JSON.parse(jsonArr)

console.log(obj)
console.log(arr)
  • obj 就是我们 js 的对象

  • arr 就是我们 js 的数组

JSON.stringify

JSON.stringify 是将对象或者数组转换为 json 格式的字符串

在使用JSON.parse()方法的时候,对于里面的数据格式要求严格

如果报错信息是 类似于 `in JSON at position` 则就传入的数据有问题

var obj = {
  name: 'Jack',
  age: 18,
  gender: '男'
}
var arr = [
  {
    name: 'Jack',
    age: 18,
    gender: '男'
  },
  {
    name: 'Jack',
    age: 18,
    gender: '男'
  },
  {
    name: 'Jack',
    age: 18,
    gender: '男'
  }
]

var jsonObj = JSON.stringify(obj)
var jsonArr = JSON.stringify(arr)

console.log(jsonObj)
console.log(jsonArr)
  • jsonObj 就是 json 格式的对象字符串

  • jsonArr 就是 json 格式的数组字符串

let 和 const 关键字

1. let及const 和 var 的区别

- 预解析

        + var 声明的变量会预解析

        + 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

- 重复声明同名变量

        + var 可以重复声明同名变量

        + let和const 不可以重复声明同名变量

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

// 使用 const 重复声明变量的时候就会报错
const num = 100
const num = 200 // 这里就会报错了

- 块级作用域

        + var 声明的变量不会被{}限制使用范围(没有块级作用域概念)

        + let 和 const 声明的变量,会将{} 变为块级块级作用域

           - 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) // 报错

2. let 和const区别

- 定义时赋值问题

        + let   声明变量的时候可以不赋值

        + const 声明变量的时候必须赋值

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

- 重新赋值问题

        + let   声明的变量可以重新赋值

        + const 声明的变量不能重新赋值

                - 所以很多地方也把const声明的变量称之为常量

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

箭头函数

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

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)
  }
}

箭头函数特点

1. 省略小括号

+ 当函数只有一个形参的时候,可以省略小阔

+ 如果函数有多个形参,则不能略小括号

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

2. 省略大括号

+ 当函数体中只有一句话(一个表达式)的时候,可以省略大阔号

+ 箭头函数会将这一句话的结果作为函数的结果返回,可以省略return关键字

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

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

3. 箭头函数中没有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) // 会直接报错

4. 箭头函数中的this关键字

+ 官方: 箭头函数函数中的this指向 执行上下文中的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

ES6新增了函数默认值的写法

在定义函数的小括号中,直接给形参赋值,这个就是函数内形参的默认值

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

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

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

模版字符串

字符串: 单引号或双引号包裹的内容

 特点1: 在字符串中不能有换行

ES6中的模板字符串可以解决以上两个问题

模板字符串: 使用反引号包括的内容  ``

1. 特点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

3.特点2: 在模板字符串可以识别 变量 ,变量在${变量} 可以解析

// 模版字符串拼接变量
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)

解构赋值

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

  • 解构赋值: 解析数据结构,并且赋值

  • 可以使用 {} 解构 对象

  • 语法: var {属性的同名变量} = 对象

  • 相当于:  var  属性的同名变量 = 对象.属性名

解构对象

快速的从对象中获取成员

// 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

解构数组

可以 []  将数组解构并赋值

语法: var [变量...] = 数组

将数组中的元素当做左边的变量的值

快速的从数组中获取成员

// 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
  • {} 是专门解构对象使用的

  • [] 是专门解构数组使用的

  • 不能混用

对象简写

1. 对象的属性名和 属性的变量名同名的时候,可以简写

2. 如果属性中的值是匿名函数,也可以简写

var username = 'zs';
  var age = 18;
  var o = {
    // 1. 对象的属性名和 属性的变量名同名的时候,可以简写
    // username:username
    username, // 简写
    age,
    // 2. 如果属性中的值是匿名函数,也可以简写
    // ff:function(){console.log( 666 )},
    ff(){console.log( 666 )},// 简写    
  }
  // console.log( o )
  // o.ff()

正则

  • 正则表达式,又名 “规则表达式”

  • 由我们自己来书写 “规则”,专门用来检测 字符串 是否符合 “规则” 使用的

  • 我们使用一些特殊的字符或者符号定义一个 “规则公式”,然后用我们定义好的 “规则公式” 去检测字符串是不是合格

创建一个正则表达式

  • 想制定 “规则”,必须要按照人家要求的方式来制定

  • 把一些字母和符号写在 // 中间的东西,叫做正则表达式,比如 /abcdefg/

  • 创建正则表达式有两个方式 字面量构造函数创建

字面量创建

// 下面就是字面量创建一个正则表达式
var reg = /abcdefg/

这个正则表达式就可以去检测字符串了

构造函数创建

// 下面就是构造函数创建一个正则表达式
var reg = new RegExp('abcdefg')
console.log(reg) //  /abcdefg/

使用构造函数方式创建的和字面量创建的,得到的结果一样

 正则表达式方法

  • 用来检测和捕获字符串中的内容的

1. test()   检测方法

语法: 正则表达式.test(字符串)

作用: 检测字符串是否符合正则表达式的规则

返回值: 布尔值

如果返回 true, 则字符串符合正则表达式的规则

如果返回 false,则字符串不符合正则表达式的规则

console.log(/\d+/.test('123')) // true
console.log(/\d+/.test('abc')) // false

2. exec()  捕获方法

语法: 正则表达式.exec(字符串)

作用: 从字符串中捕获出满足正则表达式的字符片段

返回值: 把字符串中符合正则要求的第一项以及一些其他信息,以数组的形式返回

如果可以捕获到内容,则返回一个包含捕获到的字符片段的数组

          + 如果正则表达式没有g和小括号

            - 则每次捕获都是从字符串的开始位置进行检索,如果检索到符合正则要求的内容则停止检索,返回一个数组 [0] 就是捕获的内容

          + 如果正则表达式中有标识符 g

            - 第一次捕获是从字符串的开始位置进行检索,检索到内容,则停止检索,返回数据,后续的每一次捕获都是在前一次检索结束的位置开始继续检索,如果字符串检索到最后,则下一次捕获则从开始位置开始,捕获到内容返回的都是数组 [0] 就是捕获到的字符判断

          + 如果正则表达式中有小括号

            - 捕获执行过程都一样,但是括号会进行单独捕获,在结果数组中对应小括号的位置体现

            + 如果正则表达式效果不想要单独捕获则 (?:)

var reg = /\d{3}/
var str = 'hello123world456你好789'
var res = reg.exec(str)
console.log(res)
/*
	["123", index: 5, input: "hello123world456你好789", groups: undefined]
    0: "123"
    groups: undefined
    index: 5
    input: "hello123world456你好789"
    length: 1
  	__proto__: Array(0)
*/
  • 数组第 0 项就是匹配到的字符串内容

  • index 属性表示从字符串的索引几开始是匹配的到字符串

正则表达式的组成

 1. 普通字符

 2. 元字符(表示某一类字符)

 3. 标识符

基本元字符

  • . : 匹配非换行的任意字符 (\n就是换行符)

  • \ : 转译符号,把有意义的 符号 转换成没有意义的 字符,把没有意义的 字符 转换成有意义的 符号

  • \s : 匹配空白字符(空格/制表符/...)

  • \S : 匹配非空白字符

  • \d : 匹配数字

  • \D : 匹配非数字

  • \w : 匹配数字字母下划线

  • \W : 匹配非数字字母下划线

var reg = /\s/
var str = 'a b'
var str2 = 'ab'
console.log(reg.test(str)) // true
console.log(reg.test(str2)) // false
var reg = /\d/
var str = 'abc1'
var str2 = 'abc'
console.log(reg.test(str)) // true
console.log(reg.test(str2)) // false
var reg = /\w/
var str = 'a1'
var str2 = '#@$'
console.log(reg.test(str)) // true
console.log(reg.test(str2)) // false

元字符--边界符

先限定了字符串的开头和结尾

1. ^     表示字符串以什么内容开头(必须写在正则的最前面)

2. $     表示字符串以什么内容结尾(必须写在正则的最后面)

注意: 正则表达式如果 有^和$,表示只能

注意: 正则表达式如果 没有^和$,表示包含

// 下面表示从开头到结尾只能有数字,并且出现 3 ~ 5 次
var reg = /^\d{3,5}$/
var str = 'abc'
var str2 = 'abc123'
var str3 = '1'
var str4 = '1234567'
var str5 = '123'
var str6 = '12345'
console.log(reg.test(str)) // false
console.log(reg.test(str2)) // false
console.log(reg.test(str3)) // false
console.log(reg.test(str4)) // false
console.log(reg.test(str5)) // true
console.log(reg.test(str6)) // true

元字符-限定符

限定前面内容出现的次数

  • * : 前一个内容重复至少 0 次,也就是可以出现 0 ~ 正无穷 次

  • + : 前一个内容重复至少 1 次,也就是可以出现 1 ~ 正无穷 次

  • ? : 前一个内容重复 0 或者 1 次,也就是可以出现 0 ~ 1 次

  • {n} : 前一个内容重复 n 次,也就是必须出现 n 次

  • {n,} : 前一个内容至少出现 n 次,也就是出现 n ~ 正无穷 次

  • {n,m} : 前一个内容至少出现 n 次至多出现 m 次,也就是出现 n ~ m 次

限定符是配合元字符使用的

// 下面正则表示验证数字出现 0 ~ 正无穷次都可以
var reg = /\d*/
var str = 'abc'
var str2 = 'abc1'
var str3 = 'abc123'
console.log(reg.test(str)) // true
console.log(reg.test(str2)) // true
console.log(reg.test(str3)) // true
// 下面正则表示验证数字出现 1 ~ 正无穷次都可以
var reg = /\d+/
var str = 'abc'
var str2 = 'abc1'
var str3 = 'abc123'
console.log(reg.test(str)) // false
console.log(reg.test(str2)) // true
console.log(reg.test(str3)) // true
// 下面正则表示验证数字出现 0 ~ 1 次都可以
var reg = /\d?/
var str = 'abc'
var str2 = 'abc1'
console.log(reg.test(str)) // true
console.log(reg.test(str2)) // true
// 下面正则表示验证数字必须出现 3 次
var reg = /\d{3}/
var str = 'abc'
var str2 = 'abc1'
var str3 = 'abc123'
console.log(reg.test(str)) // false
console.log(reg.test(str2)) // false
console.log(reg.test(str3)) // true
// 下面正则表示验证数字出现 3 ~ 正无穷次
var reg = /\d{3,}/
var str = 'abc'
var str2 = 'abc1'
var str3 = 'abc123'
var str4 = 'abcd1234567'
console.log(reg.test(str)) // false
console.log(reg.test(str2)) // false
console.log(reg.test(str3)) // true
console.log(reg.test(str4)) // true
// 下面正则表示验证数字只能出现 3 ~ 5 次
var reg = /\d{3,5}/
var str = 'abc'
var str2 = 'abc1'
var str3 = 'abc123'
var str4 = 'abc12345'
console.log(reg.test(str)) // false
console.log(reg.test(str2)) // false
console.log(reg.test(str3)) // true
console.log(reg.test(str4)) // true

元字符---特殊字符

具有比较特殊函数的字符

1. \

      - 转义

      - 可以将一些普通字符转为具有特殊函数的字符

        + d 就是普通字符  \d  就是表示数字了

      - 也可以将特殊字符转义为普票字符

        + . 表示非换行符  \.  就是普通的字符点 .

2. ()

      - 表示一个整体

      - 单独捕获(捕获方法中体现)

3. |

      - 或者(正则匹配左边或右边的内容)  

      - 一般在()中使用

4. []

      - 表示中括号中的任意一个

      - 注意: [] 只表示是一个位置

5. [^]

      - 表示只要不是[^]中的任意一个就行

6. -

      - 表示范围

      - 一般用在[]里面

      - 注意: 范围必须是连续的(Unicode)编码

        + a-z  A-Z

// 下面是一个简单的邮箱验证
// 非_$开头,任意字符出现至少6次,一个@符号,(163|126|qq|sina)中的任意一个,一个点,(com|cn|net)中的任意一个
var reg = /^[^_$].{6,}@(163|126|qq|sina)\.(com|cn|net)$/
//  \
  let reg = /\./;// 字符换包含点就行
  console.log( reg.test('qqcom') ) // false
  console.log( reg.test('qq.com') )// true
// ()
    let reg = /(er){3}/; // 字符串包含连续三个的er就行
    console.log( reg.test('eeerrr') ) // false
    console.log( reg.test('ererer') ) // true
    console.log( reg.test('erererer') ) // true
// |
    let reg = /(e|r){3}/; // 字符串中包含连续随机e或r出现3次
    console.log(reg.test('weeet')) // true
    console.log(reg.test('wrrrt')) // true
    console.log(reg.test('weret')) // true
    console.log(reg.test('werrt')) // true
    console.log(reg.test('wrert')) // true
    console.log(reg.test('wreet')) // true

    let reg = /^e|r$/;  // 字符串只能是e开头或r结束
    console.log( reg.test('etyu') ) // true
    console.log( reg.test('etyur') )// true
    console.log( reg.test('tyur') )// true
 // []
    let reg = /^[12345]$/; // 字符串只能是1或者2或者3或者4或者5的一位字符
    console.log( reg.test('0') ) // false
    console.log( reg.test('12') )// false
    console.log( reg.test('1') )// true
    console.log( reg.test('2') )// true
    console.log( reg.test('4') )// true
    console.log( reg.test('5') )// true
    console.log( reg.test('55') ) // false
  // [^]
    let reg = /^[^123]$/; // 字符串只能是非1或非2或非3的一位字符
    console.log( reg.test('0') ) // true
    console.log( reg.test('12') )// false
    console.log( reg.test('1') )// false
    console.log( reg.test('2') )// false
    console.log( reg.test('4') )// true
    console.log( reg.test('5') )// true
    console.log( reg.test('55') ) // false
// 中文编码范围:  u4e00-u9fa5
    let reg = /^[\u4e00-\u9fa5]{2,5}$/; //只能是2~5位的中文
    console.log( reg.test('wert') )  // false
    console.log( reg.test('你好呀') )// true
    console.log( reg.test('我是大哥') )// true
    console.log( reg.test('我也是小弟') )// true
    console.log( reg.test('我也是小弟弟') )// false
 // - 
    let reg = /^[a-zA-Z]\w{5,11}$/; // 字符串只能是字母开头,后面可以是连续的数字或字母或下滑5~11位结尾的
    // 用户名: 字母开头,只能由数字字母下滑线组成,长度6~12
    console.log(reg.test('1leon666')) // false
    console.log(reg.test('le!&#on666')) // false
    console.log(reg.test('leon666')) // true
    console.log(reg.test('l55eon6_')) // true
    console.log(reg.test('leon12345678')) // true
    console.log(reg.test('leon123456789')) // false

标识符

用于修饰正则表达式

     

  • i : 表示忽略大小写

    • 这个 i 是写在正则的最后面的

    • /\w/i

    • 就是在正则匹配的时候不去区分大小写

  • g : 表示全局匹配

    • 这个 g 是写在正则的最后面的

    • /\w/g

    • 就是全局匹配字母数字下划线

 如果是内置构造函数创建正则,则标识符写在作为第二个参数传递

          + var reg = new RegExp('qwer','ig');

内置构造函数创建正则注意事项:

      上面创建正则表达式中,传入的是字符串'\d{3}',在字符串中\是转义符号

      \d就是将d转义为特殊函数的d字符,但是转义后的字符d没有特殊函数,就是普通字符d

      所以在书写的时候,需要将\本身也转义为普通的字符

 字符串方法配合正则使用的

1. replace() 替换

        - 语法1: 字符串.replace(替换下的字符片段,替换上的字符片段)

        - 语法2: 字符串.replace(正则,替换上的字符片段)

        - 返回值: 替换完成的字符串

        注意: 如果正则表达式中的g,则会将字符串中所有匹配到的内容进行替换

var reg = /\d{3}/
var str = 'hello123world456'
var str2 = 'hello'
console.log(str.replace(reg)) // hello666world456
console.log(str2.replace(reg)) // hello
var reg = /\d{3}/g
var str = 'hello123world456'
var str2 = 'hello'
console.log(str.replace(reg)) // hello666world666
console.log(str2.replace(reg)) // hello

2. search()  查找

        - 语法1: 字符串.search(字符片段)

        - 语法2: 字符串.search(正则)

        - 返回值: 如果传入的字符片段或正则,在字符串中可以找到,则返回对应的字符片段第一个字符的索引,否则返回 -1

var reg = /\d{3}/
var str = 'hello123'
var str2 = 'hello'
console.log(str.search(reg)) // 5
console.log(str2.search(reg)) // -1

3. match()  匹配

        - 语法1: 字符串.match(字符片段)

        - 语法2: 字符串.match(正则)

        - 返回值: 如果字符片段或正则,在字符串中匹配不到,则返回null

          如果可以匹配到内容,传入的是字符串或正则表达式没有g,则返回值和正则捕获方法exec一样

          如果可以匹配到内容,传入的是正则表达式有g,则返回值是所有匹配到的字符片段组成数组

var reg = /\d{3}/
var str = 'hello123world456'
var str2 = 'hello'
console.log(str.match(reg)) 
// ["123", index: 5, input: "hello123wor456", groups: undefined]
console.log(str2.match(reg)) // nu
var reg = /\d{3}/g
var str = 'hello123world456'
var str2 = 'hello'
console.log(str.match(reg)) 
// ["123", "456"]
console.log(str2.match(reg)) // null

面向对象 

介绍面向对象

编程思想: 将过往生活中的经验,总结抽象后使用在编程中

面向过程编程: 就是每一步都要亲力亲为,注重编程中的每一个步骤,注重的过程

面向对象编程: 只需要对结果负责,不需要关注编程中的每一步骤,注重的是结果

现实生活的对象: 就是具体的某一个事物

      - 比如: 我桌子上的这个水杯,我敲代码的这台电脑

    现实中的对象,可以通过具体的事物特征和行为来描述这个对象

      - 比如: 我桌子上的这个水杯,

        + 特征:  形状: 圆柱体  材质:玻璃 上面的文字: 前锋互联

        + 行为:  装水: 可以装热水, 泡茶......

      - 比如: 你的女朋友对象

        + 特征:  身高: 165  体重: 100  头发: 黑长直

        + 行为:  吃饭: 喜欢吃辣椒  说话: 吵架....

编程中的对象,其实就是现实生活中的对象---抽象而来的

      - 将现实生活中对象的特征-----抽象为编程对象中的属性

      - 将现实生活中对象的行为-----抽象为编程对象中的方法

创建对象的方式

字面量创建对象

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

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

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

// 再来一个
var o2 = {}
o2.name = 'Rose'
o2.age = 20
o2.gender = '女'

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

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

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

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

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

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

// 正常操作对象
o1.name = 'Jack'
o1.age = 18
o1.gender = '男'

使用工厂函数的方式创建对象

  • 先书写一个工厂函数

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

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

function createPerson(name, age) {
    // 1. 创建一个空对象
    let o = new Object();
    // 2. 添加属性成员
    o.name = name;
    o.age = age;
    // 3. 返回对象
    return o;
  }
  //调用工厂函数 创建对象
  let p1 = createPerson('zs', 17);
  let p2 = createPerson('lisi', 18);
  let p3 = createPerson('ww', 19);
  console.log(p1, p2, p3); //输出三个对象
// 1. 先创建一个工厂函数
function createObj() {
  // 手动创建一个对象
  var obj = new Object()

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

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

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

工厂函数创建对象的问题

对象可以通过 instanceof 语法 来判断出 对象是属于哪一类的

语法: 对象 instanceof 构造函数

返回值: true: 该对象向是属于这类 ,false不属于  

// 内置构造函数创建对象---可以使用instanceof语法判断
    let d1 = new Date();
    let r1 = new RegExp();
    console.log(d1 instanceof Array) // false
    console.log(d1 instanceof RegExp) // false
    console.log(d1 instanceof Date) // true

内置的Object构造函数是js中的顶级构造函数---任何对象通过instanceof 语法判断是否属于Object都为true

console.log(d1 instanceof Object) // true
console.log(r1 instanceof Object) // true

工厂函数创建的对象

 let p1 = createPerson('zs', 17);
    console.log( p1 instanceof createPerson ) // false
    console.log( p1 instanceof Array ) // false
    console.log( p1 instanceof Date ) // false
    console.log( p1 instanceof Object ) // true

因为工厂函数创建的对象本质上就是Object构造函数创建的对象

所以工厂函数创建的对象 不能通过instanceof语法判断是否属于某一类

使用自定义构造函数创建对象

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

    • 手动创建对象

    • 手动添加成员

    • 手动返回对象

  • 构造函数会比工厂函数简单一下

    • 自动创建对象

    • 手动添加成员

    • 自动返回对象

  • 先书写一个构造函数

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

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

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

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

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

内置构造函数:String Number Boolean RegExp Date Function Array Object(顶级构造函数)

- 构造函数作用: 创建对象

    - 构造函数创建对象的过程  我们也叫做是实例化对象

      + 构造函数创建的对象  我们也叫做是实例对象

    - 构造函数创建对象语法: 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')

自定义构造函数小结

1. 构造函数函数名 一般首字母大写

2. 构造函数作用: 创建对象

3. 实例化对象的时候,构造函数中的this指向实例对象

4. 构造函数中不需要写return,会自动返回this指向的实例

        - 如果return 的是基本数据类型,则return 白写的

         - 如果 return 的是复杂数据类型, 则构造函数白写了

5. 在new 方式调用构造函数的时候,构造函数可以省略小阔号,但是建议不要省略  

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

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

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

自定义构造函数的缺陷

function Person(name){
    this.name = name;
    this.xi = function () {
      console.log( '洗碗' )
    }
  }
  // 实例化对象
  let zs = new Person('zs');
  let ls = new Person('ls');
  console.log( zs,ls );
  // zs.xi();
  // ls.xi();
  console.log( zs.xi === ls.xi ); // false

多个实例对象中相同的方法,功能作用都是一样的,但是在内存中会有多份,这样就会造成内存的浪费----构造函数创建对象的缺陷

自定义构造函数缺陷解决方案

// 自定义构造函数
  function Person(name) {
    this.name = name;
    this.xi = function () {
      console.log( '洗碗' )
    }
    // 方案1
    this.xi = xi;
    // 方案2
    this.xi = fnObj.xi;
  }
  // 方案2
  let fnObj = {
    xi: function () {
      console.log('洗碗')
    }
  }
  // 方案3--原型对象
  Person.prototype.xi = function () {
    console.log( '洗碗' );
  }

  // 实例化对象
  let zs = new Person('zs');
  let ls = new Person('ls');
  // 方案1
  function xi() {
    console.log( '洗碗' );
  }

  // 多个实例对象中相同的方法,功能作用都是一样的,
但是在内存中确实多份,这样就会造成内存的浪费----构造函数创建对象的缺陷

  // 构造函数实例化对象的缺陷---解决方案1
  // 将方法的函数写到全局中
  // console.log( zs.xi === ls.xi ) // true
  // 构造函数实例化对象的缺陷是解决了----但是将方法函数写到全局中,
容易造成全局变量的污染

  // 构造函数实例化对象的缺陷---解决方案2
  // 将方法函数写到一个全局对象中
  // console.log(zs.xi === ls.xi) // true
  // 构造函数实例化对象的缺陷是解决了---函数名变量污染问题也没有了,
但是需要再全局中创建一个对象(在一定程度上也是内存的浪费)


  // 构造函数实例化对象的缺陷---解决方案3
  // 将方法函数添加到原型对象中
  // 原型对象中的方法属性,实例对象可以访问到
  // 原型对象是构造函数创建的时候,浏览器自动创建的一个对象空间
  // 通过构造函数的prototype属性可以访问
  // console.log( Person.prototype )

  // console.log( zs,ls );
  // zs.xi()
  // ls.xi()
  // console.log( zs.xi === ls.xi ) // true

原型---原型对象

定义函数的时候,浏览器会自动的创建一个对象空间创建的这个空间就是原型对象

        + 也就是说 每一个函数都会有一个对应的原型对象

1. 实例对象和函数的关系

        - 函数通过new 语法创建了 实例对象

2. 原型对象和函数的关系

prototype

        - 函数都有一个属性 prototype,这个函数的属性指向的就是原型对象

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

function Person() {}

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

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

function Person() {}

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

 我们发现了一个叫做 prototype 的空间是和函数有关联的

  • 并且可以向里面存储一些东西

  • 重点: 在函数的 prototype 里面存储的内容,不是给函数使用的,是给函数的每一个实例化对象使用

        原型对象都有一个constructor属性,这个属性指向 对应的函数

3. 实例对象和原型的关系

__proto__

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

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

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

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

    • 如果这个对象自己本身有这个成员,那么就会直接给你结果

    • 如果没有,就会去 __proto__ 这个对象空间里面找,里面有的话就给你结果

function Person() {}

var p1 = new Person()

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

那么这个 __proto__ 又指向哪里呢?

  • 这个对象是由哪个构造函数 new 出来的

  • 那么这个对象的 __proto__ 就指向这个构造函数的 prototype

function Person() {}

var p1 = new Person()

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

- 对象都有一个属性 __proto__,这个属性指向的是 创建这个对象的构造函数所对应的原型对象

! 注意1: 需要给原型对象的添加成员,不要通过实例对象的__proto__来添加,应该通过函数的prototype来添加

! 注意2: 给原型对象添加的属性方法成员,一般都是给实例对象使用,而不是给原型本身使用的

原型链

  • 我们刚才聊过构造函数了,也聊了原型

  • 那么问题出现了,我们说构造函数的 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

 

ES6中创建对象新增语法class语法

class就是类---作用和构造函数一样创建对象

 !注意: 构造函数可以当做普通函数使用(函数调用),ES6中的类只能用于创建对象,不能当做函数调用

实例化对象的语法和构造函数也一样: 通过new 的语法创建对象

语法: new 类名()

 class 语法

      class 类名{

        // 在此处书写方法不要加function

        constructor(){ // constructor类的构造方法,当实例化类创建对象的时候,默认会执行方法

          // 在此方法中通过this给实例对象添加属性

          this.name = 'zs'

        }

        // 此处书写的方法就是给原型对象添加的方法

        fn(){} //给原型对象添加的 fn方法

      }

1. constructor是类的构造方法,当实例化类创建对象的时候,默认会执行方法

- constructor方法中的this指向创建的实例对象

      - 在new 类名实例化的时候传递的实参,constructor方法中的形参会接收到

- constructor方法中的this指向创建的实例对象

- 在new 类名实例化的时候传递的实参,constructor方法中的形参会接收到

// 创建Person类
  class Person {
    constructor(name){
      // this 就是实例对象
      this.name = name;      
      // 一般将方法写到原型中
      this.eat = function () {
        console.log( 'eat' )
      }
    }
    // 给原型添加方法
    study(){
      console.log( 'code' )
    }

  }
  // 实例化对象
  let zs = new Person('zs');
  let ls = new Person('ls');
  // zs.eat()
  // ls.eat()
  // // eat方法是实例对象中的方法
  // console.log( zs.eat === ls.eat ) // false

  
  // study是原型对象中的方法
  // zs.study()
  // ls.study()
  // console.log( zs.study === ls.study ) // true

ES6模块化语法

- 利用自身的语法规则,把当前文件中引入别的文件

- 在开发中更多的是模块化开发

在使用模块化语法的时候(前提)

1. script标签中type属性值 必须为module

- 只有这样才能识别里面的模块化语法

2. 页面只能通过服务器打开(可以通过vscode的临时服务器 Live Server(插件))

- 不能本地直接打开

使用模块化语法

- 在模块化中相互的文件之间没有任何联系(互不影响)

        + 一个文件就是一个文件作用域

- 如果文件之间的数据要交互,则需要使用到模块化的导入导出语法

- 导出语法:  只有向外导出的数据,别的文件中在导入的时候才可以使用

语法1: export default 数据

语法2: export 数据

 - 导入语法:

        + 导入的文件中的代码会立即执行

语法1: import 变量 from 文件

语法2: import {变量} from 文件

        - 导入语法1只能导入 导出语法1 导出的数据

        - 导入语法2只能导入 导出语法2 导出的数据

语法3: import 文件

 - 只导入执行文件,不接收任何内容

浏览器本地存储---------storage

- storage分为 localStorage 和 sessionStorage

1. 存储数据的方式

- localStorage和sessionStorage都是一键值对的形式存储数据

- 存储的键值也只能是字符串

- 如果想要存储对象或数组,则需要先将对象或数组转为JSON格式

2. 存储大小

- 20M左右

3. 存储数据的生命周期

- localStorage的数据是持久化存储(只要你不删除,永远都还在)

- sessionStorage存储的数据是 会话级别(浏览器打开到关闭)

4. 和后端的交互

- 前后端交互的时候,localStorage 和 sessionStorage的数据,

- 不会自动携带在请求和响应中

5. 页面通讯

- 在同域名下(或同是本地)localStorage可以跨页面方法

- sessionStorage中的数据,只有在当前页面跳转到的页面中才能访问到

localStorage和SessionStorage 的操作 浏览器都提供了API方法

因为localStorage和SessionStorage 的操作都是属于BOM操作,所以可以省略widnow.

localStorage的操作API

1. 设置添加方法

语法: window.localStorage.setItem(key,value)

语法: localStorage.setItem(key,value)

value值必须是字符串,如果传入的不是字符串则会隐式转为字符串然后存储

如果需要存储对象或数组,转为JSON格式然后存储

 localStorage.setItem('calssInfo', JSON.stringify({
        className: 2207,
        nums: 72
    }))
    localStorage.setItem('users', JSON.stringify([{
            username: 'zs',
            age: 17,
            score: 100
        }, {
            username: 'ls',
            age: 18,
            score: 110
        }, {
            username: 'ww',
            age: 18,
            score: 119
        }]))

键名同名的时候,就是设置修改

localStorage.setItem('userName','zs')

2. 获取方法

语法: localStorage.getItem(键名)

根据键名查找获取localStorage中的数据

返回值: 查询到的字符串数据,没有该键名则为null

   console.log( localStorage.getItem('abc') )// null
    console.log( localStorage.getItem('userInfo') )// '[object Object]'
    console.log( localStorage.getItem('userAge') ) // '18'
    console.log( typeof localStorage.getItem('userAge') ) // 'string'
    var resStr = localStorage.getItem('users');
    console.log( resStr )// JSON格式数据
    // 通过JSON.parse(JSON格式数据)  转为数组或对象
    console.log( JSON.parse(resStr) )
    let str = localStorage.getItem('userInfo');
    // console.log( str )
    console.log( JSON.parse(str) ); // 报错---因为str不是json格式数据

3. 移除方法

语法: localStorage.removeItem(键名)

 根据键名移除对应的数据

返回值: 查询到的字符串数据,没有该键名则为null

4. 清空方法

语法: localStorage.clear()

移除所有的数据

localStorage.clear();

sessionStorage的操作API

1. 设置添加方法

语法: window.sessionStorage.setItem(key,value)

语法: sessionStorage.setItem(key,value)

value值必须是字符串,如果传入的不是字符串则会隐式转为字符串然后存储

如果需要存储对象或数组,转为JSON格式然后存储

sessionStorage.setItem('userName', 'leon');
    sessionStorage.setItem('userAge', 18);
    sessionStorage.setItem('userInfo', {
        name: 'zs'
    })
    sessionStorage.setItem('classInfo', JSON.stringify({
        className: 2207,
        nums: 72
    }))
    sessionStorage.setItem('users', JSON.stringify([{
            username: 'zs',
            age: 17,
            score: 100
        }, {
            username: 'ls',
            age: 18,
            score: 110
        }, {
            username: 'ww',
            age: 18,
            score: 119
        }]))

键名同名的时候,就是设置修改

sessionStorage.setItem('userName','zs')

2. 获取方法

语法: sessionStorage.getItem(键名)

根据键名查找获取sessionStorage中的数据

返回值: 查询到的字符串数据,没有该键名则为null

 3. 移除方法

语法: sessionStorage.removeItem(键名)

根据键名移除对应的数据

 4. 清空方法

语法: sessionStorage.clear()

移除所有的数据

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值