Javascript 面向对象编程的理解


/*生成对象的原始模式
假定我们把猫看成一个对象,它有"名字"和"颜色"两个属性。*/
  var Cat = {
    name : '',
    color : ''
  }
/*现在,我们需要根据这个原型对象的规格(schema),生成两个实例对象。*/
var cat1 = {}; // 创建一个空对象
     cat1.name = "大毛"; // 按照原型对象的属性赋值
     cat1.color = "黄色";
     var cat2 = {};
     cat2.name = "二毛";
     cat2.color = "黑色";
 
/*原始模式的改进
我们可以写一个函数,解决代码重复的问题。*/
function Cat(name,color){
    return {
      name:name,
      color:color
    };
  };
 var cat3 = Cat("大毛","黄色");
    var cat4 = Cat("二毛","黑色");
 
 
 
/*构造函数模式
为了解决从原型对象生成实例的问题,Javascript提供了一个构造函数(Constructor)模式。
所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。*/
function Cat1(name,color){
    this.name=name;
    this.color=color;
  };
var cat11 = new Cat1("大毛","黄色");
     var cat12 = new Cat1("二毛","黑色");
  alert(cat1.name); // 大毛
  alert(cat1.color); // 黄色
/*这时cat1和cat2会自动含有一个constructor属性,指向它们的构造函数。*/
alert(cat11.constructor == Cat1); //true
    alert(cat12.constructor == Cat1); //true
alert(cat11.constructor.toString());
/*结果如下:
function Cat1(name,color){
    this.name=name;
    this.color=color;
  };*/
alert(cat1.toString());//[object Object]
alert(cat1.constructor.toString());//function Object(){[native code]};
Javascript还提供了一个instanceof运算符,验证原型对象与实例对象之间的关系。
  alert(cat11 instanceof Cat1); //true
  alert(cat12 instanceof Cat1); //true
var cat2 = function(name,color){
    this.name=name;
    this.color=color;
  };
//alert(cat2.toString());//function(name,color){this.name=name;this.color=color;};
//alert(cat2.constructor.toString());//function Function(){[native code]};
 
 
function Cat2(name,color){
    this.name = name;
    this.color = color;
    this.type = "猫科动物";
    this.eat = function(){alert("吃老鼠");};
  };
var cat21 = new Cat2("大毛","黄色");
  var cat22 = new Cat2 ("二毛","黑色");
  alert(cat21.type); // 猫科动物
  cat21.eat(); // 吃老鼠
/*表面上好像没什么问题,但是实际上这样做,有一个很大的弊端。那就是对于每一个实例对象,
type属性和eat()方法都是一模一样的内容,每一次生成一个实例,都必须为重复的内容,多占用一些内存。这样既不环保,也缺乏效率。*/
alert(cat21.eat == cat22.eat); //false
 
/*Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。
这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。*/
function Cat3(name,color){
    this.name = name;
    this.color = color;
  }
  Cat3.prototype.type = "猫科动物";
  Cat3.prototype.eat = function(){alert("吃老鼠")};
var cat31 = new Cat3("大毛","黄色");
var cat32 = new Cat3("二毛","黑色");
  alert(cat31.type); // 猫科动物
  cat31.eat(); // 吃老鼠
alert(cat31.eat == cat32.eat); //true
/*这时所有实例的type属性和eat()方法,其实都是同一个内存地址,指向prototype对象,因此就提高了运行效率。*/
 
 
 
/*isPrototypeOf()
这个方法用来判断,某个proptotype对象和某个实例之间的关系。object1.isPrototypeOf(object2); 是用来判断指定对象object1是否存在于另一个对象object2的原型链中,是则返回true,否则返回false*/
  alert(Cat3.prototype.isPrototypeOf(cat31)); //true
  alert(Cat3.prototype.isPrototypeOf(cat32)); //true
 
/*hasOwnProperty()
每个实例对象都有一个hasOwnProperty()方法,用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性。*/
  alert(cat31.hasOwnProperty("name")); // true
  alert(cat31.hasOwnProperty("type")); // false
 
 
/*3 in运算符
in运算符可以用来判断,某个实例是否含有某个属性,不管是不是本地属性。*/
  alert("name" in cat31); // true
  alert("type" in cat31); // true
/*in运算符还可以用来遍历某个对象的所有属性。*/
  for(var prop in cat31) { alert("cat31["+prop+"]="+cat31[prop]); };
/*此文转载,非自己编写*/