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