zoukankan      html  css  js  c++  java
  • 对JavaScript中继承机制的理解

    一、JavaScript中原型对象(构造函数)和实例对象以及protoType的关系:

    image_thumb5

    二、JS中通过构造函数实现继承的五种方式:

    1、使用apply()或call()方法:
    <script type="text/javascript">
                function Animal () {
                    this.species = "动物";
                }
                Animal.prototype.categroy = "猫科";
    
                function Cat (name, color) {
                    //Animal.apply(this, arguments);
                    Animal.call(this, name, color);
                    this.name = name;
                    this.color = color;
                }
    
                var cat1 = new Cat("tom", "yellow");
                alert(cat1.species);
                //不能继承prototype上的属性和方法
                alert(cat1.categroy);//undefined
            </script>
    2、使用prototype对象
    <script type="text/javascript">
                function Animal () {
                    this.species = "动物";
                }
                Animal.prototype.catagory = "猫科";
    
                function Cat (name, color) {
                    this.name = name;
                    this.color = color;
                }
                Cat.prototype.weight = "30";
    
                Cat.prototype = new Animal();
                alert(Cat.prototype.constructor == Animal);//true,此时constructor指向Animal
                Cat.prototype.constructor = Cat;//将constructor指回Cat
    
                var cat1 = new Cat("tom", "yellow");
                alert(cat1.constructor == Cat);//true,实例的constructor默认调用prototype对象的constructor属性
    
                //能继承构造函数内和prototype上的所有属性和方法
                alert(cat1.species);
                alert(cat1.catagory);
    
                //Cat.prototype上原有的属性和方法将被清除
                alert(Cat.prototype.weight);
            </script>

    某一对象使用prototype对象实现继承另一对象后,原对象的constructor属性指向被继承的另一对象,此时必须将原对象constructor属性指回原对象,否则会导致继承链的紊乱。设计继承时务必遵守。如下:

    o.prototype = {};
    o.prototype.constructor = o;
    3、直接继承prototype对象
    <script type="text/javascript">
                function Animal () {
                    this.species = "动物";
                }
                Animal.prototype.catagory = "猫科";
    
                function Cat (name, color) {
                    this.name = name;
                    this.color = color;
                }
                Cat.prototype.weight = "30";
    
    
                Cat.prototype = Animal.prototype;            
    
                /**此时constructor指向Animal**/
                alert(Animal.prototype.constructor);
                alert(Cat.prototype.constructor);
                /****************************************/
    
                Cat.prototype.constructor = Cat;//将constructor指回Cat
                var cat1 = new Cat("tom", "yellow");
                alert(cat1.constructor == Cat);//true,实例的constructor默认调用prototype对象的constructor属性
                alert(cat1.catagory);
    
                /**直接使用prototype对象继承后,Animal.prototype.constructor和Cat.prototype.constructor指向同一对象**/
                /**应此对Cat.prototype的修改也会反应到Animal.prototype上**/
                alert(Animal.prototype.constructor == Cat);//true
                Cat.prototype.catagory = "猫科动物";
                alert(Animal.prototype.catagory);//猫科动物
                /***********************************/
    
                //不能继承构造函数内的属性和方法
                alert(cat1.species);//undefined
            </script>
    4、间接继承prototype对象
    <script type="text/javascript">
                function Animal () {
                    this.category = "猫科";
                }
                Animal.prototype = {species: "动物"};
    
                function Cat (name, color) {
                    this.name = name;
                    this.color = color;
                }
    
                var f = function() {}
    
                f.prototype = Animal.prototype;
    
                Cat.prototype = new f();
                Cat.prototype.constructor = Cat;//将constructor指回Cat
    
                var cat1 = new Cat("tom", "yellow");
                alert(cat1.constructor == Cat);//true,实例的constructor默认调用prototype对象的constructor属性
                alert(cat1.species);
                //不能继承构造函数内的属性和方法
                alert(cat1.category);//undefined
    
                /**使用空对象间接继承后,对Cat.prototype的修改不会反应到Animal.prototype上**/
                alert(Animal.prototype.constructor == Cat);//false
                Cat.prototype.species = "哺乳动物";
                alert(Animal.prototype.species);//动物
                /***********************************/
            </script>

    对上面间接继承方法的封装如下:

    <script type="text/javascript">
                function extend(child, parent){
                    var f = function() {};
                    f.prototype = parent.prototype;
                    child.prototype = new f();
                    child.prototype.constructor = child;
                    //在子对象上打开一条通道,可以直接调用父对象的方法。这一行放在这里,只是为了实现继承的完备性,纯属备用性质。
                    child.uber = parent.prototype;
                }
                function Animal () {
                }
                Animal.prototype = {species: "动物"};
    
                function Cat (name, color) {
                    this.name = name;
                    this.color = color;
                }
    
                extend(Cat, Animal);
                var cat1 = new Cat();
                alert(cat1.species);
            </script>

    在使用prototype对象实现继承时,子对象只能继续父对象的prototype对象的属性和方法。

    5、使用属性复制实现继承
    <script type="text/javascript">
                function extend(child, parent){
                    var p = parent.prototype;
                    var c = child.prototype;
                    for(var i in p){
                        c[i] = p[i];
                    }
                    //在子对象上打开一条通道,可以直接调用父对象的方法。这一行放在这里,只是为了实现继承的完备性,纯属备用性质。
                    c.uber = p;
                }
                function Animal () {
                    this.category = "猫科";
                }
                Animal.prototype = {species: "动物"};
    
                function Cat (name, color) {
                    this.name = name;
                    this.color = color;
                }
                Cat.prototype.species = "小动物";
                Cat.prototype.weight = "30";
    
                extend(Cat, Animal);
                var cat1 = new Cat();
                alert(cat1.species);
                //不能继承构造函数内的属性和方法
                alert(cat1.category);//undefined
    
                //子对象的prototype上的不同名的属性和方法不会被清除
                alert(Cat.prototype.weight);
                //子对象的prototype上的同名的属性和方法会被重写
                alert(Cat.prototype.species);
            </script>

    三、非构造函数(json对象)的继承

    1、使用空对象间接继承
    <script type="text/javascript">
                function object(o){
                    var F = function(){};
                    F.prototype = o;
                    return new F();
                }
    
                var chinese = {nation : "cn"};
                var doctor = new object(chinese);
                doctor.career = "doctor";
                alert(doctor.nation);
            </script>
    2、通过属性复制实现继承
    <script type="text/javascript">
                /**浅复制**/
                function extendCopy(p){
                    var c = {};
                    for(var i in p){
                        c[i] = p[i];
                    }
                    c.uber = p;
                    return c;
                }
                var chinese = {nation : "cn"};
                var doctor = extendCopy(chinese);
                doctor.career = "doctor";
                alert(doctor.nation);
                /*************/
            </script>

    若父对象有数组或对象级别的属性,通过上面的属性复制方法实现继承后,对子对象继承的这些属性的修改将会影响到父对象这些属性的值。因为在js中对于对象级别变量的赋值都是传递的对象引用,并非数据副本,对变量的修改都是操作同一对象。

    通过以下深复制的方法可以实现对象的复制:

    <script type="text/javascript">
                /**深复制**/
                function deepCopy(p, c){
                    var c = c || {};
                    for(var i in p){
                        if(typeof p[i] === 'object'){
                            c[i] = (p[i].constructor === Array) ? [] : {};
                            deepCopy(p[i], c[i]);
                        }
                        else{
                            c[i] = p[i];
                        }
                    }
                    return c;
                }
    
                var chinese = {birthPlaces : ['shanghai', 'beijing', 'guangzhou']};
                var doctor = deepCopy(chinese);
                alert(doctor.birthPlaces.join(','));
    
                doctor.birthPlaces.push('shenz');
                alert(chinese.birthPlaces.join(','));
                /**************/
            </script>
  • 相关阅读:
    C#磁吸屏幕窗体类库
    准备
    我写的诗
    How to turn off a laptop keyboard
    How to tell which commit a tag points to in Git?
    Why should I care about lightweight vs. annotated tags?
    How to get rid of “would clobber existing tag”
    Facebook, Google and Twitter threaten to leave Hong Kong over privacy law changes
    The need for legislative reform on secrecy orders
    Can a foreign key be NULL and/or duplicate?
  • 原文地址:https://www.cnblogs.com/JDotNet/p/3463649.html
Copyright © 2011-2022 走看看