JS面向对象三大特征:封装、继承、多态
2020-09-02 本文已影响0人
黄黄黄大帅
封装
把事物(属性和方法)封装在类(程序对象)中,隐藏事物的属性和方法的实现细节,仅对外公开接口。
1.构造函数模式
function Person(name, sex) {
this.name = name;
this.sex = sex;
this.sayName = function () {
alert(this.name);
};
}
var adam = new Person("亚当", 1);
var eve = new Person("夏娃", 0);
2.原型prototype封装
function Cat(name,color){
this.name = name;
this.color = color;
}
Cat.prototype.type = "英短";
Cat.prototype.eat = ( () => {
alert("fish!")
} )
//生成实例
var cat1 = new Cat('Tom', 'gray');
var cat2 = new Cat('Kobe', 'purple');
console.log(cat1.type); //英短
cat2.eat(); //fish!
3.声明函数模式
- 优点
避免了全局变量--因为存在函数作用域(函数作用域画重点,以后要考)
按需执行--解析器读取到此处,函数并未执行,只有当你需要的时候,调用此函数即可
提高代码重用性 - 缺点:
易被同名变量覆盖--因为在全局作用域下声明的变量,容易被同名变量覆盖
立即执行--解析器读取到此处立即执行
4.工厂模式
function createPerson(name, sex) {
var o = new Object();
o.name = name;
o.sex = sex;
return o;
}
var adam = createPerson("亚当", 1);
var eve = createPerson("夏娃", 0);
-
优点:这种封装解决了代码重复的问题;
-
缺点:adam和eve之间没有内在的联系,不能反映出它们是同一个原型对象的实例;
5.闭包
var PI = (function () {
var _pi = 3.1415926;
return {
get: function () {
return _pi;
}
}
}())
console.log(PI.get()); //3.1415926
继承
一个对象可以使用另一个对象的属性和方法 (子类可以使用父类的属性和方法)
1.原型链继承
//创建自定义构造函数
function Hqg() {
this.name = '洪七公';
}
//在当前构造函数的原型链上添加属性skill
Hqg.prototype.skill = '打狗棒'
//通过自定义构造函数Hqg实例化一个对象gj
const gj = new Hqg()
console.log(gj.skill);//=>打狗棒
//通过自定义构造函数Hqg实例化一个对象hr
const hr = new Hqg()
console.log(hr.skill);//=>打狗棒
- 缺点:当父类(对象)属性或方法改变时,不同实例对象对应属性方法也会改变。
2.借用构造函数
//创建一个构造函数,并添加一些属性
function Hqg() {
this.name = '洪七公';
this.job = '帮主';
this.skill = ['降龙十八掌', '打狗棒']
}
//创建一个构造函数,并借用了Hqg的构造函数
function Hr() {
Hqg.call(this)
this.name = '黄蓉';
this.job = ['相夫', '教子']
}
//创建一个构造函数,并借用了Hqg的构造函数
function Gj() {
Hqg.call(this)
this.name = '郭靖';
this.job = ['吃饭', '睡觉']
}
const hr = new Hr();
console.log(hr);
const gj = new Gj();
console.log(gj);
2-1.png
这样就避免了原型链继承中,构造函数中的属性或者方法被其他实例所改变的问题
⚠️:这里要注意call方法的执行顺序:
//部分代码省略
function Hr() {
this.name = '黄蓉';
this.job = ['相夫', '教子']
Hqg.call(this)
}
function Gj() {
this.name = '郭靖';
this.job = ['吃饭', '睡觉']
Hqg.call(this)
}
//部分代码省略
4-1.png
值会被覆盖,这个要注意!
function Hqg(name,job,skill) {
this.name = name;
this.job = job;
this.skill = skill
}
function Hr() {
Hqg.call(this,'黄蓉',['相夫', '教子'],['打狗棒'])
}
function Gj() {
Hqg.call(this,'郭靖',['吃饭', '睡觉'],['降龙十八掌'])
}
const hr = new Hr();
console.log(hr);
const gj = new Gj();
console.log(gj);
3-1.png
3.组合继承
使用原型链实现对原型对象属性和方法的继承,借用构造函数实现对实例属性方法的继承
这样既通过在原型上定义方法实现了函数复用,又能保证每个实例都有自己的属性
function hqg(name) {
this.name = name
this.skill = ['打狗棒', '乾坤大挪移']
}
hqg.prototype.sayName = function () {
console.log(this.name)
}
function Hero(name, job) {
hqg.call(this, name)
this.job = job
}
Hero.prototype.sayJob = function () {
console.log(this.job)
}
Hero.prototype = new hqg()
Hero.prototype.constructor = Hero
var gj = new Hero('郭靖', '打老虎')
var hr = new Hero('黄蓉', '打豆豆')
console.log(gj)
console.log(hr)
4.寄生式继承
寄生式继承是与原型式继承紧密相关的一种思路,它创造一个仅用于封装继承过程的函数,在函数内部以某种方式增强对象,最后再返回对象。
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function hero(params) {
const clone = object(params) //通过调用函数创建一个新对象
clone.sayHi = () => {
console.log('hi');
}
return clone
}
const hqg = {
name: "洪七公",
skill: ['降龙十八掌', '打狗棒']
}
const gj = hero(hqg);
gj.name = '郭靖';
gj.skill.push('九阴真经')
console.log(gj);
3-4.png
5.寄生组合式继承
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function hero(Children, Parent) {
const proto = object(Parent.prototype); //返回Parent的一个副本
proto.constructer = Children; //设置constructor指向, 因为新副本的原型对象被重写
Children.prototype = proto; //副本作为sub的原型对象
}
function Hqg() {
this.name = '洪七公';
}
Hqg.prototype.show = function () {
console.log(this.name);
}
function Gj() {
Hqg.call(this);
this.name = '郭靖'
}
function Hr() {
Hqg.call(this);
this.name = '黄蓉'
}
hero(Gj, Hqg);
hero(Hr, Hqg);
const gj = new Gj();
const hr = new Hr();
gj.show(); // =>郭靖
hr.show(); //=> 黄蓉
多态
不同对象与同一操作产生不同结果。把“想做什么”跟“谁去做”分开,把过程化的条件语句转换为对象的多态性,从而消除条件分支语句。有重写跟重载:
重写:子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
重载:函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。
//非多态
var hobby = function(animal){
if(animal == 'cat'){
cat.eat()
}else if(animal == 'dog'){
dog.eat()
}
}
var cat = {
eat: function() {
alert("fish!")
}
}
var dog = {
eat: function() {
alert("meat!")
}
}
console.log(123);
hobby('cat'); //fish!
hobby('dog'); //meat!
//多态
var hobby=function(animal){
if(animal.eat instanceof Function){
animal.eat()
}
}
var cat={
eat:()=>{
console.log('miao')
}
}
var dog={
eat:()=>{
console.log('wang')
}
}
hobby(cat)// miao
hobby(dog)// wang