JavaScript--进阶

122 阅读10分钟

一、面向对象编程

所谓面向对象就是,想做一件事,自己做不到,就去找能够实现这个功能的对象,调用它的方法(传递参数,遵守方法规则)

 

面向对象编程,是一种编程开发思想

每一个对象都是功能中心,具有明确分工,可以完成接受信息,处理数据,发出信息等任务。

因此,面向对象编程具有灵活,代码可复用,高度模块化等特点,容易维护和开发,比起传统的面向过程编程,更适合多人合作的大型软件项目

 

面向过程就是,先做什么,然后做什么,再做什么,关注点在于解决问题的过程;

面向对象就是,先找一个对象,让它去做这个事情,关注点在找到能解决问题的对象上。

 

面向对象是面向过程的封装

 

面向对象的特性:

封装性:

将功能的具体实现,全部封装到对象的内部,外界使用对象时,只需要关注对象提供的方法如何使用,而不需要关心对象的内部具体实现

继承性:

在JS中,继承就是一个对象没有的属性和方法,另外一个对象由,就拿过来用,实现继承

多态性:

JS是弱类型语言,不支持多态

 

二、构造函数

是一个函数,可以定义形参,接收实参

 

作用:进行对象的初始化(为对象添加成员)

 

在JS中,定义一个构造函数,就相当于自定义一种类型

 

语法:

定义和普通函数差不多,一般首字母是大写

function Student(形参1,形参2,...) {

this.键(key)= 值

}

  image.png

 

构造函数中的this指向调用这个构造函数时new所创建的对象

 

构造函数的调用:

要配合new关键字调用,没有new相当于是调用普通函数

返回的是当前创建的对象

 

new做了什么:

1. 创建一个对象

2. 将对象的引用赋值给构造函数中的this

3. 调用构造函数为this添加成员

4. 将this的引用返回

 

注意:不要手动返回值,如果返回的是基本类型的值,会被忽略,如果返回的是一个引用类型的值,则会替换之前创建的对象

 

继承:

实现继承:获取到构造函数原型中的成员,添加到自身

一个对象所指向的原型是创建这个对象时,构造函数所指向的原型

 

原型是一个对象,那么可以遍历这个对象,先判断自身是否有同名的键,如果有就跳过,没有就添加

image.png  

作用域:

全局变量

局部变量(只有方法体内可以使用)

 

函数内部可以使用函数外部声明的变量,全部变量在任何地方都可以访问到

 

词法作用域:

函数一旦声明,作用域就确定好了,函数的作用域只与声明有关,与在哪里调用无关

 

let、const、var:

 

能使用const就使用const

不能使用const就使用let

不要使用var

 

Let:

会有块级(大括号:{ })作用域,

作用域就是声明这个let变量的{ },

有效作用域从let开始到他所在的 }结束

不会进行声明的提升,一定要先声明赋值再使用

 

Var:

没有块级作用域的概念

会进行声明的提升,将声明提升到当前作用域的最前面

 

Conts:

定义常量(不能修改的变量),一般在模块中的成员都是常量

基本特性和let一样

声明赋值之后不能再修改

只能在声明的同时进行赋值

常量名称一般全部都是大写

 

 

三、原型

系统会为构造函数默认关联一个对象(只要定义了一个构造函数,就会默认有一个对象与之关联),这个对象就是构造函数的原型

 

于之前对象的操作方式一样:添加成员,删除成员,遍历

 

通过构造函数.prototype访问原型对象

 

只有这个构造函数所创建的对象,才可以去访问该构造函数的原型

  image.png

特性:

1. 通过构造函数的prototype属性访问原型的对象

2. 因为原型是一个对象,所以可以像操作普通对象一样操作原型

 

操作:

1. 在原型中添加成员

成员一般是行为(方法)

image.png  

2. 访问原型中的成员

只要是当前构造函数所创建的对象,就能直接访问这个构造函数原型中的成员,也只有这个构造函数的对象可以访问

image.png  

 

所有的构造函数都是function的实例(Array 和 Person 和 Date 等都是 Function的实例)

 

 

原型链:

 

任何一个对象,都有原型对象,原型对象本身又是一个对象,所以原型对象也有自己的原型对象,这样一环扣一环就形参了一个链式结构

image.png  

 

 

属性查找原则:

如何获取:

1. 先找自身

2. 如果自身没有就根据__proto__对应的原型去查找

3. 如果没有就找到object.prototype,如果都没有,就是报错

 

 

四、this和函数的四种调用模式

1. 函数调用模式

如果一个函数不是一个对象的属性时,就是被当做成一个函数来进行调用的,此时this指向了window

2. 方法调用模式

当一个函数被保存为对象的一个属性时,称之为一个方法,当一个方法被低啊用时,this被绑定到当前的对象

3. 构造函数调用模式

如果函数是通过new关键字进行调用的,此时this被绑定到创建出来的新对象上

4. 上下文低啊用模式(借用方法模式)

(1) call

call方法可以调用一个函数,并且可以指定这个函数的this指向

image.png

(2) apply

apply()方法接收的是一个包含多个参数的数组,而call()方法接收的是若干参数的列表

image.png

(3) bind方法

bind()方法创建一个新的函数,可以绑定新的函数的this指向

image.png

 

This的指向:

单独使用,this指向全局对象

函数中的this指向全局对象

