面向对象的程序设计 --- 下篇 继承启蒙

继承是oo语言中一个最为人津津乐道的概念。ECMAScript支持实现继承,而且实现继承只要是靠原型链来实现的

·原型链
其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。
简单回顾一个构造函数,原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的
内部指针。那么,假设我们让原型对象等于另一个类型的实例,结果会怎样呢?
                //  生物的构造函数
            function Bio(){
                this.life = true
            }
            Bio.prototype.getLife = function () {
                return this.life;
            }
                //  动物的构造函数
            function Animal(){
                this.eat = true;
            }
            Animal.prototype = new Bio();
                // 狗的构造函数
            function Dog(master){
                this.master = master;
            }
            Dog.prototype = new Animal();

            var dog1 = new Dog("cl");
            console.log(dog1.life);  // true
            console.log(dog1.constructor);
            /*
            输出:
             ƒ Bio(){
             this.life = true
             }
             为什么会这样,因为 Dog 和 Animal 的constructor 被重写了的缘故
             */

上述代码中。我们没有使用Dog默认提供的原型,而是给它换了一个新原型。这个新原型就是Animal的实例。于是新原型不仅具有作为一个Animal
实例拥有的全部属性和方法,而且其内部还有一个指针,指向了Animal的原型...
通过实现原型链,本质上拓展了本章前面介绍的原型搜索机制。
默认的原型:
事实上,前面例子中展示的原型链少了一环。我们知道,所有的应用类型默认都继承了Object,而这个继承也是通过原型链实现的。大家记住,所有引用类型
默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。这正是所有自定义类型都会继承toString() ,valueOf()等
默认方法的原因。
确认原型和实例的关系:
可以通过两种方式来确定原型和实例之间的关系。
            // 第一种方法:使用instanceof 操作符,只要用这个操作符检测实例与原型链出现过的构造函数,结果就会返回true。
                console.log(dog1 instanceof Dog);
                console.log(dog1 instanceof Animal);
                console.log(dog1 instanceof Bio);
                console.log(dog1 instanceof Object); // 全部为true
                // 由于原型链的关系,我们可以说dog1 是上述四个任何一个类型的实例
            // 第二种方法:使用isPrototypeOf() 方法。同样,只要原型链出现过的原型,都可以说是该原型链所派生的实例的原型
                console.log(Object.prototype.isPrototypeOf(dog1));
                console.log(Animal.prototype.isPrototypeOf(dog1));
                console.log(Bio.prototype.isPrototypeOf(dog1));
                console.log(Dog.prototype.isPrototypeOf(dog1)); // 全部为true

谨慎的定义方法
两点问题:
1: 不管怎么样,给原型添加方法的代码一定放在替换原型的语句之后
2:通过原型链实现继承时,不能使用对象字面量创建原型方法。因为这样做就会重写原型链
原型链的问题:
code..
            function Super () {
                this.color = ["red","blue","green"];
            }
            function Sub () {

            }
            Sub.prototype = new Super();
            var ins1 = new Sub();
            ins1.color.push("black");
            console.log(ins1.color);   // ["red", "blue", "green", "black"]

            var ins2 = new Sub();
            console.log(ins2.color);  // ["red", "blue", "green", "black"]

            // 那么问题来了,由于Sub的所有实例都会共享这一个color属性,那么我们对ins1.color的修改能够通过ins2.color反映出来
                // 问题:在创建子类型的实例时,不能向超类型的构造函数传递参数。实际上,应该说是没有办法在不影响所有对象实例的情况下,给超类型的
                // 构造函数传递参数。有鉴于此,实践中很少会单独使用原型链

猜你喜欢

转载自www.cnblogs.com/cl94/p/11261825.html
今日推荐