js面向对象编程

从面向过程开发到面向对象开发,是个思维的重大转变,当真正理解了面向对象编程后,对于日常的开发就会有一个质的飞跃。

一. 面向过程与面向对象的区别

1.概念

1.面向过程
是一种以过程为中心的编程思想,面对问题,罗列出解决问题的步骤,然后按步骤一步步去实现
比如:蛋炒饭的制作,蛋和饭都混在一起,省事省力就能做出一盘美味可口的炒饭

2.面向对象
是以对象为核心,不需要关心程序内部的实现。解决问题时候,把问题抽象成对象,分析解决问题需要哪些对象,然后给对象里赋值一些方法和属性,让对象执行自己的方法,解决问题。
比如:盖浇饭的制作,把一份完整的饭拆分成米饭和菜,通过组合不同的米粉和菜能满足不同客户定制化的需求

2.区别

1.面向过程:
优点:性能较高
缺点:耦合性强,不易维护,扩展和复用

2.面向对象
优点:程序间低耦合,易于维护,扩展和复用,灵活配置
缺点:性能低于对象过程,因为面对对象需要实力化,比较消耗性能

二. 面向对象的特性

1.三大原则:封装,继承,多态

1.封装

1.概念:也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
封装可以给用户提供一个函数,函数里的方法属性不对外暴漏,而能实现用户想要实现的功能
好处:将变化隔离,程序便于使用,易于复用,安全性较高,
原则:隐藏不需要对外暴漏的属性,仅提供公共访问方式

2.继承

1.概念:让一个类拥有另一个类的属性和方法
2.创建对象的方式
1.对象字面量
const obj = {}
2.构造函数
const = new Object()
3.Object.create()

用这种方式创建一个空对象 Object.create(Object.prototype),类似 {},注意,Object.create(null)可以创建对象,但是这个对象没有原型,不会继承任何东西,连toString()方法都没有哦。

const obj1 = {name:'111'}
const obj2 = Object.create(obj1) 
console.log(obj2.name) // 111

2.继承的方式
1.原型链

1.1 基本思想:利用原型,让一个引用类型继承另一个引用类型的属性和方法

// 父函数
function Parent(){
  this.value1 = true
}
Parent.prototype.getParentValue = function(){
 return this.value1
}

// 子类函数
function Child(){
  this.value2 = false
}
// 这句话是最关键的。child 继承了parent的原型
Child.prototype = new Parent()

Child.prototype.getChildvalue = function(){
 return this.value2
}
const cc = new Child()
console.log(cc.getParentValue()) // true 这个是继承的父类的方法
console.log(cc.getChildvalue()) // false 自己的方法

1.2 缺点:
缺点1.实例共享引用类型,
原型链继承主要的问题是包含引用类型值的原型, 因为包含引用类型值的原型属性会被所有的实例共享, 而在通过原型来实现继承的时候, 原型实际变成了另外一个函数的实例(这里边就有可能存在引用类型)

缺点2.在创建 Child 的子类的时候,无法像继承元素传递参数

所以综上,这种继承方式少用

2.构造函数
3.组合继承
4.原型式继承
5.寄生式模式
6.寄生组合试继承

3.多态

三. 对象的特性

1.对象的方法

1.1 属性的简洁方

const name='zy'
const obj = {name:name}
// 简写
const obj1 ={name} 
console.log('obj1',obj1) // obj1: {name:'zy'}

1.2 属性名表达式

const obj = {name:'zy'}
obj.name // 'zy'
obj['name'] // zy

1.3 属性的可枚举和遍历 ***

1.可枚举性
1. Object.getOwnPropertyDescriptor

每个属性都有一个Descriptor,方法是 Object.getOwnPropertyDescriptor(对象,属性名)

const obj = {name:'zy'}
console.log(Object.getOwnPropertyDescriptor(obj,'name'))
//  {
//    configurable: true, // 是否可以删除
//    enumerable: true, // 是否可以枚举
//    value: zy,
//    writable: true, // 是否可以编辑
//  }
getOwnPropertydescriptor
2.Object.getOwnPropertyDescriptors

