首页 > 代码库 > 面向对象与原型3---原型

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

function Box(){}

var box = new Box();

alert(box.prototype);  //使用对象实例无法访问到prototype

alert(box._proto_);  //输出[object][object] 使用对象实例可以访问prototype的指针

alert(Box.prototype); //输出[object][object] 使用构造函数名(对象名)可以访问prototype

1.用字面量方式创建原型

为了让属性和方法更好的体现封装的效果,并且减少不必要的输入,原型的创建可以使
用字面量的方式:
function Box() {};
Box.prototype = { //使用字面量的方式创建原型对象,这里的{}就是对象,是Object,
name : ‘Lee‘,
age : 100,
run : function () {
return this.name + this.age + ‘运行中...‘;
}
};

var box = new Box();

alert(box.name);//输出Lee

2.
使用构造函数创建原型对象和使用字面量创建对象在使用上基本相同,但还是有一些区
别,字面量创建的方式使用 constructor 属性不会指向实例,而会指向 Object,构造函数创建
的方式则相反。

//构造函数创建原型对象

function Box(){}  //构造函数函数体内什么都没有,这里如果有,叫做实例属性,实习方法
Box.prototype.name = ‘Lee‘; //原型属性  原型里添加属性
Box.prototype.age = 100;
Box.prototype.run = function () {  // 原型方法  在原型里添加方法
return this.name + this.age + ‘运行中...‘;
};

var box=new Box();

alert(box.constructor);  //输出 function Box(){}

alert(box.constructor==Box);  //输出 true

//字面量方式创建原型对象

function Box() {};
Box.prototype = { //使用字面量的方式创建原型对象,这里的{}就是对象,是Object,
name : ‘Lee‘,
age : 100,
run : function () {
return this.name + this.age + ‘运行中...‘;
}
};

var box = new Box();

alert(box.constructor);  //输出 function Object(){ [native code]}

alert(box.constructor==Box);//false

alert(box.constructor==Object);//true

// 说明

构造函数创建原型, Box可以通过_proto_指向原型的constructor,而constructor可以也通过它自己得到Box本身

用字面的方式,有一个{},{}就代表创建了一个新对象,是Object,所以constructor就成了Object(因为创建了一个新的prototype对象,Box.prototype={}),而不是Box了。因为constructor没有指向原来的对象Box,用对象字面量方式会出现一些问题

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

 

问:在对象字面量的方式创建原型的时候,如何让box.constructor等于Box呢?

如果想让字面量方式的 constructor 指向实例对象,那么可以这么做:
Box.prototype = {
constructor : Box, //直接强制指向即可
};

即如下写

function Box() {};
Box.prototype = { //使用字面量的方式创建原型对象,这里的{}就是对象,是Object,

constructor:Box,  //强制指向Box
name : ‘Lee‘,
age : 100,
run : function () {
return this.name + this.age + ‘运行中...‘;
}
};

var box = new Box();

alert(box.constructor);  //输出 function Box(){}

alert(box.constructor==Box);  //true

3.

原型的声明是有先后顺序的,所以,重写的原型会切断之前的原型。

function Box() {};
Box.prototype = { //使用字面量的方式创建原型对象,这里的{}就是对象,是Object,

constructor:Box,  //强制指向Box
name : ‘Lee‘,
age : 100,
run : function () {
return this.name + this.age + ‘运行中...‘;
}
};

var box = new Box();

alert(box.name);  //输出 Lee

//以下重写了原型

Box.prototype={

age:200  //这里不会保留之前原型的任何信息了,把原来的原型对象和构造函数对象实例之间的关系切断了

};

var box = new Box();

alert(box.name);  //undefined

alert(box.run());  //not a function

 

4.

原型对象不仅仅可以在自定义对象的情况下使用,而 ECMAScript 内置的引用类型都可
以使用这种方式,并且内置的引用类型本身也使用了原型。

//数组排序

var box=[5,1,6,9,3,5,8,1];

alert(box.sort());

sort是哪里来的?

//查看sort是否是Array原型对象的方法

alert(Array.prototyp3e.sort);    //输出 function sort(){ [native code] } 说明sort一定是Array原型对象的方法,因为随便写一个肯定不是的,如下

alert(Array.prototyp3e.aaa);  //undefined

alert(String.prototype.substring);  //输出 function substring(){ [native code] }

是否可以扩展内置的引用类型呢?比如扩展一个String类型

//内置引用类型的功能扩展

String.prototype.addstring=function(){

return this+‘,被添加了‘;

};

alert(‘Lee‘,addstring());  //输出 Lee被添加了 里面的this就是Lee

PS:尽管给原生的内置引用类型添加方法使用起来特别方便,但我们不推荐使用这种

方法。因为它可能会导致命名冲突,不利于代码维护。