面向对象与原型2---原型

1.

我们创建的每个函数(或称构造函数或对象)都有一个 prototype(原型)属性,这个属性是一个对象(这个对象下有个prototype属性,而这个属性其实是另外一个对象的引用,这个属性就是一个对象),它的用途是

包含可以由特定类型的所有实例共享的属性和方法(prototype共享放到其中的属性和方法,无论实例化多少对象,属性和方法都是共享的。这样有好处也有坏处。)。逻辑上可以这么理解:prototype 通过
调用构造函数而创建的那个对象的原型对象。使用原型的好处可以让所有对象实例共享它所
包含的属性和方法。也就是说,不必在构造函数中定义对象信息,而是可以直接将这些信息
添加到原型中。

//构造函数声明对象方式

function Box(name,age) {

this.name = name;    //实例属性

this.age=age;

this.run = function(){  //实例方法

 return this.name + this.age + '运行中...';

}

//原型声明对象方式

function Box(){}  //构造函数函数体内什么都没有,这里如果有,叫做实例属性,实习方法
Box.prototype.name = 'Lee'; //原型属性  原型里添加属性
Box.prototype.age = 100;
Box.prototype.run = function () {  // 原型方法  在原型里添加方法
return this.name + this.age + '运行中...';
};
比较一下原型内的方法地址是否一致:
var box1 = new Box();

alert(box1.name);  //输出lee

alert(box1.run());  //输出lee运行中

var box2 = new Box();
alert(box1.run == box2.run); //true,方法的引用地址保持一致

以上两个例子说明:

如果是实例方法,不同的实例化,他们的方法地址是不一样的,是唯一的

如果是原型方法,那么他们的地址是共享的,大家都一样

2.

为了更进一步了解构造函数的声明方式和原型模式的声明方式,我们通过图示来了解一
下:

(1)构造函数方式中

box1和box2 的实例属性实例方法在内存中是不共享的,box1的name属性和box2的name属性的地址是不同的

(2)原型方式中

function Box(){}  
Box.prototype.name = 'Lee'; 
Box.prototype.age = 100;
Box.prototype.run = function () {  
return this.name + this.age + '运行中...';
};
var box1 = new Box();//Box实例有了,但是里面为空,实际上里面有个自带的属性_proto_

var box1 = new Box();

alert(box1.prototype);// undefined 这个属性是一个对象,访问不到

alert(box1._proto_);  // 输出 object 这个属性是一个指针,指向prototype原型对象,但是_proto_在ie浏览器中是不支持的

 创建的每个函数都有一个 prototype(原型)属性,但是这里访问不到,应该访问的是那个指针_proto_

_proto_实际上就是prototy,只不过他是个指针属性,指向prototype对象

在原型模式声明中,多了两个属性,这两个属性都是创建对象时自动生成的。__proto__
属性是实例指向原型对象的一个指针,它的作用就是指向构造函数的原型属性 constructor,而constructor指向Box,
通过这两个属性,就可以访问到原型里的属性和方法了。
PS:IE 浏览器在脚本访问__proto__会不能识别,火狐和谷歌浏览器及其他某些浏览器
均能识别。虽然可以输出,但无法获取内部信息。
alert(box1.__proto__); //[object Object]

alert(box1.constructor);  //输出 function  Box(){ } 。constructor是构造属性,可以获取构造函数本身  作用是通过被原型指针定位,然后得到构造函数本身,其实就是做一个连接的作用,就是对象实例对应原型对象的作用

以下图是在控制台打出的:

3.
判断一个对象实例(对象引用)是否指向了该构造函数的原型对象,可以使用 isPrototypeOf()方法来测试。只要实例化了,他是自动指向的。
alert(Box.prototype.isPrototypeOf(box1)); //true    只要实例化对象,即都会指向

例如:

var obj = new Object();

alert(Object.prototype.isPrototypeOf(obj)); //true

说明只要实例化了,就默认指向

alert(Object.prototype.isPrototypeOf(box1));  //true  因为所有的实例都是Object

alert(Box.prototype.isPrototypeOf(obj));   //false

4.

原型模式的执行流程:
1.先查找构造函数实例里的属性或方法,如果有,立刻返回;
2.如果构造函数实例里没有,则去它的原型对象里找,如果有,就返回;

function Box(){} // 构造函数函数体内什么都没有,如果有,叫做实例属性和实例方法
Box.prototype.name = 'Lee';   //原型属性
var box1 = new Box();

alert(box1.name);  //输出 Lee  构造函数实例里没有,则去它的原型对象里找

box1.name = 'jack';   //实例属性 并没有重写原型

alert(box1.name);   //输出 jack  就近原则  先查找构造函数实例里的属性或方法,如果有,立刻返回

var box2 = new Box();

alert(box2.name);  //实例属性不会共享,所以box2访问不到实例属性,只能访问到原型属性

delete box1.name;  //删除实例中的属性

alert(box1.name);  //输出lee

delete Box.prototype.name //删除原型中的属性

alert(box1.name);  // undefined

Box.prototype.name = 'kk';  //覆盖原型中的属性

alert(box1.name);  //输出kk

如果:

function Box(){

this.name = 'jack';  //实例属性

}

Box.prototype.name = 'Lee';   //原型属性
var box1 = new Box();

alert(box1.name);  //输出 jack

5.

如何判断属性是在构造函数的实例里,还是在原型里?可以使用 hasOwnProperty()函数
来验证:

//判断实例中是否存在指定属性

alert(box.hasOwnProperty('name')); //实例里有返回 true,否则返回 false

//判断原型中是否存在指定属性

就近原则,box1访问Jack,而不是Lee; box2访问Lee,因为没有实例属性

in 操作符会在通过对象能够访问给定属性时返回 true,无论该属性存在于实例中还是原
型中。
alert('name' in box); //true,存在实例中或原型中

我们可以通过 hasOwnProperty()方法检测属性是否存在实例中,也可以通过 in 来判断
实例或原型中是否存在属性。那么结合这两种方法,可以判断原型中是否存在属性。且只能判断原型中是否存在。

function isProperty(object, property) { //判断原型中是否存在属性
return !object.hasOwnProperty(property) && (property in object);  //实例中没有&&原型或实例中有=>原型中有
}
var box = new Box();
alert(isProperty(box, 'name')) //true,如果原型有

原文地址:https://www.cnblogs.com/mabelstyle/p/3719853.html