1

推荐一篇太极客(Very Geek)的博客。

最近在看《编写高质量代码-web前端修炼之道》,写了3篇博客,写写感想。


第一篇写了关于javascript封装以及模块化插件设计。

第二篇写了关于javascript面向对象思想以及原型和构造器。

第三篇主要写关于javascript的编写风格以及细节设计问题。


继上一篇javascript进阶,关于js插件开发的mvc思想,这次继续写篇博客,主要说说关于javascript的面向对象思想。


一、关于javascript类的定义

    首先,javascript是面向对象语言,但是js没有class类,而是通过:

new funName( );

来声明。

    javascript使用基于原型的语言,通过new实例化对象,其属性和行为来自两部分,原型和构造函数。

    当我们声明一个类时,同时生成了一个对应的原型。例如我们声明了:A这个类,会同时生成与这个类对应的原型。A.prototype指向原型,原型可以通过coustructor指向构造函数。写个代码你就懂。

function A(){
    }
    var x = A.prototype;
    var y = x.constructor;
    alert(y==A);    //return true;
    console.log("也就是说A.prototype.constructor=A");

    当我们声明类时候,新的构造函数会把旧的prototype原型给覆盖掉。
给你看个例子。

function A(){
        this.a="属性a";
        this.b="属性b";
        this.fun1=function(){
            alert("这是函数对象1");
        };
        this.fun2=function(){
            alert("这是函数对象2");
        };
    }

    var B = new A();
    B.fun1=function(){
        alert("你是笨蛋!!");
    };

    B.fun1(); //结果为alert("你是笨蛋!!");
    console.log("也就是说构造函数声明的属性会覆盖原型的函数");
```

从上面的例子里我们可以看到,原型中的函数是会随声明的属性或者方法是会被实例化过程声明覆盖。

    一般来说,我们习惯在构造函数里放属性,在原型里面放方法。给你个例子看看:

/*===========构造函数放属性,原型里放方法============*/
function A(){
    this.a="属性a";
    this.b="属性b";
}

A.prototype={
    fun1:function(){
        console.log("这是函数对象1,我们把它放在原型里");
    },
    fun2:function(){
        console.log("这是函数对象2,我们同样也把它放在原型里");
    }
};

var B = new A();
B.fun1();
B.fun2();
console.error("这样就整洁多了。");
<br>
**二、公有和私有**
&nbsp;&nbsp;&nbsp;&nbsp;js里面没有类似php一样的权限设置,可是如果我想要一个变量是私有属性怎么办?需要注意的一点是,只要写在原型里的不管是属性还是方法,都是公有性的。所以要怎样才能让一个变量私有化呢?看看例子:



```js
/*===============原型中的共有域和私有域================*/
    function A(){
        var a="属性a是私有的,在类外面你是调用不到的。";
        this.b="属性b是公有的";

        var fun1=function(){
            console.log("函数对象1是私有的,在类外面你是调用不到的。");
        };
        this.fun2=function(){
            console.log("函数对象2是共有的");
        };
    }

    A.prototype={
        fun3:function(){
            console.log("这是函数对象3,在原型里的,只能是公有的");
        }
    };

    var B = new A();
    B.a;        //not found a;
    B.b;    //返回正常
    B.fun1();   //not found
    B.fun2();
    B.fun3();

    需要强调的一点是,原型中的属性和方法,只存在一份,是公用的,在实例化的时候,并不会在复制一遍。所以,做到了代码的重复利用,但是,如果把属性和方法都放在构造函数里,也同时导致了代码修改的麻烦。

    问题出来了,你想下,那我们如果有一个属性,很多函数都要调用他,想把它放在原型里,但是又不想把让它公有友化,怎么破?怎么破?

答案是:没法破。

于是,命名规则出来了,我们规定,在命名前对一个下划线,表示私有属性。例如:

    A.prototype={
    _value:"我们规定,这个属性为私有属性(ps:其实它就是公有的)";
};

于是有些比较倔强的码农们就提出来了一套新方案。请看:

/*=============私有与公有域==============*/
    function A(){
        this.a="属性a是公有的。";
        this.b="属性b是公有的";
        this.set_a=function(value){
            this.a=value;
        };
        this.get_a=function(){
            return this.a;
        };
        this.call=function(name){
            console.log(this.get_a(name));
        };
    }

    var B = new A();
    B.set_a("我把值改了");
    B.call("a");    //return   我把值改了

