面向对象与原型(二)

原型

我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个对象。使用原型的好处可以让所有对象实例共享它所包含的属性和方法。不必再构造函数中定义对象信息,而是可以直接将这些信息添加到原型中。

function Box(){}             //创建一个构造函数

Box.prototype.name = 'Lee';                            //在原型里
Box.prototype.age = 100;
Box.prototype.run = function(){                         //在原型里添加方法
      return this.name + this.age + '运行中...';   
}

原型声明方式 图:

实例化方法:不同的实例它们的地址是不一样的,是唯一的。

原型方法:对象里的原型地址共享的,大家都一样。

  在原型模式声明中,多了两个属性,这两个属性都是创建对象是自动生成的。

   __proto__

  属性是实例指向原型对象的一个指针,它的作用就是指向构造函数的原型属性constructor。

  constructor

1、构造属性,可以获取构造函数本身

2、作用是被原型指针定位,然后得到构造函数本身

3、其实就是用来让对象实例对应原型对象的

 

 

ps:IE浏览器在脚本访问—__proto__会不能识别。
 
问:判断一个对象实例(对象引用)是不是指向原型对象?
答:Object.prototype.isPrototype(obj)
ps:只要实例化对象,都会自动指向原型
 
问:如何判断属性是在构造函数的实例里,还是在原型里?
答:
box.hasOwnProperty('name');         //判断构造函数的实例中是否存在指定属性
alert('name' in box);              //返回true or false 无论在实例中还是原型中,只要存在指定属性,就返回true
function isProperty(object,propety){        //构造函数名,属性名
    return !object.hasOwnProperty(property) && (propety in object);
}

字面量方式创建原型

function Box(){}

Box.prototype = {
       name:'Lee',
       age:100,
       run:function(){
            return this.name + this.age + '运行中...';
       } 
}    

 ps:字面量创建原型对象,使用constructor属性不会指向构造函数,而会指向object。

因为Box.prototype={};这种写法其实就是创建了一个新对象。而每创建一个函数,就会同时创建它prototype,这个对象也会自动获取constructor 属性。所以,新对象的constructor 重写了Box 原来的constructor,因此会指向新对象,那个新对象没有指定构造函数,那么就默认为Object。

 
 问:如何让字面量方式的constructor指向构造函数呢?
答:
Box.prototype={
    constructor:Box        //强制指向构造函数
}

ps:重写会切断之前的原型。所以在声明前就要指向构造函数。

拓展:

原型对象不仅仅可以在自定义对象的情况下使用,而ECMAScript 内置的引用类型都可以使用这种方式,并且内置的引用类型本身也使用了原型。
alert(Array.prototype.sort);                       //sort 就是Array 类型的原型方法
alert(String.prototype.substring);                   //substring 就是String 类型的原型方法
String.prototype.addstring = function () {                //给String 类型添加一个方法
return this + ',被添加了!';                               //this 代表调用的字符串
};
alert('Lee'.addstring());                                 //使用这个方法
 

原型的缺点:

1、初始化不能传参
2、在第一个实例修改后, 保持了共享
 
解决方法:组合构造函数+原型模式
function Box(name,age){                                          //将所有信息封装到函数体内
      this.name = name;
      this.age = age;
      if(typeof this.run != 'function'){                         //仅在第一次调用的初始化
         Box.prototype.run = function(){
               return this.name+ this.age+'运行中...';
          }
      }
}

当第一次调用构造函数时,run()方法发现不存在,然后初始化原型。当第二次调用,就不会初始化,并且第二次创建新对象,原型也不会再初始化了。这样及得到了封装,有实现了原型方法共享,并且属性都保持独立。

ps:使用动态原型模式,要注意一点,不可以在使用字面量的方法重写原型,因为会切断实例和新原型之间的联系。


原文地址:https://www.cnblogs.com/hynb/p/5831938.html