面对对象
什么是面向对象
面对对象并不是一种语法,也不是一个新的语言,它是JS完成需求的一种思想
面向对象与面向过程的区别
面向过程:
注重的是过程,每一步写的详细,一步步代码按顺序完成
存在问题:
1.每一个功能相互影响
2.轮播图举例,若有多个轮播图,则js需要书写多遍
面向对象:
注重的是得到一个对象,这个对象就是我们的需求 比如这个对象就是一个轮播图
拿生活中的例子作比较如
我想吃一碗面
面向过程的操作流程
1.准备面粉
2.准备水
3.和面
4.切面
5.烧水
6.煮面
7.吃面
而面向对象的流程是
1.找一个面馆
2.下单
3.吃面
创造对象的方式
1.字面量方式
let obj = {
name:'qf111'
age:11
}
let obj1 = {
name:'qf222'
age:22
}
这种方式在想创建多个对象时,需要多次创造,所以这种方法不适合批量创建
内置构造函数
let obj = nwe Object({name:'qf111',age:11})
let obj1 = nwe Object({name:'qf222',age:22})
这种方式在想创建多个对象时,需要多次创造,所以这种方法不适合批量创建
工厂函数的方式
就是创建一个函数,但函数内部可以创建一个对象,我们把这种函数叫做工厂函数
创造一个函数
function createObj(num){
1.手动创建一个对象
const obj = {}
2.手动给对象添加属性
obj.name = 'qf001'
obj.age = num
3.手动返回对象
return obj
}
let obj1 = createObj(18) //表示创建了一个age为18的对象
let obj2 = createObj(24) //表示创建了一个age为24的对象
利用这个方法可以只书写一个对象,从而创建多个对象
自定义构造函数
构造函数:本质上就是一个普通函数,如果在调用的时候,在前边加上关键字 new , 我们就叫构造函数
function CreateObj1(num ,a){
//1.自动创造一个对象
//2.手动给对象添加属性(因为构造函数自动创造的对象通过 this 访问所以构造函数添加属性需要通过 this 添加)
this.name = a
this.age = num
//3.自动返回对象
}
//构造函数调用时要与 new 连用
let obj3 = new CreateObj1(11 , 'ab123')
let obj = new CreateObj1(22,'ab456')
利用这个方法可以只书写一个对象,从而创建多个对象
注意:自定义构造函数书写要求:
1.构造函数的函数名首字母大写(建议,非强制,目的是与普通函数区分开)
2.构造函数内不要书写return
如果return的 是一个基本数据类型,写了也没用
如果return的 是一个引用(复杂)类型,写了会导致构造函数失效
3.构造函数调用时,必须和 new 关键字连用 如果不连用,也可以调用,但构造函数会失效
4.构造函数内部内部的 this
当一个函数和 new 关键字连用的时候,那么我们说这个函数是构造函数然后这个函数内部的 this 指向本次调用被自动创建出来的哪个对象1
5.构造函数不能使用箭头函数
因为箭头函数没有 this 但因为构造函数自动创造的对象通过 this 访问,所以构造函数添加属性需要通过 this 添加
构造函数的缺点:
构造函数内部如果有这个引用数据类型,如函数
在多次调用构造函数时,每一次调用函数时,都会重新创建一个函数,这样必然会造成内存空间的浪费
例
function CreateObj1(name , age){
this.name = name
this.age = age
this.fn = function() {
console.log('我是一个函数')
}
}
let obj3 = new CreateObj1(11 , '123466')
console.log(obj3)
let obj4 = new CreateObj1(12 , '1225')
console.log(obj4)
上述代码的运行流程
第一次运行
第一次调用CreateObj1构造函数+自动创建一个对象
1。添加一个属性name,值为形参name
2添加一个属性age,值为形参age
3。添加一个属性a,值为一个囵定的字符串4。添加一个属性fn,值为一个函数,这时的函数是我们在这个函数内部定义的一个函数,假设地址为GD001
自动返回一个对象
第二次运行
第二次调用CreateObj1构造函数+自动创建一个对象
1。添加一个属性name,值为形参name
2添加一个属性age,值为形参age
3。添加一个属性a,值为一个囵定的字符串4。添加一个属性fn,值为一个函数,这时的函数是我们在这个函数内部定义的一个函数,假设地址为GD002
自动返回一个对象
结论
由上述代码可知每次调用CreateObj1构造函数时,都会重新创建一个新的函数,但每次创建的函数内容都是相同的,只不过内部定义的地址不一样,这样就会造成内存空间的浪费.
解决方法:
将内部的引用数据类型(如函数)提取出来,放到构造函数外部,然后在构造函数内部调用这个引用数据类型(如函数)
如
function fn() {
console.log('我是一个函数')
}
function CreateObj1(name , age){
this.name = name
this.age = age
this.fn = fn
}
let obj1 = new CreateObj1('abc123' , 111)
这样在每次调用CreateObj1构造函数时,它内部就会调用函数fn()而不是重新创建函数fn()
原型
什么是原型
1.每一个函数天生拥有一个属性 prototype 它的属性值是一个对象 我们通常把这个对象叫做这个函数的原型(空间|对象)
2.这个对象中有一个属性 叫做 constructor ,这个属性表示的就是当前这个原型是哪个函数的原型
3.每一个对象天生拥有一个属性__proto__(前后都是 两个 下划线) 这个属性指向自己构造函数的原型
向函数原型上添加属性 函数.prototype.属性 = 属性值
原型的作用
把构造函数中公共方法提取出来,放到原型中
为什么这么做
构造函数的原型上的方法或者属性。在每一个实例化对象中都能正常访问
对象访问原则:
访问对象的某一属性时,会先在对象本身去查找,找到就直接用 ,如果没找到 那么会去对象的 __proto__ 中查找如果没有找到 , 那么会去这个对象(原型)__proto__ 查找直到找到js的顶层对象 Object.prototype , 如果没找到就不找了
注意:
在 JS 中, 只要是一个函数, 那么就属于构造函数 Function 的实例化对象
在 JS 中, 只要是一个对象, 那么就属于构造函数 Object 的实例化对象
案例:
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayHi = function () {
console.log('你好~~~')
}
const p1 = new Person('QF001', 18)
console.log(fn.prototype.__proto__)
1. p1 的 __proto__ 指向谁
proto 指向自己构造函数的原型 所以 相当于 指向了 Person.prototype
p1.__proto__ === Person.prototype
2. Person 的 __proto__ 指向谁
Person 是一个构造函数, 构造函数本质上就是一个函数而已
在 JS 中, 只要是一个函数, 那么就属于构造函数 Function 的实例化对象
__proto__ 指向自己构造函数的原型
所以相当于 指向了 Function.prototype
Person.__proto__ === Function.prototype
3. Person.prototype 的 __proto__ 指向谁
Person.prototype 是 Person 构造函数的原型, 本质上就是一个对象而已
在 JS 中, 只要是一个对象, 那么就属于构造函数 Object 的实例化对象
__proto__ 指向自己构造函数的原型
所以相当于指向了 Object.prototype
Person.prototype.__proto__ === Object.prototype
4. Function 的 __proto__ 指向谁
Function 是一个构造函数, 构造函数本质上就是一个函数而已
在 JS 中, 只要是一个函数, 那么就属于构造函数 Function 的实例化对象
__proto__ 指向自己构造函数的原型
所以相当于 指向了 Function.prototype
Function.__proto__ === Function.prototype
5. Function.prototype 的 __proto__ 指向谁
Function.prototype 是 Function 构造函数的原型, 本质上就是一个对象而已
在 JS 中, 只要是一个对象, 那么就属于构造函数 Object 的实例化对象
__proto__ 指向自己构造函数的原型
所以相当于指向了 Object.prototype
Function.prototype.__proto__ === Object.prototype
6. Object 的 __proto__ 指向谁
Object 是一个构造函数, 构造函数本质上就是一个函数而已
在 JS 中, 只要是一个函数, 那么就属于构造函数 Function 的实例化对象
__proto__ 指向自己构造函数的原型
所以相当于 指向了 Function.prototype
Object.__proto__ === Function.prototype
7. Object.prototype 的 __proto__ 指向谁
因为 Object.prototype 是 JS 的顶层对象, 再往上就没有了, 所以这个值为 null