cainiaoblog 23.2.171

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (401) hide show
  1. package/CNAME +1 -0
  2. package/MP_verify_o6dHCK5mIkxNpzvZ.txt +1 -0
  3. package/README.md +8 -0
  4. package/about/index.html +54 -0
  5. package/ads.txt +1 -0
  6. package/app/manual.html +104 -0
  7. package/appConfigs/config +1 -0
  8. package/archives/2018/index.html +48 -0
  9. package/archives/2019/index.html +48 -0
  10. package/archives/2019/page/2/index.html +48 -0
  11. package/archives/2020/index.html +48 -0
  12. package/archives/2021/index.html +48 -0
  13. package/archives/2022/index.html +48 -0
  14. package/archives/2023/index.html +48 -0
  15. package/archives/index.html +48 -0
  16. package/archives/page/2/index.html +48 -0
  17. package/archives/page/3/index.html +48 -0
  18. package/article/10047.html +148 -0
  19. package/article/10164.html +64 -0
  20. package/article/10624.html +436 -0
  21. package/article/10745.html +586 -0
  22. package/article/11674.html +71 -0
  23. package/article/11939.html +72 -0
  24. package/article/12238.html +86 -0
  25. package/article/1230.html +533 -0
  26. package/article/13265.html +69 -0
  27. package/article/13823.html +78 -0
  28. package/article/14125.html +72 -0
  29. package/article/14192.html +561 -0
  30. package/article/14375.html +85 -0
  31. package/article/14744.html +83 -0
  32. package/article/14936.html +451 -0
  33. package/article/1518.html +250 -0
  34. package/article/15428.html +71 -0
  35. package/article/15518.html +288 -0
  36. package/article/15569.html +418 -0
  37. package/article/1566.html +122 -0
  38. package/article/16017.html +156 -0
  39. package/article/16947.html +440 -0
  40. package/article/17096.html +82 -0
  41. package/article/17246.html +89 -0
  42. package/article/17575.html +350 -0
  43. package/article/179.html +757 -0
  44. package/article/18039.html +233 -0
  45. package/article/18071.html +375 -0
  46. package/article/18142.html +71 -0
  47. package/article/19909.html +160 -0
  48. package/article/20014.html +89 -0
  49. package/article/20021.html +389 -0
  50. package/article/20037.html +280 -0
  51. package/article/20056.html +95 -0
  52. package/article/20093.html +404 -0
  53. package/article/2021.html +607 -0
  54. package/article/20459.html +115 -0
  55. package/article/20613.html +263 -0
  56. package/article/20635.html +71 -0
  57. package/article/21317.html +71 -0
  58. package/article/21320.html +90 -0
  59. package/article/21782.html +548 -0
  60. package/article/22230.html +435 -0
  61. package/article/22237.html +347 -0
  62. package/article/22398.html +109 -0
  63. package/article/22422.html +270 -0
  64. package/article/22565.html +300 -0
  65. package/article/23046.html +250 -0
  66. package/article/23083.html +215 -0
  67. package/article/23195.html +297 -0
  68. package/article/23301.html +835 -0
  69. package/article/23589.html +285 -0
  70. package/article/23655.html +338 -0
  71. package/article/23864.html +76 -0
  72. package/article/23914.html +96 -0
  73. package/article/24169.html +135 -0
  74. package/article/24581.html +349 -0
  75. package/article/2475.html +500 -0
  76. package/article/24826.html +77 -0
  77. package/article/24924.html +247 -0
  78. package/article/25164.html +1495 -0
  79. package/article/25318.html +394 -0
  80. package/article/25710.html +1129 -0
  81. package/article/25734.html +83 -0
  82. package/article/26083.html +174 -0
  83. package/article/26147.html +283 -0
  84. package/article/26291.html +110 -0
  85. package/article/26354.html +71 -0
  86. package/article/26624.html +145 -0
  87. package/article/26639.html +298 -0
  88. package/article/26850.html +138 -0
  89. package/article/26940.html +258 -0
  90. package/article/27796.html +190 -0
  91. package/article/27800.html +161 -0
  92. package/article/28963.html +159 -0
  93. package/article/28976.html +247 -0
  94. package/article/29042.html +72 -0
  95. package/article/29596.html +81 -0
  96. package/article/29619.html +183 -0
  97. package/article/29623.html +329 -0
  98. package/article/29829.html +205 -0
  99. package/article/29abbd1c.html +112 -0
  100. package/article/30215.html +178 -0
  101. package/article/30552.html +78 -0
  102. package/article/30818.html +201 -0
  103. package/article/31330.html +364 -0
  104. package/article/3154.html +577 -0
  105. package/article/31695.html +348 -0
  106. package/article/31826.html +71 -0
  107. package/article/31843.html +132 -0
  108. package/article/32280.html +212 -0
  109. package/article/32431.html +74 -0
  110. package/article/32443.html +72 -0
  111. package/article/32732.html +122 -0
  112. package/article/3286.html +251 -0
  113. package/article/32960.html +198 -0
  114. package/article/33713.html +72 -0
  115. package/article/33899.html +615 -0
  116. package/article/34351.html +74 -0
  117. package/article/34372.html +89 -0
  118. package/article/34410.html +74 -0
  119. package/article/34431.html +118 -0
  120. package/article/3447.html +75 -0
  121. package/article/34474.html +142 -0
  122. package/article/34871.html +147 -0
  123. package/article/35397.html +175 -0
  124. package/article/3544.html +199 -0
  125. package/article/35503.html +115 -0
  126. package/article/35624.html +84 -0
  127. package/article/35697.html +384 -0
  128. package/article/35863.html +73 -0
  129. package/article/36037.html +253 -0
  130. package/article/36118.html +71 -0
  131. package/article/3621.html +119 -0
  132. package/article/36251.html +296 -0
  133. package/article/36642.html +352 -0
  134. package/article/37102.html +763 -0
  135. package/article/37336.html +351 -0
  136. package/article/37351.html +89 -0
  137. package/article/3760.html +294 -0
  138. package/article/37749.html +75 -0
  139. package/article/37789.html +83 -0
  140. package/article/38005.html +765 -0
  141. package/article/38009.html +284 -0
  142. package/article/38269.html +194 -0
  143. package/article/38344.html +88 -0
  144. package/article/38359.html +334 -0
  145. package/article/38423.html +379 -0
  146. package/article/38530.html +213 -0
  147. package/article/38743.html +268 -0
  148. package/article/38753.html +204 -0
  149. package/article/38881.html +71 -0
  150. package/article/39087.html +414 -0
  151. package/article/39309.html +84 -0
  152. package/article/39486.html +74 -0
  153. package/article/39637.html +306 -0
  154. package/article/39839.html +72 -0
  155. package/article/39937.html +152 -0
  156. package/article/39970.html +71 -0
  157. package/article/402.html +559 -0
  158. package/article/40698.html +71 -0
  159. package/article/40811.html +71 -0
  160. package/article/40964.html +462 -0
  161. package/article/41011.html +322 -0
  162. package/article/41152.html +78 -0
  163. package/article/41696.html +71 -0
  164. package/article/41717.html +281 -0
  165. package/article/41777.html +149 -0
  166. package/article/419.html +985 -0
  167. package/article/4233.html +136 -0
  168. package/article/4292.html +86 -0
  169. package/article/43302.html +96 -0
  170. package/article/43397.html +106 -0
  171. package/article/43724.html +281 -0
  172. package/article/43999.html +224 -0
  173. package/article/44426.html +77 -0
  174. package/article/44964.html +137 -0
  175. package/article/45004.html +123 -0
  176. package/article/4510.html +83 -0
  177. package/article/45156.html +320 -0
  178. package/article/45157.html +52 -0
  179. package/article/45267.html +87 -0
  180. package/article/45641.html +207 -0
  181. package/article/45960.html +75 -0
  182. package/article/46100.html +1262 -0
  183. package/article/46366.html +74 -0
  184. package/article/46771.html +96 -0
  185. package/article/46911.html +517 -0
  186. package/article/46948.html +137 -0
  187. package/article/46ee4850.html +349 -0
  188. package/article/47019.html +84 -0
  189. package/article/47532.html +94 -0
  190. package/article/4783.html +429 -0
  191. package/article/47972.html +72 -0
  192. package/article/48216.html +127 -0
  193. package/article/48252.html +185 -0
  194. package/article/48520.html +74 -0
  195. package/article/48722.html +75 -0
  196. package/article/48807.html +99 -0
  197. package/article/49126.html +323 -0
  198. package/article/50001.html +88 -0
  199. package/article/50058.html +151 -0
  200. package/article/50343.html +410 -0
  201. package/article/50510.html +82 -0
  202. package/article/51082.html +98 -0
  203. package/article/51677.html +111 -0
  204. package/article/5204.html +1085 -0
  205. package/article/52500.html +538 -0
  206. package/article/52689.html +259 -0
  207. package/article/52877.html +569 -0
  208. package/article/53125.html +191 -0
  209. package/article/53428.html +251 -0
  210. package/article/53524.html +74 -0
  211. package/article/53698.html +322 -0
  212. package/article/53803e6.html +93 -0
  213. package/article/53924.html +291 -0
  214. package/article/53962.html +253 -0
  215. package/article/54006.html +71 -0
  216. package/article/54018.html +88 -0
  217. package/article/54161.html +83 -0
  218. package/article/54178.html +69 -0
  219. package/article/54258.html +327 -0
  220. package/article/54295.html +214 -0
  221. package/article/54313.html +1976 -0
  222. package/article/54351.html +90 -0
  223. package/article/54604.html +80 -0
  224. package/article/54632.html +71 -0
  225. package/article/54912.html +756 -0
  226. package/article/54918.html +129 -0
  227. package/article/55119.html +136 -0
  228. package/article/55756.html +118 -0
  229. package/article/55769.html +136 -0
  230. package/article/55870.html +161 -0
  231. package/article/56139.html +92 -0
  232. package/article/56557.html +69 -0
  233. package/article/56604.html +69 -0
  234. package/article/56816.html +266 -0
  235. package/article/56926.html +153 -0
  236. package/article/57747.html +409 -0
  237. package/article/57965.html +475 -0
  238. package/article/58816.html +78 -0
  239. package/article/59059.html +435 -0
  240. package/article/59095.html +350 -0
  241. package/article/59349.html +244 -0
  242. package/article/59402.html +216 -0
  243. package/article/59448.html +55 -0
  244. package/article/59870.html +94 -0
  245. package/article/59877.html +208 -0
  246. package/article/5dbb6f41.html +86 -0
  247. package/article/6008.html +75 -0
  248. package/article/60327.html +126 -0
  249. package/article/6035.html +76 -0
  250. package/article/60428.html +71 -0
  251. package/article/60544.html +128 -0
  252. package/article/61319.html +95 -0
  253. package/article/61367.html +93 -0
  254. package/article/624d1918.html +292 -0
  255. package/article/62543.html +71 -0
  256. package/article/62887.html +169 -0
  257. package/article/63074.html +120 -0
  258. package/article/63266.html +311 -0
  259. package/article/63351.html +74 -0
  260. package/article/63542.html +104 -0
  261. package/article/63824.html +275 -0
  262. package/article/64051.html +653 -0
  263. package/article/64189b69.html +72 -0
  264. package/article/64354.html +75 -0
  265. package/article/64869.html +79 -0
  266. package/article/64923.html +596 -0
  267. package/article/65128.html +95 -0
  268. package/article/65295.html +79 -0
  269. package/article/6888.html +75 -0
  270. package/article/7065.html +84 -0
  271. package/article/7455.html +85 -0
  272. package/article/7a3ef8f.html +315 -0
  273. package/article/8140.html +188 -0
  274. package/article/8190.html +85 -0
  275. package/article/8225.html +78 -0
  276. package/article/84c9ccd6.html +159 -0
  277. package/article/8f9a9ae3.html +82 -0
  278. package/article/9174.html +73 -0
  279. package/article/9738.html +294 -0
  280. package/article/a4145266.html +71 -0
  281. package/article/bedea419.html +72 -0
  282. package/article/bf7e7421.html +78 -0
  283. package/article/c1867fbf.html +103 -0
  284. package/article/c5576490.html +70 -0
  285. package/article/dcb0db28.html +76 -0
  286. package/article/fc3b727a.html +79 -0
  287. package/atom.xml +445 -0
  288. package/baidusitemap.xml +1079 -0
  289. package/blocks/dns.txt +264 -0
  290. package/blocks/filter.txt +1070 -0
  291. package/blocks/script.js +42 -0
  292. package/categories/CDN/index.html +48 -0
  293. package/categories/IDE/index.html +48 -0
  294. package/categories/git/index.html +48 -0
  295. package/categories/hexo/index.html +48 -0
  296. package/categories//345/205/254/345/205/261/350/212/202/346/227/245/index.html +48 -0
  297. package/categories//345/210/206/344/272/253/index.html +48 -0
  298. package/categories//345/211/215/347/253/257/index.html +48 -0
  299. package/categories//345/211/215/347/253/257/page/2/index.html +48 -0
  300. package/categories//345/211/215/347/253/257//346/265/217/350/247/210/345/231/250/index.html +48 -0
  301. package/categories//345/211/215/347/253/257//346/265/217/350/247/210/345/231/250//347/275/221/347/273/234/345/215/217/350/256/256/index.html +48 -0
  302. package/categories//345/215/232/345/256/242/index.html +48 -0
  303. package/categories//345/267/245/345/205/267/index.html +48 -0
  304. package/categories//345/271/277/345/221/212/350/277/207/346/273/244/index.html +48 -0
  305. package/categories//345/271/277/345/221/212/350/277/207/346/273/244//350/247/206/351/242/221/347/224/265/350/247/206/345/260/217/350/257/264/346/274/253/347/224/273/350/265/204/350/256/257/351/237/263/344/271/220/index.html +48 -0
  306. package/categories//346/255/243/345/210/231/index.html +48 -0
  307. package/categories//346/265/217/350/247/210/345/231/250/index.html +48 -0
  308. package/categories//347/256/227/346/263/225/index.html +48 -0
  309. package/categories//350/265/204/350/256/257/index.html +48 -0
  310. package/categories//350/275/273/346/235/276/344/270/200/345/210/273/index.html +48 -0
  311. package/cdn/css/font-awesome.min.css +4 -0
  312. package/cdn/css/grids-responsive-min.css +7 -0
  313. package/cdn/css/normalize.css +349 -0
  314. package/cdn/css/pure-min.css +11 -0
  315. package/cdn/fonts/fontawesome-webfont.eot +0 -0
  316. package/cdn/fonts/fontawesome-webfont.svg +2671 -0
  317. package/cdn/fonts/fontawesome-webfont.ttf +0 -0
  318. package/cdn/fonts/fontawesome-webfont.woff +0 -0
  319. package/cdn/fonts/fontawesome-webfont.woff2 +0 -0
  320. package/cdn/js/Valine.min.js +17 -0
  321. package/cdn/js/canvas-nest.js +1 -0
  322. package/cdn/js/clipboard.min.js +7 -0
  323. package/cdn/js/crypto-js.js +25 -0
  324. package/cdn/js/jquery.min.js +2 -0
  325. package/css/default.css +1144 -0
  326. package/css/donate.css +338 -0
  327. package/css/hbe.style.css +749 -0
  328. package/css/style.css +2095 -0
  329. package/donate/index.html +39 -0
  330. package/google917dcf72f6e5c7f5.html +1 -0
  331. package/guestbook/index.html +68 -0
  332. package/hosts/ads.txt +149 -0
  333. package/hosts/flash.txt +9 -0
  334. package/hosts/github.txt +6 -0
  335. package/hosts/google.txt +16936 -0
  336. package/hosts/winrar.txt +2 -0
  337. package/img/alipay.svg +46 -0
  338. package/img/bitcoin.svg +135 -0
  339. package/img/blog.ico +0 -0
  340. package/img/blog.png +0 -0
  341. package/img/gaba.png +0 -0
  342. package/img/github.svg +1 -0
  343. package/img/like.svg +1 -0
  344. package/img/mp-mini.jpg +0 -0
  345. package/img/mp.png +0 -0
  346. package/img/paypal.svg +63 -0
  347. package/img/upy_logo.svg +59 -0
  348. package/img/wechat.svg +49 -0
  349. package/index.html +48 -0
  350. package/jd_root.txt +1 -0
  351. package/js/codeblock-resizer.js +51 -0
  352. package/js/dark.js +12 -0
  353. package/js/donate.js +87 -0
  354. package/js/fixedPage.js +106 -0
  355. package/js/gitment.browser.js +3751 -0
  356. package/js/search.js +86 -0
  357. package/js/share.js +60 -0
  358. package/js/smartresize.js +32 -0
  359. package/js/totop.js +12 -0
  360. package/kankan/index.html +77 -0
  361. package/lib/hbe.js +293 -0
  362. package/package.json +25 -0
  363. package/page/10/index.html +49 -0
  364. package/page/11/index.html +59 -0
  365. package/page/12/index.html +67 -0
  366. package/page/13/index.html +63 -0
  367. package/page/14/index.html +66 -0
  368. package/page/15/index.html +60 -0
  369. package/page/16/index.html +60 -0
  370. package/page/17/index.html +62 -0
  371. package/page/18/index.html +61 -0
  372. package/page/19/index.html +58 -0
  373. package/page/2/index.html +48 -0
  374. package/page/20/index.html +57 -0
  375. package/page/21/index.html +61 -0
  376. package/page/22/index.html +55 -0
  377. package/page/23/index.html +64 -0
  378. package/page/24/index.html +60 -0
  379. package/page/25/index.html +58 -0
  380. package/page/26/index.html +48 -0
  381. package/page/27/index.html +58 -0
  382. package/page/3/index.html +48 -0
  383. package/page/4/index.html +48 -0
  384. package/page/5/index.html +51 -0
  385. package/page/6/index.html +51 -0
  386. package/page/7/index.html +51 -0
  387. package/page/8/index.html +53 -0
  388. package/page/9/index.html +48 -0
  389. package/randomcall/README.html +1 -0
  390. package/randomcall/lucker.html +290 -0
  391. package/randomcall/lucky.png +0 -0
  392. package/robots.txt +22 -0
  393. package/search.xml +6740 -0
  394. package/sitemap.xml +2669 -0
  395. package/tags//345/216/237/345/210/233/index.html +48 -0
  396. package/tags//345/250/261/344/271/220/index.html +48 -0
  397. package/tags//346/211/213/345/206/231/index.html +48 -0
  398. package/tags//347/226/253/346/203/205/index.html +48 -0
  399. package/tags//350/275/254/350/275/275/index.html +48 -0
  400. package/tags//350/275/254/350/275/275/page/2/index.html +48 -0
  401. package/v.html +90 -0
