您的位置:首页 > Web前端 > JavaScript

js中的原型和继承

2013-07-23 09:34 183 查看
博客搬家:由于各种原因,我现在的博客将首发于blog.mojijs.com,
可以百度搜索 “姜哥的墨迹技术博客” , 或者 点击这里 本文地址 http://blog.mojijs.com/post/41.html

本文是JavaScript交流贴的回帖(csdn博客blog . csdn . net/tt361),因内容较多所以单独写成一篇文章,仅为抛砖,希望大家不要珍惜玉。

约定:

中文“原型”指代对象的__proto__属性指向的对象,原型链为__proto__形成的链条,prototype为函数的prototype属性。

关于原型和原型链

js中的所有对象都有一个原型,而原型又是一个对象,所以原型也有原型,这就形成了原型链。

这句话并不完全正确,原型链不是无限长的,必须有一个尽头。原型链的尽头是Object.prototype所指向的对象,所有对象(除了Object.prototype,Object.prototype没有原型)原型链的尽头都是Object.prototype,也就是说Object.prototype是除Object.prototype之外所有对象共享的,那么在Object.prototype中写入一个属性在任何对象中都是可访问的,但是这样做非常危险,慎用。
关于上述阐述可用下面代码简单测试。

console.log(Object.prototype == new Object().__proto__); // true
console.log(Object.prototype == new Date().__proto__.__proto__); // true
console.log(Object.prototype == Object.__proto__.__proto__); // true

function C(){ }
var c = new C();
console.log(Object.prototype == C.__proto__.__proto__); // true
console.log(Object.prototype == c.__proto__.__proto__); // true

var o = {};
console.log(Object.prototype == o.__proto__); // true

Object.prototype.tt361 = "my CSDN web log";
console.log(Object.tt361); // my CSDN web log
console.log(new Date().tt361); //my CSDN web log


说明:

对于chrome,对象的__proto__属性指向该对象的原型,该属性并不建议(不应该)在实际编程中使用。

原型链描绘了属性查找路径,js对象的属性查找规则如下:

1、在对象本身查找是否存在某属性,如果存在则停止查找并返回。

2、如果没找到则在原型中查找,如果存在则停止查找并返回。

3、如果仍没找到则在原型的原型中查找,如果存在则停止查找并返回。

4、重复步骤3直到找到该属性或遍历到Object.prototype,如果遍历到原型链尽头(Object.prototype)依然无法找到则返回undefined

js构造函数与原型继承

js函数本身就是对象(Object是一个函数),那么就是说js函数具有对象的所有特性。将函数作为构造函数使用(new操作符加函数,如new Object())可以生成新对象,新对象的原型(新对象的__proto__属性)是构造函数的prototype属性(并不是构造函数的__proto__)。如果使用同一构造函数创建多个对象,一般来说所有对象共享同一个原型(不共享的情况点击此链接修改构造函数原型——JavaScript中的对象(二))。

js构造函数就是js的普通函数,只不过一般来说将首字母大写以示区别。js的继承基本靠原型(还是有一些其他方法的,本文仅写原型),根据上文的描述,使用构造函数创建的对象的原型是构造函数的prototype属性所代表的对象,所以继承需要在prototype上下功夫。
举例如下:

function S(name){
this.name = name; // public变量
var mobilephone; // private变量
this.getMobilephone = function(){ // 此类方法会被创建多次,创建次数与对象数目相同
return mobilephone;
}
this.setMobilephone = function(arg){
mobilephone = arg;
}
this.total++;
}

// 父类构造函数prototype
S.prototype.total = 0 ; // 各对象共享的变量
S.prototype.getTotal = function(){ // 各对象共享的方法,该类方法仅创建一次
return this.total;
}

// 子类构造函数声明
function C(name){
S.call(this, name); // 构造函数和普通函数无异,借用父类构造函数做初始化。
var age;
this.getAge = function(){
return age;
}
this.setAge = function(arg){
age = arg;
}
}
// 子类构造函数prototype,子类prototype指向父类构造函数创建的对象主要是为了获得父类的prototype中的属性和方法。
C.prototype = new S();
C.prototype.constructor = C;

// C. 类变量
C.blog = "tt361";

var c = new C("name is tt361");
var c2 = new C("name is tt362");

c.setMobilephone("13JQQQQKKAA");
console.log(c.getMobilephone()); // 13JQQQQKKAA
console.log(c.getTotal()); // 2
console.log(c.name); // name is tt361
console.log(c instanceof C); // true
console.log(c instanceof S); // true


对于函数如果能写到原型中尽量写到原型中,写到原型中的函数仅创建一次,写到构造函数函数体中的函数会被创建多次。

js面向对象涉及到哪些变量

1.私有属性。上例构造函数S的mobilephone属性为私有属性,实现原理是闭包。

2.公有属性。在构造函数体内通过this设置的属性,因为构造函数中的this是指向正在创建的对象。

3.类变量。因为构造函数本身就是对象,给构造函数设置属性就是类属性。
4.所有对象共享但类不可访问的属性。一般情况下同一构造函数创建的多个对象共享同一实例,所以写在prototype中的属性所有对象共享。正如之前描述的“对象的原型指向是构造函数的prototype”,所以这种类型的属性并不是构造函数的属性。

js的多继承一般靠mixin实现,即属性复制,这就意味着正真的父类只有一个。

dojo的继承实现了C3算法,多继承时仅排序第一位的是真正的父类,其余的均mixin。

其他文章链接

你自认为理解了JavaScript?

JavaScript交流贴

js实现面向切面的编程(AOP)

JavaScript中的对象(一)

消除JavaScript中的if
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  js 原型 prototype 继承