JS面向对象基础

读阮一峰教程的简单记录

http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html

一、封装

原始模式的弊端:如果生成多个实例,写起来非常麻烦;实例与原型之间看不出有什么联系。

var Cat = {
    name : '';
    color : ''
}
var cat1 = {};
    cat1.name = '大毛';
    cat1.color = '黄色';
var cat2 = {};
    cat2.name = '二毛';
    cat2.color = '黑色';

 

 

所谓构造函数,就是一个内部使用 this 变量的普通函数,对构造函数使用new 运算符,就能生成实例,并且 this 变量会绑定在实例对象上

function Cat(name,color){
    this.name = name;
    this.color = color;
}

var cat1 = new Cat('大毛','黄色');
var cat2 = new Cat('二毛','黑色');

 

 

但是我们为Cat对象添加一个不变的属性,每生成一个实例都为重复内容,浪费一些内存

  function Cat(name,color){
    this.name = name;
    this.color = color;
    this.type = "猫科动物";
    this.eat = function(){alert("吃老鼠");};
  }

 

每一个构造函数都有一个prototype 属性,指向另一个对象。这个对象的所有属性和方法都会被构造函数的实例继承。那些不变的属性和方法,可以直接定义在 prototype 对象上。

  function Cat(name,color){
    this.name = name;
    this.color = color;
  }
  Cat.prototype.type = "猫科动物";
  Cat.prototype.eat = function(){alert("吃老鼠")};

 

 

isPrototypeOf()

判断某个prototype 对象和某个实例之间的关系

hasOwnProperty()

判断某一个属性是本地的,还是继承自prototype对象的

in

判断某个实例是否含有某个属性,不管是不是本地属性

for in 可以用来遍历某个对象的所有属性

 

二、构造函数的继承

1、构造函数绑定,使用 call apply 方法,将父对象构造函数绑在子对象上

function Animal(){
    this.species = "动物";
}

function Cat(name,color){
    Animal.apply(this, arguments);
    this.name = name;
    this.color = color;
}

var cat1 = new Cat("大毛","黄色");
alert(cat1.species); //动物

 

2、prototype模式

猫的prototype对象 ——指向——> Animal 的实例

猫的 实例 ——继承——>Animal

  Cat.prototype = new Animal();
  Cat.prototype.constructor = Cat;
  var cat1 = new Cat("大毛","黄色");
  alert(cat1.species); // 动物

 

注意:如果替换了prototype对象,那么接下来一定要为新的prototype对象加上constructor属性,并指回原来的构造函数

o.prototype = {};
o.prototype.constructor = o;

  

3、直接继承prototype

Animal对象中,不变的属性都可以直接写入 Animal.prototype

  function Animal(){ }
  Animal.prototype.species = "动物";
  Cat.prototype = Animal.prototype;
  Cat.prototype.constructor = Cat;
  var cat1 = new Cat("大毛","黄色");
  alert(cat1.species); // 动物

 

缺点:修改Cat.prototype 会反映到 Animal.prototype

 

4、利用空对象作为中介

  var F = function(){};
  F.prototype = Animal.prototype;
  Cat.prototype = new F();
  Cat.prototype.constructor = Cat;

修改Cat的prototype对象,就不会影响到Animal的prototype对象

封装和使用

  function extend(Child, Parent) {

    var F = function(){};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
    Child.uber = Parent.prototype;  //在子对象打开一条通道,直接调用父对象方法,属于备用性值
  }
  extend(Cat,Animal);
  var cat1 = new Cat("大毛","黄色");
  alert(cat1.species); // 动物

 

 

5、拷贝继承

将父对象的prototype对象中的属性,一一拷贝给Child对象的prototype对象。

  function Animal(){}
  Animal.prototype.species = "动物";
  function extend2(Child, Parent) {
    var p = Parent.prototype;
    var c = Child.prototype;
    for (var i in p) {
      c[i] = p[i];
      }
    c.uber = p;  //备用
  }

 

  extend2(Cat, Animal);
  var cat1 = new Cat("大毛","黄色");
  alert(cat1.species); // 动物

 

 

三、非构造函数继承

  var Chinese = {
    nation:'中国'
  };
  var Doctor ={
    career:'医生'
  }

 

object()方法

  function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
  }

 

 

浅拷贝

不是真正的拷贝,存在父对象被篡改的可能

  function extendCopy(p) {
    var c = {};
    for (var i in p) { 
      c[i] = p[i];
    }
    c.uber = p;
    return c;
  }

 

  var Doctor = extendCopy(Chinese);
  Doctor.career = '医生';
  alert(Doctor.nation); // 中国

 

 

深拷贝(递归调用浅拷贝)

  function deepCopy(p, c) {
    var c = c || {};
    for (var i in p) {
      if (typeof p[i] === 'object') {
        c[i] = (p[i].constructor === Array) ? [] : {};
        deepCopy(p[i], c[i]);
      } else {
         c[i] = p[i];
      }
    }
    return c;
  }

 

posted @ 2018-04-27 18:18  言叶以上  阅读(395)  评论(0编辑  收藏  举报