看了好别扭,但是这样你就可以在属性或者方法的值改变时候,直接留下回调函数。



三、继承

     我在上一篇博客封装过关于继承的函数。因为在javascript里面没有继承,但是继承的思想又是存在于面向对象语言里。

如果没有函数,我们要怎么继承?最笨的是,类A和类B,我把A的所有属性和方法抄一遍。好傻啊,不适合。

  • 有一种想法,看看下面的代码:
/*==================关于声明中的this==================*/

    function A(){
        this.a="属性a是公有的";
        this.b="属性b是公有的";
    }
    A.prototype={
        say:function(){
            console.log(this.a);
        }
    };

    function B(value){
        this.a=value;
        A();
    }
    var C = new B();    //你以为这么就能继承了么??天真了,试试看
    C.say();    //return undefind

哈哈,知道了吧,想知道为什么吗?

js函数调用有两种方法,

第一种是直接调用,此时,它作为函数;

第二种是通过实例化,构造函数调用;

没问题啊,但是,它们返回的this对象就不同了,第一种,作为函数调用,返回的是window对象,但是第二种调用返回的是实例对象本身。所以说不能直接调用继承。

我们把this指向改下吧:

function A(){
        this.a="属性a是公有的";
        this.b="属性b是公有的";
    }   

    A.prototype={
        say:function(){
            console.log(this.a);
        }
    };

    function B(value){
        A.call(this,value);
        A();
    }

    var C = new B();    //可以了
    C.say();    //找到值了

  • 还有一种想法:我们试试
/*================相同原型继承==================*/

    function A(){
        this.a="属性a是公有的";
        this.b="属性b是公有的";
    }

    A.prototype={
        say:function(){
            console.log(this.a);
        }
    };
    var B =function(){
    };
    B.prototype = A.prototype;
    B.prototype.test=function(){
        console.log("继承后添加的函数");
    };

    var C = new B();
    C.test();   //return  console.log("继承后添加的函数");

    var D = new A();
    D.test();   //return  console.log("继承后添加的函数");

为什么??为什么我只是在B中添加了test方法,但是我在A中也感染了??

因为javascript在赋值时候,如果判断出值是布尔,字符串,数值型等基本数据类型,会直接复制值,但是,赋值,数组,方法,对象等复杂数据,通常都会地址复制,所以,把A的原型也改了。

我们再试试,改回来,哪错改哪。

function A(){
        this.a="属性a是公有的";
        this.b="属性b是公有的";
    }

    A.prototype={
        say:function(){
            console.log(this.a);
        }
    };

    var B =function(){
    };
    B.prototype = A.prototype;
    C.prototype.constructor=A;
    B.prototype.test=function(){
        console.log("继承后添加的函数");
    };

    var C = new B();
    C.test();   //return  console.log("继承后添加的函数");

    var D = new A();
    D.test();   //return not defind

这样就好了。


最后给下,extend的具体函数把,这样就不要一个一个地来弄了,你只要调用函数就好了。


function extend(subClass, superClass){ var C=function(){}; C.prototype=superClass.prototype; subClass.prototype=new C(); subClass.prototype.constructor=subClass; subClass.superClass=superClass.prototype; if(superClass.prototype.constructor == Object.prototype.constructor){ superClass.prototype.constructor=superClass; } } /*=====搞定了=====*/


    总结下吧。今天主要就是写了一些关于javascript面向对象的思想,还有原型和构造函数的关系。
    接下来还有最后一篇《javascript进阶(三)》,主要是一些javascript原型与细节分享。





写下最近的在做什么吧:

  • 看了《javascript高质量代码》;

  • 给新生培训了下,写了篇博客;

  • 看了一点点的php数据结构


写写接下来做什么吧:

  • 《python基础教程》(华哥的项目,日志分析系统)

  • 《精通android 4》(东哥)

  • 期末了,要开始复习了。


(睡觉去。。。)

夏日小草

2013/12/3 1:57:07

(ps:如果有出错,求指点出来。)


夏日小草
2.2k 声望139 粉丝

[链接]