目录
1.变量与函数
1.1作用域
1.2定义变量
1.3作用域链
1.4闭包
1.5预解析
1.6let提升
1.7函数参数
1.8箭头函数
2.解构赋值
3.1数组解构
3.2对象解构
3.对象
4.1字面量创建对象
4.2构造函数
4.2.1自定义构造函数
4.2.2静态成员和实例成员
4.数据类型
4.1引用类型
4.1.1Object
4.1.2Array
4.1.3RegExp
4.2包装类型
4.2.1String
4.2.2Number
4.2.3Boolean
5.封装
5.1 原型对象
6.继承
5.2原型链
7.this指向
7.1普通函数
7.2严格模式
7.3箭头函数
7.3改变函数的this指向
7.3.1call
7.3.2apply
7.3.3bind
8.class关键字(类)
8.1封装
8.2继承
9.拷贝
9.1浅拷贝
9.2深拷贝
1.变量与函数
1.1作用域
作用域:规定了变量使用的范围,离开了这个范围变量就不能再被访问
分类:全局作用域和局部作用域 ===> 变量可以分为全局变量和局部变量
局部作用域:
- 函数作用域:函数内部声明的变量,只能在函数内部被访问,外部无法直接访问
- 块级作用域:JS中使用{ }包裹的代码称为代码块,代码块内部声明的变量外部有可能无法访问
局部变量:在局部作用域中声明的变量,只能在当前函数内部使用
- 函数每次执行都会开辟新的内存空间,当函数执行完毕之后,就会释放这块空间,并且销毁里面的变量(局部变量)
- 形参相当于局部变量
全局作用域:
- 在script标签中局部作用域外的区域
全局变量:在全局作用域中声明的变量,在任何地方都能使用
📖Note:
- 不建议定义大量的全局变量,防止造成变量污染
1.2定义变量
关键字:let,var,const
let和var的区别:
- let声明的变量会产生块作用域,var声明的变量不具有块级作用域
- var可以重新定义声明的变量,let不可以
- var声明的变量相当于window添加属性,let直接就是变量
let和var的同:
- var和let声明的变量都可以只定义不赋值,这个变量就是undefined
const:声明的变量值不能改变,称为常量,const声明的常量必须初始化赋值,其他用法和let相同
📖Note:
- 常量名通常大写
- 一般固定不变的值使用const定义为常量
1.3作用域链
作用域链:底层的变量查找机制,当访问一个变量时,先在当前作用域内查找是否有这个变量的声明,没有找到则去上级作用域查找,依次查找父级作用域直到全局作用域,这个查找的过程会形成一个链状结构
📖Note:
- 子作用域可以访问父作用域,父作用域不可以访问子作用域
1.4闭包
闭包:一种比较特殊的函数,使用闭包能够访问函数作用域中的变量,从代码形式上看闭包是一个作为返回值的函数
- 闭包本质仍是函数,只不过是从函数内部返回
- 闭包能够创建外部可访问的隔离作用域,避免全局变量污染,能够使变量的作用范围延伸
- 过度使用闭包可能造成内存泄漏
- 回调函数也能访问函数内部的局部变量
1.5预解析
预解析:在代码执行之前,先要预解析代码,预解析变量和函数
- 变量:带有声明的变量,JS会把声明的变量提升到当前作用域的最前面,只声明不赋值
- 函数:代表函数名的变量,JS会把带有名字的函数提升到当前作用域的最前面,只定义不调用
变量解析:
- 变量在未声明时就被访问会报语法错误
- 变量在声明之前就被访问,变量的值为undefined
- 变量提升出现在相同作用域中
- 实际开发中推荐先声明再访问变量
函数解析:
- 函数表达式不存在提升的现象
- 函数提升出现在相同作用域中
1.6let提升
上面代码报错原因:初始化之前不能访问n
let声明的变量存在变量提升,但是let定义的变量没有初始化之前不允许被使用
死区范围内(变量声明赋值之前的区域)不允许访问let定义的变量
1.7函数参数
函数参数
- 声明函数时为形参赋值即为参数的默认值
- 如果形参未定义默认值时,参数的默认值为undefined
- 调用函数时没有传入对应参数时,参数的默认值会被当成实参传入
动态参数:
arguments:函数内部内置的伪数组变量,包含函数调用时传入的所有实参
📖Note:
- 参数固定写形参,不固定使用arguements
剩余参数
- 剩余值写法:...
- ...是语法符号,置于函数最末形参前,用于获取多余的实参
- 借助...获取剩余的实参
1.8箭头函数
语法:
- let fn = (形参列表) => {函数体}
调用:
- fn(实参列表)
📖Note:
- 如果参数只要一个,那么可以省略小括号
- 如果函数体只有一行,可以省略大括号,大括号省略会自动返回结果
箭头函数的应用:回调函数
箭头函数使用注意点
- 箭头函数使基于函数表达式延伸出来的,不存在预解析,必须先定义再调用
- 箭头函数中,不存在arguements对象,动态参数使用剩余参数接收
- 箭头函数中不存在this,箭头函数中的this指向上级作用域的this
在对象的fun方法中,this本来应该指向事件源window,但是回调函数是箭头函数,箭头函数中的this指向了函数的调用者obj
2.解构赋值
解构赋值:一种快速为变量赋值的简洁语法,本质上仍是为变量赋值,
分类:数组解构,对象解构
3.1数组解构
数组解构:将数组的单元值快速批量赋值给一系列变量的简洁语法
非一一对应的情况:
1.变量多,值少
2.变量少,值多
3.按需取值
4.剩余值法
5.复杂情况
3.2对象解构
对象解构:把属性名当作变量名
命名冲突:修改属性名字
对象嵌套对象
3.对象
对象:类中某个具体的实例,属性和方法的集合体
4.1字面量创建对象
4.2构造函数
构造函数:专门用于创建对象的函数,如果一个函数使用new关键字,那么这个函数就是构造函数
4.2.1自定义构造函数
构造函数中的this指向实例化对象
instanceof: 判断一个对象是否是另外一个构造函数的实例化对象
语法:对象 instanceof 构造函数
constructor :指回构造函数本身
4.2.2静态成员和实例成员
静态成员(静态属性/方法):把在构造函数身上直接添加的成员
- 静态成员只能由构造函数访问
实例成员:构造函数内部为实例化对象准备的成员
- 实例成员只能由实例化对象访问
4.数据类型
JS中主要的数据类型:字符串,数值,布尔,undefined,null,对象
字符串,数值,布尔,undefined,null称为简单类型或基础类型;对象也称为引用类型,常见的对象类型包括数组和普通对象
JS中内置了一些构造函数,用于创建对应类型的对象
数据传递:
- 值传递:会把数据复制一份传递(简单类型)
- 引用传递:会把数据地址复制一份传递(引用类型)
4.1引用类型
4.1.1Object
Object是内置的构造函数,用于创建普通对象
常见实例方法:
- assign()方法:静态方法创建新的对象
- keys()方法:静态方法获取对象的所有键 以数组形式返回
- value()方法:获取对象中所有的属性值
4.1.2Array
Array是内置的构造函数,用于创建数组对象
数组实际上是new Array的实例化对象
常见实例方法:
- forEach():遍历数组,替代for循环
- filter():过滤数组单元值,生成新数组
- map():迭代原数组,生成新数组
- join():数组单元素拼接成字符串
- concat():合并两个数组,生成新数组
- sort():对原数组单元值排序
- splice():删除或替换原数组单元
- indexOf():检索数组单元值
- reverse():反转数组
- from():伪数组转成数组
indexOf():查找某个元素在数组中首次出现的索引位置,找不到返回-1
lastindexOf():查找某个元素在数组中尾次出现的索引位置,找不到返回-1
静态方法:
数组的使用:
4.1.3RegExp
创建正则对象
4.2包装类型
JS中,字符串,数值,布尔具有对象的使用特征,如属性和方法
字符串,数值,布尔类型数据是JS底层使用Object构造函数‘包装’来的,被称为包装类型
4.2.1String
内置的构造函数。用于创建字符串
区别:
- subString()自动识别索引的大小
相同:
- 如果只有一个参数,从这个索引位置截取直到字符串结束
4.2.2Number
内置的构造函数,用于创建数字类型
4.2.3Boolean
JS中一切皆对象
引用类型和包装类型都包含两个公共的方法
- toString:以字符串形式表示对象
- valueOf:获取原始值,很少主动调用该方法
📖Note:
- null和undefined除外
5.封装
构造函数
- 构造函数体现了面向对象的封装特性
- 构造函数实例创建的对象彼此独立,互不影响
- 命名空间式的封装无法保证数据的独立性
5.1 原型对象
原型对象:每一个构造函数都有一个名为prototype的属性,prototype指向一个对象数据类型,称为构造函数的原型对象,每个原型对象都具有constructor属性代表该原型对象对应的构造函数
作用:共享方法,节省内存
当实例对象找不到成员时,就会在原型对象中查找成员
实例化对象可以使用原型对象中的方法
6.继承
继承是面向对象的另一个特征,通过继承可以进一步提升代码的封装程度,JS中大多是借助原型对象实现继承特性
继承之后prototype的属性constructor属性被覆盖
添加constructor属性
问题:Teacher.prototype = obj是引用传值,Teacher.prototype和Student.prototype共用同一个obj的空间,Teacher.prototype.constructor = Teacher的修改也会导致Student的原型对象中的constructor属性指向Teacher
5.2原型链
原型链:由原型对象构成的一个链状结构
作用:提供了成员查找的机制
数组是Array的实例对象,构造函数Array()也有原型对象
<script>
let str = '15375635243273819198387443534234945342648'
// 用对象保存字符及字符出现次数
let obj = {
}
// 统计次数
// 如果对象中有这个键(字符),给值加1
// 没有,则添加键,并给值加一
for(let i = 0; i < str.length; i++) {
// 在obj中查找是否有str[i]属性
// 注意:不能使用.访问 obj.str[i] 是访问obj中确实存在的属性
// 存在str[i]属性 返回属性值 隐式类型转换为布尔值
if(obj[str[i]]) {
obj[str[i]]++
} else {
obj[str[i]] = 1
}
}
// 求出现最多次数的字符
let max = 1
let count = obj['1']
for(let key in obj) {
if(count < obj[key]) {
count = obj[key]
max = key
}
}
console.log(max, count)
</script>
7.this指向
7.1普通函数
普通函数的调用方式决定了this的值,谁调用函数this指向谁
构造函数 :this指向实例化对象
方法:this指向调用者
事件处理函数:this指向事件源
定时器:this指向调用者
自调用函数(立即调用函数):this指向调用者
普通函数没有明确调用者时this的值为window,严格模式下没有调用者时this的值为undefined
7.2严格模式
语法:"use strict"
放在作用域的开头,才能生效
放到全局作用域的开头,代表全局都是严格模式
严格模式下:
- 变量必须先定义再使用
- 普通函数中的this指向undefined
- 函数的形参不能重名
7.3箭头函数
箭头函数中的this不受调用方式的影响,实际上,箭头函数中并不存在this,箭头函数中访问的this是箭头函数所在作用域的this变量
📖Note:
- 事件处理函数中一般不使用箭头函数,this的指向不明确
7.3改变函数的this指向
7.3.1call
call方法调用函数,同时指定函数中的this值
语法:函数.call(this, arg1, arg2......)
📖Note:
- 使用call方法调用函数时,第一个参数为this指定的值
- call方法的其余参数会依次自动传入函数作为函数的参数
7.3.2apply
语法:函数.apply(this, [ ])
第二个参数是一个数组,是传入的参数
7.3.3bind
语法:函数.bind(this, arg1, arg2......)
bind方法不会调用函数,而是创建了一个指定了this值的新函数
8.class关键字(类)
8.1封装
class是ES6中新增的关键字,专门用于创建类,类可被用于实现逻辑的封装
constructor(构造函数,构造方法,构造器):创建类时在类的内部有一个特定的方法constructor,该方法会在类被实例化时自动被调用,常用于处理一些初始化操作
8.2继承
子类有自己的成员时,继承过程中,子类中constructor必须调用super函数
类的本质:构造函数
- ES6之前,使用构造函数创建对象
- ES6之后,使用关键字class创建对象
9.拷贝
9.1浅拷贝
复杂对象类型 ===> 简单数据类型
Object.assign(obj1, obj2)
浅拷贝