JavaScript 原型解析

大憨熊 提交于 2020-03-19 12:43:00

1、什么是对象?
     javascript中除了null和undefined之外都是Object的实例。

        在Javascript中, 每定义一个函数, 将伴生一个原型对象. 原型就是用来为同一类对象共享类型信息的, 即每一个通过该函数创建的对象都可以共享函数原型上的信息.
        也就是说, 当我们定义一个函数的时候, 实际上得到了两个对象, 一个函数对象, 一个原型对象.

        prototype就是“一个给类的对象添加方法的方法”,使用prototype属性,可以给类动态地添加方法,以便在JavaScript中实现“继承”的效果。

        prototype为我们提供了方便,使我们可以在类定义完成之后,仍可以随时为其添加方法、属性,随时添加随时使用——也就是prototype的定义具有动态性。
     

   //用构造函数生成实例对象,有一个缺点,那就是无法共享属性和方法。
        function DOG(name) {
            this.name = name;
            this.species = '犬科';
        }
        var dogA = new DOG('大毛');
        var dogB = new DOG('二毛');
        dogA.species = '猫科';
        alert(dogB.species); //


        //不仅无法做到数据共享,也是极大的资源浪费。
        function Cat(name, color) {
            this.name = name;
            this.color = color;
            this.type = "猫科动物"; //不变的属性
            this.eat = function () { alert("吃老鼠"); };
        }

       
2、什么是原型属性与原型对象?
        原型属性是一个指针,指向一个对象;而这个对象的用途是可以包含由特定类型的所有实例共享的属性和方法。
        原型对象就是一个对象,具有一些属性和方法。


3、原型属性与原型对象的关系
        每个构造函数都有一个原型对象和一个原型属性(prototype),原型属性指向原型对象,
        原型对象都包含一个指向构造函数的指针(constructor属性),而实例都包含一个指向原型对象的内部指针
       

 Prototype模式       

 DOG.prototype = { species: '犬科' };
        DOG.prototype.species = '猫科';


        function Cat(name, color) {
            this.name = name;
            this.color = color;
        }
        //所有实例的type属性和eat()方法,其实都是同一个内存地址,指向prototype对象
        Cat.prototype.type = "猫科动物";
        Cat.prototype.eat = function () { alert("吃老鼠"); };

 

        function ClassA() {
            this.a = 'a';
        }
        function ClassB() {
            this.b = 'b';
        }
        ClassB.prototype = new ClassA();
        var objB = new ClassB();
        alert(objB.a);

        ClassB.prototype.a = 'changed!';
        alert(objB.a);
        var aa = new ClassA();
        alert(aa.a);
        //javascript中的每个对象都有prototype属性,Javascript中对象的prototype属性的解释是:返回对象类型原型的引用。A.prototype = new B();

        var a = {
            name: 'tang',
            sayName: function () {
                return this.name;
            }
        };

        var b = {
            name: 'xu',
            age: '2',
            sayAge: function () {
                return this.age;
            },
            __proto__: a//在Chrome下测试
        };
        console.log(b.sayName());

原型链
      

  function foo() {
            this.add = function (x, y) {
                return x + y;
            };
        }

        foo.prototype.add = function (x, y) {
            return x + y + 10;
        };

        Object.prototype.subtract = function (x, y) {
            return x - y;
        };

        var f = new foo();
        alert(f.add(1, 2));
        alert(f.subtract(1, 2));
        //属性在查找的时候是先查找自身的属性,如果没有再查找原型,再没有,再往上走,一直插到Object的原型上,
        //        test [Bar的实例]
        //          Bar.prototype [Foo的实例] 
        //            { foo: 'Hello World' }
        //               Foo.prototype
        //                 {method: ...};
        //                    Object.prototype
        //                      {toString: ... /* etc. */};

如果extendClass中本身包含有一个与baseClass的方法同名的方法会怎么样?
      

  function baseClass() {
            this.showMsg = function () {//对象方法
                alert("baseClass::showMsg");
            };
        }

        //        baseClass.showMsg = function() {  类方法
        //            alert("baseClass::showMsg static");
        //        };

        function extendClass() {
            this.showMsg = function () {
                alert("extendClass::showMsg");
            };
        }

        extendClass.prototype = new baseClass();
        instance = new extendClass();

        instance.showMsg(); //显示extendClass::showMsg

        //函数运行时会先去本体的函数中去找,如果找到则运行,找不到则去prototype中寻找函数。或者可以理解为prototype不会克隆同名函数。

        //如果我想使用extendClass的一个实例instance调用baseClass的对象方法showMsg?
        extendClass.prototype = new baseClass();
        instance = new extendClass();

        var baseinstance = new baseClass();
        baseinstance.showMsg.call(instance); //显示baseClass::showMsg    将instance当做baseinstance来调用,调用它的对象方法

继承机制
       

 //javascript的方法可以分为三类:类方法,对象方法,原型方法。
        function People(name) {
            this.name = name;
            //对象方法
            this.Introduce = function () {
                alert("My name is " + this.name);
            };
        }
        //类方法
        People.Run = function () {
            alert("I can run");
        };
        //原型方法
        People.prototype.IntroduceChinese = function () {
            alert("我的名字是" + this.name);
        };

        //测试
        var p1 = new People("Windking");
        p1.Introduce();
        People.Run();
        p1.IntroduceChinese();


        //定义Person类
        function Person(name, age) {
            this.name = name;
            this.age = age;
        };
        //定义两个所有Person对象共享的方法
        Person.prototype.showMe = function () {
            return " Person \r\n Name: " + this.name + "\r\n Age: " + this.age + "\r\n";
        };
        //alert(Person.valueOf());  //测试
        //alert(new Person("哈哈",18).showMe());    //测试
        Person.prototype.toString = function () {
            return "Person Object";
        };

        //定义Student类
        function Student(name, age, sid) {
            //Person.apply(this, arguments);  //就近原则, this表示Person对象, 使用了apply, 故参数为数组
            this.sid = sid;
        };

        //实现继承, 替换Student的原型(子类函数的原型对象被父类的对象实例替代)
        Student.prototype = new Person();
        Student.prototype.toString = function () { //覆盖基类的方法
            return "Student Object";
        };

        var mike = new Person("mike", 30);
        var john = new Student("john", 23, "201008");

        alert(mike.showMe());   //showMe方法可以被子类使用
        alert(john.showMe());
        alert(mike.toString());
        alert(john.toString()); //重写基类的方法

Prototype模式的验证方法

        //为了配合prototype属性,Javascript定义了一些辅助方法   

        //1、isPrototypeOf()用来判断,某个proptotype对象和某个实例之间的关系
        alert(Cat.prototype.isPrototypeOf(cat1)); //true

        //2、hasOwnProperty()用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性
        alert(cat1.hasOwnProperty("name")); // true
        alert(cat1.hasOwnProperty("type")); // false

        //3、in 运算符可以用来判断,某个实例是否含有某个属性,不管是不是本地属性。
        alert("name" in cat1); // true
        for (var prop in cat1) { alert("cat1[" + prop + "]=" + cat1[prop]); }     


初步了解Js原型,有什么不对之处还请批示!希望在接下来的日子里能够为大家分享更多js原型的知识,让我们共同学习、共同进步!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!