Write the Code. Change the World.

6月 28

前言

js是一个自由,一切皆对象的脚本语言。如果说要去找面向对象的原生的packageclass,那是没有的。但是,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,cryPeople的实例方法。 所谓实例,就是要去new它。实例方法,只有实例能调用,静态方法,只有对象能调用。至于saycry也是有区别的。

  1. 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

通过打印可以看出。ManWoman继承People。继承只是继承了其实例属性和方法。

  1. 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的原型继承是引用原型,而不是复制原型。当修改原型时,会导致实例发生变化。即使对象创建(实例化)在原型修改之前,上述改变一样生效。

最后两句打印可以看出,实例属性的修改,却不能作用于原型。

  1. 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却是原型里的。

  1. 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) ["再来一首", "海洋之心", "英雄救美"]

还是证明,子类如果没有写入属性,引用的还是原型。当子类写入属性后,引用的不再是原型了。相当于重写了吧。

参考

http://blog.csdn.net/zhaozheng7758/article/details/7760433

发表评论

电子邮件地址不会被公开。 必填项已用*标注