JS面向對象編程(3):原型鏈與繼承

1.以下代碼輸出什么?

var john = { 
  firstName: "John" 
}
function func() { 
  alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi()//John:hi!

輸出John:hi!。解析:john.sayHi()可理解為john.sayHi.call(john),即this指向john荐类,輸出即為John.firstName + ":hi!"

2.以下代碼輸出什么茁帽?

func() 
function func() { 
  alert(this)
}

輸出window對象玉罐。func()相當于func.call(undefined),故輸出window對象潘拨。若要改變this指向吊输,則應寫成:func.call(obj)

3.下面代碼輸出什么?

document.addEventListener('click', function(e){
    console.log(this);
    setTimeout(function(){
        console.log(this);
    }, 200);
}, false);

單擊頁面铁追,依次輸出document對象季蚂、window對象。
DOM對象綁定事件時,傳入的函數(shù)中的this綁定到該DOM對象
setTImeout 和 setInterval 這兩個方法執(zhí)行的函數(shù)中的this綁定到全局對象window扭屁。

4.以下代碼有什么問題算谈,如何修改

var module= {
  bind: function(){
    $btn.on('click', function(){
      console.log(this) //this指$btn
      this.showMsg();
    })
  },
  
  showMsg: function(){
    console.log('饑人谷');
  }
}

在事件監(jiān)聽函數(shù)中 this.showMsg(), this指代 $btn 這個jQuery對象料滥,并不代表module對象然眼,因此 this.showMsg() 相當于 $btn.showMsg()。
想要在事件監(jiān)聽函數(shù)中 調用module 的方法葵腹,可以人為把this綁定到module對象高每,使用 bind() 即可:

var module= {
  bind: function(){
    $btn.on('click', function(){
      console.log(this)   //this指向module   
      this.showMsg();
    }.bind(this))
  },
  
  showMsg: function(){
    console.log('饑人谷');
  }
}

也可以將module的this保存起來為that,最后用that.showMsg()去執(zhí)行践宴。
也可以用ES6的箭頭函數(shù)鲸匿。

5.有如下代碼,解釋Person浴井、 prototype、proto霉撵、p磺浙、constructor之間的關聯(lián)

function Person(name){
    this.name = name;
}
Person.prototype.sayName = function(){
    console.log('My name is :' + this.name);
}
var p = new Person("Li")
p.sayName();
  • 首先,Person是一個構造函數(shù)徒坡,而p是它的一個實例撕氧。
  • 故,p.__proto__ == Person.prototype喇完。
  • prototype對象有一個constructor屬性伦泥,指向prototype對象所在的構造函數(shù)。故Person.prototype.constructor指向Person锦溪,p.__proto__.constructor也指向Person不脯。

6.上例中,對對象 p可以這樣調用 p.toString()刻诊。toString是哪里來的? 畫出原型圖?并解釋什么是原型鏈防楷。

原型圖

如圖所示,p自身沒有toString则涯,就到Person類的prototype去找复局,也沒有,prototype是個對象粟判,由Object類創(chuàng)建亿昏,但是仍然沒有toString,所以繼續(xù)到prototype的_ proto _ 也就是Object的prototype中去找档礁,最終找到了toString方法角钩。
由此引出原型鏈的概念:
每個對象都有一個proto屬性,其指向該對象的原型對象,而原型對象也是對象彤断,所以也有一個proto指向原型對象的原型對象野舶,這樣就組成了一條鏈,稱為原型鏈宰衙。在訪問對象的屬性時平道,如果在對象本身中沒有找到,則會去原型鏈中查找供炼,如果找到一屋,直接返回值。
原型鏈是實現(xiàn)繼承的主要方法袋哼。

7.對String做擴展冀墨,實現(xiàn)如下方式獲取字符串中頻率最高的字符

var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因為d 出現(xiàn)了5次

代碼如下:

String.prototype.getMostOften = function(){
  var obj = {};
  var max = 0;
  var result;
  for(var i=0; i<this.length; i++){
    if(obj[str[i]]){
      obj[str[i]] += 1;
    } else {
      obj[str[i]] = 1;
      }
 }
  for(var key in obj){
     if(obj[key]>max){
        max = obj[key];
        result = key;
     } 
  }
  
  return result;
};

8.instanceOf有什么作用?內部邏輯是如何實現(xiàn)的涛贯?

instanceOf運算符可以判斷一個對象是否是某個類的實例诽嘉。
如果一個對象通過沿著 _ proto _ 組成的原形鏈一層層查找其constructor屬性,如果有一層proto等于某類的prototype弟翘,則該對象是某類型的實例虫腋。

function instance(obj,fun){
  if(obj.__proto__){
    if(obj.__proto__ === fun.prototype){
      return true;
    } else {
         return instance(obj.__proto__,fun);
      }
  }
  return false;
}

console.log(instance([],Array));  //true
console.log(instance([],Object));  //true
console.log(instance([],String));   //false

9.繼承有什么用?

繼承是指一個對象直接使用另一對象的屬性和方法稀余。
繼承機制使得不同的實例可以共享構造函數(shù)的原型對象的屬性和方法悦冀,提高了代碼的復用性。

10. 下面兩種寫法有什么區(qū)別?

//方法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);

同樣是綁定一個printName方法,前者直接將方法寫在構造函數(shù)上师骗,而后者將方法寫在構造函數(shù)的prototype對象上历等,前者在每生成一個實例之后實例的printName就占用內存,而后者每生成一個實例后會共享構造函數(shù)prototype對象上的printName方法辟癌,以達到節(jié)省內存的效果募闲,也便于后期維護。

11.Object.create 有什么作用愿待?兼容性如何浩螺?

  • 該方法接受一個對象作為參數(shù),然后以它為原型仍侥,返回一個實例對象要出。該實例完全繼承原型對象的屬性。還可傳入第二個參數(shù)农渊,該參數(shù)是一個屬性描述對象患蹂,它所描述的對象屬性或颊,會添加到實例對象,作為該對象自身的屬性传于。
  • Object.create是ES5中的方法囱挑,各大瀏覽器的最新版本(包括IE9)都部署了這個方法。如果老式瀏覽器不支持Object.create方法沼溜,可以就用這段代碼自己部署平挑。
if(typeof Object.create !== 'function'){
   Object.create = function(obj){
      function F(){}
      F.prototype = obj;
     return new F();
   };
}

以上代碼說明,Object.create方法的實質是新建一個構造函數(shù)F系草,使其prototype屬性指向參數(shù)對象obj通熄,最后返回一個F的實例,從而讓該實例繼承obj對象的屬性。

12.hasOwnProperty有什么作用找都? 如何使用唇辨?

hasOwnProperty方法用于返回一個布爾值,用于判斷某個屬性定義在對象自身能耻,還是定義在原型鏈上赏枚。

function Person(name, sex){
    this.name = name;
    this.sex = sex;
}

Person.prototype.printName = function(){
    console.log(this.name);
}
var p1 = new Person('Li', 23)
p1.hasOwnProperty('name')  //true
p1.hasOwnProperty('printName')  //false

13.如下代碼中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的作用是,指定Person函數(shù)執(zhí)行上下文中的this為當前的Male創(chuàng)建的新對象晓猛。這樣通過Male構造出的對象饿幅,便能繼承擁有Person中的屬性,也就是name 和sex鞍帝。

14.補全代碼诫睬,實現(xiàn)繼承

function Person(name, sex){
    // todo ...
}

Person.prototype.getName = function(){
    // todo ...
};    

function Male(name, sex, age){
   //todo ...
}

//todo ...
Male.prototype.getAge = function(){
    //todo ...
};

var li = new Male('Li', '男', 24);
li.printName();

代碼如下:

function Person(name,age){
  this.name = name;
  this.age = age;
}
Person.prototype.printName = function(){
    console.log(this.name);
};

function Male(name,age,sex){
  this.sex = sex;
  Person.call(this,name,age);
}
Male.prototype = Object.create(Person.prototype);
Male.prototype.constructor = Male;
Male.prototype.printSex = function(){
  console.log(this.sex);
};

var a = new Male('Li',24,'male');
a.printName();  //Li

也可封裝成一個函數(shù)使用:

function inherit(superType,subType){
  var _superType = Object.create(superType.prototype);
  _superType.constructor = superType;
  subType.prototype = _superType;
}

function Person(name,age){
  this.name = name;
  this.age = age;
}
Person.prototype.printName = function(){
    console.log(this.name);
};

function Male(name,age,sex){
  this.sex = sex;
  Person.call(this,name,age);
}

inherit(Person,Male);

Male.prototype.printSex = function(){
  console.log(this.sex);
};
var a = new Male('Li',24,'male');
a.printName();  //Li

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末煞茫,一起剝皮案震驚了整個濱河市帕涌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌续徽,老刑警劉巖蚓曼,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異钦扭,居然都是意外死亡纫版,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門客情,熙熙樓的掌柜王于貴愁眉苦臉地迎上來其弊,“玉大人,你說我怎么就攤上這事膀斋∷蠓ィ” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵仰担,是天一觀的道長糊识。 經常有香客問我,道長,這世上最難降的妖魔是什么赂苗? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任愉耙,我火速辦了婚禮,結果婚禮上拌滋,老公的妹妹穿的比我還像新娘朴沿。我一直安慰自己,他們只是感情好鸠真,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布悯仙。 她就那樣靜靜地躺著,像睡著了一般吠卷。 火紅的嫁衣襯著肌膚如雪锡垄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天祭隔,我揣著相機與錄音货岭,去河邊找鬼。 笑死疾渴,一個胖子當著我的面吹牛千贯,可吹牛的內容都是我干的崭别。 我是一名探鬼主播雳殊,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼驶沼!你這毒婦竟也來了桩撮?” 一聲冷哼從身側響起敦第,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎店量,沒想到半個月后芜果,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡融师,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年右钾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旱爆。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡舀射,死狀恐怖,靈堂內的尸體忽然破棺而出怀伦,到底是詐尸還是另有隱情脆烟,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布空镜,位于F島的核電站浩淘,受9級特大地震影響捌朴,放射性物質發(fā)生泄漏。R本人自食惡果不足惜张抄,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一砂蔽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧署惯,春花似錦左驾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至轻猖,卻和暖如春帆吻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背咙边。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工猜煮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人败许。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓王带,卻偏偏與公主長得像,于是被迫代替她去往敵國和親市殷。 傳聞我的和親對象是個殘疾皇子愕撰,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內容