繼承相關基礎知識問答

一、問題

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

通過繼承可以繼承原有函數的一些屬性和方法,避免重復定義一些屬性和方法,舉個例子:

<!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閱讀 228,936評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,084評論 2 375

推薦閱讀更多精彩內容