继承相关基础知识问答

一、问题

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

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

<!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>

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容