js 中什么類型是引用傳遞, 什么類型是值傳遞? 如何將值類型的變量以引用的方式傳遞?
一般情況下帘瞭,簡單數(shù)據(jù)類型是在棧里面直接儲存一個數(shù)值,賦值操作直接改這個值生兆,就是值傳遞的
如果是復(fù)雜數(shù)據(jù)類型哆窿,及Object和Object延伸出的其他復(fù)雜類型,都是先在棧里儲存一個指針援奢,然后指針指向堆空間里的數(shù)值,而進行賦值傳遞的時候忍捡,只是另一個變量也僅儲存了這個指針集漾,就導(dǎo)致改這個對象,另一個對象也跟著變的砸脊,就是引用傳遞
js 中具篇, 0.1 + 0.2 === 0.3 是否為 true ? 在不知道浮點數(shù)位數(shù)時應(yīng)該怎樣判斷兩個浮點數(shù)之和與第三數(shù)是否相等?
不相等凌埂,因為JS浮點數(shù)先轉(zhuǎn)2進制再計算再轉(zhuǎn)十進制的原因驱显,會丟失精度,所以false了
盡量避免浮點數(shù)比較吧侨舆,如果非要比的話秒紧,我這邊一般兩種做法吧
一種是標(biāo)準(zhǔn)做法:
JS里,最大整數(shù)和最接近零的小數(shù)挨下,分別是2的正負(fù)52次方
而最接近0的小數(shù),也可以用Number.EPSILON
表示
如果Math.abs((0.1+0.2)-0.3)<Number.EPSILON脐湾,就可以說他倆相等了
另外一種做法就臭笆,比較野雞
比如算0.1+0.2,我就會(0.1+0.2).toFixed(15)*1
因為那個最接近0的小數(shù)秤掌,它其實是0.00..02xx愁铺,中間15個零
缺點嘛一方面toFixed肯定性能比人家自帶的常量會差一點,而且如果真的有兩個15位小數(shù)計算闻鉴,toFixed這個有誤差茵乱,而EPSILON無誤差。優(yōu)點就方便
實際情況的話孟岛,如果我抽成公共方法了瓶竭,那我就用常量督勺,如果臨時寫業(yè)務(wù),可能就toFixed了斤贰,因為讀代碼比較方便易懂
const 定義的 Array 中間元素能否被修改? 如果可以, 那 const 修飾對象的意義是?
能修改智哀,const相當(dāng)于把棧里的數(shù)據(jù)鎖死了,Array是個引用數(shù)據(jù)類型荧恍,只是鎖死了地址瓷叫,堆里面的數(shù)據(jù)依然可以隨便改
內(nèi)存釋放
node自帶垃圾回收機制了,node的GC機制送巡,就是從global中梳理所有可以訪問得到的對象引用摹菠,如果達(dá)不到,可以達(dá)到的就標(biāo)記未可達(dá)到對象骗爆,然后循環(huán)所有對象次氨,凡是不可達(dá)到對象都進行回收,只要沒有被引用的變量和方法淮腾,都會自帶被回收
而一般如果出現(xiàn)內(nèi)存泄漏了糟需,十有八九是閉包,閉包就是因為內(nèi)部函數(shù)還在被引用谷朝,導(dǎo)致外部函數(shù)內(nèi)存無法得到釋放的現(xiàn)象洲押。或者就是事件注冊了圆凰,未清除掉杈帐,比如socket、emitter注冊的事件专钉,注冊完之后不用了未清除掉
什么時候需要使用閉包
ES5時為了實現(xiàn)作用域會用到挑童,ES6基本很少用,但在Class里想要實現(xiàn)私有數(shù)據(jù)跃须,可以在constructor里面寫方法賦值出去站叼,但是這樣做,十分需要注意的是菇民,如果new出來的對象不要了尽楔,還是給變量弄個null,不然就導(dǎo)致內(nèi)存泄漏了
process
process.env獲取環(huán)境第练,比較常用阔馋,還有就是process.cwd獲取當(dāng)前的工作目錄,好通過這個目錄的相對目錄來操作文件之類的娇掏,當(dāng)然還有process.chdir()
改變當(dāng)前工作目錄呕寝,還有有時想改變事件隊列順序插入事件,可以用process.nextTick
process里還有像C++里一樣的輸入輸出流婴梧,但是很少用下梢,console的底層就是用這個實現(xiàn)的
process.nextTick
process.nextTick會將事件插入到當(dāng)前事件隊列和下輪事件隊列之間
而timeout和immediate會放到下輪事件尾
process.nextTick()客蹋,效率最高,消費資源小怔球,但會阻塞CPU的后續(xù)調(diào)用嚼酝;
setTimeout(),精確度不高竟坛,可能有延遲執(zhí)行的情況發(fā)生闽巩,且因為動用了紅黑樹,所以消耗資源大担汤;
setImmediate()涎跨,消耗的資源小,也不會造成阻塞崭歧,但效率也是最低的隅很。
守護進程
我們公司是用pm2做的守護進程,基本上就是一個配置率碾。而內(nèi)部實現(xiàn)原理的話叔营,好像都是通過C語言或什么其他語言模塊實現(xiàn)的
Child Process
通常如果需要執(zhí)行一個cmd命令,或者開啟線程和執(zhí)行其他語言的話所宰,可以用這個child_process
之前有寫過一個小工具绒尊,就用node的process執(zhí)行cmd命令做adb調(diào)試手機。還有用這個執(zhí)行過dll和go仔粥,多是做工具里有用到這個
為什么用node
感覺node的話婴谱,其實最開始大家都在宣揚node的高并發(fā),但實際上我覺得選擇node的原因躯泰,其實并不是怎么并發(fā)了
而是其實說谭羔,node很簡單,寫業(yè)務(wù)很快麦向,同樣一個項目瘟裸,node要比Java快很多
包括說node也很靈活。就拿Java多數(shù)據(jù)源诵竭,好像就很難實現(xiàn)景描,但node就很簡單,connect一下存到一個變量里調(diào)里面方法就好了
而且還有個優(yōu)點就是人員靈活秀撇。比如當(dāng)時做商城的時候,商城不僅需要后端向族,還需要后臺呵燕,然后前端人員可能就不夠了,我這種前端出身的件相,幫著寫寫后臺頁面是沒問題的
KOA和Express
一開始的時候是先出Express再扭,處理異步的方案用的callback氧苍,后來出了KOA1,說是面向未來的框架泛范,并且處理異步的方案是* yield next让虐,就開始決定用KOA了,再后來出了2就是用的async罢荡、await了赡突。
除了對異步處理之外,KOA的use中間件的方式似乎也和Express不一樣区赵,KOA的洋蔥模型惭缰,每個request會走到每個中間件的next之前,然后每個response都會先走next之后的函數(shù)笼才,再response出去
KOA2 用起來 總體的缺點來說的話
功能單薄漱受,需要自己去篩選和選擇中間件
而且因為十分開放,開發(fā)自由度大骡送,規(guī)范不統(tǒng)一
對egg的理解
對于平時寫代碼昂羡,egg利用KOA的中間件機制和HTTP服務(wù)機制,對KOA做了很大的擴展
以 Loader 機制作為Egg.js各分層機制的約定基礎(chǔ)
Egg還提供了很多功能
比如之前我們公司用KOA摔踱,就自己寫了初始化的小工具虐先,但egg就已經(jīng)自帶了 腳手架初始化、
同時我們用pm2做的多線程和多線程守護昌渤,egg都自帶了赴穗,所以其實感覺egg就是幫你在靈活的KOA里面定制好了很多標(biāo)準(zhǔn)插件、工具
egg流程
開啟插件膀息,先npm i 般眉,
然后再config/plugin里面注冊一下,就export.xx= package和enable寫一下
之后再config里注冊一下
Controller 一般不會自己產(chǎn)出數(shù)據(jù)潜支,也不會包含復(fù)雜的邏輯甸赃,復(fù)雜的過程應(yīng)抽象為業(yè)務(wù)邏輯層 [Service]
this.ctx.curl可以調(diào)接口
this.config.可以拿到配置信息
編寫擴展
方法擴展
app/extend/application.js
module.exports = {
foo(param) {
// this 就是 app 對象,在其中可以調(diào)用 app 上的其他方法冗酿,或訪問屬性
},
};
application里export出來的東西會掛載到app里
屬性擴展
一般來說屬性的計算只需要進行一次埠对,那么一定要實現(xiàn)緩存,否則在多次訪問屬性時會計算多次裁替,這樣會降低應(yīng)用性能项玛。
推薦的方式是使用 Symbol + Getter 的模式。
// app/extend/application.js
const BAR = Symbol('Application#bar');
module.exports = {
get bar() {
// this 就是 app 對象弱判,在其中可以調(diào)用 app 上的其他方法襟沮,或訪問屬性
if (!this[BAR]) {
this[BAR] = 調(diào)接口
}
return this[BAR];
},
}
app/extend/xx.js
export一個function,這個function就可以
request拓展 app/extend/request.js 的東西會合到prototype
response同理 app/extend/response.js
ctx.helper可以 app/extend/helper.js
app/extend/application.unittest.js只會在unittest 環(huán)境加載
第三方登錄
目前只做了兩個第三方登錄,分別是QQ和微信的开伏,而且感覺前端看來都是掃碼膀跌,而后端看來卻是兩個不同的邏輯
微信接入之后,用戶點擊會進入回調(diào)url并且?guī)б粋€code參數(shù)固灵,微信有提供一個接口可以根據(jù)appid捅伤、secret、code來獲取unionid巫玻,之后我會拿這個unionid到數(shù)據(jù)庫里查丛忆,這個用戶是否存在,
存在的話就直接token返給前端大审,
不存在的話蘸际,我這邊會先臨時建立一個無姓名、手機號的賬戶徒扶,并把這個賬戶的unionid給前端粮彤,前端跳綁定手機號頁面,綁定成功之后我再更新這個用戶信息
QQ和微信第三方登錄原理差不多姜骡,但是QQ登錄之后导坟,并沒有在query里放code,而是在hash里圈澈,后端拿不到hash值惫周,所以我這邊回調(diào)地址會額外跳轉(zhuǎn)一次,再拿里面的access_token去獲取qq的openid康栈,之后的步驟就和微信那邊的一樣了
核銷優(yōu)惠券
其實這個優(yōu)惠券的話递递,其實是用戶先在蘇寧、天貓啥么、順逛買了裝修優(yōu)惠券登舞,之后裝修付款可以使用這個優(yōu)惠券。在邏輯里悬荣,實際上是用戶購買完優(yōu)惠券之后菠秒,有個電子碼,輸入這個電子碼獲取優(yōu)惠氯迂。而我們這邊會調(diào)他們的第三方接口践叠,來獲取是否有效、抵扣多少元嚼蚀。如果有效的話禁灼,再調(diào)第三方接口把這個優(yōu)惠券置為已使用,并且真正收錢的時候少收一些轿曙。這個電子碼調(diào)用他們第三方接口的時候匾二,因為安全性很重要哮独,所以信息里有電子碼、店鋪號察藐、秘鑰和MD5加密進行校驗的
加密
之前這個優(yōu)惠券的加密方式可能比較low,就第三方平臺給我們一個秘鑰和店鋪號舟扎,有點類似微信的那個分飞,然后調(diào)用接口的時候,我們要把所有參數(shù)按ascii碼排序睹限,最后加上店鋪號譬猫,然后用md5以秘鑰進行加密傳給他們。他們那邊在進行校驗我們傳輸?shù)闹凳欠裾_
數(shù)據(jù)打通
簽訂合同
簽訂合同是公司購買了上上簽的服務(wù)羡疗,就是我們先有個合同染服,用戶可以在canvas里簽字,