Js面向对象

js面向对象

一.js类的生成方式

1.工厂模式

function Person(options) {
    var obj = new Object();
    obj.name = options.name;
    obj.age = options.age;
    obj.say = function () { console.log("工厂模式"); }
    return obj;
}
var person = Person({ name: 'A', age: 18 });/* 没有new */
console.log(person);/* Object{name: "A", age: 18, say: ƒ} */
person.say();/* 工厂模式 */

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

缺点:构造函数都为Object,不同类之间区分不方便。
2.构造函数模式

function Person2(options) {
    this.name = options.name;
    this.age = options.age;
    this.say = function () {
        console.log("构造函数");
    }
}
var person2 = new Person2({ name: 'B', age: 16 });
console.log(person2);/* Person2 {name: "B", age: 16, say: ƒ} */
person2.say();/* 构造函数 */
console.log(person2 instanceof Person2);/* true */

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

缺点:创建每个实例都要创建相同方法,浪费内存。
3.原型模式

function Person3(options) {
    this.name = options.name;
    this.age = options.age;
}
Person3.prototype.say = function () {
    console.log("原型  " + this.name);
}
var person3 = new Person3({ name: 'C', age: 21 });
console.log(person3);/* Person3 {name: "C", age: 21} */
person3.say();/* 原型  C */
console.log(person3.__proto__);/* say: ƒ ()   constructor: ƒ Person3(options) */

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

原型模式不仅可以防止命名冲突,还可以实现所有实例共用prototype的内容,当函数以构造函数形式调用,所创建的对象会有一个隐含属性__proto__指向该构造函数的原型对象,prototype,proto,constructor的关系如下图:
原型链
当ldh对象实例使用一个本身没有的属性或方法时,会利用__proto__一直往上延申寻找直到null,也就是Object._proto_。

二.继承

1. 构造函数继承

绑定this指向执行父类构造函数
优点:能继承父类私有属性
缺点:不能继承父类原型上的方法

/* 构造函数继承 */
function Parent() {
    this.name = "zhangsan";
    this.age = 18;
}
Parent.prototype.say = function () {
    console.log(this.name);
}
function Son() {
    Parent.call(this);
    this.sex = "male";
}

let son = new Son();
console.log(son);//Son { name: ‘zhangsan’, age: 18, sex: ‘male’ }
// son.say();//报错

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
2. 原型继承

将子类原型绑定到一个父类的实例中实现继承
优点:父类原型的方法能让子类实例对象继承
缺点:子类实例修改父类引用属性会引起所有子类实例的属性改变

/* 原型链继承 */
function Parent() {
    this.name = "zhangsan";
    this.age = 18;
    this.hobbies = ['music', 'painting'];
}
Parent.prototype.say = function () {
    console.log(this.name);
}
function Son() {
    this.sex = "male";
}
Son.prototype = new Parent();
let son = new Son();
let son2 = new Son();
console.log(son);//Parent { sex: 'male' }
son.say();//zhangsan
console.log(son.hobbies);//[ 'music', 'painting' ]
//son改变引起son2改变
son.hobbies.push('reading');
console.log(son.hobbies);//[ 'music', 'painting', 'reading' ]
console.log(son2.hobbies);//[ 'music', 'painting', 'reading' ]

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
3. 组合继承

借用构造函数继承属性:在Son构造函数中改变通过改变this指向并传参的方式调用Father实现继承属性。
利用原型继承方法:将Father的实例对象作为Son的原型,并且把Son原型的constructor强制改为Son,Son可以通过__proto__访问父类的方法,实现过程如下图:
注意:不能直接Son.prototype=Father.prototype(因为这种情况下,子类和父类指向同一原型对象,子类独有的方法父类也会拥有,例如父类是不能有exam方法的)。
原型继承

function Father(name, age) {
    this.name = name;
    this.age = age;
}
Father.prototype.money = function () {
    console.log(100000);
}
function Son(name, age) {
    // 借用父类构造函数,改变this指向实现继承属性
    Father.call(this, name, age);
}
/* 将Father的一个实例作为Son的原型 */
Son.prototype = new Father();//或者Object.create(Father.prototype);
/* Father实例的constructor是Father,需要强制改为Son */
Son.prototype.constructor = Son;
//Son自己的方法
Son.prototype.exam = function () {
    console.log("100分");
}
console.log(new Son('Mike', 11));/* Son {name: "Mike", age: 11} */

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
4. ES6中extend关键字继承

与其它语言类似,直接在定义时加关键字,注意的是构造函数里面需要用super传参并且super必须在最前面。

class Father {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    showInfo() { console.log(this.name, this.age); }
}
class Son extends Father {
    constructor(name, age) {
        super(name, age);//传入父类
        this.name = name;
        this.age = age;
    }
}
var son = new Son('zhangsan', 22);
console.log(son);/* Son {name: "zhangsan", age: 22} */
son.showInfo();/* zhangsan 22 */

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

三.重载

与其他语言不同,js中的重载并不是真正意义上的重载,而是在一个方法内根据传参情况不同做出不同表现。

function count(){
    if(arguments.length%2==1){
        console.log( "奇数个参数");
    }else{
        console.log("偶数个参数");
    }
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

四.重写

继承了父类,但是自己原型上定义了同名方法,在调用时执行自己原型上的方法。

function Father(name, age) {
    this.name = name;
    this.age = age;
}
Father.prototype.money = function () {
    console.log(100000);
}
function Son(name, age) {
    // 借用父类构造函数,改变this指向实现继承属性
    Father.call(this, name, age);
}
/* 将Father的一个实例作为Son的原型 */
Son.prototype = new Father();
/* Father实例的constructor是Father,需要强制改为Son */
Son.prototype.constructor = Son;
/* Son重写方法 */
Son.prototype.money = function () {
    console.log(100);
}
var son = new Son('Mike', 11);
son.money();//100

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

五.多态

多态的概念是对同一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果。

function Dog() { };
function Cat() { };
Dog.prototype.sound = function () { console.log("汪!") }
Cat.prototype.sound = function () { console.log('喵!') };
function makeSound(animal) {
    animal.sound();
}
makeSound(new Dog());//汪!
makeSound(new Cat());//喵!

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值