Javascript 进阶 继承

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/29194261

1、基于类的继承

下面看下面的代码:

 <script type="text/javascript">

        function Person(name, age)
        {
            this.name = name;
            this.age = age;
        }
        Person.prototype.say = function ()
        {
            console.log(this.name + " , " + this.age);
        }
        function Student(no)
        {
            this.no = no;
        }
<span style="white-space:pre">	/**
         * Student的prototype指向Person的对象
         */</span>
        Student.prototype = new Person();
        var stu1 = new Student("0001");
        stu1.name = '张三';
        stu1.age = '11';
        console.log(stu1.no);
        stu1.say();

    </script>

输出结果:

0001
张三 , 11 

可以看到Student成功集成了Person,并且拥有了Person的say方法,核心代码其实就是一句 Student.prototype = new Person();,下面通过图解来说明原理:

将Student.prototype指向new Person() , new Person的_proto_又指向Person Prototype;这样完成了整个继承。

但是这种方式存在问题:

问题1:当父类存在引用类型变量时,造成数据不一致,下面我们给Person添加一个hobbies属性,类型为数组。

 <script type="text/javascript">
        /**
         * 存在问题
         * 1、无法在Student的构造方法中传递参数用于父类的构造方法
         * 2、对于引用类型变量,造成数据不一致
         */

        function Person(name, age)
        {
            this.name = name;
            this.age = age;
            this.hobbies = [] ;
        }
        Person.prototype.say = function ()
        {
            console.log(this.name + " , " + this.age +" , " +this.hobbies);
        }
        function Student(no)
        {
            this.no = no;
        }
        Student.prototype = new Person();

        var stu1 = new Student("0001");
        stu1.name = '张三';
        stu1.age = '11';
        stu1.hobbies.push("soccer");
        stu1.say();

        var stu2 = new Student("0002");
        stu2.name = '李四';
        stu2.age = '12';
        stu2.hobbies.push("girl");
        stu2.say();

    </script>

输出结果:

张三 , 11 , soccer
李四 , 12 , soccer,girl 

可以看出,李四的hobbies应该只有girl,但是上面的代码让所有对象共享了hobbies属性。

上述的继承方式还存在一个问题:

问题2:在Student的构造方法中,无法使用new Student("00001" , "张三" , 12) ;创建对象,并初始化name和age属性,必须stu.name, stu.age进行赋值

为了解决上述问题,对上述代码进行修改:

 <script type="text/javascript">

        function Person(name, age)
        {
            this.name = name;
            this.age = age;
            this.hobbies = [];
        }
        Person.prototype.say = function ()
        {
            console.log(this.name + " , " + this.age +" , " + this.hobbies);
        }

        function Student(name, age, no)
        {
            /**
             * 使用call方法,第一个参数为上下文;
             * 有点类似Java中的super(name,age)的感觉
             */
            Person.call(this, name, age);
            this.no = no;
        }

        Student.prototype = new Person();

        var stu1 = new Student("0001","张三",11);
        stu1.hobbies.push("soccer");
        stu1.say();

        var stu2 = new Student("0002","李四",12);
        stu2.hobbies.push("cangjin");
        stu2.hobbies.push("basketball");
        stu2.say();

    </script>

输出:

0001 , 张三 , soccer
0002 , 李四 , cangjin,basketball 

在Student的构造方法中使用了Person.call(this,name,age)感觉就像super(name,age)【call的第一个参数为上下文】;并且成功解决了对引用属性的共享问题,完美解决。

2、基于原型链的继承
    <script type="text/javascript">

        /**
         * 基于原型链的集成中都是对象
         * 存在问题:
         * 1、对于引用类型变量,造成数据不一致
         */
        var Person = {
                    name: "人",
                    age: 0,
                    hobbies: [],
                    say: function ()
                    {
                        console.log(this.name + " , " + this.age + " , " + this.hobbies);
                    }
                }
                ;

        var Student = clone(Person);
        Student.no ="";
        Student.sayHello = function()
        {
            console.log(this.name  +"hello ") ;
        }

        var stu1 = clone(Student);
        stu1.name = "zhangsan";
        stu1.age = 12;
        stu1.hobbies.push("Java");
        stu1.say();

        var stu2 = clone(Student);
        stu2.name = "lisi";
        stu2.age = 13;
        stu2.hobbies.push("Javascript");
        stu2.say();

        /**
         * 返回一个prototype执行obj的一个对象
         * @param obj
         * @returns {F}
         */
        function clone(obj)
        {
            var F = function ()
            {
            };
            F.prototype = obj;
            return new F();

        }

    </script>

输出:

zhangsan , 12 , Java
lisi , 13 , Java,Javascript 

可以看出同样存在引用属性不一致的问题,并且整个操作全部基于对象,给人的感觉不是很好,下面通过图解解释下原理:

