javascript之面向对象编程

203 阅读3分钟

对象

在jacascript里一切皆为对象,对象里有属性和行为(方法),属性有对应的值。 Object为最顶层对象。

属性分两种:

  1. (自身)属性:使用this关键字定义。
  2. (原型)属性:定义在prototype上。
  3. 特殊属性: constructor其属性值为该对象引用(注意该属性可以被修改,请使用instanceof来检查对象类型)

prototype原型

定义:所在在原型上的属性都会被对象的实例继承。原型本身也是对象。Object.prototype为原型链最顶层。

相关方法:

  1. 通过原型上的isPrototypeOf方法来验证,实例是否继承了对象的原型 技巧:
  2. 当有较多原型属性时可使用对象的形式设置,再将constructor设回对象的引用
function Bird () {
    this.name = 'bird'
}

Bird.prototype = {
  constructor: Bird, // 定义 constructor 属性
  numLegs: 2,
  eat: function() {
    console.log("nom nom nom");
  },
  describe: function() {
    console.log("My name is " + this.name);
  }
};

// isPrototypeOf
let bird = new Bird()

Bird.prototype.isPrototypeOf(bird) // true
  1. 可以利用父类的方式来提取公共的原型,再通过Object.create(object.prototype)来实例化
function Animal() { }

Animal.prototype = {
  constructor: Animal, 
  eat: function() {
    console.log("nom nom nom");
  }
};

let duck = Object.create(Animal.prototype)
let beagle = Object.create(Animal.prototype)

duck.eat(); // 应该输出 "nom nom nom"
beagle.eat(); // 应该输出 "nom nom nom" 

类的继承

利用原型链来实现,不同对象之间原型的继承,注意constructor重新指向子类

注意是原型链之间的继承,所以在父类的构造函数内定义的属性和行为是不会被子类继承的

function Animal() {
    this.name = "foo"
}

Animal.prototype = {
  constructor: Animal,
  eat: function() {
    console.log("nom nom nom");
  }
};

function Dog() { }

Dog.prototype = Object.create(Animal.prototype)

let beagle = new Dog();
beagle.eat();  // 应该输出 "nom nom nom"
beagle.name; // undefiend 父类自身属性是不会被继承的


// 修正constructor
Dog.prototype.constructor = Dog

重写继承的方法

子类继承父类的方法后可以重写父类方法,同时又不影响到父类。
示例:

function Bird() { }

Bird.prototype.fly = function() { return "I am flying!"; };

function Penguin() { }
Penguin.prototype = Object.create(Bird.prototype);
Penguin.prototype.constructor = Penguin;

Penguin.prototype.fly = function () { return "Alas, this is a flightless bird." };

let penguin = new Penguin();
console.log(penguin.fly());

使用mixin在不同相关对象之间添加共同行为

子类继承父类固然可以解决提取相关对象的公共属性和方法,但仅限于相关对象,如何在不相关的对象间,共享这些属性和方法呢?
采用mixins方式,传入不同对象,经过处理后赋予对象属性和方法,这样有利于在不相关的对象间添加共同的行为
示例:

let bird = {
  name: "Donald",
  numLegs: 2
};

let boat = {
  name: "Warrior",
  type: "race-boat"
};

let glideMixin = function (obj) {
    obj.glide = function () {
        console.log('I can glide!!');
    }
}

glideMixin(bird);
glideMixin(boat);

构造函数

  • 定义: 用于创建一个新对象,并定义属性和行为。为创建新对象的一个最基本的方式
  • 惯例:
    1. 首字母大写
    2. 使用this关键字来设置属性和行为
    3. 不需要返回值
    4. 可接受自定义参数,用于创建各自的实例
  • 用法:使用new关键字
  • 技巧:
    1. 使用instanceof来验证实例的对象类型,返回布尔值
    2. 使用hasOwnProperty方法来检查(自身)属性是否在对象里,返回布尔值
    3. 使用prototype原型属性来实现实例间共享属性及减少重复的代码
  • 示例:
function Dog (name, color) {
    this.name = name;
    this.color= color;
    this.numLegs = 2;
};

let dog = new Dog('foo', 'red');

dog.name // foo
dog.hasOwnProperty(name) // true

// 验证实例的对象
dog instanceof Dog // true

// 使用prototype来实现实例间共享属性
function Dog (name, color) {
    this.name = name;
    this.color= color;
};
Dog.prototype.numLegs = 2;

构造函数属性私用化

为了保证某些重要属性值不被外界修改,利用闭包的原理将其封存在构造函数内部,仅共内部调用,以实现变量私用化。
示例:

function Bird() {
  let weight = 15;

  this.getWeight = function () {
    return weight;
  }
}

立即调用函数表达(IIFE)

函数没有名称,也不存储在变量中。函数表达式末尾的两个括号()导致它被立即执行或调用。这种模式被叫做自执行函数表达式或者IIFE。
示例:

;(function () {
    console.log('IIFE')
})();

一个自执行函数表达式(IIFE)通常用于将相关功能分组到单个对象或者是模块中。
示例:

let funModule = (function() {
  return {
    isCuteMixin:  function(obj) {
      obj.isCute = function() {
        return true;
      };
    },
    singMixin: function(obj) {
      obj.sing = function() {
        console.log("Singing to an awesome tune");
      };
    }
  }
})()