摘要:本文是高級(jí)入門的配套試題,題目解析的部分內(nèi)容將引用高級(jí)入門。接收一個(gè)對象,并由這個(gè)對象去調(diào)用函數(shù)。循環(huán)內(nèi),調(diào)用函數(shù),并設(shè)置第二個(gè)參數(shù)的值為。所以相當(dāng)于執(zhí)行而的作用是往消息隊(duì)列中存放一個(gè)回調(diào)函數(shù),并在特定時(shí)間間隔后執(zhí)行它。
本文是JS高級(jí)入門的配套試題,題目解析的部分內(nèi)容將引用JS高級(jí)入門。
題目一(this指針)
function logName(){ console.log(this.name); } function doFun1(fn){ fn(); } function doFun2(o){ o.logName(); } var obj = { name: "LiLei", logName: logName }; var name = "HanMeiMei"; doFun1(obj.logName); doFun2(obj);解析
題目首先定義了三個(gè)函數(shù):
【】logName:打印調(diào)用者(即誰去調(diào)用它,通常是一個(gè)對象)的name屬性。
【】doFun1:接收一個(gè)函數(shù),并直接運(yùn)行這個(gè)函數(shù)。
【】doFun2:接收一個(gè)對象,并由這個(gè)對象去調(diào)用logName函數(shù)。
而后定義了兩個(gè)變量:
【】obj是一個(gè)對象,里面定義了name(假設(shè)另命名為_name)的字符串變量。定義了logName(假設(shè)另起名字為_logName),指向外部的logName函數(shù)。
【】name是一個(gè)字符串變量。
最后分別對兩個(gè)函數(shù)進(jìn)行調(diào)用,
【】doFun1(obj.logName)。
向函數(shù)傳遞了obj對象內(nèi)部的_logName,而_logName是指向logName的。所以實(shí)際上doFun1接收的是指向logName函數(shù)的變量。即等價(jià)于doFun1(logName)。
而在doFun1內(nèi)部是直接執(zhí)行l(wèi)ogName的。沒有明確的調(diào)用者。則這時(shí)等價(jià)于由window對象去調(diào)用,等價(jià)于window.logName。
而再由于所有在全局作用域(注意僅僅是全局作用域)中定義的變量都是window對象下的變量。都可以通過window對象進(jìn)行訪問。
所以這時(shí)訪問到的就是name。
所以輸出的是HanMeiMei。
【】doFun2(obj)。
傳遞給doFun2的是obj的地址值,即doFun2中的o指向的就是obj,等價(jià)于obj。
o.logName是由o去調(diào)用logName。相當(dāng)于obj.logName。
所以找到的是obj內(nèi)部的name(即我們假定的_name)。
所以打印出的是LiLei。
答案HanMeiMei LiLei
題目二(this指針的修改apply)
function fun(somthing) { console.log(this.name, somthing); } function bindFun(fn, obj) { return function () { return fn.apply(obj, arguments); } } var obj = { name: "LiLei" }; var bar = bindFun(fun, obj); var b = bar("HanMeiMei"); console.log(b);解析
本題的主要考點(diǎn)是this的相關(guān)函數(shù)apply。
首先定義了三個(gè)函數(shù):
【】fun函數(shù):接收變量,并且打印這個(gè)函數(shù)的調(diào)用者的name值,以及形參something。
【】bindFun函數(shù):接收兩個(gè)參數(shù),分別是函數(shù)以及對象。bindFun沒有邏輯操作。只是返回了一個(gè)匿名函數(shù)(我們假定為_fun)
【】_fun函數(shù):同樣沒有操作,直接返回一個(gè)已經(jīng)通過apply修改了this的函數(shù)的執(zhí)行結(jié)果。(即直接返回一個(gè)函數(shù)執(zhí)行結(jié)果值,而這個(gè)函數(shù)的this的值是已經(jīng)被修改過的)
而后定義了三個(gè)變量:
【】obj是一個(gè)對象,里面只定義了name字符串變量。
【】bar是一個(gè)變量,這個(gè)變量的值為bindFun函數(shù)執(zhí)行的結(jié)果值。
【】b是一個(gè)變量,值為bar函數(shù)執(zhí)行的結(jié)果值。
整段代碼中,除了定義,一共只執(zhí)行了3句邏輯語句:
【】在bindFun函數(shù)的執(zhí)行,傳遞了兩個(gè)函數(shù),分別是fun函數(shù),obj對象。bindFun函數(shù)執(zhí)行結(jié)果是返回一個(gè)函數(shù)_fun。所以bar指向_fun函數(shù)。
【】bar函數(shù)的調(diào)用,即相當(dāng)于_fun函數(shù)的調(diào)用。
_fun函數(shù)的返回fn.apply(obj, arguments)的運(yùn)行值;
其中這里的fn是bindFun函數(shù)接受的第一個(gè)參數(shù)fun,即返回的是fun函數(shù)。
而這個(gè)fun函數(shù)進(jìn)行了apply的函數(shù)調(diào)用,修改了函數(shù)中this的值。
this指向?yàn)閎indFun函數(shù)的第二個(gè)參數(shù)值,即外部的obj變量。
apply函數(shù)還接受了第二個(gè)參數(shù)arguments,即_fun函數(shù)的參數(shù)數(shù)組。即bar函數(shù)的參數(shù)數(shù)組【"HanMeiMei"】。作為fun函數(shù)的參數(shù)。
apply函數(shù)的作用是馬上執(zhí)行調(diào)用者函數(shù),即馬上執(zhí)行bar(即_fun,即fun)函數(shù)。
fun函數(shù)執(zhí)行是打印this.name,和參數(shù)something。this指向obj,所以this.name為LiLei。而something值為【"HanMeiMei"】
所以打印了,LiLeiHanMeiMei。并且沒有返回值。
【】b是bar函數(shù)的返回值,然而bar函數(shù)并沒有返回東西,所以是undefined。所以console.log(b)打印的值是undefined。
繞了一圈,整個(gè)過程相當(dāng)于執(zhí)行。fun.call(obj,"HanMeiMei");
答案LiLeiHanMeiMei undefined
題目三(自執(zhí)行函數(shù))
function logName() { console.log(this); console.log(this.name); } var name = "XiaoMing"; var LiLei = { name: "LiLei", logName: logName }; var HanMeiMei = { name: "HanMeiMei" }; (HanMeiMei.logName = LiLei.logName)();解析
這題相對簡單一些。只考到自執(zhí)行函數(shù)的定義。并沒有借助他的特性做代碼隔離。只是想考一下是否已經(jīng)掌握了自執(zhí)行函數(shù)的定義。
首先定義了一個(gè)函數(shù):
【】logName,打印出調(diào)用者(即this指針的指向),已經(jīng)調(diào)用者的name屬性值
而后定義了三個(gè)變量:
【】name:字符串變量,由于全局的,所以相當(dāng)于window對象的屬性值。
【】LiLei:定義了對象,該對象包含name值,以及l(fā)ogName(我們假定LiLei的logName重新命名為_logName)。指向外部的logName函數(shù)
【】HanMeiMei:定義了對象,該對象只包含name值。
最終只執(zhí)行了一條語句,兩個(gè)步驟。
分別是賦值語句:
為HanMeiMei對象添加一個(gè)參數(shù)logName,賦值為LiLei的_logName。即指向外部的logName。這不是重點(diǎn),重點(diǎn)是賦值語句的結(jié)果是什么?
是所賦的值,即賦值語句的結(jié)果是LiLei.logName,即HanMeiMei.logName = LiLei.logName終止得到的是logName。
然后對這個(gè)函數(shù)進(jìn)行調(diào)用。即logName(),這時(shí)this沒有發(fā)生改變,還是window,所以輸出是打印window對象。已經(jīng)window.name即XiaoMing。
答案XiaoMing
題目四(聲明提前)
test(); var test = 0; function test() { console.log(1); } test(); test = function () { console.log(2); }; test();解析
聲明提前的題,把背后的代碼執(zhí)行順序理順就好。
首先將聲明都放到代碼的最上面:
var test;//定義變量
function test(){console.log(1)}//定義函數(shù)
然后執(zhí)行的操作:
test();//函數(shù)調(diào)用操作
test = 0;//賦值操作
test();//函數(shù)調(diào)用操作
test = function(){console.log(2)}//賦值操作,將test賦值為函數(shù)
test();//函數(shù)調(diào)用操作
所以上述代碼等價(jià)于(聲明提前,先定義,后執(zhí)行):
var test;
function test(){console.log(1)}
test();//調(diào)用函數(shù),輸出1
test = 0;
test();//此時(shí)test為0,不是函數(shù),將報(bào)錯(cuò)test is not a function
test = function(){console.log(2)}//由于JS報(bào)錯(cuò),后面的代碼將不被運(yùn)行
test();//由于JS報(bào)錯(cuò),后面的代碼將不被運(yùn)行
綜合來說,這里設(shè)置了三個(gè)考點(diǎn):
聲明提前。
函數(shù)的定義與函數(shù)賦值的區(qū)別,function xx為函數(shù)定義,將整體上移。
JS報(bào)錯(cuò)后,后面的代碼將不被運(yùn)行。
答案1 Uncaught TypeError: test is not a function
題目五(基本類型與引用類型)
var name = "LiLei"; var people = {name: "HanMeiMei"}; function test1(name) { name = "LaoWang"; } function test2(obj) { obj.name = "LaoWang"; } test1(name); test2(people); console.log("name " + name); console.log("name " + people.name);解析
題目首先定義了兩個(gè)函數(shù):
【】test1:接受一個(gè)參數(shù),并修改該參數(shù)的值。
【】test2:接收一個(gè)對象,并修改該對象的屬性的值。
而后定義了兩個(gè)變量:
【】name是一個(gè)字符串參數(shù),值為"LiLei"
【】people是一個(gè)對象,包含一個(gè)name屬性。值為"HanMeiMei"
然后分別對兩個(gè)函數(shù)進(jìn)行調(diào)用:
test1(name):即將name作為參數(shù),調(diào)用test1函數(shù)。
這時(shí)函數(shù)的內(nèi)部將產(chǎn)生一個(gè)新的參數(shù)name(記作_name),它的值等于外部的name的值(LiLei);
test1函數(shù)將_name的值修改為"LaoWang",但是由于_name和name是兩份獨(dú)立的變量。所以name的值不受改變。
test2(people):將people作為參數(shù),調(diào)用test1函數(shù)。
這時(shí)函數(shù)的內(nèi)部將產(chǎn)生一個(gè)新的參數(shù)obj,它的值等于外部的people的值;
而people是引用類型,其值為對象{name:"HanMeiMei"}的地址值。所以obj也為對象{name:"HanMeiMei"}的地址值。
test2對對象{name:"HanMeiMei"}的name屬性進(jìn)行修改,改為"LaoWang"
所以obj和people的name值都發(fā)生了改變。
這里涉及到兩個(gè)知識(shí)點(diǎn)
基本數(shù)據(jù)類型是按值訪問的,即該變量就存在了實(shí)際值。而引用數(shù)據(jù)類型保存的是則是對實(shí)際值的引用(即指向?qū)嶋H值的指針)。
函數(shù)形參(即在函數(shù)中實(shí)際使用的值,如test函數(shù)里面的name)和參數(shù)的實(shí)參(即往調(diào)用函數(shù)時(shí)調(diào)用的參數(shù),如test(name)中的name)的值相同,但并不是"同一個(gè)值"(在內(nèi)存中的地址是不同的,相當(dāng)于var a = b =0;)。
在函數(shù)參數(shù)的傳遞,是通過按值傳遞的。
答案LiLei LaoWang
題目六(JS線程與閉包)
執(zhí)行的結(jié)果是什么,分別在什么時(shí)間輸出 for (var i = 1; i < 5; i++) { setTimeout(function () { console.log(i); }, i * 1000); }解析
JS線程的規(guī)則:程序?qū)⑾劝阎鬟壿嫷膬?nèi)容做完,再去讀取消息列表,調(diào)用消息列表中的回調(diào)函數(shù)
在這里主邏輯為一個(gè)for循環(huán),從i為1到i為4循環(huán)執(zhí)行4次for循環(huán)的內(nèi)容。
for循環(huán)內(nèi),調(diào)用setTimeout函數(shù),并設(shè)置第二個(gè)參數(shù)的值為i。注意這里是對setTimeout函數(shù)直接進(jìn)行調(diào)用。所以參數(shù)中i的值是隨for循環(huán)改變的。所以相當(dāng)于執(zhí)行
setTimeout(function () {doSomething}, 1000);
setTimeout(function () {doSomething}, 2000);
setTimeout(function () {doSomething}, 3000);
setTimeout(function () {doSomething}, 4000);
而setTimeout的作用是往消息隊(duì)列中存放一個(gè)回調(diào)函數(shù),并在特定時(shí)間間隔后執(zhí)行它。所以該回調(diào)函數(shù)會(huì)在for循環(huán)之后完成。
for循環(huán)執(zhí)行完時(shí),i的值為5。(因?yàn)?<5不成立,結(jié)束循環(huán))。所以調(diào)用回調(diào)函數(shù)function(){console.log(i)}時(shí),i的值為5。所以輸出為5。
閉包是因?yàn)榛卣{(diào)函數(shù)引用到了for循環(huán)的i,回調(diào)函數(shù)沒執(zhí)行完,i不能被回收。所以還是能訪問到。
答案輸出4次,每一秒輸出一個(gè)5
題目七(作用域陷阱)
function logName(){ console.log(name); } function test () { var name = 3; logName(); } var name = 2; test();解析
一句話可以解釋完:作用域的層級(jí)關(guān)系與函數(shù)定義時(shí)所處的層級(jí)關(guān)系相同
注意是,函數(shù)定義時(shí)的層級(jí)關(guān)系,而不是調(diào)用時(shí)的層級(jí)關(guān)系。
在這里,logName函數(shù),test函數(shù)以及外部的name變量(值為2)處于同一個(gè)層級(jí)。
所以調(diào)用logName時(shí),找到的是外部的name變量。
所以打印出2
2
題目八(隱式閉包)
function logNum(num) { console.log("num " + num); } for (var i = 0; i < 2; i++) { var fun = logNum.bind(null, i); setTimeout(fun, 100); }解析
這道題和第六題很像,但是運(yùn)行結(jié)果并不一樣。
原因是bind函數(shù)產(chǎn)生了隱式閉包。
為什么bind函數(shù)能修改this指針?底層實(shí)現(xiàn)筆者不知道,但是我們可以利用閉包的特性通過自執(zhí)行函數(shù)來模擬bind函數(shù)。
bind(obj,elem0,elem1,elem2...)函數(shù)相當(dāng)于
(function(_obj,_elem0,_elem1,_elem2...){ return function(){//這個(gè)函數(shù)就是調(diào)用bind函數(shù)的函數(shù) doSomething; //將this.替換成_obj. //這里將可能使用到_elem0,_elem1,_elem2參數(shù)。 } })(obj,elem0,elem1,elem2...)
通過自執(zhí)行函數(shù)返回一個(gè)函數(shù),形成一個(gè)閉包,內(nèi)部函數(shù)調(diào)用的參數(shù)是自執(zhí)行函數(shù)的參數(shù),而不是外部的元素。
根據(jù)前面第五題的解析函數(shù)形參(即在函數(shù)中實(shí)際使用的值,如test函數(shù)里面的name)和參數(shù)的實(shí)參(即往調(diào)用函數(shù)時(shí)調(diào)用的參數(shù),如test(name)中的name)的值相同,但并不是"同一個(gè)值"(在內(nèi)存中的地址是不同的,相當(dāng)于var a = b =0;)。
doSomething中使用到的參數(shù)是自執(zhí)行函數(shù)的形參(_elemX),而不是外部的實(shí)參elem。
所以外部的elem的變化對doSomething沒有影響。
根據(jù)解析,對題目進(jìn)行改造,相當(dāng)于
function logNum(num) { console.log("num " + num); } for (var i = 0; i < 2; i++) { var fun = (function(_i){ return function(){ console.log(_i); } })(i); setTimeout(fun, 100); }
而自執(zhí)行函數(shù)是定義完馬上執(zhí)行的。所以拿到的值_i也是隨著for循環(huán)改變的。
所以輸出0 1
利用該特性還可以解決常見的面試題:通過原生JS返回所點(diǎn)擊元素索引值。
var domList = document.getElementsByTagName("div"); for (var i = 0, length = domList.length; i < length; i++) { var item = domList[ i ]; (function(_item, _i) { _item.addEventListener("click", function() { console.log(_i); }) })(item, i) }答案
0 1
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/81869.html
摘要:閑心面試題一任選一題分的區(qū)別的區(qū)別是無序列表,是有序列表,是定義列表有層次關(guān)系。無任何語義,僅僅用作樣式化或者腳本化的鉤子是有一定語義的,適合有主題性的內(nèi)容,表示一個(gè)專題,一般有標(biāo)題,但是不可以亂用。誕生于年,由等人創(chuàng)建,后為所收購。 閑心面試題 一、任選一題(5分)a) ul、ol、dl的區(qū)別?b) div、section、article的區(qū)別? a:ul是無序列表,ol是有序列表,...
摘要:前端工程師學(xué)習(xí)資料,快速查找面試題,經(jīng)典技術(shù)文章的總結(jié),編程技巧,幫助學(xué)習(xí)者快速定位問題花點(diǎn)時(shí)間整理出一下前端工程師日常工作所需要的學(xué)習(xí)資料查找,幫助學(xué)習(xí)者快速掌握前端工程師開發(fā)的基本知識(shí)編程始于足下記住再牛逼的夢想也抵不住傻逼似的堅(jiān)持蝴蝶 前端工程師學(xué)習(xí)資料,快速查找面試題,經(jīng)典技術(shù)文章的總結(jié),編程技巧,幫助學(xué)習(xí)者快速定位問題花點(diǎn)時(shí)間整理出一下web前端工程師日常工作所需要的學(xué)習(xí)資料...
摘要:面試題來源于網(wǎng)絡(luò),看一下高級(jí)前端的面試題,可以知道自己和高級(jí)前端的差距。 面試題來源于網(wǎng)絡(luò),看一下高級(jí)前端的面試題,可以知道自己和高級(jí)前端的差距。有些面試題會(huì)重復(fù)。 使用過的koa2中間件 koa-body原理 介紹自己寫過的中間件 有沒有涉及到Cluster 介紹pm2 master掛了的話pm2怎么處理 如何和MySQL進(jìn)行通信 React聲明周期及自己的理解 如何...
閱讀 3957·2021-11-16 11:50
閱讀 951·2021-11-11 16:55
閱讀 3677·2021-10-26 09:51
閱讀 878·2021-09-22 15:03
閱讀 3447·2019-08-30 15:54
閱讀 3273·2019-08-30 15:54
閱讀 2487·2019-08-30 14:04
閱讀 930·2019-08-30 13:53