美文网首页
继承相关基础知识问答

继承相关基础知识问答

作者: 该帐号已被查封_才怪 | 来源:发表于2016-11-02 20:11 被阅读85次

    一、问题

    (一)、继承有什么作用?

    通过继承可以继承原有函数的一些属性和方法,避免重复定义一些属性和方法,举个例子:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
        <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.min.js"></script>
    </head>
    <body>
    
        <script>
            function Person(name) {
                this.name=name;
                console.log(this.name)
            }
            Person.prototype.sayHi=function () {
                console.log("Hi! my name is:"+this.name)
            };
            Person.prototype.sayEyesNum=function () {
                console.log("I have two eyes.")
            };
            function Students(name) {
                this.name=name;
                Person.call(this,name)
    
            }
            Students.prototype=Object.create(Person.prototype); //这里一定要注意
    //与Students.prototype.sayHi 间的顺序,Students.prototype.sayHi应该在后面,否则其会被覆盖掉!!
            Students.prototype.constructor=Students;
            Students.prototype.sayHi=function () {
                console.log("Hi! I am student and my name is"+this.name)
            };
            Students.prototype.sayTeacherName=function () {
                console.log("My Teacher's name is Wang")
            };
    
            var p1=new Person("ren"),
                stu1=new Students("xue");
    
        </script>
    
    </body>
    </html>
    

    上述代码中,我先定义了一个Person的函数,且在该函数属性上绑定sayEyesNum()这个方法,然后我通过继承的方法,使得Students函数也具有了sayEyesNum()这个方法,而无需重新在Students函数上绑定sayEyesNum()这个方法。

    (二)、有几种常见创建对象的方式? 举例说明?
    • 1、工厂模式:
    function createPerson( name, age, job ) {
        var o = new Object();
        o.name = name;
        o.age = age;
        o.job = job;
        o.sayName = function() {
            alert(this.name);
        }
    
        return o;
    }
    
    var person1 = createPerson("Nicholas", 29, "software Engineer");
    var person2 = createPerson("Greg", 27, "Doctor");
    
    person1.sayName(); //"Nicholas"
    person2.sayName(); //"Greg"
    

    工厂模式未能够解决对象识别的问题;

    • 2、构造函数模式
    function Person( name, age, job ) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.sayName = function() {
            alert(this.name);
        }
    }
    
    var person1 = new Person("Nicholas", 29, "software Engineer");
    var person2 = new Person("Greg", 27, "Doctor");
    
    person1.sayName(); //"Nicholas"
    person2.sayName(); //"Greg"
    

    构造函数的主要问题是每个方法都会在每个实例上创建一遍。

    • 3、原型模式
    function Person(){
    
    }
    
    Person.prototype = {
        constructor: Person,
        name: "Nicholas",
        age: 29,
        job: "software Engineer",
        friends: ["Shelby","Court"],
        sayName: function() {
            alert(this.name);
        }
    }
    
    var person1 = new Person();
    var person2 = new Person();
    
    person1.friends.push("Van");
    
    alert(person1.friends); //"Shelby,Court,Van"
    alert(person2.friends); //"Shelby,Court,Van"
    alert(person1.friends === person2.friends); //true
    

    原型模式虽然解决了上述几个问题,但是有时候我们需要某个实例要有自己的方法和属性。因此出现了运用最广泛的组合模式

    • 4、组合使用构造函数模式和原型模式
    function Person( name, age, job ) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.friends = ["Shelby","Court"];
    }
    
    Person.prototype = {
        constructor: Person,
        sayName: function(){
            alert(this.name);
        }
    }
    
    var person1 = new Person("Nicholas", 29, "software Engineer");
    var person2 = new Person("Greg", 27, "Doctor");
    
    person1.friends.push("Van");
    
    alert(person1.friends); //"Shelby,Court,Van"
    alert(person2.friends); //"Shelby,Court"
    alert(person1.friends === person2.friends); //false
    alert(person1.sayName === person2.sayName); //true
    

    该组合模式中,构造函数用于定义实例属性,原型用于定义方法和共享属性;

    • 5、动态原型模式
    function Person( name, age, job ) {
        //属性
        this.name = name;
        this.age = age;
        this.job = job;
    
        //方法
        if( typeof this.sayName != "function" ) {
            Person.prototype.sayName = function() {
                alert(this.name);
            }
        }
    }
    
    var person = new Person("Nicholas", 29, "software Engineer");
    person.sayName();
    
    • 6、寄生构造函数模式
    function SpecialArray() {
        //创建数组
        var values = new Array();
    
        //添加值
        values.push.apply(values,arguments);
    
        //添加新方法
        values.toPipedString = function(){
            return this.join("|");
        };
    
        //返回数组
        return values;
    }
    
    var colors = new SpecialArray("red","blue","green");
    alert(colors.toPipedString()); //"red|blue|green"
    

    返回的对象与构造函数或者与构造函数的原型之间没有关系;不能依赖instanceof操作符来确定对象的类型。由于存在上述问题,我们建议在可以使用其他模式的情况下,不要使用这种模式。

    • 7、稳妥构造函数模式
    function Person( name, age, job ) {
        //创建要返回的对象
        var o = new Object();
    
        //可以在这里定义私有变量和函数
    
        //添加方法
        o.sayName = function() {
            alert(name);
        };
    
        //返回对象
        return o;
    }
    
    var person = Person("Nicholas", 29, "software Engineer");
    Person.sayName(); //"Nicholas"
    

    与寄生构造函数模式类似,使用稳妥构造函数模式创建的对象与构造函数之间也没什么关系, 因此instanceof操作符对这种对象没有意义。

    (三)、下面两种写法有什么区别?
    //方法1
    function People(name, sex){
        this.name = name;
        this.sex = sex;
        this.printName = function(){
            console.log(this.name);
        }
    }
    var p1 = new People('饥人谷', 2)
    
    
    //方法2
    function Person(name, sex){
        this.name = name;
        this.sex = sex;
    }
    
    Person.prototype.printName = function(){
        console.log(this.name);
    }
    var p1 = new Person('若愚', 27);
    

    通过第一种方式,People的printName方法是在函数People实例对象里的,因此当后面再新建一个People的实例对象时,又会创建一个printName方法,而不能够像第二种方式那样可以在People函数的属性上共用printName方法,不利于节省空间。

    (四)、Object.create 有什么作用?兼容性如何?如何使用?

    Object.create的作用是创建一个指定原型和若干个指定属性的对象。

    由于Object.create是在ES5后出现的,因此如下浏览器才支持:


    桌面端 移动端

    它的语法如下:

    Object.create(proto, [ propertiesObject ])
    
    • proto 一个对象: 作为新创建的对象的原型;
    • propertiesObject 可选。该参数对象是一组属性与值,该对象的名称将是新建对象的属性名称,值是描述性属性符。值得注意的是该参数对象不能是undefined,另外该对象自身所拥有的可枚举的属性才有效,也就是说其原型链上的属性是无效的。

    举个例子:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
        <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.min.js"></script>
    </head>
    <body>
    
        <script>
            var o;
            o = Object.create({}, { p: { value: 42 } });
            // 省略了的属性特性默认为false,所以属性p是不可写,不可枚举,不可配置的:
            o.p = 24;
            o.p  //42
    
            o.A = 12;
            for (var prop in o) {
                console.log(prop)
            }
            //"A"
            delete o.p;
            //false
    
        </script>
    </body>
    </html>
    
    (五)、hasOwnProperty有什么作用? 如何使用?

    用来判断某个对象是否含有指定的自身属性。其与in运算符不同,hasOwnProperty会忽略掉原型链上继承到的属性。

    其使用语法为obj.hasOwnProperty(prop)

    • prop 为要检测的属性名;
      举个例子:
        <script>
            var car={};
            car.name="bench";
        </script>
    
    从原型链上继承的属性被忽略了
    (六)、实现Object.create的 polyfill,如:(ps: 写个 函数create,实现 Object.create 的功能)
    var obj = {a: 1, b:2};
    var obj2 = create(obj);
    console.log(obj2.a); //1
    

    简单模拟:

            function create(obj) {
                 function Tem() {}
                Tem.prototype=obj;
                 return  new Tem()
            }
    

    真实模拟:

            if (typeof Object.create != 'function') {
                // Production steps of ECMA-262, Edition 5, 15.2.3.5
                // Reference: http://es5.github.io/#x15.2.3.5
                Object.create = (function() {
                    //为了节省内存,使用一个共享的构造器
                    function Temp() {}
    
                    // 使用 Object.prototype.hasOwnProperty 更安全的引用
                    var hasOwn = Object.prototype.hasOwnProperty;
    
                    return function (O) {
                        // 1. 如果 O 不是 Object 或 null,抛出一个 TypeError 异常。
                        if (typeof O != 'object') {
                            throw TypeError('Object prototype may only be an Object or null');
                        }
    
                        // 2. 使创建的一个新的对象为 obj ,就和通过
                        //    new Object() 表达式创建一个新对象一样,
                        //    Object是标准内置的构造器名
                        // 3. 设置 obj 的内部属性 [[Prototype]] 为 O。
                        Temp.prototype = O;
                        var obj = new Temp();
                        Temp.prototype = null; // 不要保持一个 O 的杂散引用(a stray reference)...
    
                        // 4. 如果存在参数 Properties ,而不是 undefined ,
                        //    那么就把参数的自身属性添加到 obj 上,就像调用
                        //    携带obj ,Properties两个参数的标准内置函数
                        //    Object.defineProperties() 一样。
                        if (arguments.length > 1) {
                            // Object.defineProperties does ToObject on its first argument.
                            var Properties = Object(arguments[1]);
                            for (var prop in Properties) {
                                if (hasOwn.call(Properties, prop)) {
                                    obj[prop] = Properties[prop];
                                }
                            }
                        }
    
                        // 5. 返回 obj
                        return obj;
                    };
                })();
            }
    
    
    (七)、如下代码中call的作用是什么?
    function Person(name, sex){
        this.name = name;
        this.sex = sex;
    }
    function Male(name, sex, age){
        Person.call(this, name, sex);    //这里的 call 有什么作用
        this.age = age;
    }
    
    

    这里call的作用是在函数Male的运行环境中运行Person函数,让函数Male继承了Person函数的属性和方法;

    (八)、补全代码,实现继承
    function Person(name, sex){
        // todo ...
    }
    
    Person.prototype.getName = function(){
        // todo ...
    };    
    
    function Male(name, sex, age){
       //todo ...
    }
    
    //todo ...
    Male.prototype.getAge = function(){
        //todo ...
    };
    
    var ruoyu = new Male('若愚', '男', 27);
    ruoyu.printName();
    
            function Person(name, sex){
               this.name=name;
                this.sex=sex;
            }
    
            Person.prototype.getName = function(){
                return (this.name)
            };
    
            function Male(name, sex, age){
                this.name=name;
                this.sex=sex;
                this.age=age;
            }
            Person.prototype.printName=function () {
                console.log(this.name)
            };
    
            Male.prototype=Object.create(Person.prototype);
            Male.prototype.constructor=Male;
            Male.prototype.getAge = function(){
                return (this.age)
            };
    
            var ruoyu = new Male('若愚', '男', 27);
            ruoyu.printName();
    

    二、代码

    (一)、实现如下dialog 弹窗功能, 参考效果
    //功能描述: 
    // 1. 可使用 dialog.open() 去打开弹窗
    // 2. 当点击确定、取消时可使用用户自定义事件
    // 3. dialog 可拖动
    // 4. 允许页面展示多个 dialog
    
    
    function Dialog(){
    //todo ...
    }
    
    
    var tpl = '<ul><li>列表1</li><li>列表2</li><li>列表1</li><li>列表1</li></ul>';
    
    $('#open4').on('click',function(){
      var dialog4 = new Dialog();
      dialog4.open({
        title: '欢迎来到饥人谷',
        message: tpl,
        isShowCloseBtn: true,
        isShowConfirmBtn: true,
        onClose: function(){
          alert('close')
        },
        onConfirm: function(){
          alert('确定');
        }
      });
    });
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            body{
                position: relative;
            }
            .dialog{
                border-radius: 5px;
                background-color:#eee ;
                box-shadow:0 0 5px 2px rgba(0, 0, 0, 0.5);
                position: absolute;
                top: 30%;
                left: 50%;
                width: 328px;
            }
            .title{
                background-color: #676666;
                padding: 8px 10px;
                color: #fff;
                font-weight: bolder;
            }
            .clearfix:after{
                display: block;
                clear: both;
                content: "";
            }
    
            a{
                text-align: center;
                text-decoration: none;
    
            }
            .button a{
                background-color: #e33100;
                padding: 5px 8px;
                border-radius: 5px;
                margin-left: 10px;
                margin-right: 10px;
                color: #fff;
            }
            .button{
                padding:  20px 0;
                text-align: center;
            }
            .title a{
                float: right;
                width: 10px;
                color: #fff;
            }
            .content{
                color:#666 ;
                padding: 10px;
            }
            .draggable{
                cursor: move;
                opacity: 0.8;
            }
    
    
    
        </style>
        <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.min.js"></script>
    </head>
    <body>
        <button id="open1">打开1</button>
        <button id="open2">打开2</button>
        <button id="open3">打开3</button>
        <button id="open4">打开4</button>
        <button id="open5">打开5</button>
        <p>鼠标在 dialog 上左键按下可拖动 dialog</p>
    
        <p>可创建多个 dialog</p>
    
        <script>
    
    
    
    
    
            //功能描述:
            // 1. 可使用 dialog.open() 去打开弹窗
            // 2. 当点击确定、取消时可使用用户自定义事件
            // 3. dialog 可拖动
            // 4. 允许页面展示多个 dialog
    
            function Dialog(){
                this.createDialog();
                this.bindEvent();
            }
            Dialog.prototype={
                originOpts:{
                    title:"",
                    message:"",
                    isShowCancelBtn:true,
                    isShowConfirmBtn:false,
                    onCancel:function () {
                        
                    },
                    onConfirm:function () {
                        
                    }
                },
                open:function (opts) {
                    this.setOpts(opts);
                    this.setDialog();
                    this.showDialog();
                },
                setOpts:function (opts) {
                    if (typeof opts==="string"){
                        this.opts=$.extend({},this.originOpts,{message:opts})
                    }else if (typeof opts==="object"){
                        this.opts=$.extend({},this.originOpts,opts)
                    }
    
                },
    
                setDialog:function () {
                    var $dialog=this.$dialog;
                    console.log($dialog);
                    if (!this.opts.title){
                        $dialog.find(".title").hide();
                    }else {
                        $dialog.find(".title").show();
                    }
                    if (!this.opts.isShowCancelBtn){
                        $dialog.find(".button .cancel").hide();
                    }else {
                        $dialog.find(".button .cancel").show();
                    }
                    if (!this.opts.isShowConfirmBtn){
                        $dialog.find(".confirm").hide();
                    }else {
                        $dialog.find(".confirm").show();
                    }
                    $dialog.find(".title span").text(this.opts.title);
                    $dialog.find(".content").html(this.opts.message);
    
                },
                showDialog:function () {
                    this.$dialog.show();
    
                },
                hideDialog:function () {
                    this.$dialog.hide();
    
                },
                createDialog:function () {
                    var tp1='<div class="dialog">'+'<div class="title clearfix"><span></span><a class="cancel" href="####">X</a></div>'+'<h3 class="content"></h3>'+'<div class="button"><a class="cancel" href="####">取消</a><a class="confirm" href="####">确定</a></div>'+'</div>';
                    this.$dialog=$(tp1);
                    $("body").append(this.$dialog);
                },
                bindEvent:function () {
                    var _this=this;
                    _this.$dialog.find(".cancel").on("click",function () {
                        _this.opts.onCancel();
                        _this.hideDialog();
                    });
                    _this.$dialog.find(".confirm").on("click",function () {
                        _this.opts.onConfirm();
                        _this.hideDialog();
                    });
                    _this.$dialog.on("mousedown",function (e) {
                        var $dialog=$(this),
                                evtX=e.pageX-$dialog.offset().left,
                                evtY=e.pageY-$dialog.offset().top;
                        $dialog.addClass("draggable").data("evtPos",{
                            x:evtX,
                            y:evtY
                        })
    
    
                    });
                    $("body").on("mousemove",function (e) {
                        $(".draggable").length && $(".draggable").offset({
                            top:e.pageY-$(".draggable").data("evtPos").y,
                            left:e.pageX-$(".draggable").data("evtPos").x
                        });
                        $("body").on("mouseup",function () {
                            $('.draggable').length && $('.draggable').removeClass('draggable').removeData('evtPos');
    
    
                        })
                    })
    
                }
    
                
            };
    
            $('#open1').on('click', function() {
                var dialog1 = new Dialog();
                dialog1.open('hello, 这里是饥人谷');
            });
            $('#open2').on('click', function() {
                var dialog2 = new Dialog();
                dialog2.open('<a href="####">这里是链接</a>');
            });
            $('#open3').on('click',function(){
                var dialog3 = new Dialog();
                dialog3.open({
                    title: '欢迎来到饥人谷',
                    message: "hello",
                    isShowCancelBtn: true,
                    isShowConfirmBtn: true,
                    onCancel: function(){
                        alert('cancel')
                    },
                    onConfirm: function(){
                        alert('确定');
                    }
                });
            });
    
    
            var tp1 = '<ul><li>列表1</li><li>列表2</li><li>列表1</li><li>列表1</li></ul>';
    
            $('#open4').on('click',function(){
                var dialog4 = new Dialog();
                dialog4.open({
                    title: '欢迎来到饥人谷',
                    message: tp1,
                    isShowCancelBtn: true,
                    isShowConfirmBtn: true,
                    onCancel: function(){
                        alert('cancel')
                    },
                    onConfirm: function(){
                        alert('确定');
                    }
                });
            });
    
            $('#open5').on('click',function(){
                var dialog5 = new Dialog();
                dialog5.open({
                    title: '欢迎来到饥人谷',
                    message: "hello",
                    isShowCancelBtn: false,
                    isShowConfirmBtn: false
                });
            });
            
    
    
        </script>
    
    
    
    </body>
    </html>
    
    (二)、实现如下一个日历组件 【Demo】
      <input class="date-ipt" type="text" placeholder="有初始值" date-init="2016/05/31" />
      <input class="date-ipt" type="text" placeholder="无初始值"  />
      <script>
      // 使用
       $('.date-ipt').datePicker();
      </script>
    

    **本文版权归本人即简书笔名:该账户已被查封 所有,如需转载请注明出处。谢谢! *

    相关文章

      网友评论

          本文标题:继承相关基础知识问答

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