欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

js继承解读

程序员文章站 2022-06-07 19:15:41
...

 

一直搞不懂js的继承机制,虽然知道什么 js继承是由原型prototype和构造函数constructor实现继承!看了很多文章还是这样模糊:为什么这样,为什么那样,为什么为什么为什么!... ... 。不懂为什么,当然就不是真正理解,记也记不住。(即使记住也是没用的)。不过经过自己反复测试后终于茅塞顿开。现拿来和大家分享下。js继承解读
            
    
    博客分类: js  

最难理解的当然就是prototype和constructor,这两个都理解,其他自然不在话下。

prototype原型prototype方式的属性查询可以理解为js独有的一个机制

 

就是说,js读取一个对象属性的时候,对象本身若找不到,则会去读取构造函数的prototype对象的同名属性,然后若还是找不到,则去读取Object构造函数的prototype对象的同名属性——即所谓的“继承”...

 

如果要实现继承关系A->B,则想要A继承B的属性,则需要自己去维护这个prototype对象。

——这就涉及一些技巧。

 

constructor:它是每个对象都有的一个属性,它引用初始化这个对象时候的构造函数。js这也是独有的一个机制。它有默认值。

你可以不去维护它,这个时候你不去用它,也不会有任何问题。但是,当你想让它正确工作的时候,则就需要我们去维护它了!

——这就涉及一些技巧。

 

懂得这两个技巧后,就可以说你理解了js的继承原理!

 

下面是测试代码,大家测试的时候把相应的地方的注释打开,把不想要的地方注释起来就ok了:

 

/************  NOTICE START :基础知识 ************
1 对于函数
每个函数都一个prototype 属性,它引用预定义的原型对象———— prototype在使用new操作符把函数作为构造函数时起作用!
—— 具体什么作用呢?后面会讲到

2 对于对象
js中,每个对象都有一个constructor属性,他引用初始化这个对象时候的构造函数
eg. var d = new Date(); d.constructor == Date;// true

———— 注意,这个引用在内建对象时候是自动的,js内部已经维护好了

=================================================================
但是对于自定义类,则需要自己维护!!!  而在继承的时候可能还会出问题,所以就需要自己修改
=================================================================
因为自定义类的对象的constructor默认指向Function的构造函数:funciton Function(){ [native code] }

而这可能不是想要的。
所有js的类继承于Object,—— 这其实是js内部做了一些工作实现的



js用原型prototype和构造函数constructor实现继承!

************  NOTICE END ************/


/**
*	开始测试
*/

//var d = new Date(); 
//alert(d.constructor==Date);// true 



//函数 ------ 其实又可当做对象的构造函数
var Person = function(name,age){
	this.name = name;
	this.age = age;
	this.mc = "MMCC";
	this.toString = function (){
		return "Person:name="+this.name+"/age="+this.age;
	};
};
//alert(Person.constructor);//  funciton Function(){ [native code] }
//alert(Person);// 即上面函数代码

Object.prototype.toString = function(){
	return " Object.prototype ";
};

//alert(Person.prototype); //显示 [object Object]—— 这是默认的prototype
//alert(Object.prototype); //显示 [object Object]
//alert(Object);
//alert({});

/**
 * 
 * Man Class Defination. Try to extends the Person Class
 * @param name
 * @param age
 * @param work
 * @param hobby
 * @return
 */
var Man = function(name,age,work,hobby) {
	this.work = work;
	this.hobby = hobby;
	Person.call(this,name,age);// 这样做的目的只有一个:就是借用Person函数初始化name/age。除此之外绝无他意
	// 我们可以把这种调用方式叫做构造函数链: 构造函数中调用另一个构造函数
	
	this.toString = function() {
		return "Man:name="+this.name+"/age="+this.age;
	};
};


// 注意new Person()这里不需要参数
Man.prototype = new Person();//  这个的意义 ???  
//这样之后Man.prototype可以使用Person的方法了!!!———— 对,就是这样的方式,实现了继承!!!———— 当然如果要使用Person的name等属性就会得到undefined
//因为 new Person();出来的对象name尽管存在,但未赋值。。。

delete Man.prototype.name;// 可以删去,也可以不删去。影响不是很大。。
//alert(Man.prototype.name);
delete Man.prototype.age;


//alert(Man.constructor);
Person.prototype.wealth = function() {
	return this.name +" * Person wealth * "+this.age;
};
Man.prototype.wealth = function() {
	return this.name +" * Man wealth * "+this.age;
};
Person.prototype.health = function() {
	return this.name +" * Man health * "+this.age;
};

var p = new Person("Chen",25);

//alert(p.constructor);// 实际上会去通过原型链的方式查找constructor,最终找到的是类的原型的constructor属性
//alert(p.prototype);// undefined
//alert(Person.constructor); // 这个和上面p.constructor结果不同, 它结果为 Function(){ [native code] } __ why

var man = new Man("luo",27,"IT","shopping");
//alert(man.constructor);// 实际上会去通过原型链的方式查找constructor,最终找到的是类的原型的constructor属性
//alert(man.prototype);// undefined
//alert(Man.constructor); // 这个和上面man.constructor结果不同, 它结果为 Function(){ [native code] }



//alert(Man.prototype);
//alert(man);

alert(man.health());
//alert(p.wealth());

//Man.prototype.constructor = Man;//这样之后,使一个class的constructor属性指向 它的构造函数 --- 这样又有什么好处呢?有什么必要呢?
// ———— 使Man类的原型的constructor正确的指向 它的构造函数Man,


//这样做的必要性在于,之后我们可能需要“正确”的调用Man函数的constructor属性
//alert(Person.prototype.constructor);// function(name,age){。。。 }
//alert(Man.prototype.constructor);// function(name,age,work,hobby) {。。。 }


// 下三者都为 true,这是符合继承常理,同时说明子类编写成功
//alert(man instanceof Object);这个想当然是会一直成立的
//alert(man instanceof Person);//这个只有在设置Man.prototype = new Person();才会成立
//alert(man instanceof Man);//这个其实是会一直成立的,不用担心这个


/**==============  单层继承的时候,可以通过为子类原型对象添加一个名为superclass的属性,来简化继承
*/
var Man2 = function(name,age,work,hobby) {
	this.superclass(name,age);
	this.work = work;
	this.hobby = hobby;
};
//然后在new Man2之前
Man2.prototype.superclass = Person;
//然后就可以使用了:
var m2 = new Man2("luok",22,"IT","Think");
alert(m2.name);



// 一个规则是 一个类的原型的constructor 需要指向 它的构造函数 。 否则呢

// 每个函数都会有一个 prototype 的属性 --- 默认为一个Object的对象,即Object类的实例。 为内建的代码

// 函数的原型对象


// constructor 
/**可以 直接Man.constructor 、 Man.prototype.constructor 区别:*
 * Man.constructor 为Man函数的构造函数—— Function(){ [native code]}
 * Man.prototype.constructor 当然就是Man的原型对象的构造函数
 */





 

 总结:

其实js实现继承有多种方式。据说是三种:(一)对象冒充 (二)原型prototype链方式 (即本文介绍的这种) (三)原型prototype拷贝方式

这三种的介绍可以在博文中找到:http://www.iteye.com/topic/70028

不过个人认为,(一)(三)的方式根本不能算是真正的继承。用原型prototype和构造函数constructor实现的继承才是真正的继承。

 

再次提一下前面讲的两个技巧。相信大家测试后也知道是什么技巧了。这里再说明一下,其实主要就是这两个句:

1——Man.prototype = new Person();

2——Man.prototype.constructor = Man;