美文网首页我爱编程
笔记:js原型、原型链与面向对象思想-封装

笔记:js原型、原型链与面向对象思想-封装

作者: 南京1865 | 来源:发表于2018-05-20 13:53 被阅读0次
    前言

    本来只是想深入研究下apply的用法,断断续续的查了不少的资料,结果牵扯出一大堆的知识,也就有了这篇文章写点心得,如有错误,欢迎留言指正。

    js原型与原型链

    在JS里,万物皆对象。JS的任何对象都有个属性_proto_
    Function也有_proto_对象,其constructor包含了一个指针,指回原构造函数,原构造函数在实例化后可以动态赋值;
    Function这个特殊的对象,除了这个_proto_外还有一个自己特有的属性prototype,这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法,可以理解为是静态的,它可以覆盖重载但不可以动态赋值;
    上述描述有点拗口,等后续代码详解后,可回头再来看这句话。
    先看代码:

    function Animal(){};
    var dog = new Animal();
    
    3.png
    上面定义了一个最简单的函数类,以及一个实例对象
    上诉讲的有点抽象,借用一个网友文章的代码来分析下原型和原型链
    function Dog(){};
    Dog.prototype.name = "小黄";
    Dog.prototype.age =  13;
    Dog.prototype.getAge = function(){
        return this.age;
    }
    var dog1 = new Dog();
    var dog2 = new Dog();
    dog2.name = "小黑";
    console.log(dog1.name); // 小黄 来自原型
    console.log(dog2.name); // 小黑 来自实例
    
    1.png
    面向对象思想-封装

    在诸如Java,C#等语言中都有一个类的概念,而我们知道,js是一个基于对象的语言,万物皆对象,但并没有类和实例的区分,不过js提供了一种原型prototype的概念,来实现面向对象的编程思想。

    先来看看js与其它面向对象编程语言写法的区别:

    //Java写法
    class Animal(){
        String name;
        public void get() {
            System.out.println("种类:"+name);
        }
    }
    Animal dog = new Animal()
    dog .name= "狗"
    dog .get();//种类:狗
    
    //js函数写法
    function Animal(species){
        this.name= name;
    }
    var dog = new Animal("狗");
    console.log("种类:"+dog.name);//种类:狗
    

    为了解决从原型对象生成实例的问题,Javascript提供了一个构造函数(Constructor)模式。
    所谓"构造函数",其实就是一个普通函数,但是内部使用了this指针。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。
    这里需要注意的是js构造函数Animal中的this指针,指向的是当前新创建的实例对象,后面我们会细讲;

    静态变量与动态变量

    先看下诉代码

    function Animal(species){
        this.name= name;
        this.specail = "哺乳动物";
    }
    var dog = new Animal("狗");
    dog.specail="哺乳动物-犬类"
    console.log(dog.specail);//哺乳动物-犬类
    var cat = new Animal("猫");
    console.log(cat .specail);//哺乳动物
    

    我们建立了Animal类,并且新建了两个实例dog和cat,dog和cat都有specail这个固有属性,但我们改了dog的specail属性后发现cat的specail的属性其实并没有修改,这两个实例的species属性是独立的,修改其中一个,不会影响到另一个,每一个实例对象,都有自己的属性和方法的副本。这类的属性,都可以理解为"动态变量"。动态变量不仅无法做到数据共享,也是极大的资源浪费,违背了类设计初衷的概念

    function Animal(name){
      this.name=name;
    }
    Animal.prototype.specail="犬类";
    var dog1 = new Animal("小黑");
    var dog2 = new Animal("小黄");
    dog1.specail = "动物";
    console.log(dog1.specail);//动物
    console.log(dog2.specail);//犬类
    

    这里我们将需要共享的数据和方法写入到构造函数Animal.prototype属性中充当"静态成员",自己私有的动态变量直接写入构造函数Animal中,而constructor。
    这里我们修改了dog1.specail,并没有影响dog2的specail属性,但我们确实对dog1的specail做了修改,看上去这个specail也不是"静态变量",至少我们是可以修改的。其实dog1.specail这时候指向的是Animal构造函数中的动态变量specail(为了避免混淆,我们在构造函数中没有定义specail属性,但js的机制是没有属性我们可以动态添加属性),dog1.specail指向Animal构造函数prototype的静态变量specail,两者使用不同的变量空间,属于不同的变量,至于为何有这样区别,我将在下篇文章中分解

    相关文章

      网友评论

        本文标题:笔记:js原型、原型链与面向对象思想-封装

        本文链接:https://www.haomeiwen.com/subject/tkkwdftx.html