一.JavaScript面向过程编程
1.定义:分析出解决问题需要的步骤,然后用函数这些步骤一步一步实现,使用时再调用
二.类和对象
定义:提取公共部分模块化
1.类:
//创建类class
class 类名 {
}
//利用类创建对象 new
new 类名()
1.类里有一个constructor函数,可以接收传递过来的参数,同时返回实例对象
2.constructor 只要new生成实例时会自动调用这个函数,如果我们不写,类也会自动生成new不能省略
3. 语法规范:类 与类名后面不需要加小括号,生成实例,类名后加小括号,构造函数不需要加function
2.类中添加方法
class 类名 {
constructor(a, b) {
}
方法名(){
方法逻辑
}
}
//利用类创建对象 new
new 类名()
1.我们类里面的函数不需要写function 多个函数方法用逗号分隔
3.类的继承
class 父类 {
constructor(a, b) {
}
方法名(){
方法逻辑
}
}
class 子类 extends 父类{
}
let a = new 子类()
a.方法 //使用
4.super使用
class 父类 {
constructor(a, b) {
this.a = a //使用必须加this
this.b = b
}
方法名(){
方法逻辑
}
}
class 子类 extends 父类{
constructor(a, b) {
super(a,b) //调用了父类中的构造函数 因为this的指向不同所以将子类的参数传给父类
}
}
let a = new 子类()
a.方法 //使用
1.继承中,如果实例化子类输出的一个方法,先看子类有没有之个方法,有就先执行子类的,就近原则
2.继承中,如果子类没有,就会去父类查找,如果有就执行父类的方法
3.如果两个都有一样的方法或者想调用父类的方法可以,super.方法()调用父类中的函数
重点:
(1).super调用必须再this之前调用
(2).再ES6中类没有变量的提升,所以先定义类,才能通过类的实例化对象
(3).类里面的共有的属性方法一定加this使用
(4).this的指向,谁调用指向谁
三.构造函数和原型
1.再ES6之前,对象不基于类创建,而是用构造函数的特殊函数来定义对象和它的特征
使用:
function 函数名 (a,b){ // a,b是形参
方法
}
let a = new 函数名(a,b) // a,b是实参
//new执行做的事情
1.在内存中创建一个新的空对象
2.让this指向这个新的对象
3.执行构造函数里的代码,给这个新的对象添加属性和方法
4.返回这个新的对象(不用写return)
// 实例成员就是构造函数内部this添加的成员 实例成员只能通过实例化对象来访问
//静态成员,在构造函数 本身添加的成员 如 函数名.变量 ='xxxx' (只能通过构造函数来访问)
2.构造函数的问题
1.存在内存浪费的问题,每构造一个函数就会在内存占有不同内存空间
2.构造函数的原型 prototype对象
我们可以把相同的方法,直接定义在prototype身上,这样所有的对象实例就可以共享
函数名.prototype.方法 = function(){
}
3.对象原型__proto__
1.对象都会有一个__proto__属性,指向构造函数的prototype原型对象,之所以我们可以使用构造函数prototype原型对象属性和方法,就是因为对象有__proto__原型存在
2.方法查找原则:首先看调用的对象本身是否有这个方法,有就执行,没有就会去prototype插值
3.__proto__对象原型的意义就是为对象的查找机制提供一个方向,在实际开发中不可以使用这个属性
4.构造函数中的 constructor
1.constructor 这个属性指回原来的构造函数
2.如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
5. 构成函数与实例、原型对象三者关系
1.构成函数与原型对象关系
构造函数 prototype指向 原型对象 原型对象的prototype.constructor也指向构造函数
2.构成函数与实例、原型对象关系 new一个实例对象,构造函数就会指向实例对象 实例对象中__proto__指向原型对象 ,原型对象中prototype.constructor再指回构造函数
3.原型对象中的__proto__指向object原型对象中的prototype,object构造函数 object.prototype再指向object原型对象,object原型对象中,object原型对象.constructor再指回object构造函数 object原型对象prototype.__proto__则为null
4.查找机制:
当访问的一个对象的属性或方法时,首先查找自身,自身没有就会找它的原型对象,(也就是__proto__ 指向prototype) 如果还没有找到就会查找原型对象的原型(object原型对象)类推直到为null为止
四.this指向的问题
1.在构造函数中,this指向的是对象对象实例
2.原型对象函数里的this指向的是实例对象
五.扩展内置对象
自定义方法:
Array.prototype.方法名 = function(){
//方法逻辑
}
六.数组遍历
1.forEach()
数组.forEach((value,index,array)=>{
//value 返回每个数组元素 index 数组元素的索引值 array数组本身 在forEach中 return true不会中止迭代
})
2.filter()
filter()方法创建一个新的数组,新数组的元素是通过检查指定数组中符合条件的所有元素,主要用于筛选数组
注意:它返回一个新数组
数组.filter((value,index,array)=>{
//value 数组当前项的值 index 数组元素的索引值 array数组本身
})
3.some()
数组.some((value,index,array)=>{
//value 数组当前项的值 index 数组元素的索引值 array数组本身 在some中 return true会中止迭代
})
1.some()方法用于检测数组元素是否满足指定条件,通俗点查找数组中是否满足条件的元素
2注意:它返回值是布尔值如果查找到元素,就返回ture,如果查找不到就返回flase
3.如果找到第一个满足条件的元素,则中止循环,不在继续查找
七.函数的定义方式
1.自定义方式(命名函数)
function 函数名 (){}
2.函数表达式(匿名函数)
let a = function (){}
3.利用new Function
let a =new Function('参数1','参数2','函数体') //字符串形式
//效率低不建议使用 函数也是对象 万物皆对象
八.函数调用的方式
//a是变量的名字,b是方法名字
function a (){}
//调用方式:
1.a()
2.a.call()
2.对象的方法
let a ={
b:function(){
}
}
a.b()
3.构造函数
function a (){}
new a()
4.绑定事件函数
a.onclick = function(){}
5.定时器函数
setInterval(()=>{}) //定时器自动调用
6.立即执行函数
(function a (){})() //自己调用
九.this的指向
1.这些this的指向,是当我们调用函数的时候确定的,调用方式的不同决定this的指向不同
2.一般指向我们的调用者
调用方式 | this的指向 |
普通函数调用 | window |
构造函数调用 | 实例对象,原型对象里面的方法也指向实例对象 |
对象方法的调用 | 该方法所属对象 |
事件绑定方法 | 绑定事件对象 |
定时器函数 | window |
立即执行函数 | window |
十.改变this指向
1.改变this指向 有三种方法 bind() call() apply()
2.使用:
1.call:
let a ={
}
function b (){}
b.call(a) // b是函数名 a是this要指向的
// call 第一个可以调用函数,第二个可以改变函数this的指向 call也可以实现继承
function a (){
}
function b (){
a.call(this ,a,b....) //调用了a 也改变了b的this的指向,指向了a
}
2.apply方法
apply()方法调用一个函数。简单理解为调用函数的方式,但是它可以改变函数的this指向
a.apply(thisArg ,[argsArray])
thisArg:在a 函数运行时指定的this值
argsArray:传递的值,必须在数组里面
返回值就是函数的返回值,因为它就是调用函数
apply的主要应用 比如说我们可以利用 apply借助数学内置对象求最大值
let a =[1,2,3,5,9]
Math.max.apply(Math,arr)
3.bind方法
bind()的方法不会调用函数。但是能改变函数this指向
let b = a.bind(thisArg , a , b......) //需要变量接收
1.thisArg :在a函数运行时指定this的值
2.a ,b:传递的其他参数
3.返回的原函数改变this之后产生的新函数
4.如果有道函数我们不需要立即调用,但想改变内部this的指向 如点击一个按钮一定时间内不可以点击
总结:
相同点:都可以改变函数this的指向
区别:
1.call 和apply 会调用函数,并且改变this的指向
2.call 和apply 传递的参数不易 ,call传参 a,b,c.....
apply必须数组[1,2,3,4]
3.bind 不会调用函数,可以改变函数内部this的指向
主要应用场景:
1.call经常做继承
2.apply经常跟数组有关系,比如借助与数学对象实例求最大最小值
3.bind 不调用函数,但还是想改变this指向,比如改变定时器的指向
十一.严格模式
更改:
1.消除了js语法的一些不合理,不严谨之处,减少了一些怪异行为 比如可以先使用变量,再声明这种怪异
2.消除了代码运行的一些不安全之处,保证代码安全运行
3.提高代码编译的速率,加速运行速度
4.禁用了未来版本中可能会定义的一些语法 比如calss,enum,export ........不能做变量名
使用:
严格模式可以应用到整个脚本或个别函数中。因此在使用时,我们可以将严格模式 分为脚本开启严格模式 或 为函数开启严格模式
1.为脚本开启严格模式
需要在所有语句之前放一个特点语句 'use strict' 下面的代码就会按严格模式执行
2.为函数开启严格模式
function a(){
'use strict' //为函数a开启严格模式
}
2.严格模式发生的变化
1.变量名先声明再使用
2.严禁删除声明过的变量
3.严格模式下全局作用域中函数中this的指向undefined
4.如果构造函数不加new调用,this就会报错 加了就会指向实例对象
5.严格模式下函数里面的参数不允许重名
十二.高阶函数
1.函数也是一种数据类型,同样可以作为参数,传递给另一个参数使用。最典型的就是作为回调函数
2.高阶函数时对其他汉书进行操作的函数,他接收函数作为参数或将函数作为返回值输出
十三.闭包
1.定义:闭包指有权访问另一个函数作用域中变量的函数。 一个作用域可以访问另一个函数中的变量
如:
function a(){
let b = 10
function c (){
console.log(b); //可以得出知道b的值
}
c()
}
a()
1.外部函数访问内部变量
如:
function a(){
let b = 10
function c (){
console.log(b);
}
return c
}
let d = a()
d() //可以得出知道b的值
十四.递归
定义:一个函数内部可以调用其本身,那么这个函数就是递归函数 容易造成死循环,必须在里面添加退出条件
如:
let b = 0
function a(){
console.log(1);
if (b === 3) {
return
}
b++
a()
}
a()
十五.浅拷贝与深拷贝
1.浅拷贝只能拷贝一层,更深层次只拷贝了地址进行引用
2.深拷贝多层,每一层级别的数据都会拷贝
深拷贝的封装:
function deepCopy(newobj,oldobj){
for(let k in oldobj){
let item = oldobj[k]
if (item instanceof Array ) {
newobj[k] =[]
deepCopy(newobj[k],item)
}else if( item instanceof Object){
newobj[k] ={}
deepCopy(newobj[k],item)
}else{
newobj[k] = item
}
}
}
deepCopy(a,b)