若要看整个对象的描述,可以用Object.getOwnPropertyDescriptors(obj)

const obj = {name:'zy',age:'1'}
Object.getOwnPropertyDescriptors(obj)
// {
// age: {
//  configurable: true,
//  enumerable: true,
//  value: "1",
//  writable: true,
//}
//name: {
//  configurable: true,
//  enumerable: true,
//  value: "zy",
//  writable: true,
//}
//}
Object.getOwnPropertyDescriptors
3.Object.defineProperty

这里可以看到通过对象字面量直接创建的属性默认是可以遍历,可以更改和可以删除的,下面我们通过另一种方法创建对象的属性,Object.defineProperty

const obj = {}
Object.defineProperty(obj,'name',{
  value:'zy'
})
console.log(obj) // {name:'zy}
console.log(Object.getOwnPropertyDescriptor(obj,'name'))
// {
// configurable: false
// enumerable: false
// value: 12
// writable: false,
// }
Object.defineProtery

通过对比可以发现,直接字面量创建的对象属性默认都是可以编辑遍历和删除的,而通过Object.definePorperty创建的对象属性则默认是不可编辑遍历和删除的。

扩展下 defineProperty的相关知识
configurable 是配置属性是否可以删除,默认true
enumerable 是配置属性是否可以枚举,默认true
writable 是配置属性是否可以编辑,默认true

4.Object.preventExtensions

Object.preventExtensions()方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。
1.通过对象字面量新增属性,静默的失败

const obj = {name:'zy'}
Object.preventExtensions(obj)
obj.age = '1' //通过对象这种方式添加属性已经添加不上去了
console.log(obj) // {name:'zy'}

2.通过defineProperty给对象添加属性则直接报错

const obj = {name:'zy'}
Object.preventExtensions(obj)
Object.defineProperty(obj,'age',{value:'1'})
console.log(obj) 
// Uncaught TypeError: Cannot define property age, object is not extensible
5.Object.isExtensible()

Object.isExtensible() 方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。

const obj = {name:'zy'}
Object.isExtensible(obj) // true
Object.preventExtensions(obj)
Object.isExtensible(obj) //false
6.Object.seal()

Object.seal()方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。

7.Object.freeze()

方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。

2.遍历

对象的遍历总共有5种方式

1.for...in

for in可以遍历对象自身和继承的属性,不含不可枚举和Symbol

补充个知识点:in 操作符 和 hasOwnProperty
in和hasOwnProperty的区别
in 可以检查出自身和原型上的所有属性
hasOwnProperty 判断的自身的属性
通过这两个属性可以区分是哪些属性是自身的,哪些属性是原型上的

const obj = {
 name:'zy',
 age:'1',
}
// in 操作符
console.log('name' in obj) // true 自身的属性
console.log('age' in obj) // true 自身的属性
console.log('wdith' in obj) // false 不存在这个属性
console.log('toString' in obj) // true 原型上的方法

// hasOwnProperty
console.log(Object.hasOwnProperty('name')) // true 自身的属性
console.log(Object.hasOwnProperty('toString')) // false 不是自身的属性和方法

// 通过in 和 hasOwnProperty组合区分出原型的方法属性
in 返回true hasOwnProperty 返回false的就是原型上的方法
function isPropertyItem(item,obj){
  return item in obj  && !Object.hasOwnProperty(item)  
}
2.Object.keys(obj)

Object.keys,返回一个数组,可遍历对象自身属性,不含不可枚举和Symbol

3.Object.getOwnpropertyNames(obj)

getOwnpropertyNames ,返回数组,获取自身所有属性,包含不可枚举,不含Symbol

4.Object.getOwnPropertySymbols(obj)

Object.getOwnPropertySymbols 返回数组,获取自身所有Symbol属性

5.Reflect.ownKeys(obj)

Reflect.ownKeys返回一个数组,获取自身所有属性,包含 不可枚举和Symbol

你可能感兴趣的:(js面向对象编程)