js中的原型和继承

博客搬家:由于各种原因,我现在的博客将首发于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


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值