JS进阶
面向对象编程
两大编程思想:
-
面向过程:面向过程就是分析出解决问题所需的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个一次调用
优点:性能比面向对象高,适合跟硬件联系很紧密的东西,例如单片机采用的面向过程编程
缺点:没有面向对象易维护、易复用、易扩展
-
面向对象:把事物分解成一个一个对象,然后由对象之间分工合作
优点:易维护、易复用、易扩展、具有封装、继承、多态的特性,可以设计出低耦合的系统,使得系统更加灵活,更加易于维护
缺点:性能比面向过程低
面向对象特性:
- 封装性
- 继承性
- 多态性
面向对象思维特点:
1、抽取对象共用的属性和行为组织(封装)成一个类(模板)
2、对类进行实例化,获取类的对象
对象是由属性和方法组成的:
- 属性:事物的特征,在对象中用属性来表示
- 方法:事物的行为,在对象中用方法来表示
ES6中的类和对象
类constructor构造函数
constructor()方法是类的构造,用于传递参数,返回实例对象,通过new命令生成对象实例时,自动调用该方法,如果没有显示定义,类内部会自动给我们创建一个constructor()
类的继承
语法:
class 子类名称 extends 父类名称{}
super关键字
super关键字用于访问和调用对象父级上的函数。可以调用父类的构造函数,也可以调用父类的普通函数。
类和对象使用的注意
1.在ES中类没有变量提升,所以必须先定义类,才能通过类实例化对象
2.类里面的共有属性和方法一定要加this使用
3.类里面的this指向问题,谁调用了,this就指向谁
构造函数和原型导读
创建对象可以通过以下三种方式:
1.对象字面量
2.new Object
3.自定义构造函数
构造函数
- 静态成员:在构造函数本上添加的成员称为静态成员。只能由构造函数来访问
- 实例成员:在构造函数内部创建的对象成员称为实例成员,只能由实例化的对象来访问
构造函数原型 prototype
构造函数通过分配的函数是所有对象所共享的
js规定,每一个构造函数都有一个prototype属性,指向另一个对象,注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
我们可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法。
对象原型 _ _ proto _ _
对象身上系统自己添加了一个__proto__指向我们构造函数的原型对象prototype
-
_ _proto _ _对象原型和原型对象prototype是等价的
-
_ _ proto _ _对象原型的意义在于对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,他只是内部原型对象prototype
构造函数,实例,原型对象三者之间的关系:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Igyq7LNh-1630739439771)(C:\Users\11091\Desktop\1.png)]
原型链
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jgbtqRGj-1630739439774)(C:\Users\11091\Desktop\2.png)]
js的成员查找机制(规则)
1.当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
2.如果没有就查找它的原型(也就是__ proto __指向的prototype原型对象)
3.如果还没有就查找原型对象的原型(Object的原型对象)
4.以此类推一直找到Object为止(null)
原型对象this指向
原型对象函数里面的this指向的是实例对象
扩展内置对象
通过原型对象,对原来的内置对象进行扩展自定义的方法。比如给数组增加自定义求偶数和功能
注意:数组和字符内置对象不能给原型对象覆盖操作Array.prototype={},只能是Array.prototype.xxx=function(){}的方式
继承
ES6之前没有给我们提供extendes继承。我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承。
call()
调用这个函数,并且修改函数运行时this的指向
fun.call(thisArg,arg1,arg2…)
- thisArg:当前调用函数this的指向对象
- arg1,arg2:传递其他参数
作用:
- call()可以调用函数
- call()可以改变这个函数的this指向
借用构造函数继承父类型属性
核心原理:通过call()把父类型的this指向子类型的this,这样就可以实现子类型继承父类型的属性
ES5新增方法
- 数组方法
- 字符串方法
- 对象方法
数组方法
迭代方法:forEach(),map(),filter(),some(),every()
forEach()
语法:
array.forEach(function(currentValue,index,arr))
- currentValue:数组当前项的值
- index:数组当前项的索引
- arr:数组对象本身
filter()
语法:
arrary.filter(function(currentValue,index,arr))
- filter()方法创建的一个新数组,新数组中的元素是通过检查指定数组中符合的所有元素,主要用于筛选数组
- 注意它直接返回一个新数组
- currentValue:数组当前项的值
- index:数组当前项的索引
- arr:数组对象本身
some()
array.some(function(currentValue,index,arr))
- some()方法用于检测数组中的元素是否满足条件,通俗点,查找数组中是否满足条件的元素
- 注意它返回的是布尔值,如果查找到这个元素,就返回true,找不到就返回false
- 如果找到第一个满足条件的元素,则终止循环,不在继续查找
- currentValue:数组当前项的值
- index:数组当前项的索引
- arr:数组对象本身
字符串方法
trim()
trim()方法会从一个字符串的两端删除空白字符
语法:
str.trim()
trim()方法并不影响原字符串本身,它返回的是一个新的字符串
Object.keys()
Object.keys()用于获取对象自身所有的属性
语法:
Object.keys(obj)
- 效果类似for… in
- 返回一个由属性名组成的数组
Object.defineProperty()
Object.defineProperty()定义对象中新属性或修改原有的属性
Object.definerProperty(obj,prop,descriptor)
- obj:必需,目标对象
- prop:必需,需要定义或修改的属性的名字
- descriptor:必需,目标属性所拥有的特性
- descriptor以对象形式{}书写
- 1.value:设置属性值,默认为undefined
- 2.writable:值是否可以重写,true|false,默认false
- 3.enumerable:目标属性是否可以被枚举。true|false 默认是false
- 4.configurable:目标数属性是否可以被删除或是可以再次修改特性true|false,默认为false
函数进阶
函数定义和调用
函数的定义
1.函数声明方式function关键字(命名函数)
2.函数表达式(匿名函数)
3.new Function(‘参数1’,‘参数2’,‘函数体’)
- Function里面参数都必须是字符串的格式
- 第三种方式执行效率低,不方便书写,因此比较少用
- 所有函数都是Function的实例(对象)
- 函数也属于对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g4MCDoDm-1630739439775)(C:\Users\11091\Desktop\3.png)]
函数的调用
1.普通函数
2.对象方法
3.构造函数
4.绑定事件函数
5.定时器函数
6.立即执行函数
函数内的this指向
这些this的指向,是当我们调用函数的时候确定的,调用方式的不同决定了this的指向不同,一般指向我们的调用者
调用方式 | this指向 |
---|---|
普通函数调用 | window |
构造函数调用 | 实例对象 原型对象里面的方法也指向实例对象 |
对象方法调用 | 该方法所属对象 |
事件绑定方法 | 绑定事件对象 |
定时器对象 | window |
立即执行函数 | window |
改变函数内部this指向
js为我们专门提供了一些函数方法来帮助我们更好的处理函数内部this 的指向问题,常用的有bind(),call(),apply()三种方法
call方法
call()方法调用一个对象,简单理解为调用函数的方式,但是它可以改变函数的this指向。
语法:
fun.call(thisArg,arg1,arg2…)
- thisArg:当前调用函数this的指向对象
- arg1,arg2:传递其他参数
apple方法
apple()方法调用一个函数,简单理解为调用函数的方式,但是它可以改变函数的this指向
语法:
fun.apply(thisArg,[argsArray])
- thisArg:在fun函数运行时指定的this值
- argArray:传递的值,必须包含在数组里面
- 返回值就是函数的返回值,因为它就是调用函数
它的参数必须的数组(伪数组)
bind方法
bind()方法不会调用函数,但是能改变函数内部this指向
语法:
fun.bind(thisArg,arg1,arg2,…)
- thisArg:在fun函数运行时指定的this值
- arg1,arg2:传递的其他参数
- 返回由指定的this值和初始化参数改造的原函数拷贝
如果有的函数我们不需要立即调用,又想改变这个函数内部的this指向,只能由bind方法
call,apple,bind区别
1.call和apply可以调用函数,bind不能
2.call和apply传递的参数不一样,call传递参数aru1,aru2形式,apply必须数组形式[arg]
3.call经常用继承。apply经常和数组有关系,比如借助数学对象实现数组最大值最小值。bind不调用函数,但是还想改变this指向,比如改变定时器内部的this指向。
严格模式
JavaScript除了提供正常模式外,还提供了严格模式。ES5的严格模式是采用具有限制性JavaScript变体的一种方法,即在严格的条件下运行JS代码。
严格模式对正常JavaScript语义做了一些更改:
1.消除了JavaScript语法的一些不合理,不严谨之处,减少了一些怪异行为。
2.消除代码运行的一些不安全之处,保证代码运行的安全
3.提高了编译效率,增加运行速度
4.禁用了在ECMAscript的未来版本中可能会定义的一些语法,为未来版本的JavaScript做好铺垫,比如一些保留字如:class,enum,extend,export,import,super不能做变量名。
开启严格模式
严格模式可以运用到整个脚本或个别函数中,一次在使用时,我们可以将严格模式分为为脚本开启严格模式和为函数开启严格模式。
1.为脚本开启严格模式
为整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句‘use strict’;
2.为函数开启严格模式
要给某个函数开启严格模式,需要把‘use strict’;声明放在函数体所有语句之前。
严格模式的变化
1.变量规定
-
在正常模式中,如果一个变量没有声明赋值,默认是全局变量,严格模式中禁止这种用法,变量都是必须先用var命名清楚声明,然后再使用。
-
严禁删除已经声明变量,例如,delete x;语法是错误的
2.this指向问题
-
以前在全局作用域中的this指向window对象。在严格模式下全局作用域中函数中的this是undefined。
-
以前构造函数不加new也可以调用,当普通函数,this指向全局对象。在严格模式下,如果构造函数不加new调用,this就会报错。
-
定时器里面的this指向的还是window
-
事件,对象还是指向调用者
3.函数变化
- 函数不能有重名的参数
- 函数必须声明在顶层,新版本的JavaScript会引入‘块级作用域’(ES6中已经引入)。为了与新版本接轨,不允许在非函数的代码块内声明函数。
高阶函数
高阶函数是其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出。
闭包
变量作用域
变量根据作用域的不用分为两种:全局变量和局部变量
- 函数内部可以使用全局变量
- 函数外部不能使用函数内部变量
- 当函数执行完毕,本作用域内的局部变量会销毁
什么是闭包
闭包指的是有权访问另外一个函数作用域的变量函数。
简单来说就是,一个作用域可以访问另外一个函数内部的局部变量。
闭包的主要作用:延伸了变量的作用范围
递归
什么是递归
如果y一个函数在内部可以调用其本身,那么这个函数就是递归函数。
简单来说就是函数内部自己调用自己,这就是递归函数。
由于递归很容易发生‘栈溢出’错误,所以必须要加退出条件return。
浅拷贝和深拷贝
1.浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用
2.深拷贝拷贝多层,每一级别的数据都会拷贝
3.Object.assign(target,…sources) es6新增的方法可以浅拷贝
正则表达式
什么是正则表达式
正则表达式是用于匹配字符串中字符组合的模式,在js中,正则表达式也是对象。
正则表达式通常用来检索,替换那些符合某个模式的文本。或者用于过滤掉页面内容中的一些敏感词,或从字符串中获取我们想要的特定部分等。
特点:
1.灵活性,逻辑性,功能性非常强。
2.可以迅速地用极为简单的方式达到字符串的复杂控制。
如何在js中使用正则表达式
创建正则表达式
1.通过调用RegExp对象的构造函数创建
语法:
var 变量名 = new RegExp(/表达式/)
2.通过字面量创建
var 变量名 = /表达式/
检测正则表达式test
test()正则对象方法,用于检测字符串是否符合该规则,该对象会返回true或false,其参数是测试字符串。
语法:
regexObj.test(str)
1.regexObj 是写的正则表达式
2.str 我们要测试的文本
3.就是检测str文本是否符合我们写的正则表达式规范
正则表达式的组成
一个正则表达式可以由简单的字符构成,比如/abc/,也可以是简单和特殊字符的组合,比如/ab*c/.其中特殊字符也被称为元字符,在正则表达式中也是具有特殊意义的专用符号,如^,$,+等。
边界符
边界符 | 说明 |
---|---|
^ | 表示匹配行首文本(开头是谁) |
$ | 表示匹配行尾文本(结尾是谁) |
字符类
1.[ ]表示有一系列字符可供选择,只要匹配其中一个就可以了
2.[-]方括号内部 范围符-
3.[^]方括号内部 取反^
量词符
量词符用来设定某个模式出现的次数。
量词 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
预定义类
预定义类指的是某些常见模式的简写方式
预定义类 | 说明 |
---|---|
\d | 匹配0-9之间的任意数字,相当于[0-9] |
\D | 匹配除了0-9的字符,相当于[ ^0-9] |
\w | 匹配任意的字母,数字和下划线,相当于[A-Za-z0-9_] |
\W | 除多有字母,数组和下划线以为的字符,相当于[ ^A-Za-z0-9_] |
\s | 匹配空格(包括换行符,制表符,空格符等),相当于[\t\r\n\v\f] |
\S | 匹配非空格符,相当于[ ^\t\r\n\v\f] |
正则表达式的替换
replace()方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则表达式。
语法:
stringObject.replace(regexp/substr,replacement)
1.第一个参数:被替换的字符串或者正则表达式
2.第二个参数:替换为的字符串
3.返回值是一个替换完毕的新字符串
正则表达式参数
语法:
/表达式/[switch]
switch(也称为修饰符)按照什么样的模式来匹配。有三种值:
- g:全局匹配
- i:忽略大小写
- gi:全局匹配+忽略大小写
ES6
let
- let声明的变量只在所处于块级有效
注意:使用let关键字声明的变量才具有块级作用域
-
不存在变量提升
-
暂时性死区
const
作用:声明常量,常量就是值(内存地址)不能变化的量
-
具有块级作用域
-
声明常量必须赋值
-
常量赋值后,值不能修改
let,const,var的区别
1.使用var声明变量,其作用域为该语句所在的函数内
2.使用let声明的变量,其作用域为该语句所在的代码块内
3.使用const声明的是常量,在后面出现的代码中不能再修改该代码的值
var | let | const |
---|---|---|
函数级作用域 | 块级作用域 | 块级作用域 |
变量提升 | 不存在变量提升 | 不存在变量提升 |
值可以更改 | 值可以更改 | 值不能改 |
解构赋值
ES6中允许从数组中提取值,按照对应位置,对变量赋值,对象也可以实现解构。
数组解构
let[a,b,c] = [1,2,3];
如果解构不成功,变量的值为undefined
对象解构
let person = {name:‘zhangsan’,age = 18};
let{name , age} = person
箭头函数
语法:
() => {}
const fn = () => {}
特点
-
函数体中只有一句代码,且代码的执行结果就是返回值,可以省略大括号。
-
如果形参只有一个,可以省略小括号
-
箭头函数不绑定this关键字,箭头函数中的this,指向的是函数定义位置的上下文this
剩余参数
剩余参数语法允许我们将一个不定数量的参数表示为一个数组。
语法:
function sum (first,…args){
console.log(first);// 10
console.log(…args); //[20,30]
}
sum(10,20,30)
Array的扩展方法
扩展运算符(展开语法)
扩展运算符可以将数组或者对象转为逗号分隔的参数序列。
扩展运算符可以应用于合并数组。
方法一:
let ary1 = [1,2,3];
let ary2 = [3,4,5];
let ary3 = […ary1,…ary2];
方法二:
ary1.push(ary2);
将类数组或可遍历对象转换为真正的数组
方法一:
let divs = document.querySelectAll(‘div’);
divs = […divs]
方法二:
构造函数方法:Array.from()
Array.from(array,function(){});
array:要转化的数组
function:有几个数组,函数就调用多少次
实例方法:find()
用于查找出第一个符合条件的数组成员,如果没有找到就返回undefined
ary.find((item,index) => {})
item:为当前项
index:为当前索引
实例方法:findIndex()
用于找出第一个符合条件的数组成员的位置,如果没有找到返回-1
ary.findIndex((value,index) => {})
实例方法:includes()
表示某个数组是否包含给定的值,返回布尔值
例子:
[1,2,3].includes(2) //true
string的扩展方法
模板字符串
ES6新增的创建字符串的方式,使用反引号定义
语法:
let name = `zhangsan`
- 字符串中可以换行
- 在模板字符串中可以调用函数
实例方法:startsWith()和endsWith()
- startsWith:表示参数字符串是否在原字符串的头部,返回布尔值
- endsWith:表示参数字符串是否在原字符串的尾部,返回布尔值
例子:
let str = ‘hello world’;
str.startsWith(‘hello’); //true
str.endsWith(‘world’); //false
实例方法:repeat()
repeat方法表示将原字符串重复n次,返回一个新字符串
例子:
‘x’.repeat(3) //‘xxx’
‘hello’.repeat(2) //‘hellohello’
set数据结构
ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
set本身是一个构造函数,用来生成set数据结构
const s = new Set();
Set函数可以结构一个数组作为参数,用来初始化。
const set = new Set([1,2,3,4,4])
实例方法
- add(value):添加某个值,返回Set结构本身
- delete(value):删除某个值,返回一个布尔值,表示删除是否成功
- has(value):返回一个布尔值,表示该值是否为Set的成员
- clear():清除所有成员,没有返回值
例子:
const s = new Set();
s.add(1).add(2); 向set结构中添加值
s.delete(2); 删除set结构中的2值
s.has(1); 表示set结构中是否有1这个值,返回布尔值
s.clear(); 清除set结构中所有的值
遍历
Set结构的实例与数组一样,也拥有forEach方法,对于每个成员执行某种操作,没有返回值。
语法:
s.forEach(value => console.log(value))