問題1: apply剖淀、call 肿男、bind有什么作用介汹,什么區(qū)別
apply和call就是為了改變函數(shù)內(nèi)部this的指向;
如果使用apply或call方法舶沛,那么this指向他們的第一個(gè)參數(shù)嘹承,apply的第二個(gè)參數(shù)是一個(gè)參數(shù)數(shù)組,call的第二個(gè)及其以后的參數(shù)都是數(shù)組里面的元素冠王,就是說要全部列舉出來赶撰;bind與apply、call最大的區(qū)別就是:bind不會(huì)立即調(diào)用,其他兩個(gè)會(huì)立即調(diào)用
舉例:
var info = 'tom';
function foo(){
//this指向window
var info = 'jerry';
console.log(this.info); //tom
console.log(this===window) //true
}
foo();
var obj = {
info:'spike'
}
foo.call(obj); //這里foo函數(shù)里面的this就指向了obj
foo.apply(obj);//輸出
var arr = [123,34,5,23,3434,23];
//方法一
var arr1 = arr.sort(function(a,b){
return b-a;
});
console.log(arr1[0]);
//方法二
var max = Math.max.apply(null,arr) //借用別的對(duì)象的方法
console.log(max);
2.獲取數(shù)組中的最大值和最小值,利用他們擴(kuò)充作用域擁有Math的min和max方法凭舶;
由于沒有什么對(duì)象調(diào)用這個(gè)方法,所以第一個(gè)參數(shù)可以寫作null或者本身瘤载;
var numbers = [5, 458 , 120 , -215 ];
var maxInNumbers = Math.max.apply(Math, numbers), //458
maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215);
驗(yàn)證是否是數(shù)組(前提是toString()方法沒有被重寫過)
function isArray(obj){
return Object.prototype.toString.call(obj) === '[object Array]' ;
}
問題3: 下面代碼輸出什么,為什么
func()
function func() {
alert(this)
}
輸出為window對(duì)象卖擅。由于func是在全局作用域下被調(diào)用
問題4:下面代碼輸出什么
document.addEventListener('click', function(e){
console.log(this);//document鸣奔,是DOM對(duì)象本身,
setTimeout(function(){
console.log(this);//window惩阶,這是由于setTimeout函數(shù)是掛在window
對(duì)象下的
}, 200);
}, false);
問題5:下面代碼輸出什么挎狸,why
var john = {
firstName: "John"
}
function func() {
alert( this.firstName )
}
func();//輸出undefined,因?yàn)槿窒略L問不到firstname
問題6: 以下代碼有什么問題,如何修改
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指的是btn
this.showMsg();
})
},
showMsg: function(){
console.log('饑人谷');
}
}
bind屬性中断楷,this.showMsg()語句的this指的是$btn锨匆,是無法調(diào)用showMsg()的,
此時(shí)需要保存事件綁定函數(shù)外部的this冬筒,修改如下
var module= {
bind: function(){
var cur = this//這里的this指的是module,先把它保存起來以后用
$btn.on('click', function(){
console.log(this) //this指的是btn
cur.showMsg(); 這里就可以名正言順調(diào)用自己的方法了相當(dāng)于module.showMsg
})
},
showMsg: function(){
console.log('饑人谷');
}
}
補(bǔ)充類似題目
1
var o = {
foo:'bar',
func: function(){
console.log(this)
}
}
var a = o.func;
a();//打印出來的this變成了全局對(duì)象window恐锣,不再是o
在瀏覽器中輸入a,返回的是一個(gè)函數(shù)舞痰,當(dāng)再次調(diào)用a土榴,就是相當(dāng)于在全局作用域下調(diào)用函數(shù)
2
先打印的是person的name2,然后是全局name1
假如最后添加兩行代碼响牛,var a=person.say; a()
意思是先把函數(shù)賦給a玷禽,則a就是一個(gè)函數(shù)了赫段,在調(diào)用a相當(dāng)于在全局下調(diào)用
var myobject={
foo:"bar",
func:function () {
var self=this;
console.log(this.foo);//bar無疑問
(function() {
console.log(this)//window,立即執(zhí)行函數(shù)有自己的作用域
console.log(this.foo)//理所當(dāng)然undefined
console.log(self.foo);//還為bar
})();
}
}
myobject.func();
假如變形把最后一行改為var f=myobject.func;
f()矢赁,則this指的就是window瑞佩,根本拿不到foo的值,全是undefined
var name='name1';
function say() {
console.log(name);
}
var person={
name:'name2',
say:say
}
person.say();
say();//注意與上題的不同坯台,這里的打印出來的name都是全局name!!!!!
var user='jrg';
var box={
user:'hh',
getuser:function () {
var self=this;
return function () {
return self.user
}
}
}
console.log(box.getuser()())
非常具有迷惑性一個(gè)題目,首先把box.getuser打印出來就一目了然了瘫寝,是打印hh,因?yàn)橛衯ar self=this;所以無論怎么變形都是打印hh,box.getuser().call(box)這個(gè)也是打印相同結(jié)果
function func1() {
var n=99;
nadd=function () {
console.log(this)
this.n+=1;
console.log(this.n)
}
function func2() {
console.log(n)
}
return func2;
}
var result=func1();
result();
nadd();NAN,這個(gè)函數(shù)能訪問到有點(diǎn)不懂
result();
var obj={
name:'obj',
close:function () {
this.name="close";
return function () {
return this.name;
}
}
}
console.log(obj.close().call(obj))不call的話輸出為空蜒蕾,加了輸出為close,obj的name已經(jīng)改變
原型鏈相關(guā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();
- Person是構(gòu)造函數(shù)褒纲,也是一個(gè)對(duì)象准夷,這個(gè)對(duì)象里面存在一個(gè)prototype屬性,而構(gòu)造函數(shù)內(nèi)部定義了實(shí)例的屬性和方法莺掠,這些屬性和方法是屬于該類的所有實(shí)例的特征衫嵌;
- p是通過構(gòu)造函數(shù)Person構(gòu)造出來的實(shí)例,也是擁有proto屬性彻秆。所以p.proto === Person.prototype;
- prototype是構(gòu)造函數(shù)內(nèi)部的原型對(duì)象楔绞,所以擁有contructor和proto屬性,其中contructor屬性指向構(gòu)造函數(shù)Person唇兑,proto指向該對(duì)象的原型酒朵,即
Person.prototype.__proto__ === Object.prototype;
Person.prototype.constructor == Person
問題8: 上例中,對(duì)對(duì)象 p可以這樣調(diào)用 p.toString()扎附。toString是哪里來的? 畫出原型圖?并解釋什么是原型鏈蔫耽。
- p.toString()方法是繼承構(gòu)造函數(shù)Object的原型對(duì)象里定義的toString方法,首先p會(huì)找自己的toString方法帕棉,如果沒有找到针肥,會(huì)沿著proto屬性繼續(xù)到構(gòu)造函數(shù)Person的prototype里找toString方法,如果還未找到香伴,再繼續(xù)往Person.prototype的proto即Object.prototype找toString方法慰枕,最后找到toString()方法。
- 原型鏈:由于原型對(duì)象本身也是對(duì)象即纲,而每個(gè)javascript對(duì)象都有一個(gè)原型對(duì)象具帮,每個(gè)對(duì)象都有一個(gè)隱藏的proto屬性,原型對(duì)象也有自己的原型,而它自己的原型對(duì)象又可以有自己的原型蜂厅,這樣就組成了一條鏈匪凡,這個(gè)就是原型鏈。在訪問對(duì)象的屬性時(shí)掘猿,如果在對(duì)象本身中沒有找到病游,則會(huì)去原型鏈中查找,如果找到稠通,直接返回值衬衬,如果整個(gè)鏈都遍歷且沒有找到屬性,則返回undefined改橘。原型鏈一般實(shí)現(xiàn)為一個(gè)鏈表滋尉,這樣就可以按照一定的順序來查找。
補(bǔ)充:
var a={n:4399}
var b=function () {
this.n=9999
}
var c=function () {
var n=8888
}
b.prototype=a;
c.prototype=a;
var d=new b();
var e=new c()
a.n++;
console.log(d.n)9999自己的
console.log(e.n)4400a的
這個(gè)實(shí)在理解不了飞主。狮惜。。
var F=function () {
}
Object.prototype.a=function () {
}
Function.prototype.b=function () {
}
var f=new F();
F能拿到b碌识,f拿不到因?yàn)樗约菏菍?duì)象
問題9:對(duì)String做擴(kuò)展碾篡,實(shí)現(xiàn)如下方式獲取字符串中頻率最高的字符
String.prototype.getMostOften = function() {
var obj = {};
for (var i = 0; i < this.length; i++) {
if(!obj[this[i]]) {
obj[this.charAt(i)] = 1;
}else if(obj[this[i]]) {
obj[this.charAt(i)]++;
}
}
console.log(obj);
var val = '';
var num = 0;
for(var key in obj) {
if (obj[key] > num) {
num = obj[key];
val = key
}
}
return (val,'因?yàn)?+val+'出現(xiàn)了'+num+'次');
};
var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因?yàn)閐 出現(xiàn)了5次
問題10: instanceOf有什么作用?內(nèi)部邏輯是如何實(shí)現(xiàn)的丸冕?
簡單來記就是如果實(shí)例的_proto不等于構(gòu)造函數(shù)的prototype就去實(shí)例的
_proto_._proto_去找
function instanceOf(obj,Func){
var __proto__=obj.__proto__;
do{
if(__proto__===Func.prototype) {
return true;
}
if(!__proto__) return false;
}
while(__proto__=__proto__.__proto__);
return false;
}
繼承相關(guān)問題
問題11:繼承有什么作用?
JavaScript 對(duì)象有一個(gè)指向一個(gè)原型對(duì)象的鏈耽梅。當(dāng)試圖訪問一個(gè)對(duì)象的屬性時(shí),它不僅僅在該對(duì)象上搜尋胖烛,還會(huì)搜尋該對(duì)象的原型眼姐,以及該對(duì)象的原型的原型,依此層層向上搜索佩番,直到找到一個(gè)名字匹配的屬性或到達(dá)原型鏈的末尾众旗。這就意味著,JS對(duì)象可以使用所有其原型的所有方法趟畏,如果我們?cè)谠蜕咸砑有碌姆椒ü逼纾敲磳?shí)例也會(huì)擁有該方法,能夠大大減少冗余代碼
問題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);
區(qū)別:同樣都是創(chuàng)建printName方法赋秀,方法1的printName方法是在函數(shù)Person實(shí)例對(duì)象里的利朵,方法2是在Person的prototype對(duì)象上的。當(dāng)再創(chuàng)建一個(gè)Person實(shí)例對(duì)象的時(shí)候猎莲,方法1又將會(huì)再創(chuàng)建一個(gè)printName方法绍弟,占用新的內(nèi)存,而方法2將一個(gè)公用的printName方法寫在原型上著洼,當(dāng)對(duì)象要使用該方法只需到原型鏈里調(diào)用就可以了樟遣,達(dá)到節(jié)省內(nèi)存的效果
問題13: Object.create 有什么作用而叼?兼容性如何?
- 作用:創(chuàng)建一個(gè)擁有指定原型和若干個(gè)指定屬性的對(duì)象豹悬。
-
兼容性:
-使用:
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
console.log(this.name);
}
function Male(name, age, sex){
Person.call(this, name, age);
this.sex = sex;
}
// Male.prototype = new Person(); //該方法同下葵陵,代替不兼容Object.create()的使用場(chǎng)景
Male.prototype = Object.create(Person.prototype);
Male.prototype.constructor = Male;
Male.prototype.sayAge = function(){
console.log(this.age);
};
var p1 = new Male('hunger', 20, 'nan');
p1.sayName();//hunger
p1.sayAge();//20
問題14: hasOwnProperty有什么作用? 如何使用瞻佛?
function Person(name,age) {
this.name = name;
this.age = age;
}
Person.prototype.printName = function() {
console.log(this.name);
}
function people(name) {
this.name = name;
}
people.prototype = Object.create(Person.prototype);
var p = new people('John');
console.log(p.hasOwnProperty('printName'));//false也就是說必須是自己的脱篙,
從原型繼承過來的不算
問題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;
}
Male中的call,指定了其執(zhí)行環(huán)境在Person下伤柄。換句話說涡尘,實(shí)現(xiàn)了從People的繼承
問題16: 補(bǔ)全代碼,實(shí)現(xiàn)繼承
function Person(name, sex){
this.name = name;
this.sex = sex;
}
Person.prototype.getName = function(){
return this.name;
};
Person.prototype.printName = function () {
console.log(this.name)
}
function Male(name, sex, age){
this.sex = sex;
Person.call(this,name,sex);
}
Male.prototype = Object.create(Person.prototype);
Male.prototype.constructor = Male;
Male.prototype.getAge = function(){
return this.age;
};
var ruoyu = new Male('若愚', '男', 27);
ruoyu.printName();