@@ -0,0 +1,1976 @@
1
+ <!DOCTYPE html><html lang="zh-CN" data-dark><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"><meta content="yes" name="apple-mobile-web-app-capable"><meta content="black-translucent" name="apple-mobile-web-app-status-bar-style"><meta content="telephone=no" name="format-detection"><meta name="description" content="前端壹菜鸟,记录工作难题,关注前端知识,收集精彩博文,做技术的搬运工"><meta name="msvalidate.01" content="0FE4D8B3381D3D87088996B886E1E2BD"><title>70个JavaScript面试问题 | 前端壹菜鸟</title><link rel="stylesheet" type="text/css" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/css/style.min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/normalize.css@latest/normalize.min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/purecss@latest/build/pure-min.min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/purecss@latest/build/grids-responsive-min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css"><link rel="icon" mask="" sizes="any" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.ico"><link rel="Shortcut Icon" type="image/x-icon" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.ico"><link rel="apple-touch-icon" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.png"><link rel="apple-touch-icon-precomposed" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.png"><link rel="alternate" type="application/atom+xml" href="/atom.xml"><script type="text/javascript" src="//cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js"></script><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8385136408348258"></script><script src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" async></script><script>(function(){
2
+ var bp = document.createElement('script');
3
+ var curProtocol = window.location.protocol.split(':')[0];
4
+ if (curProtocol === 'https'){
5
+ bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
6
+ }
7
+ else{
8
+ bp.src = 'http://push.zhanzhang.baidu.com/push.js';
9
+ }
10
+ var s = document.getElementsByTagName("script")[0];
11
+ s.parentNode.insertBefore(bp, s);
12
+ })();
13
+ </script><script>(function(){
14
+ var src = 'https://jspassport.ssl.qhimg.com/11.0.1.js?d182b3f28525f2db83acfaaf6e696dba';
15
+ document.write('<script src="' + src + '" id="sozz"><\/script>');
16
+ })();
17
+ </script><script>var _hmt=_hmt||[];(function(){var hm=document.createElement("script");hm.src='https://hm.baidu.com/hm.js?011f0b44e8452bfa57fbfa23c5fe7683';var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(hm, s);})();
18
+ </script><script async src="https://www.googletagmanager.com/gtag/js?id=UA-150860401-1"></script><script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);};gtag('js',new Date());gtag('config','UA-150860401-1');
19
+ </script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/fixedPage.min.js"></script><meta name="generator" content="Hexo 6.3.0"></head><body><div class="body_container"><div id="header"><div class="site-name"><a id="logo" href="/.">前端壹菜鸟</a><p class="description">关注前端知识,收集精彩博文,做技术的搬运工</p></div><div id="nav-menu"><a class="current" href="/." target="_self"><i class="fa fa-home"> 首页</i></a><a href="/archives/" target="_self"><i class="fa fa-archive"> 归档</i></a><a href="/guestbook/" target="_self"><i class="fa fa-comments"> 留言</i></a><a href="/about/" target="_self"><i class="fa fa-user"> 关于</i></a><a href="https://laonongmin.online/" target="_target"><i class="fa fa-group"> 看看</i></a><a href="https://love.xuehuayu.cn/" target="_target"><i class="fa fa-heart"> LOVE</i></a></div></div><div class="pure-g" id="layout"><div class="pure-u-1 pure-u-md-3-4"><div class="content_container"><div class="post"><h1 class="post-title c-post">70个JavaScript面试问题</h1><div class="post-meta"><span class="date">2020-01-16</span><span> | </span><span class="tag"><a href="/tags/%E8%BD%AC%E8%BD%BD/">转载 </a></span><span> | </span><span class="category"><a href="/categories/%E5%88%86%E4%BA%AB/">分享 </a></span><span id="busuanzi_container_page_pv"> | <span id="busuanzi_value_page_pv"><i class="fa fa-spinner"></i></span><span> 阅读</span></span><span class="post-time"><span class="post-meta-item-text"> | </span><span class="post-meta-item-icon"><i class="fa fa-keyboard-o"></i><span class="post-count"> 19.1k</span><span class="post-meta-item-text"> 字</span></span></span><span class="post-time"> | <span class="post-meta-item-icon"><i class="fa fa-hourglass-half"></i><span class="post-count"> 81</span><span class="post-meta-item-text"> 分钟</span></span></span></div><a class="disqus-comment-count" href="/article/54313.html#vcomment"><span class="waline-comment-count" data-path="/article/54313.html"></span><span> 条评论</span></a><div class="post-content"><p><code>原文地址:https://www.html.cn/interview/15926.html</code></p>
20
+ <span id="more"></span>
21
+ <h4 id="考题列表"><a href="#考题列表" class="headerlink" title="考题列表"></a>考题列表</h4><ul>
22
+ <li><a href="#_1">1. undefined 和 null 有什么区别?</a></li>
23
+ <li><a href="#_2">2. &amp;&amp; 运算符能做什么</a></li>
24
+ <li><a href="#_3">3. || 运算符能做什么</a></li>
25
+ <li><a href="#_4">4. 使用 + 或一元加运算符是将字符串转换为数字的最快方法吗?</a></li>
26
+ <li><a href="#_5">5. DOM 是什么?</a></li>
27
+ <li><a href="#_6">6. 什么是事件传播?</a></li>
28
+ <li><a href="#_7">7. 什么是事件冒泡?</a></li>
29
+ <li><a href="#_8">8. 什么是事件捕获?</a></li>
30
+ <li><a href="#_9">9. event.preventDefault() 和 event.stopPropagation()方法之间有什么区别?</a></li>
31
+ <li><a href="#_10">10. 如何知道是否在元素中使用了event.preventDefault()方法?</a></li>
32
+ <li><a href="#_11">11. 为什么此代码obj.someprop.x会引发错误?</a></li>
33
+ <li><a href="#_12">12. 什么是event.target?</a></li>
34
+ <li><a href="#_13">13. 什么是event.currentTarget?</a></li>
35
+ <li><a href="#_14">14. &#x3D;&#x3D; 和 &#x3D;&#x3D;&#x3D; 有什么区别?</a></li>
36
+ <li><a href="#_15">15. 为什么在 JS 中比较两个相似的对象时返回 false?</a></li>
37
+ <li><a href="#_16">16. !! 运算符能做什么?</a></li>
38
+ <li><a href="#_17">17. 如何在一行中计算多个表达式的值?</a></li>
39
+ <li><a href="#_18">18. 什么是提升?</a></li>
40
+ <li><a href="#_19">19. 什么是作用域?</a></li>
41
+ <li><a href="#_20">20. 什么是闭包?</a></li>
42
+ <li><a href="#_21">21. JavaScript中的虚值是什么?</a></li>
43
+ <li><a href="#_22">22. 如何检查值是否虚值?</a></li>
44
+ <li><a href="#_23">23. ‘use strict’ 是干嘛用的?</a></li>
45
+ <li><a href="#_24">24. JavaScript中 this 值是什么?</a></li>
46
+ <li><a href="#_25">25. 对象的 prototype 是什么?</a></li>
47
+ <li><a href="#_26">26. 什么是IIFE,它的用途是什么?</a></li>
48
+ <li><a href="#_27">27. Function.prototype.apply方法的用途是什么?</a></li>
49
+ <li><a href="#_28">28. Function.prototype.call方法的用途是什么?</a></li>
50
+ <li><a href="#_29">29. Function.prototype.apply 和 Function.prototype.call 之间有什么区别?</a></li>
51
+ <li><a href="#_30">30. Function.prototype.bind的用途是什么?</a></li>
52
+ <li><a href="#_31">31. 什么是函数式编程? JavaScript的哪些特性使其成为函数式语言的候选语言?</a></li>
53
+ <li><a href="#_32">32. 什么是高阶函数?</a></li>
54
+ <li><a href="#_33">33. 为什么函数被称为一等公民?</a></li>
55
+ <li><a href="#_34">34. 手动实现<code>Array.prototype.map</code>方法</a></li>
56
+ <li><a href="#_35">35. 手动实现<code>Array.prototype.filter</code>方法</a></li>
57
+ <li><a href="#_35">35. 手动实现<code>Array.prototype.reduce</code>方法</a></li>
58
+ <li><a href="#_37">37. arguments 的对象是什么?</a></li>
59
+ <li><a href="#_38">38. 如何创建一个没有 prototype(原型) 的对象?</a></li>
60
+ <li><a href="#_39">39. 为什么在调用这个函数时,代码中的<code>b</code>会变成一个全局变量?</a></li>
61
+ <li><a href="#_40">40. ECMAScript是什么?</a></li>
62
+ <li><a href="#_41">41. ES6或ECMAScript 2015有哪些新特性?</a></li>
63
+ <li><a href="#_42">42. <code>var</code>,<code>let</code>和<code>const</code>的区别是什么</a></li>
64
+ <li><a href="#_43">43. 什么是箭头函数?</a></li>
65
+ <li><a href="#_44">44. 什么是类?</a></li>
66
+ <li><a href="#_45">45. 什么是模板字符串?</a></li>
67
+ <li><a href="#_46">46. 什么是对象解构?</a></li>
68
+ <li><a href="#_47">47. 什么是 ES6 模块?</a></li>
69
+ <li><a href="#_48">48. 什么是<code>Set</code>对象,它是如何工作的?</a></li>
70
+ <li><a href="#_49">49. 什么是回调函数?</a></li>
71
+ <li><a href="#_50">50. Promise 是什么?</a></li>
72
+ <li><a href="#_51">51. 什么是 <code>async/await</code> 及其如何工作?</a></li>
73
+ <li><a href="#_52">52. 展开运算符和Rest运算符有什么区别?</a></li>
74
+ <li><a href="#_53">53. 什么是默认参数?</a></li>
75
+ <li><a href="#_54">54. 什么是包装对象(wrapper object)?</a></li>
76
+ <li><a href="#_55">55. 隐式和显式转换有什么区别?</a></li>
77
+ <li><a href="#_56">56. 什么是NaN? 以及如何检查值是否为 NaN?</a></li>
78
+ <li><a href="#_57">57. 如何判断值是否为数组?</a></li>
79
+ <li><a href="#_58">58. 如何在不使用<code>%</code>模运算符的情况下检查一个数字是否是偶数?</a></li>
80
+ <li><a href="#_59">59. 如何检查对象中是否存在某个属性?</a></li>
81
+ <li><a href="#_60">60. AJAX 是什么?</a></li>
82
+ <li><a href="#_61">61. 如何在JavaScript中创建对象?</a></li>
83
+ <li><a href="#_62">62. Object.seal 和 Object.freeze 方法之间有什么区别?</a></li>
84
+ <li><a href="#_63">63. 对象中的 in 运算符和 hasOwnProperty 方法有什么区别?</a></li>
85
+ <li><a href="#_64">64. 有哪些方法可以处理javascript中的异步代码?</a></li>
86
+ <li><a href="#_65">65. 函数表达式和函数声明之间有什么区别?</a></li>
87
+ <li><a href="#_66">66. 调用函数,可以使用哪些方法?</a></li>
88
+ <li><a href="#_67">67. 什么是缓存及它有什么作用?</a></li>
89
+ <li><a href="#_68">68. 手动实现缓存方法</a></li>
90
+ <li><a href="#_69">69. 为什么typeof null返回 object? 如何检查一个值是否为 null?</a></li>
91
+ <li><a href="#_70">70. new 关键字有什么作用?</a></li>
92
+ </ul>
93
+ <h3 id="1-undefined-和-null-有什么区别?-1-undefined-和-null-有什么区别?"><a href="#1-undefined-和-null-有什么区别?-1-undefined-和-null-有什么区别?" class="headerlink" title="[1.undefined 和 null 有什么区别?](1.undefined 和 null 有什么区别?)"></a>[1.undefined 和 null 有什么区别?](1.undefined 和 null 有什么区别?)</h3><p>在理解<code>undefined</code>和<code>null</code>之间的差异之前,我们先来看看它们的相似类。</p>
94
+ <p><strong>它们属于 JavaScript 的 7 种基本类型。</strong></p>
95
+ <pre><code> let primitiveTypes = [&#39;string&#39;,&#39;number&#39;,&#39;null&#39;,&#39;undefined&#39;,&#39;boolean&#39;,&#39;symbol&#39;, &#39;bigint&#39;];
96
+ </code></pre>
97
+ <p>它们是属于虚值,可以使用<code>Boolean(value)</code>或<code>!!value</code>将其转换为布尔值时,值为<code>false</code>。</p>
98
+ <pre><code>console.log(!!null); // false
99
+ console.log(!!undefined); // false
100
+
101
+ console.log(Boolean(null)); // false
102
+ console.log(Boolean(undefined)); // false
103
+ </code></pre>
104
+ <p>接着来看看它们的区别。</p>
105
+ <p><code>undefined</code>是未指定特定值的变量的默认值,或者没有显式返回值的函数,如:<code>console.log(1)</code>,还包括对象中不存在的属性,这些 JS 引擎都会为其分配 <code>undefined</code> 值。</p>
106
+ <pre><code>let _thisIsUndefined;
107
+ const doNothing = () =&gt; &#123;&#125;;
108
+ const someObj = &#123;
109
+ a : &quot;ay&quot;,
110
+ b : &quot;bee&quot;,
111
+ c : &quot;si&quot;
112
+ &#125;;
113
+
114
+ console.log(_thisIsUndefined); // undefined
115
+ console.log(doNothing()); // undefined
116
+ console.log(someObj[&quot;d&quot;]); // undefined
117
+ </code></pre>
118
+ <p><code>null</code>是<strong>“不代表任何值的值”</strong>。 <code>null</code>是已明确定义给变量的值。 在此示例中,当<code>fs.readFile</code>方法未引发错误时,我们将获得<code>null</code>值。</p>
119
+ <pre><code>fs.readFile(&#39;path/to/file&#39;, (e,data) =&gt; &#123;
120
+ console.log(e); // 当没有错误发生时,打印 null
121
+ if(e)&#123;
122
+ console.log(e);
123
+ &#125;
124
+ console.log(data);
125
+ &#125;);
126
+ </code></pre>
127
+ <p>在比较<code>null</code>和<code>undefined</code>时,我们使用<code>==</code>时得到<code>true</code>,使用<code>===</code>时得到<code>false</code>:</p>
128
+ <pre><code> console.log(null == undefined); // true
129
+ console.log(null === undefined); // false
130
+ </code></pre>
131
+ <h3 id="2-amp-amp-运算符能做什么-2-amp-amp-运算符能做什么"><a href="#2-amp-amp-运算符能做什么-2-amp-amp-运算符能做什么" class="headerlink" title="[2. &amp;&amp; 运算符能做什么](2. &amp;&amp; 运算符能做什么)"></a>[2. &amp;&amp; 运算符能做什么](2. &amp;&amp; 运算符能做什么)</h3><p><code>&amp;&amp;</code> 也可以叫<strong>逻辑与</strong>,在其操作数中找到第一个虚值表达式并返回它,如果没有找到任何虚值表达式,则返回最后一个真值表达式。它采用短路来防止不必要的工作。</p>
132
+ <pre><code>console.log(false &amp;&amp; 1 &amp;&amp; []); // false
133
+ console.log(&quot; &quot; &amp;&amp; true &amp;&amp; 5); // 5
134
+ </code></pre>
135
+ <p><strong>使用<code>if</code>语句</strong></p>
136
+ <pre><code>const router: Router = Router();
137
+
138
+ router.get(&#39;/endpoint&#39;, (req: Request, res: Response) =&gt; &#123;
139
+ let conMobile: PoolConnection;
140
+ try &#123;
141
+ //do some db operations
142
+ &#125; catch (e) &#123;
143
+ if (conMobile) &#123;
144
+ conMobile.release();
145
+ &#125;
146
+ &#125;
147
+ &#125;);
148
+ </code></pre>
149
+ <p><strong>使用<code>&amp;&amp;</code>操作符</strong></p>
150
+ <pre><code>const router: Router = Router();
151
+
152
+ router.get(&#39;/endpoint&#39;, (req: Request, res: Response) =&gt; &#123;
153
+ let conMobile: PoolConnection;
154
+ try &#123;
155
+ //do some db operations
156
+ &#125; catch (e) &#123;
157
+ conMobile &amp;&amp; conMobile.release()
158
+ &#125;
159
+ &#125;);
160
+ </code></pre>
161
+ <h3 id="3-运算符能做什么-3-运算符能做什么"><a href="#3-运算符能做什么-3-运算符能做什么" class="headerlink" title="[3. || 运算符能做什么](3. || 运算符能做什么)"></a>[3. || 运算符能做什么](3. || 运算符能做什么)</h3><p><code>||</code>也叫或<code>逻辑或</code>,在其操作数中找到第一个真值表达式并返回它。这也使用了短路来防止不必要的工作。在支持 ES6 默认函数参数之前,它用于初始化函数中的默认参数值。</p>
162
+ <pre><code>console.log(null || 1 || undefined); // 1
163
+
164
+ function logName(name) &#123;
165
+ var n = name || &quot;Mark&quot;;
166
+ console.log(n);
167
+ &#125;
168
+
169
+ logName(); // &quot;Mark&quot;
170
+ </code></pre>
171
+ <h3 id="4-使用-或一元加运算符是将字符串转换为数字的最快方法吗?-4-使用-或一元加运算符是将字符串转换为数字的最快方法吗?"><a href="#4-使用-或一元加运算符是将字符串转换为数字的最快方法吗?-4-使用-或一元加运算符是将字符串转换为数字的最快方法吗?" class="headerlink" title="[4. 使用 + 或一元加运算符是将字符串转换为数字的最快方法吗?](4. 使用 + 或一元加运算符是将字符串转换为数字的最快方法吗?)"></a>[4. 使用 + 或一元加运算符是将字符串转换为数字的最快方法吗?](4. 使用 + 或一元加运算符是将字符串转换为数字的最快方法吗?)</h3><p>根据<a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Unary_plus">MDN文档</a>,<code>+</code>是将字符串转换为数字的最快方法,因为如果值已经是数字,它不会执行任何操作。</p>
172
+ <h3 id="5-DOM-是什么?-5-DOM-是什么?"><a href="#5-DOM-是什么?-5-DOM-是什么?" class="headerlink" title="[5. DOM 是什么?](5. DOM 是什么?)"></a>[5. DOM 是什么?](5. DOM 是什么?)</h3><p><strong>DOM</strong> 代表<strong>文档对象模型</strong>,是 HTML 和 XML 文档的接口(API)。当浏览器第一次读取(解析)HTML文档时,它会创建一个大对象,一个基于 HTM L文档的非常大的对象,这就是<strong>DOM</strong>。它是一个从 HTML 文档中建模的树状结构。DOM 用于交互和修改DOM结构或特定元素或节点。</p>
173
+ <p>假设我们有这样的 HTML 结构:</p>
174
+ <pre><code>&lt;!DOCTYPE html&gt;
175
+ &lt;html lang=&quot;en&quot;&gt;
176
+
177
+ &lt;head&gt;
178
+ &lt;meta charset=&quot;UTF-8&quot;&gt;
179
+ &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
180
+ &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot;&gt;
181
+ &lt;title&gt;Document Object Model&lt;/title&gt;
182
+ &lt;/head&gt;
183
+
184
+ &lt;body&gt;
185
+ &lt;div&gt;
186
+ &lt;p&gt;
187
+ &lt;span&gt;&lt;/span&gt;
188
+ &lt;/p&gt;
189
+ &lt;label&gt;&lt;/label&gt;
190
+ &lt;input&gt;
191
+ &lt;/div&gt;
192
+ &lt;/body&gt;
193
+
194
+ &lt;/html&gt;
195
+ </code></pre>
196
+ <p>等价的<strong>DOM</strong>是这样的:</p>
197
+ <p><img src="https://img.php.cn/upload/image/440/587/283/1579139376818807.png" alt="1579139376818807.png"></p>
198
+ <p>JS 中的<code>document</code>对象表示DOM。它为我们提供了许多方法,我们可以使用这些方法来选择元素来更新元素内容,等等。</p>
199
+ <h3 id="6-什么是事件传播-6-什么是事件传播"><a href="#6-什么是事件传播-6-什么是事件传播" class="headerlink" title="[6. 什么是事件传播?](6. 什么是事件传播?)"></a>[6. 什么是事件传播?](6. 什么是事件传播?)</h3><p>当<strong>事件</strong>发生在<strong>DOM</strong>元素上时,该<strong>事件</strong>并不完全发生在那个元素上。 在<strong>“冒泡阶段”</strong>中,事件冒泡或向上传播至父级,祖父母,祖父母或父级,直到到达<code>window</code>为止;而在<strong>“捕获阶段”</strong>中,事件从<code>window</code>开始向下触发元素 事件或<code>event.target</code>。</p>
200
+ <p>事件传播有三个阶段:</p>
201
+ <ol>
202
+ <li><strong>捕获阶段</strong>–事件从 <code>window</code> 开始,然后向下到每个元素,直到到达目标元素。</li>
203
+ <li><strong>目标阶段</strong>–事件已达到目标元素。</li>
204
+ <li><strong>冒泡阶段</strong>–事件从目标元素冒泡,然后上升到每个元素,直到到达 <code>window</code>。</li>
205
+ </ol>
206
+ <p><img src="https://img.php.cn/upload/image/371/153/737/1579139382783438.png" alt="1579139382783438.png"></p>
207
+ <h3 id="7-什么是事件冒泡?-7-什么是事件冒泡?"><a href="#7-什么是事件冒泡?-7-什么是事件冒泡?" class="headerlink" title="[7. 什么是事件冒泡?](7. 什么是事件冒泡?)"></a>[7. 什么是事件冒泡?](7. 什么是事件冒泡?)</h3><p>当<strong>事件</strong>发生在<strong>DOM</strong>元素上时,该<strong>事件</strong>并不完全发生在那个元素上。 在冒泡阶段,事件冒泡,或者事件发生在它的父代,祖父母,祖父母的父代,直到到达<code>window</code>为止。</p>
208
+ <p>假设有如下的 HTML 结构:</p>
209
+ <pre><code>&lt;div class=&quot;grandparent&quot;&gt;
210
+ &lt;div class=&quot;parent&quot;&gt;
211
+ &lt;div class=&quot;child&quot;&gt;1&lt;/div&gt;
212
+ &lt;/div&gt;
213
+ &lt;/div&gt;
214
+ </code></pre>
215
+ <p>对应的 JS 代码:</p>
216
+ <pre><code>function addEvent(el, event, callback, isCapture = false) &#123;
217
+ if (!el || !event || !callback || typeof callback !== &#39;function&#39;) return;
218
+ if (typeof el === &#39;string&#39;) &#123;
219
+ el = document.querySelector(el);
220
+ &#125;;
221
+ el.addEventListener(event, callback, isCapture);
222
+ &#125;
223
+
224
+ addEvent(document, &#39;DOMContentLoaded&#39;, () =&gt; &#123;
225
+ const child = document.querySelector(&#39;.child&#39;);
226
+ const parent = document.querySelector(&#39;.parent&#39;);
227
+ const grandparent = document.querySelector(&#39;.grandparent&#39;);
228
+
229
+ addEvent(child, &#39;click&#39;, function (e) &#123;
230
+ console.log(&#39;child&#39;);
231
+ &#125;);
232
+
233
+ addEvent(parent, &#39;click&#39;, function (e) &#123;
234
+ console.log(&#39;parent&#39;);
235
+ &#125;);
236
+
237
+ addEvent(grandparent, &#39;click&#39;, function (e) &#123;
238
+ console.log(&#39;grandparent&#39;);
239
+ &#125;);
240
+
241
+ addEvent(document, &#39;click&#39;, function (e) &#123;
242
+ console.log(&#39;document&#39;);
243
+ &#125;);
244
+
245
+ addEvent(&#39;html&#39;, &#39;click&#39;, function (e) &#123;
246
+ console.log(&#39;html&#39;);
247
+ &#125;)
248
+
249
+ addEvent(window, &#39;click&#39;, function (e) &#123;
250
+ console.log(&#39;window&#39;);
251
+ &#125;)
252
+
253
+ &#125;);
254
+ </code></pre>
255
+ <p><code>addEventListener</code>方法具有第三个可选参数<code>useCapture</code>,其默认值为<code>false</code>,事件将在冒泡阶段中发生,如果为<code>true</code>,则事件将在捕获阶段中发生。 如果单击<code>child</code>元素,它将分别在控制台上记录<code>child</code>,<code>parent</code>,<code>grandparent</code>,<code>html</code>,<code>document</code>和<code>window</code>,这就是事件冒泡。</p>
256
+ <h3 id="8-什么是事件捕获?-8-什么是事件捕获?"><a href="#8-什么是事件捕获?-8-什么是事件捕获?" class="headerlink" title="[8. 什么是事件捕获?](8. 什么是事件捕获?)"></a>[8. 什么是事件捕获?](8. 什么是事件捕获?)</h3><p>当事件发生在 <strong>DOM</strong> 元素上时,该事件并不完全发生在那个元素上。在捕获阶段,事件从<code>window</code>开始,一直到触发事件的元素。</p>
257
+ <p>假设有如下的 HTML 结构:</p>
258
+ <pre><code>&lt;div class=&quot;grandparent&quot;&gt;
259
+ &lt;div class=&quot;parent&quot;&gt;
260
+ &lt;div class=&quot;child&quot;&gt;1&lt;/div&gt;
261
+ &lt;/div&gt;
262
+ &lt;/div&gt;
263
+ </code></pre>
264
+ <p>对应的 JS 代码:</p>
265
+ <pre><code>function addEvent(el, event, callback, isCapture = false) &#123;
266
+ if (!el || !event || !callback || typeof callback !== &#39;function&#39;) return;
267
+ if (typeof el === &#39;string&#39;) &#123;
268
+ el = document.querySelector(el);
269
+ &#125;;
270
+ el.addEventListener(event, callback, isCapture);
271
+ &#125;
272
+
273
+ addEvent(document, &#39;DOMContentLoaded&#39;, () =&gt; &#123;
274
+ const child = document.querySelector(&#39;.child&#39;);
275
+ const parent = document.querySelector(&#39;.parent&#39;);
276
+ const grandparent = document.querySelector(&#39;.grandparent&#39;);
277
+
278
+ addEvent(child, &#39;click&#39;, function (e) &#123;
279
+ console.log(&#39;child&#39;);
280
+ &#125;);
281
+
282
+ addEvent(parent, &#39;click&#39;, function (e) &#123;
283
+ console.log(&#39;parent&#39;);
284
+ &#125;);
285
+
286
+ addEvent(grandparent, &#39;click&#39;, function (e) &#123;
287
+ console.log(&#39;grandparent&#39;);
288
+ &#125;);
289
+
290
+ addEvent(document, &#39;click&#39;, function (e) &#123;
291
+ console.log(&#39;document&#39;);
292
+ &#125;);
293
+
294
+ addEvent(&#39;html&#39;, &#39;click&#39;, function (e) &#123;
295
+ console.log(&#39;html&#39;);
296
+ &#125;)
297
+
298
+ addEvent(window, &#39;click&#39;, function (e) &#123;
299
+ console.log(&#39;window&#39;);
300
+ &#125;)
301
+
302
+ &#125;);
303
+ </code></pre>
304
+ <p><code>addEventListener</code>方法具有第三个可选参数<code>useCapture</code>,其默认值为<code>false</code>,事件将在冒泡阶段中发生,如果为<code>true</code>,则事件将在捕获阶段中发生。 如果单击<code>child</code>元素,它将分别在控制台上打印<code>window</code>,<code>document</code>,<code>html</code>,<code>grandparent</code>和<code>parent</code>,这就是<strong>事件捕获</strong>。</p>
305
+ <h3 id="9-event-preventDefault-和-event-stopPropagation-方法之间有什么区别?-9-event-preventDefault-和-event-stopPropagation-方法之间有什么区别?"><a href="#9-event-preventDefault-和-event-stopPropagation-方法之间有什么区别?-9-event-preventDefault-和-event-stopPropagation-方法之间有什么区别?" class="headerlink" title="[9. event.preventDefault() 和 event.stopPropagation()方法之间有什么区别?](9. event.preventDefault() 和 event.stopPropagation()方法之间有什么区别?)"></a>[9. event.preventDefault() 和 event.stopPropagation()方法之间有什么区别?](9. event.preventDefault() 和 event.stopPropagation()方法之间有什么区别?)</h3><p><code>event.preventDefault()</code> 方法可防止元素的默认行为。 如果在表单元素中使用,它将阻止其提交。 如果在锚元素中使用,它将阻止其导航。 如果在上下文菜单中使用,它将阻止其显示或显示。 <code>event.stopPropagation()</code>方法用于阻止捕获和冒泡阶段中当前事件的进一步传播。</p>
306
+ <h3 id="10-如何知道是否在元素中使用了event-preventDefault-方法?-10-如何知道是否在元素中使用了event-preventDefault-方法?"><a href="#10-如何知道是否在元素中使用了event-preventDefault-方法?-10-如何知道是否在元素中使用了event-preventDefault-方法?" class="headerlink" title="[10. 如何知道是否在元素中使用了event.preventDefault()方法?](10. 如何知道是否在元素中使用了event.preventDefault()方法?)"></a>[10. 如何知道是否在元素中使用了<code>event.preventDefault()</code>方法?](10. 如何知道是否在元素中使用了<code>event.preventDefault()</code>方法?)</h3><p>我们可以在事件对象中使用<code>event.defaultPrevented</code>属性。 它返回一个布尔值用来表明是否在特定元素中调用了<code>event.preventDefault()</code>。</p>
307
+ <h3 id="11-为什么此代码-obj-someprop-x-会引发错误-11-为什么此代码-obj-someprop-x-会引发错误"><a href="#11-为什么此代码-obj-someprop-x-会引发错误-11-为什么此代码-obj-someprop-x-会引发错误" class="headerlink" title="[11. 为什么此代码 obj.someprop.x 会引发错误?](11. 为什么此代码 obj.someprop.x 会引发错误?)"></a>[11. 为什么此代码 <code>obj.someprop.x</code> 会引发错误?](11. 为什么此代码 <code>obj.someprop.x</code> 会引发错误?)</h3><pre><code>const obj = &#123;&#125;;
308
+ console.log(obj.someprop.x);
309
+ </code></pre>
310
+ <p>显然,由于我们尝试访问<code>someprop</code>属性中的<code>x</code>属性,而 someprop 并没有在对象中,所以值为 <code>undefined</code>。 记住对象本身不存在的属性,并且其原型的默认值为<code>undefined</code>。因为<code>undefined</code>没有属性<code>x</code>,所以试图访问将会报错。</p>
311
+ <h3 id="12-什么是-event-target-?-12-什么是-event-target-?"><a href="#12-什么是-event-target-?-12-什么是-event-target-?" class="headerlink" title="[12. 什么是 event.target ?](12. 什么是 event.target ?)"></a>[12. 什么是 event.target ?](12. 什么是 event.target ?)</h3><p>简单来说,<code>event.target</code>是发生事件的元素或触发事件的元素。</p>
312
+ <p>假设有如下的 HTML 结构:</p>
313
+ <pre><code>&lt;div onclick=&quot;clickFunc(event)&quot; style=&quot;text-align: center;margin:15px;
314
+ border:1px solid red;border-radius:3px;&quot;&gt;
315
+ &lt;div style=&quot;margin: 25px; border:1px solid royalblue;border-radius:3px;&quot;&gt;
316
+ &lt;div style=&quot;margin:25px;border:1px solid skyblue;border-radius:3px;&quot;&gt;
317
+ &lt;button style=&quot;margin:10px&quot;&gt;
318
+ Button
319
+ &lt;/button&gt;
320
+ &lt;/div&gt;
321
+ &lt;/div&gt;
322
+ &lt;/div&gt;
323
+ </code></pre>
324
+ <p>JS 代码如下:</p>
325
+ <pre><code>function clickFunc(event) &#123;
326
+ console.log(event.target);
327
+ &#125;
328
+ </code></pre>
329
+ <p>如果单击 <code>button</code>,即使我们将事件附加在最外面的<code>div</code>上,它也将打印 <code>button</code> 标签,因此我们可以得出结论<code>event.target</code>是触发事件的元素。</p>
330
+ <h3 id="13-什么是-event-currentTarget??-13-什么是-event-currentTarget??"><a href="#13-什么是-event-currentTarget??-13-什么是-event-currentTarget??" class="headerlink" title="[13. 什么是 event.currentTarget??](13. 什么是 event.currentTarget??)"></a>[13. 什么是 event.currentTarget??](13. 什么是 event.currentTarget??)</h3><p><code>event.currentTarget</code>是我们在其上显式附加事件处理程序的元素。</p>
331
+ <p>假设有如下的 HTML 结构:</p>
332
+ <pre><code>&lt;div onclick=&quot;clickFunc(event)&quot; style=&quot;text-align: center;margin:15px;
333
+ border:1px solid red;border-radius:3px;&quot;&gt;
334
+ &lt;div style=&quot;margin: 25px; border:1px solid royalblue;border-radius:3px;&quot;&gt;
335
+ &lt;div style=&quot;margin:25px;border:1px solid skyblue;border-radius:3px;&quot;&gt;
336
+ &lt;button style=&quot;margin:10px&quot;&gt;
337
+ Button
338
+ &lt;/button&gt;
339
+ &lt;/div&gt;
340
+ &lt;/div&gt;
341
+ &lt;/div&gt;
342
+ </code></pre>
343
+ <p>JS 代码如下:</p>
344
+ <pre><code>function clickFunc(event) &#123;
345
+ console.log(event.currentTarget);
346
+ &#125;
347
+ </code></pre>
348
+ <p>如果单击 <code>button</code>,即使我们单击该 <code>button</code>,它也会打印最外面的<code>div</code>标签。 在此示例中,我们可以得出结论,<code>event.currentTarget</code>是附加事件处理程序的元素。</p>
349
+ <h3 id="14-x3D-x3D-和-x3D-x3D-x3D-有什么区别?-14-x3D-x3D-和-x3D-x3D-x3D-有什么区别?"><a href="#14-x3D-x3D-和-x3D-x3D-x3D-有什么区别?-14-x3D-x3D-和-x3D-x3D-x3D-有什么区别?" class="headerlink" title="[14. &#x3D;&#x3D; 和 &#x3D;&#x3D;&#x3D; 有什么区别?](14. &#x3D;&#x3D; 和 &#x3D;&#x3D;&#x3D; 有什么区别?)"></a>[14. &#x3D;&#x3D; 和 &#x3D;&#x3D;&#x3D; 有什么区别?](14. &#x3D;&#x3D; 和 &#x3D;&#x3D;&#x3D; 有什么区别?)</h3><p><code>==</code>用于一般比较,<code>===</code>用于严格比较,<code>==</code>在比较的时候可以转换数据类型<code>,===</code>严格比较,只要类型不匹配就返回<code>flase</code>。</p>
350
+ <p>先来看看 <code>==</code> 这兄弟:</p>
351
+ <p>强制是将值转换为另一种类型的过程。 在这种情况下,<code>==</code>会执行隐式强制。 在比较两个值之前,<code>==</code>需要执行一些规则。</p>
352
+ <p>假设我们要比较<code>x == y</code>的值。</p>
353
+ <ol>
354
+ <li>如果<code>x</code>和<code>y</code>的类型相同,则 JS 会换成<code>===</code>操作符进行比较。</li>
355
+ <li>如果<code>x</code>为<code>null</code>, <code>y</code>为<code>undefined</code>,则返回<code>true</code>。</li>
356
+ <li>如果<code>x</code>为<code>undefined</code>且<code>y</code>为<code>null</code>,则返回<code>true</code>。</li>
357
+ <li>如果<code>x</code>的类型是<code>number</code>, <code>y</code>的类型是<code>string</code>,那么返回<code>x == toNumber(y)</code>。</li>
358
+ <li>如果<code>x</code>的类型是<code>string</code>, <code>y</code>的类型是<code>number</code>,那么返回<code>toNumber(x) == y</code>。</li>
359
+ <li>如果<code>x</code>为类型是<code>boolean</code>,则返回<code>toNumber(x)== y</code>。</li>
360
+ <li>如果<code>y</code>为类型是<code>boolean</code>,则返回<code>x == toNumber(y)</code>。</li>
361
+ <li>如果<code>x</code>是<code>string</code>、<code>symbol</code>或<code>number</code>,而<code>y</code>是<code>object</code>类型,则返回<code>x == toPrimitive(y)</code>。</li>
362
+ <li>如果<code>x</code>是<code>object</code>,<code>y</code>是<code>string</code>,<code>symbol </code>则返回<code>toPrimitive(x) == y</code>。</li>
363
+ <li>剩下的 返回 <code>false</code></li>
364
+ </ol>
365
+ <p>注意:<code>toPrimitive</code>首先在对象中使用<code>valueOf</code>方法,然后使用<code>toString</code>方法来获取该对象的原始值。</p>
366
+ <p>举个例子。<br>xyx &#x3D;&#x3D; y55true1’1’truenullundefinedtrue0falsetrue’1,2’[1,2]true’[object Object]’{}true<br>这些例子都返回<code>true</code>。</p>
367
+ <p>第一个示例符合<code>条件1</code>,因为<code>x</code>和<code>y</code>具有相同的类型和值。</p>
368
+ <p>第二个示例符合<code>条件4</code>,在比较之前将<code>y</code>转换为数字。</p>
369
+ <p>第三个例子符合<code>条件2</code>。</p>
370
+ <p>第四个例子符合<code>条件7</code>,因为<code>y</code>是<code>boolean</code>类型。</p>
371
+ <p>第五个示例符合<code>条件8</code>。 使用<code>toString()</code>方法将数组转换为字符串,该方法返回<code>1,2</code>。</p>
372
+ <p>最后一个示例符合<code>条件8</code>。 使用<code>toString()</code>方法将对象转换为字符串,该方法返回<code>[object Object]</code>。<br>xyx &#x3D;&#x3D;&#x3D; y55true1’1’falsenullundefinedfalse0falsefalse’1,2’[1,2]false’[object Object]’{}false<br>如果使用<code>===</code>运算符,则第一个示例以外的所有比较将返回<code>false</code>,因为它们的类型不同,而第一个示例将返回<code>true</code>,因为两者的类型和值相同。</p>
373
+ <h3 id="15-为什么在-JS-中比较两个相似的对象时返回-false?-15-为什么在-JS-中比较两个相似的对象时返回-false?"><a href="#15-为什么在-JS-中比较两个相似的对象时返回-false?-15-为什么在-JS-中比较两个相似的对象时返回-false?" class="headerlink" title="[15. 为什么在 JS 中比较两个相似的对象时返回 false?](15. 为什么在 JS 中比较两个相似的对象时返回 false?)"></a>[15. 为什么在 JS 中比较两个相似的对象时返回 false?](15. 为什么在 JS 中比较两个相似的对象时返回 false?)</h3><p>先看下面的例子:</p>
374
+ <pre><code>let a = &#123; a: 1 &#125;;
375
+ let b = &#123; a: 1 &#125;;
376
+ let c = a;
377
+
378
+ console.log(a === b); // 打印 false,即使它们有相同的属性
379
+ console.log(a === c); // true
380
+ </code></pre>
381
+ <p>JS 以不同的方式比较对象和基本类型。在基本类型中,JS 通过值对它们进行比较,而在对象中,JS 通过引用或存储变量的内存中的地址对它们进行比较。这就是为什么第一个<code>console.log</code>语句返回<code>false</code>,而第二个<code>console.log</code>语句返回<code>true</code>。<code>a</code>和<code>c</code>有相同的引用地址,而<code>a</code>和<code>b</code>没有。</p>
382
+ <h3 id="16-运算符能做什么?-16-运算符能做什么?"><a href="#16-运算符能做什么?-16-运算符能做什么?" class="headerlink" title="[16. !! 运算符能做什么?](16. !! 运算符能做什么?)"></a>[16. !! 运算符能做什么?](16. !! 运算符能做什么?)</h3><p><code>!!</code>运算符可以将右侧的值强制转换为布尔值,这也是将值转换为布尔值的一种简单方法。</p>
383
+ <pre><code>console.log(!!null); // false
384
+ console.log(!!undefined); // false
385
+ console.log(!!&#39;&#39;); // false
386
+ console.log(!!0); // false
387
+ console.log(!!NaN); // false
388
+ console.log(!!&#39; &#39;); // true
389
+ console.log(!!&#123;&#125;); // true
390
+ console.log(!![xuehuayu.cn]); // true
391
+ console.log(!!1); // true
392
+ console.log(!![xuehuayu.cn].length); // false
393
+ </code></pre>
394
+ <h3 id="17-如何在一行中计算多个表达式的值?-17-如何在一行中计算多个表达式的值?"><a href="#17-如何在一行中计算多个表达式的值?-17-如何在一行中计算多个表达式的值?" class="headerlink" title="[17. 如何在一行中计算多个表达式的值?](17. 如何在一行中计算多个表达式的值?)"></a>[17. 如何在一行中计算多个表达式的值?](17. 如何在一行中计算多个表达式的值?)</h3><p>可以使用<code>逗号</code>运算符在一行中计算多个表达式。 它从左到右求值,并返回右边最后一个项目或最后一个操作数的值。</p>
395
+ <pre><code>let x = 5;
396
+
397
+ x = (x++ , x = addFive(x), x *= 2, x -= 5, x += 10);
398
+
399
+ function addFive(num) &#123;
400
+ return num + 5;
401
+ &#125;
402
+ </code></pre>
403
+ <p>上面的结果最后得到<code>x</code>的值为<code>27</code>。首先,我们将<code>x</code>的值增加到<code>6</code>,然后调用函数<code>addFive(6)</code>并将<code>6</code>作为参数传递并将结果重新分配给<code>x</code>,此时<code>x</code>的值为<code>11</code>。之后,将<code>x</code>的当前值乘以<code>2</code>并将其分配给<code>x</code>,<code>x</code>的更新值为<code>22</code>。然后,将<code>x</code>的当前值减去<code>5</code>并将结果分配给<code>x``x</code>更新后的值为<code>17</code>。最后,我们将<code>x</code>的值增加<code>10</code>,然后将更新的值分配给<code>x</code>,最终<code>x</code>的值为<code>27</code>。</p>
404
+ <h3 id="18-什么是提升?-18-什么是提升?"><a href="#18-什么是提升?-18-什么是提升?" class="headerlink" title="[18. 什么是提升?](18. 什么是提升?)"></a>[18. 什么是提升?](18. 什么是提升?)</h3><p><strong>提升</strong>是用来描述变量和函数移动到其(全局或函数)作用域顶部的术语。</p>
405
+ <p>为了理解提升,需要来了解一下<strong>执行上下文</strong>。<strong>执行上下文</strong>是当前正在执行的<strong>“代码环境”</strong>。执行上下文有两个阶段:<code>编译</code>和<code>执行</code>。</p>
406
+ <p><strong>编译</strong>-在此阶段,JS 引荐获取所有<strong>函数声明</strong>并将其<strong>提升</strong>到其作用域的顶部,以便我们稍后可以引用它们并获取所有变量声明(使用<code>var</code>关键字进行声明),还会为它们提供默认值: <code>undefined</code>。</p>
407
+ <p><strong>执行</strong>——在这个阶段中,它将值赋给之前提升的变量,并执行或调用函数(对象中的方法)。</p>
408
+ <p>**注意:**只有使用<code>var</code>声明的变量,或者函数声明才会被提升,相反,函数表达式或箭头函数,<code>let</code>和<code>const</code>声明的变量,这些都不会被提升。</p>
409
+ <p>假设在全局使用域,有如下的代码:</p>
410
+ <pre><code>console.log(y);
411
+ y = 1;
412
+ console.log(y);
413
+ console.log(greet(&quot;Mark&quot;));
414
+
415
+ function greet(name)&#123;
416
+ return &#39;Hello &#39; + name + &#39;!&#39;;
417
+ &#125;
418
+
419
+ var y;
420
+ </code></pre>
421
+ <p>上面分别打印:<code>undefined</code>,<code>1</code>, <code>Hello Mark!</code>。</p>
422
+ <p>上面代码在编译阶段其实是这样的:</p>
423
+ <pre><code>function greet(name) &#123;
424
+ return &#39;Hello &#39; + name + &#39;!&#39;;
425
+ &#125;
426
+
427
+ var y; // 默认值 undefined
428
+
429
+ // 等待“编译”阶段完成,然后开始“执行”阶段
430
+
431
+ /*
432
+ console.log(y);
433
+ y = 1;
434
+ console.log(y);
435
+ console.log(greet(&quot;Mark&quot;));
436
+ */
437
+ </code></pre>
438
+ <p>编译阶段完成后,它将启动执行阶段调用方法,并将值分配给变量。</p>
439
+ <pre><code>function greet(name) &#123;
440
+ return &#39;Hello &#39; + name + &#39;!&#39;;
441
+ &#125;
442
+
443
+ var y;
444
+
445
+ //start &quot;execution&quot; phase
446
+
447
+ console.log(y);
448
+ y = 1;
449
+ console.log(y);
450
+ console.log(greet(&quot;Mark&quot;));
451
+ </code></pre>
452
+ <h3 id="19-什么是作用域?-19-什么是作用域?"><a href="#19-什么是作用域?-19-什么是作用域?" class="headerlink" title="[19. 什么是作用域?](19. 什么是作用域?)"></a>[19. 什么是作用域?](19. 什么是作用域?)</h3><p>JavaScript 中的作用域是我们可以有效访问变量或函数的区域。JS 有三种类型的作用域:<strong>全局作用域</strong>、<strong>函数作用域</strong>和**块作用域(ES6)**。</p>
453
+ <ul>
454
+ <li><p><strong>全局作用域</strong>——在全局命名空间中声明的变量或函数位于全局作用域中,因此在代码中的任何地方都可以访问它们。</p>
455
+ <p> &#x2F;&#x2F;global namespace<br> var g &#x3D; “global”;</p>
456
+ <p> function globalFunc(){<br>function innerFunc(){<br> console.log(g); &#x2F;&#x2F; can access “g” because “g” is a global variable<br>}<br> innerFunc();<br> }</p>
457
+ </li>
458
+ <li><p><strong>函数作用域</strong>——在函数中声明的变量、函数和参数可以在函数内部访问,但不能在函数外部访问。</p>
459
+ <p> function myFavoriteFunc(a) {<br>if (true) {<br> var b &#x3D; “Hello “ + a;<br>}<br>return b;<br> }</p>
460
+ <p> myFavoriteFunc(“World”);</p>
461
+ <p> console.log(a); &#x2F;&#x2F; Throws a ReferenceError “a” is not defined<br> console.log(b); &#x2F;&#x2F; does not continue here</p>
462
+ </li>
463
+ <li><p><strong>块作用域</strong>-在块<code>&#123;&#125;</code>中声明的变量(<code>let,const</code>)只能在其中访问。</p>
464
+ <p> function testBlock(){<br> if(true){<br> let z &#x3D; 5;<br> }<br> return z;<br> }</p>
465
+ <p> testBlock(); &#x2F;&#x2F; Throws a ReferenceError “z” is not defined</p>
466
+ </li>
467
+ </ul>
468
+ <p>作用域也是一组用于查找变量的规则。 如果变量在当前作用域中不存在,它将向外部作用域中查找并搜索,如果该变量不存在,它将再次查找直到到达全局作用域,如果找到,则可以使用它,否则引发错误,这种查找过程也称为<strong>作用域链</strong>。</p>
469
+ <pre><code> /* 作用域链
470
+
471
+ 内部作用域-&gt;外部作用域-&gt; 全局作用域
472
+ */
473
+
474
+ // 全局作用域
475
+ var variable1 = &quot;Comrades&quot;;
476
+ var variable2 = &quot;Sayonara&quot;;
477
+
478
+ function outer()&#123;
479
+ // 外部作用域
480
+ var variable1 = &quot;World&quot;;
481
+ function inner()&#123;
482
+ // 内部作用域
483
+ var variable2 = &quot;Hello&quot;;
484
+ console.log(variable2 + &quot; &quot; + variable1);
485
+ &#125;
486
+ inner();
487
+ &#125;
488
+ outer(); // Hello World
489
+ </code></pre>
490
+ <p><img src="https://img.php.cn/upload/image/709/757/979/1579139493301003.png" alt="1579139493301003.png"></p>
491
+ <h3 id="20-什么是闭包?-20-什么是闭包?"><a href="#20-什么是闭包?-20-什么是闭包?" class="headerlink" title="[20. 什么是闭包?](20. 什么是闭包?)"></a>[20. 什么是闭包?](20. 什么是闭包?)</h3><p>这可能是所有问题中最难的一个问题,因为闭包是一个有争议的话题,这里从个人角度来谈谈,如果不妥,多多海涵。</p>
492
+ <p><strong>闭包</strong>就是一个函数在声明时能够记住当前作用域、父函数作用域、及父函数作用域上的变量和参数的引用,直至通过作用域链上全局作用域,基本上闭包是在声明函数时创建的作用域。</p>
493
+ <p>看看小例子:</p>
494
+ <pre><code> // 全局作用域
495
+ var globalVar = &quot;abc&quot;;
496
+
497
+ function a()&#123;
498
+ console.log(globalVar);
499
+ &#125;
500
+
501
+ a(); // &quot;abc&quot;
502
+ </code></pre>
503
+ <p>在此示例中,当我们声明<code>a</code>函数时,全局作用域是<code>a</code>闭包的一部分。</p>
504
+ <p><img src="https://img.php.cn/upload/image/994/868/829/1579139510687958.png" alt="1579139510687958.png"></p>
505
+ <p>变量<code>globalVar</code>在图中没有值的原因是该变量的值可以根据调用函数<code>a</code>的位置和时间而改变。但是在上面的示例中,<code>globalVar</code>变量的值为<code>abc</code>。</p>
506
+ <p>来看一个更复杂的例子:</p>
507
+ <pre><code>var globalVar = &quot;global&quot;;
508
+ var outerVar = &quot;outer&quot;
509
+
510
+ function outerFunc(outerParam) &#123;
511
+ function innerFunc(innerParam) &#123;
512
+ console.log(globalVar, outerParam, innerParam);
513
+ &#125;
514
+ return innerFunc;
515
+ &#125;
516
+
517
+ const x = outerFunc(outerVar);
518
+ outerVar = &quot;outer-2&quot;;
519
+ globalVar = &quot;guess&quot;
520
+ x(&quot;inner&quot;);
521
+ </code></pre>
522
+ <p><img src="https://img.php.cn/upload/image/917/676/301/1579139523486205.png" alt="1579139523486205.png"></p>
523
+ <p>上面打印结果是 <code>guess outer inner</code>。</p>
524
+ <p>当我们调用<code>outerFunc</code>函数并将返回值<code>innerFunc</code>函数分配给变量<code>x</code>时,即使我们为<code>outerVar</code>变量分配了新值<code>outer-2</code>,<code>outerParam</code>也继续保留<code>outer</code>值,因为重新分配是在调用<code>outerFunc</code>之后发生的,并且当我们调用<code>outerFunc</code>函数时,它会在作用域链中查找<code>outerVar</code>的值,此时的<code>outerVar</code>的值将为 <code>&quot;outer&quot;</code>。</p>
525
+ <p>现在,当我们调用引用了<code>innerFunc</code>的<code>x</code>变量时,<code>innerParam</code>将具有一个<code>inner</code>值,因为这是我们在调用中传递的值,而<code>globalVar</code>变量值为<code>guess</code>,因为在调用<code>x</code>变量之前,我们将一个新值分配给<code>globalVar</code>。</p>
526
+ <p>下面这个示例演示没有理解好闭包所犯的错误:</p>
527
+ <pre><code>const arrFuncs = [];
528
+ for(var i = 0; i &lt; 5; i++)&#123;
529
+ arrFuncs.push(function ()&#123;
530
+ return i;
531
+ &#125;);
532
+ &#125;
533
+ console.log(i); // i is 5
534
+
535
+ for (let i = 0; i &lt; arrFuncs.length; i++) &#123;
536
+ console.log(arrFuncs[i]()); // 都打印 5
537
+ &#125;
538
+ </code></pre>
539
+ <p>由于闭包,此代码无法正常运行。<code>var</code>关键字创建一个全局变量,当我们 push 一个函数时,这里返回的全局变量<code>i</code>。 因此,当我们在循环后在该数组中调用其中一个函数时,它会打印<code>5</code>,因为我们得到<code>i</code>的当前值为<code>5</code>,我们可以访问它,因为它是全局变量。</p>
540
+ <p>因为闭包在创建变量时会保留该变量的引用而不是其值。 我们可以使用<strong>IIFES</strong>或使用 <code>let</code> 来代替 <code>var</code> 的声明。</p>
541
+ <h3 id="21-JavaScript-中的虚值是什么?-21-JavaScript-中的虚值是什么?"><a href="#21-JavaScript-中的虚值是什么?-21-JavaScript-中的虚值是什么?" class="headerlink" title="[21. JavaScript 中的虚值是什么?](21. JavaScript 中的虚值是什么?)"></a>[21. JavaScript 中的虚值是什么?](21. JavaScript 中的虚值是什么?)</h3><pre><code> const falsyValues = [&#39;&#39;, 0, null, undefined, NaN, false];
542
+ </code></pre>
543
+ <p>简单的来说虚值就是是在转换为布尔值时变为 <code>false</code> 的值。</p>
544
+ <h3 id="22-如何检查值是否虚值?-22-如何检查值是否虚值?"><a href="#22-如何检查值是否虚值?-22-如何检查值是否虚值?" class="headerlink" title="[22. 如何检查值是否虚值?](22. 如何检查值是否虚值?)"></a>[22. 如何检查值是否虚值?](22. 如何检查值是否虚值?)</h3><p>使用 <code>Boolean</code> 函数或者 <code>!!</code> 运算符。</p>
545
+ <h3 id="23-‘use-strict’-是干嘛用的?-23-‘use-strict’-是干嘛用的?"><a href="#23-‘use-strict’-是干嘛用的?-23-‘use-strict’-是干嘛用的?" class="headerlink" title="[23. ‘use strict’ 是干嘛用的?](23. ‘use strict’ 是干嘛用的?)"></a>[23. ‘use strict’ 是干嘛用的?](23. ‘use strict’ 是干嘛用的?)</h3><p><code>&quot;use strict&quot;</code> 是 <strong>ES5</strong> 特性,它使我们的代码在函数或整个脚本中处于<strong>严格模式</strong>。<strong>严格模式</strong>帮助我们在代码的早期避免 bug,并为其添加限制。</p>
546
+ <p><strong>严格模式</strong>的一些限制:</p>
547
+ <ol>
548
+ <li>变量必须声明后再使用</li>
549
+ <li>函数的参数不能有同名属性,否则报错</li>
550
+ <li>不能使用<code>with</code>语句</li>
551
+ <li>不能对只读属性赋值,否则报错</li>
552
+ <li>不能使用前缀 0 表示八进制数,否则报错</li>
553
+ <li>不能删除不可删除的属性,否则报错</li>
554
+ <li>不能删除变量<code>delete prop</code>,会报错,只能删除属性<code>delete global[prop]</code></li>
555
+ <li><code>eval</code>不能在它的外层作用域引入变量</li>
556
+ <li><code>eval</code>和<code>arguments</code>不能被重新赋值</li>
557
+ <li><code>arguments</code>不会自动反映函数参数的变化</li>
558
+ <li>不能使用<code>arguments.callee</code></li>
559
+ <li>不能使用<code>arguments.caller</code></li>
560
+ <li>禁止<code>this</code>指向全局对象</li>
561
+ <li>不能使用<code>fn.caller</code>和<code>fn.arguments</code>获取函数调用的堆栈</li>
562
+ <li>增加了保留字(比如<code>protected</code>、<code>static</code>和<code>interface</code>)</li>
563
+ </ol>
564
+ <p>设立”严格模式”的目的,主要有以下几个:</p>
565
+ <ol>
566
+ <li>消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;</li>
567
+ <li>消除代码运行的一些不安全之处,保证代码运行的安全;</li>
568
+ <li>提高编译器效率,增加运行速度;</li>
569
+ <li>为未来新版本的Javascript做好铺垫。</li>
570
+ </ol>
571
+ <h3 id="24-JavaScript-中-this-值是什么?-24-JavaScript-中-this-值是什么?"><a href="#24-JavaScript-中-this-值是什么?-24-JavaScript-中-this-值是什么?" class="headerlink" title="[24. JavaScript 中 this 值是什么?](24. JavaScript 中 this 值是什么?)"></a>[24. JavaScript 中 <code>this</code> 值是什么?](24. JavaScript 中 <code>this</code> 值是什么?)</h3><p>基本上,<code>this</code>指的是当前正在执行或调用该函数的对象的值。<code>this</code>值的变化取决于我们使用它的上下文和我们在哪里使用它。</p>
572
+ <pre><code>const carDetails = &#123;
573
+ name: &quot;Ford Mustang&quot;,
574
+ yearBought: 2005,
575
+ getName()&#123;
576
+ return this.name;
577
+ &#125;,
578
+ isRegistered: true
579
+ &#125;;
580
+
581
+ console.log(carDetails.getName()); // Ford Mustang
582
+ </code></pre>
583
+ <p>这通常是我们期望结果的,因为在<code>getName</code>方法中我们返回<code>this.name</code>,在此上下文中,<code>this</code>指向的是<code>carDetails</code>对象,该对象当前是执行函数的“所有者”对象。</p>
584
+ <p>接下我们做些奇怪的事情:</p>
585
+ <pre><code>var name = &quot;Ford Ranger&quot;;
586
+ var getCarName = carDetails.getName;
587
+
588
+ console.log(getCarName()); // Ford Ranger
589
+ </code></pre>
590
+ <p>上面打印<code>Ford Ranger</code>,这很奇怪,因为在第一个<code>console.log</code>语句中打印的是<code>Ford Mustang</code>。这样做的原因是<code>getCarName</code>方法有一个不同的“所有者”对象,即<code>window</code>对象。在全局作用域中使用<code>var</code>关键字声明变量会在<code>window</code>对象中附加与变量名称相同的属性。请记住,当没有使用<code>“use strict”</code>时,在全局作用域中<code>this</code>指的是<code>window</code>对象。</p>
591
+ <pre><code>console.log(getCarName === window.getCarName); // true
592
+ console.log(getCarName === this.getCarName); // true
593
+ </code></pre>
594
+ <p>本例中的<code>this</code>和<code>window</code>引用同一个对象。</p>
595
+ <p>解决这个问题的一种方法是在函数中使用<code>apply</code>和<code>call</code>方法。</p>
596
+ <pre><code>console.log(getCarName.apply(carDetails)); // Ford Mustang
597
+ console.log(getCarName.call(carDetails)); // Ford Mustang
598
+ </code></pre>
599
+ <p><code>apply</code>和<code>call</code>方法期望第一个参数是一个对象,该对象是函数内部<code>this</code>的值。</p>
600
+ <p><code>IIFE</code>或<strong>立即执行的函数表达式</strong>,在全局作用域内声明的函数,对象内部方法中的匿名函数和内部函数的<code>this</code>具有默认值,该值指向<code>window</code>对象。</p>
601
+ <pre><code> (function ()&#123;
602
+ console.log(this);
603
+ &#125;)(); // 打印 &quot;window&quot; 对象
604
+
605
+ function iHateThis()&#123;
606
+ console.log(this);
607
+ &#125;
608
+
609
+ iHateThis(); // 打印 &quot;window&quot; 对象
610
+
611
+ const myFavoriteObj = &#123;
612
+ guessThis()&#123;
613
+ function getName()&#123;
614
+ console.log(this.name);
615
+ &#125;
616
+ getName();
617
+ &#125;,
618
+ name: &#39;Marko Polo&#39;,
619
+ thisIsAnnoying(callback)&#123;
620
+ callback();
621
+ &#125;
622
+ &#125;;
623
+
624
+
625
+ myFavoriteObj.guessThis(); // 打印 &quot;window&quot; 对象
626
+ myFavoriteObj.thisIsAnnoying(function ()&#123;
627
+ console.log(this); // 打印 &quot;window&quot; 对象
628
+ &#125;);
629
+ </code></pre>
630
+ <p>如果我们要获取<code>myFavoriteObj</code>对象中的<code>name</code>属性(即<strong>Marko Polo</strong>)的值,则有两种方法可以解决此问题。</p>
631
+ <p>一种是将 <code>this</code> 值保存在变量中。</p>
632
+ <pre><code>const myFavoriteObj = &#123;
633
+ guessThis()&#123;
634
+ const self = this; // 把 this 值保存在 self 变量中
635
+ function getName()&#123;
636
+ console.log(self.name);
637
+ &#125;
638
+ getName();
639
+ &#125;,
640
+ name: &#39;Marko Polo&#39;,
641
+ thisIsAnnoying(callback)&#123;
642
+ callback();
643
+ &#125;
644
+ &#125;;
645
+ </code></pre>
646
+ <p>第二种方式是使用箭头函数</p>
647
+ <pre><code> const myFavoriteObj = &#123;
648
+ guessThis()&#123;
649
+ const getName = () =&gt; &#123;
650
+ //copies the value of &quot;this&quot; outside of this arrow function
651
+ console.log(this.name);
652
+ &#125;
653
+ getName();
654
+ &#125;,
655
+ name: &#39;Marko Polo&#39;,
656
+ thisIsAnnoying(callback)&#123;
657
+ callback();
658
+ &#125;
659
+ &#125;;
660
+ </code></pre>
661
+ <p>箭头函数没有自己的 <code>this</code>。它复制了这个封闭的词法作用域中<code>this</code>值,在这个例子中,<code>this</code>值在<code>getName</code>内部函数之外,也就是<code>myFavoriteObj</code>对象。</p>
662
+ <h3 id="25-对象的-prototype-原型-是什么?-25-对象的-prototype-原型-是什么?"><a href="#25-对象的-prototype-原型-是什么?-25-对象的-prototype-原型-是什么?" class="headerlink" title="[25. 对象的 prototype(原型) 是什么?](25. 对象的 prototype(原型) 是什么?)"></a>[25. 对象的 prototype(原型) 是什么?](25. 对象的 prototype(原型) 是什么?)</h3><p>简单地说,原型就是对象的蓝图。如果它存在当前对象中,则将其用作属性和方法的回退。它是在对象之间共享属性和功能的方法,这也是JavaScript实现继承的核心。</p>
663
+ <pre><code>const o = &#123;&#125;;
664
+ console.log(o.toString()); // logs [object Object]
665
+ </code></pre>
666
+ <p>即使<code>o</code>对象中不存在<code>o.toString</code>方法,它也不会引发错误,而是返回字符串<code>[object Object]</code>。 当对象中不存在属性时,它将查看其原型,如果仍然不存在,则将其查找到原型的原型,依此类推,直到在原型链中找到具有相同属性的属性为止。 原型链的末尾是<code>Object.prototype</code>。</p>
667
+ <pre><code>console.log(o.toString === Object.prototype.toString); // logs true
668
+ // which means we we&#39;re looking up the Prototype Chain and it reached
669
+ // the Object.prototype and used the &quot;toString&quot; method.
670
+ </code></pre>
671
+ <h3 id="26-什么是-IIFE,它的用途是什么?-26-什么是-IIFE,它的用途是什么?"><a href="#26-什么是-IIFE,它的用途是什么?-26-什么是-IIFE,它的用途是什么?" class="headerlink" title="[26. 什么是 IIFE,它的用途是什么?](26. 什么是 IIFE,它的用途是什么?)"></a>[26. 什么是 IIFE,它的用途是什么?](26. 什么是 IIFE,它的用途是什么?)</h3><p><strong>IIFE</strong>或立即调用的函数表达式是在创建或声明后将被调用或执行的函数。 创建<strong>IIFE的</strong>语法是,将<code>function ()&#123;&#125;</code>包裹在在括号<code>()</code>内,然后再用另一个括号<code>()</code>调用它,如:<code>(function()&#123;&#125;)()</code></p>
672
+ <pre><code>(function()&#123;
673
+ ...
674
+ &#125; ());
675
+
676
+ (function () &#123;
677
+ ...
678
+ &#125;)();
679
+
680
+ (function named(params) &#123;
681
+ ...
682
+ &#125;)();
683
+
684
+ (() =&gt; &#123;
685
+
686
+ &#125;);
687
+
688
+ (function (global) &#123;
689
+ ...
690
+ &#125;)(window);
691
+
692
+ const utility = (function () &#123;
693
+ return &#123;
694
+ ...
695
+ &#125;
696
+ &#125;)
697
+ </code></pre>
698
+ <p>这些示例都是有效的<strong>IIFE</strong>。 倒数第二个救命表明我们可以将参数传递给<strong>IIFE</strong>函数。 最后一个示例表明,我们可以将<code>IIFE</code>的结果保存到变量中,以便稍后使用。</p>
699
+ <p><strong>IIFE</strong>的一个主要作用是避免与全局作用域内的其他变量命名冲突或污染全局命名空间,来个例子。</p>
700
+ <pre><code>&lt;script src=&quot;https://cdnurl.com/somelibrary.js&quot;&gt;&lt;/script&gt;
701
+ </code></pre>
702
+ <p>假设我们引入了一个<code>omelibr.js</code>的链接,它提供了一些我们在代码中使用的全局函数,但是这个库有两个方法我们没有使用:<code>createGraph</code>和<code>drawGraph</code>,因为这些方法都有<code>bug</code>。我们想实现自己的<code>createGraph</code>和<code>drawGraph</code>方法。</p>
703
+ <p>解决此问题的一种方法是直接覆盖:</p>
704
+ <pre><code>&lt;script src=&quot;https://cdnurl.com/somelibrary.js&quot;&gt;&lt;/script&gt;
705
+ &lt;script&gt;
706
+ function createGraph() &#123;
707
+ // createGraph logic here
708
+ &#125;
709
+ function drawGraph() &#123;
710
+ // drawGraph logic here
711
+ &#125;
712
+ &lt;/script&gt;
713
+ </code></pre>
714
+ <p>当我们使用这个解决方案时,我们覆盖了库提供给我们的那两个方法。</p>
715
+ <p>另一种方式是我们自己改名称:</p>
716
+ <pre><code>&lt;script src=&quot;https://cdnurl.com/somelibrary.js&quot;&gt;&lt;/script&gt;
717
+ &lt;script&gt;
718
+ function myCreateGraph() &#123;
719
+ // createGraph logic here
720
+ &#125;
721
+ function myDrawGraph() &#123;
722
+ // drawGraph logic here
723
+ &#125;
724
+ &lt;/script&gt;
725
+ </code></pre>
726
+ <p>当我们使用这个解决方案时,我们把那些函数调用更改为新的函数名。</p>
727
+ <p>还有一种方法就是使用<strong>IIFE</strong>:</p>
728
+ <pre><code>&lt;script src=&quot;https://cdnurl.com/somelibrary.js&quot;&gt;&lt;/script&gt;
729
+ &lt;script&gt;
730
+ const graphUtility = (function () &#123;
731
+ function createGraph() &#123;
732
+ // createGraph logic here
733
+ &#125;
734
+ function drawGraph() &#123;
735
+ // drawGraph logic here
736
+ &#125;
737
+ return &#123;
738
+ createGraph,
739
+ drawGraph
740
+ &#125;
741
+ &#125;)
742
+ &lt;/script&gt;
743
+ </code></pre>
744
+ <p>在此解决方案中,我们要声明了<code>graphUtility</code> 变量,用来保存<strong>IIFE</strong>执行的结果,该函数返回一个包含两个方法<code>createGraph</code>和<code>drawGraph</code>的对象。</p>
745
+ <p><strong>IIFE</strong> 还可以用来解决一个常见的面试题:</p>
746
+ <pre><code>var li = document.querySelectorAll(&#39;.list-group &gt; li&#39;);
747
+ for (var i = 0, len = li.length; i &lt; len; i++) &#123;
748
+ li[i].addEventListener(&#39;click&#39;, function (e) &#123;
749
+ console.log(i);
750
+ &#125;)
751
+ </code></pre>
752
+ <p>假设我们有一个带有<code>list-group</code>类的<code>ul</code>元素,它有<code>5</code>个<code>li</code>子元素。 当我们单击单个<code>li</code>元素时,打印对应的下标值。但在此外上述代码不起作用,这里每次点击 <code>li</code> 打印 <code>i</code> 的值都是<code>5</code>,这是由于闭包的原因。</p>
753
+ <p><strong>闭包</strong>只是函数记住其当前作用域,父函数作用域和全局作用域的变量引用的能力。 当我们在全局作用域内使用<code>var</code>关键字声明变量时,就创建全局变量<code>i</code>。 因此,当我们单击<code>li</code>元素时,它将打印<code>5</code>,因为这是稍后在回调函数中引用它时<code>i</code>的值。</p>
754
+ <p>使用 <strong>IIFE</strong> 可以解决此问题:</p>
755
+ <pre><code>var li = document.querySelectorAll(&#39;.list-group &gt; li&#39;);
756
+ for (var i = 0, len = li.length; i &lt; len; i++) &#123;
757
+ (function (currentIndex) &#123;
758
+ li[currentIndex].addEventListener(&#39;click&#39;, function (e) &#123;
759
+ console.log(currentIndex);
760
+ &#125;)
761
+ &#125;)(i);
762
+ &#125;
763
+ </code></pre>
764
+ <p>该解决方案之所以行的通,是因为<strong>IIFE</strong>会为每次迭代创建一个新的作用域,我们捕获<code>i</code>的值并将其传递给<code>currentIndex</code>参数,因此调用<strong>IIFE</strong>时,每次迭代的<code>currentIndex</code>值都是不同的。</p>
765
+ <h3 id="27-Function-prototype-apply-方法的用途是什么?-27-Function-prototype-apply-方法的用途是什么?"><a href="#27-Function-prototype-apply-方法的用途是什么?-27-Function-prototype-apply-方法的用途是什么?" class="headerlink" title="[27. Function.prototype.apply 方法的用途是什么?](27. Function.prototype.apply 方法的用途是什么?)"></a>[27. Function.prototype.apply 方法的用途是什么?](27. Function.prototype.apply 方法的用途是什么?)</h3><p><code>apply()</code> 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。</p>
766
+ <pre><code>const details = &#123;
767
+ message: &#39;Hello World!&#39;
768
+ &#125;;
769
+
770
+ function getMessage()&#123;
771
+ return this.message;
772
+ &#125;
773
+
774
+ getMessage.apply(details); // &#39;Hello World!&#39;
775
+ </code></pre>
776
+ <blockquote>
777
+ <p><code>call()</code>方法的作用和 <code>apply()</code> 方法类似,区别就是<code>call()</code>方法接受的是参数列表,而<code>apply()</code>方法接受的是一个参数数组。</p>
778
+ </blockquote>
779
+ <pre><code>const person = &#123;
780
+ name: &quot;Marko Polo&quot;
781
+ &#125;;
782
+
783
+ function greeting(greetingMessage) &#123;
784
+ return `$&#123;greetingMessage&#125; $&#123;this.name&#125;`;
785
+ &#125;
786
+
787
+ greeting.apply(person, [&#39;Hello&#39;]); // &quot;Hello Marko Polo!&quot;
788
+ </code></pre>
789
+ <h3 id="28-Function-prototype-call-方法的用途是什么?-28-Function-prototype-call-方法的用途是什么?"><a href="#28-Function-prototype-call-方法的用途是什么?-28-Function-prototype-call-方法的用途是什么?" class="headerlink" title="[28. Function.prototype.call 方法的用途是什么?](28. Function.prototype.call 方法的用途是什么?)"></a>[28. <code>Function.prototype.call</code> 方法的用途是什么?](28. <code>Function.prototype.call</code> 方法的用途是什么?)</h3><p><code>call()</code> 方法使用一个指定的 <code>this</code> 值和单独给出的一个或多个参数来调用一个函数。</p>
790
+ <pre><code>const details = &#123;
791
+ message: &#39;Hello World!&#39;
792
+ &#125;;
793
+
794
+ function getMessage()&#123;
795
+ return this.message;
796
+ &#125;
797
+
798
+ getMessage.call(details); // &#39;Hello World!&#39;
799
+ </code></pre>
800
+ <p>注意:该方法的语法和作用与 <code>apply()</code> 方法类似,只有一个区别,就是 <code>call()</code> 方法接受的是一个参数列表,而 <code>apply()</code> 方法接受的是一个包含多个参数的数组。</p>
801
+ <pre><code>const person = &#123;
802
+ name: &quot;Marko Polo&quot;
803
+ &#125;;
804
+
805
+ function greeting(greetingMessage) &#123;
806
+ return `$&#123;greetingMessage&#125; $&#123;this.name&#125;`;
807
+ &#125;
808
+
809
+ greeting.call(person, &#39;Hello&#39;); // &quot;Hello Marko Polo!&quot;
810
+ </code></pre>
811
+ <h3 id="29-Function-prototype-apply-和-Function-prototype-call-之间有什么区别?-29-Function-prototype-apply-和-Function-prototype-call-之间有什么区别?"><a href="#29-Function-prototype-apply-和-Function-prototype-call-之间有什么区别?-29-Function-prototype-apply-和-Function-prototype-call-之间有什么区别?" class="headerlink" title="[29. Function.prototype.apply 和 Function.prototype.call 之间有什么区别?](29. Function.prototype.apply 和 Function.prototype.call 之间有什么区别?)"></a>[29. Function.prototype.apply 和 Function.prototype.call 之间有什么区别?](29. Function.prototype.apply 和 Function.prototype.call 之间有什么区别?)</h3><p><code>apply()</code>方法可以在使用一个指定的 <code>this</code> 值和一个参数数组(或类数组对象)的前提下调用某个函数或方法。<code>call()</code>方法类似于<code>apply()</code>,不同之处仅仅是<code>call()</code>接受的参数是参数列表。</p>
812
+ <pre><code>const obj1 = &#123;
813
+ result:0
814
+ &#125;;
815
+
816
+ const obj2 = &#123;
817
+ result:0
818
+ &#125;;
819
+
820
+ function reduceAdd()&#123;
821
+ let result = 0;
822
+ for(let i = 0, len = arguments.length; i &lt; len; i++)&#123;
823
+ result += arguments[i];
824
+ &#125;
825
+ this.result = result;
826
+ &#125;
827
+
828
+ reduceAdd.apply(obj1, [1, 2, 3, 4, 5]); // 15
829
+ reduceAdd.call(obj2, 1, 2, 3, 4, 5); // 15
830
+ </code></pre>
831
+ <h3 id="30-Function-prototype-bind-的用途是什么?-30-Function-prototype-bind-的用途是什么?"><a href="#30-Function-prototype-bind-的用途是什么?-30-Function-prototype-bind-的用途是什么?" class="headerlink" title="[30. Function.prototype.bind 的用途是什么?](30. Function.prototype.bind 的用途是什么?)"></a>[30. Function.prototype.bind 的用途是什么?](30. Function.prototype.bind 的用途是什么?)</h3><p><code>bind()</code> 方法创建一个新的函数,在 <code>bind()</code> 被调用时,这个新函数的 <code>this</code> 被指定为 <code>bind()</code> 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。</p>
832
+ <pre><code>import React from &#39;react&#39;;
833
+
834
+ class MyComponent extends React.Component &#123;
835
+ constructor(props)&#123;
836
+ super(props);
837
+ this.state = &#123;
838
+ value : &quot;&quot;
839
+ &#125;
840
+ this.handleChange = this.handleChange.bind(this);
841
+ // 将 “handleChange” 方法绑定到 “MyComponent” 组件
842
+ &#125;
843
+
844
+ handleChange(e)&#123;
845
+ //do something amazing here
846
+ &#125;
847
+
848
+ render()&#123;
849
+ return (
850
+ &lt;&gt;
851
+ &lt;input type=&#123;this.props.type&#125;
852
+ value=&#123;this.state.value&#125;
853
+ onChange=&#123;this.handleChange&#125;
854
+ /&gt;
855
+ &lt;/&gt;
856
+ )
857
+ &#125;
858
+ &#125;
859
+ </code></pre>
860
+ <h3 id="31-什么是函数式编程-JavaScript-的哪些特性使其成为函数式语言的候选语言?-31-什么是函数式编程-JavaScript-的哪些特性使其成为函数式语言的候选语言?"><a href="#31-什么是函数式编程-JavaScript-的哪些特性使其成为函数式语言的候选语言?-31-什么是函数式编程-JavaScript-的哪些特性使其成为函数式语言的候选语言?" class="headerlink" title="[31. 什么是函数式编程? JavaScript 的哪些特性使其成为函数式语言的候选语言?](31. 什么是函数式编程? JavaScript 的哪些特性使其成为函数式语言的候选语言?)"></a>[31. 什么是函数式编程? JavaScript 的哪些特性使其成为函数式语言的候选语言?](31. 什么是函数式编程? JavaScript 的哪些特性使其成为函数式语言的候选语言?)</h3><p>函数式编程(通常缩写为FP)是通过编写纯函数,避免共享状态、可变数据、副作用 来构建软件的过程。数式编程是声明式 的而不是命令式 的,应用程序的状态是通过纯函数流动的。与面向对象编程形成对比,面向对象中应用程序的状态通常与对象中的方法共享和共处。</p>
861
+ <p>函数式编程是一种编程范式 ,这意味着它是一种基于一些基本的定义原则(如上所列)思考软件构建的方式。当然,编程范示的其他示例也包括面向对象编程和过程编程。</p>
862
+ <p>函数式的代码往往比命令式或面向对象的代码更简洁,更可预测,更容易测试 - 但如果不熟悉它以及与之相关的常见模式,函数式的代码也可能看起来更密集杂乱,并且 相关文献对新人来说是不好理解的。</p>
863
+ <p><strong>JavaScript支持闭包和高阶函数是函数式编程语言的特点。</strong></p>
864
+ <h3 id="32-什么是高阶函数?-32-什么是高阶函数?"><a href="#32-什么是高阶函数?-32-什么是高阶函数?" class="headerlink" title="[32. 什么是高阶函数?](32. 什么是高阶函数?)"></a>[32. 什么是高阶函数?](32. 什么是高阶函数?)</h3><p><strong>高阶函数只是将函数作为参数或返回值的函数。</strong></p>
865
+ <pre><code>function higherOrderFunction(param,callback)&#123;
866
+ return callback(param);
867
+ &#125;
868
+ </code></pre>
869
+ <h3 id="33-为什么函数被称为一等公民?-33-为什么函数被称为一等公民?"><a href="#33-为什么函数被称为一等公民?-33-为什么函数被称为一等公民?" class="headerlink" title="[33. 为什么函数被称为一等公民?](33. 为什么函数被称为一等公民?)"></a>[33. 为什么函数被称为一等公民?](33. 为什么函数被称为一等公民?)</h3><p>在JavaScript中,函数不仅拥有一切传统函数的使用方式(声明和调用),而且可以做到像简单值一样赋值<code>(var func = function()&#123;&#125;)</code>、传参<code>(function func(x,callback)&#123;callback();&#125;)</code>、返回<code>(function()&#123;return function()&#123;&#125; &#125;)</code>,这样的函数也称之为<strong>第一级函数(First-class Function)</strong>。不仅如此,JavaScript中的函数还充当了类的构造函数的作用,同时又是一个<code>Function</code>类的实例(instance)。这样的多重身份让JavaScript的函数变得非常重要。</p>
870
+ <h3 id="34-手动实现-Array-prototype-map-方法-34-手动实现-Array-prototype-map-方法"><a href="#34-手动实现-Array-prototype-map-方法-34-手动实现-Array-prototype-map-方法" class="headerlink" title="[34. 手动实现 Array.prototype.map 方法](34. 手动实现 Array.prototype.map 方法)"></a>[34. 手动实现 <code>Array.prototype.map 方法</code>](34. 手动实现 <code>Array.prototype.map 方法</code>)</h3><p><code>map()</code> 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。</p>
871
+ <pre><code>function map(arr, mapCallback) &#123;
872
+ // 首先,检查传递的参数是否正确。
873
+ if (!Array.isArray(arr) || !arr.length || typeof mapCallback !== &#39;function&#39;) &#123;
874
+ return [];
875
+ &#125; else &#123;
876
+ let result = [];
877
+ // 每次调用此函数时,我们都会创建一个 result 数组
878
+ // 因为我们不想改变原始数组。
879
+ for (let i = 0, len = arr.length; i &lt; len; i++) &#123;
880
+ result.push(mapCallback(arr[i], i, arr));
881
+ // 将 mapCallback 返回的结果 push 到 result 数组中
882
+ &#125;
883
+ return result;
884
+ &#125;
885
+ &#125;
886
+ </code></pre>
887
+ <h3 id="35-手动实现Array-prototype-filter方法-35-手动实现Array-prototype-filter方法"><a href="#35-手动实现Array-prototype-filter方法-35-手动实现Array-prototype-filter方法" class="headerlink" title="[35. 手动实现Array.prototype.filter方法](35. 手动实现Array.prototype.filter方法)"></a>[35. 手动实现<code>Array.prototype.filter</code>方法](35. 手动实现<code>Array.prototype.filter</code>方法)</h3><p><code>filter()</code> 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。</p>
888
+ <pre><code>function filter(arr, filterCallback) &#123;
889
+ // 首先,检查传递的参数是否正确。
890
+ if (!Array.isArray(arr) || !arr.length || typeof filterCallback !== &#39;function&#39;)
891
+ &#123;
892
+ return [];
893
+ &#125; else &#123;
894
+ let result = [];
895
+ // 每次调用此函数时,我们都会创建一个 result 数组
896
+ // 因为我们不想改变原始数组。
897
+ for (let i = 0, len = arr.length; i &lt; len; i++) &#123;
898
+ // 检查 filterCallback 的返回值是否是真值
899
+ if (filterCallback(arr[i], i, arr)) &#123;
900
+ // 如果条件为真,则将数组元素 push 到 result 中
901
+ result.push(arr[i]);
902
+ &#125;
903
+ &#125;
904
+ return result; // return the result array
905
+ &#125;
906
+ &#125;
907
+ </code></pre>
908
+ <h3 id="36-手动实现Array-prototype-reduce方法-36-手动实现Array-prototype-reduce方法"><a href="#36-手动实现Array-prototype-reduce方法-36-手动实现Array-prototype-reduce方法" class="headerlink" title="[36. 手动实现Array.prototype.reduce方法](36. 手动实现Array.prototype.reduce方法)"></a>[36. 手动实现<code>Array.prototype.reduce</code>方法](36. 手动实现<code>Array.prototype.reduce</code>方法)</h3><p><code>reduce()</code> 方法对数组中的每个元素执行一个由您提供的<code>reducer</code>函数(升序执行),将其结果汇总为单个返回值。</p>
909
+ <pre><code>function reduce(arr, reduceCallback, initialValue) &#123;
910
+ // 首先,检查传递的参数是否正确。
911
+ if (!Array.isArray(arr) || !arr.length || typeof reduceCallback !== &#39;function&#39;)
912
+ &#123;
913
+ return [];
914
+ &#125; else &#123;
915
+ // 如果没有将initialValue传递给该函数,我们将使用第一个数组项作为initialValue
916
+ let hasInitialValue = initialValue !== undefined;
917
+ let value = hasInitialValue ? initialValue : arr[0];
918
+
919
+
920
+ // 如果有传递 initialValue,则索引从 1 开始,否则从 0 开始
921
+ for (let i = hasInitialValue ? 0 : 1, len = arr.length; i &lt; len; i++) &#123;
922
+ value = reduceCallback(value, arr[i], i, arr);
923
+ &#125;
924
+ return value;
925
+ &#125;
926
+ &#125;
927
+ </code></pre>
928
+ <h3 id="37-arguments-的对象是什么?-37-arguments-的对象是什么?"><a href="#37-arguments-的对象是什么?-37-arguments-的对象是什么?" class="headerlink" title="[37. arguments 的对象是什么?](37. arguments 的对象是什么?)"></a>[37. arguments 的对象是什么?](37. arguments 的对象是什么?)</h3><p><code>arguments</code>对象是函数中传递的参数值的集合。它是一个类似数组的对象,因为它有一个length属性,我们可以使用数组索引表示法<code>arguments[1]</code>来访问单个值,但它没有数组中的内置方法,如:<code>forEach</code>、<code>reduce</code>、<code>filter</code>和<code>map</code>。</p>
929
+ <p>我们可以使用<code>Array.prototype.slice</code>将<code>arguments</code>对象转换成一个数组。</p>
930
+ <pre><code>function one() &#123;
931
+ return Array.prototype.slice.call(arguments);
932
+ &#125;
933
+ </code></pre>
934
+ <p><strong>注意:箭头函数中没有<code>arguments</code>对象。</strong></p>
935
+ <pre><code>function one() &#123;
936
+ return arguments;
937
+ &#125;
938
+ const two = function () &#123;
939
+ return arguments;
940
+ &#125;
941
+ const three = function three() &#123;
942
+ return arguments;
943
+ &#125;
944
+
945
+ const four = () =&gt; arguments;
946
+
947
+ four(); // Throws an error - arguments is not defined
948
+ </code></pre>
949
+ <p>当我们调用函数<code>four</code>时,它会抛出一个<code>ReferenceError: arguments is not defined error</code>。使用<code>rest</code>语法,可以解决这个问题。</p>
950
+ <pre><code>const four = (...args) =&gt; args;
951
+ </code></pre>
952
+ <p>这会自动将所有参数值放入数组中。</p>
953
+ <h3 id="38-如何创建一个没有-prototype-原型-的对象?-38-如何创建一个没有-prototype-原型-的对象?"><a href="#38-如何创建一个没有-prototype-原型-的对象?-38-如何创建一个没有-prototype-原型-的对象?" class="headerlink" title="[38. 如何创建一个没有 prototype(原型)的对象?](38. 如何创建一个没有 prototype(原型)的对象?)"></a>[38. 如何创建一个没有 prototype(原型)的对象?](38. 如何创建一个没有 prototype(原型)的对象?)</h3><p>我们可以使用<code>Object.create</code>方法创建没有原型的对象。</p>
954
+ <pre><code>const o1 = &#123;&#125;;
955
+ console.log(o1.toString()); // [object Object]
956
+
957
+ const o2 = Object.create(null);
958
+ console.log(o2.toString());
959
+ // throws an error o2.toString is not a function
960
+ </code></pre>
961
+ <h3 id="39-为什么在调用这个函数时,代码中的b会变成一个全局变量-39-为什么在调用这个函数时,代码中的b会变成一个全局变量"><a href="#39-为什么在调用这个函数时,代码中的b会变成一个全局变量-39-为什么在调用这个函数时,代码中的b会变成一个全局变量" class="headerlink" title="[39. 为什么在调用这个函数时,代码中的b会变成一个全局变量?](39. 为什么在调用这个函数时,代码中的b会变成一个全局变量?)"></a>[39. 为什么在调用这个函数时,代码中的<code>b</code>会变成一个全局变量?](39. 为什么在调用这个函数时,代码中的<code>b</code>会变成一个全局变量?)</h3><pre><code>function myFunc() &#123;
962
+ let a = b = 0;
963
+ &#125;
964
+
965
+ myFunc();
966
+ </code></pre>
967
+ <p>原因是赋值运算符是从右到左的求值的。这意味着当多个赋值运算符出现在一个表达式中时,它们是从右向左求值的。所以上面代码变成了这样:</p>
968
+ <pre><code>function myFunc() &#123;
969
+ let a = (b = 0);
970
+ &#125;
971
+
972
+ myFunc();
973
+ </code></pre>
974
+ <p>首先,表达式<code>b = 0</code>求值,在本例中<code>b</code>没有声明。因此,JS引擎在这个函数外创建了一个全局变量<code>b</code>,之后表达式<code>b = 0</code>的返回值为<code>0</code>,并赋给新的局部变量<code>a</code>。</p>
975
+ <p>我们可以通过在赋值之前先声明变量来解决这个问题。</p>
976
+ <pre><code>function myFunc() &#123;
977
+ let a,b;
978
+ a = b = 0;
979
+ &#125;
980
+ myFunc();
981
+ </code></pre>
982
+ <h3 id="40-ECMAScript-是什么?-40-ECMAScript-是什么?"><a href="#40-ECMAScript-是什么?-40-ECMAScript-是什么?" class="headerlink" title="[40. ECMAScript 是什么?](40. ECMAScript 是什么?)"></a>[40. ECMAScript 是什么?](40. ECMAScript 是什么?)</h3><p>ECMAScript 是编写脚本语言的标准,这意味着JavaScript遵循ECMAScript标准中的规范变化,因为它是JavaScript的蓝图。</p>
983
+ <p>ECMAScript 和 Javascript,本质上都跟一门语言有关,一个是语言本身的名字,一个是语言的约束条件<br>只不过发明JavaScript的那个人(Netscape公司),把东西交给了ECMA(European Computer Manufacturers Association),这个人规定一下他的标准,因为当时有java语言了,又想强调这个东西是让ECMA这个人定的规则,所以就这样一个神奇的东西诞生了,这个东西的名称就叫做ECMAScript。</p>
984
+ <p>javaScript &#x3D; ECMAScript + DOM + BOM(自认为是一种广义的JavaScript)</p>
985
+ <p>ECMAScript说什么JavaScript就得做什么!</p>
986
+ <p>JavaScript(狭义的JavaScript)做什么都要问问ECMAScript我能不能这样干!如果不能我就错了!能我就是对的!</p>
987
+ <p>——突然感觉JavaScript好没有尊严,为啥要搞个人出来约束自己,</p>
988
+ <p>那个人被创造出来也好委屈,自己被创造出来完全是因为要约束JavaScript。</p>
989
+ <h3 id="41-ES6或ECMAScript-2015有哪些新特性?-41-ES6或ECMAScript-2015有哪些新特性?"><a href="#41-ES6或ECMAScript-2015有哪些新特性?-41-ES6或ECMAScript-2015有哪些新特性?" class="headerlink" title="[41. ES6或ECMAScript 2015有哪些新特性?](41. ES6或ECMAScript 2015有哪些新特性?)"></a>[41. ES6或ECMAScript 2015有哪些新特性?](41. ES6或ECMAScript 2015有哪些新特性?)</h3><ul>
990
+ <li>箭头函数</li>
991
+ <li>类</li>
992
+ <li>模板字符串</li>
993
+ <li>加强的对象字面量</li>
994
+ <li>对象解构</li>
995
+ <li>Promise</li>
996
+ <li>生成器</li>
997
+ <li>模块</li>
998
+ <li>Symbol</li>
999
+ <li>代理</li>
1000
+ <li>Set</li>
1001
+ <li>函数默认参数</li>
1002
+ <li>rest 和展开</li>
1003
+ <li>块作用域</li>
1004
+ </ul>
1005
+ <h3 id="42-var-let和const的区别是什么?-42-var-let和const的区别是什么?"><a href="#42-var-let和const的区别是什么?-42-var-let和const的区别是什么?" class="headerlink" title="[42. var,let和const的区别是什么?](42. var,let和const的区别是什么?)"></a>[42. <code>var</code>,<code>let</code>和<code>const</code>的区别是什么?](42. <code>var</code>,<code>let</code>和<code>const</code>的区别是什么?)</h3><p><strong><code>var</code>声明的变量会挂载在<code>window</code>上,而<code>let</code>和<code>const</code>声明的变量不会:</strong></p>
1006
+ <pre><code>var a = 100;
1007
+ console.log(a,window.a); // 100 100
1008
+
1009
+ let b = 10;
1010
+ console.log(b,window.b); // 10 undefined
1011
+
1012
+ const c = 1;
1013
+ console.log(c,window.c); // 1 undefined
1014
+ </code></pre>
1015
+ <p><strong><code>var</code>声明变量存在变量提升,<code>let</code>和<code>const</code>不存在变量提升:</strong></p>
1016
+ <pre><code>console.log(a); // undefined ===&gt; a已声明还没赋值,默认得到undefined值
1017
+ var a = 100;
1018
+
1019
+ console.log(b); // 报错:b is not defined ===&gt; 找不到b这个变量
1020
+ let b = 10;
1021
+
1022
+ console.log(c); // 报错:c is not defined ===&gt; 找不到c这个变量
1023
+ const c = 10;
1024
+ </code></pre>
1025
+ <p><strong><code>let</code>和<code>const</code>声明形成块作用域</strong></p>
1026
+ <pre><code>if(1)&#123;
1027
+ var a = 100;
1028
+ let b = 10;
1029
+ &#125;
1030
+
1031
+ console.log(a); // 100
1032
+ console.log(b) // 报错:b is not defined ===&gt; 找不到b这个变量
1033
+
1034
+ -------------------------------------------------------------
1035
+
1036
+ if(1)&#123;
1037
+ var a = 100;
1038
+ const c = 1;
1039
+ &#125;
1040
+ console.log(a); // 100
1041
+ console.log(c) // 报错:c is not defined ===&gt; 找不到c这个变量
1042
+ </code></pre>
1043
+ <p><strong>同一作用域下<code>let</code>和<code>const</code>不能声明同名变量,而<code>var</code>可以</strong></p>
1044
+ <pre><code>var a = 100;
1045
+ console.log(a); // 100
1046
+
1047
+ var a = 10;
1048
+ console.log(a); // 10
1049
+ -------------------------------------
1050
+ let a = 100;
1051
+ let a = 10;
1052
+
1053
+ // 控制台报错:Identifier &#39;a&#39; has already been declared ===&gt; 标识符a已经被声明了。
1054
+ </code></pre>
1055
+ <p><strong>暂存死区</strong></p>
1056
+ <pre><code>var a = 100;
1057
+
1058
+ if(1)&#123;
1059
+ a = 10;
1060
+ //在当前块作用域中存在a使用let/const声明的情况下,给a赋值10时,只会在当前作用域找变量a,
1061
+ // 而这时,还未到声明时候,所以控制台Error:a is not defined
1062
+ let a = 1;
1063
+ &#125;
1064
+ </code></pre>
1065
+ <p><strong>const</strong></p>
1066
+ <pre><code>/*
1067
+ *   1、一旦声明必须赋值,不能使用null占位。
1068
+ *
1069
+ *   2、声明后不能再修改
1070
+ *
1071
+ *   3、如果声明的是复合类型数据,可以修改其属性
1072
+ *
1073
+ * */
1074
+
1075
+ const a = 100;
1076
+
1077
+ const list = [];
1078
+ list[0] = 10;
1079
+ console.log(list);  // [10]
1080
+
1081
+ const obj = &#123;a:100&#125;;
1082
+ obj.name = &#39;apple&#39;;
1083
+ obj.a = 10000;
1084
+ console.log(obj);  // &#123;a:10000,name:&#39;apple&#39;&#125;
1085
+ </code></pre>
1086
+ <h3 id="43-什么是箭头函数?-43-什么是箭头函数?"><a href="#43-什么是箭头函数?-43-什么是箭头函数?" class="headerlink" title="[43. 什么是箭头函数?](43. 什么是箭头函数?)"></a>[43. 什么是箭头函数?](43. 什么是箭头函数?)</h3><p>箭头函数表达式的语法比函数表达式更简洁,并且没有自己的<code>this</code>,<code>arguments</code>,<code>super</code>或<code>new.target</code>。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数。</p>
1087
+ <pre><code>//ES5 Version
1088
+ var getCurrentDate = function ()&#123;
1089
+ return new Date();
1090
+ &#125;
1091
+
1092
+ //ES6 Version
1093
+ const getCurrentDate = () =&gt; new Date();
1094
+ </code></pre>
1095
+ <p>在本例中,ES5 版本中有<code>function()&#123;&#125;</code>声明和<code>return</code>关键字,这两个关键字分别是创建函数和返回值所需要的。在箭头函数版本中,我们只需要<code>()</code>括号,不需要 <code>return</code> 语句,因为如果我们只有一个表达式或值需要返回,箭头函数就会有一个隐式的返回。</p>
1096
+ <pre><code>//ES5 Version
1097
+ function greet(name) &#123;
1098
+ return &#39;Hello &#39; + name + &#39;!&#39;;
1099
+ &#125;
1100
+
1101
+ //ES6 Version
1102
+ const greet = (name) =&gt; `Hello $&#123;name&#125;`;
1103
+ const greet2 = name =&gt; `Hello $&#123;name&#125;`;
1104
+ </code></pre>
1105
+ <p>我们还可以在箭头函数中使用与函数表达式和函数声明相同的参数。如果我们在一个箭头函数中有一个参数,则可以省略括号。</p>
1106
+ <pre><code>const getArgs = () =&gt; arguments
1107
+
1108
+ const getArgs2 = (...rest) =&gt; rest
1109
+ </code></pre>
1110
+ <p>箭头函数不能访问<code>arguments</code>对象。所以调用第一个<code>getArgs</code>函数会抛出一个错误。相反,我们可以使用<strong>rest</strong>参数来获得在箭头函数中传递的所有参数。</p>
1111
+ <pre><code>const data = &#123;
1112
+ result: 0,
1113
+ nums: [1, 2, 3, 4, 5],
1114
+ computeResult() &#123;
1115
+ // 这里的“this”指的是“data”对象
1116
+ const addAll = () =&gt; &#123;
1117
+ return this.nums.reduce((total, cur) =&gt; total + cur, 0)
1118
+ &#125;;
1119
+ this.result = addAll();
1120
+ &#125;
1121
+ &#125;;
1122
+ </code></pre>
1123
+ <p>箭头函数没有自己的<code>this</code>值。 它捕获词法作用域函数的<code>this</code>值,在此示例中,<code>addAll</code>函数将复制<code>computeResult</code> 方法中的<code>this</code>值,如果我们在全局作用域声明箭头函数,则<code>this</code>值为 <code>window</code> 对象。</p>
1124
+ <h3 id="44-什么是类?-44-什么是类?"><a href="#44-什么是类?-44-什么是类?" class="headerlink" title="[44. 什么是类?](44. 什么是类?)"></a>[44. 什么是类?](44. 什么是类?)</h3><p><code>类(class)</code>是在 JS 中编写构造函数的新方法。它是使用构造函数的语法糖,在底层中使用仍然是原型和基于原型的继承。</p>
1125
+ <pre><code> //ES5 Version
1126
+ function Person(firstName, lastName, age, address)&#123;
1127
+ this.firstName = firstName;
1128
+ this.lastName = lastName;
1129
+ this.age = age;
1130
+ this.address = address;
1131
+ &#125;
1132
+
1133
+ Person.self = function()&#123;
1134
+ return this;
1135
+ &#125;
1136
+
1137
+ Person.prototype.toString = function()&#123;
1138
+ return &quot;[object Person]&quot;;
1139
+ &#125;
1140
+
1141
+ Person.prototype.getFullName = function ()&#123;
1142
+ return this.firstName + &quot; &quot; + this.lastName;
1143
+ &#125;
1144
+
1145
+ //ES6 Version
1146
+ class Person &#123;
1147
+ constructor(firstName, lastName, age, address)&#123;
1148
+ this.lastName = lastName;
1149
+ this.firstName = firstName;
1150
+ this.age = age;
1151
+ this.address = address;
1152
+ &#125;
1153
+
1154
+ static self() &#123;
1155
+ return this;
1156
+ &#125;
1157
+
1158
+ toString()&#123;
1159
+ return &quot;[object Person]&quot;;
1160
+ &#125;
1161
+
1162
+ getFullName()&#123;
1163
+ return `$&#123;this.firstName&#125; $&#123;this.lastName&#125;`;
1164
+ &#125;
1165
+ &#125;
1166
+ </code></pre>
1167
+ <p>重写方法并从另一个类继承。</p>
1168
+ <pre><code>//ES5 Version
1169
+ Employee.prototype = Object.create(Person.prototype);
1170
+
1171
+ function Employee(firstName, lastName, age, address, jobTitle, yearStarted) &#123;
1172
+ Person.call(this, firstName, lastName, age, address);
1173
+ this.jobTitle = jobTitle;
1174
+ this.yearStarted = yearStarted;
1175
+ &#125;
1176
+
1177
+ Employee.prototype.describe = function () &#123;
1178
+ return `I am $&#123;this.getFullName()&#125; and I have a position of $&#123;this.jobTitle&#125;
1179
+ and I started at $&#123;this.yearStarted&#125;`;
1180
+ &#125;
1181
+
1182
+ Employee.prototype.toString = function () &#123;
1183
+ return &quot;[object Employee]&quot;;
1184
+ &#125;
1185
+
1186
+ //ES6 Version
1187
+ class Employee extends Person &#123; //Inherits from &quot;Person&quot; class
1188
+ constructor(firstName, lastName, age, address, jobTitle, yearStarted) &#123;
1189
+ super(firstName, lastName, age, address);
1190
+ this.jobTitle = jobTitle;
1191
+ this.yearStarted = yearStarted;
1192
+ &#125;
1193
+
1194
+ describe() &#123;
1195
+ return `I am $&#123;this.getFullName()&#125; and I have a position of $&#123;this.jobTitle&#125;
1196
+ and I started at $&#123;this.yearStarted&#125;`;
1197
+ &#125;
1198
+
1199
+ toString() &#123; // Overriding the &quot;toString&quot; method of &quot;Person&quot;
1200
+ return &quot;[object Employee]&quot;;
1201
+ &#125;
1202
+ &#125;
1203
+ </code></pre>
1204
+ <p><strong>所以我们要怎么知道它在内部使用原型?</strong></p>
1205
+ <pre><code>class Something &#123;
1206
+
1207
+ &#125;
1208
+
1209
+ function AnotherSomething()&#123;
1210
+
1211
+ &#125;
1212
+ const as = new AnotherSomething();
1213
+ const s = new Something();
1214
+
1215
+ console.log(typeof Something); // &quot;function&quot;
1216
+ console.log(typeof AnotherSomething); // &quot;function&quot;
1217
+ console.log(as.toString()); // &quot;[object Object]&quot;
1218
+ console.log(as.toString()); // &quot;[object Object]&quot;
1219
+ console.log(as.toString === Object.prototype.toString); // true
1220
+ console.log(s.toString === Object.prototype.toString); // true
1221
+ </code></pre>
1222
+ <h3 id="45-什么是模板字符串?-45-什么是模板字符串?"><a href="#45-什么是模板字符串?-45-什么是模板字符串?" class="headerlink" title="[45. 什么是模板字符串?](45. 什么是模板字符串?)"></a>[45. 什么是模板字符串?](45. 什么是模板字符串?)</h3><p>模板字符串是在 JS 中创建字符串的一种新方法。我们可以通过使用反引号使模板字符串化。</p>
1223
+ <pre><code>//ES5 Version
1224
+ var greet = &#39;Hi I\&#39;m Mark&#39;;
1225
+
1226
+ //ES6 Version
1227
+ let greet = `Hi I&#39;m Mark`;
1228
+ </code></pre>
1229
+ <p>在 ES5 中我们需要使用一些转义字符来达到多行的效果,在模板字符串不需要这么麻烦:</p>
1230
+ <pre><code>//ES5 Version
1231
+ var lastWords = &#39;\n&#39;
1232
+ + &#39; I \n&#39;
1233
+ + &#39; Am \n&#39;
1234
+ + &#39;Iron Man \n&#39;;
1235
+
1236
+
1237
+ //ES6 Version
1238
+ let lastWords = `
1239
+ I
1240
+ Am
1241
+ Iron Man
1242
+ `;
1243
+ </code></pre>
1244
+ <p>在ES5版本中,我们需要添加<code>\n</code>以在字符串中添加新行。 在模板字符串中,我们不需要这样做。</p>
1245
+ <pre><code>//ES5 Version
1246
+ function greet(name) &#123;
1247
+ return &#39;Hello &#39; + name + &#39;!&#39;;
1248
+ &#125;
1249
+
1250
+
1251
+ //ES6 Version
1252
+ function greet(name) &#123;
1253
+ return `Hello $&#123;name&#125; !`;
1254
+ &#125;
1255
+ </code></pre>
1256
+ <p>在 ES5 版本中,如果需要在字符串中添加表达式或值,则需要使用<code>+</code>运算符。 在模板字符串s中,我们可以使用<code>$&#123;expr&#125;</code>嵌入一个表达式,这使其比 ES5 版本更整洁。</p>
1257
+ <h3 id="46-什么是对象解构?-46-什么是对象解构?"><a href="#46-什么是对象解构?-46-什么是对象解构?" class="headerlink" title="[46. 什么是对象解构?](46. 什么是对象解构?)"></a>[46. 什么是对象解构?](46. 什么是对象解构?)</h3><p><strong>对象析构</strong>是从对象或数组中获取或提取值的一种新的、更简洁的方法。假设有如下的对象:</p>
1258
+ <pre><code>const employee = &#123;
1259
+ firstName: &quot;Marko&quot;,
1260
+ lastName: &quot;Polo&quot;,
1261
+ position: &quot;Software Developer&quot;,
1262
+ yearHired: 2017
1263
+ &#125;;
1264
+ </code></pre>
1265
+ <p>从对象获取属性,早期方法是创建一个与对象属性同名的变量。这种方法很麻烦,因为我们要为每个属性创建一个新变量。假设我们有一个大对象,它有很多属性和方法,用这种方法提取属性会很麻烦。</p>
1266
+ <pre><code>var firstName = employee.firstName;
1267
+ var lastName = employee.lastName;
1268
+ var position = employee.position;
1269
+ var yearHired = employee.yearHired;
1270
+ </code></pre>
1271
+ <p>使用解构方式语法就变得简洁多了:</p>
1272
+ <pre><code>&#123; firstName, lastName, position, yearHired &#125; = employee;
1273
+ </code></pre>
1274
+ <p>我们还可以为属性取别名:</p>
1275
+ <pre><code>let &#123; firstName: fName, lastName: lName, position, yearHired &#125; = employee;
1276
+ </code></pre>
1277
+ <p>当然如果属性值为 <code>undefined</code> 时,我们还可以指定默认值:</p>
1278
+ <pre><code>let &#123; firstName = &quot;Mark&quot;, lastName: lName, position, yearHired &#125; = employee;
1279
+ </code></pre>
1280
+ <h3 id="47-什么是-ES6-模块?-47-什么是-ES6-模块?"><a href="#47-什么是-ES6-模块?-47-什么是-ES6-模块?" class="headerlink" title="[47. 什么是 ES6 模块?](47. 什么是 ES6 模块?)"></a>[47. 什么是 ES6 模块?](47. 什么是 ES6 模块?)</h3><p><strong>模块</strong>使我们能够将代码基础分割成多个文件,以获得更高的可维护性,并且避免将所有代码放在一个大文件中。在 ES6 支持模块之前,有两个流行的模块。</p>
1281
+ <ul>
1282
+ <li><strong>CommonJS-Node.js</strong></li>
1283
+ <li>AMD(异步模块定义)-<strong>浏览器</strong></li>
1284
+ </ul>
1285
+ <p>基本上,使用模块的方式很简单,<code>import</code>用于从另一个文件中获取功能或几个功能或值,同时<code>export</code>用于从文件中公开功能或几个功能或值。</p>
1286
+ <p><strong>导出</strong></p>
1287
+ <p>使用 ES5 (CommonJS)</p>
1288
+ <pre><code>// 使用 ES5 CommonJS - helpers.js
1289
+ exports.isNull = function (val) &#123;
1290
+ return val === null;
1291
+ &#125;
1292
+
1293
+ exports.isUndefined = function (val) &#123;
1294
+ return val === undefined;
1295
+ &#125;
1296
+
1297
+ exports.isNullOrUndefined = function (val) &#123;
1298
+ return exports.isNull(val) || exports.isUndefined(val);
1299
+ &#125;
1300
+ </code></pre>
1301
+ <p>使用 ES6 模块</p>
1302
+ <pre><code>// 使用 ES6 Modules - helpers.js
1303
+ export function isNull(val)&#123;
1304
+ return val === null;
1305
+ &#125;
1306
+
1307
+ export function isUndefined(val) &#123;
1308
+ return val === undefined;
1309
+ &#125;
1310
+
1311
+ export function isNullOrUndefined(val) &#123;
1312
+ return isNull(val) || isUndefined(val);
1313
+ &#125;
1314
+ </code></pre>
1315
+ <p>在另一个文件中导入函数</p>
1316
+ <pre><code>// 使用 ES5 (CommonJS) - index.js
1317
+ const helpers = require(&#39;./helpers.js&#39;); // helpers is an object
1318
+ const isNull = helpers.isNull;
1319
+ const isUndefined = helpers.isUndefined;
1320
+ const isNullOrUndefined = helpers.isNullOrUndefined;
1321
+
1322
+ // or if your environment supports Destructuring
1323
+ const &#123; isNull, isUndefined, isNullOrUndefined &#125; = require(&#39;./helpers.js&#39;);
1324
+ -------------------------------------------------------
1325
+
1326
+ // ES6 Modules - index.js
1327
+ import * as helpers from &#39;./helpers.js&#39;; // helpers is an object
1328
+
1329
+ // or
1330
+
1331
+ import &#123; isNull, isUndefined, isNullOrUndefined as isValid &#125; from &#39;./helpers.js&#39;;
1332
+
1333
+ // using &quot;as&quot; for renaming named exports
1334
+ </code></pre>
1335
+ <p><strong>在文件中导出单个功能或默认导出</strong></p>
1336
+ <p>使用 ES5 (CommonJS)</p>
1337
+ <pre><code>// 使用 ES5 (CommonJS) - index.js
1338
+ class Helpers &#123;
1339
+ static isNull(val) &#123;
1340
+ return val === null;
1341
+ &#125;
1342
+
1343
+ static isUndefined(val) &#123;
1344
+ return val === undefined;
1345
+ &#125;
1346
+
1347
+ static isNullOrUndefined(val) &#123;
1348
+ return this.isNull(val) || this.isUndefined(val);
1349
+ &#125;
1350
+ &#125;
1351
+
1352
+
1353
+ module.exports = Helpers;
1354
+ </code></pre>
1355
+ <p>使用ES6 Modules</p>
1356
+ <pre><code>// 使用 ES6 Modules - helpers.js
1357
+ class Helpers &#123;
1358
+ static isNull(val) &#123;
1359
+ return val === null;
1360
+ &#125;
1361
+
1362
+ static isUndefined(val) &#123;
1363
+ return val === undefined;
1364
+ &#125;
1365
+
1366
+ static isNullOrUndefined(val) &#123;
1367
+ return this.isNull(val) || this.isUndefined(val);
1368
+ &#125;
1369
+ &#125;
1370
+
1371
+ export default Helpers
1372
+ </code></pre>
1373
+ <p>从另一个文件导入单个功能</p>
1374
+ <p>使用ES5 (CommonJS)</p>
1375
+ <pre><code>// 使用 ES5 (CommonJS) - index.js
1376
+ const Helpers = require(&#39;./helpers.js&#39;);
1377
+ console.log(Helpers.isNull(null));
1378
+ </code></pre>
1379
+ <p>使用 ES6 Modules</p>
1380
+ <pre><code>import Helpers from &#39;.helpers.js&#39;
1381
+ console.log(Helpers.isNull(null));
1382
+ </code></pre>
1383
+ <h3 id="48-什么是Set对象,它是如何工作的?-48-什么是Set对象,它是如何工作的?"><a href="#48-什么是Set对象,它是如何工作的?-48-什么是Set对象,它是如何工作的?" class="headerlink" title="[48. 什么是Set对象,它是如何工作的?](48. 什么是Set对象,它是如何工作的?)"></a>[48. 什么是<code>Set</code>对象,它是如何工作的?](48. 什么是<code>Set</code>对象,它是如何工作的?)</h3><p><strong>Set</strong> 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。</p>
1384
+ <p>我们可以使用<code>Set</code>构造函数创建<code>Set</code>实例。</p>
1385
+ <pre><code>const set1 = new Set();
1386
+ const set2 = new Set([&quot;a&quot;,&quot;b&quot;,&quot;c&quot;,&quot;d&quot;,&quot;d&quot;,&quot;e&quot;]);
1387
+ </code></pre>
1388
+ <p>我们可以使用<code>add</code>方法向<code>Set</code>实例中添加一个新值,因为<code>add</code>方法返回<code>Set</code>对象,所以我们可以以链式的方式再次使用<code>add</code>。如果一个值已经存在于<code>Set</code>对象中,那么它将不再被添加。</p>
1389
+ <pre><code>set2.add(&quot;f&quot;);
1390
+ set2.add(&quot;g&quot;).add(&quot;h&quot;).add(&quot;i&quot;).add(&quot;j&quot;).add(&quot;k&quot;).add(&quot;k&quot;);
1391
+ // 后一个“k”不会被添加到set对象中,因为它已经存在了
1392
+ </code></pre>
1393
+ <p>我们可以使用<code>has</code>方法检查<code>Set</code>实例中是否存在特定的值。</p>
1394
+ <pre><code>set2.has(&quot;a&quot;) // true
1395
+ set2.has(&quot;z&quot;) // true
1396
+ </code></pre>
1397
+ <p>我们可以使用<code>size</code>属性获得<code>Set</code>实例的长度。</p>
1398
+ <pre><code>set2.size // returns 10
1399
+ </code></pre>
1400
+ <p>可以使用<code>clear</code>方法删除 <code>Set</code> 中的数据。</p>
1401
+ <pre><code>set2.clear();
1402
+ </code></pre>
1403
+ <p>我们可以使用<code>Set</code>对象来删除数组中重复的元素。</p>
1404
+ <pre><code>const numbers = [1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 5];
1405
+ const uniqueNums = [...new Set(numbers)]; // [1,2,3,4,5,6,7,8]
1406
+ </code></pre>
1407
+ <h3 id="49-什么是回调函数?-49-什么是回调函数?"><a href="#49-什么是回调函数?-49-什么是回调函数?" class="headerlink" title="[ 49. 什么是回调函数?]( 49. 什么是回调函数?)"></a>[ 49. 什么是回调函数?]( 49. 什么是回调函数?)</h3><p><strong>回调函数</strong>是一段可执行的代码段,它作为一个参数传递给其他的代码,其作用是在需要的时候方便调用这段(回调函数)代码。</p>
1408
+ <p>在JavaScript中函数也是对象的一种,同样对象可以作为参数传递给函数,因此函数也可以作为参数传递给另外一个函数,这个作为参数的函数就是回调函数。</p>
1409
+ <pre><code>const btnAdd = document.getElementById(&#39;btnAdd&#39;);
1410
+
1411
+ btnAdd.addEventListener(&#39;click&#39;, function clickCallback(e) &#123;
1412
+ // do something useless
1413
+ &#125;);
1414
+ </code></pre>
1415
+ <p>在本例中,我们等待<code>id</code>为<code>btnAdd</code>的元素中的<code>click</code>事件,如果它被单击,则执行<code>clickCallback</code>函数。回调函数向某些数据或事件添加一些功能。</p>
1416
+ <p>数组中的<code>reduce</code>、<code>filter</code>和<code>map</code>方法需要一个回调作为参数。回调的一个很好的类比是,当你打电话给某人,如果他们不接,你留下一条消息,你期待他们回调。调用某人或留下消息的行为是事件或数据,回调是你希望稍后发生的操作。</p>
1417
+ <h3 id="50-Promise-是什么?-50-Promise-是什么?"><a href="#50-Promise-是什么?-50-Promise-是什么?" class="headerlink" title="[50. Promise 是什么?](50. Promise 是什么?)"></a>[50. Promise 是什么?](50. Promise 是什么?)</h3><p><strong>Promise</strong> 是异步编程的一种解决方案:从语法上讲,<code>promise</code>是一个对象,从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。<code>promise</code>有三种状态:<code>pending(等待态)</code>,<code>fulfiled(成功态)</code>,<code>rejected(失败态)</code>;状态一旦改变,就不会再变。创造<code>promise</code>实例后,它会立即执行。</p>
1418
+ <pre><code>fs.readFile(&#39;somefile.txt&#39;, function (e, data) &#123;
1419
+ if (e) &#123;
1420
+ console.log(e);
1421
+ &#125;
1422
+ console.log(data);
1423
+ &#125;);
1424
+ </code></pre>
1425
+ <p>如果我们在回调内部有另一个异步操作,则此方法存在问题。 我们将有一个混乱且不可读的代码。 此代码称为<strong>“回调地狱”</strong>。</p>
1426
+ <pre><code>// 回调地狱
1427
+ fs.readFile(&#39;somefile.txt&#39;, function (e, data) &#123;
1428
+ //your code here
1429
+ fs.readdir(&#39;directory&#39;, function (e, files) &#123;
1430
+ //your code here
1431
+ fs.mkdir(&#39;directory&#39;, function (e) &#123;
1432
+ //your code here
1433
+ &#125;)
1434
+ &#125;)
1435
+ &#125;)
1436
+ </code></pre>
1437
+ <p>如果我们在这段代码中使用<code>promise</code>,它将更易于阅读、理解和维护。</p>
1438
+ <pre><code>promReadFile(&#39;file/path&#39;)
1439
+ .then(data =&gt; &#123;
1440
+ return promReaddir(&#39;directory&#39;);
1441
+ &#125;)
1442
+ .then(data =&gt; &#123;
1443
+ return promMkdir(&#39;directory&#39;);
1444
+ &#125;)
1445
+ .catch(e =&gt; &#123;
1446
+ console.log(e);
1447
+ &#125;)
1448
+ </code></pre>
1449
+ <p><code>promise</code>有三种不同的状态:</p>
1450
+ <ul>
1451
+ <li>pending:初始状态,完成或失败状态的前一个状态</li>
1452
+ <li>fulfilled:操作成功完成</li>
1453
+ <li>rejected:操作失败</li>
1454
+ </ul>
1455
+ <p><code>pending</code> 状态的 <code>Promise</code> 对象会触发 <code>fulfilled/rejected</code> 状态,在其状态处理方法中可以传入参数&#x2F;失败信息。当操作成功完成时,<strong>Promise</strong> 对象的 <code>then</code> 方法就会被调用;否则就会触发 <code>catch</code>。如:</p>
1456
+ <pre><code>const myFirstPromise = new Promise((resolve, reject) =&gt; &#123;
1457
+ setTimeout(function()&#123;
1458
+ resolve(&quot;成功!&quot;);
1459
+ &#125;, 250);
1460
+ &#125;);
1461
+
1462
+ myFirstPromise.then((data) =&gt; &#123;
1463
+ console.log(&quot;Yay! &quot; + data);
1464
+ &#125;).catch((e) =&gt; &#123;...&#125;);
1465
+ </code></pre>
1466
+ <h3 id="51-什么是-async-await-及其如何工作?-51-什么是-async-await-及其如何工作?"><a href="#51-什么是-async-await-及其如何工作?-51-什么是-async-await-及其如何工作?" class="headerlink" title="[51. 什么是 async/await 及其如何工作?](51. 什么是 async/await 及其如何工作?)"></a>[51. 什么是 <code>async/await</code> 及其如何工作?](51. 什么是 <code>async/await</code> 及其如何工作?)</h3><p><code>async/await</code>是 JS 中编写异步或非阻塞代码的新方法。它建立在<strong>Promises</strong>之上,让异步代码的可读性和简洁度都更高。</p>
1467
+ <p><code>async/await</code>是 JS 中编写异步或非阻塞代码的新方法。 它建立在<code>Promises</code>之上,相对于 Promise 和回调,它的可读性和简洁度都更高。 但是,在使用此功能之前,我们必须先学习<code>Promises</code>的基础知识,因为正如我之前所说,它是基于<code>Promise</code>构建的,这意味着幕后使用仍然是<strong>Promise</strong>。</p>
1468
+ <p><strong>使用 Promise</strong></p>
1469
+ <pre><code>function callApi() &#123;
1470
+ return fetch(&quot;url/to/api/endpoint&quot;)
1471
+ .then(resp =&gt; resp.json())
1472
+ .then(data =&gt; &#123;
1473
+ //do something with &quot;data&quot;
1474
+ &#125;).catch(err =&gt; &#123;
1475
+ //do something with &quot;err&quot;
1476
+ &#125;);
1477
+ &#125;
1478
+ </code></pre>
1479
+ <p><strong>使用async&#x2F;await</strong></p>
1480
+ <p>在<code>async/await</code>,我们使用 tru&#x2F;catch 语法来捕获异常。</p>
1481
+ <pre><code>async function callApi() &#123;
1482
+ try &#123;
1483
+ const resp = await fetch(&quot;url/to/api/endpoint&quot;);
1484
+ const data = await resp.json();
1485
+ //do something with &quot;data&quot;
1486
+ &#125; catch (e) &#123;
1487
+ //do something with &quot;err&quot;
1488
+ &#125;
1489
+ &#125;
1490
+ </code></pre>
1491
+ <p><strong>注意</strong>:使用 <code>async</code>关键声明函数会隐式返回一个<strong>Promise</strong>。</p>
1492
+ <pre><code>const giveMeOne = async () =&gt; 1;
1493
+
1494
+ giveMeOne()
1495
+ .then((num) =&gt; &#123;
1496
+ console.log(num); // logs 1
1497
+ &#125;);
1498
+ </code></pre>
1499
+ <p><strong>注意:</strong><code>await</code>关键字只能在<code>async function</code>中使用。在任何非<strong>async function</strong>的函数中使用<code>await</code>关键字都会抛出错误。<code>await</code>关键字在执行下一行代码之前等待右侧表达式(可能是一个<strong>Promise</strong>)返回。</p>
1500
+ <pre><code>const giveMeOne = async () =&gt; 1;
1501
+
1502
+ function getOne() &#123;
1503
+ try &#123;
1504
+ const num = await giveMeOne();
1505
+ console.log(num);
1506
+ &#125; catch (e) &#123;
1507
+ console.log(e);
1508
+ &#125;
1509
+ &#125;
1510
+
1511
+ // Uncaught SyntaxError: await is only valid in async function
1512
+
1513
+ async function getTwo() &#123;
1514
+ try &#123;
1515
+ const num1 = await giveMeOne(); // 这行会等待右侧表达式执行完成
1516
+ const num2 = await giveMeOne();
1517
+ return num1 + num2;
1518
+ &#125; catch (e) &#123;
1519
+ console.log(e);
1520
+ &#125;
1521
+ &#125;
1522
+
1523
+ await getTwo(); // 2
1524
+ </code></pre>
1525
+ <h3 id="52-展开-spread-运算符和-剩余-Rest-运算符有什么区别?-52-展开-spread-运算符和-剩余-Rest-运算符有什么区别?"><a href="#52-展开-spread-运算符和-剩余-Rest-运算符有什么区别?-52-展开-spread-运算符和-剩余-Rest-运算符有什么区别?" class="headerlink" title="[52. 展开(spread )运算符和 剩余(Rest) 运算符有什么区别?](52. 展开(spread )运算符和 剩余(Rest) 运算符有什么区别?)"></a>[52. 展开(spread )运算符和 剩余(Rest) 运算符有什么区别?](52. 展开(spread )运算符和 剩余(Rest) 运算符有什么区别?)</h3><p>展开运算符(spread)是三个点(<code>...</code>),可以将一个数组转为用逗号分隔的参数序列。说的通俗易懂点,有点像化骨绵掌,把一个大元素给打散成一个个单独的小元素。</p>
1526
+ <p>剩余运算符也是用三个点(<code>...</code>)表示,它的样子看起来和展开操作符一样,但是它是用于解构数组和对象。在某种程度上,剩余元素和展开元素相反,展开元素会“展开”数组变成多个元素,剩余元素会收集多个元素和“压缩”成一个单一的元素。</p>
1527
+ <pre><code>function add(a, b) &#123;
1528
+ return a + b;
1529
+ &#125;;
1530
+
1531
+ const nums = [5, 6];
1532
+ const sum = add(...nums);
1533
+ console.log(sum);
1534
+ </code></pre>
1535
+ <p>在本例中,我们在调用<code>add</code>函数时使用了展开操作符,对<code>nums</code>数组进行展开。所以参数<code>a</code>的值是<code>5</code> ,<code>b</code>的值是<code>6</code>,所以<code>sum</code> 是<code>11</code>。</p>
1536
+ <pre><code>function add(...rest) &#123;
1537
+ return rest.reduce((total,current) =&gt; total + current);
1538
+ &#125;;
1539
+
1540
+ console.log(add(1, 2)); // 3
1541
+ console.log(add(1, 2, 3, 4, 5)); // 15
1542
+ </code></pre>
1543
+ <p>在本例中,我们有一个<code>add</code>函数,它接受任意数量的参数,并将它们全部相加,然后返回总数。</p>
1544
+ <pre><code>const [first, ...others] = [1, 2, 3, 4, 5];
1545
+ console.log(first); // 1
1546
+ console.log(others); // [2,3,4,5]
1547
+ </code></pre>
1548
+ <p>这里,我们使用剩余操作符提取所有剩余的数组值,并将它们放入除第一项之外的其他数组中。</p>
1549
+ <h3 id="53-什么是默认参数?-53-什么是默认参数?"><a href="#53-什么是默认参数?-53-什么是默认参数?" class="headerlink" title="[53. 什么是默认参数?](53. 什么是默认参数?)"></a>[53. 什么是默认参数?](53. 什么是默认参数?)</h3><p>默认参数是在 JS 中定义默认变量的一种新方法,它在ES6或ECMAScript 2015版本中可用。</p>
1550
+ <pre><code>//ES5 Version
1551
+ function add(a,b)&#123;
1552
+ a = a || 0;
1553
+ b = b || 0;
1554
+ return a + b;
1555
+ &#125;
1556
+
1557
+ //ES6 Version
1558
+ function add(a = 0, b = 0)&#123;
1559
+ return a + b;
1560
+ &#125;
1561
+ add(1); // returns 1
1562
+ </code></pre>
1563
+ <p>我们还可以在默认参数中使用解构。</p>
1564
+ <pre><code>function getFirst([first, ...rest] = [0, 1]) &#123;
1565
+ return first;
1566
+ &#125;
1567
+
1568
+ getFirst(); // 0
1569
+ getFirst([10,20,30]); // 10
1570
+
1571
+ function getArr(&#123; nums &#125; = &#123; nums: [1, 2, 3, 4] &#125;)&#123;
1572
+ return nums;
1573
+ &#125;
1574
+
1575
+ getArr(); // [1, 2, 3, 4]
1576
+ getArr(&#123;nums:[5,4,3,2,1]&#125;); // [5,4,3,2,1]
1577
+ </code></pre>
1578
+ <p>我们还可以使用先定义的参数再定义它们之后的参数。</p>
1579
+ <pre><code>function doSomethingWithValue(value = &quot;Hello World&quot;, callback = () =&gt; &#123; console.log(value) &#125;) &#123;
1580
+ callback();
1581
+ &#125;
1582
+ doSomethingWithValue(); //&quot;Hello World&quot;
1583
+ </code></pre>
1584
+ <h3 id="54-什么是包装对象(wrapper-object)?-54-什么是包装对象(wrapper-object)?"><a href="#54-什么是包装对象(wrapper-object)?-54-什么是包装对象(wrapper-object)?" class="headerlink" title="[54. 什么是包装对象(wrapper object)?](54. 什么是包装对象(wrapper object)?)"></a>[54. 什么是包装对象(wrapper object)?](54. 什么是包装对象(wrapper object)?)</h3><p>我们现在复习一下JS的数据类型,JS数据类型被分为两大类,<strong>基本类型</strong>和<strong>引用类型</strong>。</p>
1585
+ <p>基本类型:<code>Undefined</code>,<code>Null</code>,<code>Boolean</code>,<code>Number</code>,<code>String</code>,<code>Symbol</code>,<code>BigInt</code></p>
1586
+ <p>引用类型:<code>Object</code>,<code>Array</code>,<code>Date</code>,<code>RegExp</code>等,说白了就是对象。</p>
1587
+ <p>其中引用类型有方法和属性,但是基本类型是没有的,但我们经常会看到下面的代码:</p>
1588
+ <pre><code>let name = &quot;marko&quot;;
1589
+
1590
+ console.log(typeof name); // &quot;string&quot;
1591
+ console.log(name.toUpperCase()); // &quot;MARKO&quot;
1592
+ </code></pre>
1593
+ <p><code>name</code>类型是 <code>string</code>,属于基本类型,所以它没有属性和方法,但是在这个例子中,我们调用了一个<code>toUpperCase()</code>方法,它不会抛出错误,还返回了对象的变量值。</p>
1594
+ <p>原因是基本类型的值被临时转换或强制转换为<strong>对象</strong>,因此<code>name</code>变量的行为类似于<strong>对象</strong>。 除<code>null</code>和<code>undefined</code>之外的每个基本类型都有自己<strong>包装对象</strong>。也就是:<code>String</code>,<code>Number</code>,<code>Boolean</code>,<code>Symbol</code>和<code>BigInt</code>。 在这种情况下,<code>name.toUpperCase()</code>在幕后看起来如下:</p>
1595
+ <pre><code>console.log(new String(name).toUpperCase()); // &quot;MARKO&quot;
1596
+ </code></pre>
1597
+ <p>在完成访问属性或调用方法之后,新创建的对象将立即被丢弃。</p>
1598
+ <h3 id="55-隐式和显式转换有什么区别)?-55-隐式和显式转换有什么区别)?"><a href="#55-隐式和显式转换有什么区别)?-55-隐式和显式转换有什么区别)?" class="headerlink" title="[55. 隐式和显式转换有什么区别)?](55. 隐式和显式转换有什么区别)?)"></a>[55. 隐式和显式转换有什么区别)?](55. 隐式和显式转换有什么区别)?)</h3><p>隐式强制转换是一种将值转换为另一种类型的方法,这个过程是自动完成的,无需我们手动操作。</p>
1599
+ <p>假设我们下面有一个例子。</p>
1600
+ <pre><code>console.log(1 + &#39;6&#39;); // 16
1601
+ console.log(false + true); // 1
1602
+ console.log(6 * &#39;2&#39;); // 12
1603
+ </code></pre>
1604
+ <p>第一个<code>console.log</code>语句结果为<code>16</code>。在其他语言中,这会抛出编译时错误,但在 JS 中,<code>1</code>被转换成字符串,然后与<code>+运</code>算符连接。我们没有做任何事情,它是由 JS 自动完成。</p>
1605
+ <p>第二个<code>console.log</code>语句结果为<code>1</code>,JS 将<code>false</code>转换为<code>boolean</code> 值为 <code>0</code>,,<code>true</code>为<code>1</code>,因此结果为<code>1</code>。</p>
1606
+ <p>第三个<code>console.log</code>语句结果<code>12</code>,它将<code>&#39;2&#39;</code>转换为一个数字,然后乘以<code>6 * 2</code>,结果是12。</p>
1607
+ <p>而显式强制是将值转换为另一种类型的方法,我们需要手动转换。</p>
1608
+ <pre><code>console.log(1 + parseInt(&#39;6&#39;));
1609
+ </code></pre>
1610
+ <p>在本例中,我们使用<code>parseInt</code>函数将<code>&#39;6&#39;</code>转换为<code>number</code> ,然后使用<code>+</code>运算符将<code>1</code>和<code>6</code>相加。</p>
1611
+ <h3 id="56-什么是NaN?-以及如何检查值是否为NaN?-56-什么是NaN?-以及如何检查值是否为NaN?"><a href="#56-什么是NaN?-以及如何检查值是否为NaN?-56-什么是NaN?-以及如何检查值是否为NaN?" class="headerlink" title="[56. 什么是NaN? 以及如何检查值是否为NaN?](56. 什么是NaN? 以及如何检查值是否为NaN?)"></a>[56. 什么是NaN? 以及如何检查值是否为NaN?](56. 什么是NaN? 以及如何检查值是否为NaN?)</h3><p><code>NaN</code>表示<strong>“非数字”</strong>是 JS 中的一个值,该值是将数字转换或执行为非数字值的运算结果,因此结果为<code>NaN</code>。</p>
1612
+ <pre><code>let a;
1613
+
1614
+ console.log(parseInt(&#39;abc&#39;)); // NaN
1615
+ console.log(parseInt(null)); // NaN
1616
+ console.log(parseInt(undefined)); // NaN
1617
+ console.log(parseInt(++a)); // NaN
1618
+ console.log(parseInt(&#123;&#125; * 10)); // NaN
1619
+ console.log(parseInt(&#39;abc&#39; - 2)); // NaN
1620
+ console.log(parseInt(0 / 0)); // NaN
1621
+ console.log(parseInt(&#39;10a&#39; * 10)); // NaN
1622
+ </code></pre>
1623
+ <p>JS 有一个内置的<code>isNaN</code>方法,用于测试值是否为isNaN值,但是这个函数有一个奇怪的行为。</p>
1624
+ <pre><code>console.log(isNaN()); // true
1625
+ console.log(isNaN(undefined)); // true
1626
+ console.log(isNaN(&#123;&#125;)); // true
1627
+ console.log(isNaN(String(&#39;a&#39;))); // true
1628
+ console.log(isNaN(() =&gt; &#123; &#125;)); // true
1629
+ </code></pre>
1630
+ <p>所有这些<code>console.log</code>语句都返回<code>true</code>,即使我们传递的值不是<code>NaN</code>。</p>
1631
+ <p>在<code>ES6</code>中,建议使用<code>Number.isNaN</code>方法,因为它确实会检查该值(如果确实是<code>NaN</code>),或者我们可以使自己的辅助函数检查此问题,因为在 JS 中,<strong>NaN</strong>是唯一的值,它不等于自己。</p>
1632
+ <pre><code>function checkIfNaN(value) &#123;
1633
+ return value !== value;
1634
+ &#125;
1635
+ </code></pre>
1636
+ <h3 id="57-如何判断值是否为数组?-57-如何判断值是否为数组?"><a href="#57-如何判断值是否为数组?-57-如何判断值是否为数组?" class="headerlink" title="[57. 如何判断值是否为数组?](57. 如何判断值是否为数组?)"></a>[57. 如何判断值是否为数组?](57. 如何判断值是否为数组?)</h3><p>我们可以使用<code>Array.isArray</code>方法来检查值是否为<strong>数组</strong>。 当传递给它的参数是数组时,它返回<code>true</code>,否则返回<code>false</code>。</p>
1637
+ <pre><code>console.log(Array.isArray(5)); // false
1638
+ console.log(Array.isArray(&quot;&quot;)); // false
1639
+ console.log(Array.isArray()); // false
1640
+ console.log(Array.isArray(null)); // false
1641
+ console.log(Array.isArray(&#123; length: 5 &#125;)); // false
1642
+
1643
+ console.log(Array.isArray([])); // true
1644
+ </code></pre>
1645
+ <p>如果环境不支持此方法,则可以使用<code>polyfill</code>实现。</p>
1646
+ <pre><code>function isArray(value)&#123;
1647
+ return Object.prototype.toString.call(value) === &quot;[object Array]&quot;
1648
+ &#125;
1649
+ </code></pre>
1650
+ <p>当然还可以使用传统的方法:</p>
1651
+ <pre><code>let a = []
1652
+ if (a instanceof Array) &#123;
1653
+ console.log(&#39;是数组&#39;)
1654
+ &#125; else &#123;
1655
+ console.log(&#39;非数组&#39;)
1656
+ &#125;
1657
+ </code></pre>
1658
+ <h3 id="58-如何在不使用-模运算符的情况下检查一个数字是否是偶数?-58-如何在不使用-模运算符的情况下检查一个数字是否是偶数?"><a href="#58-如何在不使用-模运算符的情况下检查一个数字是否是偶数?-58-如何在不使用-模运算符的情况下检查一个数字是否是偶数?" class="headerlink" title="[58. 如何在不使用%模运算符的情况下检查一个数字是否是偶数?](58. 如何在不使用%模运算符的情况下检查一个数字是否是偶数?)"></a>[58. 如何在不使用<code>%</code>模运算符的情况下检查一个数字是否是偶数?](58. 如何在不使用<code>%</code>模运算符的情况下检查一个数字是否是偶数?)</h3><p>我们可以对这个问题使用按位<code>&amp;</code>运算符,<code>&amp;</code>对其操作数进行运算,并将其视为二进制值,然后执行与运算。</p>
1659
+ <pre><code>function isEven(num) &#123;
1660
+ if (num &amp; 1) &#123;
1661
+ return false
1662
+ &#125; else &#123;
1663
+ return true
1664
+ &#125;
1665
+ &#125;
1666
+ </code></pre>
1667
+ <p><code>0</code> 二进制数是 <code>000</code><br><code>1</code> 二进制数是 <code>001</code><br><code>2</code> 二进制数是 <code>010</code><br><code>3</code> 二进制数是 <code>011 </code><br><code>4</code> 二进制数是 <code>100</code><br><code>5</code> 二进制数是 <code>101</code><br><code>6</code> 二进制数是 <code>110</code><br><code>7</code> 二进制数是 <code>111</code></p>
1668
+ <p>以此类推…</p>
1669
+ <p>与运算的规则如下:<br>aba &amp; b000010111<br>因此,当我们执行<code>console.log(5&amp;1)</code>这个表达式时,结果为<code>1</code>。首先,<code>&amp;</code>运算符将两个数字都转换为二进制,因此<code>5</code>变为<code>101</code>,<code>1</code>变为<code>001</code>。</p>
1670
+ <p>然后,它使用按位怀运算符比较每个位(<code>0</code>和<code>1</code>)。 <code>101&amp;001</code>,从表中可以看出,如果<code>a &amp; b</code>为<code>1</code>,所以<code>5&amp;1</code>结果为<code>1</code>。<br>101 &amp; 001101001001</p>
1671
+ <ul>
1672
+ <li>首先我们比较最左边的<code>1&amp;0</code>,结果是<code>0</code>。</li>
1673
+ <li>然后我们比较中间的<code>0&amp;0</code>,结果是<code>0</code>。</li>
1674
+ <li>然后我们比较最后<code>1&amp;1</code>,结果是<code>1</code>。</li>
1675
+ <li>最后,得到一个二进制数<code>001</code>,对应的十进制数,即<code>1</code>。</li>
1676
+ </ul>
1677
+ <p>由此我们也可以算出<code>console.log(4 &amp; 1)</code> 结果为<code>0</code>。知道<code>4</code>的最后一位是<code>0</code>,而<code>0 &amp; 1</code> 将是<code>0</code>。如果你很难理解这一点,我们可以使用递归函数来解决此问题。</p>
1678
+ <p>function isEven(num) {</p>
1679
+ <pre><code> if (num &lt; 0 || num === 1) return false;
1680
+ if (num == 0) return true;
1681
+ return isEven(num - 2);
1682
+ </code></pre>
1683
+ <p>}</p>
1684
+ <h3 id="59-如何检查对象中是否存在某个属性?-59-如何检查对象中是否存在某个属性?"><a href="#59-如何检查对象中是否存在某个属性?-59-如何检查对象中是否存在某个属性?" class="headerlink" title="[59. 如何检查对象中是否存在某个属性?](59. 如何检查对象中是否存在某个属性?)"></a>[59. 如何检查对象中是否存在某个属性?](59. 如何检查对象中是否存在某个属性?)</h3><p>检查对象中是否存在属性有三种方法。</p>
1685
+ <p>第一种使用 <code>in</code> 操作符号:</p>
1686
+ <pre><code>const o = &#123;
1687
+ &quot;prop&quot; : &quot;bwahahah&quot;,
1688
+ &quot;prop2&quot; : &quot;hweasa&quot;
1689
+ &#125;;
1690
+
1691
+ console.log(&quot;prop&quot; in o); // true
1692
+ console.log(&quot;prop1&quot; in o); // false
1693
+ </code></pre>
1694
+ <p>第二种使用 <code>hasOwnProperty</code> 方法,<code>hasOwnProperty()</code> 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。</p>
1695
+ <pre><code>console.log(o.hasOwnProperty(&quot;prop2&quot;)); // true
1696
+ console.log(o.hasOwnProperty(&quot;prop1&quot;)); // false
1697
+ </code></pre>
1698
+ <p>第三种使用括号符号<code>obj[&quot;prop&quot;]</code>。如果属性存在,它将返回该属性的值,否则将返回<code>undefined</code>。</p>
1699
+ <pre><code>console.log(o[&quot;prop&quot;]); // &quot;bwahahah&quot;
1700
+ console.log(o[&quot;prop1&quot;]); // undefined
1701
+ </code></pre>
1702
+ <h3 id="60-AJAX-是什么?-60-AJAX-是什么?"><a href="#60-AJAX-是什么?-60-AJAX-是什么?" class="headerlink" title="[60. AJAX 是什么?](60. AJAX 是什么?)"></a>[60. AJAX 是什么?](60. AJAX 是什么?)</h3><p>即异步的 <strong>JavaScript 和 XML</strong>,是一种用于创建快速动态网页的技术,传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。使用<strong>AJAX</strong>则不需要加载更新整个网页,实现部分内容更新</p>
1703
+ <p>用到AJAX的技术:</p>
1704
+ <ul>
1705
+ <li><strong>HTML</strong> - 网页结构</li>
1706
+ <li><strong>CSS</strong> - 网页的样式</li>
1707
+ <li><strong>JavaScript</strong> - 操作网页的行为和更新DOM</li>
1708
+ <li><strong>XMLHttpRequest API</strong> - 用于从服务器发送和获取数据</li>
1709
+ <li><strong>PHP,Python,Nodejs</strong> - 某些服务器端语言</li>
1710
+ </ul>
1711
+ <h3 id="61-如何在-JS-中创建对象?-61-如何在-JS-中创建对象?"><a href="#61-如何在-JS-中创建对象?-61-如何在-JS-中创建对象?" class="headerlink" title="[61. 如何在 JS 中创建对象?](61. 如何在 JS 中创建对象?)"></a>[61. 如何在 JS 中创建对象?](61. 如何在 JS 中创建对象?)</h3><p><strong>使用对象字面量:</strong></p>
1712
+ <pre><code> const o = &#123;
1713
+ name: &quot;Mark&quot;,
1714
+ greeting() &#123;
1715
+ return `Hi, I&#39;m $&#123;this.name&#125;`;
1716
+ &#125;
1717
+ &#125;;
1718
+
1719
+ o.greeting(); //returns &quot;Hi, I&#39;m Mark&quot;
1720
+ </code></pre>
1721
+ <p><strong>使用构造函数:</strong></p>
1722
+ <pre><code>function Person(name) &#123;
1723
+ this.name = name;
1724
+ &#125;
1725
+
1726
+ Person.prototype.greeting = function () &#123;
1727
+ return `Hi, I&#39;m $&#123;this.name&#125;`;
1728
+ &#125;
1729
+
1730
+ const mark = new Person(&quot;Mark&quot;);
1731
+
1732
+ mark.greeting(); //returns &quot;Hi, I&#39;m Mark&quot;
1733
+ </code></pre>
1734
+ <p><strong>使用 Object.create 方法:</strong></p>
1735
+ <pre><code>const n = &#123;
1736
+ greeting() &#123;
1737
+ return `Hi, I&#39;m $&#123;this.name&#125;`;
1738
+ &#125;
1739
+ &#125;;
1740
+
1741
+ const o = Object.create(n); // sets the prototype of &quot;o&quot; to be &quot;n&quot;
1742
+
1743
+ o.name = &quot;Mark&quot;;
1744
+
1745
+ console.log(o.greeting()); // logs &quot;Hi, I&#39;m Mark&quot;
1746
+ </code></pre>
1747
+ <h3 id="62-Object-seal-和-Object-freeze-方法之间有什么区别?-62-Object-seal-和-Object-freeze-方法之间有什么区别?"><a href="#62-Object-seal-和-Object-freeze-方法之间有什么区别?-62-Object-seal-和-Object-freeze-方法之间有什么区别?" class="headerlink" title="[62. Object.seal 和 Object.freeze 方法之间有什么区别?](62. Object.seal 和 Object.freeze 方法之间有什么区别?)"></a>[62. Object.seal 和 Object.freeze 方法之间有什么区别?](62. Object.seal 和 Object.freeze 方法之间有什么区别?)</h3><p>这两种方法之间的区别在于,当我们对一个对象使用Object.freeze方法时,该对象的属性是不可变的,这意味着我们不能更改或编辑这些属性的值。而在Obj.Engor方法中,我们可以改变现有的属性。**<br>**</p>
1748
+ <p><strong>Object.freeze()</strong></p>
1749
+ <p><code>Object.freeze()</code> 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改<code>。freeze()</code> 返回和传入的参数相同的对象。</p>
1750
+ <p><strong>Object.seal()</strong></p>
1751
+ <blockquote>
1752
+ <p>Object.seal()方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要可写就可以改变。</p>
1753
+ </blockquote>
1754
+ <p>方法的相同点:</p>
1755
+ <ol>
1756
+ <li>ES5新增。</li>
1757
+ <li>对象不可能扩展,也就是不能再添加新的属性或者方法。</li>
1758
+ <li>对象已有属性不允许被删除。</li>
1759
+ <li>对象属性特性不可以重新配置。</li>
1760
+ </ol>
1761
+ <p>方法不同点:</p>
1762
+ <ul>
1763
+ <li><p><code>Object.seal</code>方法生成的密封对象,如果属性是可写的,那么可以修改属性值。</p>
1764
+ </li>
1765
+ <li><p><code>Object.freeze</code>方法生成的冻结对象,属性都是不可写的,也就是属性值无法更改。</p>
1766
+ </li>
1767
+ </ul>
1768
+ <h3 id="63-in-运算符和-Object-hasOwnProperty-方法有什么区别?-63-in-运算符和-Object-hasOwnProperty-方法有什么区别?"><a href="#63-in-运算符和-Object-hasOwnProperty-方法有什么区别?-63-in-运算符和-Object-hasOwnProperty-方法有什么区别?" class="headerlink" title="[63. in 运算符和 Object.hasOwnProperty 方法有什么区别?](63. in 运算符和 Object.hasOwnProperty 方法有什么区别?)"></a>[63. <code>in</code> 运算符和 <code>Object.hasOwnProperty</code> 方法有什么区别?](63. <code>in</code> 运算符和 <code>Object.hasOwnProperty</code> 方法有什么区别?)</h3><p>如你所知,这两个特性都检查对象中是否存在属性,它将返回truefalse。它们之间的区别在于,in操作符还会检查对象的原型链,如果属性在当前对象中没有找到,而hasOwnProperty方法只检查属性是否存在于当前对象中,而忽略原型链。**<br>**</p>
1769
+ <p><strong>hasOwnPropert方法</strong></p>
1770
+ <p><code>hasOwnPropert()</code>方法返回值是一个布尔值,指示对象自身属性中是否具有指定的属性,因此这个方法会忽略掉那些从原型链上继承到的属性。</p>
1771
+ <p>看下面的例子:</p>
1772
+ <pre><code>Object.prototype.phone= &#39;15345025546&#39;;
1773
+
1774
+ let obj = &#123;
1775
+ name: &#39;西门大官人&#39;,
1776
+ age: &#39;28&#39;
1777
+ &#125;
1778
+ console.log(obj.hasOwnProperty(&#39;phone&#39;)) // false
1779
+ console.log(obj.hasOwnProperty(&#39;name&#39;)) // true
1780
+ </code></pre>
1781
+ <p>可以看到,如果在函数原型上定义一个变量<code>phone</code>,<code>hasOwnProperty</code>方法会直接忽略掉。</p>
1782
+ <p><strong>in 运算符</strong></p>
1783
+ <p>如果指定的属性在指定的对象或其原型链中,则<code>in</code> 运算符返回<code>true</code>。</p>
1784
+ <p>还是用上面的例子来演示:</p>
1785
+ <pre><code>console.log(&#39;phone&#39; in obj) // true
1786
+ </code></pre>
1787
+ <p>可以看到<code>in</code>运算符会检查它或者其原型链是否包含具有指定名称的属性。</p>
1788
+ <h3 id="64-有哪些方法可以处理-JS-中的异步代码?-64-有哪些方法可以处理-JS-中的异步代码?"><a href="#64-有哪些方法可以处理-JS-中的异步代码?-64-有哪些方法可以处理-JS-中的异步代码?" class="headerlink" title="[64. 有哪些方法可以处理 JS 中的异步代码?](64. 有哪些方法可以处理 JS 中的异步代码?)"></a>[64. 有哪些方法可以处理 JS 中的异步代码?](64. 有哪些方法可以处理 JS 中的异步代码?)</h3><ul>
1789
+ <li>回调</li>
1790
+ <li>Promise</li>
1791
+ <li>async&#x2F;await</li>
1792
+ <li>还有一些库: async.js, bluebird, q, co</li>
1793
+ </ul>
1794
+ <h3 id="65-函数表达式和函数声明之间有什么区别?-65-函数表达式和函数声明之间有什么区别?"><a href="#65-函数表达式和函数声明之间有什么区别?-65-函数表达式和函数声明之间有什么区别?" class="headerlink" title="[65. 函数表达式和函数声明之间有什么区别?](65. 函数表达式和函数声明之间有什么区别?)"></a>[65. 函数表达式和函数声明之间有什么区别?](65. 函数表达式和函数声明之间有什么区别?)</h3><p>看下面的例子:</p>
1795
+ <pre><code>hoistedFunc();
1796
+ notHoistedFunc();
1797
+
1798
+ function hoistedFunc()&#123;
1799
+ console.log(&quot;注意:我会被提升&quot;);
1800
+ &#125;
1801
+
1802
+ var notHoistedFunc = function()&#123;
1803
+ console.log(&quot;注意:我没有被提升&quot;);
1804
+ &#125;
1805
+ </code></pre>
1806
+ <p><code>notHoistedFunc</code>调用抛出异常:<code>Uncaught TypeError: notHoistedFunc is not a function</code>,而<code>hoistedFunc</code>调用不会,因为<code>hoistedFunc</code>会被提升到作用域的顶部,而<code>notHoistedFunc</code> 不会。</p>
1807
+ <h3 id="66-调用函数,可以使用哪些方法?-66-调用函数,可以使用哪些方法?"><a href="#66-调用函数,可以使用哪些方法?-66-调用函数,可以使用哪些方法?" class="headerlink" title="[66. 调用函数,可以使用哪些方法?](66. 调用函数,可以使用哪些方法?)"></a>[66. 调用函数,可以使用哪些方法?](66. 调用函数,可以使用哪些方法?)</h3><p>在 JS 中有4种方法可以调用函数。</p>
1808
+ <ul>
1809
+ <li><p><strong>作为函数调用</strong>——如果一个函数没有作为方法、构造函数、<code>apply</code>、<code>call</code> 调用时,此时 <code>this</code> 指向的是 <code>window</code> 对象(非严格模式)</p>
1810
+ <pre><code>//Global Scope
1811
+
1812
+ function add(a,b)&#123;
1813
+ console.log(this);
1814
+ return a + b;
1815
+ &#125;
1816
+
1817
+ add(1,5); // 打印 &quot;window&quot; 对象和 6
1818
+
1819
+ const o = &#123;
1820
+ method(callback)&#123;
1821
+ callback();
1822
+ &#125;
1823
+ &#125;
1824
+
1825
+ o.method(function ()&#123;
1826
+ console.log(this); // 打印 &quot;window&quot; 对象
1827
+ &#125;);
1828
+ </code></pre>
1829
+ </li>
1830
+ <li><p><strong>作为方法调用</strong>——如果一个对象的属性有一个函数的值,我们就称它为<strong>方法</strong>。调用该方法时,该方法的<code>this</code>值指向该对象。</p>
1831
+ <p> const details &#x3D; {<br>name : “Marko”,<br>getName(){<br> return this.name;<br>}<br> }</p>
1832
+ <p> details.getName(); &#x2F;&#x2F; Marko<br> &#x2F;&#x2F; the “this” value inside “getName” method will be the “details” object</p>
1833
+ </li>
1834
+ <li><p><strong>作为构造函数的调用</strong>-如果在函数之前使用<code>new</code>关键字调用了函数,则该函数称为<code>构造函数</code>。构造函数里面会默认创建一个空对象,并将<code>this</code>指向该对象。</p>
1835
+ <p> function Employee(name, position, yearHired) {<br>&#x2F;&#x2F; creates an empty object {}<br>&#x2F;&#x2F; then assigns the empty object to the “this” keyword<br>&#x2F;&#x2F; this &#x3D; {};<br>this.name &#x3D; name;<br>this.position &#x3D; position;<br>this.yearHired &#x3D; yearHired;<br>&#x2F;&#x2F; inherits from Employee.prototype<br>&#x2F;&#x2F; returns the “this” value implicitly if no<br>&#x2F;&#x2F; explicit return statement is specified<br> };</p>
1836
+ <p> const emp &#x3D; new Employee(“Marko Polo”, “Software Developer”, 2017);</p>
1837
+ </li>
1838
+ <li><p><strong>使用<code>apply</code>和<code>call</code>方法调用</strong>——如果我们想显式地指定一个函数的<code>this</code>值,我们可以使用这些方法,这些方法对所有函数都可用。</p>
1839
+ <p> const obj1 &#x3D; {<br> result:0<br> };</p>
1840
+ <p> const obj2 &#x3D; {<br> result:0<br> };</p>
1841
+ <p> function reduceAdd(){<br> let result &#x3D; 0;<br> for(let i &#x3D; 0, len &#x3D; arguments.length; i &lt; len; i++){<br> result +&#x3D; arguments[i];<br> }<br> this.result &#x3D; result;<br> }</p>
1842
+ <p> reduceAdd.apply(obj1, [1, 2, 3, 4, 5]); &#x2F;&#x2F; reduceAdd 函数中的 this 对象将是 obj1<br> reduceAdd.call(obj2, 1, 2, 3, 4, 5); &#x2F;&#x2F; reduceAdd 函数中的 this 对象将是 obj2</p>
1843
+ </li>
1844
+ </ul>
1845
+ <h3 id="67-什么是缓存及它有什么作用?-67-什么是缓存及它有什么作用?"><a href="#67-什么是缓存及它有什么作用?-67-什么是缓存及它有什么作用?" class="headerlink" title="[67. 什么是缓存及它有什么作用?](67. 什么是缓存及它有什么作用?)"></a>[67. 什么是缓存及它有什么作用?](67. 什么是缓存及它有什么作用?)</h3><p>缓存是建立一个函数的过程,这个函数能够记住之前计算的结果或值。使用缓存函数是为了避免在最后一次使用相同参数的计算中已经执行的函数的计算。这节省了时间,但也有不利的一面,即我们将消耗更多的内存来保存以前的结果。</p>
1846
+ <h3 id="68-手动实现缓存方法-68-手动实现缓存方法"><a href="#68-手动实现缓存方法-68-手动实现缓存方法" class="headerlink" title="[68. 手动实现缓存方法](68. 手动实现缓存方法)"></a>[68. 手动实现缓存方法](68. 手动实现缓存方法)</h3><pre><code>function memoize(fn) &#123;
1847
+ const cache = &#123;&#125;;
1848
+ return function (param) &#123;
1849
+ if (cache[param]) &#123;
1850
+ console.log(&#39;cached&#39;);
1851
+ return cache[param];
1852
+ &#125; else &#123;
1853
+ let result = fn(param);
1854
+ cache[param] = result;
1855
+ console.log(`not cached`);
1856
+ return result;
1857
+ &#125;
1858
+ &#125;
1859
+ &#125;
1860
+
1861
+ const toUpper = (str =&quot;&quot;)=&gt; str.toUpperCase();
1862
+
1863
+ const toUpperMemoized = memoize(toUpper);
1864
+
1865
+ toUpperMemoized(&quot;abcdef&quot;);
1866
+ toUpperMemoized(&quot;abcdef&quot;);
1867
+ </code></pre>
1868
+ <p>这个缓存函数适用于接受一个参数。 我们需要改变下,让它接受多个参数。</p>
1869
+ <pre><code>const slice = Array.prototype.slice;
1870
+ function memoize(fn) &#123;
1871
+ const cache = &#123;&#125;;
1872
+ return (...args) =&gt; &#123;
1873
+ const params = slice.call(args);
1874
+ console.log(params);
1875
+ if (cache[params]) &#123;
1876
+ console.log(&#39;cached&#39;);
1877
+ return cache[params];
1878
+ &#125; else &#123;
1879
+ let result = fn(...args);
1880
+ cache[params] = result;
1881
+ console.log(`not cached`);
1882
+ return result;
1883
+ &#125;
1884
+ &#125;
1885
+ &#125;
1886
+ const makeFullName = (fName, lName) =&gt; `$&#123;fName&#125; $&#123;lName&#125;`;
1887
+ const reduceAdd = (numbers, startingValue = 0) =&gt;
1888
+ numbers.reduce((total, cur) =&gt; total + cur, startingValue);
1889
+
1890
+ const memoizedMakeFullName = memoize(makeFullName);
1891
+ const memoizedReduceAdd = memoize(reduceAdd);
1892
+
1893
+ memoizedMakeFullName(&quot;Marko&quot;, &quot;Polo&quot;);
1894
+ memoizedMakeFullName(&quot;Marko&quot;, &quot;Polo&quot;);
1895
+
1896
+ memoizedReduceAdd([1, 2, 3, 4, 5], 5);
1897
+ memoizedReduceAdd([1, 2, 3, 4, 5], 5);
1898
+ </code></pre>
1899
+ <h3 id="69-为什么typeof-null-返回-object?-如何检查一个值是否为-null?-69-为什么typeof-null-返回-object?-如何检查一个值是否为-null?"><a href="#69-为什么typeof-null-返回-object?-如何检查一个值是否为-null?-69-为什么typeof-null-返回-object?-如何检查一个值是否为-null?" class="headerlink" title="[69. 为什么typeof null 返回 object? 如何检查一个值是否为 null?](69. 为什么typeof null 返回 object? 如何检查一个值是否为 null?)"></a>[69. 为什么typeof null 返回 object? 如何检查一个值是否为 null?](69. 为什么typeof null 返回 object? 如何检查一个值是否为 null?)</h3><p><code>typeof null == &#39;object&#39;</code>总是返回<code>true</code>,因为这是自 JS 诞生以来<code>null</code>的实现。曾经有人提出将<code>typeof null == &#39;object&#39;</code>修改为<code>typeof null == &#39;null&#39;</code>,但是被拒绝了,因为这将导致更多的<strong>bug</strong>。</p>
1900
+ <p>我们可以使用严格相等运算符<code>===</code>来检查值是否为<code>null</code>。</p>
1901
+ <pre><code>function isNull(value)&#123;
1902
+ return value === null;
1903
+ &#125;
1904
+ </code></pre>
1905
+ <h3 id="70-new-关键字有什么作用?-70-new-关键字有什么作用?"><a href="#70-new-关键字有什么作用?-70-new-关键字有什么作用?" class="headerlink" title="[70. new 关键字有什么作用?](70. new 关键字有什么作用?)"></a>[70. new 关键字有什么作用?](70. new 关键字有什么作用?)</h3><p><code>new</code>关键字与构造函数一起使用以创建对象在JavaScript中。</p>
1906
+ <p>下面看看例子:</p>
1907
+ <pre><code>function Employee(name, position, yearHired) &#123;
1908
+ this.name = name;
1909
+ this.position = position;
1910
+ this.yearHired = yearHired;
1911
+ &#125;;
1912
+
1913
+ const emp = new Employee(&quot;Marko Polo&quot;, &quot;Software Developer&quot;, 2017);
1914
+ </code></pre>
1915
+ <p><code>new</code>关键字做了<code>4</code>件事:</p>
1916
+ <ul>
1917
+ <li>创建空对象 <code>&#123;&#125;</code></li>
1918
+ <li>将空对象分配给 <code>this</code> 值</li>
1919
+ <li>将空对象的<code>__proto__</code>指向构造函数的<code>prototype</code></li>
1920
+ <li>如果没有使用显式<code>return</code>语句,则返回<code>this</code></li>
1921
+ </ul>
1922
+ <p>根据上面描述的,它将首先创建一个空对象{},然后它将this值赋给这个空对象this&#x3D;{},并向这个对象添加属性。因为我们没有显式的return语句,所以它会自动为我们返回this。</p>
1923
+ <p>英文原文地址:<a target="_blank" rel="noopener" href="https://dev.to/macmacky/70-javascript-interview-questions-5gfi#61-what-are-the-ways-of-making-objects-in-javascript">https://dev.to/macmacky/70-javascript-interview-questions-5gfi#61-what-are-the-ways-of-making-objects-in-javascript</a></p>
1924
+ <p>为了保证的可读性,本文采用意译而非直译。</p>
1925
+ <p>更多<a target="_blank" rel="noopener" href="https://www.html.cn/">web开发</a>知识,请查阅 HTML中文网 !!</p>
1926
+ <p>以上就是70个JavaScript面试问题的详细内容,更多请关注html中文网其它相关文章!</p>
1927
+ </div><iframe src="/donate/?AliPayQR=https://store.xuehuayu.cn/store/public/alipay_qr.jpg&amp;WeChatQR=https://store.xuehuayu.cn/store/public/wechat_qr.png&amp;UnionPayQR=null&amp;GitHub=null&amp;BTCQR=null&amp;BTCKEY=null&amp;PayPal=https://www.paypal.com/paypalme/OrdinaryPerson" style="overflow-x:hidden; overflow-y:hidden; border:0xp none #fff; min-height:240px; width:100%;" frameborder="0" scrolling="no"></iframe><div><ul class="post-copyright"><li class="post-copyright-author"><strong>本文作者:</strong>雪花雨</li><li class="post-copyright-link"><strong>本文链接:</strong><a href="/article/54313.html">https://xuehuayu.cn/article/54313.html</a></li><li class="post-copyright-license"><strong>版权声明:</strong>① 标为原创的文章为博主原创,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接。② 转载文章来自网络,已标明出处,<a href="mailto:cainiaoblog@126.com">侵删</a>。</li></ul></div><br><div class="tags"><a href="/tags/%E8%BD%AC%E8%BD%BD/">转载</a></div><div class="post-nav"><a class="pre" href="/article/14192.html">字节跳动面试官:请你实现一个大文件上传和断点续传</a><a class="next" href="/article/16947.html">面试常考手写代码学习技巧总结</a></div><div id="vcomment"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@waline/client@v2/dist/waline.min.css"><script src="//cdn.jsdelivr.net/npm/@waline/client@v2/dist/waline.js"></script><script>const origin = window.location.origin
1928
+ const serverURL = origin.includes('cainiaoblog') ? 'https://cmts.cainiaoblog.cn' : 'https://cmts.xuehuayu.cn'
1929
+ const locale = {
1930
+ placeholder: '请正确填写昵称和邮箱,方便接收回复通知~',
1931
+ sofa: '沙发空缺中,还不快抢~',
1932
+ };
1933
+ Waline.init({
1934
+ el: '#vcomment',
1935
+ serverURL: serverURL,
1936
+ pageSize: '20',
1937
+ visitor: true, // 阅读量统计
1938
+ requiredMeta: ['nick', 'mail'],
1939
+ emoji: [
1940
+ 'https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/weibo',
1941
+ 'https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/qq',
1942
+ 'https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/tw-emoji',
1943
+ ],
1944
+ locale,
1945
+ pageview: true
1946
+ })
1947
+ </script></div></div></div><div class="pure-u-1 pure-u-md-1-4 fixed-search hidden_mid_and_down"><div id="sidebar"><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/search.min.js"></script><div class="widget"><div class="widget-search"><input class="search" type="radio" name="search" value="baidu" id="baidu" checked="checked"/><label class="label" for="baidu" title="百度全站搜索">百度</label><input class="search" type="radio" name="search" value="google" id="google"/><label class="label" for="google" title="谷歌全站搜索">谷歌</label><input class="search" type="radio" name="search" value="self" id="self"/><label class="label" for="self" title="使用站内搜索">站内</label></div><div class="widget" id="search"><form class="search-form" action="//www.baidu.com/baidu" method="get" accept-charset="utf-8" target="_blank"><input type="search" name="word" maxlength="30" placeholder="百度全站搜索"/><input type="hidden" name="si" value="xuehuayu.cn"/><input type="hidden" name="cl" value="3"/><input type="hidden" name="ct" value="2097152"/><input type="hidden" name="s" value="on"/><input class="search-submit" type="submit" value=""/></form></div></div><script>$('input[type=radio][name=search]').change(function() {
1948
+ var val = $(this).val()
1949
+ var self = '<div class="search-form"><input id="local-search-input" placeholder="站内搜索,首次慢" type="search" name="q" results="0"><input class="search-submit" type="submit" value=""/><div id="local-search-result"></div></div>'
1950
+ var google = '<form class="search-form" action="//www.google.com/search" method="get" accept-charset="utf-8" target="_blank"><input type="search" name="q" maxlength="30" placeholder="谷歌全站搜索"><input type="hidden" name="sitesearch" value="xuehuayu.cn"><input class="search-submit" type="submit" value=""/></form>'
1951
+ var baidu = '<form class="search-form" action="//www.baidu.com/baidu" method="get" accept-charset="utf-8" target="_blank"><input type="search" name="word" maxlength="30" placeholder="百度全站搜索"><input type="hidden" name="si" value="xuehuayu.cn"><input type="hidden" name="cl" value="3"><input type="hidden" name="ct" value="2097152"><input type="hidden" name="s" value="on"><input class="search-submit" type="submit" value=""/></form>'
1952
+
1953
+ if (val === 'self') {
1954
+ $('#search').html(self)
1955
+ var search_path = 'search.xml';
1956
+ if (search_path.length == 0) {
1957
+ search_path = 'search.xml';
1958
+ }
1959
+ var path = 'https://cdn.staticaly.com/gh/npljy/npljy.github.io/main/' + search_path;
1960
+ searchFunc(path, 'local-search-input', 'local-search-result');
1961
+ } else if (val === 'baidu') {
1962
+ $('#search').html(baidu)
1963
+ } else if (val === 'google') {
1964
+ $('#search').html(google)
1965
+ }
1966
+ })</script><div class="widget widget-wxmp"><img alt="微信公众号" width="100%" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/mp-mini.jpg"/></div><div class="widget widget-categories"><div class="widget-title"><i class="fa fa-folder-o"> 分类</i></div><ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/CDN/">CDN</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/IDE/">IDE</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/git/">git</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/hexo/">hexo</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%85%AC%E5%85%B1%E8%8A%82%E6%97%A5/">公共节日</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%88%86%E4%BA%AB/">分享</a><span class="category-list-count">29</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%89%8D%E7%AB%AF/">前端</a><span class="category-list-count">191</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%89%8D%E7%AB%AF/%E6%B5%8F%E8%A7%88%E5%99%A8/">浏览器</a><span class="category-list-count">1</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%89%8D%E7%AB%AF/%E6%B5%8F%E8%A7%88%E5%99%A8/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE/">网络协议</a><span class="category-list-count">1</span></li></ul></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%8D%9A%E5%AE%A2/">博客</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%B7%A5%E5%85%B7/">工具</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%B9%BF%E5%91%8A%E8%BF%87%E6%BB%A4/">广告过滤</a><span class="category-list-count">8</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%B9%BF%E5%91%8A%E8%BF%87%E6%BB%A4/%E8%A7%86%E9%A2%91%E7%94%B5%E8%A7%86%E5%B0%8F%E8%AF%B4%E6%BC%AB%E7%94%BB%E8%B5%84%E8%AE%AF%E9%9F%B3%E4%B9%90/">视频电视小说漫画资讯音乐</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E6%AD%A3%E5%88%99/">正则</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E6%B5%8F%E8%A7%88%E5%99%A8/">浏览器</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E7%AE%97%E6%B3%95/">算法</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E8%B5%84%E8%AE%AF/">资讯</a><span class="category-list-count">16</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E8%BD%BB%E6%9D%BE%E4%B8%80%E5%88%BB/">轻松一刻</a><span class="category-list-count">1</span></li></ul></div><div class="widget widget-tags"><div class="widget-title"><i class="fa fa-star-o"> 标签</i></div><div class="tagcloud"><a href="/tags/%E5%8E%9F%E5%88%9B/" style="font-size: 15px;">原创</a> <a href="/tags/%E8%BD%AC%E8%BD%BD/" style="font-size: 15px;">转载</a> <a href="/tags/%E6%89%8B%E5%86%99/" style="font-size: 15px;">手写</a> <a href="/tags/%E7%96%AB%E6%83%85/" style="font-size: 15px;">疫情</a> <a href="/tags/%E5%A8%B1%E4%B9%90/" style="font-size: 15px;">娱乐</a></div></div><div class="widget widget-recent-posts"><div class="widget-title"><i class="fa fa-file-o"> 最近文章</i></div><ul class="post-list"><li class="post-list-item"><a class="post-list-link" href="/article/c5576490.html">面试准备</a></li><li class="post-list-item"><a class="post-list-link" href="/article/84c9ccd6.html">精读《SolidJS》</a></li><li class="post-list-item"><a class="post-list-link" href="/article/53803e6.html">git提交注释规范</a></li><li class="post-list-item"><a class="post-list-link" href="/article/a4145266.html">前端数组拍平flat一行代码</a></li><li class="post-list-item"><a class="post-list-link" href="/article/bedea419.html">一道前端this面试题</a></li><li class="post-list-item"><a class="post-list-link" href="/article/bf7e7421.html">git多账号配置</a></li></ul></div><div class="widget widget-links"><div class="widget-title"><i class="fa fa-external-link"> 友情链接</i></div><ul></ul><a href="https://github.com/npljy?utm_source=xuehuayu.cn" title="GitHub" target="_blank">GitHub</a><ul></ul><a href="https://laonongmin.online?utm_source=xuehuayu.cn" title="看看" target="_blank">看看</a><ul></ul><a href="https://cainiaoblog.cn?utm_source=xuehuayu.cn" title="菜鸟博客" target="_blank">菜鸟博客</a><ul></ul><a href="mailto:cainiaoblog@126.com" title="友链联系" target="_blank">友链联系</a></div></div></div><div class="pure-u-1 pure-u-md-3-4"><div id="footer"><div class="flex-block justify-center align-center flex-wrap"><a class="gxba-link" id="gxba" rel="nofollow" target="_blank" href="http://beian.miit.gov.cn/">京ICP备20007647号-2</a><a class="gaba-link" id="gaba-link" rel="nofollow" target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11010802031264"><img class="nofancybox" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/gaba.png" alt=""/><span id="gaba">京公网安备 11010802031264号</span><span style="padding-right: 10px;"></span></a><span>Copyright © 2023 </span><a href="/." rel="nofollow">前端壹菜鸟. </a><script>(function(){
1967
+ var cnb =window.location.origin.indexOf('cainiaoblog') !==-1
1968
+ if (cnb) {
1969
+ var gxba =document.getElementById('gxba')
1970
+ var gaba =document.getElementById('gaba')
1971
+ var gabaLink =document.getElementById('gaba-link')
1972
+ gxba.innerText ='京ICP备20007647号-1'
1973
+ gaba.innerText ='京公网安备 11010802031254号'
1974
+ gabaLink.setAttribute('href','http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11010802031254')
1975
+ }
1976
+ })()</script></div><div class="flex-block justify-center align-center flex-wrap"><a rel="nofollow" target="_blank" href="https://v6.51.la/s/Guz3lwHCsVme9Cu"><div class="busuanzi_container" id="busuanzi_container"><span class="busuanzi_container_site_pv" id="busuanzi_container_site_pv">访问量:<span id="busuanzi_value_site_pv"><i class="fa fa-spinner"></i></span></span><span class="busuanzi_container_site_uv" id="busuanzi_container_site_uv">访客数:<span id="busuanzi_value_site_uv"><i class="fa fa-spinner"></i></span></span><span style="padding-right: 10px;"></span></div></a><a rel="nofollow" target="_blank" href="https://www.upyun.com/?utm_source=lianmeng&amp;utm_medium=referral"><span style="font-weight:bold;letter-spacing: 1px;">本网站由 </span><img class="nofancybox" height="32" style="vertical-align: middle" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/upy_logo.min.svg" alt=""/><span style="font-weight:bold;letter-spacing: 1px;">提供CDN加速/云存储服务</span></a><span style="padding-right: 10px;"></span><a rel="nofollow" style="font-size:18px;font-weight:bold;vertical-align: middle" target="_blank" title="注册就送代金券可直接使用" href="https://console.upyun.com/register/?invite=HyDsjZHIL">注册</a></div></div></div></div><a class="show" id="rocket" href="#top"></a><div class="darkmode-toggle">🌓</div><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/totop.min.js" async></script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/dark.min.js" async></script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/codeblock-resizer.min.js"></script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/smartresize.min.js"></script></div></body></html>