在函数内部,this的指向在函数定义的时候是不能确定的,只有函数执行的时候才能确定

在方法中,this指向调用该方法的对象

  image.png

 

五、箭头函数

语法:

let  变量 = (参数) =>  {   }

image.png

 

箭头函数是不能单独使用的

 

注:

1. 如果函数体只有一句,那么可以省略{},同时默认返回函数体的结构,不能写return

let  变量 = (参数) =>  ...

image.png

2.如果只有一个参数,()可以省略

let 变量 =  参数  => 参数 + 10

image.png  

4. 如果没有参数,()不能省略

let 变量 =  ()  =>  ...

 

特性:

箭头函数的this是确定的,并且永远不变

箭头函数中的this指向创建这个箭头函数所在对象的上下文

 

六、Es6  class

JavaScript 语言中,生成实例对象的传统方法是通过构造函数,es6的class 的出现 基本上可以替代了es5的构造函数和原型,使之代码结构上更加简洁。

 

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

 

语法:class Person {

要添加构造器,来为对象进行成员的初始化

constructor(参数1,参数2,...){

this.键(key)= 值

}

Say(){

}在原型中添加成员,可以直接写函数

}

 

Class继承:class可以通过extends关键字实现继承

语法:

Class 子类 extends 父类

有了extends关键字,子类默认就会继承父类的所有原型中的成员,同时,默认也会继承父类的构造器

class  Student  extends  Person {

Constructor ( name ,age , gender) {

使用this之前必须调用父类构造器,同时让父类构造器中的this为当前子类对象,所以可以通过super关键字来调用父类构造器来构建子类对象的成员

super (name , age)←这句就相当于了(this.name = name,  this.age=age)

 

This.gender = geender

}

}

image.png

image.png

 

七、递归函数

函数内部直接或者间接的调用自己

image.png  

要求:

1. 函数自己直接或间接的调用自己

2. 要有结束条件

image.png   image.png

 

斐波那契数列

image.png  

八、简便的方法

8.1函数参数默认值

定义函数的同时,可以给形参一个默认值,默认值参数一般在参数列表的最后

 

如果电泳函数的时候没有传递参数,则使用默认值

如果调用函数时传递了参数,则使用传递的参数

Function init(a,b){  }

Function init(b, a = ‘ 有德 ’ ) {  }

 

8.2对象简写

在定义对象的时候,如果属性名和变量名一致,那么可以实现简写

 

Let name =  ‘ 有德 ’

Let age = 20

Let obj = {

‘ name ‘ = name ,

‘ age ‘  = age

}

 

键值同名简写:

Let obj = {

name,

age

}

 

8.3解构

从对象或者数组中提取元素

 

数组结构需要将接收值的变量使用 [ ]包裹

Let  arr =  [ 1 , 23 , 45 , 78 ]

Let  [ a , b , c , d ]  =  arr

a = 1  b = 23  c = 45  d = 78

 

注:用 ... 表示剩余的元素,必须放在数组的最后,不能结构出中间的元素

 

对象结构同理

Let  obj = { name : ‘ 有德 ’ ,age :20 , gender : ‘ 男 ’}

Let  { name , age} = obj

Name = ‘ 有德 ’  age = 20

 

注:对象解构的时候,只能解构出对象中已有属性,如果结构的名称在对象中不存,则返回undefined

如果在结构的时候,已有同名变量,可以设置别名,后续使用,是使用别名

 

Let name = ‘ 马沙 ’ 

Let  age = 20

Let  obj = { name : ‘ 有德 ’ ,age :20 , gender : ‘ 男 ’}

Let  { name:newName , age:newAge } = obj

newName  = ‘ 有德 ’  newAge = 20

 

如果对象里的成员是对象,也可以二次结构

 

Let  obj = { name : ‘ 有德 ’ ,age :20 , gender : ‘ 男 ’ computer : {

gundam: ‘ 隆巴纳 ’

}

}

Let { computer { gundam } } = obj

 

 

获取数组中的元素

image.png

元素交换顺序

image.png

获取对象中的属性

image.png

 

8.4拓展(展开)运算符 ||剩余运算符

通过 ... 符号来获取剩下的参数

image.png

image.png

image.png

 

九、Set

不会有重复元素的对象(数组)

image.png  

 

十、闭包

在JavaScript中,在函数中可以嵌套定义另外一个函数时,如果内部的函数引用了外部的函数的变量,则产生闭包。

闭包就是一个具有封闭的对外不公外的包裹结构或空间

 

产生闭包的条件:

当内部函数访问了外部函数的变量的时候,就会形成闭包

1. 函数内部声明函数——嵌套函数——内部函数

2. 内部声明的函数使用了外部声明的成员

3. 返回了内部函数,外面进行接收,通过这个函数使用内部成员

 

作用:

保护私有变量不被修改

 

 

 

斐波那契数列优化

缓存:数据的缓冲区,当要读取数据时,先从缓冲中获取数据,如果找到,直接获取,如果找不到,重新去请求数据

 

计算斐波那契数列,会有很大的性能问题,因为重复的计算了很多次,使用缓存来解决性能问题

步骤:

如果要获取数据,先查询缓存,如果有就直接使用,如果没有,就进行计算,斐波那契并且将计算后的结果放到缓存中,方便下次使用

  image.png

使用缓存,需要保证缓存的数据安全,不能被别人修改,需使用闭包来实现缓存的私有化

image.png