1

声明:

概念性介绍会简单穿插,以过程式分析问题为主,便于提高实践的意义。

前言:

面向对象,早已烂熟于耳,以java为最,php5.6之后更是扩展了面向对象式开发(起先引入对象概念,没当个大方向,这下无心插柳柳成荫,繁盛起来了),js也基于对象式开发了。。。

开扒

但是,JS没有类的概念,是构造函数和原型链的方式来体现的。

我这里仅通过1个例子(有点懒~),尽量全面的分析下实现过程。

   /*=================定义“类”=================*/
   /*=======父类Foo=======*/
   function Foo(name,age){
     this.name = name;    //this是当前 [调用FOO()构造函数的] 对象,如果有子类Bar继承则代表子类对象
     this.age = age;      //this.参数名,则意味着各个对象,有属于自己的名字和年龄
    }                     //如上,是对象间差异化、独立性的体现
    
    /*父类Foo的原型*/
    Foo.prototype = {         //在此定义Foo对象公有的方法/属性,以节省内存、便于维护(性能上:如果把sayHi()方法定义在了Foo(name,age)构造函数中,等于说每new一个Foo或子类对象,每个对象在堆内存就会多占点空间来存放sayHi()方法,耗内存啊。)   
        sayHi:function(){     //公有方法  
            alert("Hi,I'm "+this.name);
        },
        guess:888             //公有属性
    };
    
    /*=======子类Bar=======*/
    function Bar(name,age,sex){    
        Foo.call(this,name,age); //等同于Foo.apply(this,[name,age]);你要初始化的东东,父类搞好了,只管调用
        this.sex = sex;          //Bar对象本身的特有属性
    }  
    /*子类Bar的原型是个Foo对象*/
    Bar.prototype = new Foo();   //Bar的原型类=Foo对象,意味着Bar对象能调到本身没有却在(Foo对象或者Foo.prototype)中存在的属性或方法
    
    //创建并调用
    var bar = new Bar('Lin',18,'male'); 
    bar.sayHi();
     

运行效果:

clipboard.png

案例补充说明:

    
    1)var bar = new Bar('Lin',18,'male'); 
    解释:
        new 一个 Bar对象,名为bar.
        bar就继承了Foo类的属性和Foo原型上的方法。
        
    2)bar.sayHi();    //可调
    解释:
        bar对象,首先自身查找是否有sayHi()方法,没有则bar.__proto__得到Bar.prototype;
        在Bar.prototype这个原型对象中继续查找,而前面我们已指定Bar.prototype = new Foo();
        则意味着是在Foo对象中查找,然而Foo对象本身没有sayHi()方法;
        则调用(new Foo()).__proto__得到原型对象Foo.prototype;
        继续在该原型对象Foo.prototype中查找sayHi()方法;
        终于找到了!!!返回结果吧。
    
    扩展:
       如果依然没找到,就会Foo.prototype.__proto__得到Object.prototype,
       Object.prototype本身没有sayHi()方法,就会
       Object.prototype.__proto__得到null.
       null是最顶级的对象。在该对象中,查无此方法,就报错了;查无此属性,就undefined.
   
 

涉及术语:

原型链
    各构造函数,各有与之相对应的原型;
    类之间的继承,就暗暗的把原型间的关系统筹在了一起。
    顶层原型上方法或属性的查找过程,就是依靠着原型间的这种关系,一层一层的向上查找的。

原型继承
     Bar.prototype = new Foo(); 

借用继承
     Foo.call(this,name,age); //Foo.apply(this,[name,age]);

组合继承
     function Bar(name,age,sex){    
        Foo.call(this,name,age);
        this.sex = sex;                
     }  
    Bar.prototype = new Foo();  

    现象式总结:        
        仅是原型继承,子类Bar确实可调用(父类Foo的属性和原型上的方法)了,但实例化出来的Bar对象就不独立了。意味着某个对象对Foo构造函数中的属性或方法的修改,会影响到其他对象调用的结果.
        简言之,子类可调父类了,但是实例化的对象不独立。

        仅是借用继承,子类bar实例化的对象是独立的,对象间不受影响,但父类原型上的方法调不了了.
   
        推荐组合继承,既保证了对象间的独立性,又能调用到父类的原型上的方法。



福利:

1.原型链图示(网上找的,看懂即可跳过上述内容)

clipboard.png
该图把原型和构造函数间的关系理的很清楚,可在Google浏览器的console运行demo并查看对象下原型间的关系。

2.JS高级部分,之前看的是ali的Bosn的JavaScript深入浅出

如有不适内容,欢迎指正。


Lin945
211 声望6 粉丝

技术沉淀还是很有必要的,尽量多写写。