ES6-面向对象编程思想
概念
面向对象的思想和类紧密相关。
把客观对象抽象成属性数据和对数据的相关操作,进而隐藏内部细节和不相关的信息,把同一个类型的客观对象进行总结,抽象出属性和属性的操作,封装成类。允许类通过继承实现属性和操作的共享。
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
ES5实现面向对象
function Person(name) {
//构造函数⾥⾯的⽅法和属性
this.name = name;
this.getName = function() {
console.log(this.name);
};
this.setName = function(name) {
this.name = name;
}
}
let p = new Person("张三");
p.getName(); //张三
p.setName("李四");
p.getName(); //李四
function Person(name) {
this.name = name
};
Person.prototype.say = function() {
console.log('hello',this.name)
}
var per = new Person('章三');
per.say()
ES6实现面对对象
首先你要知道js里面没有类的概念 ,所谓的面向对象都是模拟出来的。类的本质其实还是⼀个函数,我们也可以简单的认为,类就是函数的另外⼀种写法。ES6里边的类实际上都是函数的语法糖。
class Person {
//类的构造函数,实例化的时候执⾏new的时候执⾏
constructor(name) {
this.name = name;
};
getName() {
console.log(this.name);
};
setName(name) {
this.name = name
}
}
let p = new Preson('张三')
p.getName(); //张三
p.setName('李四');
p.getName(); //李四
面向对象三个基本特征是:封装、继承、多态。
封装
在说封装之先了解一下封装到底是什么?
我们平时所⽤的⽅法和类都是⼀种封装,当我们在项⽬开发中, 遇到⼀段功能的代码在好多地⽅重复使⽤的时候,我们可以把他单独封装成⼀个⽅法,这样在我们需要使⽤的地⽅直接调⽤就可以了。
在面向对象里边,封装通常是指创建一个对象集中保存一个事物的属性与功能。将对象运行所需的资源封装在一段程序中——基本上就是是方法和数据。
如果更进一步,对于封装的理解,可能还有一个层面就是抽离,首先你要清楚在一段代码中你应该抽离那些属性方法,有了这些为基础才能更好的做好封装。封装无非就是其属性和方法封装。
类:封装对象的属性和行为
方法:封装具体逻辑功能
访问封装:访问修饰封装无非就是对其访问权限进行封装
class Employees {
constructor(name,age) {
this.name = name;
this.age = age;
}
getInfo() {
let {name,age} = this;
return {name,age};
};
static seyHi() {
console.log("Hi");
}
}
let lisi = new Employees("Aaron",18);
lisi.seyHi(); //lisi.seyHi is not a function
lisi.getInfo(); //{name: "Aaron", age: 18}
Employees.seyHi() //Hi1234567891011121314151612345678910111213141516
分析:在Employees中抽出的公共属性有name,age,公共方法有getInfo,seyHi,然而getInfo与seyHi所不同的是seyHi使用了static修饰符,改变其为静态方法,seyHi只属于Employees这个类。然而getInfo方法则是属于实例的。这里使用了static对seyHi方法对其进行了访问权限的封装。
Promise.then() //Promise.then is not a function
let p1 = new Promise(() => {})
p1.then(); //Promise {<pending>}
Promise.all([1]) //Promise {<resolved>: Array(1)}123123
从上面的代码中可以看出Promise也使用了static对其方法的访问权限进行了封装。
继承
继承是指父亲的成员,孩子无需重复创建就可直接使用。继承实现了代码重用,节约内存。
class Father {
constructor(name) {
this.name = name;
};
//实例方法,通过实例对象调⽤
getName() {
console.log(this.name);
};
// 静态⽅法不会被继承,并且是通过类名去调⽤的
static hitXiaoMing() {
console.log("打⼩明");
}
};
class Son extends Father {
constructor(name, age) {
//实例化⼦类的时候把⼦类的数据传给⽗类(这里的super必须有,super里的参数是所继承的⽗类实例化所需要的数据)
super(name);
this.age = age;
}
}
var DaMing = new Father('⼤明');
Father.hitXiaoMing(); //打⼩明
DaMing.getName(); //⼤明
var XiaoMing = new Son('⼩明',15);
XiaoMing.getName() //⼩明
继承可以使得子类具有父类的各种的公有属性和公有方法。而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。
子类继承父类后,子类具有父类属性和方法,然而也同样具备自己所独有的属性和方法,也就是说,子类的功能要比父类多或相同,不会比父类少。
class Employees {
constructor(name) {
this.name = name;
};
getName() {
console.log(this.name)
};
static seyHi() {
console.log("Hi");
};
};
class Java extends Employees {
constructor(name) {
super(name);
};
work() {
console.log("做后台工作");
}
}
let java = new Java("Aaron");
java.getName();
java.work();
java.seyHi() //java.seyHi is not a function
从上面的例子可以看出继承不会继承父类的静态方法,只会继承父类的公有属性与方法,这一点需要注意。子类继承之后既拥有了getName方法,同样也拥有自己的worker方法。
多态
按字面的意思就是“多种状态”,说白了多态就是相同的事物,一个接口,多种实现,同时在最初的程序设定时,有可能会根据程序需求的不同,而不确定哪个函数实现,通过多态不需要修改源代码,就可以实现一个接口多种解决方案。
多态的具体表现为⽅法重载和⽅法重写。
⽅法重载: 重载是指不同的函数使⽤相同的函数名, 但是函数的参数个数或类型不同。调⽤的时候根据函数的参数来区别不同的函数
⽅法重写:子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
重写 (也叫覆盖) 是指在派⽣类中重新对基类中的虚函数 (注意是虚函数) 重新实现。即函数名和参数都⼀样, 只是函数的实现体不⼀样。
class Father {
constructor(name) {
this.name = name;
};
//实例⽅法,通过实例对象调⽤
getName() {
console.log(this.name);
};
work() {
console.log('我的⼯作是累死累活,赚钱养家');
};
// 静态⽅法不会被继承,并且是通过类名去调⽤的
static hitXiaoMing() {
console.log("打⼩明");
}
};
class Son extends Father {
constructor(name, age) {
//实例化⼦类的时候把⼦类的数据传给⽗类(这⾥的super必须有,super⾥的参数是所继承的⽗类实例化所需要的数据)
super(name);
this.age = age;
};
work() {
console.log('我的⼯作是好好学习,天天向上。');
};
}
var DaMing = new Father('⼤明');
DaMing.work() // 我的⼯作是累死累活,赚钱养家。
var XiaoMing = new Son('⼩明',15);
XiaoMing.work(); // 我的⼯作是好好学习,天天向上。
class Employees {
constructor(name) {
this.name = name;
};
seyHello() {
console.log("Hello");
};
getName() {
console.log(this.name);
};
};
class Java extends Employees {
constructor(name) {
super(name);
};
seyHello(){
console.log(`Hello,我的名字是${this.name},我是做Java工作的。`);
};
}
const employees = new Employees("Aaron");
const java = new Java("Leo");
employees.seyHello(); //Hello
java.seyHello(); //Hello,我的名字是Leo,我是做Java工作的。
employees.getName(); //Aaron
java.getName() //Leo
重载
JS没有重载的概念。原因是JS的函数只看真实的传参数。重载就是函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。
class Employees {
constructor(arg) {
let obj = null;
switch(type of arg) {
case "string":
obj = new StringEmployees(arg);
break;
case "object":
obj = new ObjEmployees(ObjEmployees);
break;
case "number":
obj = new NumberEmployees(ObjEmployees);
break;
}
return obj;
}
};
class ObjEmployees {
constructor(arg) {
console.log("ObjEmployees")
}
};
class StringEmployees {
constructor(arg) {
console.log("StringEmployees")
}
};
class NumberEmployees {
constructor(arg) {
console.log("NumberEmployees")
}
}
new Employees({}); // ObjEmployees
new Employees("123456"); // StringEmployees
new Employees(987654) // NumberEmployees
因为JavaScript是没有重载的概念的所以要自己编写逻辑完成重载。
在上面的代码中定义了Employees,ObjEmployees,StringEmployees,NumberEmployees类,在实例化Employees的时候在constructor里面进行了判断,根据参数的不同返回不同的对应的类,这样完成了一个简单的类重载。
面向过程和面向对象
// 面向对象事实上是和面向过程来对比的。
// 面向对象和面向过程是两种不同思路的编程思想。
// 经典案例:把大象塞进冰箱
// 面向过程的思路: 经典的编程语言C
// 第一步 打开冰箱门
// 第二步 把大象放进去
// 第三步 关闭冰箱门
// 伪代码
// 打开门
// 检测冰箱门是否可以打开
// 启动降温系统
// 操控冰箱门压力阀
// 打开冰箱
// 放大象
// 把大象放进去
// 检查冰箱内的温度
// 调成合适的温度
// 关闭冰箱门
// 看是否能够关紧
// 关闭后的温度调节
// 提示已经关门成功
// 面向对象的思路 封装一个对象 让对象去做
// 1、封装对象 =》冰箱
// 冰箱可以打开门 (方法封装)
// 检测冰箱门是否可以打开
// 启动降温系统
// 操控冰箱门压力阀
// 打开冰箱
//冰箱可以关上门 (方法封装)
// 看是否能够关紧
// 关闭后的温度调节
// 提示已经关门成功
//冰箱可以放东西 (方法封装)
// 把大象放进去
// 检查冰箱内的温度
// 调成合适的温度
// 2、调用冰箱的开门方法
// 3、调用冰箱的存放的方法
// 4、调用冰箱的关门方法
// 下一次,我不放大象了,我把长颈鹿放进去,我不需要去写冰箱开门关门放东西的方法,只需要直接调用,达到了代码复用的效果。
// 1、调用冰箱的开门方法
// 2、调用冰箱的存放的方法
// 3、调用冰箱的关门方法
总结
1、封装可以隐藏实现细节,使得代码模块化。封装的优势在于只可以在类内部进⾏对属性的操作,外部只能通过类实现的方法进行操作,相当于对类的操作进行了规范。
2、继承可以扩展已存在的代码模块(类),它们的目的都是为了——代码重用。减少了代码的冗余,省略了很多重复代码,开发者可以从⽗类底层定义所有⼦类必须有的属性和⽅法,以达到减少耦合的⽬的。
3、多态就是相同的事物,调用其相同的方法,参数也相同时,但表现的行为却不同。多态实现了⽅法的个性化, 不同的⼦类根据具体状况可以实现不同的⽅法,光有⽗类定义的⽅法不够灵活, 遇见特殊状况就捉襟见肘了。在编程的是多多运用这个写思想对其编程时很有用的,能够使你的代码达到高复用以及可维护。
转载自:https://juejin.cn/post/7151996502292840456