对象间通过一个clone函数,不断的返回一个新的对象,且prototype执行传入的对象,整个继承过程其实就是_proto_不断的指向,形成一个链,所以叫做原型链。

好了,已经介绍完了,js的两种集成的方式,最好使用的还是通过类的继承(上述第一种方案,解决存在问题的)。

如果代码或者讲解存在任何问题,欢迎留言指出。

Javascript 进阶 继承

时间: 2024-10-12 09:42:12

Javascript 进阶 继承的相关文章

Javascript 进阶 面向对象编程 继承的一个例子

Javascript的难点就是面向对象编程,上一篇介绍了Javascript的两种继承方式:Javascript 进阶 继承,这篇使用一个例子来展示js如何面向对象编程,以及如何基于类实现继承. 1.利用面向对象的写法,实现下面这个功能,实时更新数据的一个例子: 2.使用对上面类的继承,完成下面的效果: 好了,不多说,js的训练全靠敲,所以如果觉得面向对象不是很扎实,可以照着敲一个,如果觉得很扎实了,提供了效果图,可以自己写试试. 1.第一个效果图代码: [javascript] view pl

JavaScript 进阶问题列表

JavaScript 进阶问题列表 我在我的 Instagram 上每天都会发布 JavaScript 的多选问题,并且同时也会在这个仓库中发布. 从基础到进阶,测试你有多了解 JavaScript,刷新你的知识,或者帮助你的 coding 面试! 我每周都会在这个仓库下更新新的问题. 答案在问题下方的折叠部分,点击即可展开问题.祝你好运 1. 输出是什么? function sayHi() { console.log(name) console.log(age) var name = 'Lyd

javascript类继承

function extend(subClass, superClass) { var f = function() {}; f.prototype = superClass.prototype; subClass.prototype = new f(); subClass.superClass = superClass.prototype; } var parent = function (name, age) { this._name = name; this._age = age; };

javascript进阶笔记(2)

js是一门函数式语言,因为js的强大威力依赖于是否将其作为函数式语言进行使用.在js中,我们通常要大量使用函数式编程风格.函数式编程专注于:少而精.通常无副作用.将函数作为程序代码的基础构件块. 在函数式编程中,有一种函数称为匿名函数,也就是没有名称的函数,是js中的一个非常重要的概念.通常匿名函数的使用情况是,创建一个供以后使用的函数.比如将匿名函数保存在一个变量里面,或将其作为一个对象方法,更有甚者将其作为一个回调等等之类的. //保存在变量中,通过fn去引用 var fn=function

Javascript进阶---前言

前言: 在没有完全认识Javacript的时候,经常用Javascript/jQuery操纵DOM,改个样式什么的,使用Ajax进行前端后端的数据交互. 经常会想,这近些年大热的Javascript就只能做这么点事儿吗? 直到后来,慢慢接触到了AngularJS.NodeJS才知道,才知道将Javascript作为一门完整的语言去看待,而不仅仅是网页的脚本. Javascript进阶学习笔记,将会以ECMAScript 6为标准,去学习真正的Javascript. 注意: 1.整理内容具有个人偏

javascript深度克隆与javascript的继承实现

1.javascript深度克隆: //注意这里的对象包括object和array function cloneObject(obj){ var o = obj.constructor === Array ? [] : {}; for(var key in obj){ if(obj.hasOwnProperty(key)){ o[key] = typeof obj[key] === "object" ? cloneObject(obj[key]) : obj[key]; } } ret

JavaScript进阶系列06,事件委托

在"JavaScript进阶系列05,事件的执行时机, 使用addEventListener为元素同时注册多个事件,事件参数"中已经有了一个跨浏览器的事件处理机制.现在需要使用这个事件处理机制为页面元素注册事件方法. □ 点击页面任何部分触发事件 创建一个script1.js文件. (function() { eventUtility.addEvent(document, "click", function(evt) { alert('hello'); }); }(

JavaScript原型继承的陷阱

JavaScript原型继承的陷阱 JavaScript默认采用原型继承.虽然没有类(class)的概念,它的函数(function)可以充当构造器(constructor).构造器结合this,new可以构建出类似Java的类.因此,JavaScript通过扩展自身能模拟类式(class-based)继承. JavaScript和其它面向对象语言一样,对象类型采用引用方式.持有对象的变量只是一个地址,而基本类型数据是值.当原型上存储对象时,就可能有一些陷阱. 先看第一个例子 var creat

浅话javascript的继承

javascript的继承和java或C#的继承是不一样的,后者是基于类的继承,而javascript是通过原型来继承的.所以,先得理一理原型是个什么鬼. 当一个函数对象被创建时,Function构造器产生的函数对象会运行类似这样一些代码:this.prototype={constructor:this},新对象被赋予prototype这样一个属性,它的值是一个包含constructor属性的对象.可以看出,这个constructor指向新对象本身.prototype属性指向的对象自然不会只有c