原型鏈相關(guān)問(wèn)題
問(wèn)題7:有如下代碼,解釋Person爪喘、 prototype宏邮、proto泽示、p、constructor之間的關(guān)聯(lián)蜜氨。
function Person(name){
this.name = name;
}
Person.prototype.sayName = function(){
console.log('My name is :' + this.name);
}
var p = new Person("若愚")
p.sayName(); //打印結(jié)果 My name is :若愚
如圖:
1.Person是一個(gè)構(gòu)造函數(shù),也是一個(gè)對(duì)象,通過(guò)new方法可以創(chuàng)建新的實(shí)例械筛。例子中,變量p就是通過(guò)Person()創(chuàng)建的一個(gè)實(shí)例飒炎。
2.prototype是原型對(duì)象埋哟,每個(gè)函數(shù)都有這個(gè)屬性。原型對(duì)象默認(rèn)有constructor
和__proto__
兩個(gè)屬性郎汪;
prototype屬性實(shí)現(xiàn)繼承機(jī)制:這個(gè)原型對(duì)象中存有的屬性和方法赤赊,通過(guò)構(gòu)造函數(shù)創(chuàng)建的每一個(gè)實(shí)例,都可以訪問(wèn)到這些屬性和方法煞赢。
3.__proto__
是每個(gè)對(duì)象都擁有的屬性抛计,它指向創(chuàng)建該對(duì)象的構(gòu)造函數(shù)的原型。例子中耕驰,p.__proto__ === Person.prototype
爷辱。
所以當(dāng)調(diào)用p.sayName 的時(shí)候p先查找自己的屬性中有沒有录豺,沒有就在原型鏈中查找朦肘。
4.constructor是每個(gè)函數(shù)的原型對(duì)象中都含有的屬性,它指向構(gòu)造函數(shù)本身双饥。
問(wèn)題8: 上例中媒抠,對(duì)對(duì)象 p可以這樣調(diào)用 p.toString()。toString是哪里來(lái)的? 畫出原型圖?并解釋什么是原型鏈咏花。
如圖
toString()從哪里來(lái)趴生?
toString()實(shí)際上是Object的方法阀趴。
首先p對(duì)象在自己身上找toString(),沒有然后到p.__proto__
指向的原型
對(duì)象里面找苍匆,沒有然后到原型對(duì)象里__proto__
指向的原型對(duì)象里面找刘急,最后在Object.prototype對(duì)象里就找到了toString();什么是原型鏈?
每個(gè)對(duì)象都有一個(gè)默認(rèn)的__proto__
屬性浸踩,這個(gè)屬性就是對(duì)其父元素原型對(duì)象(protoType)的引用叔汁。由于原型對(duì)象本身也是對(duì)象,也有__proto__
屬性检碗,它的__proto__
屬性又指向了其更高父元素原型對(duì)象据块。這樣就形成了一條鏈,這就是原型鏈折剃。
例如:圖中通過(guò)__proto__
連接起來(lái)的鏈就叫做原型鏈另假。
問(wèn)題9:對(duì)String做擴(kuò)展,實(shí)現(xiàn)如下方式獲取字符串中頻率最高的字符
//to do
var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因?yàn)閐 出現(xiàn)了5次
代碼如下
String.prototype.getMostOften=function(){
var obj={};
for(var i=0;i<this.length;i++){
var p=this[i];
//console.log( this==str ); //this指的是str字符串對(duì)象
if(!obj[p]){
obj[p]=1; //如果是屬性值為undefind怕犁,然后設(shè)置值為1
}else{
obj[p]++ //如果屬性值不為undefined边篮,那么就再加1
}
}
console.log(obj);
//遍歷對(duì)象,找到出現(xiàn)次數(shù)最多的
var max=0;
var val;
for(var key in obj){
if( obj[key]>max ){
max=obj[key];
val=key
}
}
return '因?yàn)?+val+'出現(xiàn)了'+max+'次';
}
var str="ahbbccdeddddfg";
var ch=str.getMostOften();
console.log(ch); //d , 因?yàn)閐 出現(xiàn)了5次
問(wèn)題10: instanceOf有什么作用奏甫??jī)?nèi)部邏輯是如何實(shí)現(xiàn)的苟耻?
instanceOf判斷一個(gè)對(duì)象是否是某個(gè)構(gòu)造函數(shù)的實(shí)例,通過(guò)檢測(cè)某個(gè)構(gòu)造函數(shù)的原型是否存在于要檢測(cè)的對(duì)象的原型鏈上扶檐。
function a(){};
var b=new a();
b instanceof a; //打印true
b instanceof Function凶杖; //打印false
b instanceof Object; //打印true
首先調(diào)用p.__proto__
,看其與所要對(duì)比的函數(shù)的prototype是否相同,即a.prototype款筑。如果不同智蝠,則繼續(xù)調(diào)用p.__proto__.__proto__
.直到調(diào)用至原型鏈最底層。如果p._proto__
的原型鏈上出現(xiàn)了所要對(duì)比的函數(shù)的prototype奈梳,便停止查找杈湾,并返回true,否則返回false攘须。
繼承相關(guān)問(wèn)題
問(wèn)題11:繼承有什么作用?
繼承的作用就是讓子類能獲得父類的方法和屬性漆撞,提高代碼的復(fù)用性。在父類的基礎(chǔ)上于宙,自己可以擴(kuò)展新的屬性和方法浮驳。
問(wèn)題12: 下面兩種寫法有什么區(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);
- 方法1中p1對(duì)象里面有name,sex捞魁,printName三個(gè)屬性
- 方法2中p1對(duì)象里面有name至会,sex兩個(gè)屬性,printName方法綁定在其父類Person的prototype屬性下谱俭,p1可以繼承父類的屬性和方法奉件,所以可以調(diào)用p1.printName宵蛀。
問(wèn)題13: Object.create 有什么作用?兼容性如何县貌?
作用:
Object.create(proto, [ propertiesObject ]):創(chuàng)建一個(gè)具有指定原型且可選擇性地包含指定屬性的對(duì)象术陶。
proto:一個(gè)對(duì)象,作為新創(chuàng)建對(duì)象的原型煤痕⊥穑或者為 null。第二個(gè)參數(shù)是對(duì)象的屬性描述符杭攻,這個(gè)參數(shù)是可選的祟敛。
例如
function Person(name){
this.name=name;
}
Person.prototype.sayName=function(){
console.log('My name is :' + this.name);
console.log( this===p1 );
}
function Student(name,age){
Person.call(this,name); //這里是繼承Person里的屬性
this.age=age;
// console.log(this);
}
Student.prototype=Object.create(Person.prototype); //這里是繼承Person原型里的方法
Student.prototype.constructor=Student; //將Student里新對(duì)象中設(shè)置constructor為本身
Student.prototype.sayAge=function(){ //將Student里新對(duì)象中設(shè)置屬性sayAge
console.log(this.age);
}
var p1 = new Student('hunger',20);
console.log(p1);
p1.sayName();
p1.sayAge();
- 通過(guò)Object.create()方法,讓Student.prototype指向Person.prototype,繼承它的printName方法兆解。
- 對(duì)Student.prototype進(jìn)行修改不會(huì)影響到原來(lái)Person.prototype的屬性和方法馆铁。
兼容性:
問(wèn)題14: hasOwnProperty有什么作用? 如何使用锅睛?
- hasOwnProperty方法會(huì)返回一個(gè)布爾值埠巨,其用來(lái)判斷某個(gè)對(duì)象是否含有特定的自身屬性,該方法會(huì)忽略掉那些從原型鏈上繼承到的屬性现拒。
- 語(yǔ)法為obj.hasOwnProperty(prop)辣垒,參數(shù)prop為要檢測(cè)的屬性。
例如
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.sayName=function(){
console.log(this.name);
}
var p1 = new Person('hunger',100);
console.log( p1.hasOwnProperty('name') ); //打印出true 因?yàn)閷傩詎ame存在于實(shí)例中
console.log( p1.hasOwnProperty('sayName') ); //打印出false 因?yàn)閷傩允菑膒rototype中繼承的
問(wèn)題15:如下代碼中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í)行的環(huán)境印蔬。在Male作用域下執(zhí)行Person函數(shù)勋桶。此時(shí)Person函數(shù)中的this,就指向Male函數(shù)中的this侥猬。
Male(name,sex,age)中的name和sex則是傳遞給Person的參數(shù)例驹。 - 通過(guò)這種方式就實(shí)現(xiàn)了屬性的繼承。
問(wèn)題16: 補(bǔ)全代碼退唠,實(shí)現(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 ruoyu = new Male('若愚', '男', 27);
ruoyu.printName();
代碼如下
function Person(name,sex){
this.name=name;
this.sex=sex;
}
Person.prototype.getName=function(){
console.log(this.name);
//console.log(this);
}
function Male(name,sex,age){
Person.call(this,name,sex);
this.age=age;
}
Male.prototype = Object.create(Person.prototype);
Male.prototype.constructor = Male;
Male.prototype.getAge=function(){
console.log(this.age);
}
var ruoyu = new Male('若愚','男',27);
console.log(ruoyu);
ruoyu.getName();