1.原型
Javascript规定,每一个函数都有一个prototype对象属性,指向另一个对象(原型链上面的)。
prototype(对象属性)的所有属性和方法,都会被构造函数的实例继承。这意味着,我们可以把那些不变(公用)的属性和方法,直接定义在prototype对象属性上。
prototype就是调用构造函数所创建的那个实例对象的原型(proto)。
prototype可以让所有对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中定义对象信息,而是可以直接将这些信息添加到原型中。
1.1访问原型
原型实际就是一个普通对象,继承Object类,有JavaScript自动创建并依附在每个函数中,
访问原型的三种方法:obj.__proto__
obj.constructor.prototype
Object.getPrototypeOf(obj)
//是一个静态函数,参数是实例对象,返回值是实例对象的原型对象
注意:obj是一个实例对象,constructor表示构造函数。
实例设计:
var F = funciton() {}; //构造函数
var obj= new F(); //实例化
var Proto1 = obj.__proto__; //引用原型(注意,IE暂不支持)
var Proto2 = obj.constructor.prototype; //引用原型
var Proto3 = Object.getPrototypeOf(obj); //引用原型
var Proto4 = F.prototype; //利用构造函数访问原型
console.log(Proto1==Proto2); //ture
1.2设置原型
设置原型的三种方法obj.__proto__=prototypeObj;
Object.setPrototypeOf(obj,prototypeObj);
Object.create(prototypeObj);
其中,obj表示一个实例对象,prototypeObj表示原型对象。注意,IE目前不支持前面两种方法。
实例设计:通过以上三种方法,为对象直接量设置原型;
var proto = {
name: "prototype"
}; //原型对象
var obj1 = {}; //普通对象直接量
obj1.__proto__ = proto; //设置原型
console.log(obj1.__proto__);
var obj2 = {};
Object.setPrototypeOf(obj2, proto); //设置原型
console.log(obj2.name);
var obj3 = Object.create(proto); //创建对象并设置原型
console.log(obj3.name);
1.3检测原型
使用isPrototypeOf方法可以判断该对象是否为参数对象的原型对象。isPrototypeOf()是一个原型方法,可以在每个实例对象上调用。
实例设计:
//检测原型
var F = function() {}; //构造函数
var obj = new F(); //实例化
var proto1 = Object.getPrototypeOf(obj); //引用原型
console.log(proto1.isPrototypeOf(obj)); //true
console.log(Object.getPrototypeOf(obj));
也可以使用下面的代码检测不同类型的实例对象
var proto2 = Object.prototype;
console.log(proto2.isPrototypeOf({})); //true
console.log(proto2.isPrototypeOf([])); //true
console.log(proto2.isPrototypeOf(/ /)); //true
console.log(proto2.isPrototypeOf(function() {})); //true
console.log(proto2.isPrototypeOf(null)); //false
1.4应用原型
原型对象可以被所有实例访问,而私有属性只能被当前实例访问。
实例设计
示例1:利用原型为对象设置默认值。当原型属性与私有属性同名是,删除私有属性之后,可以访问原型属性,即可以把原型属性值作为初始化默认值。
//【示例1】利用原型为对象设置默认值。当原型属性与私有属性同名时,删除私有属性之后,可以访问原型属性,即可以把原型属性值作为初始化默认值。
function p(x){ //构造函数
if(x) //如果参数存在,则设置属性,该条件是关键
this.x = x; //使用参数初始化私有属性x的值
}
p.prototype.x = 0; //利用原型属性,设置私有属性x的默认值
var p1 = new p(); //实例化一个没有带参数的对象
console.log(p1.x); //返回0,即显示私有属性的默认值
var p2 = new p(1); //再次实例化,传递一个新的参数
console.log(p2.x); //返回1,即显示私有属性的初始化值
//【示例2】利用原型间接实现本地数据备份。把本地对象的数据完全赋值给原型对象,相当于为该对象定义一个副本,通俗地说就是备份对象。这样当对象属性被修改时,可以通过原型对象来恢复本地对象的初始值。
function p(x){ //构造函数
this.x = x;
}
p.prototype.backup = function(){ //原型方法,备份本地对象的数据到原型对象中
for(var i in this){
p.prototype[i] = this[i];
}
}
var p1 = new p(1); //实例化对象
p1.backup(); //备份实例对象中的数据
p1.x =10; //改写本地对象的属性值
console.log(p1.x) //返回10,说明属性值已经被改写
p1 = p.prototype; //恢复备份
console.log(p1.x) //返回1,说明对象的属性值已经被恢复
//【示例3】利用原型还可以为对象属性设置“只读”特性,这在一定程序上可以避免对象内部数据被任意修改的尴尬。下面示例演示了如何根据平面上两点坐标来计算它们之间的距离。构造函数p用来设置定位点坐标,当传递两个参数值时,会返回以参数为坐标值的点,如果省略参数则默认点为原点(0,0)。而在构造函数l中通过传递的两点坐标对象,技算它们的距离。
function p(x,y){ //求坐标点构造函数
if(x) this.x =x; //初始x轴值
if(y) this.y = y; //初始y轴值
p.prototype.x =0; //默认x轴值
p.prototype.y = 0; //默认y轴值
}
function l(a,b){ //求两点距离构造函数
var a = a; //参数私有化
var b = b; //参数私有化
var w = function(){ //计算x轴距离,返回对函数引用
return Math.abs(a.x - b.x);
}
var h = function(){ //计算y轴距离,返回对函数引用
return Math.abs(a.y - b.y);
}
this.length = function(){ //计算两点距离,调用私有方法w()和h()
return Math.sqrt(w()*w() + h()*h());
}
this.b = function(){ //获取起点坐标对象
return a;
}
this.e = function(){ //获取终点坐标对象
return b;
}
}
var p1 = new p(1,2); //实例化p构造函数,声明一个点
var p2 = new p(10,20); //实例化p构造函数,声明另一个点
var l1 = new l(p1,p2); //实例化l构造函数,传递两点对象
console.log(l1.length()) //返回20.12461179749811,计算两点距离
l1.b().x = 50; //不经意改动方法b()的一个属性为50
console.log(l1.length()) //返回43.86342439892262,说明影响两点距离值
…….
2.原型链
在JavaScript中,实例对象在读取属性值时,总是先检查私有属性,如果存在,则会返回私有属性值,否则就会检索prototype原型,如果找到同名属性,则返回prototype原型的属性值。
prototype原型允许引用其他对象。如果在prototype原型中没有找到指定的属性,则JavaScript将会根据引用关系,继续检索prototype原型对象的prototype原型,以此类推。
实例设计
//示例1,下面的示例演示了对象属性查找原型的基本方法和属性
function a(x) {
this.x = x;
} //构造函数
a.prototype.x = 0; //原型属性x的值为0
function b(x) {
this.x = x; //构造函数b
}
b.prototype = new a(1); //原型对象为构造函数a的实例
function c(x) {
this.x = x; //构造函数c
}
c.prototype = new b(2); //原型对象为构造函数b的实例
var d = new c(3); //实例化构造函数c
console.log(d.x); //调用实例对象d的私有属性,返回值为3
delete d.x; //删除实例对象的私有属性x
console.log(d.x); //调用实例对象d的属性,返回值为2
delete c.prototype.x; //删除c类原型属性x
console.log(d.x); //调用实例对象d的属性x,返回值为1
delete b.prototype.x; //删除b类原型属性x
console.log(d.x); //返回值为0