摘要:函數(shù)的形參和函數(shù)體就是兩個(gè)不同的作用域。這里只聲明了還是形參這里改變了形參的值,所以返回是這題還有一個(gè)坑點(diǎn),我拿到里面去轉(zhuǎn)一下得到的結(jié)果是這里結(jié)果是這種神奇的代碼還是盡量不要寫(xiě)呀如果有理解錯(cuò)誤的地方,歡迎指正
把話說(shuō)完:90%面試官都不會(huì)問(wèn)的題,因?yàn)槊嬖嚬僖膊灰欢ǘ?/p>
直接來(lái)看一看今天要說(shuō)的題目:
// 問(wèn)題:foo.x的值是什么?bar.x? var foo = { n: 1 }; var bar = foo; foo.x = foo = { n: 2 }; console.log(foo.x) // ? console.log(bar.x) // ? // 問(wèn)題:下面兩題的結(jié)果是? (function(x, f = () => x) { var x; var y = x; x = 2; return [x, y, f()]; // ? })(1) (function(x, f = () => x) { var y = x; x = 2; return [x, y, f()]; // ? })(1)
這兩題是我最近在一個(gè)討論群里看到的,發(fā)出來(lái)的時(shí)候還是引起了大家非常熱烈的討論。不過(guò)大家最后都覺(jué)得這種題目沒(méi)有什么意義,實(shí)際做項(xiàng)目的時(shí)候不會(huì)也不建議這么寫(xiě)(ps: 我要是在項(xiàng)目發(fā)現(xiàn)誰(shuí)這樣寫(xiě),直接從三樓丟下去),不過(guò)從學(xué)習(xí)的角度其實(shí)還是可以研究一下的。
第一個(gè)問(wèn)題:// 問(wèn)題:foo.x的值是什么?bar.x? var foo = { n: 1 }; var bar = foo; foo.x = foo = { n: 2 }; console.log(foo.x) // ? console.log(bar.x) // ?
我一看到這個(gè)問(wèn)題,第一個(gè)反應(yīng)的結(jié)果是:
foo.x = {n: 2}; bar.x = {n: 2};
當(dāng)時(shí)我的內(nèi)心獨(dú)白是這樣的: So easy !! 這種題也有什么好問(wèn)的!
然而結(jié)果是:
bar.x = {n: 2}; foo.x = undefined;
Why!!!!!!?????? 我表示很郁悶
然后我果斷去調(diào)研了一番,下面大概總結(jié)一下~
針對(duì)這題其實(shí)要明白兩點(diǎn):
對(duì)于對(duì)象賦值,傳遞的都是引用,都是引用調(diào)用
對(duì)于賦值語(yǔ)句,總是先對(duì)lhs求值,再對(duì)rhs求值,然后PutValue。
可以參考一下ECMAScript標(biāo)準(zhǔn),下面來(lái)看一下上面代碼的執(zhí)行。
1.第一第二行代碼很簡(jiǎn)單,就是把一個(gè)對(duì)象({n: 2})賦給 foo, 然后通過(guò) foo 再把對(duì)象賦值給 bar。這時(shí)候 bar 和 foo 存的都是對(duì)象 {n: 2} 的引用。
2.接下來(lái)重點(diǎn)看 foo.x = foo = { n: 2 }。我們就按照 [ 對(duì)于賦值語(yǔ)句,總是先對(duì)lhs求值,再對(duì)rhs求值,然后PutValue。 ] 來(lái)解析這行代碼。
第一步,首先對(duì) foo.x 進(jìn)行求值,foo 指向的是對(duì)象 { n: 2 }(下面稱(chēng)為:ObjectF ), ObjectF 沒(méi)有屬性 x ,那么為 ObjectF 添加屬性x,左值的求值結(jié)果就是對(duì)剛才添加的屬性 x 的引用(某個(gè)內(nèi)存地址X)。
第二步, 對(duì)右值進(jìn)行求值,右值是 foo = {n : 2}。遞歸向下,先對(duì)左值求值,得到 foo,foo 還是 ObjectF 引用,然后對(duì)右值{a : 2}求值,得到 ObjectE ,接著PutValue將改變 foo 的指向到 ObjectE,賦值表達(dá)式foo = {n : 2}返回得到 ObjectE引用。
這個(gè)時(shí)候 foo 和 ObjectF 已經(jīng)解綁,而且重新指向了 ObjectE,ObjectE上沒(méi)有 x 這個(gè)屬性,所以 foo.x 這個(gè)時(shí)候是undefined。
第三步, PutValue將左值指向 ObjectE,也就是說(shuō)第一步中的內(nèi)存地址X存的是ObjectE的引用。
到這里整個(gè)賦值過(guò)程就完成了。
第二個(gè)問(wèn)題:// 問(wèn)題:下面兩題的結(jié)果是? (function(x, f = () => x) { var x; var y = x; x = 2; return [x, y, f()]; // [2, 1, 1] })(1) (function(x, f = () => x) { var y = x; x = 2; return [x, y, f()]; // [2, 2, 1] })(1)
對(duì)于這個(gè)問(wèn)題,第二個(gè)函數(shù)相信大家都不會(huì)有啥疑問(wèn)。應(yīng)該集中在第一個(gè)上。
要理解這題也需要明白兩個(gè)點(diǎn):
1.函數(shù)體內(nèi)和函數(shù)體外是兩個(gè)不同的命名空間或者說(shuō)作用域,函數(shù)體外的作用域是不能訪問(wèn)函數(shù)體內(nèi)的變量的。函數(shù)的形參(x, f) 和 函數(shù)體 { } 就是兩個(gè)不同的作用域。
(function(a, f = () => x) { var x = 2; return [ a, f()]; })(1) // Uncaught ReferenceError: x is not defined
2.函數(shù)中的默認(rèn)參數(shù)可用于后面的默認(rèn)參數(shù)(已經(jīng)遇到的參數(shù)可用于以后的默認(rèn)參數(shù))。
怎么理解 【函數(shù)中的默認(rèn)參數(shù)可用于后面的默認(rèn)參數(shù)(已經(jīng)遇到的參數(shù)可用于以后的默認(rèn)參數(shù))】,看下面的例子:
function singularAutoPlural(singular, plural = singular+"s", rallyingCry = plural + " ATTACK!!!") { return [singular, plural, rallyingCry ]; } //["Gecko","Geckos", "Geckos ATTACK!!!"] singularAutoPlural("Gecko"); //["Fox","Foxes", "Foxes ATTACK!!!"] singularAutoPlural("Fox","Foxes"); //["Deer", "Deer", "Deer ... change."] singularAutoPlural("Deer", "Deer", "Deer peaceably and respectfully petition the government for positive change.")
Demo來(lái)自MDN
看懂了這個(gè),接下來(lái)就直接來(lái)解釋一下這個(gè)題目~
(function(x, f = () => x) { // 首先這里給參數(shù) f 默認(rèn)賦值了一個(gè)匿名函數(shù),根據(jù)我們之前說(shuō)的第二個(gè)知識(shí)點(diǎn)這里的 x 就是形參 x。由于作用域的關(guān)系 函數(shù)f 是不能訪問(wèn)到函數(shù)內(nèi)的 x 的。 var x; // ?。?! 注意,這里進(jìn)行了變量聲明,會(huì)分配新的內(nèi)存地址。但是因?yàn)橹贿M(jìn)行了聲明而沒(méi)有賦值,所以在作用域鏈還會(huì)找到 形參x var y = x; // 這里 y 的值取的還是形參 x 的值 x = 2; // 這里 對(duì)上面的 var x 進(jìn)行賦值而形參x 的值是不受影響的(console.log(arguments[0])試一下, 所以 f() 返回是1),此時(shí)作用域鏈上會(huì)先找到函數(shù)內(nèi)聲明的 x。 return [x, y, f()]; // [2, 1, 1] })(1) (function(x, f = () => x) { var y = x; // 這里只聲明了y, x 還是形參x x = 2; // 這里改變了形參x的值,所以 f() 返回是 2 return [x, y, f()]; // [2, 1, 2] })(1)
這題還有一個(gè)坑點(diǎn),我拿到babel里面去轉(zhuǎn)一下得到的結(jié)果是
"use strict"; (function (x) { var f = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () { return x; }; var x; var y = x; x = 2; return [x, y, f()]; // ?。?! 這里結(jié)果是 [2, 1, 2] })(1);
這種神奇的代碼還是盡量不要寫(xiě)呀!
如果有理解錯(cuò)誤的地方,歡迎指正!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/93874.html
摘要:到十二月份,公司開(kāi)始第二波裁員,我決定主動(dòng)拿賠償走人。加一個(gè)小插曲上面的題是餓了嗎面試問(wèn)到的。想去的公司沒(méi)有面試好,不要?dú)怵H,繼續(xù)加油準(zhǔn)備。避免打擊自信心。 回顧一下自己這段時(shí)間的經(jīng)歷,九月份的時(shí)候,公司通知了裁員,我匆匆忙忙地出去面了幾家,但最終都沒(méi)有拿到offer,我感覺(jué)今年的寒冬有點(diǎn)冷。到十二月份,公司開(kāi)始第二波裁員,我決定主動(dòng)拿賠償走人。后續(xù)的面試過(guò)程我做了一些準(zhǔn)備,基本都能走...
摘要:不過(guò)幸運(yùn)的是所有面試的公司都給了,在這里總結(jié)下經(jīng)驗(yàn)吧。這里推薦下我當(dāng)時(shí)看的一篇的面經(jīng),木易楊老師寫(xiě)的大廠高級(jí)前端面試題匯總。 前言 本人畢業(yè)一年,最近陸續(xù)面試了頭條、瓜子、360、猿輔導(dǎo)、中信銀行、老虎等公司,由于最近比較寒冬而且招1-3年的并不多,再加上自己對(duì)公司規(guī)模和位置有一定要求,所以最后合適的也就這幾家了。不過(guò)幸運(yùn)的是所有面試的公司都給了offer,在這里總結(jié)下經(jīng)驗(yàn)吧。掘金:h...
摘要:閉包加作用域問(wèn)題打印結(jié)果是函數(shù)聲明了兩次,有一次覆蓋,最后的覆蓋了前面的,要是只聲明一遍,那么打印的就是作用域問(wèn)題打印反直覺(jué)自帶坑的題找鼠標(biāo)最近的標(biāo)簽鏈接最美的不是下雨天是你鏈接最美的不是鏈接最美的不是下雨鏈接最美的不是下雨天鏈接最美的不 1.閉包加作用域問(wèn)題 let test let a = ()=>{ let n=99 test = ()=>{ n...
摘要:總體來(lái)說(shuō),玄武科技的真的很熱情,為他們點(diǎn)個(gè)贊,雖然自己最后沒(méi)能去玄武科技,然后就是技術(shù)面非常簡(jiǎn)單,面和高管面也都還好,不會(huì)有壓抑的感覺(jué),總體聊得很愉快。 該文已加入開(kāi)源文檔:JavaGuide(一份涵蓋大部分Java程序員所需要掌握的核心知識(shí))。地址:https://github.com/Snailclimb... 秋招歷程流水賬總結(jié) 筆主大四準(zhǔn)畢業(yè)生,在秋招末流比較幸運(yùn)地進(jìn)入了一家...
閱讀 3470·2021-10-11 11:06
閱讀 2259·2019-08-29 11:10
閱讀 2005·2019-08-26 18:18
閱讀 3311·2019-08-26 13:34
閱讀 1616·2019-08-23 16:45
閱讀 1100·2019-08-23 16:29
閱讀 2860·2019-08-23 13:11
閱讀 3313·2019-08-23 12:58