node.js中的forEach是同步還是異步
node里幾乎所有用到回調函數的地方,都是異步的,回調函數后面的代碼很可能比回調函數中的代碼后先執行,特別是數據庫操作。當然,node也提供了同步版本的函數,例如文件操作,fs.readFileSync()是fs.readFile()的同步版本。那么問題來了,forEach()是不是異步的呢?按理說,沒有加Sync,應該是異步的呀。復制代碼代碼如下:vararr=['a','b','c']
;varstr='123'
;arr.forEach(function(item){str+=item;while(true){};//用一個死循環,卡死它~~})
;console.log(str);運行上面的代碼,結果它就這么卡死了,沒有任何輸出。。
所以說,node里的forEach()是同步的!!
第一次用node的時候,沒有考慮過這個問題,按同步的寫了,寫突然想到,測試后虛驚一場,以為以前的代碼都寫錯了。
forEach和map有什么區別
map與forEach其實都是JS中,對array進行遍歷的方法,區別在于map是存在返回值的,而forEach返回值為undefined
我對map的理解是,這個方法對一個數組arr1中的每一個元素進行遍歷(傳遞給一個數組,參數為(item,index,arr1)),返回值保存到另一個數組中,遍歷結束后,整個方法返回這個數組
require和request有什么區別
1require和request的意義不同2require是指在Node.js中引入另一個模塊,類似于Java中的import或include。而request是指向另一個服務器發出請求并接收響應的操作,常用于獲取HTTP接口數據。3require和request都是在開發中常用的操作,需要靈活掌握和運用。
什么是跨域,跨域的實現方式有哪些
查了一些資料,再結合我之前的了解,給大家介紹一下,如果有說的不對的地方,請大家留言指正。
什么是跨域瀏覽器有一個毛病(策略):請求url的協議、域名、端口必須相同,才允許訪問(通信),否則就不允許訪問,是跨域。
https(協議)://www.wukong.com(域名和端口)/index.html
比如:
https://www.wukong.com/index.html
http://www.wukong.com/index.html
這樣就不允許通信,因為協議不同。
完整的舉個例子:
你有服務器A和服務器B,服務器A上存著CSS和JS腳本,服務器B上存著HTML,HTML頁面上的CSS和JS都是鏈接的服務器A上面的。
然后用瀏覽器打開服務器B上面的xxx.html,頁面打開后可以正常渲染出樣式,可以運行JS腳本,這樣就是跨域名,跨端口,跨協議。
如何解決跨域JSONP:利用了script標簽不受同源策略的限制,通過script加載服務器A的資源。
Proxy代理:使用服務器接口做代理,因為同源策略之針對瀏覽器。
CORS:跨域資源共享,這個就是瀏覽器后悔了,出了一個跨域訪問機制(XMLHttpRequest),低版本IE不支持。
Postmessage:HTML5新增的跨域機制。
Nginx反向代理:相當于Proxy代理。
希望我的回答可以幫助到你!
為什么Java不支持運算符重載
Java不支持運算符重載=小白也能學編程
Java之所以不支持運算符重載,并不是如下原因:
會使JVM變得復雜、性能下降:君不見C++內置運算符重載的能力?C++的性能在任何時代秒殺Java相信沒有爭議。便于靜態分析、工具化等:一葉障目、不見泰山。運算符重載只是一種動態特性,動態語言的形式化靜態分析方法已經有成熟的方法論。Java是面向對象語言:Ruby是比Java更徹底的面向對象的語言,然而它對運算符重載的支持非常優秀,在Ruby中一切都是對象,幾乎一切都可以override。不支持運算符重載的根本原因,是源自JamesGosling設計Java的初衷:那就是要讓Java的學習門檻足夠低,這樣才能讓這個編程語言被更多的人使用,從而擁有最大的市場占有率。
Java誕生之前,基本上是C/C++的天下。光C語言的一個指針,就嚇退了多少莘莘學子?C++引入更多的動態特性:多態、多重繼承、函數重載、函數重寫、運算符重載、泛型……這更不知道讓多少人望而卻步!
正是在那樣的大環境下,JamesGosling才萌生了“開發一個小白都能上手”的編程語言的念頭。
運算符重載的底層思想并不是面向對象運算符重載的底層邏輯來自函數式編程。它的祖師爺是Lisp,一個“從來被模仿、從未被超越”的神級語言。
可以負責任地講,如今流行的Python、Javascript、Typescript、Go、Ruby、Haskell、Scala、Groovy等,在動態高級特性上都是在不斷模仿60多年前的Lisp。包括Java從誕生起就在鼓吹的垃圾回收等優點,全部都是“偷師”Lisp。有興趣的小伙伴可以自行下載Lisp的發明者——JohnMcCarthy老爺爺1960年發表的GC論文。
函數式語言的核心思想其實是數學。
說得更白話一點:通過數學表達式描述問題,而不是人肉模擬解答過程。問題描述完了,也就解決了——運行時處理執行細節。
說得更學院派一點:通過無狀態的函數加以其他優化特性,將這些函數組件進行拼接。
看到這里,估計有不少人要來拍磚:運算符重載看起來那么復雜,明明可以定義方法或者函數來解決,除了裝逼格,沒有實用價值。
筆者這里回應一下:數學本來就不是普通大眾擅長的,數學的目的就是用最簡潔的方式來解決最復雜的問題。所以函數式語言從誕生之初,就沒有想過要蕓蕓眾生。它追求的是大道至簡。
這里來看一個例子:計算一組數據(假設放在一個一維數組中)的標準差。
如果不采用函數式編程,采用通常的面向過程或者面向對象的編程范式,那么只能:
第一步,先通過循環體(for/foreach/while等),挨個遍歷求出平均值mean;
第二步,再來一次循環,挨個求與mean的差值并平方,然后逐個累加得到平方合sumOfSquares;
第三步,對sumOfSquares調用平方根函數,求出最終值standardDeviation。
下面我們來進化一點:
有基本函數式編程概念的小伙伴可能會寫出如下的簡化范式(這里以Ruby為例):
mean=a.inject{|x,y|x+y}/a.size
sumOfSquares=a.map{|x|(x-mean)**2}.inject{|x,y|x+y}
standardDeviation=Math.sqrt(sumOfSquares/(a.size-1))
但是真正的函數式編程高手是會這樣寫的:
第一步:寫一個通用的數學意義上的復合函數(f(g(x))=f*g(x))的表達:
moduleFunctional
defapply(enum)
enum.map&self
end
alias|apply
defreduce(enum)
enum.inject&self
end
alias<=reduce
defcompose(f)
ifself.respond_to?(:arity)&&self.arity==1
lambda{|*args|self[f[*args]]}
else
lambda{|*args|self[*f[*args]]}
end
end
alias*compose
end
第二步:把計算標準差所需要的各個元素的數學表達列示好:
sum=lambda{|x,y|x+y}#Afunctiontoaddtwonumbers
mean=(sum<=a)/a.size#Orsum.reduce(a)ora.inject(&sum)
deviation=lambda{|x|x-mean}#Functiontocomputedifferencefrommean
square=lambda{|x|x*x}#Functiontosquareanumber
第三步:像寫標準差的數學表達式一樣,一步到位:
standardDeviation=Math.sqrt((sum<=square*deviation|a)/(a.size-1))
總結Java之所以流行,并不是因為其語言設計得最優秀,相反地,在很多地方——比如泛型、Lambda、完全面向對象等設計上都存在不足。它的成功在于:揚長避短,把所有牛X的高級語言特性在一開始全部都拋棄,留一個最小核,然后通過營銷,大規模地培養本語言陣營的程序員,建立各種各樣的“輪子”,成就了巨無霸的生態;在站穩格局之后,慢慢地再逐步添加回來一些以前拋棄的其他語言的優秀特性——這是一種比較實用的策略,但是帶來的惡果就是:歷史包袱比較重,導致新特性很多時候是“半殘”的。
回到運算符重載本身,對于高手,可以利用該特性寫出極具“魔性”、接近數學語言的代碼,這樣的代碼可以體現“極簡之美”——但是,一個不利影響就是:數學不好的小伙伴,不容易看得懂,也很難體會其中蘊含的“數學之美”。