前言
js
是一个自由,一切皆对象的脚本语言。如果说要去找面向对象的原生的package
,class
,那是没有的。但是,js
可以去封装。
了解prototype
w3school
这样定义的:prototype
属性使您有能力向对象添加属性和方法。这个是动态的,也就是什么时候都可以。每个对象都有prototype属性,它本身也是一个对象。如此循环下去就形成了一个prototype链,这个链当遇到链中的prototype为null
时即中止(Object默认的prototype为null)。
1. demo1。
(function(name){
var People = function(name, age){
this.name = name;
this.age = age;
this.cry = function(){
console.log(this.name + "哭了!");
}
}
People.prototype = {
say:function(value){
console.log(this.name + "说:" + value);
}
}
People.smile = function(){
console.log(this.name + "笑了!");
}
try
{
People.smile();
People.cry();
People.say("给我一个理由忘记!");
}
catch(e)
{
console.log(e);
}
try
{
var man = new People(name, 32, 168);
man.say("仿佛有痛楚");
man.cry();
man.smile();
}
catch(e)
{
console.log(e);
}
})('vini');
打印结果:
People笑了!
(index):232 TypeError: People.cry is not a function
vini说:仿佛有痛楚
vini哭了!
(index):244 TypeError: man.smile is not a function
通过打印可以看出。如果把People
函数看做一个类,smile
则是People
的静态方法,而say
,cry
为People
的实例方法。 所谓实例,就是要去new
它。实例方法,只有实例能调用,静态方法,只有对象能调用。至于say
和cry
也是有区别的。
- demo2。
(function(name){
var People = function(name, age){
this.name = name;
this.age = age;
this.cry = function(){
console.log(this.name + "哭了!");
}
}
People.prototype = {
say:function(value){
console.log(this.name + "说:" + value);
}
}
People.smile = function(){
console.log(this.name + "笑了!");
}
var Man = function(){
this.gender = "男";
}
Man.prototype = new People("七月羽歌", 32);
var Woman = function(){
this.gender = "女";
}
Woman.prototype = new People("白河依依", 27);
var man = new Man();
man.say("神奇动物在哪里")
console.log([man.name, man.age, man.gender, String(man.smile), String(Man.smile)].join(" "));
var woman = new Woman();
woman.say("神奇女侠");
console.log([woman.name, woman.age, woman.gender, String(woman.smile), String(Man.smile)].join(" "));
})('vini');
打印结果:
七月羽歌说:神奇动物在哪里
七月羽歌 32 男 undefined undefined
白河依依说:神奇女侠
白河依依 27 女 undefined undefined
通过打印可以看出。Man
和Woman
都继承
了People
。继承只是继承了其实例属性和方法。
- demo3。
(function(name){
var People = function(name, age){
this.name = name;
this.age = age;
this.cry = function(){
console.log(this.name + "哭了!");
}
}
People.prototype = {
say:function(value){
console.log(this.name + "说:" + value);
}
}
People.smile = function(){
console.log(this.name + "笑了!");
}
var Man = function(){
this.gender = "男";
}
var man = new Man();
console.log(man.name);
Man.prototype.name = "寂寞";
console.log(man.name);
man.name = "寂寞寂寞就好";
console.log(man.name);
console.log(Man.prototype.name);
})('vini');
打印结果:
七月羽歌
寂寞
寂寞寂寞就好
寂寞
通过前两句打印结果可以看出。js
的原型继承是引用原型,而不是复制原型。当修改原型时,会导致实例发生变化。即使对象创建(实例化)在原型修改之前,上述改变一样生效。
最后两句打印可以看出,实例属性的修改,却不能作用于原型。
- demo4
(function(name){
var People = function(name, age){
this.name = name;
this.age = age;
this.cry = function(){
console.log(this.name + "哭了!");
}
}
People.prototype = {
say:function(value){
console.log(this.name + "说:" + value);
}
}
People.smile = function(){
console.log(this.name + "笑了!");
}
var Man = function(){
this.gender = "男";
}
Man.prototype = new People("七月羽歌", 32);
var man1 = new Man();
var man2 = new Man();
console.log(man1.name == man2.name);
console.log(man1.cry == man2.cry);
console.log(man1.say == man2.say);
Man.prototype.name = "变形金刚";
console.log(man1.name, " ", man2.name);
man1.name = "神奇动物在哪里";
man2.name = "神奇女侠";
console.log(man1.name, " ", man2.name);
Man.prototype.name = "变形金刚";
console.log(man1.name, " ", man2.name);
})('vini');
打印结果:
true
true
true
变形金刚 变形金刚
神奇动物在哪里 神奇女侠
神奇动物在哪里 神奇女侠
通过前三条打印结果,更进一步的证明了。子类对象都执行同一个原型的引用,所以子类对象中的原型成员实际是同一个。
倒数第二条结果证明了。子类对象的写操作只访问子类对象的成员,相互之间不产生影响。
倒数第三条结果证明。如果改变的是原型,则所有实例都会发生变化。如果再看最后一条结果。则说明当子类改变了,再改变原型。子类读的却不再是原型了。
写一定是写子类,读则要看是否子类中有,若有则读子类,若无则读原型。为了进一步证明,读先读子类,再读原型。
请看下边的code。
(function(name){
var People = function(name, age){
this.name = name;
this.age = age;
this.cry = function(){
console.log(this.name + "哭了!");
}
}
People.prototype = {
say:function(value){
console.log(this.name + "说:" + value);
}
}
People.smile = function(){
console.log(this.name + "笑了!");
}
var Man = function(){
this.gender = "男";
this.age = 18;
}
Man.prototype = new People("七月羽歌", 32);
var man = new Man();
console.log(man.age, " ", man.name);
Man.prototype.age = 16;
Man.prototype.name = "神奇动物在哪里";
console.log(man.age, " " ,man.name);
})('vini');
打印结果:
18 "七月羽歌"
18 "神奇动物在哪里"
看到子类中,也定义了age属性。这个时候,无论原型怎么操作age,子类始终读子类中的age。而name却是原型里的。
- demo5。
(function(name){
var People = function(name, age){
this.name = name;
this.age = age;
this.gift = [];
this.cry = function(){
console.log(this.name + "哭了!");
}
}
People.prototype = {
say:function(value){
console.log(this.name + "说:" + value);
}
}
People.smile = function(){
console.log(this.name + "笑了!");
}
var Man = function(){
this.gender = "男";
this.age = 18;
}
Man.prototype = new People("七月羽歌", 32);
var man1 = new Man();
var man2 = new Man();
man1.gift.push("再来一首", "海洋之心", "英雄救美");
console.log(man1.gift, man2.gift);
man1.gift = ["鲜花", "狗粮"];
console.log(man1.gift, man2.gift);
})('vini');
打印结果:
(3) ["再来一首", "海洋之心", "英雄救美"] (3) ["再来一首", "海洋之心", "英雄救美"]
(2) ["鲜花", "狗粮"] (3) ["再来一首", "海洋之心", "英雄救美"]
还是证明,子类如果没有写入属性,引用的还是原型。当子类写入属性后,引用的不再是原型了。相当于重写
了吧。