Repository: suoyuesmile/full-stack-developer Branch: master Commit: 6068b6934e0b Files: 389 Total size: 14.3 MB Directory structure: gitextract_o3sr3lo_/ ├── .gitattributes ├── .gitignore ├── .vscode/ │ └── launch.json ├── README.md ├── articals/ │ ├── c/ │ │ ├── Demo/ │ │ │ ├── argv[2] │ │ │ ├── bug1.c │ │ │ ├── mywords │ │ │ ├── test.c │ │ │ ├── test10.c │ │ │ ├── test11.c │ │ │ ├── test12.c │ │ │ ├── test13.c │ │ │ ├── test14.c │ │ │ ├── test15.c │ │ │ ├── test16.c │ │ │ ├── test17.c │ │ │ ├── test18.c │ │ │ ├── test19.c │ │ │ ├── test2.c │ │ │ ├── test20.c │ │ │ ├── test21.c │ │ │ ├── test22.c │ │ │ ├── test23.c │ │ │ ├── test24.c │ │ │ ├── test25.c │ │ │ ├── test26.c │ │ │ ├── test27.c │ │ │ ├── test28.c │ │ │ ├── test29.c │ │ │ ├── test3.c │ │ │ ├── test30.c │ │ │ ├── test31.c │ │ │ ├── test32.c │ │ │ ├── test33.c │ │ │ ├── test34.c │ │ │ ├── test35.c │ │ │ ├── test36.c │ │ │ ├── test37.c │ │ │ ├── test38.c │ │ │ ├── test39.c │ │ │ ├── test4.c │ │ │ ├── test40.c │ │ │ ├── test41.c │ │ │ ├── test42.c │ │ │ ├── test43.c │ │ │ ├── test44.c │ │ │ ├── test45.c │ │ │ ├── test46.c │ │ │ ├── test47.c │ │ │ ├── test48.c │ │ │ ├── test49.c │ │ │ ├── test5.c │ │ │ ├── test50.c │ │ │ ├── test51.c │ │ │ ├── test52.c │ │ │ ├── test53.c │ │ │ ├── test54.c │ │ │ ├── test55.c │ │ │ ├── test56.c │ │ │ ├── test57.c │ │ │ ├── test58.c │ │ │ ├── test59.c │ │ │ ├── test6.c │ │ │ ├── test60.c │ │ │ ├── test61.c │ │ │ ├── test62.c │ │ │ ├── test63.c │ │ │ ├── test64.c │ │ │ ├── test65.c │ │ │ ├── test66.c │ │ │ ├── test67.c │ │ │ ├── test68.c │ │ │ ├── test69.c │ │ │ ├── test7.c │ │ │ ├── test70.c │ │ │ ├── test71.c │ │ │ ├── test72.c │ │ │ ├── test73.c │ │ │ ├── test74.c │ │ │ ├── test75.c │ │ │ ├── test76.c │ │ │ ├── test77.c │ │ │ ├── test78.c │ │ │ ├── test79.c │ │ │ ├── test8.c │ │ │ ├── test80.c │ │ │ ├── test81.c │ │ │ ├── test82.c │ │ │ ├── test83.c │ │ │ ├── test84.c │ │ │ ├── test85.c │ │ │ ├── test86.c │ │ │ ├── test87.c │ │ │ ├── test88.c │ │ │ ├── test89.c │ │ │ ├── test9.c │ │ │ ├── test90.c │ │ │ ├── test91.c │ │ │ ├── test91.h │ │ │ ├── test92.c │ │ │ ├── test93.c │ │ │ ├── test94.c │ │ │ ├── test95.c │ │ │ ├── test96.c │ │ │ ├── test97.c │ │ │ ├── test98.c │ │ │ ├── test99.c │ │ │ ├── testDice_d.c │ │ │ ├── testFgets.c │ │ │ ├── testFgets2.c │ │ │ ├── testFgets3.c │ │ │ ├── testFileIO.c │ │ │ ├── testGets.c │ │ │ ├── testIO.c │ │ │ ├── testP02.c │ │ │ ├── testPntAdd.c │ │ │ ├── testPo.c │ │ │ ├── testPoint.c │ │ │ ├── testPrintfScanf.c │ │ │ ├── testR_d.c │ │ │ ├── testRand.c │ │ │ ├── testRandom.c │ │ │ ├── testRecursion.c │ │ │ ├── testReducto.c │ │ │ ├── testScope.c │ │ │ ├── testStrSort.c │ │ │ ├── testSwap.c │ │ │ ├── testToBinary.c │ │ │ ├── words │ │ │ ├── words.red │ │ │ └── wordscp │ │ ├── array.md │ │ ├── data.md │ │ ├── fileIO.md │ │ ├── function.md │ │ ├── memory.md │ │ └── string.md │ ├── c++/ │ │ ├── class.md │ │ ├── function.md │ │ ├── oop.md │ │ ├── reload.md │ │ ├── str_map_arr.md │ │ └── var.md │ ├── h5/ │ │ ├── 0001.md │ │ ├── 0002.md │ │ └── 0003.md │ ├── interview/ │ │ └── 0001.md │ ├── js/ │ │ ├── 0001.md │ │ └── 0002.md │ ├── react/ │ │ └── 0001.md │ └── vue/ │ ├── 0001.md │ └── 0002.md ├── booknotes/ │ ├── bst.md │ ├── compute.md │ ├── demo/ │ │ ├── AVL.class.cpp │ │ ├── BST.class.cpp │ │ ├── BTNode.h │ │ ├── BTree.class.cpp │ │ ├── BinNode.h │ │ ├── BinTree.class.cpp │ │ ├── Edge.h │ │ ├── Graph.class.cpp │ │ ├── GraphMatrix.class.cpp │ │ ├── Lcs.cpp │ │ ├── List.class.cpp │ │ ├── ListNode.h │ │ ├── Node.h │ │ ├── PQ.class.cpp │ │ ├── PQ_ComplHeap.class.cpp │ │ ├── Queue.class.cpp │ │ ├── RedBlack.class.cpp │ │ ├── SList.class.cpp │ │ ├── Splay.class.cpp │ │ ├── Stack.class.cpp │ │ ├── Vector.class.cpp │ │ ├── VectorTest.cpp │ │ ├── Vertex.h │ │ ├── a_bubbleSort.cpp │ │ ├── a_convert.cpp │ │ ├── a_evaluate.cpp │ │ ├── a_fib.cpp │ │ ├── a_hailstone.cpp │ │ ├── a_paren.cpp │ │ ├── a_sum.cpp │ │ ├── a_vector.cpp │ │ └── sort.cpp │ ├── graph.md │ ├── hash.md │ ├── list.md │ ├── proqueue.md │ ├── sort.md │ ├── string.md │ ├── sum.md │ ├── superBST.md │ ├── tree.md │ └── vector.md ├── package.json ├── public/ │ └── html/ │ ├── demo-box-model.html │ ├── demo-display.html │ ├── demo-float.html │ ├── demo-position.html │ └── layout.css ├── src/ │ ├── README.md │ ├── algorithm/ │ │ ├── array/ │ │ │ ├── insert.js │ │ │ └── searchInsert.js │ │ ├── search/ │ │ │ └── binsearch.js │ │ ├── sort/ │ │ │ ├── bubblesort.js │ │ │ └── quicksort.js │ │ └── string/ │ │ └── repeat.js │ ├── babel/ │ │ └── tiny-compiler/ │ │ └── index.js │ ├── cryto/ │ │ └── sha256.js │ ├── css/ │ │ ├── box-model.html │ │ ├── center.html │ │ ├── flex.html │ │ ├── float.html │ │ ├── hairline.html │ │ ├── layout.html │ │ ├── three-layout.html │ │ ├── two-layout.html │ │ └── var.html │ ├── data-structure/ │ │ ├── linklist-circle.js │ │ ├── linklist-curd.js │ │ ├── linklist.js │ │ └── list.js │ ├── javascript/ │ │ ├── array.js │ │ ├── async_sync.js │ │ ├── block-scope.js │ │ ├── call.js │ │ ├── callback.js │ │ ├── class/ │ │ │ └── construct.js │ │ ├── class.js │ │ ├── closure/ │ │ │ ├── closure-circle.js │ │ │ └── proxy.js │ │ ├── code/ │ │ │ ├── huiwen-longest-str.js │ │ │ ├── is-huiwen-num.js │ │ │ ├── is-huiwen-string.js │ │ │ ├── longest-asc-str.js │ │ │ ├── longest-norepeat-str.js │ │ │ ├── merge-two-array.js │ │ │ ├── merge-two-lists.js │ │ │ ├── two-nums-2.js │ │ │ ├── two-nums-add.js │ │ │ ├── two-nums.js │ │ │ └── valid-parent.js │ │ ├── curry.js │ │ ├── debounce.js │ │ ├── dom.js │ │ ├── event-loop.js │ │ ├── event.js │ │ ├── flat.js │ │ ├── function-scope.js │ │ ├── function-this.js │ │ ├── hoisting.js │ │ ├── implement/ │ │ │ ├── apply.js │ │ │ ├── async.js │ │ │ ├── bind.js │ │ │ ├── class.js │ │ │ ├── compose.js │ │ │ ├── copy.js │ │ │ ├── inherit.js │ │ │ ├── new.js │ │ │ ├── pipe.js │ │ │ ├── promise.js │ │ │ ├── reduce.js │ │ │ └── sleep.js │ │ ├── inherit.js │ │ ├── map.js │ │ ├── new.js │ │ ├── object/ │ │ │ ├── copy.js │ │ │ ├── enum.js │ │ │ ├── exist.js │ │ │ ├── get-set.js │ │ │ ├── iterator.js │ │ │ ├── property-desciptor.js │ │ │ └── traverse.js │ │ ├── promise.js │ │ ├── proto.js │ │ ├── proxy/ │ │ │ └── base.js │ │ ├── recursion/ │ │ │ └── base.js │ │ ├── regExp.js │ │ ├── scope.js │ │ ├── set/ │ │ │ └── set.js │ │ ├── set.js │ │ ├── sleep.js │ │ ├── string.js │ │ ├── this.js │ │ ├── throttle.js │ │ ├── type.js │ │ └── uniqu.js │ ├── json/ │ │ ├── data.json │ │ ├── distinct_data.json │ │ ├── manage__origin_data.json │ │ ├── manage_cata_data.js │ │ └── manage_cata_data.json │ ├── koa/ │ │ ├── db/ │ │ │ └── index.js │ │ └── index.js │ ├── leetcode/ │ │ ├── 1.两数之和.js │ │ ├── 13.罗马数字转整数.js │ │ ├── 14.最长公共前缀.js │ │ ├── 165.比较版本号.js │ │ ├── 2.两数相加.js │ │ ├── 20.有效的括号.js │ │ ├── 21.合并两个有序链表.js │ │ ├── 26.删除排序数组中的重复项.js │ │ ├── 27.移除元素.js │ │ ├── 28.实现-str-str.js │ │ ├── 3.无重复字符的最长子串.js │ │ ├── 341.扁平化嵌套列表迭代器.js │ │ ├── 35.搜索插入位置.js │ │ ├── 38.外观数列.js │ │ ├── 53.最大子序和.js │ │ ├── 58.最后一个单词的长度.js │ │ ├── 66.加一.js │ │ ├── 67.二进制求和.js │ │ ├── 69.x-的平方根.js │ │ ├── 7.整数反转.js │ │ └── 9.回文数.js │ ├── linux/ │ │ └── process_manage.sh │ ├── node/ │ │ ├── api-test/ │ │ │ └── image.js │ │ ├── app/ │ │ │ ├── index.js │ │ │ ├── requestHandles.js │ │ │ ├── router.js │ │ │ └── server.js │ │ ├── file/ │ │ │ ├── file-download.js │ │ │ └── file-read.js │ │ └── node-fetch/ │ │ └── index.js │ ├── question/ │ │ └── interserction.js │ ├── react/ │ │ ├── app/ │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ ├── index.html │ │ │ │ ├── manifest.json │ │ │ │ └── robots.txt │ │ │ └── src/ │ │ │ ├── antd/ │ │ │ │ ├── searchDemo.js │ │ │ │ └── upload.js │ │ │ ├── antd-mobile/ │ │ │ │ ├── input.js │ │ │ │ ├── picker-demo.js │ │ │ │ ├── steps-demo.js │ │ │ │ └── steps-demo.scss │ │ │ ├── assets/ │ │ │ │ ├── font/ │ │ │ │ │ └── PingFangSC-Regular.fft │ │ │ │ └── scss/ │ │ │ │ └── font.scss │ │ │ ├── components/ │ │ │ │ ├── count-down.js │ │ │ │ ├── steps-hooks.js │ │ │ │ ├── steps.js │ │ │ │ └── steps.scss │ │ │ ├── examples/ │ │ │ │ └── steps-demo.js │ │ │ ├── font/ │ │ │ │ └── pingfangsc-demo.js │ │ │ ├── index.js │ │ │ ├── paratice/ │ │ │ │ ├── hook.js │ │ │ │ ├── index.css │ │ │ │ ├── index.js │ │ │ │ └── lasy-compontent.js │ │ │ ├── redux.js │ │ │ ├── router/ │ │ │ │ ├── index.js │ │ │ │ └── index.scss │ │ │ ├── serviceWorker.js │ │ │ └── setupTests.js │ │ ├── demo.html │ │ └── demo.jsx │ ├── shell/ │ │ └── image_filter.sh │ ├── typescript/ │ │ ├── js/ │ │ │ ├── class-demo.js │ │ │ ├── decorators-demo.js │ │ │ ├── demo.js │ │ │ ├── fn-demo.js │ │ │ ├── function-demo.js │ │ │ ├── generics-demo.js │ │ │ ├── interface-demo.js │ │ │ ├── overload-demo.js │ │ │ ├── type-advanced-demo.js │ │ │ ├── type-demo.js │ │ │ └── type-inference-demo.js │ │ └── ts/ │ │ ├── class-demo.ts │ │ ├── decorators-demo.ts │ │ ├── demo.ts │ │ ├── function-demo.ts │ │ ├── generics-demo.ts │ │ ├── interface-demo.ts │ │ ├── overload-demo.ts │ │ ├── tsconfig.json │ │ ├── type-advanced-demo.ts │ │ ├── type-demo.ts │ │ └── type-inference-demo.ts │ ├── web-api/ │ │ ├── localstorage.js │ │ └── sessionstorage.js │ └── webpack/ │ └── simple-webpack/ │ ├── buddle.js │ └── example/ │ ├── entry.js │ ├── message.js │ └── name.js └── yarn-error.log ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ *.js linguist-language=JavaScript *.css linguist-language=JavaScript *.html linguist-language=JavaScript *.c linguist-language=JavaScript *.c++ linguist-language=JavaScript *.php linguist-language=JavaScript *.python linguist-language=JavaScript *.scss linguist-language=JavaScript ================================================ FILE: .gitignore ================================================ /node_modules /json private-* ================================================ FILE: .vscode/launch.json ================================================ { "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Launch Program", "program": "${file}" } ] } ================================================ FILE: README.md ================================================ :rocket: _It's my records of the journey from phper to fronter, now sharing to you and hoping that these make sence for you. if you like it, please star it! Thank You!_ 本博客将持续更新,喜欢请收藏STAR一下,更多内容在[suosmile](https://github.com/suoyuesmile)关注一下,谢谢~:yum:

微信群 公众号

文章将优先发布于掘金平台,点击关注掘金账号哦。如果需要接受通知请关注微信公众号@前端攻城狗!

公众号

## 前端技术实战、研究总结 ### 个人技术博客文章列表 | 编号 | 名称 | 状态 | | ---- | ---------------------------------------------------------------------------------------- | ---- | | 0001 | [记一次忏悔的前端面试经验(Vue 双向绑定原理)](articals/vue/0001.md) | 完成 | | 0002 | [关于这些天杭州各厂面试汇总(从JavaScript各种原理到框架源码](articals/interview/0001.md) | 完成 | | 0003 | [3个小时能把 React 学到哪种程度?](articals/react/0001.md) | 完成 | | 0004 | [如何让 Promise 控制业务流程(Re 同步异步 开始一步一步深入)](articals/js/0001.md) | 完成 | | 0005 | [理解promise、 generator 、async & await 之间的联系](articals/js/0002.md) | 完成 | | 0006 | [吃透移动端 1px](articals/h5/0001.md) | 完成 | | 0007 | [吃透移动端 H5 响应式布局](articals/h5/0002.md) | 完成 | | 0008 | [吃透移动端 H5 与 hybrid](articals/h5/0003.md) | 完成 | | 0009 | [吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧《上》](articals/vue/0002.md) | 完成 | | 0010 | [吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧《中》](https://juejin.im/post/5e15932ee51d4540f02fae27) | 完成 | | 0011 | [吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧《下》](https://juejin.im/post/5e1eb1dff265da3e354ea2d0) | 完成 | | 0012 | [杭州前端面试通关新手入门指南](https://juejin.im/user/59a3e1de51882524401237cf) | 完成 | | 0013 | [TypeScript 语言精髓与项目实战]() | 10月计划 | | 0014 | [Vue 到 React 全面比较与上手指南]() | 10月计划 | | 0015 | [Node 入门练习]() | 10月计划 | | 0016 | [前端技术框架与架构的思索与探索]() | 10月计划 | ### 每日一个编程小题 | 编号 | 名称 | 状态 | 难度 | | ---- | ------------------------------------------------------ | ---- | ---- | | 0001 | [1.两数相加](https://github.com/suoyuesmile/suo-blog/blob/master/src/leetcode/1.两数之和.js) | 完成 | 简单 | | 0002 | [7.整数反转](https://github.com/suoyuesmile/suo-blog/blob/master/src/leetcode/7.整数反转.js) | 完成 | 简单 | | 0003 | [9.回文数](https://github.com/suoyuesmile/suo-blog/blob/master/src/leetcode/9.回文数.js) | 完成 | 简单 | | 0004 | [13.罗马数字转整数](https://github.com/suoyuesmile/suo-blog/blob/master/src/leetcode/13.罗马数字转整数.js) | 完成 | 简单 | | 0005 | [14.最长公共前缀](https://github.com/suoyuesmile/suo-blog/blob/master/src/leetcode/14.最长公共前缀.js) | 完成 | 简单 | | 0006 | [20.有效的括号](https://github.com/suoyuesmile/suo-blog/blob/master/src/leetcode/20.有效的括号.js) | 完成 | 简单 | | 0007 | [26.删除排序数组中的重复项](https://github.com/suoyuesmile/suo-blog/blob/master/src/leetcode/26.删除排序数组中的重复项.js) | 完成 | 简单 | | 0008 | [27.移除元素](https://github.com/suoyuesmile/suo-blog/blob/master/src/leetcode/27.移除元素.js) | 完成 | 简单 | | 0009 | [28.实现-str-str](https://github.com/suoyuesmile/suo-blog/blob/master/src/leetcode/28.实现-str-str.js) | 完成 | 简单 | | 0010 | [35.搜索插入位置](https://github.com/suoyuesmile/suo-blog/blob/master/src/leetcode/35.搜索插入位置.js) | 完成 | 简单 | | 0011 | [58.最后一个单词的长度](https://github.com/suoyuesmile/suo-blog/blob/master/src/leetcode/58.最后一个单词的长度.js) | 完成 | 简单 | | 0012 | [66.加一](https://github.com/suoyuesmile/suo-blog/blob/master/src/leetcode/66.加一.js) | 完成 | 简单 | ### 前端开放研究点 todo #### JavaScript | 编号 | 名称 | 状态 | | ---- | ----------------------------------- | ---- | | 0001 | [闭包](articals/js/0002.md) | 10月计划 | | 0002 | [this](articals/js/0002.md) | 10月计划 | | 0003 | [new](articals/js/0002.md) | 10月计划 | | 0004 | [深浅拷贝](articals/js/0002.md) | 10月计划 | | 0005 | [promise](articals/js/0002.md) | 计划 | | 0006 | [async、await](articals/js/0002.md) | 计划 | | 0007 | [原型与原型链](articals/js/0002.md) | 计划 | | 0008 | [继承](articals/js/0002.md) | 计划 | | 0009 | [防抖与节流](articals/js/0002.md) | 计划 | | 0010 | [类型判断](articals/js/0002.md) | 计划 | | 0011 | [运行机制](articals/js/0002.md) | 计划 | #### CSS | 编号 | 名称 | 状态 | | ---- | ----------------------------------- | ---- | | 0001 | [常用开发技巧](articals/js/0002.md) | 10月计划 | | 0002 | [BFC](articals/js/0002.md) | 10月计划 | | 0003 | [布局](articals/js/0002.md) | 10月计划 | | 0004 | [flexbox](articals/js/0002.md) | 10月计划 | | 0005 | [计量单位](articals/js/0002.md) | 计划 | | 0006 | [提升UI效果](articals/js/0002.md) | 计划 | | 0007 | [对齐](articals/js/0002.md) | 计划 | | 0008 | [过渡与动画](articals/js/0002.md) | 计划 | | 0009 | [预编译](articals/js/0002.md) | 计划 | | 0010 | [高级用法](articals/js/0002.md) | 计划 | #### HTML | 编号 | 名称 | 状态 | | ---- | ----------------------------------- | ---- | | 0001 | [常用开发技巧](articals/js/0002.md) | 10月计划 | | 0002 | [语义化开发](articals/js/0002.md) | 10月计划 | | 0003 | [块级与内联](articals/js/0002.md) | 10月计划 | | 0004 | [DOM 树分析](articals/js/0002.md) | 10月计划 | | 0004 | [PUG 相关](articals/js/0002.md) | 10月计划 | #### TypeScript | 编号 | 名称 | 状态 | | ---- | ----------------------------------- | ---- | | 0001 | [常用开发技巧](articals/js/0002.md) | 10月计划 | | 0002 | [类型增强与推断](articals/js/0002.md) | 10月计划 | | 0003 | [面向对象开发](articals/js/0002.md) | 10月计划 | | 0004 | [高级技巧](articals/js/0002.md) | 10月计划 | | 0004 | [装饰器](articals/js/0002.md) | 10月计划 | #### Node | 编号 | 名称 | 状态 | | ---- | ----------------------------------- | ---- | | 0001 | [常用开发技巧](articals/js/0002.md) | 10月计划 | | 0002 | [服务提供](articals/js/0002.md) | 10月计划 | | 0003 | [面向对象开发](articals/js/0002.md) | 10月计划 | | 0004 | [高级技巧](articals/js/0002.md) | 10月计划 | | 0004 | [装饰器](articals/js/0002.md) | 10月计划 | #### Vue | 编号 | 名称 | 状态 | | ---- | ----------------------------------- | ---- | | 0001 | [常用开发技巧](articals/js/0002.md) | 10月计划 | | 0002 | [服务提供](articals/js/0002.md) | 10月计划 | | 0003 | [面向对象开发](articals/js/0002.md) | 10月计划 | | 0004 | [高级技巧](articals/js/0002.md) | 10月计划 | | 0004 | [装饰器](articals/js/0002.md) | 10月计划 | #### React | 编号 | 名称 | 状态 | | ---- | ----------------------------------- | ---- | | 0001 | [常用开发技巧](articals/js/0002.md) | 10月计划 | | 0002 | [服务提供](articals/js/0002.md) | 10月计划 | | 0003 | [面向对象开发](articals/js/0002.md) | 10月计划 | | 0004 | [高级技巧](articals/js/0002.md) | 10月计划 | | 0004 | [装饰器](articals/js/0002.md) | 10月计划 | #### Webpack | 编号 | 名称 | 状态 | | ---- | ----------------------------------- | ---- | | 0001 | [常用开发技巧](articals/js/0002.md) | 10月计划 | | 0002 | [服务提供](articals/js/0002.md) | 10月计划 | | 0003 | [面向对象开发](articals/js/0002.md) | 10月计划 | | 0004 | [高级技巧](articals/js/0002.md) | 10月计划 | | 0004 | [装饰器](articals/js/0002.md) | 10月计划 | #### 浏览器 | 编号 | 名称 | 状态 | | ---- | ----------------------------------- | ---- | | 0001 | [常用开发技巧](articals/js/0002.md) | 10月计划 | | 0002 | [服务提供](articals/js/0002.md) | 10月计划 | | 0003 | [面向对象开发](articals/js/0002.md) | 10月计划 | | 0004 | [高级技巧](articals/js/0002.md) | 10月计划 | | 0004 | [装饰器](articals/js/0002.md) | 10月计划 | ## 编程基础笔记 ### c & c++ | c | c++ | | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | [c语言基础之数据类型](articals/c/data.md) | [c++变量解析](articals/c++/var.md) | | [c数组](articals/c/array.md) | [c++数组、向量、字符串](articals/c++/str_map_arr.md) | | [c函数](articals/c/function.md) | [c++函数](articals/c++/function.md) | | [c字符串](articals/c/string.md) | [c++类](articals/c++/class.md) | | [c内存管理](articals/c/memory.md) | [c++面向对象](articals/c++/oop.md) | | [c文件IO](articals/c/fileIO.md) | [c++操作符重载](articals/c++/reload.md) | | **Reference** | **Reference** | | [c/c++ 中文参考手册](http://zh.cppreference.com/) | [c 语言编程透视](https://www.gitbook.com/book/tinylab/cbook/details) | | [c++ 并发编程指南](https://github.com/forhappy/Cplusplus-Concurrency-In-Practice) | [Linux C编程一站式学习](http://akaedu.github.io/book/) | | [100个gdb小技巧](https://github.com/hellogcc/100-gdb-tips/blob/master/src/index.md) | [100个gcc小技巧](https://github.com/hellogcc/100-gcc-tips/blob/master/src/index.md) | | [c/c++ Primer](https://github.com/andycai/cprimer) | [C++ Primer 5th Answers](https://github.com/Mooophy/Cpp-Primer) | | [---------------表格内容填充物----------------]() | [---------------表格内容填充物----------------]() | ### 数据结构 & 算法 | 数据结构 | 算法 | | ------------------------------------------------------- | ------------------------------------------------------------------------------ | | [数据结构之向量](src/note/vector.md) | [算法与数据结构知识归纳整理](src/note/sum.md) | | [数据结构之列表](src/note/list.md) | [用来度量算法好坏的方法](src/note/computer.md) | | [数据结构之二叉树](src/note/tree.md) | [算法之排序](http://blog.csdn.net/hguisu/article/details/7776068) | | [数据结构之图](src/note/graph.md) | [以串为基础的算法](src/note/string.md) | | [数据结构之二叉搜索树](src/note/bst.md) | [算法之递归](http://www.cnblogs.com/xiaoliu66007/p/3927111.html) | | [数据结构之高级搜索树](src/note/superBST.md) | [算法之迭代](http://blog.csdn.net/l979951191/article/details/47659777) | | [数据结构之优先级队列](src/note/proqueue.md) | [算法之动态规划](https://www.zhihu.com/question/23995189) | | [数据结构之散列表](src/note/hash.md) | [算法之贪心算法](http://blog.csdn.net/effective_coder/article/details/8736718) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ### 编译原理相关 | 编译原理 | | | ------------------------------------------------------- | ------------------------------------------------------------------------------ | | [数据结构之向量](src/note/vector.md) | [算法与数据结构知识归纳整理](src/note/sum.md) | | [数据结构之列表](src/note/list.md) | [用来度量算法好坏的方法](src/note/computer.md) | | [数据结构之二叉树](src/note/tree.md) | [算法之排序](http://blog.csdn.net/hguisu/article/details/7776068) | | [数据结构之图](src/note/graph.md) | [以串为基础的算法](src/note/string.md) | | [数据结构之二叉搜索树](src/note/bst.md) | [算法之递归](http://www.cnblogs.com/xiaoliu66007/p/3927111.html) | | [数据结构之高级搜索树](src/note/superBST.md) | [算法之迭代](http://blog.csdn.net/l979951191/article/details/47659777) | | [数据结构之优先级队列](src/note/proqueue.md) | [算法之动态规划](https://www.zhihu.com/question/23995189) | | [数据结构之散列表](src/note/hash.md) | [算法之贪心算法](http://blog.csdn.net/effective_coder/article/details/8736718) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ## 入门资料收集 ### HTML & CSS 简单入门 | Reference | Reference | | ---------------------------------------------------------------------- | ----------------------------------------------------------- | | [W3C入门手册教程]() | [CSS语法参考](http://tympanus.net/codrops/css_reference) | | [MDN HTML 中文文档](https://developer.mozilla.org/zh-CN/docs/Web/HTML) | [CSS3动画手册](http://isux.tencent.com/css3/index.html) | | [HTML和CSS编码规范](http://codeguide.bootcss.com/) | [CSS3动画制作工具](http://isux.tencent.com/css3/tools.html) | | [学习CSS布局](http://zh.learnlayout.com/) | [Emmet 文档](http://yanxyz.github.io/emmet-docs/) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ### JavaScript & jQuery 基础入门 | Article | Article | | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | [JavaScript继承设计机制](https://github.com/suoyuesmile/full-stack-developer/issues/14) | [JavaScript同源策略与规避](https://github.com/suoyuesmile/full-stack-developer/issues/15) | | [jQuery设计思想](https://github.com/suoyuesmile/full-stack-developer/issues/12) | [jQuery最佳实践](https://github.com/suoyuesmile/full-stack-developer/issues/13) | | [JavaScript严格模式](https://github.com/suoyuesmile/full-stack-developer/issues/10) | [JavaScript快速排序](https://github.com/suoyuesmile/full-stack-developer/issues/11) | | [JavaScript模块化编程](https://github.com/suoyuesmile/full-stack-developer/issues/8) | [JavaScript异步编程 ](https://github.com/suoyuesmile/full-stack-developer/issues/9) | | [JavaScript的this用法](https://github.com/suoyuesmile/full-stack-developer/issues/6) | [JavaScript定义类的方法](https://github.com/suoyuesmile/full-stack-developer/issues/7) | | [JavaScript面向对象编程](https://github.com/suoyuesmile/full-stack-developer/issues/4) | [JavaScript闭包原理与分析](https://github.com/suoyuesmile/full-stack-developer/issues/5) | | Reference | Reference | | [廖雪峰JavaScript全栈教程](http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000) | [jQuery 解构](http://www.cn-cuckoo.com/deconstructed/jquery.html) | | [阮一峰 JavaScript基础教程](http://javascript.ruanyifeng.com) | [简单易懂的JQuery魔法](http://www.nowamagic.net/librarys/books/contents/jquery) | | [JavaScript中的this陷阱的最全收集](https://segmentfault.com/a/1190000002640298) | [How to write jQuery plugin](http://i5ting.github.io/How-to-write-jQuery-plugin/build/jquery.plugin.html) | | [Promise迷你书(中文版](http://liubin.github.io/promises-book) | [You Don't Need jQuery](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md) | | [前端框架最新排名 TOP 100](https://www.awesomes.cn/rank) | [如何实现一个类jQuery?](https://github.com/MeCKodo/forchange) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ### PHP 基础入门 | Reference | Reference | | ------------------------------------------------------- | --------------------------------------------------------- | | [w3c中php快速入门手册](http://www.w3school.com.cn/php/) | [ThinkPHP 入门视频教程(网盘)]() | | [学习php的正确道路 ](http://www.phptherightway.com/) | [PHP 官方手册](http://php.net/manual/zh/) | | [php官方组成员鸟哥的博客](http://www.laruence.com/ ) | [深入理解PHP内核](https://github.com/reeze/tipi) | | [最热门php开发社区:phpchina](http://www.phpchina.com/) | [PHP扩展开发及内核应用](http://www.walu.cc/phpbook/) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ### MySQL & Web Server 基础入门 | Reference | Reference | | --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | [21分钟MySQL入门教程](http://www.cnblogs.com/mr-wid/archive/2013/05/09/3068229.html) | [Apache Spark 设计与实现](https://github.com/JerryLead/SparkInternals/tree/master/markdown) | | [MySQL慕课网中免费进阶教程]() | [Nginx开发从入门到精通](http://tengine.taobao.org/book/index.html) | [Nginx教程从入门到精通](http://www.ttlsa.com/nginx/nginx-stu-pdf/) | | [常用sql语句大集合]() | [OpenResty最佳实践](https://www.gitbook.com/book/moonbingbing/openresty-best-practices/details) | | [MySQL索引数据结构及算法原理](http://blog.codinglabs.org/articles/theory-of-mysql-index.html) | [Apache 中文手册](http://works.jinbuguo.com/apache/menu22/index.html) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ### Laravel & Yii 基础入门 | Reference | Reference | | -------------------------------------------------------- | --------------------------------------------------------- | | [Laravel5.1 中文文档](http://laravel-china.org/docs/5.1) | [YiiBook几本Yii框架的在线教程](http://yiibook.com//doc) | | [Laravel 5.1 LTS 速查表](https://cs.phphub.org/) | [深入理解 Yii 2.0](http://www.digpage.com/) | | [Laravel 最大的中国开发者社区]() | [Yii 框架中文文檔](http://www.yiichina.com/) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ### Linux & Git 基础入门 | Reference | Reference | | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | [Linux安装镜像(Unbutu16)]() | [Git window安装包]() | | [鸟哥的Linux私房菜](http://vbird.dic.ksu.edu.tw/) | [Pro Git 中文版](https://www.gitbook.com/book/0532/progit/details) | | [The Linux Command Line](http://billie66.github.io/TLCL/index.html) | [猴子都能懂的GIT入门](http://backlogtool.com/git-guide/cn/) | | [UNIX TOOLBOX](http://cb.vu/unixtoolbox_zh_CN.xhtml) | [廖雪峰Git教程](http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ### Sublime & Vim 简单使用 | Reference | Reference | | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------- | | [Sublime使用技巧之快捷键](http://www.jb51.net/softjc/180873.html) | [exvim--vim 改良成IDE项目](http://exvim.github.io/docs-zh/intro/) | | [Sublime插件大全](http://www.oschina.net/translate/20-powerful-sublimetext-plugins) | [Vim中文文档](https://github.com/vimcn/vimcdoc) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ### Markdown 简单使用 | Reference | Reference | | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | [Markdown 语法说明 (简体中文版)](http://wowubuntu.com/markdown) | [Markdown入门参考](https://github.com/LearnShare/Learning-Markdown/blob/master/README.md) | | [Mdeditor(国内在线markdown编辑器)](https://www.zybuluo.com/mdeditor) | [Stackedit(国外markdown编辑器)](https://stackedit.io) | | [Mditor轻量级的markdown编辑器](http://bh-lay.github.io/mditor) | [lepture-editor](https://github.com/lepture/editor) | | [Markdown-editor](https://github.com/jbt/markdown-editor) | | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ### Weapp 基础教程 | Reference | Reference | | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- | | [微信小程序简易教程](https://mp.weixin.qq.com/debug/wxadoc/dev/index.html?t=2017621) | [微信小程序官方组件库](https://mp.weixin.qq.com/debug/wxadoc/dev/component/text.html) | | [微信小程序入门教程(视频)](http://pan.baidu.com/s/1c1OdUQc) | [有赞小程序ui组件](https://github.com/youzan/zanui-weapp) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ### NodeJS & AngularJS 基础入门 | Reference | Reference | | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------- | | [Node.js 看了就懂系列](https://github.com/alsotang/node-lessons) | [AngularJS最佳实践和风格指南](https://github.com/mgechev/angularjs-style-guide/blob/master/README-zh-cn.md) | | [你信不信5天学会NodeJS](http://nqdeng.github.io/7-days-nodejs/) | [AngularJS中译本](https://github.com/peiransun/angularjs-cn) | | [从零开始的nodejs世界生活](http://blog.fens.me/series-nodejs) | [AngularJS入门教程](https://github.com/zensh/AngularjsTutorial_cn) | | [赶紧的Node.js入门系列](http://www.nodebeginner.org/index-zh-cn.html) | [构建自己的AngularJS](https://github.com/xufei/Make-Your-Own-AngularJS/blob/master/01.md) | | [Node初学者入门,NodeJS教程](http://ourjs.com/detail/529ca5950cb6498814000005) | [在Windows环境下构建AngularJS项目](http://www.waylau.com/build-angularjs-app-with-yeoman-in-windows/) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ### React & Vue 文档 | Reference | Reference | | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | [React教程 我是菜鸟系列](http://www.runoob.com/react/react-tutorial.html) | [Vue官网](http://cn.vuejs.org) | | [React.js快速开始系列](http://www.phperz.com/article/15/0712/140537.html#) | [Awesome-vue这是啥很厉害的样子](https://github.com/vuejs/awesome-vue) | | [轻松入门React和Webpack](https://segmentfault.com/a/1190000002767365) | [Vue开发这论坛](http://forum.vuejs.org) | | [Redux 中文文档](http://cn.redux.js.org/) | [移动端Vue组件集合](https://github.com/ElemeFE/mint-ui ) | | [React介绍及实践教程](http://www.ibm.com/developerworks/cn/web/1509_dongyue_react/index.html) | [桌面端Vue集合](https://github.com/ElemeFE/element) | | [React.js amazeui UI](http://amazeui.org/react) | [Vue菜鸟教程](http://www.runoob.com/w3cnote/vue2-start-coding.html) | | [React Native 中文版](http://wiki.jikexueyuan.com/project/react-native) | [Vue快速入门](http://www.cnblogs.com/rik28/p/6024425.html) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ### Front-end 整理一些资料 | Reference | Reference | | --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | [前端知识汇总](https://github.com/JacksonTian/fks) | [前端开发大系概览图](https://github.com/unruledboy/WebFrontEndStack) | | [免费的编程中文书籍索](https://github.com/justjavac/free-programming-books-zh_CN) | [前端书籍大全](https://github.com/dypsilon/frontend-dev-bookmarks) | | [前端免费书籍大全](https://github.com/vhf/free-programming-books) | [重新介绍JavaScript(JS教程)](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/A_re-introduction_to_JavaScript) | | [Gitbook](https://www.gitbook.com) | [Front-End-Develop 前端开发指南](https://github.com/Front-End-Developers-Hunan/Front-End-Develop-Guide) | | [前端开发笔记本](https://li-xinyang.gitbooks.io/frontend-notebook/content) | [大前端工具集](https://github.com/nieweidong/fetool) | | [前端开发者手册](https://dwqs.gitbooks.io/frontenddevhandbook/content) | [结合个人经历总结的前端入门方法](https://github.com/qiu-deqing/FE-learning) | | [前端学习计划](http://blog.csdn.net/qq_25827845/article/details/53079094) | [前端知识体系图](img/qian.jpg) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ### Front-end 规范相关 | Reference | Reference | | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | [github工程师代码书写习惯](http://alloyteam.github.io/CodeGuide/) | [HTML&CSS编码规范 by @mdo](http://codeguide.bootcss.com) | | [前端编码规范之js - by yuwenhui](http://yuwenhui.github.io) | [前端编码规范之js - by 李靖](http://www.cnblogs.com/hustskyking/p/javascript-spec.html) | | [Airbnb JavaScript 编码规范](https://github.com/yuche/javascript#table-of-contents) | [AMD与CMD规范的区别](http://www.zhihu.com/question/20351507) | | [AMD与CMD规范的区别](http://www.cnblogs.com/tugenhua0707/p/3507957.html) | [KISSY 源码规范](http://docs.kissyui.com/1.4/docs/html/tutorials/style-guide/kissy-source-style.html) | | [前端代码规范及最佳实践](http://blog.jobbole.com/79075) | [百度前端规范](http://coderlmn.github.io/code-standards) | | [JavaScript风格指南/编码规范](http://blog.jobbole.com/79484) | [网易前端开发规范](http://nec.netease.com/standard) | | [前端规范资源列表](https://github.com/ecomfe/spec) | [Web 前端开发规范文档](http://codecloud.net/5622.html) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ### 性能优化相关 | Reference | Reference | | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | [性能优化页面渲染](http://www.infoq.com/cn/articles/javascript-high-performance-animation-and-page-rendering) | [移动前端性能优化指南](http://isux.tencent.com/h5-performance.html) | | [前端开发者必看的看的前端性能优化](http://www.uisdc.com/front-end-performance-for-web-designers-and-front-end-developers) | [前端性能再优化](http://www.zhangxinxu.com/wordpress/tag/%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD/) | | [前端性能优化进阶大道](http://www.aliued.cn/2013/01/20/web%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E8%BF%9B%E9%98%B6%E8%B7%AF.html) | [前端性能指导书](http://www.feelcss.com/tag/%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD) | | [YSLOW中文介绍](http://www.cnblogs.com/yslow) | [Yahoo团队实践分享:网站性能](http://www.360doc.com/content/10/0928/09/2588264_56971287.shtml) | | [加载,不只是少一点点](http://tgideas.qq.com/webplat/info/news_version3/804/808/811/m579/201109/41355.shtml) | [12306谈谈网站前端性能](http://coolshell.cn/articles/6470.html) | | [【高性能前端1】高性能HTML](http://www.alloyteam.com/2012/10/high-performance-html) | [【高性能前端2】高性能CSS](http://www.alloyteam.com/2012/10/high-performance-css) | | [静态资源版本更新与缓存](http://www.infoq.com/cn/articles/front-end-engineering-and-performance-optimization-part1) | [静态资源管理与模板框架](http://www.infoq.com/cn/articles/front-end-engineering-and-performance-optimization-part2) | | [HTTPS连接的前几毫秒发生了什么](http://blog.jobbole.com/48369) | [Yslow](http://uicss.cn/yslow/#more-12319) | | [阿里无线前端Pt.1 加载期优化)](https://github.com/amfe/article/issues/1) | [前端网页性能最佳实践](http://www.cnblogs.com/developersupport/p/3248695.html) | | [---------------------------------------------------]() | [-----------------------------------------------------]() | ================================================ FILE: articals/c/Demo/bug1.c ================================================ #include int alpha(char); int main(){ char ch; while( (ch = getchar()) != EOF ) { printf("location: %d\n", alpha(ch) ); while( getchar() != '\n') continue; } return 0; } int alpha(char ch){ if(ch >= 65 && ch <= 90) { printf("%c is upper alpha\n", ch); ch -= 64; } else if(ch >=97 && ch <= 122) { ch -= 96; printf("%c is lower alpha\n", ch); } else{ ch = -1; printf("%c is not alpha\n", ch); } return ch; } ================================================ FILE: articals/c/Demo/mywords ================================================ 5.3 6.2 3.6 5.6 7.9 5.6 3.9 1.5 6.9 4.8 4.1 56.6 23.7 56.1 18.6 ================================================ FILE: articals/c/Demo/test.c ================================================ #include /** * @return * @Author Suoyue * @DateTime 2017-08-21 */ int main(){ printf("shao suo\n"); printf("shao\nsuo\n"); printf("shao "); printf("suo\n"); return 0; } //anything be careful ================================================ FILE: articals/c/Demo/test10.c ================================================ #include int main(){ int a = 66; printf("ASCII = %c\n", a); return 0; } ================================================ FILE: articals/c/Demo/test11.c ================================================ #include int main(){ printf("\aStartled by the sudden sound, Sally shouted,\n\"By the Great Pumpkin, what was that!\"\n"); return 0; } ================================================ FILE: articals/c/Demo/test12.c ================================================ #include int main(){ float f; printf("Enter a floating-point value:"); scanf("%f", &f); printf("fixed-point natation:%f\n", f); printf("exponential natation:%e\n", f); printf("p natation:%.2a\n", f); return 0; } ================================================ FILE: articals/c/Demo/test13.c ================================================ #include #define YEAR_S 3.156e+7 int main(){ float age; printf("please input your age:"); scanf("%f", &age); printf("your live for %.0f second \n", age * YEAR_S); return 0; } ================================================ FILE: articals/c/Demo/test14.c ================================================ #include #define WATER_W 3.0e-23 #define KATUO_W 950 int main(){ float n; printf("please input kuatu num:"); scanf("%f", &n); printf("water num: %e", n * KATUO_W / WATER_W); return 0; } ================================================ FILE: articals/c/Demo/test15.c ================================================ #include #define YIN_CM 2.54 int main(){ float h; printf("please input your height:"); scanf("%f", &h); printf("%f\n", h * YIN_CM); return 0; } ================================================ FILE: articals/c/Demo/test16.c ================================================ #include #define PIN_CUP 2 #define CUP_YAS 8 #define YAS_SOU 2 #define SOU_CHA 3 int main(){ float cup; printf("please input cup:"); scanf("%f", &cup); printf("pin=%f,yas=%f,sou=%f,cha=%f\n", cup*PIN_CUP, cup/CUP_YAS, cup/CUP_YAS/YAS_SOU, cup/CUP_YAS/YAS_SOU/SOU_CHA); return 0; } ================================================ FILE: articals/c/Demo/test17.c ================================================ #include #include int main(){ char fname[30]; char sname[30]; printf("please input your first name:"); scanf("%s", fname); printf("please input your second name:"); scanf("%s", sname); printf("%s,%s\n", sname, fname); return 0; } ================================================ FILE: articals/c/Demo/test18.c ================================================ #include int main(){ char fname[30], sname[30], tip[10] = "name:"; printf("please input your first name:"); scanf("%s", fname); printf("please input your second name:"); scanf("%s", sname); printf("\"%s %s\"\n", sname, fname); printf("%-20s\"%s %s\"\n", tip, sname, fname); printf("\"%s %s\"%20s\n", sname, fname, tip); return 0; } ================================================ FILE: articals/c/Demo/test19.c ================================================ #include int main(){ float f; scanf("%f", &f); printf("%.1f\n", f); printf("%.1e\n", f); return 0; } ================================================ FILE: articals/c/Demo/test2.c ================================================ #include int main(){ char* name = "shaosuo"; char* address = "wuhan"; printf("name = %s, address = %s\n", name, address); return 0; } ================================================ FILE: articals/c/Demo/test20.c ================================================ #include int main(){ float h; printf("please input your height(cm):"); scanf("%f", &h); printf("Dabbey, your are %.3f (m)\n", h/100); return 0; } ================================================ FILE: articals/c/Demo/test21.c ================================================ #include int main(){ float speed, fsize; printf("please input download speed, file size:"); scanf("%f%f", &speed, &fsize); printf("At %.2f megabits per second, a file of %.2f megabytes downloads in %.2f seconds\n", speed, fsize, fsize/speed); return 0; } ================================================ FILE: articals/c/Demo/test22.c ================================================ #include #include int main(){ char fname[30], sname[30]; int flen, slen; printf("please input your first name:"); scanf("%s", fname); printf("please input your second name:"); scanf("%s", sname); flen = strlen(fname); slen = strlen(sname); printf("%6s %6s\n", fname, sname); printf("%6d %6d\n", flen, slen); printf("%-6s %-6s\n", fname, sname); printf("%-6d %-6d\n", flen, slen); return 0; } ================================================ FILE: articals/c/Demo/test23.c ================================================ #include #include int main(){ double d = 1.0/3.0; float f = 1.0/3.0; printf("%.6Lf, %.12Lf, %.18Lf\n", d, d, d); printf("%.18Lf\n", DBL_DIG); printf("%.6f, %.12f, %.18f\n", f, f, f); printf("%.18f\n", FLT_DIG); return 0; } ================================================ FILE: articals/c/Demo/test24.c ================================================ #include #define JIA_S 3.785 #define YIN_KM 1.609 int main(){ float s, fule; printf("please input s(yinli), fule(jialu):"); scanf("%f%f", &s, &fule); printf("result:%.1f(KM/SHENG)\n", (s/YIN_KM)/(fule*JIA_S)); return 0; } ================================================ FILE: articals/c/Demo/test25.c ================================================ #include #define ROUND 60 int main(){ int min = 1; while(min > 0){ printf("please input a min:"); scanf("%d", &min); printf("time: %d hours %d min\n", min/60, min%60); } return 0; } ================================================ FILE: articals/c/Demo/test26.c ================================================ #include int main(){ int n, max; printf("please input a intege:"); scanf("%d", &n); max = n + 10; while( n++ < max ){ printf("%d ", n); } return 0; } ================================================ FILE: articals/c/Demo/test27.c ================================================ #include int main(){ int days = 1; while(days){ printf("please input days:"); scanf("%d", &days); printf("%d days are %d weeks, %d days\n", days, days/7, days%7); } return 0; } ================================================ FILE: articals/c/Demo/test28.c ================================================ #include #define CM_INCHES 0.393701 #define CM_FEET 0.032808 int main(){ float height = 1.0; while(height){ printf("Enter a height in centimeters:"); scanf("%f", &height); printf("%.2f cm = %.0f feet, %.2f inches\n", height, height*CM_FEET, height*CM_INCHES); } return 0; } ================================================ FILE: articals/c/Demo/test29.c ================================================ #include int main(){ int n, count = 0, sum = 0; printf("please input n:"); scanf("%d" ,&n); while( count++ < n){ sum += count; } printf("sum = %d\n", sum); return 0; } ================================================ FILE: articals/c/Demo/test3.c ================================================ #include void jolly(); void deny(); int main(){ jolly(); jolly(); jolly(); deny(); return 0; } void jolly(){ printf("For he's a jolly good fellow!\n"); } void deny(){ printf("Which nobody can deny!\n"); } ================================================ FILE: articals/c/Demo/test30.c ================================================ #include int main(){ int n, count = 0, sum = 0; printf("please input n:"); scanf("%d" ,&n); while( count++ < n){ sum += count * count; } printf("sum = %d\n", sum); return 0; } ================================================ FILE: articals/c/Demo/test31.c ================================================ #include void thr(int n); int main(){ int n; scanf("%d", &n); thr(n); return 0; } void thr(int n){ printf("%d\n", n*n*n); } ================================================ FILE: articals/c/Demo/test32.c ================================================ #include void resmode(); int main(){ int first, second; printf("start!\n"); printf("input second operand\n"); scanf("%d", &second); printf("input first operand\n"); scanf("%d", &first); resmode(first, second); printf("done!\n"); } void resmode(int first, int second){ printf("%d %% %d is %d\n", first, second, first%second); } ================================================ FILE: articals/c/Demo/test33.c ================================================ #include int main(){ char a[27] = "abcdefghijklmnopqrstuvwxyz"; int i = 0; while( i++ < 26){ printf("%c\n", a[i-1]); //前面+1 ,-1即为真实元素 } return 0; } ================================================ FILE: articals/c/Demo/test34.c ================================================ #include int main(){ int i, j; char ch = '$'; for(i = 0; i < 5; ++i){ for (j = 0; j <= i; ++j) { printf("%c", ch); } printf("\n"); } return 0; } ================================================ FILE: articals/c/Demo/test35.c ================================================ #include int main(){ char lets[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int i, j; for (i = 0; i < 6; ++i) { for (j = 0; j <= i; j++) { printf("%c", lets[5-j]); } printf("\n"); } return 0; } ================================================ FILE: articals/c/Demo/test36.c ================================================ #include int main(){ char lets[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int i, j; for (i = 0; i < 6; i++) { for (j = 0; j <= i; j++) { printf("%c", lets[i*(i+1)/2+j]); } printf("\n"); } return 0; } ================================================ FILE: articals/c/Demo/test37.c ================================================ #include #define START 64 int main(){ char ch; int i, j; scanf("%c", &ch); for (j = 0; j < ch - START; ++j) { for (i = 0; i < ch - START - j - 1; ++i) { printf(" "); } for (i = 0; i < j ; ++i) { printf("%c", START + 1 + i); } printf("%c", START + j + 1); for (i = j; i > 0; --i) { printf("%c", START + i); } printf("\n"); } return 0; } ================================================ FILE: articals/c/Demo/test38.c ================================================ #include int main(){ int i, start, end; printf("start,end\n"); scanf("%d,%d",&start, &end); for (i = start; i <= end; ++i) { printf("------------------------------\n"); printf("|%-9d|%-9d|%-9d|\n", i, i*i, i*i*i); } printf("------------------------------\n"); return 0; } ================================================ FILE: articals/c/Demo/test39.c ================================================ #include #include int main(){ char w[50]; scanf("%s", w); int len = strlen(w); while(len-- >= 0){ printf("%c", w[len]); } return 0; } ================================================ FILE: articals/c/Demo/test4.c ================================================ #include void br(); void ic(); int main(){ br(); printf(", "); ic(); printf("\n"); ic(); printf(",\n"); br(); return 0; } void br(){ printf("Brazil, Russia"); } void ic(){ printf("India, China"); } ================================================ FILE: articals/c/Demo/test40.c ================================================ #include int main(){ float num1, num2; while (scanf("%f%f", &num1, &num2) != 2){ printf("please input correct digit!\n"); } printf("%f\n", (num1-num2)/(num1*num2)); return 0; } //?????????????????????????????????? ================================================ FILE: articals/c/Demo/test41.c ================================================ #include float addff(float f1, float f2); int main(){ float num1, num2; while ( scanf("%f%f", &num1, &num2) != 2 ){ printf("please input correct digit!\n"); } printf("%f\n", addff(num1, num2)); return 0; } float addff(float f1, float f2){ return (f1-f2)/(f1*f2); } ================================================ FILE: articals/c/Demo/test42.c ================================================ #include int main(){ int a, b; printf("Enter lower and upper integer limits:"); scanf("%d%d", &a, &b); while( a < b ){ printf("The sums of the squares from %d to %d is %d\n", a*a, b*b, a*a+b*b); printf("Enter next set of limits:"); scanf("%d%d", &a, &b); } printf("done!\n"); return 0; } ================================================ FILE: articals/c/Demo/test43.c ================================================ #include #define LEN 8 void swap(int *a, int *b); int main() { int i, j, a[LEN]; for (i = 0; i < LEN; ++i) { scanf("%d", &a[i]); } for (i = 0; i < LEN -1; ++i) { for (j = 0; j < LEN - i - 1; ++j) { if(a[j] < a[j+1]) { swap(&a[j], &a[j+1]); } } } for (i = 0; i < LEN; ++i) { printf("%d ", a[i]); } } void swap(int *a, int *b) { int t = *a; *a = *b; *b = t; } ================================================ FILE: articals/c/Demo/test44.c ================================================ #include int main(){ float f1 = 1.0, f2 = 1.0, sum1 = 0, sum2 = 0; int i, n; scanf("%d", &n); while( n > 0){ f1 = 1.0, f2 = 1.0, sum1 = 0, sum2 = 0; for (i = 0; i < n; ++i) { sum1 += f1/f2; if( (i+1)%2 == 0 ) { sum2 -= f1/f2; }else{ sum2 += f1/f2; } f2++; } printf("sum1 = %f, sum2 = %f\n", sum1, sum2); scanf("%d", &n); } return 0; } ================================================ FILE: articals/c/Demo/test45.c ================================================ #include #define LEN 8 int main(){ int arr[LEN]; int i, tem = 1; for (i = 0; i < LEN; ++i) { tem *= 2; arr[i] = tem; } i = 0; do{ printf("%d ", arr[i]); i++; }while (i < LEN); return 0; } ================================================ FILE: articals/c/Demo/test46.c ================================================ #include #define LEN 8 int main(){ double a[LEN], b[LEN], tem = 0; int i; for (i = 0; i < LEN; ++i) { printf("Enter a double is NO%d:", i+1); scanf("%lf", &a[i]); tem += a[i]; b[i] = tem; //灵活使用临时变量 } i = 0; while(i++ < LEN) { printf("%.2lf ", a[i-1]); } i = 0; printf("\n"); while(i++ < LEN) { printf("%.2lf ", b[i-1]); } printf("\n"); return 0; } ================================================ FILE: articals/c/Demo/test47.c ================================================ #include #include #define MAX_LEN 255 int main(){ char a[MAX_LEN]; scanf("%s", a); int len = strlen(a); while(len-- > 0){ printf("%c", a[len]); } return 0; } ================================================ FILE: articals/c/Demo/test48.c ================================================ #include int main(){ int start = 5, week, weekfds, i = 0; printf("start friends is %d\n", start); scanf("%d", &week); while(i++ < week){ weekfds= (start-i) * 2; printf("week%d friends is %d\n", i, weekfds); start = weekfds; } return 0; } ================================================ FILE: articals/c/Demo/test49.c ================================================ #include #include int main(){ char ch; int nblank = 0, nt = 0, n = 0; while( (ch = getchar()) != '#' ){ if(ch == '\n') nt++; else if(isblank(ch)) nblank++; else n++; } printf("nblank = %d, nt = %d, n = %d\n", nblank, nt, n); return 0; } ================================================ FILE: articals/c/Demo/test5.c ================================================ #include int main(){ int toes = 10; printf("toes*2 = %d, toes^2 = %d\n", toes * 2, toes * toes); return 0; } ================================================ FILE: articals/c/Demo/test50.c ================================================ #include int main(){ char ch; int n = 0; while( (ch = getchar()) != '#' ){ putchar(ch); printf(" %d ", ch); n++; if(n % 8 == 0){ putchar('\n'); } } return 0; } ================================================ FILE: articals/c/Demo/test51.c ================================================ #include int main(){ char ch, pre; int n = 0; while( (ch = getchar()) != '#' ){ if(pre == 'e' && ch == 'i') n++; pre = ch; } printf("%d\n", n); return 0; } ================================================ FILE: articals/c/Demo/test52.c ================================================ #include #define BASIC_SALARY 10.00 #define LOVER_RATE 0.15 #define MIDDLE_RATE 0.2 #define HIGH_RATE 0.25 int main(){ float work_hours, salary, tax, income; printf("Enter your work hours:"); scanf("%f", &work_hours); if(work_hours > 40){ work_hours= 40 + (work_hours-40) * 1.5; } salary = work_hours * BASIC_SALARY; if(salary <= 300) tax = salary * LOVER_RATE; else if(salary <= 450) tax = 300 * LOVER_RATE + (salary-300) * MIDDLE_RATE; else tax = 300 * LOVER_RATE + 150 * MIDDLE_RATE + (salary-450) * HIGH_RATE ; income = salary - tax; printf("his salary, tax, income are %.2f, %.2f, %.2f\n", salary, tax, income); return 0; } ================================================ FILE: articals/c/Demo/test53.c ================================================ #include #define LOVER_RATE 0.15 #define MIDDLE_RATE 0.2 #define HIGH_RATE 0.25 int main(){ float work_hours, basic, salary, tax, income; int choice; printf("Enter your work hours:"); scanf("%f", &work_hours); printf("*******************************************************************\n"); printf("Enter the number corresponding to the desired pay rate or action:\n"); printf("1) $8.75/hr"); printf("\t\t\t2) $9.33/hr\n"); printf("3) $10.00/hr"); printf("\t\t\t4) $11.2/hr\n"); printf("5) quit!\n"); printf("*******************************************************************\n"); while ( scanf("%d", &choice) == 1){ switch (choice){ case 1: basic = 8.75; break; case 2: basic = 9.33; break; case 3: basic = 10.00; break; case 4: basic = 11.2; break; default: break; } } if(work_hours > 40){ work_hours= 40 + (work_hours-40) * 1.5; } salary = work_hours * basic; if(salary <= 300) tax = salary * LOVER_RATE; else if(salary <= 450) tax = 300 * LOVER_RATE + (salary-300) * MIDDLE_RATE; else tax = 300 * LOVER_RATE + 150 * MIDDLE_RATE + (salary-450) * HIGH_RATE ; income = salary - tax; printf("his salary, tax, income are %.2f, %.2f, %.2f\n", salary, tax, income); return 0; } ================================================ FILE: articals/c/Demo/test54.c ================================================ #include #include #include _Bool isPrime(int n); int main(){ unsigned a, i; printf("Enter a integer n(n>0):"); if ( scanf("%u", &a) != 1 ) //not match but return 1 printf("enter a integer must more than 0"); else for (i = 2; i <= a; ++i) if(isPrime(i)) printf("%d ", i); printf("\n"); return 0; } _Bool isPrime(int n){ _Bool res = 1; int i, j; for (i = 1; i <= sqrt(n); ++i) for (j = sqrt(n); j < n; ++j) if(i * j == n) res = 0; return res; } ================================================ FILE: articals/c/Demo/test55.c ================================================ #include #define NORMAL_TAX 0.15 #define EXT_TAX 0.28 void menu(); int main(){ int choice; float salary, ext_line, tax; printf("enter your salary:\n"); scanf("%f", &salary); menu(); while( scanf("%d", &choice) == 1){ switch (choice){ case 1: ext_line = 17850;break; case 2: ext_line = 23900;break; case 3: ext_line = 29750;break; case 4: ext_line = 14875;break; default: printf("bye\n");break; } tax = ( salary <= ext_line ? salary*NORMAL_TAX : ext_line*NORMAL_TAX + (salary-ext_line)*EXT_TAX ); printf("%.2f\n", tax); } return 0; } void menu(){ printf("enter a status choice:"); printf("**********status************\n"); printf(" 1) single\n"); printf(" 2) host\n"); printf(" 3) married\n"); printf(" 4) divorce\n"); printf(" 5) input 'q' eixt\n"); printf("****************************\n"); } ================================================ FILE: articals/c/Demo/test56.c ================================================ #include int main(){ char choice; float fweight = 0, sweight = 0, tweight = 0; float fcharge = 0, scharge = 0, tcharge = 0; float weight, price, charge, orderCharge, orderWeight, account, extCharge, pay; printf("enter a, b, c chooce your goods, q is quit:\n"); while ( (choice = getchar()) != 'q' ) { if('\n' == choice) continue; if( choice == 'a' || choice == 'b' || choice == 'c' ) { switch (choice) { case 'a': price = 2.05; printf("please enter want to buy yangli weight:\n"); scanf("%f", &weight); ; fweight += weight; fcharge += fweight * price; printf("%.2f\n", fweight); break; case 'b': price = 1.15; printf("please enter want to buy taincai weight:\n"); scanf("%f", &weight); sweight += weight; scharge += sweight * price; printf("%.2f\n", sweight); break; case 'c': price = 1.09; printf("please enter want to buy hulubo weight:\n"); scanf("%f", &weight); tweight += weight; tcharge += tweight * price; printf("%.2f\n", tweight); break; default: ; } } else { printf("pleae enter 'a', 'b', 'c' !\n"); } printf("enter a, b, c chooce your goods, q is quit:\n"); } orderWeight = fweight + sweight + tweight; orderCharge = fcharge + scharge + tcharge; account = orderCharge > 100 ? orderCharge * 0.05 : 0; if( orderWeight <= 5 ) extCharge = 6.5; else if( orderWeight <= 20) extCharge = 14; else extCharge = 14 + (orderWeight-14) * 0.5; pay = orderCharge + extCharge - account; printf("******************* order ******************\n"); printf("*name-------price------weight-------charge*\n"); printf("*yang-------$2.05--------%9.2f---------$%9.2f*\n", fweight, fcharge); printf("*tian-------$1.15--------%9.2f---------$%9.2f*\n", sweight, scharge); printf("*hulobo-----$1.09--------%9.2f---------$%9.2f*\n", tweight, tcharge); printf("totalWeight:%.2f, orderCharge:$%.2f", orderWeight, orderCharge); printf("account:$%.2f, extCharge:$%.2f, pay:$%.2f\n", account, extCharge, pay); printf("*************************************************\n"); return 0; } ================================================ FILE: articals/c/Demo/test57.c ================================================ #include #include int main(){ char ch; int count = 0; while( (ch = getchar()) != EOF ) { if(isblank(ch) || ch == '\n') continue; count++; } printf("count : %d\n", count); return 0; } ================================================ FILE: articals/c/Demo/test58.c ================================================ #include void dealSpecial(char sp); int main(){ char ch; while( (ch = getchar()) != EOF ){ // if( ch == '\n' ) // continue; dealSpecial(ch); // putchar(ch); // while(getchar() != '\n') // continue; } return 0; } void dealSpecial(char sp){ switch (sp){ case '\n': printf("\\n %d", sp); break; case '\t': printf("\\t %d", sp); break; case ' ': printf("\\ %d", sp); break; } } ================================================ FILE: articals/c/Demo/test59.c ================================================ #include #include int main(){ char ch; int lower = 0, upper = 0; while( (ch = getchar()) != EOF ){ if( ch == '\n' ) continue; if(islower(ch)) lower++; if(isupper(ch)) upper++; } printf("lower= %d, upper= %d\n", lower, upper); return 0; } ================================================ FILE: articals/c/Demo/test6.c ================================================ #include int main(){ int age = 23; printf("my day in life:%d\n", age*365); return 0; } ================================================ FILE: articals/c/Demo/test60.c ================================================ #include int main(){ char ch; int count = 0; while( (ch = getchar()) != EOF ){ count++; if(ch == ' ' || ch == '\n'){ printf("%d ", count - 1); count = 0; } } return 0; } ================================================ FILE: articals/c/Demo/test61.c ================================================ #include int main(){ int ran, lower = 1, upper = 100, i = 0; int smart = (lower + upper) / 2; printf("please enter 1 ~ 100 a integer:"); scanf("%d", &ran); while( ran != smart){ if(ran < smart) upper = smart; else lower = smart; i++; printf("though %d times = %d\n", i, smart); smart = (lower + upper) / 2; } printf("though %d times = %d\n", i+1, smart); return 0; } ================================================ FILE: articals/c/Demo/test62.c ================================================ #include void count(); int get_int(); char get_first(); char get_choice(); int main(){ char choice; count(); while( (choice = get_choice()) != 'q' ){ switch (choice){ case 'a': printf("buy low, sell high\n"); break; case 'b': printf("\a\n"); break; case 'c': count(); break; default: printf("error!!!\n"); break; } } return 0; } //计数 void count(){ int n, i; printf("Count how far?\n"); n = get_int(); for (int i = 0; i <= n; ++i) { printf("%d\n", i); } while( getchar() != '\n' ) continue; } //异常处理 int get_int(){ int n; char ch; while( scanf("%d", &n) != 1 ){ while( getchar() != '\n') putchar(ch); printf("is not a integer!!!\n"); } return n; } //过滤换行符 char get_first(){ char choice; choice = getchar(); while( getchar() != '\n' ) continue; return choice; } //删选合适的字符 char get_choice(){ char choice; printf("please enter a, b, c\n"); choice = get_first(); while( (choice < 'a' || choice > 'c') && choice != 'q'){ printf("please enter correct code!!\n"); choice = get_first(); } return choice; } ================================================ FILE: articals/c/Demo/test63.c ================================================ #include int main(){ return 0; } ================================================ FILE: articals/c/Demo/test64.c ================================================ #include int main(){ return 0; } ================================================ FILE: articals/c/Demo/test65.c ================================================ #include void show(char, int, int); int main(void){ char a; int b, c; scanf("%c%d%d", &a, &b, &c); show(a, b ,c); return 0; } void show(char a, int b, int c) { int i, j; for (int i = 0; i < c; ++i) { for (int j = 0; j < b; ++j) { putchar(a); } putchar('\n'); } } ================================================ FILE: articals/c/Demo/test66.c ================================================ #include double avg(double, double); int main(){ double a, b; scanf("%lf%lf", &a, &b); printf("%.2lf", avg(a, b) ); return 0; } double avg(double a, double b){ return 1./( (1./a + 1./b)/2. ); } ================================================ FILE: articals/c/Demo/test67.c ================================================ #include void large_of(double *, double *); int main(void){ double a, b; scanf("%lf%lf", &a, &b); large_of(&a, &b); printf("%.2lf, %.2lf\n", a, b); return 0; } void large_of(double *a, double *b){ // *a > *b ? *b = *a : *a = *b ; ?????? if( *a > *b ) *b = *a; else *a = *b; } ================================================ FILE: articals/c/Demo/test68.c ================================================ #include void order(double *, double *, double *); void swap(double *, double *); int main(void){ double a, b, c; scanf("%lf%lf%lf", &a, &b, &c); order(&a, &b, &c); printf("%.2lf, %.2lf, %.2lf\n", a, b, c); return 0; } void order(double *a, double *b, double *c){ if(*a > *b) swap(a, b); if(*b > *c) swap(b, c); } void swap(double *m, double *n){ double tem; tem = *m; *m = *n; *n = tem; } ================================================ FILE: articals/c/Demo/test69.c ================================================ #include double power(double, int); int main(){ double n; int c; scanf("%lf%d", &n, &c); printf("%.2lf\n", power(n, c)); return 0; } double power(double n, int c){ int i, pow = 1; if( n == 0 ) return 0; if( c == 0 ) return 1; for (i = 1; i <= c; ++i) pow *= n; return pow; } ================================================ FILE: articals/c/Demo/test7.c ================================================ #include void smile(); int main(){ int i, j; for(i = 3; i > 0; i--) { for(j = i; j > 0; j--) smile(); printf("\n"); } return 0; } void smile(){ printf("Smile!"); } ================================================ FILE: articals/c/Demo/test70.c ================================================ #include double power(double, int); int main(){ double n; int c; scanf("%lf%d", &n, &c); printf("%.2lf\n", power(n, c)); return 0; } double power(double n, int c){ if( n == 0 ) return 0; if( c == 0 ) return 1; return n*power(n, c-1); } ================================================ FILE: articals/c/Demo/test71.c ================================================ #include void to_base_n(int, int); int main(void){ int x, n; scanf("%d%d", &x, &n); to_base_n(x, n); return 0; } void to_base_n(int x, int n){ int r; r = x%n; if(x >= n) to_base_n(x/n, n); printf("%d", r ); } ================================================ FILE: articals/c/Demo/test72.c ================================================ #include int fibonacciRec(int); //递归 int fibonacci(int); //非递归 int main(void){ int n; scanf("%d", &n); printf("%d\n", fibonacciRec(n) ); printf("%d\n", fibonacci(n) ); return 0; } int fibonacciRec(int n){ if(n == 1 || n == 2) return 1; else return fibonacciRec(n-1) + fibonacciRec(n-2); } int fibonacci(int n){ int i, fib1 = 1, fib2 = 1; if( n == 1 || n == 2) return 1; for(i = 3 ; i <= n; i++){ fib2 = fib1 + fib2; fib1 = fib2 - fib1; } return fib2; } ================================================ FILE: articals/c/Demo/test73.c ================================================ #include #define N 5 void cp_arr(double [], const double [], int); void cp_ptr(double [], const double *, int); void cp_ptrs(double *, const double *, const double *); void show_arr(double [], int); int main(void){ double source[N] = {1, 2, 3, 4, 5}; double target1[N], target2[N], target3[N]; cp_arr(target1, source, N); cp_ptr(target2, source, N); cp_ptrs(target3, source, source+N); show_arr(target1, N); putchar('\n'); show_arr(target2, N); putchar('\n'); show_arr(target3, N); putchar('\n'); return 0; } void cp_arr(double target[], const double source[], int n){ int i; for (i = 0; i < n; ++i) { target[i] = source[i]; } } void cp_ptr(double target[], const double *source, int n){ int i; for (i = 0; i < n; ++i) { target[i] = *(source+i); } } void cp_ptrs(double target[], const double *source_start, const double *source_end){ while(source_start < source_end){ *target = *source_start++; target++; } } void show_arr(double a[], int n){ int i; for (i = 0; i < n; ++i) { printf("%.2lf ", a[i]); } } ================================================ FILE: articals/c/Demo/test74.c ================================================ #include #define SIZE 10 void sort(double [], int); void swap(double *, double *); void show_arr(const double [], int); int main(void){ double a[] = {2,4,6,7,8,3,5,1,10,9}; sort(a, SIZE); show_arr(a, SIZE); return 0; } void sort(double a[], int n){ int i, j; for (int i = 0; i < n; ++i) for (int j = 0; j < n - i; ++j) if(a[j+1] > a[j]) swap(&a[j+1], &a[j]); } void swap(double *p, double *q){ double temp = *p; *p = *q; *q = temp; } void show_arr(const double a[], int n){ int i; for (i = 0; i < n; ++i) { printf("%.2lf ", a[i]); } } ================================================ FILE: articals/c/Demo/test75.c ================================================ #include #define COLS 3 #define ROWS 2 void cp_arr(double [], const double [], int); void cp2_arr2(double [][COLS], const double [][COLS], int); void show_arr2(const double [][COLS], int); int main(void){ double arr1[ROWS][COLS] = { {1,2,3}, {4,5,6} }; double arr2[ROWS][COLS]; cp2_arr2(arr2, arr1, ROWS); show_arr2(arr2, ROWS); return 0; } void cp_arr(double target[], const double source[], int n){ int i; for (i = 0; i < n; ++i) { target[i] = source[i]; } } void cp2_arr2(double tgt[][COLS], const double src[][COLS], int rows){ int i; for (i = 0; i < rows; ++i) cp_arr(tgt[i], src[i], COLS); } void show_arr2(const double a[][COLS], int rows){ int i, j; for (i = 0; i < rows; ++i) { for (j = 0; j < COLS; ++j) printf("%.2lf ", a[i][j]); printf("\n"); } } ================================================ FILE: articals/c/Demo/test76.c ================================================ #include #define N 7 #define M 3 void cp_arr(double [], const double [], int); void cp_ptr(double [], const double *, int); void cp_ptrs(double *, const double *, const double *); void show_arr(double [], int); int main(void){ double source[N] = {1, 2, 3, 4, 5, 6, 7}; double target1[M], target2[M], target3[M]; cp_arr(target1, source, M); cp_ptr(target2, source, M); cp_ptrs(target3, source+2, source+5); show_arr(target1, M); putchar('\n'); show_arr(target2, M); putchar('\n'); show_arr(target3, M); putchar('\n'); return 0; } void cp_arr(double target[], const double source[], int m){ int i; for (i = 2; i < 2+m; ++i) { target[i-2] = source[i]; } } void cp_ptr(double target[], const double *source, int m){ int i; for (i = 2; i < 2+m; ++i) { target[i-2] = *(source+i); } } void cp_ptrs(double target[], const double *source_start, const double *source_end){ while(source_start < source_end){ *target = *source_start++; target++; } } void show_arr(double a[], int n){ int i; for (i = 0; i < n; ++i) { printf("%.2lf ", a[i]); } } ================================================ FILE: articals/c/Demo/test77.c ================================================ #include void show_vla(int, int, double [*][*]); int main(void){ int i, j; const int rows = 3; const int cols = 5; double arr[rows][cols] = {{1,2,3,4,5}, {6,7,8,9,10}, {11,12,13,14,15}}; double arr2[rows][cols]; for(i=0; i #define YEAR 5 #define MONTH 12 void perYearFall(const double [][MONTH], int); void perMonthFall(const double [][MONTH], int); int main(void){ const double a[YEAR][MONTH] = { {4.3, 4.3, 4.3, 3.0, 2.0, 1.2, 0.2, 0.2, 0.4, 2.4, 3.5, 6.6}, {8.5, 8.2, 1.2, 1.6, 2.4, 0.0, 5.2, 0.9, 0.3, 0.9, 1.4, 7.3}, {9.1, 8.5, 6.7, 4.3, 2.1, 0.8, 0.2, 0.2, 1.1, 2.3, 6.1, 8.4}, {7.2, 9.9, 8.4, 3.3, 1.2, 0.8, 1.4, 0.0, 0.6, 1.7, 4.3, 6.2}, {7.6, 5.6, 3.8, 2.8, 3.8, 0.2, 0.0, 0.0, 0.0, 1.3, 2.6, 5.2} }; perYearFall(a, YEAR); perMonthFall(a, YEAR); return 0; } void perYearFall(const double a[][MONTH], int year){ int i, j; double yearFall, sumYearFall; for(i = 0; i < year; i++) { yearFall = 0; for(j = 0; j < MONTH; j++) yearFall += a[i][j]; printf("%dyear\t\t%.2lf(inches)\n", i+2010, yearFall); sumYearFall += yearFall; } printf("\nthe yearly average is %.2lf\n\n", sumYearFall/year); } void perMonthFall(const double a[][MONTH], int year){ int i, j; double monthFall; for (i = 0; i < MONTH; ++i) { monthFall = 0; for (j = 0; j < year; ++j) monthFall += a[j][i]; printf("%.2lf ", monthFall/5); } } ================================================ FILE: articals/c/Demo/test79.c ================================================ #include #define ROWS 3 #define COLS 5 void getArr(double [][COLS], int); void averageGroup(double [], const double [][COLS], int); double average(const double [][COLS], int); double max(double [][COLS], int); void swap(double *, double *); void show(double [], int, double, double); int main(void){ double arr[ROWS][COLS] = {0}; double aveGroup[ROWS] = {0}; //注意初始化 double ave = 0; double m = 0; getArr(arr, ROWS); averageGroup(aveGroup, arr, ROWS); ave = average(arr, ROWS); m = max(arr, ROWS); show(aveGroup, ROWS, ave, m); return 0; } void getArr(double a[][COLS], int rows){ int i, j; for (i = 0; i < rows; ++i) for (j = 0; j < COLS; ++j) scanf("%lf", &a[i][j]); } void averageGroup(double b[], const double a[][COLS], int rows){ int i, j; double sum = 0; for (i = 0; i < rows; ++i){ for (j = 0; j < COLS; ++j) sum += a[i][j]; b[i] = sum/rows; } } double average(const double a[][COLS], int rows){ int i, j; double sum = 0; for (i = 0; i < rows; ++i) for (j = 0; j < COLS; ++j) sum += a[i][j]; return sum/(COLS*rows); } double max(double a[][COLS], int rows){ int i, j; for (i = 0; i < rows; ++i) { for (j = 0; j < COLS; ++j) if(a[i][j] > a[i][j+1]) swap(&a[i][j], &a[i][j+1]); if(a[i][j] > a[i+1][j]) swap(&a[i][j], &a[i+1][j]); } return a[i][j]; } void show(double a[], int size, double av, double m){ int i; for(i = 0; i < size; i++){ printf("%.2lf ", a[i]); } printf("\naverage = %.2lf\n", av); printf("max = %.2lf\n", m); } void swap(double *p, double *q){ double temp = *p; *p = *q; *q = temp; } ================================================ FILE: articals/c/Demo/test8.c ================================================ #include void one_three(); void two(); int main(){ printf("starting now:\n"); one_three(); printf("done\n"); return 0; } void one_three(){ printf("one\n"); two(); printf("three\n"); } void two(){ printf("two\n"); } ================================================ FILE: articals/c/Demo/test80.c ================================================ #include int main(void){ return 0; } ================================================ FILE: articals/c/Demo/test81.c ================================================ #include #define N 50 void getStr(char *, int ); int main(void){ char a[N]; getStr(a, N); puts(a); return 0; } void getStr(char * a, int n){ while( n-- > 0){ a[n] = getchar(); } } ================================================ FILE: articals/c/Demo/test82.c ================================================ #include #define N 50 void getStr(char *, int ); int main(void){ char a[N];; getStr(a, N); puts(a); return 0; } void getStr(char * a, int n) { int i = 0; while( i++ < n){ a[i] = getchar(); if(a[i] == '\n' || a[i] == '\t' || a[i] == '\0') { break; } } } ================================================ FILE: articals/c/Demo/test83.c ================================================ #include #include void reStr(char *, int); int main(void){ char str[20]; while( fgets(str, 20, stdin) ){ reStr(str, strlen(str)); fputs(str, stdout); } return 0; } void reStr(char * a, int n){ int i = 0; char b[n]; while(i++ < n) b[i] = a[i-1]; i = 0; while(n-- >= 0){ a[i] = b[n]; i++; } } ================================================ FILE: articals/c/Demo/test84.c ================================================ #include int main(void){ return 0; } ================================================ FILE: articals/c/Demo/test85.c ================================================ #include #include #define N 10 int main(void){ char a[N]; int i, word, up, low, num, pun; int countWord, countUp, countLow, countNum, countPun; while( fgets(a, N, stdin) != NULL && a[0] != '\n'){ i = 0, num=0, low=0, up=0, pun=0, word=0; if(a[i] == '\n') a[i] == ' '; if(isblank(a[i])) word++; else if(isdigit(a[i])) num++; else if(islower(a[i])) low++; else if(isupper(a[i])) up++; else pun++; } return 0; } ================================================ FILE: articals/c/Demo/test86.c ================================================ #include int main(int argc, char * argv[]){ int i = argc; printf("%d\n", argc); while( i-- > 1 ) puts(argv[i]); } // --i情况 (没想到argc = 4) (- -) // test86 see you later 0 1 2 3 // 1) (i = 4- 1 = 3, i > 0) -> a[3] // 2) (i = 3- 1 = 2, i > 0) -> a[2] // i--情况 // 1) (i = 4 > 0, i = 3 - 1 = 2) -> a[3] // 2) (i = 3 > 0, i = 2 - 1 = 2) -> a[2] // 3) (i = 2 > 0, i = 1 - 1 = 1) -> a[1] ================================================ FILE: articals/c/Demo/test87.c ================================================ ================================================ FILE: articals/c/Demo/test88.c ================================================ #include #include #define N 10 void pf(char * , int); void toUpper(char * , int); void toLower(char * , int); int main(int argc, char * argv[]){ char a[N]; switch (argv[1][1]){ case 'p': pf(a, N); break; case 'u': toUpper(a, N); break; case 'l': toLower(a, N); break; default : puts("enter error!"); break; } return 0; } //原样输出 void pf(char * a, int n){ while( fgets(a, n, stdin) != NULL && a[0] != '\n'){ fputs(a, stdout); } } //输出大写 void toLower(char * a, int n){ int i; while( fgets(a, n, stdin) != NULL && a[0] != '\n'){ i = 0; while(i++ < n-1){ // i=0<9 i=1 a[0], i=1<9 i=2 a[1] ---> i=8<9 i=9 a[8] if(isupper(a[i-1])) a[i-1] = tolower(a[i-1]); } fputs(a, stdout); } } //输出小写 void toUpper(char * a, int n){ int i; while( fgets(a, n, stdin) != NULL && a[0] != '\n'){ i = 0; while(i++ < n-1){ if(islower(a[i-1])) a[i-1] = toupper(a[i-1]); } fputs(a, stdout); } } ================================================ FILE: articals/c/Demo/test89.c ================================================ #include // int units = 0; void critic(int ); int main(){ int units = 0; scanf("%d", &units); if(units != 56) critic(units); return 0; } void critic(int u){ printf("%d\n", u); } ================================================ FILE: articals/c/Demo/test9.c ================================================ #include int main(){ int n = 2147483647; float f = 1e+20; float f1 = -f; printf("n = %d, n+1 = %d\n", n, n+1); printf("f = %f, f+1 = %f\n", f, f+1); printf("f1 = %f, f1+1 = %f\n", f1, f1-1); return 0; } ================================================ FILE: articals/c/Demo/test90.c ================================================ #include int main(void){ int mode; printf("enter 0 for metric, 1 for Us mode:\n"); while(scanf("%d", &mode) == 1 && mode >= 0){ set_mode(mode); get_info(); show_info(); printf("enter 0 for metric, 1 for Us mode:\n"); printf("-1 to quit:"); } return 0; } ================================================ FILE: articals/c/Demo/test91.c ================================================ #include "test91.h" void set_mode(int mode){ if(mode == 0) fule = distance/kalub; if(mode == 1) fule = distance/kalub*100; } void get_info(void){ printf("enter a kalub, distance, fule:"); scanf("%lf%lf%lf", kalub, distance, fule); } void show_info(void){ printf("%d\n", fule); } ================================================ FILE: articals/c/Demo/test91.h ================================================ #include double kalub; double distance; double fule; void set_mode(int); void show_info(void); void get_info(void); ================================================ FILE: articals/c/Demo/test92.c ================================================ #include static int i = 0; int a(void); int main(){ int n = 10; while( n-- ) printf("%d\n", a()); } int a(void){ return ++i; } ================================================ FILE: articals/c/Demo/test93.c ================================================ ================================================ FILE: articals/c/Demo/test94.c ================================================ #include #include #include #define N 1000 int rand1(int); void count(const int *, int); int main(){ int a[N] = {0}; srand( (unsigned int) time(0) ); for (int i = 0; i < N; ++i) { a[i] = rand1(10); } count(a, N); } //产生随机数 int rand1(int n){ return rand() % n + 1; } //计算每个数产生的个数 void count( const int *a, int n){ int b[10] = {0}; for(int j = 0; j < 10; ++j) for(int i = 0; i < n; ++i) if(a[i] == j+1) b[j]++; for (int i = 0; i < 10; ++i) printf("%d\n", b[i]); } ================================================ FILE: articals/c/Demo/test95.c ================================================ #include #include #include #define N 100 int rand1(int); void sort(int *, int); void show(const int *, int); int main(){ int a[N] = {0}; srand( (unsigned int) time(0) ); for (int i = 0; i < N; ++i) { a[i] = rand1(10); } show(a, N); sort(a, N); putchar('\n'); show(a, N); } //产生随机数 int rand1(int n){ return rand() % n + 1; } //选择排序 void sort(int *a, int n){ for (int top = 0; top < n - 1; ++top) for (int seek = top + 1; seek < n; ++seek) if( a[top] < a[seek]){ int tmp = a[top]; a[top] = a[seek]; a[seek] = tmp; } } //打印数组 void show( const int *a, int n){ for (int i = 0; i < n; ++i) { printf("%d ", a[i]); } } ================================================ FILE: articals/c/Demo/test96.c ================================================ #include #include #define SIZE 20 int get_n(){ int words; if(scanf("%d", &words) == 1 && words > 0) return words; else printf("enter error!!!\n"); } void show(char * a[], int n){ int i = 0; while( i++ < n ){ puts(a[i-1]); } } int main(void){ int words, i = 0, j = 0; char ch; printf("how many words do you wish to enter:"); words = get_n(); //处理输入的单词数 // char * q [5] = (char (*) [5])malloc( SIZE * 5 * sizeof(char) ); //动态创建 printf("enter %d words:", words); while( (ch = getchar()) != '\n' ){ if(ch == ' ') { char * p = (char *)malloc( i * sizeof(char) ); q[j] = p; free( p ); j++; i = 0; continue; } i++; } show(q, words); free( q ); return 0; } ================================================ FILE: articals/c/Demo/test97.c ================================================ #include #include #define SIZE 512 int main(int argc, char * argv[]){ FILE *in, *out; char buff[SIZE]; //读文件到缓冲区 if( (in = fopen(argv[1], "r")) == NULL ){ fputs("error", stderr); exit(EXIT_FAILURE); } fread(buff, SIZE, 1, in); //从缓冲区写文件 if( (out = fopen(argv[2], "w")) == NULL ) { fputs("error", stderr); exit(EXIT_FAILURE); } fwrite(buff, SIZE, 1, out); //关闭文件 if( fclose(in) != 0 || fclose(out) != 0 ) fputs("not close", stderr); return 0; } ================================================ FILE: articals/c/Demo/test98.c ================================================ #include #include #include #define SIZE 512 int main(){ char *infile, *outfile; FILE *in, *out; char buff[SIZE]; //输入到缓冲区 printf("enter a in file:"); scanf("%s", &infile); if( (in = fopen(infile, "r") ) == NULL ){ fputs("std in eror", stderr); exit(EXIT_FAILURE); } fgets(buff, in); //从缓冲区输出到文件 printf("enter a out file:"); scanf("%s", &outfile); if( (out = fopen(outfile, "w") ) == NULL ){ fputs("std out eror", stderr); exit(EXIT_FAILURE); } fputs(buff, out); return 0; } ================================================ FILE: articals/c/Demo/test99.c ================================================ #include ================================================ FILE: articals/c/Demo/testDice_d.c ================================================ #include #include #include #include "testRandom.c" int main(void){ int dice, roll; int sides, status; srand((unsigned int) time(0)); printf("enter a number of sides:\n"); while(scanf("%d", &sides) == 1 && sides > 0){ printf("how many dice\n"); //检查输入部分 if(status = scanf("%d", &dice) != 1){ if(status == EOF) //检查是否有文件终止符 break; else{ while(getchar() != '\n') //去掉换行符 continue; continue; } } //开始计算骰子总和 roll = roll_n_dice(dice, sides); //打印结果 printf("total %d , using %d times, %d-sides\n", roll, dice, sides); } printf("function called : %d\n", roll_count); return 0; } ================================================ FILE: articals/c/Demo/testFgets.c ================================================ #include int main(void){ char a[10]; fgets(a, 7, stdin); //读了dsfdsf个字符+'\0' fputs(a, stdout); //输出dsfdsf\0 没有+'\n' return 0; } //dsfdsfsdgfdgdffdg //dsfdsf ================================================ FILE: articals/c/Demo/testFgets2.c ================================================ #include #define N 10 int main(void){ char word[N]; while( fgets(word, N, stdin) != NULL && word[0] != '\n' ){ fputs(word, stdout); } return 0; } ================================================ FILE: articals/c/Demo/testFgets3.c ================================================ #include #define N 10 int main(){ char word[N]; int i; while( fgets(word, N, stdin) != NULL && word[0] != '\n'){ i = 0; while(word[i] != '\n' && word[i] != '\0') i++; //不是换行符或者空字符跳过 if(word[i] == '\n') word[i] = '\0'; //遇到换行符,转空字符 else while(getchar() != '\n') //读到空字符,丢弃剩余 continue; fputs(word, stdout); } return 0; } ================================================ FILE: articals/c/Demo/testFileIO.c ================================================ #include int main(){ char ch; while( (ch = getchar()) != EOF){ putchar(ch); } return 0; } ================================================ FILE: articals/c/Demo/testGets.c ================================================ #include int main(void){ char name[10]; gets(name); puts(name); return 0; } //fgdfgdfgdfgfdgfdg //fgdfgdfgdfgfdgfdg ================================================ FILE: articals/c/Demo/testIO.c ================================================ #include #include int main(int argc, char * argv[]){ int ch; //读取文件,存储每个字符的地方 FILE *fp; //文件指针 unsigned long count = 0; if(argc != 2){ printf("Usage: %s filename \n", argv[0]); } if( (fp = fopen(argv[1], "r")) == NULL ){ printf("can't open %s\n", argv[1]); exit(EXIT_FAILURE); } while( (ch = getc(fp)) != EOF ){ putc(ch, stdout); count++; } fclose(fp); printf("File %s has %lu characters\n", argv[1], count); return 0; } ================================================ FILE: articals/c/Demo/testP02.c ================================================ #include int a[2] = {1, 2}; int main(){ int *p1, *p2, *p3; p1 = p2 = p3 = a; printf("%d,%d,%d\n", *p1, *p1++, *p1); //分析: 函数中参数的传递的顺序是从右往左传递 // 1.*p1 = 1 ==> no3 = 1 // 2.*p1++ ==> *p1 = 1 , p1 += 1; ==> no2 = 1 // 3.*p1 ==> a[1] ==> no3 = 2 printf("%d,%d,%d\n", *p2, (*p2)++, *p2); // 1.*p2 = 1 ==> no3 = 1 // 2.(*p2)++ ==> *p2 = a[0], no2 = 1, a[0] = 2 // 3.*p2 = a[0] = 2 ==> no1 = 2; printf("%d,%d,%d\n", *p3, *++p3, *p3); // 1.*p3 = a[0] ==> no3 = 2 // 2.*++p3 ==> p3= p3+1 = &a[1] => no2 = *&a[1] = 2 // 3.*p3 = a[1] = 2 ==> no1 = 2; return 0; } // 2 1 1 // 2 1 1 // 2 2 2 ================================================ FILE: articals/c/Demo/testPntAdd.c ================================================ #include #define SIZE 10 int main(){ short a[SIZE] = {1,2,3,4,5,6,7,8,9,10}; double b[SIZE] = {1,2,3,4,5,6,7,8,9,10}; short i, *pa = a; double *pb = b; for (i = 0; i < 2; ++i) { printf("pa%d point %p\n", i, pa++); } for (i = 0; i < 2; ++i) { printf("pb%d point %p\n", i, pb++); } } // pa0 point 0060FF00 // pa1 point 0060FF02 // pb0 point 0060FEB0 // pb1 point 0060FEB8 ================================================ FILE: articals/c/Demo/testPo.c ================================================ #include #define SIZE 4 int sum(int * start, int * end){ int sum = 0; while(start < end){ sum += *start++; //分析 * ++(后缀) 同优先级右结合 //步骤分解 1. start先使用用 sum = sum + *start; // 2. start = start + 1; } return sum; } int main(void){ int a[SIZE] = {1, 2 , 3, 4}; printf("%d", sum(a, a+SIZE)); return 0; } // 10 正确 ================================================ FILE: articals/c/Demo/testPoint.c ================================================ #include int arr(int); int main(void){ int (* p)(int); p = arr; printf("%p,%p\n", p, arr); return 0; } int arr(int n){ return n; } //00401499,00401499 ================================================ FILE: articals/c/Demo/testPrintfScanf.c ================================================ #include int main(){ int a = 0, b =0; int pn1 = printf("ok!\n"); // pn1 = 4 int pn2 = printf("ok!,%d,%d\n",a, b); // pn2 = 8 int sn1 = scanf("%d", &a, &b); // sn1 = 1 int sn2 = scanf("%d%d", &a, &b); // sn2 = 2 printf("pn1=%d, sn1=%d, pn2=%d, sn2=%d\n", pn1, sn1, pn2, sn2); return 0; } ================================================ FILE: articals/c/Demo/testR_d.c ================================================ #include extern unsigned int rand0(void); extern void changeNext(unsigned int); int main(void){ unsigned int seed; while( scanf("%u", &seed) == 1 ){ changeNext(seed); for (int i = 0; i < 5; ++i) printf("%d\n", rand0()); } return 0; } ================================================ FILE: articals/c/Demo/testRand.c ================================================ #include static unsigned long int next = 1; //种子 unsigned int rand0(void){ next = next * 1103515245 + 12345; return (unsigned int) (next / 65536) % 32768; } void changeNext(unsigned int seed){ next = seed; } ================================================ FILE: articals/c/Demo/testRandom.c ================================================ #include #include int roll_count = 0; int roll_n_dice(int, int); int rollem(int); // int main(void){ // for (int i = 0; i < 10; ++i) // { // printf("%d\n", rollem(6)); // } // return 0; // } //生成1 - 6 之间的随机数 int rollem(int sides){ int roll; roll = rand() % sides + 1; roll_count++; return roll; } int roll_n_dice(int dice, int sides){ int d; int total = 0; if(sides < 2) return -2; if(sides < 1) return -1; for (d = 0; d < dice; ++d) total += rollem(sides); return total; } ================================================ FILE: articals/c/Demo/testRecursion.c ================================================ #include int up_and_down(int); int main(void){ up_and_down( 1 ); return 0; } int up_and_down(int n){ printf("%d, %p\n", n, &n); if(n < 4) up_and_down( n + 1 ); printf("%d, %p\n", n, &n); } // 1, 0060FF20 // 2, 0060FF00 // 3, 0060FEE0 // 4, 0060FEC0 // 4, 0060FEC0 // 3, 0060FEE0 // 2, 0060FF00 // 1, 0060FF20 ================================================ FILE: articals/c/Demo/testReducto.c ================================================ #include #include #include #define N 40 int main(int argc, char * argv[]){ FILE *in, *out; int ch; char name[N]; int count; //检查命令行参数 if(argc < 2){ fprintf(stderr, "Usage:%s filename\n", argv[0]); exit(EXIT_FAILURE); } //设置输入 if( (in = fopen(argv[1], "r")) == NULL){ fprintf(stderr, "I could not open this file\" %s \" \n ", argv[1]); exit(EXIT_FAILURE); } //设置输出 strncpy(name, argv[1], N - 5); name[N -5] = '\0'; strcat(name, ".red"); if( (out = fopen(name, "w")) == NULL ){ fprintf(stderr, "I could not open this file"); exit(3); } //拷贝 while( (ch = getc(in)) != EOF ){ if (count++ % 3 == 0) putc(ch, out); } //关闭文件 if( fclose(in) != 0 || fclose(out) != 0 ) fprintf(stderr, "Error in closing files\n"); return 0; } ================================================ FILE: articals/c/Demo/testScope.c ================================================ #include int main(void){ int i = 1 ; // for (int i = 0; i < 10; ++i) // { // // int i = 6; // printf("%d ", i); // } printf("block:%d\n", i); return 0; } // 0 1 2 3 4 5 6 7 8 9 file:3 ================================================ FILE: articals/c/Demo/testStrSort.c ================================================ #include #include #define SIZE 81 //字符串长度 #define LIM 20 //最大行数 #define HALT "" //读到空字符结束 void strSort(char * str [], int num); //排序函数 char * strGets(char * , int ); //输入字符串函数 int main(void){ char in[LIM][SIZE]; char * pstr[LIM]; int ct = 0, k = 0; //输入输出计数 while(ct < LIM && strGets(in[ct], SIZE) != NULL && in[ct][0] != '\0'){ pstr[ct] = in[ct]; ct++; //输入字符串 } strSort(pstr, ct); //排序字符串 for(k = 0; k < ct; k++) puts(pstr[k]); //输出字符串 return 0; } //选择排序 void strSort(char * str [], int num){ char *temp; int top, seek; for (top = 0; top < num-1; ++top) { for (seek = top + 1; seek < num; ++seek) { if( strcmp(str[top], str[seek]) > 0 ) temp = str[top]; str[top] = str[seek]; str[seek] = temp; } } } //自定义输入函数 char * strGets(char * str, int n){ char * ret_val; int i = 0; ret_val = fgets(str, n, stdin); if(ret_val){ while(str[i] != '\n' && str[i] != '\0') i++; if(str[i] == '\n') str[i] = '\0'; else while(getchar() != '\n') continue; } return ret_val; } ================================================ FILE: articals/c/Demo/testSwap.c ================================================ #include void swap(int *, int *); int main(void){ int a = 1, b =2; swap(&a, &b); printf("%d, %d\n", a, b); return 0; } void swap(int *p, int * q){ int temp; temp = *p; *p = *q; *q = temp; } ================================================ FILE: articals/c/Demo/testToBinary.c ================================================ #include void to_binary(int); int main(void){ int n; scanf("%d", &n); to_binary(n); return 0; } void to_binary(int n){ int r; r = n % 2; if( n >= 2 ) to_binary( n/2 ); printf("%d", r==0 ? 0 : 1); } ================================================ FILE: articals/c/Demo/words ================================================ Apple Banana Orager HongKong SHANGHAI wuhan ================================================ FILE: articals/c/Demo/words.red ================================================ AlBa aroKgHGIun ================================================ FILE: articals/c/array.md ================================================ # 数组 ### 一维数组 - 声明:和声明变量一样,但是数组不能直接赋值给它,可以初始化 ``` int a[10]; ``` - 初始化:声明并初始化并非赋值,不允许先声明后直接赋值 ``` int a[10] = {1,2,3,4,5,6,6,7,7,8}; //可读可写 const int b[10] = = {1,2,3,4,5,6,6,7,7,8};//只读数组 ``` - 未完全初始化:**不初始化,数组里面同变量一样全是垃圾值,如果部分初始化,其余值为0** - 指定初始化器:C99增加的特性,可以指定某个位置的值 ``` int a[10] = {1, 2, 3, [4] = 10, 5, 6, [9] = 20}; // 1, 2, 3, 0, 0, 10, 5, 6, 0, 20 //直接到指定的值给其赋值,中间未赋值的设置为0 ``` - 赋值:通过循环依次给数组赋值,**不允许作为单元给数组赋值** ``` for(i=0; i 编译器是相信程序员的,程序员最好声明数组时,用符号常量来表示数组大小 - 变长数组(VLA):c90不允许,c99允许,c11可选(不是必备) ``` int a = 5; int a[a]; //a为变量,非常量 ``` ### 多维数组 - 申明:第一个是行,第二个是列 ``` int a[3][4]; ``` - 初始化:2种方式 ``` int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; int a[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} }; // 3行4列 ``` - 赋值:使用双重循环进行赋值 ``` for(a = 0; a < ROWS; a++) for( b = 0 ; b < COLS; b++) arr[a][b] = a + b; ``` ### 指针和数组 - 指针与数组的联系:数组名是数组首元素的地址,首地址加1是下一个元素的地址 ``` int a[3]; // a == &a[0]; ``` ``` #include #define SIZE 10 int main(){ short a[SIZE] = {1,2,3,4,5,6,7,8,9,10}; double b[SIZE] = {1,2,3,4,5,6,7,8,9,10}; short i, *pa = a; double *pb = b; for (i = 0; i < 2; ++i) { printf("pa%d point %p\n", i, pa++); } for (i = 0; i < 2; ++i) { printf("pb%d point %p\n", i, pb++); } } // pa0 point 0060FF00 // pa1 point 0060FF02 // pb0 point 0060FEB0 // pb1 point 0060FEB8 ``` > 系统中,地址是按字节编址,而在c语言中指针加1是指增加一个存储单元,而不是固定的字节 ``` a[SIZE]; // a+5 == &a[0+5] *(a+5) == a[5] *a+1 ==> (*a)+1 ==> a[0]+1 *(a+1) ==> a[1] ``` ### 数组的传递 - 函数原型与定义(数组):**通过传指针的方式,传数组** ``` int sum(int *, int); //通过指针传递(数组首地址) int sum(int [], int); //等效1,提醒读者是数组 int sum(int * a, int n){} int sum(int a[], int n){} ``` - 调用数组:**传递数组首地址** ``` sum(a, SIZE); //a为数组名, SZIE为数组大小 ``` - 指针形参:传2个指针表示数组的开始和结束 ``` int sum(int * start, int * end){ int sum = 0; while(start < end){ sum += *start; start++; } return sum; } ``` **是否可以 sum += *start++ ? 答案是可以的** ``` #include #define SIZE 4 int sum(int * start, int * end){ int sum = 0; while(start < end){ sum += *start++; //分析 * ++(后缀) 同优先级右结合 //步骤分解 1. start先使用用 sum = sum + *start; // 2. start = start + 1; } return sum; } int main(void){ int a[SIZE] = {1, 2 , 3, 4}; printf("%d", sum(a, a+SIZE)); return 0; } // 10 正确 ``` ** 另外两种形式又怎样呢? ** ``` #include int a[2] = {1, 2}; int main(){ int *p1, *p2, *p3; p1 = p2 = p3 = a; printf("%d,%d,%d\n", *p1, *p1++, *p1); //分析: 函数中参数的传递的顺序是从右往左传递 // 1.*p1 = 1 ==> no3 = 1 // 2.*p1++ ==> *p1 = 1 , p1 += 1 ==> no2 = 1 // 3.*p1 ==> a[1] ==> no3 = 2 printf("%d,%d,%d\n", *p2, (*p2)++, *p2); // 1.*p2 = 1 ==> no3 = 1 // 2.(*p2)++ ==> *p2 = a[0], no2 = 1, a[0] = 2 // 3.*p2 = a[0] = 2 ==> no1 = 2; printf("%d,%d,%d\n", *p3, *++p3, *p3); // 1.*p3 = a[0] ==> no3 = 2 // 2.*++p3 ==> p3= p3+1 = &a[1] => no2 = *&a[1] = 2 // 3.*p3 = a[1] = 2 ==> no1 = 2 return 0; } // 2 1 1 // 2 1 1 // 2 2 2 ``` > 函数中参数的传递的顺序是从右往左传递 ### 指针操作 - 赋值 - 解引用 - 取地址 - 与整数相加 - 递增 - 与整数相减 - 递减 - 求差 - 比较 ### 保护数组数据 - 原因:通过地址传的数组都是原始数据,可以改变 但有些时候不需要改变数组的原始数据 - 对形参使用const:不需要改变数组内容时,最好加上const ``` int sum(coust int *, int); //不能完全保护 int sum(const int [], int); //完全保护 ``` - const其他内容:const比#define更加灵活,不应该把const数组作实参传递 ``` const double PI = 3.14; //PI值不能被改变 const int a[SIZE] = {1,3,4}; //数组值不能被改变 const int *p = a; //将int类型声明为const,不能用p来改变a的值 //可以用数组改变其值,p也可以指向其他变量 int * const p = a; //常量指针不能指向其他地方 //可以修改指向的值 const int * const p = a; //不能指向其他地方,也不能通过p来改变变量的值 ``` ### 指针和多维数组 - 首地址之间的关系:a == a[0] == &a[0][0] 值虽然相同,但代表的含义不同 ``` int a[3][4] = { {1,2,3,4} {5,6,7,8} {7,8,9,1} }; // a == &a[0][0]; 二维数组的首地址 // a[0] == &a[0][0]; 作为第一个数组名a[0]的首地址也为二维数组的首地址 // 即有 a == a[0] 值虽然相同,但代表的含义不同 ``` - 解引用: ``` a &a[0][0] 二维数组首地址 a+2 &a[2] 二维数组第3个元素地址 *(a+2) &a[2][0] 二维数组第3个元素的首地址 *(a+2)+1 &a[2][1] 二维数组第3个元素的第二个元素的地址 *(*(a+2)+1) a[2][1] 二维数组第3个元素的第二个元素的值 ``` - 地址步长:a + 1 跨一个数组元素, *a + 1 跨一个数元素 ``` ``` - 指向多维数组的指针:[]优先级高于*,所以一定要加() ``` int (*p) [2]; //声明含有两个int的数组 int a[2][3]; p = a; //指向二维数组a int * p[2]; //声明一个含有两个指针的数组 ``` - 指针兼容性:指针之间类型没有隐式转化,类型不匹配会编译出错 - 多维数组与函数:形参3种写法,指针式无法省略参数会引发歧义 ``` int sum(int (*p)[COLS], int ROWS); //指针式 int sum(int a[][COLS], int ROWS); //数组式 int sum(int [][COLS], int ROWS); //数组略参式 ``` - 变长数组:变长数组并不能改变大小,只是在初始化的时候可以用变量来初始化大小 ``` int sum(int a[rows][cols], int rows, int cols); //无效顺序 int sum(int rows, int cols, int a[rows][cols]); //有效 int sum(int, int, int a[*][*]); //省略形参名 const int SIZE = 80; int sum[SIZE]; c11允许 ,c90好像不允许 ``` - 复合字面量:C99加入的 { 2,3,4,5,9 } ``` int a[2] = {10 ,20}; //初始化数组 (int [2]) {10, 20}; //初始化匿名数组,必须在创建的同时使用它 (int []) {10, 20}; //省略大小,编译器自动计算 int *p = (int []) {10, 20}; //首地址给指针p sum( (int []){10, 20}, SIZE ); //用作实参 ``` - 小训练:一维数组3种拷贝函数 ``` #include #define N 5 void cp_arr(double [], const double [], int); void cp_ptr(double [], const double *, int); void cp_ptrs(double *, const double *, const double *); void show_arr(double [], int); int main(void){ double source[N] = {1, 2, 3, 4, 5}; double target1[N], target2[N], target3[N]; cp_arr(target1, source, N); cp_ptr(target2, source, N); cp_ptrs(target3, source, source+N); show_arr(target1, N); putchar('\n'); show_arr(target2, N); putchar('\n'); show_arr(target3, N); putchar('\n'); return 0; } void cp_arr(double target[], const double source[], int n){ int i; for (i = 0; i < n; ++i) { target[i] = source[i]; } } void cp_ptr(double target[], const double *source, int n){ int i; for (i = 0; i < n; ++i) { target[i] = *(source+i); } } void cp_ptrs(double target[], const double *source_start, const double *source_end){ while(source_start < source_end){ *target = *source_start++; target++; } } void show_arr(double a[], int n){ int i; for (i = 0; i < n; ++i) { printf("%.2lf ", a[i]); } } ``` - 小训练:二维数组处理函数 ``` #include #define ROWS 3 //行数 #define COLS 5 //列数 void getArr(double [][COLS] ,int); void averageGroup(double [], const double [][COLS], int); double average(const double [][COLS], int); double max(double [][COLS], int); void swap(double *, double *); void show(double [], int, double, double); int main(void){ double arr[ROWS][COLS] = {0}; double aveGroup[ROWS] = {0}; //注意初始化 double ave = 0; double m = 0; getArr(arr, ROWS); averageGroup(aveGroup, arr, ROWS); ave = average(arr, ROWS); m = max(arr, ROWS); show(aveGroup, ROWS, ave, m); return 0; } //给二维数组赋值 void getArr(double a[][COLS], int rows){ int i, j; for (i = 0; i < rows; ++i) for (j = 0; j < COLS; ++j) scanf("%lf", &a[i][j]); } //求每行数据的平均值 void averageGroup(double b[], const double a[][COLS], int rows){ int i, j; double sum = 0; for (i = 0; i < rows; ++i){ for (j = 0; j < COLS; ++j) sum += a[i][j]; b[i] = sum/rows; } } //求所有数据的平均值 double average(const double a[][COLS], int rows){ int i, j; double sum = 0; for (i = 0; i < rows; ++i) for (j = 0; j < COLS; ++j) sum += a[i][j]; return sum/(COLS*rows); } //求二维数组的最大值 double max(double a[][COLS], int rows){ int i, j; for (i = 0; i < rows; ++i) { for (j = 0; j < COLS; ++j) if(a[i][j] > a[i][j+1]) swap(&a[i][j], &a[i][j+1]); if(a[i][j] > a[i+1][j]) swap(&a[i][j], &a[i+1][j]); } return a[i][j]; } //打印结果 void show(double a[], int size, double av, double m){ int i; for(i = 0; i < size; i++){ printf("%.2lf ", a[i]); } printf("\naverage = %.2lf\n", av); printf("max = %.2lf\n", m); } //交换两个变量值 void swap(double *p, double *q){ double temp = *p; *p = *q; *q = temp; } ``` ================================================ FILE: articals/c/data.md ================================================ # C与数据 ### 11种数据类型 - 整型类:int,short(短整型),long(长整型),unsigned(无符号),char(字符整型) - 浮点类:float(单精度),double(双精度) - C90新增:signed(有符号),void(空) - C99新增:*_Boo*l(布尔指)*,_Complex*(复数),*_Imaginary*(虚数) ### 存储单元 - 位:最小的存储单元,存储0或1 - 字节:常用存储单位,几乎所有机器有1字节等于8位,即1字节可以表示0-255之间的整数 - 字:自然存储单位:8位的微型计算机一字为8位,16,32位的为即一字为16位或32位 ### 基本整型类型 1. int型:储存要占1个机器字长,16位机器,范围-32768 ~ 32767目前大多数机器32位,即占4个字节,存储数字范围为:-2147483648 ~ 2147483647 2. short型:存储小于等于int,-32768 ~ 32767 3. long型:储存大于等于int,-2147483648 ~ 2147483647 4. long long型:存储至少64位,即8个字节 5. unsigned型:无符号,只能存储正整数,能存储比signed更大的整数 6. 目前普遍设置:long long 64位8字节,long 32位4字节,short 16位2字节,int 16/32位 2/4字节 7. 常量:超出int范围,视为long,超出long范围,视为unsigned long,继续long long, unsigned long long 8. 用H/h作为short,用L/l作为long, 用LL/ll作为long long,用U/u作为unsigned,例如343H,3234L,35455LL,435345U,534546467ULL 9. char型:一个字节,-128 ~ 127,ASCII编码0~127,存储绰绰有余,C语言将字符常量视为int型非char型,是否有符号看编译器 10. 整型可以表示10,8,16进制,如32,032,0x32/0X32 ### 基本浮点类型 - float:至少6位有效数字,取值至少10的-37到+37次方。通常浮点占32位,8位指数的值和符号,剩下的24位非指数的值和符号。 浮点最大:999999961690316250000000000000000000.000000 超过:*1.#INF00* - double,至少13位有效数字。通常64位,剩下的32位给非指数部分。 - long double 更高的精确要求,至少比double精确 ### 复数和虚数类型 - 复数:float_Complex,double_Complex,long double_Complex - 虚数:float_Imaginary,double_Imaginary,long double_Imaginary ### 类型大小 sizeof()函数 sizeof(int),sizeof(char)等等…… ### 问题 整型,浮点的上溢出,下溢出? # 字符串与格式化输出输入 ### 字符串 string 1. 字符串数组(变量)来存储,char name[40]; 2. 输入scanf("%s",name) name是数组首地址 3. 输出printf("%s",name) 4. 数组大小sizeof(name) => 40,可以写成 sizeof name 5. 字符串长度 strlen(name) =>字符实际长度 6. 空字符结尾(\n) ### 预处理 define - 格式 #define NAME 'shaosuo' - 注意是简单的替换,没有其他操作 ### 限定符 const - 明示常量:limits.h float.h - imits/h:包含*INT_MAX*, *INT_MIN* 等预处理常量数值h - float.h:包含*FLT_MAX*, *FLT_MIN*.. ### 输出函数 printf() #### 转换格式 - %a/A 浮点,16进制,p计数 - %g/G 自动选择%f,%e - %i 有符号10进制整数 - %u 无符号10进制整数 - %% 打印百分号 - %p 指针 - %o 无符号8进制 - %x 无符号16进制 #### 转换修饰符 - 标记:-(左对齐),+(添加符号),空格(空格覆盖正号),#(防止0被删除),0(0填充符号位) - 宽度:数字(最小字段宽度)(用于字段对齐,右对齐) - 精度:.数字 - 类型:h(short),hh(char),j,l,ll,L(long double),t,z #### 返回值 ``` #include int main(){ int a = 0, b =0; int pn1 = printf("ok!\n"); // pn1 = 4 int pn2 = printf("ok!,%d,%d\n",a, b); // pn2 = 8 int sn1 = scanf("%d", &a, &b); // sn1 = 1 int sn2 = scanf("%d%d", &a, &b); // sn2 = 2 printf("pn1=%d, sn1=%d, pn2=%d, sn2=%d\n", pn1, sn1, pn2, sn2); return 0; } ``` - printf()返回正确按照格式变量个数,即打印字符的数 - scanf()返回正确按照指定格式接收的变量个数 # 运算符表达式和语句 ### 基本运算符 - 算数:(),+(取正),-(取负),+,-,*,/,%(取模),=(赋值) - sizeof:如果对象是类型,必须加括号,是变量可以不加,返回字节大小 - %取模运算符:如13%5=3,只能用于整数,不能用于浮点数 - 递增(减)运算符++(--):前缀与后缀区别,**i++ => 先使用 i,再递增,++ i => 先递增 i,再使用** ### 类型自动转换 - 普遍:**较小类型转换为较大类型** - 运算时:两个值被分别两种;类型的更高级别 - 高低:long double,double,float,unsigned long long,long long,unsigned long, long,unsigned int,int(int和long大小可能相同 ) - 参数传递时,char,short转换成int,float转化成double - **赋值语句可能导致类型的升级和降级** ### 类型强制转化 - 格式:(double)a = (double)1 + (double) 1; - 显示使用类型转化比较好,避免不必要的错误 # 控制语句 ### 循环 - 关系运算符,表达式:<,<=,==,>=,>,!= - 真假:**非0 即为真** - 注意:**= 赋值,== 比较** - 优先级关系:x > y + 2 => x = ( y + 2 ) - while语句:非计数循环 ``` #include int main(){ char a[27] = "abcdefghijklmnopqrstuvwxyz"; int i = 0; while( i++ < 26){ printf("%c\n", a[i-1]); //前面+1 ,-1即为真实元素 } return 0; } ``` - for语句:计数循环 - 逗号运算符:结果为右边的值 - 入口,出口条件:while,do while - 嵌套循环 ``` #include int main(){ char lets[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int i, j; for (i = 0; i < 6; i++) { for (j = 0; j <= i; j++) { printf("%c", lets[i*(i+1)/2+j]); } printf("\n"); } return 0; } ``` - 示例:倒序打印(test47.c) ``` #include #include #define MAX_LEN 255 int main(){ char a[MAX_LEN]; scanf("%s", a); int len = strlen(a); while(len-- > 0){ printf("%c", a[len]); } return 0; } ``` - 示例:冒泡排序(test43.c) ``` void bb(int a[]){ int i, j; for (i = 0; i < LEN -1; ++i) { for (j = 0; j < LEN - i - 1; ++j) { if(a[j] < a[j+1]) { swap(&a[j], &a[j+1]); } } } } ``` ### 分支与跳转 - 选择语句 if……:**执行或者跳过这条语句** - 双选语句 if ……else:**在两条语句中进行选择** ``` if(n == 0) s = 1; else s = -1; ``` - 字符输入输出函数:getchar(),putchar(),它们是#include中的**预处理,不是真正的函数** ``` ch = getchar(); //scanf("%c", &ch); putchar(ch); //printf("%c", ch); ``` - ctype.h系列的字符函数:**使用时别忘记头文件** 函数名 | 作用 ---|--- isalnum() | 字母或数组 isalpha() | 字母 isblank() | 空白符 isdigit() | 数字 islower() | 小写字母 isupper() | 大写字母 isxdigit()| 16进制字母 tolower() | 返回小写字母 toupper() | 返回大写字母 - 多重选择if …… (else if) …… else:在多条语句中选择,**完全等价与if else多重嵌套模式** ``` if (score <= 60) score = 6; else if(score <= 70 ) score = 7; else if(score <= 80) score = 8; else score = 10; ``` - 逻辑运算符:&&(与), ||(或),!(非) - 替代iso664.h:and,or,not - 优先级:**!与递增运算符一样,&&大于||** - 条件运算符: ?: ``` max = a > b ? a : b; ``` - 配对:else 与最近的 if 配对 - 循环辅助continue:程序循环到一部分,可以跳过剩余部分,进行下一轮循环 - 循环辅助break:程序循环到一部,直接跳出该层循环,进入下一阶段 - 多重选择switch ……break:可用来替代ifelse,使用break跳出,不往下继续执行 ``` switch (整型表达式) { case 常量1: 语句 case 常量2: 语句 default: 语句 } ``` - 多重case标签 - 跳转语句goto:避免使用goto - **注意:“==” 不要写成“=”,不要忘记打印结果** ``` #include int main(){ char ch, pre; int n = 0; while( (ch = getchar()) != '#' ){ if(pre == 'e' && ch == 'i') //切记 n++; pre = ch; } printf("%d\n", n); //切记 return 0; } ``` - 综合训练:**注意,getchar连续输入要去掉\n,菜单要过滤字符,退出写在循环条件中** ``` #include int main(){ char choice; float fweight = 0, sweight = 0, tweight = 0; float fcharge = 0, scharge = 0, tcharge = 0; float weight, price, charge, orderCharge, orderWeight, account, extCharge, pay; printf("enter a, b, c chooce your goods, q is quit:\n"); while ( (choice = getchar()) != 'q' ) { if('\n' == choice) continue; if( choice == 'a' || choice == 'b' || choice == 'c' ) { switch (choice) { case 'a': price = 2.05; printf("please enter want to buy yangli weight:\n"); scanf("%f", &weight); ; fweight += weight; fcharge += fweight * price; printf("%.2f\n", fweight); break; case 'b': price = 1.15; printf("please enter want to buy taincai weight:\n"); scanf("%f", &weight); sweight += weight; scharge += sweight * price; printf("%.2f\n", sweight); break; case 'c': price = 1.09; printf("please enter want to buy hulubo weight:\n"); scanf("%f", &weight); tweight += weight; tcharge += tweight * price; printf("%.2f\n", tweight); break; default: ; } } else { printf("pleae enter 'a', 'b', 'c' !\n"); } printf("enter a, b, c chooce your goods, q is quit:\n"); } orderWeight = fweight + sweight + tweight; orderCharge = fcharge + scharge + tcharge; account = orderCharge > 100 ? orderCharge * 0.05 : 0; if( orderWeight <= 5 ) extCharge = 6.5; else if( orderWeight <= 20) extCharge = 14; else extCharge = 14 + (orderWeight-14) * 0.5; pay = orderCharge + extCharge - account; printf("******************* order ******************\n"); printf("*name-------price------weight-------charge*\n"); printf("*yang-------$2.05--------%9.2f---------$%9.2f*\n", fweight, fcharge); printf("*tian-------$1.15--------%9.2f---------$%9.2f*\n", sweight, scharge); printf("*hulobo-----$1.09--------%9.2f---------$%9.2f*\n", tweight, tcharge); printf("totalWeight:%.2f, orderCharge:$%.2f", orderWeight, orderCharge); printf("account:$%.2f, extCharge:$%.2f, pay:$%.2f\n", account, extCharge, pay); printf("*************************************************\n"); return 0; } ``` ### 友好的交互 - 缓冲区:字符被收集存储的临时存储区(是否有无缓冲输入取决于系统)正常的都是有缓冲输入 ``` graph LR typeHI!-->|无缓冲区程序立即使用| HI! typeHI!-->|缓冲区| HI! ``` - 结束键盘输入:文件,流,键盘输入 ``` #include int main(){ char ch; while( (ch =getchar()) != '#') { putchar(ch); } } ``` **使用的#字符可能会被我们用到,使用#退出并不一定起作用** **c语言把输入输出设备,视为文件,stdin流表示键盘输入,stdout流表示显示输出** **使用文件的形式来结束键盘的输入** - 文件结尾:Ctrl+Z(曾经操作系统),存储文件大小信息,**EOF(C语言)** ``` #define EOF -1 //stdio.h定义的 ``` ``` while( (ch =getchar()) != EOF) ``` - - **getchar()返回int,可能会报信息,但不影响putchar()输出字符** - - **正确的使用是找到操作系统,文件终止符识别方案,大多数是Ctrl+D,有些是Ctrl+Z** - - **EOF不要加字符的‘’** - 重定向和文件:把stdin流重新赋给文件,主要问题与操作系统有关 ``` testFileIO < words // UNIX与DOS 输入重定向 testFileIO > mywords //输出重定向 DOS Ctrl+Z结束,UNIX Ctrl+D结束 testFileIO < words > mywords //组合重定向 ``` **不能读多个文件,也不能写多个文件,空格不是必须的,写入的会把之前的覆盖掉** - 友好的用户界面 **丢弃换行符两种方式比较** ``` if (ch == '\n') //当输入的字符为换行符时,直接跳入下一轮循环 continue; ``` ``` while( getchar() != '\n' ) //只要输入的字符不为换行符进入下一轮循环 continue; ``` ***问题来了?为什么用第二种不用第一种?*** - 混合字符数字输入: **1.验证输入正确性2.丢弃换行符** ``` if(2 != scanf("%d%d", &a, &b)) break; ``` - 输入验证: **事先预测可能输入,检测和处理** ``` while( scanf("%ld", &n) == 1 && n > 0 ) //验证正整数 ``` - 模块化编程:**用单独的函数,验证输入和管理显示** ``` #include void count(); int get_int(); char get_first(); char get_choice(); int main(){ char choice; count(); while( (choice = get_choice()) != 'q' ){ switch (choice){ case 'a': printf("buy low, sell high\n"); break; case 'b': printf("\a\n"); break; case 'c': count(); break; default: printf("error!!!\n"); break; } } return 0; } //计数 void count(){ int n, i; printf("Count how far?\n"); n = get_int(); for (int i = 0; i <= n; ++i) { printf("%d\n", i); } while( getchar() != '\n' ) continue; } //异常处理 int get_int(){ int n; char ch; while( scanf("%d", &n) != 1 ){ while( getchar() != '\n') putchar(ch); printf("is not a integer!!!\n"); } return n; } //过滤换行符 char get_first(){ char choice; choice = getchar(); while( getchar() != '\n' ) continue; return choice; } //删选合适的字符 char get_choice(){ char choice; printf("please enter a, b, c\n"); choice = get_first(); while( (choice < 'a' || choice > 'c') && choice != 'q'){ printf("please enter correct code!!\n"); choice = get_first(); } return choice; } ``` - 实战例子(test57.c):统计文件字符数 ``` #include #include int main(){ char ch; int count = 0; while( (ch = getchar()) != EOF ) { if(isblank(ch) || ch == '\n') continue; count++; } printf("count : %d\n", count); return 0; } ``` - 实战例子(test61.c):二分查找找1-100中的数 ``` #include int main(){ int ran, lower = 1, upper = 100, i = 0; int smart = (lower + upper) / 2; printf("please enter 1 ~ 100 a integer:"); scanf("%d", &ran); while( ran != smart){ if(ran < smart) upper = smart; else lower = smart; i++; printf("though %d times = %d\n", i, smart); smart = (lower + upper) / 2; } printf("though %d times = %d\n", i+1, smart); return 0; } ``` ================================================ FILE: articals/c/fileIO.md ================================================ # 文件输入输出 ### 文件通信 - 重定向:books > bklist 可能会把不必要的东西输出到文件 - 文件:一系列连续的字节,文本模式,二进制模式 - 文件模式:所有文件内容都以二进制形式存储 - 文本文件:最初使用二进制编码的字符表示文本 - 二进制文件:二进制值代表机器语言代码或数值数据或图片或音乐编码 - 不同操作系统处理不同 MS-DOS读文件\r\n-->\n写文件\n-->\r\n - I/O级别:底层I/O使用操作系统标准I/O,标准高级I/O使用stdio.h头文件的定义的(通用) - 标准文件:C打开3个文件,标准输入(键盘),标准输出,标准准错误输出(显示器) ### 标准I/O - 好处:可移植性强,专门函数简化了操作,输入输出优势缓冲的 - 演示: ``` #include #include int main(int argc, char * argv[]){ int ch; //读取文件,存储每个字符的地方 FILE *fp; //文件指针 unsigned long count = 0; if(argc != 2){ printf("Usage: %s filename \n", argv[0]); } if( (fp = fopen(argv[1], "r")) == NULL ){ printf("can't open %s\n", argv[1]); exit(EXIT_FAILURE); } while( (ch = getc(fp)) != EOF ){ putc(ch, stdout); count++; } fclose(fp); printf("File %s has %lu characters\n", argv[1], count); return 0; } ``` - 检查命令行参数:exit()关闭文件并结束程序(0或EXIT_SUCCESS结束成功,EXIT _FALLURE结束失败) - fopen函数:打开文件,成功打开后返回文件指针(FILE*) ``` FILE * fp = fopen("words", "r"); ``` 模式 | 含义 ---|--- r | 读模式 w | 写模式(文件长度截0,可以创建新文件) a | 写模式(添加字符,可以创建新文件) r+ | 更新模式(读写) w+ | 更新模式(读写,截断,创新) a+ | 更新模式(读写,添加,创新) *b | 二进制文件用法同上 - getc和putc函数:与getchar,putchar类似 ``` ch = getchar(); ch = getc(fp); //文件输入 ch = putchar(); ch = putc(fpout) //文件输出 ``` - 文件结尾:避免读到空文件,使用入口循环 ``` while( (ch = getc(fp)) != EOF) { putc(fpout); } ``` - fclose函数:关闭指定的文件,必要刷新缓冲取区 ``` if (fclose(fp) != 0 ) //成功放回0,否则返回EOF printf("error in closing file %s\n", argv[1]); ``` - 指向标准文件的指针 标准文件 | 文件指针 | 设备 ---|---|--- 标准输入 | stdin | 键盘 标准输出 | stdou | 显示器 标准错误 | stder | 显示器 ### 文件压缩程序 ``` #include #include #include #define N 40 int main(int argc, char * argv[]){ FILE *in, *out; int ch; char name[N]; int count; //检查命令行参数 if(argc < 2){ fprintf(stderr, "Usage:%s filename\n", argv[0]); exit(EXIT_FAILURE); } //设置输入 if( (in = fopen(argv[1], "r")) == NULL){ fprintf(stderr, "I could not open this file\" %s \" \n ", argv[1]); exit(EXIT_FAILURE); } //设置输出 strncpy(name, argv[1], N - 5); name[N -5] = '\0'; strcat(name, ".red"); if( (out = fopen(name, "w")) == NULL ){ fprintf(stderr, "I could not open this file"); exit(3); } //拷贝 while( (ch = getc(in)) != EOF ){ if (count++ % 3 == 0) putc(ch, out); } //关闭文件 if( fclose(in) != 0 || fclose(out) != 0 ) fprintf(stderr, "Error in closing files\n"); return 0; } ``` ### 文件I/O - fprinf和fscanf函数:与printf和scanf类似,区别在于,前面需要第一个参数待处理的文件。 ``` fprintf(fp, "%s\n", words); fscanf(fp, "%s\n", words); ``` - fgets和fputs函数: ``` fgets(buf, LEN, fp); // buf char型数组的名称,fp指针 fputs(buf, fp); ``` ### 随机访问 - fseek() ftell()函数:文件看成数组,fseek返回int.ftell返回long ``` fseek(fp, 0L, SEEK_END); //定位到文件末尾 // 1)FILE指针,指向待查找的文件 // 2)偏移量,从起始点开始要移动的距离,正负0 // 3)模式,SEEK_SET文件开始, SEEK_CUR当前位置,SEEK_END文件末尾 // 正常返回0,c出现错误返回-1 ftell(fp) //返回当前位置 ``` - 二进制模式和文本模式: - - UNIX只有一种文件格式,不需要特殊转换,MS-DOS很多编辑器都是用ctrl+z来标记文件结尾的二进制文件和文本文件模式的另一个不同的地方, - - MS_DOS用户\r\n来标识文件结尾,c程序会把\r\n看做成\n,对于ftell()返回值把\r\n当作一个字节来计数 - 可移植性: - - 二进制模式中,实现不必支持SEEK_END模式,因此无法保证程序的可移植性,更好的办法是一个一个字节读取整个文件 - - 文本模式中,只有使用fseek才能保证其相应的行为 - fgetpos函数,fsetpos函数:新增的定位函数,突破long的限制 ``` int fgetpos(FILE * restrict stream, fpos_t * restrict pos); // 成功返回0,失败返回非0 // 把fpos_t的值放在pos指向的位置 int fsetpos(FILE * stream, const fpos_t * pos); //成功返回0,失败返回非0 // 使用fpos_t设置文件指针指向该值指向的位置 ``` ### 标准IO机理 ``` //第一步:调用fopen打开文件 //1)自动打开3个标准文件 //2)打开文件 //3)打开一个或者两个缓冲区以及其文件缓冲的数据结构 //4)返回一个指向该结构的指针 FILE * fp = fopen("words", "a+"); //第二步:调用stdio.h中的输入函数 //1)文件的数据块被拷贝至缓冲区 //2)设置缓冲区大小,设置fp所指向结构中的值(流中当前位置和拷贝进缓冲区的字节数) ``` ### 其他标准IO函数 函数 | 作用 ---|--- int ungetc(int, FILE*) | c指定的字符放回输入流 int fflush(FILE*) | 刷新缓冲区 int setcbuf(FILE*,char *, int, size_t) |创建一个供io替换的缓冲区 size_t fread() | 二进制out size_t fwirte() | 二进制in - size_t fwrite函数:返回sizeof运算后的类型 ``` size_t fwrite(const void * restrict ptr, size_t size, size_t nmemb, FILE * restrict fp); // ptr 待写入的地址,size数据块的大小, nmemb带写入数据块的数量,fp待写入的文件 char buffer[256]; fwrite(buffer, 256, 1, fp); double earnings[10]; fwrite(earings, sizeof(double), 10, fp); ``` - size_t fread函数:返回sizeof运算后的类型 ``` size_t fwrite(void * restrict ptr, size_t size, size_t nmemb, FILE * restrict fp); // ptr 待读取文件数据在内存中的地址,size数据块的大小, nmemb带写入数据块的数量,fp待读取的文件 char buffer[256]; fwrite(buffer, 256, 1, fp); double earnings[10]; fwrite(earings, sizeof(double), 10, fp); ``` ================================================ FILE: articals/c/function.md ================================================ # 函数 ### 复习函数 - 什么是函数:完成特定任务的独立程序代码单元 - 函数的作用:省去重复多于代码,提高代码可读性,方便修改 - 函数的构成: - - 函数原型:声明函数,告诉编译器函数的类型 - - 函数调用:使用函数 - - 函数定义:实现函数 ``` int fun(char s); //申明函数 fun('a'); //调用函数 int fun(char s){ return s; } //实现函数 ``` - 函数形参:局部变量,内部私有,每个变量要求声明类型 ``` void show(int, int); //也是合法的 ``` - 函数实参:实参是具体的值, 会赋值给形参 - 返回值:测试函数的程序称为驱动程序,return语句会终止函数并把控制交给主调函数 - 无参数:注意加void ``` void show(void); ``` ### 递归 - 定义:C允许函数调用自己,这种调用称为递归 - 演示: ``` #include int up_and_down(int); int main(void){ up_and_down(1); return 0; } int up_and_down(int n){ printf("%d, %p\n", n, &n); if(n < 4) up_and_down(n+1); printf("%d, %p\n", n, &n); } // 1, 0060FF20 // 2, 0060FF00 // 3, 0060FEE0 // 4, 0060FEC0 // 4, 0060FEC0 // 3, 0060FEE0 // 2, 0060FF00 // 1, 0060FF20 ``` - 原理: - - 每次调用都有自己的变量,变量都是n但值不同 - - 每次调用完之后都会返回一次,逐级返回 - - 调用之前的顺序执行,调用之后的倒序返回 - - 没有拷贝函数代码,可以代替循环,可以被i循环代替 - - 必须包含让递归停止的语句 - 尾递归:递归调用置于函数的末尾,相当于循环,能使用选择循环,莫使用递归(速度,内存优势) - 递归和倒序计算 - 整数化二进制 - ``` void to_binary(int n){ int r; r = n % 2; if( n >= 2 ) to_binary( n/2 ); printf("%d", r==0 ? 0 : 1); } ``` - 递归优缺点:**为很多程序提供了简单的解决方案,但效率和消耗不令人满意** ### 多文件编译 - 预处理和申明函数放在头文件中 - 使用命令编译(linux) ``` gcc file1.c file2.c //一起编译 gcc file1.c file2.o ``` ### 指针 - 本质:值为内存地址的变量 - 作用:存储变量的地址 - 取地址符&:得到变量的地址 &a 表示a的地址 - 解引用符*:找到存储在地址中的值 *&a ==> a - 用%p打印地址 - 声明与赋值:严格区分开 ``` int * pi; //声明int型指针 pi = &a; //给指针赋值 int *pi = &a; //上面两步合并成一步 b = *pi; //获取pi所指向地址中存储变量的值并赋值给b ``` - 使用指针在函数间通信:函数传值无法真正的改变实参的值,传地址可以改变实参的值。 - 交换两个整数值: ``` #include void swap(int *, int *); int main(void){ int a = 1, b =2; swap(&a, &b); printf("%d, %d\n", a, b); return 0; } void swap(int *p, int *q){ int temp; temp = *p; *p = *q; *q = temp; } ``` - 小训练1:10进制转任何进制 ``` void to_base_n(int x, int n){ int r; r = x%n; if(x >= n) to_base_n(x/n, n); printf("%d", r ); } ``` - 小训练2:Fibonacci递归与非递归 ``` #include int fibonacciRec(int); //递归 int fibonacci(int); //非递归 int main(void){ int n; scanf("%d", &n); printf("%d\n", fibonacciRec(n) ); printf("%d\n", fibonacci(n) ); return 0; } int fibonacciRec(int n){ if(n == 1 || n == 2) return 1; else return fibonacciRec(n-1) + fibonacciRec(n-2); } int fibonacci(int n){ int i, fib1 = 1, fib2 = 1; if( n == 1 || n == 2) return 1; for(i = 3 ; i <= n; i++){ fib2 = fib1 + fib2; fib1 = fib2 - fib1; } return fib2; } ``` ================================================ FILE: articals/c/memory.md ================================================ # 内存管理 ### 存储类别 - 对象(object):被存储的值占有一定的物理内存 > 此对象非面向对象中的对象 - 访问(access):声明变量来访问对象,也可以通过其他方式指定对象 ``` int entity = 3; //声明变量访问 int * pt = &entity; //指针访问 int rank[10]; //数组访问 ``` - 作用域(scope): - - 块作用域:使用的局部变量(包含形参)都有块作用域 ,C99扩展了声明 - - 函数作用域:仅用于goto,延伸整个函数 - - 函数原型作用域:从形参定义到原型结束,形参名并不重要,仅变长数组需要 - - 文件作用域:定义在函数外面,从该定义至文件末尾均可见(全局变量) ``` double blocky(double a){ double b; for(int c=0; c<10; c++){ ... } } //a, b, c 都具备块作用域 ``` - 链接(linkage): - - 外部链接:全局作用域,在多个文件中使用的且具有文件作用域 - - 内部链接:文件作用域,在一个文件使用且具有文件作用域 - - 无链接:局部作用域,具有块,函数,原型作用域 ``` static: int giants = 5; //文件作用,外部 static int dodgers = 3; //文件作用,内部 ``` - 存储期(storage duration):对象在内存中保留的时间 - - 静态存储期:执行期间一直存在,文件作用域变量具有静态存储期 - - 线程存储期:用于并发设计,从申明至线程结束 - - 自动存储期:块作用域变量通常具备自动存储期 - - 动态分配存储期: - 存储类别:5种 存储类别 | 存储期 | 作用域 | 链接 | 声明 ---|---|---|---|--- 自动 | 自动 | 块 | 无 | 块内 寄存器 | 自动 | 块 | 无 | 块内 使用register 静态外部链接 | 静态 | 文件 | 外部 | 函数外 静态内部链接 | 静态 | 文件 | 内部 | 函数外 使用static 静态无链接 | 静态 | 文件 | 无 | 块内 使用static - 自动变量: - - 使用auto显示声明(不同于c++中auto) - - 内层变量于外层同名:暂时隐藏外层变量,等运行完后回到原来作用域、 ``` #include int main(void){ int i = 3; for (int i = 0; i < 10; ++i) printf("%d ", i); printf("file:%d\n", i); return 0; } // 0 1 2 3 4 5 6 7 8 9 file:3 ``` - - 初始化:自动变量不会初始化除非显示初始化,未初始化会造成不可预期的异常 - 寄存器变量:存储在cpu中,处理速度更快的自动变量 - 静态内部链接变量:只能用于同一文件的函数中 ``` static int a = 0; int main(){} ``` - 静态外部链接变量:外部变量(external variable) - - 使用其他文件的变量必须再次声明,函数内则可以不必声明 ``` int a; //定义外部变量,给全局 extern char coal; //声明使用其他文件外部变量 int main(){ extern char coal; //再次声明变量,可以省略 char coal; //定义的自动变量,隐藏了外部变量 } ``` - - 初始化:可以显示初始化,也可以自动初始化为0,只能用常量表达式初始化 - - 使用:函数内使用时,可以声明加extern,也可以不申明 - - 定义和申明:**extern表明声明的变量定义在别处** ``` int tern = 1; //定义并初始化 extern int tern; //此文件声明,也可以不申明 extern int a; //必须有其他文件定义过a extern int b = 0; //错误,extern只能申明不能初始化 ``` 存储类别说明符:auto, register,static,extern,_ Thread_local,typedef 存储类别与函数:外部函数(默认), 静态函数, 内联函数(C99) ``` double a(); //外部函数,其他文件可以使用 static double beta(); //静态函数,此文件使用 extern double c(); //内联函数,其他文件定义的函数 ``` > 存储类别:按需使用 ### 随机数函数和静态变量 ``` #include static unsigned long int next = 1; //种子 unsigned int rand0(void){ next = next * 1103515245 + 12345; return (unsigned int) (next / 65536) % 32768; } void changeNext(unsigned int seed){ next = seed; } ``` ### 掷色子 ``` #include #include int roll_count = 0; int roll_n_dice(int, int); int rollem(int); // int main(void){ // for (int i = 0; i < 10; ++i) // { // printf("%d\n", rollem(6)); // } // return 0; // } //生成1 - 6 之间的随机数 int rollem(int sides){ int roll; roll = rand() % sides + 1; roll_count++; return roll; } int roll_n_dice(int dice, int sides){ int d; int total = 0; if(sides < 2) return -2; if(sides < 1) return -1; for (d = 0; d < dice; ++d) total += rollem(sides); return total; } ``` ``` #include #include #include #include "testRandom.c" int main(void){ int dice, roll; int sides, status; srand((unsigned int) time(0)); printf("enter a number of sides:\n"); while(scanf("%d", &sides) == 1 && sides > 0){ printf("how many dice\n"); //检查输入部分 if(status = scanf("%d", &dice) != 1){ if(status == EOF) //检查是否有文件终止符 break; else{ while(getchar() != '\n') //去掉换行符 continue; continue; } } //开始计算骰子总和 roll = roll_n_dice(dice, sides); //打印结果 printf("total %d , using %d times, %d-sides\n", roll, dice, sides); } printf("function called : %d\n", roll_count); return 0; } ``` ### 分配内存 - malloc与free函数:可以申请所需内存 ``` #include //使用时声明 double *p; p = (double *) malloc(30 * sizeof(double)); //申请内存块给指针 // p为内存的首地址,可以作为数组名使用,比变长数组更灵活 free(p); //回收内存,配套使用,如果不使用会造成内存泄露,即耗尽 //malloc 可能分配不到内存,放回空指针 if( p == NULL ) exit(EXIT_FALLURE); ``` - calloc与free函数:和malloc略有区别 ``` double * p; p = (double *) calloc(30 , sizeof(double)); //把块所有位置设置为0 free(p); ``` - 存储类别和动态内存分配:自动对象,静态对象,动态对象存储在不同区域 ### 类型限定符 - 恒常性:const关键字申明的对象不能,赋值,递增或者递减来修改 - - 指针和形参中申明const ``` const float * p; //指向float类型的const值 float const * p; //同上 float * const p; //常量指针,不能指向其他值 const float * const p; //前面2个的结合 int sum(const int * p, const int p[]) //两个形参意义相同,表示数组数据不能更改 ``` > const 放在*左边表示指针指的对象是const,放在*右边表示指针是const - - 对全局使用const:避免数据被更改,2种策略 ``` // 外部变量,给其他地方声明 const int a = 1; //file1.c extern const int a; //file2.c // 使用头文件 static const int a = 1; //file.h #include "file.h" //file.c ``` - 易变形:volatile 涉及编译器(寄存器)的优化,const和volitile同时使用时顺序不重要 - 新增:restrict(c99表明指针是唯一访问,并初始的方式), _Atomic(c11并发程序中要用到的) - 新位置:c99加入 ``` int sum( int * const a, int * restrict b); //旧式 int sum( int a[const], int b[restrict]); //新式 ``` - 小训练:动态分配字符(待调bug) ``` #include #include #define SIZE 20 int get_n(){ int words; if(scanf("%d", &words) == 1 && words > 0) return words; else printf("enter error!!!\n"); } void show(char * a[], int n){ int i = 0; while( i++ < n ){ puts(a[i-1]); } } int main(void){ int words, i = 0, j = 0; char ch; printf("how many words do you wish to enter:"); words = get_n(); //处理输入的单词数 // char * q [5] = (char (*) [5])malloc( SIZE * 5 * sizeof(char) ); //动态创建 printf("enter %d words:", words); while( (ch = getchar()) != '\n' ){ if(ch == ' ') { char * p = (char *)malloc( i * sizeof(char) ); q[j] = p; free( p ); j++; i = 0; continue; } i++; } show(q, words); free( q ); return 0; } ``` ================================================ FILE: articals/c/string.md ================================================ # 字符串 ### 表示字符串和字符串IO ```c #define MSG = "hello world!"; char a[MAX] = "hello world!"; char * p = "hello world!"; puts(MSG); puts(a); puts(p); ``` ### 定义字符串 - 字符串字面量:双引号括起来的内容,编译器会自动加入\n,双引号之间紧邻或者空格看作相连的 ```c char * a = "hello " "world!"; // hello world! ``` 函数中使用字符串,只存储一次,被视为指向该字符串位置的指针 ```c printf("%s, %p, %c\n", "hello", "world", *"ok"); // hello,0X000000999,o ``` - 字符串数组:和字符数组区别,两种初始化方式 ```c char a[40] = "sadasfsdfgsdgfdgfdhfdh"; //简易初始化 char a[40] = {'a','b','c'...'g', '\n'} //标准初始化 char a[] = "dsfsdfsdfdsfsdfsdf"; //编译器自动计算长度 const char * a = "sdsafsdfsdfsdfsfdf"; //同上 //定长初始化中未被初始化的部分填充'\0' ``` - 数组形式与指针形式区别 - - 数组形式的a == &a[0] 只能作为常量,不能进行a++等操作,指针形式a 是可以进行a ++的 - - 指针对数据类型匹配很高,指向常量的指针需要被声明为常量const char * p = "abc"; - - 意味着不能用p改变数据的值,但可以改变p的位置 - - 初始化数组把静态存储区的字符串拷贝给数组,初始化指针只是把字符串的地址给指针 - 字符串与数组 ```c //相当于字符的二维数组 char f[3][4] = {{"ab"},{"cd"},{"e"}}; // ab\0, cd\0, e\0\0 //相当于3个字符串指针 const char * p[3] = {{"ab"},{"cd"},{"e"}}; // ab\0, cd\0, e\0 自动获取大小 ``` - 字符串与指针:指针拷贝也只拷贝地址,没有拷贝整个字符串 ### 字符串输入 - 分配空间:用显示声明来输入,否则会丢失数据 ```c char *name; scanf("%s", name); //不好 char name[SIZE]; scanf("%s", name); //可以的 ``` - gets()函数:已废弃,并不知道字符串有多长,输入字符过长导致缓冲区溢出,可能导致其他数据被擦除 ```c #include int main(void){ char name[10]; gets(name); puts(name); return 0; } //gcc 编译没报任何消息 //fgdfgdfgdfgfdgfdg //fgdfgdfgdfgfdgfdg ``` > 实际情况:大多数编译器仍支持 - fgets()函数:可以替代gets(),可扩展,可以从文件输入,保留换行符,需要手动设置为空字符 - - 读一行:读到换行或者读到n个字符,最终打印的n-1个字符 ```c #include int main(void){ char a[10]; fgets(a, 7, stdin); //读了dsfdsf个字符+'\0' fputs(a, stdout); //输出dsfdsf\0 没有+'\n' return 0; } //dsfdsfsdgfdgdffdg //dsfdsf ``` - - 连续读取,fgets可以存储换行符,读完一段,继续读剩下的,可以直接读到文件尾部 ```c #include #define N 10 int main(void){ char word[N]; while( fgets(word, N, stdin) != NULL && word[0] != '\n' ){ fputs(word, stdout); } return 0; } ``` - - 每行只读一定数量的字符,并丢弃了换行符 ```c #include #define N 10 int main(){ char word[N]; int i; while( fgets(word, N, stdin) != NULL && word[0] != '\n'){ i = 0; while(word[i] != '\n' && word[i] != '\0') i++; //不是换行符或者空字符跳过 if(word[i] == '\n') word[i] = '\0'; //遇到换行符,转空字符 else while(getchar() != '\n') //读到空字符,丢弃剩余 continue; fputs(word, stdout); } return 0; } ``` > 空字符于空指针:空字符('\0')与空指针(NULL)都可以用0表示,但空字符是字符型(1字节),空指针是指针型(4字节) - gets_s()函数:c11新增,可扩展,只从标准输入中输入,丢弃换行符,输入太长时更安全 - s_gets()函数:fgets()变体,遇到换行符设为空,遇到空丢弃其余字符 - scanf()函数:可指定宽度,但遇空格即终止,只能用于输入单词 ### 字符串输出 - puts()函数:使用字符串地址作参数,自动添加换行符 - fputs()函数:用于文件输出,不添加换行符,遇fgets()配对使用 - printf()函数:不自动加换行符,打印多个字符更简单 ### 自定义输入输出 ### 字符串函数 (类型)函数名 | 参数 | 作用 ---|---|--- int strlen | char * | 统计字符串长度 char * strcat | char *, char * | 把第二个字符串拼接在第一个上 char * strncat | char *, char *, int | 把第二个字符串指定长度添加到第一个字符串上 int strcmp | char *, char * | 比较两个字符串,相同返回0,二大于1返回正,否则返回负 int strncmp | char *, char *, int | 限定比较的字符串长度 char * strcpy | char *, char * | 把第二个拷贝到第一个 char * strcpy | char *, char * int | 限制拷贝的字符串长度 void sprintf | char *, 格式化, name | 将printf的内容存储在一个字符串中 ### 字符串排序 - 示例 ```c #include #include #define SIZE 81 //字符串长度 #define LIM 20 //最大行数 #define HALT "" //读到空字符结束 void strSort(char * str [], int num); //排序函数 char * strGets(char * , int ); //输入字符串函数 int main(void){ char in[LIM][SIZE]; char * pstr[LIM]; int ct = 0, k = 0; //输入输出计数 while(ct < LIM && strGets(in[ct], SIZE) != NULL && in[ct][0] != '\0'){ pstr[ct] = in[ct]; ct++; //输入字符串 } strSort(pstr, ct); //排序字符串 for(k = 0; k < ct; k++) puts(pstr[k]); //输出字符串 return 0; } //选择排序 void strSort(char * str [], int num){ char *temp; int top, seek; for (top = 0; top < num-1; ++top) { for (seek = top + 1; seek < num; ++seek) { if( strcmp(str[top], str[seek]) > 0 ) temp = str[top]; str[top] = str[seek]; str[seek] = temp; } } } //自定义输入函数 char * strGets(char * str, int n){ char * ret_val; int i = 0; ret_val = fgets(str, n, stdin); if(ret_val){ while(str[i] != '\n' && str[i] != '\0') i++; if(str[i] == '\n') str[i] = '\0'; else while(getchar() != '\n') continue; } return ret_val; } ``` - 排序单位是指针:排序的是指针而不是字符串本身 - 选择排序算法 ```c //伪代码 for n = 首元素 to n=倒数第2个元素 找出剩余元素中的最大元素,并将其放在第n个元素 //C代码 for(top = 0; top < n - 1; top++) for(seek = top + 1; seek < n; seek++) if(a[top] > a[seek]) swap(&a[top], &a[seek]); ``` ### 命令行参数:int argc, char *argv[] ```c int main(int argc, char *argv[]) { argc // 命令行字符串数量 argv // 字符串数组指针 argv[n] 表示第n个字符串的地址 } ``` ```c #include int main(int argc, char * argv[]){ int i = argc; printf("%d\n", argc); while( i-- > 1 ) puts(argv[i]); } // --i情况 (没想到argc = 4) (- -) // test86 see you later 0 1 2 3 // 1) (i = 4- 1 = 3, i > 0) -> a[3] // 2) (i = 3- 1 = 2, i > 0) -> a[2] // i--情况 // 1) (i = 4 > 0, i = 3 - 1 = 2) -> a[3] // 2) (i = 3 > 0, i = 2 - 1 = 2) -> a[2] // 3) (i = 2 > 0, i = 1 - 1 = 1) -> a[1] ``` ### 字符串转数字 - 小训练:逆转字符串 ```c void reStr(char * a, int n){ int i = 0; char b[n]; while(i++ < n) b[i] = a[i-1]; i = 0; while(n-- >= 0){ a[i] = b[n]; i++; } } ``` - 小训练:命令行输出 ```c #include #include #define N 10 void pf(char * , int); void toUpper(char * , int); void toLower(char * , int); int main(int argc, char * argv[]){ char a[N]; switch (argv[1][1]){ case 'p': pf(a, N); break; case 'u': toUpper(a, N); break; case 'l': toLower(a, N); break; default : puts("enter error!"); break; } return 0; } //原样输出 void pf(char * a, int n){ while( fgets(a, n, stdin) != NULL && a[0] != '\n'){ fputs(a, stdout); } } //输出大写 void toLower(char * a, int n){ int i; while( fgets(a, n, stdin) != NULL && a[0] != '\n'){ i = 0; while(i++ < n-1){ // i=0<9 i=1 a[0], i=1<9 i=2 a[1] ---> i=8<9 i=9 a[8] if(isupper(a[i-1])) a[i-1] = tolower(a[i-1]); } fputs(a, stdout); } } //输出小写 void toUpper(char * a, int n){ int i; while( fgets(a, n, stdin) != NULL && a[0] != '\n'){ i = 0; while(i++ < n-1){ if(islower(a[i-1])) a[i-1] = toupper(a[i-1]); } fputs(a, stdout); } } ``` ================================================ FILE: articals/c++/class.md ================================================ # 类(7.14) > 基本思想:数据抽象,封装。数据抽象是一种依赖于接口于实现分离式编程技术 ### 抽象数据类型 - 设计类 - 改进类 - 定义成员函数 - 引入this - 引入const成员函数 - 类作用域和成员函数 - 外部定义成员函数 - 定义返回this对象的函数 - 定义非成员函数 - 构造函数:特殊的成员函数控制对象的初始化,只要对象被构建就会执行构造函数 ``` 1)没有返回类型,含有一个参数列表和函数体 2)可以包含多个构造函数,但构造函数之间必须是重载的 3)构造函数不能声明成const,创建const对象时,直到构造函数完成才能获得常量属性 4)没有构造函数会执行默认初始化,通过一个特殊的构造函数来初始化对象,无须任何实参 5)执行顺序,存在类内初始值,用其初始化,否则默认构造函数初始化 6)只有当不存在任何构造函数的情况下,编译器才会帮我们创建默认构造函数,否则不会 7)包含内置类型或复合类型的成员可能产生未定义的值 8)类中包含其他类型成员且这个成员的类型没有默认构造函数,也不会生成默认构造函数 ``` - 拷贝赋值析构 ### 访问控制、封装 - 公有与私有 - 友元:允许一个非成员函数访问类的私有成员,关键词friend,声明可以出现在类内部的任何地方 - - 1)将非成员函数reset(),声明为example类的友元,可以访问私有成员 ``` // class example; // 这里必须对类 example 做前向声明,否则下面的函数声明将报错 void reset(example &e); class example { public: friend void reset(class example &e); private: int n; }; // 该函数定义必须放在类 example 的后面,否则无法解析变量n void reset(example &e) { e.n = 0; } ``` - - 2)将man设为woman的友元类,这样man对象的任何成员函数都可以访问woman的私有成员 ``` class woman; // 前向声明 class man { public: void disp(woman &w); void reset(woman &w); }; class woman { public: friend class man; // private: string name; }; void man::disp(woman &w) { cout << w.name << endl; } void man::reset(woman &w) { w.name.clear(); } ``` - - 3)将一个类的成员函数声明为一个另一个类的友元函数,从而来访问私有函数 ``` [cpp] view plain copy print? class woman; // 前向声明 class man { public: void disp(woman &w); void reset(woman &w); }; class woman { public: friend void man::disp(woman &w); private: string name; }; void man::disp(woman &w) { cout << w.name << endl; } // man的reset()成员函数不是woman类的友元函数,因此不能访问其私有成员 /* void man::reset(woman &w) { w.name.clear(); } */ ``` - - **友元定义与声明存在依赖关系,一定要弄清楚顺序** > 原则:对象的声明里的其他对象必须放在该对象之前声明,对象的定义里的对象必须放在该对象之前定义 - - 重载函数:多个重载函数的版本,那么可以将其中的一个或者几个设为某个类的友元。其他的函数不受此设置的影响 - - 友元必须具备public权限,否则不能调用 ### 类的特性 - 类成员 - 返回*this函数 - 类类型 - 友元2 ### 类作用域 - 名字查找 - 构造函数2 - 委托构造函数 - 默认构造函数 - 隐式类转换 - 聚合类 ### 静态成员 - 声明静态成员 - 使用静态成员 - 定义静态函数 - 内类初始化 - 特殊作用 ================================================ FILE: articals/c++/function.md ================================================ # 函数 ### 函数基础:兼容C - 典型的函数:返回类型,函数名字,0个或多个形参组成的列表,函数体 - 函数调用:实参初始化形参,控制权转移给被调函数 - 实参与形参:实参是形参的初始值,实参类型必须与形参类型匹配,至少可以隐式的转换成形参 - 形参列表:可以为空,但不能省略,为了与c兼容加上void,任何形参都不能同名,而且外层作用域的局部变量不能与形参同名 - 返回类型:大多数类型都能作为函数返回类型,void是特殊的返回类型,表示不返回任何值,不能是数组或者函数类型,但可以是它们的指针 - 局部对象:名字有作用域,对象有生命周期,形参和函数体内部都变量都是局部变量,仅在函数作用域可见 - 自动对象:只存在于块执行期间的对象称自动对象 - 局部静态对象:将局部变量定义成static类型,在执行路径第一次经过对象定义语句初始化,程序结束后被销毁 - 函数声明:函数只能定义一次,但可以声明多次,用分号代替函数体,也称函数原型,记得在头文件中声明 - 分离式编译:编译和链接多个文件 ### 参数传递:传值和引用 - 传值参数:初始值拷贝给对象,对变量改变不会影响初始值,指针形参可以间接访问他所指向的对象,可以修改对象的值 - 传引用参数:通过引用形参,允许函数改变一个或者多个实参的值 ``` #include void swap(int &a, int &b){ int tem = a; a = b; b = tem; } //传引用 int main(void){ int c = 1, d = 2; swap(c, d); std:: cout << c << d << std:: endl; } // 结果:21 ``` - - 使用引用可以避免拷贝,拷贝大的类型或者容器对象比较低效 - - 使用引用参数返回额外的信息,一个函数只能返回一个值,引用给我提供了解决方法 ``` //返回指定字符串中指定字符的位置和出现的次数 string::size_type find_char(const string &s, char c, string::size_type &occurs){ auto ret = s.size(); occurs = 0; for(decltype(re)) } ``` - - const形参和实参:同样的规则应用到形参上 ``` int b; void reset(int &a); reset(b);//参数为引用,只能用int对象,不能用字面量,需要转换的对象,const int void reset(int *a); reset(&b);//参数为指针,只能用int *对象 //允许字面量初始常量引用 ``` - - 尽量用常量引用:把函数不会改变的形参定义称引用是一种比较常见的错误,给调用者误导这是可以修改的,同时限制了实参的类型 - - 数组形参:不允许拷贝数组,只能通过指针形式来传值 ``` //比c语言多一样 void print(const int *); void print(const int []); void print(const int [10]); //期望的长度,不一定 //通过显示传递参数来表示数组的大小 void print(const int [], size_t ); //数组引用形参 void print(int (&arr)[10]); //多维数组 void print(int (*mat)[10], int row); void print(int mat[][10], int row); ``` ### 返回类型 ### 函数重载 ### 特殊用途 - 默认实参:有一种形参很多次调用都赋予相同的值,这样的值称为默认实参 ``` //默认实参的形式,直接在函数中给形参赋值,一旦某一形参被赋予了值,后面所有形参都必须赋默认值 string screen(sz ht = 24, sz wid = 80, char background = ''); //使用默认实参,默认实参按位置解析,负责填写缺少的尾部实参,只能是尾部的 //调用必须赋值赋满所有的形参 window = screen(); ==> 24, 80, '' window = screen(66); ==> 66, 80, '' window = screen(66, 256); ==> 66, 256, '' window = screen( , ,'a'); ==> 错误,只能省略尾部的,从第一位开始填写的 //通常声明放头文件中,函数只声明一次,可以声明多次但形参不能重复赋值 //默认实参是可以初始化的,必须在函数之外进行 sz sw = 80; string screen(sz ht = 24, sz wid = sw, char background = ''); ``` - 内联函数:避免调用函数开销,在每个调用点内联的展开,优化规模较小,流程直接,频繁调用的函数 ``` inline const string & shorterString(const string &s1, const string &s2){ return s1.size() <= s2.size() ? s1 : s2; } cout << shortrtString(a,b) << endl; ==> cout << s1.size() <= s2.size() ? s1 : s2 << endl; //内联的展开 ``` - - 用函数的内联取代宏原因 ``` 1)宏代码最大的缺点容易出错 2)宏无法进行调试 3)宏无法操作类的私有成员 ``` - - 函数内联的工作原理:将内联函数的返回值,形参,函数放入符号表,没有错误则将代码放入符号表,发现正确调用后直接替换调用语句 - - 优点:==具备宏的效率,增加了安全型,又可以自由的操作类的成员==,编译器可以根据上下文对代码进行深优化 - - 注意: ``` 1)inline必须与函数定义放一起才算真正的内联(声明时没多大必要加inline) 2)定义在类内部的函数会自动变成内联函数 3)定义有必要放头文件,这样每个文件都可以访问到,否则每个源文件都有从新定义它 4)慎用内联,函数只有10行甚至更小时才用内联,内联会增加代码的长度,复杂的代码增加更多的执行开销和内存消耗 5)内联的声明只是请求,是否使用取决于编译器,太长的函数编译器可能拒绝使用内联 ``` - constexpr:能用于常量表达式的函数,函数返回类型和形参必须都是字面量类型,函数有且只有一个return语句 ``` constexpr int new_st(){ return 42; } //常量函数 constexpr int foo = new_st(); //常量表达式 //被隐式的指定为内联函数 //允许函数返回值并非常量 ``` ### 函数匹配 ### 函数指针 ================================================ FILE: articals/c++/oop.md ================================================ # 面向对象程序设计(7.16) ### oop - 概述 - 动态绑定 ### 基类派生类 - 定义基类 ``` class A{}; ``` - 定义派生类 ``` class B : public A{}; ``` - 类型转换与继承 ### 虚函数 - 虚函数:实现多态,实现运行期绑定 ``` #include using namespace std; class A { public: virtual void foo() { cout<<"A::foo() is called"<foo(); // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的! a = new C(); a->foo(); return 0; } ``` - 纯虚函数:方便实现多态性,具有存虚函数不能生成对象,必须由不同的派生类来实现它 ``` virtual void foo() = 0; ``` ### 抽象基类 ### 继承与访问控制 - 三种权限:对于类中成员对外开放的属性 访问权限 | public | protect | private ---|---|---|--- 对本类 | 可见 | 可见 | 可见 对子类 | 可见 | 可见 | 不可见 外部调用 | 可见 | 不可见 | 不可见 - 继承方式:子类对父类的访问权限控制 - 1)公有继承:直接继承不改变父类中的权限 - 2)保护继承:把父类中公有成员变换成保护成员 - 3)私有继承:把父类的公有成员和保护成员变为私有成员 ``` #include using namespace std; class A{ private: void show(){ cout << "private:A" << endl; } protected: void show2(){ cout << "protected:A" << endl; } public: void show3(){ cout << "public:A" << endl; } }; class B : public A{ }; class C : protected A{ }; class D : private A{ }; int main(void){ A a; a.show(); //fail a.show2(); //fail a.show3(); //ok 只有公有成员外部才可以直接调用 // //公有继承:权限属性不变 B b; b.show(); //fail b.show2(); //fail b.show3(); //ok //保护继承:公有属性转保护属性 C c; c.show(); //fail c.show2(); //fail c.show3(); //fail 保护属性 //私有继承:公有属性,保护继承转私有继承 D d; d.show(); //fail d.show2(); //fail 私有属性 d.show3(); //fail 私有属性 return 0; } ``` ### 继承类作用域 ### 构造函数域拷贝控制 ### 容器域继承 ### 文本查询 ================================================ FILE: articals/c++/reload.md ================================================ # 重载运算符 ### 理论 - 来源:对于自定义的数据类型,需要和自带的运算符的相同功能的运算,实质是函数重载 - 语法:operator关键词 ``` Complex operator+(Complex c2){ Complex c; c.real = real + c2.real; c.imag = imag + c2.imag; return c; } ``` - 参数数量: - - 非成员函数:一元有一个运算符,二元有两个运算符,对于二元左侧传递给第一个参数,右侧传递给第二个参数 - - 成员函数:左侧运算对象绑定到this指针上,运算参数对象比运算符运算对象少一个 - 注意: ``` 1)只能重载已有的运算符,不能发明新的运算符 2)部分运算符既是一元又是二元,只能从参数上来判断到底重载的那个运算符 3)优先级和结合率与内置运算符保持一致 4)不能被重载的运算符:作用域运算符::,成员运算符., 点乘运算符.*,条件运算符 :? 5)不应被重载的运算符:逻辑与或运算符和逗号运算符 6)需要有与内置运算符一一样的含义有重载==就应当有!= 7)应当与内置运算符的放回类型兼容 ``` - 作为成员与非成员函数 ``` 准则: 1)赋值,下标,调用,成员访问运算符必须作为成员 2)复合赋值一般作为成员 3)改变对象状态的,或与类型密切相关的,递增,递减,解引用之类的一般作为成员 4)具有对称型的运算符可能转换任意一端的运算对象,算术,相等,关系和位运算等作为非成员 ``` ### 输入输出:必须是非成员函数 ``` ostream &operator<<(ostream &os, const Sale_data &item){ os << item.isbn() << " " << item.units_sold << endl; return os; } ``` ### 赋值 ### 下标 ### 递增递减 ### 成员访问 ### 函数调用 ================================================ FILE: articals/c++/str_map_arr.md ================================================ # 字符串、向量、数组 ### 名字空间 - 作用域操作符 ``` std:: cout << i; //左侧的作用域中找出右侧的名字,头文件不应包含 ``` - 使用using声明:最安全的方法 ``` using namespace::name; using std::cin; //使用cin时从std中获取 using namespace std; //对文件使用名字空间 ``` ### string库:可变长字符序列 - 头文件:#include - 定义初始化:直接初始化,拷贝初始化 ``` string s1; //默认初始化 string s1(s2); //直接初始化 string s1 = s2; //拷贝初始化 string s1(n, 'c'); // 初始化成连续字符串 ``` - 操作: 表示 | 作用 ---|--- << s | 输出 >> s | 输入 getline(is, s)| 读取一行给s s.empty() | 判空 s.size() | 返回字符个数 s[n] | 返回第n个字符的引用 s1+s2 | 返回连接的结果 s1 = s2 | 用s2的副本代替s1 s1 == s2 | 字符完全一样相等,大小写敏感 - 读取string ``` string s; cin >> s; //跳过空格,从第一个字符开始读取,读到下一个空格为止 cout << s << endl; string s1; while( cin >> s1 ){ cout << s1 << endl; //读到文件末尾 } string s2; while ( getline(cin, line) ){ cout << line << endl; // 读一整行 } ``` - empty和size ``` while( getline(cin , line) ){ if( !line.empty() ) if(line.size() > 80 ) cout << line << endl; } //跳过空行,输出字符超过80的行 ``` - 处理单个字符:使用继承c的库 ctpye.h ---> cctype ``` #incldue for (auto c : str) //使用基于范围的for语句 ``` ### vector库:对象的集合,所有对象都相同,类模板,每一个对象有一个与之对应的索引,被称为容器 > vector是模板.并非类型 - 头文件:#include ### 迭代器(7.19) ### 数组 # 表达式 ### 成员访问运算符 ### sizeof运算符 ### 类型转换 ### 优先级 # 语句 ### 语句作用域 ### 范围for语句:遍历容器和其他序列的所有元素 ``` vector v = {0,1,2,3,4,5,6,7,8,9}; //范围变量必须是引用型才能进行写操作 for (auto &r : v) r *= 2; //v中每个元素的值翻倍 //等价于 for(auto beg = v.begin(), end = v.end(); beg != end; ++ beg) auto &r = *beg; r *= 2; ``` ### 异常处理语句 - throw 表达式:主动抛出异常 ``` if(a != b) throw runtime_error("data ..."); ``` - try……catch表达式:捕获处理异常 ``` try { …… }catch (runtime_error err) { cout << err.what() << endl; } ``` - 标准异常 header 1 | header 2 ---|--- row 1 col 1 | row 1 col 2 row 2 col 1 | row 2 col 2 ================================================ FILE: articals/c++/var.md ================================================ # 变量和基本类型 ### 变量 ### 复合类型:基于其他类型定义的类型 - 引用:为对象起的别名,已经存在的对象的另一个名字 ``` int ival = 1024; int &refVal = ival; //引用定义时必须被初始化 //引用定义时必须和初始值绑定在一起,无法再绑定其他值 //引用并非对象无法定义引用的引用 //引用只能绑定在对象上,不能绑定常量 //绑定时类型必须严格的匹配 ``` - 指针:本身就是一个对象,允许赋值和拷贝 ``` int ival = 42; int *p = &ival; // 类型严格匹配 ``` - - 指针的值:4种情况 ``` //1)指向一个对象 //2)指向紧邻对象的下一个位置 //3)空指针,不指向任何对象 //4)无效指针其他值 ``` - - 指针访问对象:使用解引用符,间接访问符 ``` cout << *p << endl; //p为指向a的指针 ``` - - 空指针:不指向任何对象 ``` int *p = nullptr; //生成空指针 int *p = 0; int *p = NULL; //预处理变量 include cstdlib ``` - - void*:特殊的指针,存任意对象的地址 ``` double obj = 3.14, *pd = &obj; void *p = &obj; //不能直接操作对象 p = pd; //指向同一个对象 ``` - - 定义多个变量 ``` int* p, q; //一个指针一个变量 int *p, *q; //两个指针 ``` - - 指向指针的指针 ``` int ival = 1024; int *p = &ival; int **pi = &p; ``` ``` graph LR pi[p的地址]-->p[ival的地] p[ival的地址]-->ival[1024] ``` ### const:限定对象不被改变 - 初始化和const:const的对象一旦创建就不能被改变,所以必须初始化 ``` const int buff = 512; //编译时初始化 const int i = getSize(); //运行时初始化 //默认情况仅在文件内有效 //想要文件共享const,定义和声明都必须加extern //如果其中一个没加会报错undefined reference to `a' collect2.exe: error: ld returned 1 exit status ``` - const的引用:**对常量的引用,不能用作修改他所绑定的对象** ``` const int ci = 1024; //常量对象 const int &r1 = ci; //必须加const r1 = 42; //错误,不允许改变值 int i = 1024; //非常量对象 const int &r1 = i; //允许 const int &r2 = 42; //允许 const int &r3 = r1 * 42; //允许 ``` > 对常量的引用可能引用一个并非常量的对象,但不允许它修改对象的值 - const的指针:**常量指针必须初始化,不能修改指针的指向** ``` int a = 0; int * const p = &a; const b = 1024; const int * const q = &b; ``` ### 类型处理 ### 结构 - 内存字节对齐原则: - 1)第一个成员的地址为0,以后的每一个成员的地址,都要以该成员大小为整数倍地址来开始存储 - 2)结构体作为成员要从最大的元素地址的整数倍开始存储 - 3)结构体的总大小要是最大元素的整数倍,不然就要补齐 ``` typedef struct bb { int id; //[0]....[3] double weight; //[8].....[15]      原则1 float height; //[16]..[19],总长要为8的整数倍,补齐[20]...[23]     原则3 }BB; //24 typedef struct aa { char name[2]; //[0],[1] int id; //[4]...[7]          原则1 double score; //[8]....[15]     short grade; //[16],[17]         BB b; //[24]......[47]          原则2 }AA; //48 struct stu { union{ char bj[5]; int bh[2]; } Class; //[0]....[5] char xm[8]; //[8]....[16] float cj; //[16]...[19] }xc; //20 ``` ================================================ FILE: articals/h5/0001.md ================================================ # 前言 最近在写移动端 H5 应用,遇到一个值得记录下来的点。现在从它的由来到实现,我们来聊一下移动端 1px,说 1px 不够准确,应该说成 1 **物理像素**。 通过阅读下面文章,你将会理解以下问题: ## 问题 - **为什么有 1px 这个问题?** - **实现 1px 有哪些方法?这些方法分别有哪些优缺点?** - **开源项目中使用的哪些解决方案?** - **如何在项目中处理 1px 的相关问题?** # 由来 ## 基本概念 首先,我们要了解两个概念,一个是**像素(pixel)**可以简写为**px**,另外一个是**设备像素比(DPR)** 像素 :指在由一个数字序列表示的图像中的一个最小单元,单位是 px,不可再次分割了。 设备像素比(DPR): 设备像素比 = 设备像素 / 设备独立像素。 下面我来简单解释下几个概念 - CSS 像素 (虚拟像素):指的是 CSS 样式代码中使用的逻辑像素,在 CSS 规范中,长度单位可以分为两类,绝对单位以及相对单位。px 是一个相对单位,相对的是设备像素。 - 设备像素 (物理像素):指设备能控制显示的最小物理单位,意指显示器上一个个的点。从屏幕在工厂生产出的那天起,它上面设备像素点就固定不变了,和屏幕尺寸大小有关。 - 设备独立像素 (逻辑像素):可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如: CSS 像素),这个点是没有固定大小的,越小越清晰,然后由相关系统转换为物理像素。 **也就是说,当逻辑像素是 1pt 时,在 DPR 为 2 的 设备上显示为 2px 的物理像素** ## 参考数据 **各种类型的 iphone 手机屏幕设备的参数** ![](https://user-gold-cdn.xitu.io/2019/12/13/16efd4e7df7660ca?w=1632&h=740&f=jpeg&s=191564) 注:这里的缩放因子呢,就是 DRP 的值 **设计稿对比数据** ![](https://user-gold-cdn.xitu.io/2019/12/13/16efd4fa13455bf6?w=1434&h=1426&f=jpeg&s=226003) 会有人好奇,为什么设计稿上显示是 750x1334 呢,这是因为设计稿是显示的**物理像素** 而我们 css 中的像素是**逻辑像素**应该为 375x 667,在编写代码时要将自定义宽度设置成 375px ![](https://user-gold-cdn.xitu.io/2019/12/13/16efd4ff7d8fbcba?w=580&h=300&f=jpeg&s=30965) 那么此时设计稿上的 1px 宽度实际代表的 css 参数应该是 0.5px 对应物理像素 1px,那么怎么实现这个物理像素为 1px 呢 # 实践 **归根结底有两种方案,一种是利用 css 中的`transfrom:scaleY(0.5)`,另一种是设置 媒体查询根据不同 DPR 缩放** ## 解决方案一 ### 原理 **利用 css 的 伪元素`::after` + `transfrom` 进行缩放** **为什么用伪元素?** 因为伪元素`::after`或`::before`是独立于当前元素,可以单独对其缩放而不影响元素本身的缩放 > 伪元素大多数浏览器默认单引号也可以使用,和伪类一样形式,而且单引号兼容性(ie)更好些 ### 实现 ```html
cell
``` ## 解决方案二(升级方案一) ### 原理 使用 less 对公共代码(方案一)封装,同时增加媒体查询分别对不同 DPR 的设备,进行不同的缩放 ```less .border( @borderWidth: 1px; @borderStyle: solid; @borderColor: @lignt-gray-color; @borderRadius: 0) { position: relative; &:before { content: ''; position: absolute; width: 98%; height: 98%; top: 0; left: 0; transform-origin: left top; -webkit-transform-origin: left top; box-sizing: border-box; pointer-events: none; } @media (-webkit-min-device-pixel-ratio: 2) { &:before { width: 200%; height: 200%; -webkit-transform: scale(.5); } } @media (-webkit-min-device-pixel-ratio: 2.5) { &:before { width: 250%; height: 250%; -webkit-transform: scale(.4); } } @media (-webkit-min-device-pixel-ratio: 2.75) { &:before { width: 275%; height: 275%; -webkit-transform: scale(1 / 2.75); } } @media (-webkit-min-device-pixel-ratio: 3) { &:before { width: 300%; height: 300%; transform: scale(1 / 3); -webkit-transform: scale(1 / 3); } } .border-radius(@borderRadius); &:before { border-width: @borderWidth; border-style: @borderStyle; border-color: @borderColor; } } .border-all( @borderWidth: 1px; @borderStyle: solid; @borderColor: @lignt-gray-color; @borderRadius: 0) { .border(@borderWidth; @borderStyle; @borderColor; @borderRadius); } ``` ## 其他方案: - 使用图片:兼容性最好,灵活行最差,不能改变颜色、长度 - 使用 `viewport` 和 `rem`,`js` 动态改变 `viewport` 中 `scale` 缩放,缺点在于不适用于已有的项目,例如:使用 `vh` 和 `vw` 布局的 ```html ``` - 使用 css 渐变`linear-gradient`或者`box-shadow` **上述 3 种方案均有致命缺陷暂不推荐使用** ## 兼容性 最后看一下兼容性如何,主要是伪元素、`transform:scale` 和`min-device-pixel-ratio` 这几个关键词的兼容性 ![](https://user-gold-cdn.xitu.io/2019/12/13/16efde9534c2f737?w=2508&h=862&f=jpeg&s=281950) ![](https://user-gold-cdn.xitu.io/2019/12/13/16efde99b7cf56be?w=2510&h=696&f=jpeg&s=221428) ![](https://user-gold-cdn.xitu.io/2019/12/13/16efde9d3c0b1a36?w=2516&h=716&f=jpeg&s=250779) ## 开源库的解决方案 ### vant 组件库 [跳去 github 查看相关代码](https://github.com/youzan/vant/blob/dev/src/style/mixins/hairline.less) 使用`less`写的 ```less .hairline-common() { position: absolute; box-sizing: border-box; content: ' '; pointer-events: none; } .hairline(@color: @border-color) { .hairline-common(); top: -50%; right: -50%; bottom: -50%; left: -50%; border: 0 solid @color; transform: scale(0.5); } ``` 也是采用第一种解决方案 ### ant-design-mobile 组件库 [跳去 github 查看相关代码](https://github.com/ant-design/ant-design-mobile/blob/master/components/style/mixins/hairline.less) ```less .scale-hairline-common(@color, @top, @right, @bottom, @left) { content: ''; position: absolute; background-color: @color; display: block; z-index: 1; top: @top; right: @right; bottom: @bottom; left: @left; } .hairline(@direction, @color: @border-color-base) when (@direction = 'top') { border-top: 1PX solid @color; html:not([data-scale]) & { @media (min-resolution: 2dppx) { border-top: none; &::before { .scale-hairline-common(@color, 0, auto, auto, 0); width: 100%; height: 1PX; transform-origin: 50% 50%; transform: scaleY(0.5); @media (min-resolution: 3dppx) { transform: scaleY(0.33); } } } } } .hairline(@direction, @color: @border-color-base) when (@direction = 'right') { border-right: 1PX solid @color; html:not([data-scale]) & { @media (min-resolution: 2dppx) { border-right: none; &::after { .scale-hairline-common(@color, 0, 0, auto, auto); width: 1PX; height: 100%; background: @color; transform-origin: 100% 50%; transform: scaleX(0.5); @media (min-resolution: 3dppx) { transform: scaleX(0.33); } } } } } .hairline(@direction, @color: @border-color-base) when (@direction = 'bottom') { border-bottom: 1PX solid @color; html:not([data-scale]) & { @media (min-resolution: 2dppx) { border-bottom: none; &::after { .scale-hairline-common(@color, auto, auto, 0, 0); width: 100%; height: 1PX; transform-origin: 50% 100%; transform: scaleY(0.5); @media (min-resolution: 3dppx) { transform: scaleY(0.33); } } } } } .hairline(@direction, @color: @border-color-base) when (@direction = 'left') { border-left: 1PX solid @color; html:not([data-scale]) & { @media (min-resolution: 2dppx) { border-left: none; &::before { .scale-hairline-common(@color, 0, auto, auto, 0); width: 1PX; height: 100%; transform-origin: 100% 50%; transform: scaleX(0.5); @media (min-resolution: 3dppx) { transform: scaleX(0.33); } } } } } .hairline(@direction, @color: @border-color-base, @radius: 0) when (@direction = 'all') { border: 1PX solid @color; border-radius: @radius; html:not([data-scale]) & { @media (min-resolution: 2dppx) { position: relative; border: none; &::before { content: ''; position: absolute; left: 0; top: 0; width: 200%; height: 200%; border: 1PX solid @color; border-radius: @radius * 2; transform-origin: 0 0; transform: scale(0.5); box-sizing: border-box; pointer-events: none; // @media (min-resolution: 3dppx) { // width: 300%; // height: 300%; // border-radius: @radius * 3; // transform: scale(0.33); // } } } } } ``` 这个值得研究下,比 vant 和 第一种解决方案有点不同,主要在于处理了 DPR 为 2 和为 3 的两种情况,相比来说更加完善。 > 这里 PX 大写,为了防止插件将 px 转成 rem 等单位 # 总结 通过该文,你大概了解 1px 问题的来龙去脉了吧,也明白了如何解决相关问题,如果这票文章能解决你的疑问或者工作中问题,不妨点个赞收藏下。 由于技术水平有限,文章中如有错误地方,请在评论区指出,感谢! 接下我应该会关于**移动端 H5 布局问题和一些踩坑**进行一段学习工作总结,不妨点个关注。 [issue评论区](https://github.com/suoyuesmile/suo-blog/issues/40) ================================================ FILE: articals/h5/0002.md ================================================ # 前言 最近写第三个移动端 H5 的项目了,准备记录下自己在 H5 项目中的一些实践探索。移动端 H5 与 PC 端开发最大的区别之一,大概就是**响应式布局**问题。 那么下面我们来聊聊移动端响应式布局,了解他的来龙去脉,对现有的最佳解决方案探索。 ## 问题 全文将围绕下面几个问题进行论述和展开: - **写移动端 H5 相关页面,相比 PC 端有哪些值得注意的点?** - **关于H5 响应式布局有哪些解决方案?** - **什么是 rem?如何在项目中完美使用它?** - **vh/vw 是最佳解决方案吗?它有什么优势和缺陷** - **大型开源库里面常用解决方案是什么?** - **怎样快速搭建一套移动端布局解决方案?** # 由来 ## 概念 #### 什么是 H5 技术? H5 这个命名本身是一个很不讨巧的命名,咋一眼看上去认为 HTML5,或者第 5 级标题的标签,对一些造成一些不小的误解。 > 比如:我的一个某后端同事,谈论到 H5 很简单,HTML 之前我也学过一些,以后要是你请假,我来帮你写。 > 我是一脸蒙蔽,H5 === HTML? 再看看,搜索引擎中H5是什么?(引用来自谷歌词条第一页) ![](https://user-gold-cdn.xitu.io/2019/12/15/16f089d4360ca135?w=1248&h=938&f=jpeg&s=336754) 如此看来,将 H5 视作 HTML 的大有人在,而 H5 这个概念只在中国特有,所以对外国人来说他们也认为是 HTML, 所以,对于外国人和非这个领域的人来说,他们存在一样的误解。 目前的 H5 算是一个比较大的概念了,我认为的 H5 技术是**一系列移动端 web 前端技术的集合** 大致用一个韦恩图表示如下 ![](https://user-gold-cdn.xitu.io/2019/12/15/16f0770741bdb529?w=1042&h=524&f=jpeg&s=45958) 我们这里只谈 web 前端中 H5 技术,H5 技术本身是用于**移动端的 web 网页**。由于App本身有个 “ webview ” 的容器,在容器里可以运行 web 前端相关代码,由此 H5 和原生 App 结合又衍生出来了 **Hybrid App 技术**。 #### Hybrid App 技术大致原理 ![](https://user-gold-cdn.xitu.io/2019/12/15/16f09268f45d559d?w=1066&h=1452&f=jpeg&s=89857) 这是我给公司同事普及 H5 知识绘制的图像。 # 实践 ## 解决方案一:rem + pxToRem ### 概念 css 中用于计量的单位有两种,一种是**绝对单位**,另一种是**相对单位** #### 绝对单位 ![](https://user-gold-cdn.xitu.io/2019/12/15/16f08ae5c7ad5186?w=1992&h=614&f=jpeg&s=128652) 对于绝对单位,一般来说常用的也就 `px`, 其他的可能打印需要用到 #### 相对单位 ![](https://user-gold-cdn.xitu.io/2019/12/15/16f08af89b956dcb?w=2006&h=780&f=jpeg&s=176592) 对于相对单位来说,`em` 和 `rem` 属于一对,`vw` 和 `vh` 属于一对。 前一对相对于**字体大小**,区别在于 `rem` 相对于**根字体**,对于我们控制整体的大小相对容易些,所以我们可以使用它来控制整个页面的缩放。 后一对,相对于视窗的大小,这个将在下一个节中发挥主要作用。 ### 原理 1. 监听屏幕视窗的宽度,通过一定比例换算赋值给`html`的`font-size`。此时,根字体大小就会随屏幕宽度而变化。 2. 将 `px` 转换成 `rem`, 常规方案有两种,一种是利用`sass`/`less`中的自定义函数 `pxToRem`,写`px`时,利用`pxToRem`函数转换成 `rem`。另外一种是直接写`px`,编译过程利用插件全部转成`rem`。这样 dom 中元素的大小,就会随屏幕宽度变化而变化了。 ### 实现 1. 动态更新根字体大小 ```js const MAX_FONT_SIZE = 420 // 定义最大的屏幕宽度 document.addEventListener('DOMContentLoaded', () => { const html = document.querySelector('html') let fontSize = window.innerWidth / 10 fontSize = fontSize > MAX_FONT_SIZE ? MAX_FONT_SIZE : fontSize html.style.fontSize = fontSize + 'px' }) ``` 2. `px` 转 `rem` #### `pxToRem` 方案一 ```scss $rootFontSize: 375 / 10; // 定义 px 转化为 rem 的函数 @function px2rem ($px) { @return $px / $rootFontSize + rem; } .demo { width: px2rem(100); height: px2rem(100); } ``` #### `pxToRem`方案二 `vue-cli3` 中配置 装 `postcss-pxtorem` 插件就可以了,其他平台大致差不多 ```js const autoprefixer = require('autoprefixer') const pxtorem = require('postcss-pxtorem') module.exports = { // ... css: { sourceMap: true, loaderOptions: { postcss: { plugins: [ autoprefixer(), pxtorem({ rootValue: 37.5, propList: ['*'] }) ] } } } } ``` [点击快速配置 H5 项目工程](https://github.com/suoyuesmile/vue-h5-awsome) 继续探索[postcss-pxtorem](https://github.com/cuth/postcss-pxtorem/blob/master/index.js)插件源码,查看它实现的原理 ```js function createPxReplace (rootValue, unitPrecision, minPixelValue) { return function (m, $1) { if (!$1) return m; var pixels = parseFloat($1); if (pixels < minPixelValue) return m; var fixedVal = toFixed((pixels / rootValue), unitPrecision); return (fixedVal === 0) ? '0' : fixedVal + 'rem'; }; } ``` `px`变换成 `rem` 主要是这个函数,当然里面有很多可配置的参数, 核心原理和我们方案一差不多,方便在于,不需要每次写`px`都要加上一个函数,代码也清晰很多 > 是不是所有元素 `px` 都要转换成 `rem`呢?,那可不一定哦,border 中的 `px` 不应该转 rem,涉及到另外一个 1px 的问题,上一篇文章详细论述过,避免 px 转 rem,将 border 中的 px 大写成 PX/Px/pX 1px 适配问题请移至 [吃透移动端 1px](https://juejin.im/post/5df3053ce51d45583d425ada) ## 解决方案二:vh + vw ### 原理 **`vw` 相对于视窗宽度的单位,随宽度变化而变化。由此看来,方案一其实是方案二的一种 Hack, 通过使用监听实现了方案二的效果** ### 实现 与 rem 类似做法,直接使用 [postcss-px-to-viewport](https://github.com/evrone/postcss-px-to-viewport/blob/master/index.js) 插件进行配置, 配置方式也是和 [postcss-pxtorem](https://github.com/cuth/postcss-pxtorem/blob/master/index.js) 大同小异 我们看看插件的原理是不是也是一样的 ```js function createPxReplace(opts, viewportUnit, viewportSize) { return function (m, $1) { if (!$1) return m; var pixels = parseFloat($1); if (pixels <= opts.minPixelValue) return m; var parsedVal = toFixed((pixels / viewportSize * 100), opts.unitPrecision); return parsedVal === 0 ? '0' : parsedVal + viewportUnit; }; } ``` **果然呢,连方法名、变量名、代码逻辑,都一摸一样哈哈哈,谁抄谁,我就不指出来啦 - -** ## 其他解决方案 | | 方案 | 缺陷 | ---------- | ------------ | ------------| |1|百分比|高度无法百分比| |2|媒体查询 + meta 中 viewport |不同设备宽度不同,缩放比无法完全确定| |3|flex |还是无法解决宽度超出问题| 上面方案均存在致命缺陷,不推荐使用它完成移动端布局计算。 > flex 与 rem 结合使用更佳 ## 兼容性 上述两种方案,**兼容性主要在于 rem,vh,vw 关键词上** ![](https://user-gold-cdn.xitu.io/2019/12/15/16f09065583eefd8?w=2532&h=896&f=jpeg&s=291766) `rem`在移动端表现高达 100%,令人惊叹! ![](https://user-gold-cdn.xitu.io/2019/12/15/16f090720034ca25?w=2518&h=718&f=jpeg&s=195287) ![](https://user-gold-cdn.xitu.io/2019/12/15/16f0908b94190dfb?w=2520&h=712&f=jpeg&s=184002) `vh vw` 表现惨不忍睹 **不得不说 `rem` 仍然是移动端 h5 布局的最佳方案** ## 开源库解决方案 ### vant 组件库 ![](https://user-gold-cdn.xitu.io/2019/12/15/16f090ee96c9b299?w=1540&h=984&f=jpeg&s=153330) vant 组件库中,默认采用 px 做计量单位,如果需要使用 rem,直接使用插件完美适配。 对于 vw 方案,vant 也是可以通过插件将 px 转成 vw,对于 vw 可能会存在一些坑点。 ### ant-design-mobile 组件库 ant-design-mobile 组件库仍然使用 `px` 单位 ```less @hd: 1px; // 基本单位 // 字体尺寸 // --- @font-size-icontext: 10 * @hd; @font-size-caption-sm: 12 * @hd; @font-size-base: 14 * @hd; @font-size-subhead: 15 * @hd; @font-size-caption: 16 * @hd; @font-size-heading: 17 * @hd; // 圆角 // --- @radius-xs: 2 * @hd; @radius-sm: 3 * @hd; @radius-md: 5 * @hd; @radius-lg: 7 * @hd; @radius-circle: 50%; // 边框尺寸 // --- @border-width-sm: 1PX; @border-width-md: 1PX; @border-width-lg: 2 * @hd; ``` 与 `vant` 组件一样,还是由开发者来决定到底用哪一种方案 这种把选择权交给开发者,算是一种开源库的最灵活的做法了。 # 总结 通过该文,你大概了解 H5 问题的来龙去脉了吧,也明白了如何解决移动端响应式布局问题,如果这票文章能解决你的疑问或者工作中问题,不妨点个赞收藏下。 由于技术水平有限,文章中如有错误地方,请在评论区指出,感谢! 上一篇文章 解决了 1px 问题,这篇文章解决了响应式布局问题, 接下我应该会继续研究下关于 H5 一些踩坑总结,之后应该回去研究下 vue 最新的源码再进行分享,想持续了解更多,不妨点个关注。 ================================================ FILE: articals/h5/0003.md ================================================ # 前言 作为一个开发了多个 H5 项目的前端工程师,在开发过程中难免会遇到一些兼容性等**爬过坑**的问题。现在我将这些问题一一汇总一下,并在后面给出**坑产生的原理**,和**现阶段常规的填坑方案**。由此来做一个阶段性的总结。 > 常规操作哈,**点赞**后再观看呗!你的**点赞**就是我创作的动力之一! # 问题 下面列举了我遇到的一些常规问题,如有遇到其他问题请在评论区补充,之后我也会实践后加以补充,感谢!(经常更新该文) ## 移动端 H5 相关问题汇总: - **1px 问题** - **响应式布局** - **iOS 滑动不流畅** - **iOS 上拉边界下拉出现白色空白** - **页面件放大或缩小不确定性行为** - **click 点击穿透与延迟** - **软键盘弹出将页面顶起来、收起未回落问题** - **iPhone X 底部栏适配问题** - **保存页面为图片和二维码问题和解决方案** - **微信公众号 H5 分享问题** - **H5 调用 SDK 相关问题及解决方案** - **H5 调试相关方案与策略** ## 移动端 H5 相关基础技术概览 ![](https://user-gold-cdn.xitu.io/2019/12/24/16f368720d3eb421?w=2206&h=1140&f=jpeg&s=247732) # 原理与实践 之前两篇文章已经详细的论述了**1px** 问题与 **响应式布局**问题,并给出了原理和解决方案。 > 防止丢失,**点赞收藏**后跳转至快捷通道:[**1px**](https://juejin.im/entry/5df32ffd6fb9a016194afb5e)通道与[响应式布局](https://juejin.im/entry/5df613c3f265da33ca400e72)通道 接下来呢,我们看看其他问题的原理和解决方案吧。 > 以下解决方案,均经过我测试成功,健康安全,请放下食用。由于篇幅原因,某些非核心解决方案的实现细节暂未谈论,需要自行研究。 ## iOS 滑动不流畅 ### 表现 上下滑动页面会产生卡顿,手指离开页面,页面立即停止运动。整体表现就是滑动不流畅,没有滑动惯性。 ### 产生原因 **为什么 iOS 的 webview 中 滑动不流畅,它是如何定义的?** 最终我在 `safari` 文档里面寻找到了答案(文档链接在参考资料项)。 ![](https://user-gold-cdn.xitu.io/2019/12/19/16f1daab7c41e044?w=1420&h=1104&f=jpeg&s=165493) 原来在 iOS 5.0 以及之后的版本,滑动有定义有两个值 `auto` 和 `touch`,默认值为 `auto`。 ```css -webkit-overflow-scrolling: touch; /* 当手指从触摸屏上移开,会保持一段时间的滚动 */ -webkit-overflow-scrolling: auto; /* 当手指从触摸屏上移开,滚动会立即停止 */ ``` ### 解决方案 #### 1.在滚动容器上增加滚动 touch 方法 将`-webkit-overflow-scrolling` 值设置为 `touch` ```css .wrapper { -webkit-overflow-scrolling: touch; } ``` > 设置滚动条隐藏: `.container ::-webkit-scrollbar {display: none;}` 可能会导致使用`position:fixed;` 固定定位的元素,随着页面一起滚动 #### 2.设置 overflow 设置外部 `overflow` 为 `hidden`,设置内容元素 `overflow` 为 `auto`。内部元素超出 body 即产生滚动,超出的部分 body 隐藏。 ```css body { overflow-y: hidden; } .wrapper { overflow-y: auto; } ``` > 两者结合使用更佳! ## iOS 上拉边界下拉出现白色空白 ### 表现 手指按住屏幕下拉,屏幕顶部会多出一块白色区域。手指按住屏幕上拉,底部多出一块白色区域。 ### 产生原因 在 iOS 中,手指按住屏幕上下拖动,会触发 `touchmove` 事件。这个事件触发的对象是整个 `webview` 容器,容器自然会被拖动,剩下的部分会成空白。 ### 解决方案 #### 1. 监听事件禁止滑动 移动端触摸事件有三个,分别定义为 ``` 1. touchstart :手指放在一个DOM元素上。 2. touchmove :手指拖曳一个DOM元素。 3. touchend :手指从一个DOM元素上移开。 ``` 显然我们需要控制的是 `touchmove` 事件,由此我在 W3C 文档中找到了这样一段话 > Note that the rate at which the user agent sends touchmove events is implementation-defined, and may depend on hardware capabilities and other implementation details. > If the preventDefault method is called on the first touchmove event of an active touch point, it should prevent any default action caused by any touchmove event associated with the same active touch point, such as scrolling. **`touchmove` 事件的速度是可以实现定义的,取决于硬件性能和其他实现细节** **`preventDefault` 方法,阻止同一触点上所有默认行为,比如滚动。** 由此我们找到解决方案,通过监听 `touchmove`,让需要滑动的地方滑动,不需要滑动的地方禁止滑动。 > 值得注意的是我们要过滤掉具有滚动容器的元素。 实现如下: ```js document.body.addEventListener('touchmove', function(e) { if(e._isScroller) return; // 阻止默认事件 e.preventDefault(); }, { passive: false }); ``` #### 2. 滚动妥协填充空白,装饰成其他功能 在很多时候,我们可以不去解决这个问题,换一直思路。根据场景,**我们可以将下拉作为一个功能性的操作**。 **比如: 下拉后刷新页面** ![](https://user-gold-cdn.xitu.io/2019/12/20/16f219d17a6fd448?w=754&h=1326&f=jpeg&s=183570) ## 页面放大或缩小不确定性行为 ### 表现 双击或者双指张开手指页面元素,页面会放大或缩小。 ### 产生原因 HTML 本身会产生放大或缩小的行为,比如在 PC 浏览器上,可以自由控制页面的放大缩小。但是在移动端,我们是不需要这个行为的。所以,我们需要禁止该不确定性行为,来提升用户体验。 ### 原理与解决方案 HTML `meta` 元标签标准中有个 中 `viewport` 属性,用来控制页面的缩放,一般用于移动端。如下图 MDN 中介绍 ![](https://user-gold-cdn.xitu.io/2019/12/19/16f1cf528e787498?w=1294&h=1202&f=jpeg&s=325010) 移动端常规写法 ```html ``` 因此我们可以设置 `maximum-scale`、`minimum-scale` 与 `user-scalable=no` 用来避免这个问题 ```html ``` ## click 点击事件延时与穿透 ### 表现 监听元素 `click` 事件,点击元素触发时间延迟约 `300ms`。 点击蒙层,蒙层消失后,下层元素点击触发。 ### 产生原因 #### 为什么会产生 click 延时? iOS 中的 safari,为了实现双击缩放操作,在单击 300ms 之后,如果未进行第二次点击,则执行 `click` 单击操作。也就是说来判断用户行为是否为双击产生的。但是,在 App 中,无论是否需要双击缩放这种行为,`click` 单击都会产生 300ms 延迟。 > #### 为什么会产生 click 点击穿透? 双层元素叠加时,在上层元素上绑定 `touch` 事件,下层元素绑定 `click` 事件。由于 `click` 发生在 `touch` 之后,点击上层元素,元素消失,下层元素会触发 `click` 事件,由此产生了点击穿透的效果。 ### 原理与解决方案 #### 解决方案一:使用 touchstart 替换 click 前面已经介绍了,移动设备不仅支持点击,还支持几个触摸事件。 那么我们现在基本思路就是用 `touch` 事件代替`click` 事件。 将 `click` 替换成 `touchstart` 不仅解决了 `click` 事件都延时问题,还解决了穿透问题。因为穿透问题是在 `touch` 和 `click` 混用时产生。 在原生中使用 ```js el.addEventListener("touchstart", () => { console.log("ok"); }, false); ``` 在 vue 中使用 ```html ``` 开源解决方案中,也是既提供了 `click` 事件,又提供了`touchstart` 事件。如 vant 中的 `button` 组件 ![](https://user-gold-cdn.xitu.io/2019/12/19/16f1d13300321655?w=1512&h=368&f=jpeg&s=59760) **那么,是否可以将 `click` 事件全部替换成 `touchstart` 呢?为什么开源框架还会给出 `click` 事件呢?** 我们想象一种情景,同时需要点击和滑动的场景下。如果将 `click` 替换成 `touchstart` 会怎样? > 事件触发顺序: `touchstart`, `touchmove`, `touchend`, `click`。 很容易想象,在我需要`touchmove`滑动时候,优先触发了`touchstart`的点击事件,是不是已经产生了冲突呢? 所以呢,在具有滚动的情况下,还是建议使用 `click` 处理。 在接下来的`fastclick`开源库中也做了如下处理。 针对 `touchstart` 和 `touchend`,截取了部分源码。 ```js // If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and: // 1) the user does a fling scroll on the scrollable layer // 2) the user stops the fling scroll with another tap // then the event.target of the last 'touchend' event will be the element that was under the user's finger // when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check // is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42). this.updateScrollParent(targetElement); ``` ```js // Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled // and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42). scrollParent = targetElement.fastClickScrollParent; if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) { return true; } ``` 主要目的就是,在使用 `touchstart` 合成 `click` 事件时,保证其不在滚动的父元素之下。 #### 解决方案二: 使用 fastclick 库 使用 `npm/yarn` 安装后使用 ```js import FastClick from 'fastclick'; FastClick.attach(document.body, options); ``` 同样,使用`fastclick`库后,`click` 延时和穿透问题都没了 按照我的惯例,只要涉及开源库,那么我们一定要去了解它实现的原理。主要是将现有的原生事件集合封装合成一个兼容性较强的事件集合。 [fastclick源码](https://github.com/ftlabs/fastclick/blob/master/lib/fastclick.js) 核心代码不长, 1000 行不到。有兴趣可以了解一下! ## 软键盘将页面顶起来、收起未回落问题 ### 表现 Android 手机中,点击 `input` 框时,键盘弹出,将页面顶起来,导致页面样式错乱。 移开焦点时,键盘收起,键盘区域空白,未回落。 ### 产生原因 我们在app 布局中会有个固定的底部。安卓一些版本中,输入弹窗出来,会将解压 `absolute` 和 `fixed` 定位的元素。导致可视区域变小,布局错乱。 ### 原理与解决方案 软键盘将页面顶起来的解决方案,主要是通过监听页面高度变化,强制恢复成弹出前的高度。 ```js // 记录原有的视口高度 const originalHeight = document.body.clientHeight || document.documentElement.clientHeight; window.onresize = function(){ var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight; if(resizeHeight < originalHeight ){ // 恢复内容区域高度 // const container = document.getElementById("container") // 例如 container.style.height = originalHeight; } } ``` 键盘不能回落问题出现在 iOS 12+ 和 wechat 6.7.4+ 中,而在微信 H5 开发中是比较常见的 Bug。 兼容原理,1.判断版本类型 2.更改滚动的可视区域 ```js const isWechat = window.navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i); if (!isWechat) return; const wechatVersion = wechatInfo[1]; const version = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/); // 如果设备类型为iOS 12+ 和wechat 6.7.4+,恢复成原来的视口 if (+wechatVersion.replace(/\./g, '') >= 674 && +version[1] >= 12) { window.scrollTo(0, Math.max(document.body.clientHeight, document.documentElement.clientHeight)); } ``` > `window.scrollTo(x-coord, y-coord)`,其中`window.scrollTo(0, clientHeight)`恢复成原来的视口 ## iPhone X系列安全区域适配问题 ### 表现 头部刘海两侧区域或者底部区域,出现刘海遮挡文字,或者呈现黑底或白底空白区域。 ### 产生原因 iPhone X 以及它以上的系列,都采用**刘海屏设计**和**全面屏手势**。头部、底部、侧边都需要做特殊处理。才能适配 iPhone X 的特殊情况。 ### 解决方案 **设置安全区域,填充危险区域,危险区域不做操作和内容展示。** > 危险区域指头部不规则区域,底部横条区域,左右触发区域。 ![](https://user-gold-cdn.xitu.io/2019/12/19/16f1d31150e79cb9?w=1118&h=594&f=jpeg&s=49124) 具体操作为:`viewport-fit` `meta` 标签设置为 `cover`,获取所有区域填充。 判断设备是否属于 iPhone X,给头部底部增加**适配层** > `viewport-fit` 有 3 个值分别为: > - `auto`:此值不影响初始布局视图端口,并且整个web页面都是可查看的。 > - `contain`: 视图端口按比例缩放,以适合显示内嵌的最大矩形。 > - `cover`:视图端口被缩放以填充设备显示。强烈建议使用 `safe area inset` 变量,以确保重要内容不会出现在显示之外。 #### 设置 viewport-fit 为 `cover` ```html ``` #### 增加适配层 使用 `safe area inset` 变量 ```css /* 适配 iPhone X 顶部填充*/ @supports (top: env(safe-area-inset-top)){ body, .header{ padding-top: constant(safe-area-inset-top, 40px); padding-top: env(safe-area-inset-top, 40px); padding-top: var(safe-area-inset-top, 40px); } } /* 判断iPhoneX 将 footer 的 padding-bottom 填充到最底部 */ @supports (bottom: env(safe-area-inset-bottom)){ body, .footer{ padding-bottom: constant(safe-area-inset-bottom, 20px); padding-bottom: env(safe-area-inset-bottom, 20px); padding-top: var(safe-area-inset-bottom, 20px); } } ``` > `safe-area-inset-top`, `safe-area-inset-right`, `safe-area-inset-bottom`, `safe-area-inset-left` `safe-area-inset-*`由四个定义了视口边缘内矩形的 `top`, `right`, `bottom` 和 `left` 的环境变量组成,这样可以安全地放入内容,而不会有被非矩形的显示切断的风险。对于矩形视口,例如普通的笔记本电脑显示器,其值等于零。 对于非矩形显示器(如圆形表盘,`iPhoneX` 屏幕),在用户代理设置的四个值形成的矩形内,所有内容均可见。 其中 `env()` 用法为 `env( , ? )`,第一个参数为自定义的区域,第二个为备用值。 其中 `var()` 用法为 `var( , ? )`,作用是在 `env()` 不生效的情况下,给出一个备用值。 `constant()` 被 `css` 2017-2018 年为草稿阶段,是否已被标准化未知。而其他iOS 浏览器版本中是否有此函数未知,作为兼容处理而添加进去。 详情请查看文章末尾的参考资料。 #### 兼容性 ![](https://user-gold-cdn.xitu.io/2019/12/20/16f212ff998e1ec1?w=2024&h=568&f=jpeg&s=142698) ## 页面生成为图片和二维码问题 ### 表现 在工作中有需要将页面生成图片或者二维码的需求。可能我们第一想到的,交给后端来生成更简单。但是这样我们需要把页面代码全部传给后端,网络性能消耗太大。 ### 解决方案 #### 生成二维码 使用 QRCode 生成二维码 ```js import QRCode from 'qrcode'; // 使用 async 生成图片 const options = {}; const url = window.location.href; async url => { try { console.log(await QRCode.toDataURL(url, options)) } catch (err) { console.error(err); } } ``` 将 `await QRCode.toDataURL(url, options)` 赋值给 图片 `url` 即可 #### 生成图片 主要是使用 `htmlToCanvas` 生成 `canvas` 画布 ```js import html2canvas from 'html2canvas'; html2canvas(document.body).then(function(canvas) { document.body.appendChild(canvas); }); ``` 但是不单单在此处就完了,由于是 `canvas` 的原因。移动端生成出来的图片比较模糊。 我们使用一个新的 `canvas` 方法多倍生成,放入一倍容器里面,达到更加清晰的效果,通过超链接下载图片 **下载文件简单实现,更完整的实现方式之后更新** ```js const scaleSize = 2; const newCanvas = document.createElement("canvas"); const target = document.querySelector('div'); const width = parseInt(window.getComputedStyle(target).width); const height = parseInt(window.getComputedStyle(target).height); newCanvas.width = width * scaleSize; newCanvas.height = widthh * scaleSize; newCanvas.style.width = width + "px"; newCanvas.style.height =width + "px"; const context = newCanvas.getContext("2d"); context.scale(scaleSize, scaleSize); html2canvas(document.querySelector('.demo'), { canvas: newCanvas }).then(function(canvas) { // 简单的通过超链接设置下载功能 document.querySelector(".btn").setAttribute('href', canvas.toDataURL()); } ``` > 根据需要设置 `scaleSize` 大小 ## 微信公众号分享问题 ### 表现 在微信公众号 H5 开发中,页面内部点击分享按钮调用 SDK,方法不生效。 ### 解决方案 #### 解决方法:添加一层蒙层,做分享引导。 因为页面内部点击分享按钮无法直接调用,而分享功能需要点击右上角更多来操作。 然后用户可能不知道通过右上角小标里面的功能分享。又想引导用户分享,这时应该怎么做呢? 技术无法实现的,从产品出发。 ![](https://user-gold-cdn.xitu.io/2019/12/20/16f1efa63207199b?w=328&h=574&f=jpeg&s=55215) **如果技术上实现复杂,或者直接不能实现。不要强行钻牛角尖哦,学会怼产品,也是程序员必备的能力之一。** ## H5 调用 SDK 相关解决方案 ### 产生原因 在 Hybrid App 中使用 H5 是最常见的不过了,刚接触的,肯定会很生疏模糊。不知道 H5 和 Hybrid 是怎么交互的。怎样同时支持 iOS 和 Android 呢?现在来谈谈 Hybrid 技术要点,**原生与 H5 的通信**。 ### 解决方案 ![](https://user-gold-cdn.xitu.io/2019/12/20/16f21bc7e4d19065?w=1740&h=448&f=jpeg&s=62616) 使用 `DSBridge` 同时支持 iOS 与 Android > 文档见参考资料 #### SDK小组 提供方法 1. 注册方法 `bridge.register` ```js bridge.register('enterApp', function() { broadcast.emit('ENTER_APP') }) ``` 2. 回调方法 `bridge.call` ```js export const getSDKVersion = () => bridge.call('BLT.getSDKVersion') ``` #### 事件监听与触发法 ```js const broadcast = { on: function(name, fn, pluralable) { this._on(name, fn, pluralable, false) }, once: function(name, fn, pluralable) { this._on(name, fn, pluralable, true) }, _on: function(name, fn, pluralable, once) { let eventData = broadcast.data let fnObj = { fn: fn, once: once } if (pluralable && Object.prototype.hasOwnProperty.call(eventData, 'name')) { eventData[name].push(fnObj) } else { eventData[name] = [fnObj] } return this }, emit: function(name, data, thisArg) { let fn, fnList, i, len thisArg = thisArg || null fnList = broadcast.data[name] || [] for (i = 0, len = fnList.length; i < len; i++) { fn = fnList[i].fn fn.apply(thisArg, [data, name]) if (fnList[i].once) { fnList.splice(i, 1) i-- len-- } } return this }, data: {} } export default broadcast ``` #### 踩坑注意 方法调用前,一定要判断 SDK 是否提供该方法 如果 Android 提供该方法,iOS 上调用就会出现一个方法**调用失败等弹窗**。 怎么解决呢? 提供一个判断是否 Android、iOS。根据设备进行判断 ``` export const hasNativeMethod = (name) => return bridge.hasNativeMethod('BYJ.' + name) } export const getSDKVersion = function() { if (hasNativeMethod('getSDKVersion')) { bridge.call('BYJ.getSDKVersion') } } ``` > 同一功能需要iOS,Android方法名相同,这样更好处理哦 ## H5 调试相关方案策略 ### 表现 调试代码一般就是为了**查看数据**和**定位 bug**。分为两种场景,一种是开发和测试时调试,一种是生产环境上调试。 > 为什么有生产环境上调试呢?有些时候测试环境上没法复现这个 bug,测试环境和生产环境不一致,此时就需要紧急生产调试。 在 PC 端开发时,我们可以直接掉出控制台,使用浏览器提供的工具操作devtools或者查看日志。但是在 App 内部我们怎么做呢? ### 原理与解决方案 #### 1. `vconsole` 控制台插件 使用方法也很简单 ```js import Vconsole from 'vconsole' new Vconsole() ``` ![](https://user-gold-cdn.xitu.io/2019/12/19/16f1d57bc648e216?w=1208&h=906&f=jpeg&s=56866) 有兴趣看看它实现的基本原理,我们关注的点应该在 **vsconsole 如何打印出我们所有 log 的** [腾讯开源vconsole](https://github.com/Tencent/vConsole/blob/dev/src/core/core.js) 上述方法仅用于开发和测试。**生产环境中不允许出现,所以,使用时需要对环境进行判断。** ```js import Vconsole from 'vconsole' if (process.env.NODE_ENV !== 'production') { new Vconsole() } ``` #### 2. 代理 + spy-debugger 操作稍微有点麻烦,不过我会详细写出,大致分为 4 个步骤 1. 安装插件(全局安装) ```sh sudo npm install spy-debugger -g ``` 2. 手机与电脑置于同一 wifi 下,手机设置代理 设置手机的 HTTP 代理,代理 IP 地址设置为 PC 的 IP 地址,端口为`spy-debugger`的启动端口 > spy-debugger 默认端口:9888 > Android :设置 - WLAN - 长按选中网络 - 修改网络 - 高级 - 代理设置 - 手动 > IOS :设置 - Wi-Fi - 选中网络, 点击感叹号, HTTP 代理手动 3. 手机打开浏览器或者 app 中 H5 页面 4. 打开桌面日志网站进行调试,点击 npm 控制台监听地址。查看抓包和 H5 页面结构 **这种方式可以调试生成环境的页面,不需要修改代码,可以应付大多数调试需求** # 总结 本篇文章耗费作者一个多星期的业余时间,存手工敲打 4500 +字,同时收集,整理之前很多坑点和边写作边**思考**和**总结**。如果能对你有帮助,便是它最大的价值。都看到这里还不**点赞**,太过不去啦!😄 由于技术水平有限,文章中如有错误地方,请在评论区指出,感谢! 关于移动端 H5 的文章告一段落了,之后实践中遇到的问题都将在此文中更新。另外准备做一个移动端 H5 开源项目。多关注下 [我的github](https://github.com/suoyuesmile/suo-blog)动态哦! 之后,应该回去研究下**开源和面试题相关内容**分享,想持续了解更多,不妨**点赞**和**关注**呗。 # 参考资料 - [Safari CSS Reference](https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariCSSRef/Articles/StandardCSSProperties.html#//apple_ref/css/property/-webkit-overflow-scrolling) - [MDN touch 事件]() - [MDN css var()](https://developer.mozilla.org/zh-CN/docs/Web/CSS/var) - [MDN css env()](https://developer.mozilla.org/zh-CN/docs/Web/CSS/env) - [csswg env() drafts](https://drafts.csswg.org/css-env-1/) - [fastclick 源码](https://github.com/ftlabs/fastclick/blob/master/lib/fastclick.js) - [DSBridge-Android](https://github.com/wendux/DSBridge-Android) & [DSBridge-iOS](https://github.com/wendux/DSBridge-IOS) - [qrcodejs 源码](https://github.com/davidshimjs/qrcodejs) - [html2canvas 源码](https://github.com/niklasvh/html2canvas) - [关于H5页面在iPhoneX适配](https://www.cnblogs.com/lolDragon/p/7795174.html) - [vant 相关文档](https://youzan.github.io/vant/#/zh-CN/button) ================================================ FILE: articals/interview/0001.md ================================================ 首先呢,统计一下情况: 本人校招进入新三板上市企业工作一年,并有半年多一线互联网实习经验 来到杭州投出简历 24 封,收到面试邀约 10 次 `result = 正式offer * 2 + 口头offer * 1` 令人头疼的是并没拿到自己想要的 offer,理想的公司大多连面试机会都不给... 伤脑筋...明天还有两家电话面试,过了大半个月,还是打算继续面下去... ### 理想公司: - ***服:简历都没过(惨)还被一个蚂***外包招聘diss我这样的一年工作经验都外包都够呛(晕) - *赞:投了很多遍,简历全部卡在`HR`上了(惨) - *猫:没敢投(吓) - **车:一下午全部面完,环境一般,每轮面试都等了很长时间,两轮技术面后又和HR聊了一个多小时技术问题,表示很无奈,从此对大搜车印象大大折扣。回去等通知,一周之后说经验不符。敢情经验不符,你让我去面试个球(气) - *吧:HR主动找,问 ```js 你会 React ?我答会 你会移动端吗?我答会 你有过 H5 经验吗?我答有 对不起,面试官说经验不符 ???(懵) ``` - **顺:只招应届生了 ### 考题汇总: - `this` 指向 * 10 (必考有没有,这都不知道还学啥JavaScript--笑) - 同步异步或者事件机制 * 8 - `Vue` 双向绑定实现原理 * 8 - 箭头函数 * 6(考察 ES6 使用情况) - `call` `apply` `bind` 的使用和区别 * 6 (问到`this`很可能问到这些) - 常用 `Array` 函数 * 6 - `Vuex` 应用及其原理 * 6 - `Vue` 父子兄弟通信 * 5 - `Redux` 原理 * 5 - `dom` 事件 * 5 - `Vdom` 原理及`diff`算法 * 5 - `Promise`机制 * 5 - 原型链及面向对象相关知识 * 4 - `HTTPS` 安全性 * 3 - 闭包 * 3 - 变量提升 * 3 - `HTTP` 状态码 * 2 - `Proxy` 和 其他一些 `ES6` 新特性 - 防抖与节流 * 1 - 深浅拷贝原理和实现 * 1 - `getComputedStyle` * 1 - `rem` * 1 (考察关于移动端布局到问题) - 其他忘记了... ### 聊聊面试题 #### `this` 指向什么? 一起源于 `this` 《You dou't kown JavaScript》 这本书讲等最清楚了 首先是两个误解: 1. `this` 指向自身,根据英语翻译来说,这是一种自然的想法,其实不然,这是一个误解。 2. `this` 指向函数作用域,这个在某种情况下是正确的 其次是四种情况 1. 默认绑定 ```js var name = 'lufei' function show() { var name = 'namei' console.log(this.name) } show() // lufei ``` 可以看出最后 `this` 绑定在全局对象上,所以结果是 `lufei` 2. 隐式绑定 ```js function show() { var member = 'namei' console.log(this.member) } var member = 'zoro' var caomao = { member: 'lufei', showMember: show } caomao.showMember() // lufei ``` 这里最后通过 `caomao` 来调用这个函数,函数中的 `this` 则被绑定到 `caomao` 这个对象上 3. 显式绑定 ```js var caomao = { member: 'lufei' } var member = 'zoro' function show() { var member = 'namei' console.log(this.member) } show.call(caomao) // lufei ``` 通过 `call`,`apply`,`bind` 我们可以显示的改变 `this` 的绑定 4. `new` 绑定 最后一种是使用 `new` 调用函数,或者说是构造函数调用时 ``` function SeaPoacherBoat(member) { this.member = member } var caomao = new SeaPoacherBoat('lufei') console.log(caomao.member) // lufei ``` 这段代码会执行以下操作: 1. 创建一个全新的对象 2. 进行原型(`prototype`)链接 3. 将 新对象 绑定到函数调用的 `this` 4. 如果没有返回其他对象,则自动返回一个新对象 它们绑定的优先级是 `new` > 显示绑定 > 隐式绑定 > 默认,这也是很容易理解的,`new` 是生成了一个全新的对象优先级是最高的,显示绑定函数要起作用优先级一定要高于隐式绑定,默认绑定是最低的这个也无可厚非 最后一句话总结 **`this` 是运行期间绑定,和它声明的环境无关,只与调用它的对象有关** #### 我们知道了它的指向,要想改变它怎么办呢? 改变 `this` 指向最直接的方法是 `call`, `apply`, `bind`,来看一下下面这段代码 ```js var name = '草帽海贼团' var caomao = { name: '路飞' } function printMember(arg1, arg2) { var name = '娜美' console.log(this.name) console.log(arg1, arg2) } printMember('山治', '索隆') // 草帽海贼团 山治 索隆 printMember.call(caimao, '山治', '索隆') // 路飞 山治 索隆 printMember.apply(caimao, ['山治', '索隆']) // 路飞 山治 索隆 printMember.bind(caimao, '山治', '索隆')() // 路飞 山治 索隆 ``` 根据上面代码,`this` 现在指向的 `window` 对象,所以打印的是草帽海贼团而不是娜美 下面我们通过三种方式将 `this` 指针绑定到 `caomao` 这个对象,所以最后打印的都是路飞 很明显它们的区别无非就在于形式的不同,以`call`为基础来说,`apply` 是将后面的参数合成一个数组一起传人函数,`bind`最后返回的是一个函数,只有调用这个函数后才算执行。 有一种特殊情况就是把 `null` 和 `undefined` 作为`this`的绑定对象传人进去,这样的实际情况是采用的默认绑定原则 那么这有什么用途呢?常见用于**展开数组**来,看一段代码 ```js function print(a, b) { console.log(a, b) } print.apply(null, [1, 2]) ``` 还有呢, 使用`bind`用于**柯里化** ```js var foo = print.bind(null, 1) foo(2) ``` 也就是延迟执行最终的结果 **是不是所有函数都可以绑定`this` 呢?** 没错你可能很快想到就是箭头函数,普通函数来说,`this`是运行期绑定,而 `ES6`新规则里箭头函数并没有绑定 `this`,它是不存在 `this`的绑定的。那在箭头函数中存在`this` 会怎么样呢 ```js // 情景一,全局范围内调用箭头函数 var foo = () => { console.log(this) } foo() // window // 情景二,对象中调用 function monkey() { var bar = () => console.log(this) bar() } var obj = { monkey: monkey } var other = { obj: obj } other.obj.monkey() // { monkey } ``` 之前很多人对箭头函数中的 `this` 都有一些误解,认为箭头函数中的 `this` 自身绑定或者是任何绑定在最终调用方式上。其实不然,从上面代码中我们可以看出箭头中的 `this` 绑定在离最近外层的对象 obj 上, 而不是最终调用对象 other 上。 #### 我们知道了 `this` 的指向的对象调用它的函数,那么调用它的时候到底发生了什么?我们需要知道JS执行机制到底是怎么样的 ```js console.log(run) var run function run(run) { var run = 2 this.run = run console.log(this, arguments) console.log(run) } run('1') console.log(run) run = 3 console.log(run) ``` ![](https://user-gold-cdn.xitu.io/2019/6/29/16ba13ddd0559ef8?w=1916&h=366&f=jpeg&s=90505) 我们来分析一下它的运行方式 首先开始预解析,它有个规则是**变量声明提升**,我们可以知道函数声明会被提升到最上面,其次是变量。**声明后的变量不会重复声明**,所以第二次声明的变量不生效,我们手动来做一次转换 ``` // 提升函数声明 function run(run) { console.log(this, arguments) var run = 2 this.run = run console.log(run) } // 提升变量声明 var run console.log(run) run('1') console.log(run) run = 3 console.log(run) ``` 所以第一个 log 会打印出函数而不是变量 开始按顺序执行下面的语句,此时遇到一个`run()`的调用 将`run`推入到执行栈中,进行以下几个步骤: 1. 绑定 `this` 和 初始化参数, 根据之前谈到的规则,`this` 绑定到调用它的全局对象 `window`,所以第二个 log 打印出 `window`对象和传递过来的参数 2. 同样在函数作用域中开始执行预解析,执行语句,函数中又定义了一个`run`。我们知道作用域原理是就近查找,存在一个屏蔽作用,`run` 函数作用域中的 `run` 此刻就是 `2`,所以第三个 log 会打印出 `2`, `this.run = run` 将全局中的 `run` 赋值为 `2` 3. 执行完成后,`run` 函数出栈,继续执行全局语句,`run` 的值已经被改变成 `2`,所以此刻第四个 log 也打印出了 `2`,最终又被改变成 `3`,所以最后一个 log ,打印出了 `3` ### 聊聊框架 Vue 和 React 你学哪一个? 哎呀!头疼, 能不能不要选啊,选 `React` 都说 `React`待遇好,大厂都爱`React`。 HR问,你`Vue` 多少经验?没有,bye~,不符合项目经验。那就学 Vue 呗,好上手,越来越流行。 HR问,你`React` 多少经验?没有,bye~,不符合项目经验。- - 大家仰望天空叹息到,学不动了...不怕学不动了,就怕学到的东西马上就过时了。 所以只有学到**真正底层基础思想**的东西才是真正重要的。 就算哪天没有这些框架了也能马上撸一个出来。 ### 分享想法 最近找工作萌生了一个 开源 idea - 痛点一:每次制作需要去找模版,去制作模版,而对于我们前端而言,更加擅长制作个性在线简历,可不可以考虑使用前端技术制作一个在线简历模版,开源免费供大家使用,大家开发自己的主题,大家不需要花钱去模版网站找那些并不适合自己的简历模版。 - 痛点二:对于前端来说,知识点太杂,面试考点太多。简历不单单是一个介绍,也是我们技术的一个总结。通过开发一个工具自动识别我们简历里面的技术点,模拟面试官给出一些面试考察的题目,让我们知道自己的不足,持续的学习和进步。 - 痛点三:对于简历,我们不应该一份简历进行海投,应该针对不同的岗位职责进行修改。所以我们可以开发一个输入职位地址,自动匹配简历与岗位中的差异并标记。这样我们就知道自身与岗位职责之间又多大差距,然后努力去接近它。同时我们需要对不同简历进行管理。 以上都是目前各大招聘网站和简历制作网站所没有的需求,这是我们技术人员和求职者自身的诉求。 而目前各大招聘网站更加注重招聘者的需求,往往不会管应聘者的需求,甚至要求各种付费的一些功能。 这个开源项目不是为了取代招聘网站,而是做一个从学习->工作->求职环节的一个补充。 需求 - v1.0.0 在线简历编辑功能,自己制作主题功能... - v2.0.0 技术匹配识别功能,模拟面试功能,面试评分功能... - v3.0.0 简历管理功能,职位匹配功能... - v4.0.0 内推,代码练习,文章订阅... 技术实现 待定... ### 开源计划 https://github.com/suoyuesmile/resume-promotion ![](https://user-gold-cdn.xitu.io/2019/6/28/16b9c2da2dbaa14f?w=2050&h=1282&f=jpeg&s=264545) ### 感谢阅读 第二次发文章,技术不到位多多海涵,里面技术点一部分来自 `You don't kown JavaScript`,另一部分来自平时看过的文章和平时的总结。以后会持续更新,也算是对自己技术相关原理的总结。推荐大家去认真看看这本书,相信你会有更大的收获。 高清电子书资源(请私聊,我单独发给你) ![](https://user-gold-cdn.xitu.io/2019/6/28/16b9c1f885d8de6b?w=1580&h=1498&f=jpeg&s=316923) ### 下期预告(待定) #### 函数又来自哪?同时数组又来自哪?原型链又是什么东西? #### 我们已经有了函数,为什么还要箭头函数?箭头函数仅仅是替代函数写法吗? #### 我们知道 Vue 通过 `Object.defineProperty()` 劫持对象,那么它数组又是怎么劫持的呢? #### 函数有个执行栈,我们知道同步函数是在执行栈里执行,那异步函数呢? #### 说到异步,怎么实现异步的?异步与同步最大的区别在于什么? #### 回调函数可以实现异步,为什么还要用 `Promise`? #### `Promise` 异步就很好用了,为啥又有 `async` 和 `await` ------------------------------更新------------------------------------- 2019.7.3 更新 工作已确定,帮忙内推的朋友多谢了...去了一家小型待遇还不错的小公司 2019.12.6 更新 前一天还在谈论技术方案,今天公司倒闭缱散了,又成自由人了... 希望下家稳定些... [掘金地址](https://juejin.im/post/5d14bb9a5188255d3f6ca8f6) [issue评论区](https://github.com/suoyuesmile/suo-blog/issues/37) ================================================ FILE: articals/js/0001.md ================================================ 对写文章这件事已经阁了3个月了,工作太忙很难抽出大块时间来总结写作。现在稍微闲赋些,准备好好对以前的技术做一下总结。为什么要写关于 `Promise` 呢?有以下 3 点 1. 之前面试时候,面试官问 `Promise` 问的比较多,实在要对它进行一个好好总结了,也是 JavaScript 比较难懂的一个技术点,平时我面试别人时候,也喜欢问 `Promise` 相关的,保证他在工作中能够熟练运用,自己能封装`axios`,能控制比较复杂的同步异步流程等... 2. 这三个月的工作中,自己也总是遇到关于 `Promise` 的一些运用场景,有时候又比较疑惑一些地方,也是为自己总结一下 `Promise`,以后在工作中更加运用自如。 接下来我从最基础的同步异步谈起,再通过图示谈他的语法,如何自己写一个`Promise`,再谈一下我在工作中遇到的 `Promise`,最后谈一下 新的语法 `async` 和 `await `与 `Promise` 的结合和比较 3. 网上关于`Promise`的介绍大多数是一些语法的介绍,大多没有结合场景和同步异步相关理解来谈。对于理解`Promise`的前世今生还是不够深入,不够具体。 ### 理解同步异步 #### 理解JS执行原理 ```js console.log(1) setTimeout(() => { console.log(2) }, 1000) console.log(3) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc36793510dcb?w=870&h=178&f=png&s=21690) 如果延迟时间为`0`呢 ```js console.log(1) setTimeout(() => { console.log(2) }, 0) console.log(3) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3768cc93ab7?w=870&h=178&f=png&s=21690) ```js console.log(1) setTimeout(() => { console.log(2) }, 2000) console.log(3) setTimeout(() => { console.log(4) }, 1000) console.log(5) setTimeout(() => { console.log(6) }, 0) console.log(7) setTimeout(() => { console.log(8) }, 1000) console.log(9) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc37d13c8d4d1?w=979&h=237&f=png&s=25651) 这里可以发现几点 - 1,3,5,7,9 是同步代码,6,4,8,2是异步代码,同步先于异步执行 - 单看同步代码,按位置顺序依次执行 - 单看异步代码,不同执行时间,越长越靠后执行。相同执行时间,按位置顺序依次执行 这里我们总结下同步与异步的规律 - **代码中存在异步函数,不管需要时间多久,都要在同步完成后执行** - **同步按位置顺序执行;异步按时间长短执行,同样时间长短时,按位置顺序执行** 这是一个怎样的机制,JS引擎又是如何处理的呢? 我找到了一张这样的图 ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc4f54ce86a77?w=668&h=728&f=png&s=116007) 首先来解释一下这个图:这是JS的事件循环,分为3个步骤 1. 引擎将同步、异步函数按次序载入到执行栈里面 2. 执行栈的将异步函数放入异步线程里面 3. 线程根据任务完成时间依次推入任务队列中执行 如何处理异步呢, 最初的方法是使用回调 #### 理解回调 引入一下知乎上的高赞回答 ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3910ea37e92?w=672&h=175&f=png&s=61333) 现在我们把它用代码写出来看看 ```js function fetchSomething() { console.log('去取货!') } function buySomething(callback) { console.log('没货了!') setTimeout(() => { console.log('有货了!') callback() }, 1000) } buySomething(fetchSomething) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc39781a4e90f?w=971&h=93&f=png&s=16593) 用简单的语言描述就是:**将一个函数作为参数传给另一个函数调用** 要搞清楚的一点是,回调和异步没有直接的关系,也可以同步回调,也可以异步回调。我们是通过回调这个机制来实现异步的操作,例如 ```js // 这个一个请求的异步函数,来实现异步操作 function getSomePeopleName(params, callback) { setTimeout(() => { let data if (params === 'suo') { data = 'yue' } console.log(callback(data)) }, 1000) } console.log(getSomePeopleName('suo', (data) => '我是回调函数:' + data)) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc39cc16756ca?w=981&h=50&f=png&s=10223) 回调函数的结果一定是在回调函数里面,如果我是这样一个流程呢? A -> B -> C -> D ```js function A(callback) { console.log('开始执行A') setTimeout(() => { callback('A') }, 500) } function B(callback) { console.log('开始执行B') setTimeout(() => { callback('B') }, 400) } function C(callback) { console.log('开始执行C') callback('C') } function D(callback) { console.log('开始执行D') setTimeout(() => { callback('D') }, 200) } A((a) => { B((b) => { C((c) => { D((d) => { console.log(a, b, c, d) }) }) }) }) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3a059ac9335?w=984&h=138&f=png&s=28153) 由上可知,回调函数有几个特定 - 使用回调函数嵌套,回调函数一定在上一个回调之后执行,用于可以控制流程,不会出现异步函数在执行顺序的混乱,即使同步异步函数混合 - 回调函数解构嵌套,代码不够清晰,俗称回调地狱 那么有没有更好的异步操作机制呢?这里我们就要谈到 `Promise` 了 ### 深入 Promise #### 为什么要有Promise? #### ES6 标准中 Promise 语法 - `Promise`是一个构造函数 我们写一个简单的 `Promise` 看看 ```js new Promise(() => {}) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3a54349e6a6?w=999&h=81&f=png&s=24159) ```js // 有一个参数executor的构造函数 // executor 也是一个函数,具有两个参数 resolve, reject 是两个回调函数,当执行到回调函数时,会执行 const isResolve = true new Promise((resolve, reject) => { if (isResolve) { resolve() } else { reject() } }) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3aa82ed74d5?w=993&h=84&f=png&s=26690) 可以看到 `Promise` 的状态从`pending`变成`resolved` 如果将 `isResolve` 置为 `false` 呢? ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3ac9e1ca05b?w=988&h=155&f=png&s=49526) `Promise` 状态从 `pending` 变成 `rejected` 同时抛出一个异常,并且异常未被捕获,所以我们写Promise时候一定要加上catch 来捕获异常 ```js const isResolve = false new Promise((resolve, reject) => { if (isResolve) { resolve() } else { reject('我拒绝你') } }).catch((err) => { console.log('捕获异常', err) }) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3b01a156c52?w=974&h=111&f=png&s=32482) 现在我们把异常捕获到了,但是神奇的事情发生了,异常状态应该是`rejected`,怎么变成 `resolved`了呢? 我们或许很纳闷,这个放在后面讨论,我们先看看 `then` 怎么处理的 ```js const isResolve = true new Promise((resolve, reject) => { if (isResolve) { resolve('通过') } else { reject('我拒绝你') } }).then((res) => { console.log('resolve', res) }, (res) => { console.log('reject', res) }) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3b21dfb11e8?w=993&h=51&f=png&s=11455) 当`isResolve = false` 时 ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3b3d70db1fe?w=970&h=256&f=png&s=63737) 我们可以看到 `then` 是怎么处理的 1. 如果 前面`resolve()`调用,Promise状态为 `resolved`,`then`则执行第一个回调函数参数 2. 如果 前面`reject()`调用,Promise状态为 `rejected`,`then`则执行第二个回调函数参数 3. **then 执行回调函数之后Promise 的 状态都为 resolved** 下面进一步验证下 ```js const isResolve = false new Promise((resolve, reject) => { if (isResolve) { resolve('通过') } else { reject('我拒绝你') } }).catch(err => { console.log('我捕获到了', err) }).then((res) => { console.log('resolve', res) }, (res) => { console.log('reject', res) }) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3b6af37dd29?w=994&h=69&f=png&s=18872) 果然呢,`catch`之后,`then`还会去执行,并且`resolve` 的参数为 `undefined` 问题是现在我们如何控制一个流程呢?`Promise`并不能直接给我们进行长流程的分支选择 下面有一个简单流程 ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3b891c6d0a2?w=569&h=301&f=png&s=28502) 尝试使用`Promise`去控制流程 ```js const process = [102, 204] new Promise((resolve, reject) => { if (process[0] === 101) { setTimeout(() => { console.log(101) resolve(101) }, 1000) } else { setTimeout(() => { console.log(102) reject(102) }, 1000) } }).then(() => { if (process[1] === 201) { setTimeout(() => { console.log(201) }, 500) } else { setTimeout(() => { console.log(202) }, 500) } }, () => { if (process[1] === 203) { setTimeout(() => { console.log(203) }, 500) } else { setTimeout(() => { console.log(204) }, 500) } }).catch((err) => { console.log(err) }) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3bb5ff9fa71?w=980&h=44&f=png&s=6778) 下面我们试试更加复杂的流程 #### Promise 调用链:then 的作用 单个`Promise`没办法控制长流程,我们怎么将`Promise`形成一个控制链呢,需要理解`then`的返回在其中起到的作用 ```js promise.then(onFulfilled, onRejected) ``` - 接收两个参数,`onFulfilled` 在`promise`的 `resolved` 状态被调用 - 接收两个参数,`onRejected` 在`promise`的 `rejected` 状态被调用 - 返回值比较复杂,下面用表格列出来 | 序号 | 场景 | 返回的Promise状态改变为 | 回调函数参数值 | | ---- | ----------------- | ----------------------- | ------------------------- | | 1 | 返回1 个值 | resolved | 返回值 | | 2 | 没有返回 | resolved | undefined | | 3 | 抛出错误 | rejected | 错误 | | 4 | resolved的Promise | resolved | 返回的Promise回调的参数值 | | 5 | rejected的Promise | rejected | 返回的Promise回调的参数值 | | 6 | pending的Promise | pending | 返回的Promise回调的参数值 | 我们可以看出想要控制`then` 的后续流程,必须通过这 6 种情况来控制 下面来测试一下 这 6 种情况是否符合我们的预期 1. 返回一个值 ```js new Promise((resolve, reject) => { resolve('通过') }).then((res) => { console.log('1', res) return res // then的返回值 }).then((res) => { console.log('2', res) }) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3bd681ae92f?w=982&h=129&f=png&s=34577) 2. 不返回 ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3bfadb1cbf8?w=1000&h=191&f=png&s=45586) 3. 抛出错误 ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3c4554d2fd5?w=974&h=215&f=png&s=49392) 4. resolved的Promise ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3c86725cdaa?w=991&h=213&f=png&s=52329) 5. rejected的Promise ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3cf8ba7e522?w=965&h=215&f=png&s=52296) 6. pending的Promise ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3d20e84c428?w=992&h=222&f=png&s=53439) #### 看图写代码 ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3d4e79ea88d?w=550&h=516&f=png&s=40451) 分析特点: 这样就比较复杂了,还要考虑暂停的问题,但是根据我们上面测试到的,通过`then`的返回值控制流程也没有想象那么难 ```js task([101, 201]) function task(testPath) { console.log('开始测试', testPath) new Promise((resolve, reject) => { console.log('000') if (101 === testPath[0]) { resolve('101') } else { reject('102') } }).then((res) => { console.log('201', '上一个返回:' + res) return new Promise(() => {}) }, (res) => { if (202 === testPath[1]) { console.log('202', '上一个返回:' + res) return '202' } else { console.log('203', '上一个返回:' + res) throw '203' } }).then((res) => { console.log('301', '上一个返回:' + res) return Promise.resolve('301') }, (res) => { console.log('302', '上一个返回:' + res) return Promise.resolve('302') }).then((res) => { console.log('401', '上一个返回:' + res) return Promise.reject('401') }).catch((err) => { console.log(err) }) } ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3d7e6c84dd3?w=1000&h=96&f=png&s=19460) ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3d9d7f7e00d?w=997&h=148&f=png&s=33965) ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3dbe3d246bf?w=991&h=145&f=png&s=32813) - `Promise.resolve()` 等同用 `new Promise((resolve, reject) => resolve())` - `Promise.reject()` 等同用 `new Promise((resolve, reject) => reject())` - `Promise.all()` ```js // 作为参数promise 数组中,所有promise状态都是resolved才回调then第一个,只要有一个reject就reject Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]).then((res) => { console.log('通过', res) }, (res) => { console.log('拒绝', res) }) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3dd9ce0f6f4?w=951&h=53&f=png&s=11561) 返回值为全部值的一个数组 ```js Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.reject(3)]).then((res) => { console.log('通过', res) }, (res) => { console.log('拒绝', res) }) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3df3f859554?w=972&h=140&f=png&s=44175) 返回值仅返回拒绝的那个 - `Promise.race()` ```js Promise.race([new Promise((resolve, reject) => { setTimeout(() => { reject(1) }, 1001) }), new Promise((resolve, reject) => { setTimeout(() => { resolve(2) }, 1002) })]).then((res) => { console.log('通过', res) }).catch((res) => { console.log('拒绝', res) }) ``` ![](https://user-gold-cdn.xitu.io/2019/10/24/16dfc3e15074ee98?w=985&h=276&f=png&s=69811) race 相当于竞赛,多个`Promise`竞赛,谁先状态变成`resolved`和`rejected`,谁就执行下面的回调(根据时间来抉择) ## 下节预告 ### Promise 到 generator 再到 async & await ### Promise 实际应用 #### 对异步请求封装 #### 流程控制 ### 手写一个Promise ## 后记 总结一下,从同步异步到回调,在到`Promise`的语法和应用全部都可以在谷歌浏览器的控制台中输出测试。通过一点点代码的编写和输出,才会让我们思维更清晰,对`Promise`的理解更深刻。之后再总结工作中用到的`Promise`,以后也会慢慢将`async`、`await`结合P`romise`来谈关于 es6 以后异步相关的新特性。 ================================================ FILE: articals/js/0002.md ================================================ Promise 处理异步代码相对于纯回调函数比较有序明了,但是对于同步函数写法还是挺繁琐的,下面有两种语法糖让异步更加清晰简洁 ### 生成器 #### generator 函数 像指针一样下移,有点像在debug代码 ```js function* gen() { yield 1 yield 2 yield 3 } let g = gen() console.log(g.next()) console.log(g.next()) console.log(g.next()) console.log(g.next()) ``` ![](https://user-gold-cdn.xitu.io/2019/10/26/16e05c5073d15915?w=443&h=112&f=png&s=20314) - 中断并完成下移`return()` ```js function* gen() { yield 1 yield 2 yield 3 } let g = gen() console.log(g.next()) console.log(g.next()) console.log(g.return('完成')) console.log(g.next()) ``` ![](https://user-gold-cdn.xitu.io/2019/10/26/16e05c8e0a184e1d?w=479&h=112&f=png&s=21553) - 中断并抛出异常 `throw()` ```js function* gen() { try { yield 1 yield 2 yield 3 } catch(e) { console.log(e) } } let g = gen() console.log(g.next()) console.log(g.next()) console.log(g.throw('异常')) console.log(g.next()) ``` ![](https://user-gold-cdn.xitu.io/2019/10/26/16e05c943fb42af0?w=528&h=128&f=png&s=22410) 如果在异步函数里面使用 `generator` 函数怎样? ```js function promise() { return new Promise((resolve, reject) => { setTimeout(() => { resolve('resolved') }, 1000) }) } function* generate() { promise().then((res) => { console.log(res) }) } function fn() { const res = generate().next() console.log(res) } fn() ``` ![](https://user-gold-cdn.xitu.io/2019/10/26/16e05c98d09a0b6d?w=472&h=71&f=png&s=10162) 现在发现,异步代码不需要`then`回调了,看起来和同步函数写法一样 不过现在我们有了`async`、`await`函数,将生成器进一步封装,也可以说出语法糖 ### async、await函数 使用Promise 写法写一个简单的例子 ```js function promise() { return new Promise((resolve, reject) => { setTimeout(() => { resolve('resolved') }, 1000) }) } function fn() { promise().then((res) => { console.log(res) }) } fn() ``` ![](https://user-gold-cdn.xitu.io/2019/10/26/16e05ca6a93a9bcc?w=493&h=47&f=png&s=5346) 改写成 `async` 函数 ```js async function asyncFn() { console.log(await promise()) } asyncFn() ``` ![](https://user-gold-cdn.xitu.io/2019/10/26/16e05cacfd6339fe?w=994&h=47&f=png&s=9295) **async 和 then 一样 可以达到同一个的效果,而且代码中没有回调函数的影子了** 多条异步链的情况 ```js function promise() { return new Promise((resolve, reject) => { setTimeout(() => { resolve(1) }, 1000) }) } function fn() { const p = promise().then((res) => { console.log('第一个then', res) return res === 2 ? new Promise((resolve, reject) => { setTimeout(() => { resolve(2) }, 500) }) : new Promise((resolve, reject) => { setTimeout(() => { reject(3) }, 500) }) }).then((res) => { console.log('第二个then', res) }).catch((err) => { console.log('异常', err) }) } fn() ``` ![](https://user-gold-cdn.xitu.io/2019/10/26/16e05cb37467eebb?w=504&h=70&f=png&s=8552) 使用 async 改写 ```js function promise() { return new Promise((resolve, reject) => { setTimeout(() => { resolve(1) }, 1000) }) } function promise2() { return new Promise((resolve, reject) => { setTimeout(() => { resolve(2) }, 500) }) } function promise3() { return new Promise((resolve, reject) => { setTimeout(() => { resolve(3) }, 500) }) } async function asyncFn() { const step1_res = await promise() console.log('第一步的结果:', step1_res) try { if (step1_res === 2) { console.log('第二步的结果:', await promise2()) } else { console.log('第二步的拒绝的结果:', await promise3()) } } catch(err) { console.log('异常:', err) } } asyncFn() ``` ![](https://user-gold-cdn.xitu.io/2019/10/26/16e05cbb2f180de7?w=516&h=51&f=png&s=9559) **用同步的代码写出了异步的效果** ================================================ FILE: articals/react/0001.md ================================================ 2019年7月3日 天气小晴 现在早上9点,准时开始学习 React ### 半个小时过一遍 React 官方文档和教程 (9:00 - 9:30) ![](https://user-gold-cdn.xitu.io/2019/7/4/16bbad4fb3e586eb?w=2706&h=1444&f=jpeg&s=408281) #### 扫视一遍它的基本介绍(5分钟) 我们看到下面介绍了三个 React 最重要的特性: - **声明式**:它是说:React 创建用户界面很简单,当数据改变就会高效的更新和立即渲染组件。同时声明式可以让你的代码更加**可预测和易调试**。 怎么就是可预测的和易调试呢,暂时不是很理解 - **组件化**:可以创建一个管理自身状态的组件,通过组合这些组件来创造复杂的UI。因为组件逻辑是用 JavaScript 写的而不是模版,所以你可以传更丰富的数据到你的APP,同时还可以与 DOM 解藕。 - **一学多用**:不需要新的技术栈,重新写新的代码就可以开发一些新的功能。比如用作服务器渲染,`React Native` 编写移动端代码。 ![](https://user-gold-cdn.xitu.io/2019/7/4/16bbad78e9a04efa?w=2482&h=3628&f=jpeg&s=982997) 再往下扫,给出了 React 的 4 个简单的小例子 - **Helloworld(认识 组件 和 props)** ```jsx class HelloMessage extends React.Component { render() { return (
Hello {this.props.name}
); } } ReactDOM.render( , document.getElementById('hello-example') ); ``` 看到它使用 ES6 的继承,继承了一个组件的基类,此刻充满好奇心的你,肯定会想我继承的这个 `React.Component` 到底是啥?(先留着之后去看 React 的源码) 没有写构造函数,说明它直接继承了基类的构造函数 里面有一个 `render` 函数 `return` 一个貌似模版的东西,这个就是最简单的组件 紧接着下面一个 `ReactDOM.render`函数接受两个参数一个是组件标签,一个`id`查找,现在大概的意思就是`render`函数就是要把组件渲染到找到`id`的这个地方。 组件标签里面的属性就给组件中作为`this.props`的属性。而且我们知道**父组件通过 `props` 可以将数据传递给子组件**。 - **定时器(认识 状态state)** ```jsx class Timer extends React.Component { constructor(props) { super(props); this.state = { seconds: 0 }; } tick() { this.setState(state => ({ seconds: state.seconds + 1 })); } componentDidMount() { this.interval = setInterval(() => this.tick(), 1000); } componentWillUnmount() { clearInterval(this.interval); } render() { return (
Seconds: {this.state.seconds}
); } } ReactDOM.render( , document.getElementById('timer-example') ); ``` 我们看到第二个例子会发现里面多了很多其他的东西: - 构造函数 - state - 声明周期函数 发现我们可以在组件里面定义组件的构造函数,而且可以在构造函数里面初始化一个名为 状态(state)的东东。 **怎样去理解状态(state)这个词?** 我们假设组件是有生命的,它必然有个生命周期。大致分给三个阶段: 出生----> 变化----> 死亡 (对应) 创建----> 更新----> 销毁 伴随着生命周期的变化,它身上的属性也在发生变化,比如体温、寿命、心情、皮肤好坏、细胞生命力,甚至思维模式。我们可以把**这些变化的属性成为状态(state)** 但是作为它的创建者,我们即为它的上帝,所以需要控制管理它的状态的变化。所以我们在每一个阶段的变化中加了一个钩子,在相应的阶段去定义一些程序。 这些大概是我看完这段代码最粗浅的理解吧 。 - **Todo(一个小型增删改查APP)** ```jsx class TodoApp extends React.Component { constructor(props) { super(props); this.state = { items: [], text: '' }; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } render() { return (

TODO

); } handleChange(e) { this.setState({ text: e.target.value }); } handleSubmit(e) { e.preventDefault(); if (!this.state.text.length) { return; } const newItem = { text: this.state.text, id: Date.now() }; this.setState(state => ({ items: state.items.concat(newItem), text: '' })); } } class TodoList extends React.Component { render() { return (
    {this.props.items.map(item => (
  • {item.text}
  • ))}
); } } ReactDOM.render( , document.getElementById('todos-example') ); ``` 这个主要是对一下事件的一些运用,增加,删除数组的元素然后更新 dom 相关的操作。在React 中我们能很容易办到。 - **输入绑定(认识插件和双向绑定)** ```js class MarkdownEditor extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); this.state = { value: 'Hello, **world**!' }; } handleChange(e) { this.setState({ value: e.target.value }); } getRawMarkup() { const md = new Remarkable(); return { __html: md.render(this.state.value) }; } ``` 全部快速过一遍,尝试跟着敲一遍。哦,原来 React 是这么用的!!! **总结一下 React 可以做什么呢?** - 创建一个简单组件,父组件可以通过 `props` 传值给子组件 - 还可以创建拥有状态的组件,添加生命周期钩子管理组件状态 - 对数据增删改查,渲染在 `UI` 上 - 通过事件实现表单的双向绑定 差不多知道怎么用了,我们现在系统的来看一下文档,给以后深入研究铺路 接下来我们去系统的看看它相关的一些概念... #### 开始进入DOC 系统性的学习下有关 React 的文档概念相关(20分钟) 1. 安装运行 React 安装运行有三种方式: - 直接使用 script 标签引入 ```html
``` - 在 node 环境下安装 ```sh npx create-react-app my-app cd my-app npm start ``` - 使用 CDN 2. React 的相关概念 - 简单的例子 ```jsx ReactDOM.render(

Hello, world!

, document.getElementById('root') ); ``` 大致理解为通过ReactDOM对象的render函数,将`

Hello, world!

`挂载在 id 为 root 下面 - 我们来了解下JSX,长这个样子: ```jsx const element =

Hello, world!

; ``` 这个写法称为JSX, 它既不是字符串,也不是HTML,而是JavaScript 的一种扩展。 看到它有几个特点: **它可以赋值给 一个引用** **插入变量和函数** 它可以使用`{}`插入变量和函数 ```jsx const element =

Hello, {name}

; // or const element = (

Hello, {formatName(user)}!

); ``` **插入在属性值中** ```jsx const element = ; ``` **可以嵌套子节点** ```jsx const element = (

Hello!

Good to see you here.

); ``` **防止xss攻击** ```js const title = response.potentiallyMaliciousInput; // This is safe: const element =

{title}

; ``` **通过babel编译后长这个样子** ```jsx const element = React.createElement( 'h1', {className: 'greeting'}, 'Hello, world!' ); ``` - 渲染节点是怎么渲染的 不像浏览器DOM, React 节点是一些简单的对象,所以很容易创建,而且它主要关心的是需要更新的部分。 HTML 中始终存在一个唯一的 root 节点`
`,React DOM 回去管理这个root 下面的东西。 然后把 JSX 和 这个root节点,传递给 `ReactDOM.render()`,使用这个方法吧节点渲染出来 **那么它是怎么更新的呢?** **React 节点是 immutable(不变的),一旦创建就不能改变它的子节点和属性**,所以唯一能更新的方法就是,创建一个新的节点,传到`ReactDOM.render()`重新渲染 现在就很清楚了,也就是它要更新UI,存在两个状态,一个是更新前到,一个是更新后的 而**React 仅仅会更新它必须更新的部分,也就是差异的部分** 这个可以放到后面研究,大概是使用 diff 算法比较 虚拟dom树 差异后来更新真实dom 现在我们大致清楚它是如何渲染和更新的了 - 组件和 props 组件和函数一样接受一个输入值,返回一个React element **创建组件的两种方式:** 通过函数创建 ```jsx function Welcome(props) { return

Hello, {props.name}

; } ``` 通过ES 6 class 创建 ```jsx class Welcome extends React.Component { render() { return

Hello, {this.props.name}

; } } ``` **组件也可以组合成一个复杂的组件** ```jsx return (
); ``` **组件的扩展** ```jsx function Avatar(props) { return ( {props.user.name} ); } ``` **父组件传值到子组件(props)** > All React components must act like pure functions with respect to their props. > 它这里强调了就像纯函数一样,所有 React 组件中`props`也是一样不能直接改变它 - 状态和生命周期 之前也提到,大概组件会有三个阶段,每个阶段具体会有几个生命周期方法,大概罗列一下: **载入(挂载阶段 Mounting...)**:`constructor`(构造)、 static getDerivedStateFromProps(处于初始化挂载和更新之间,返回一个更新需要的对象或者null(不更新))、render(渲染 DOM )、componentDidMount(完成挂载) **变化(更新阶段 Updating...)**:static getDerivedStateFromProps(同上)、shouldComponentUpdate(更新前,决定是否更新,返回false不更新)、render(更新 DOM)、getSnapshotBeforeUpdate(更新完成前捕获DOM的信息,然后返回一个参数给`DidUpdate` 使用)、componentDidUpdate(更新完成) **销毁(卸载阶段 Unmounting...)**:componentWillUnmount(卸载前) 还有 2 个**错误处理**的钩子 static getDerivedStateFromError(),componentDidCatch() 具体了解访问 https://reactjs.org/docs/react-component.html **如何使用生命周期钩子呢?** 将生命周期钩子添加到Class中 ```jsx class Clock extends React.Component { constructor(props) { super(props); } componentDidMount() { //... } render() { return (

Hello, world!

); } } ``` 常用做法 ```js componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } ``` 在`componentDidMount()`设置定时器(异步操作),`componentWillUnmount()`清除相关异步操作 **如何更新状态呢?** 使用`this.setState({comment: 'Hello'});`更新状态,**不要直接修改state,因为这样不会重新渲染组件** - 事件机制 事件处理和 DOM0 很相似但是有这些不同的地方 ``` function ActionLink() { function handleClick(e) { e.preventDefault(); console.log('The link was clicked.'); } return ( Click me ); } ``` **驼峰而不是全小写** **传递函数作为事件处理而不是字符串** **需要使用 `preventDefault` 而不是返回`false`阻止浏览器默认事件** 我们可以通过 箭头函数将 `this` 绑定到点击事件处理函数上 ```jsx handleClick = () => { console.log('this is:', this); } ``` 或者在初始化时候就绑定 ```jsx constructor(props) { super(props); this.state = {isToggleOn: true}; // This binding is necessary to make `this` work in the callback this.handleClick = this.handleClick.bind(this); } ``` - 条件渲染 大概可以分为两种方式 **在render函数外部判断,通过return 返回或者引用不同的 React element** ```jsx if (isLoggedIn) { button = ; } else { button = ; } ``` **在render函数内部判断,使用三元操作符来判断** ```jsx render() { const isLoggedIn = this.state.isLoggedIn; return (
{isLoggedIn ? ( ) : ( )}
); } ``` - 列表和 key 使用数组`map()`来渲染多组件 ```jsx const listItems = numbers.map((number) =>
  • {number}
  • ); ``` 渲染多组件需要使用 唯一的Key 来提高渲染性能,这个也和 diff 算法有关,大概是Key识别组件后,就可以直接复用了旧VDOM的节点了 ```jsx
      {props.posts.map((post) =>
    • {post.title}
    • )}
    ``` >We don’t recommend using indexes for keys if the order of items may change. This can negatively impact performance and may cause issues with component state. Check out Robin Pokorny’s article for an in-depth explanation on the negative impacts of using an index as a key. If you choose not to assign an explicit key to list items then React will default to using indexes as keys. **如果列表的顺序可能改变的话,这里不推荐使用 index 作为 keys,它可能造成性能问题**。大概是因为数组顺序改变了和 改变前的index 和 改变后的index 与组件不对应,这样也是没法复用的。(猜测)这里放在后续研究,这篇文章有讲 https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318 - 表单相关 这里提到了一个新的名词“"受控组件",大概意思就是它可以通过输入来控制和改变自己的状态,一般组件只能通过 `setState()`改变状态,而它可以通过输入改变,它是受到用户输入控制的。 大概有以下几种:` input`, `textarea`,`select` ... 我们这样可以通过这种特性来实现一个双向绑定, 这里暂时留着后面补充 - 状态提升 这个为来解决两个组件值同步问题的,有点像联级查询 通常来说,组件与组件之间是独立的,一个组件的状态改变不会影响另外一个组件。但是我们现在需要一个组件状态变化,另外一个组件状态也会变化,那该怎么办呢? 现在就又一种方式,给两个组件加一个相同的状态作为桥梁,一旦这个状态改变,同时改变这两个状态的其他状态,这样就达到了更新另一个组件状态的目的。 ```jsx class Calculator extends React.Component { constructor(props) { super(props); this.handleCelsiusChange = this.handleCelsiusChange.bind(this); this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this); this.state = {temperature: '', scale: 'c'}; } handleCelsiusChange(temperature) { this.setState({scale: 'c', temperature}); } handleFahrenheitChange(temperature) { this.setState({scale: 'f', temperature}); } render() { const scale = this.state.scale; const temperature = this.state.temperature; const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature; const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature; return (
    ); } } ``` - 组合和继承 组合和继承真的是老生常谈的话题,设计模式里面推荐是使用组合,原因就在于**组合是松耦合的模式,继承是紧耦合的模式**。父亲的改变必定会影响到儿子的改变,所以会谨慎使用集成。 除非是父是很稳定不变的,像接口那样只是一个约束,而且约束原则不会频繁变化,使用继承是恰当的。但是一般情况使用组合实现松耦合。 3. 高级指南(这里还有很多地方不是特别理解,后续添加) - Higher-Order Components(高阶组件) - Optimizing Performance(性能优化) - Reconciliation(协调) - Refs (引用) - Portals (门) - Render Props(渲染 Props) - Static Type Checking(静态类型检查) - Uncontrolled Components(非受控组件) - Web Components(web 组件) 4. 了解相关API(这里还有很多地方不是特别理解,后续添加) - React - React.Component - ReactDOM - ReactDOMServer - Shallow Renderer - JS Environment Requirements - Glossary 5. 研究新特性(Hooks) **Hooks 是什么?** **为了让你放心大胆的使用,它给出了你使用Hooks的三大好处** - 完全选择性加入:你不想用可以不需要学习和使用,使用它不需要重写你已有的组件代码 - 100%的向后兼容:它不会中断现有的改变 - 现在就可以用:16.8 之后就可以用了 **为啥要用Hooks?** **它可以让你不使用class也可以使用状态和其他功能** - 组件之间的逻辑很难重用 - 组件太复杂难以理解 - class会造成迷惑 可能这些问题,在真正投入使用,真正实践的时候才会遇到吧,暂时先不讨论 **看看它怎么去重用逻辑和去除 class 的?** ``` mport React, { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0); return (

    You clicked {count} times

    ); } ``` 这里它通过 `useState` 来接受一个初始的状态,调用一个`setCount`函数来控制状态的逻辑. 点击按钮,就会调用这个函数,一旦调用这个函数,就触发了状态的变更。 也就是说我们可以任意时刻去管理状态了,函数组件中就可以了。 这个变更带来的一个直接的好处就是:我们完全可以将组件的某些处理状态的逻辑抽离出来单独处理。 这大概是我最初浅的认识,还需要实践中检验,之后会给出例子。 **看看它的API** ![](https://user-gold-cdn.xitu.io/2019/7/4/16bbb0a2b3e95bb5?w=798&h=850&f=jpeg&s=78228) 6. FAQ - Virtual DOM and Internals(虚拟DOM 和它内部实现介绍-fiber) 之后再去研究 ### 一个小时做一个后台项目的一个小订单管理页面 #### 提出一个需求(2分钟) ```js /** * 订单管理页面,包含3个部分 * 1. 筛选栏,包含日期选择、单选、输入、查询按钮 * 2. 表格,包含ID,商品信息,商品数量,金额,状态,操作 * 3. 分页 */ ``` #### 选择技术方案(3分钟) 尽可能的简单快速的实现它 - UI组件 antd - 预处理 sass - 获取数据 axios - 模拟数据 json-sever - 测试 jest - 路由,状态管理,持续集成...暂不需要 #### 动手简单的实践一下(45分钟) 由于篇幅原因,具体实践请看下篇文章…这里跳转(之后添加链接) #### 效果展示和调优(10分钟) 大概差不多是这种效果 ![](https://user-gold-cdn.xitu.io/2019/7/4/16bbb122b2f014d1?w=2874&h=1118&f=jpeg&s=179046) 这个不是最终效果,还需要调优... ### 深入技术栈来研究 (10:00 - 11:00) 知乎上/掘金上搜索一些讲 React 比较好的书,诶,发现两本,很快搞到资源了 - 《React 精髓》 ![](https://user-gold-cdn.xitu.io/2019/7/4/16bbafba663d8bc1?w=992&h=1222&f=jpeg&s=228323) - 《深入 React 技术栈》 ![](https://user-gold-cdn.xitu.io/2019/7/4/16bbafbcf35f26bd?w=992&h=1222&f=jpeg&s=228323) 浅读这两本之后会写一篇博客,对里面知识和作者想法进行梳理 开始大致过一遍这两本书的内容 #### 总结下阅读这两本书的感觉 两本书写的都很好,而且它们刚好侧重点不同,前者侧重于里面**核心api的设计思想和理念**,后者侧重于**实际开发中的一些技术难点** *之后会有精读的文章出来,请持续关注…* ### 深入源码(11:00 - 11:30) #### 阅读 React 源码(15分钟) 进入 `github` 仓库 https://github.com/facebook/react 头一眼看到全是代码很懵,不知道看啥好 首先来搜一些目录结构图,我们要知道 - 哪个版本? - 哪里上手? - 我们应该看什么? - 这些目录都是做什么用的? - 需要掌握哪些东西? - 看完后有什么收获? *之后会有深入研究的文章出来,请持续关注* #### 阅读 antd 源码 (15分钟) 现在还有点时间,我们跑去 antd 的github里面,看看它的各个组件是怎么写的 尝试自己写一个 `dialog` 和 `table` 以后再做 差不多粗略看完源码我们对 React 有些许了解了 现在开始了解一下它的相关生态了 ### 逛逛生态圈(11:30 - 12:00) #### 组件库(10分钟) - antd ![](https://user-gold-cdn.xitu.io/2019/7/4/16bbaf205e1ab258?w=1280&h=1538&f=jpeg&s=224562) - antd pro ![](https://user-gold-cdn.xitu.io/2019/7/4/16bbaf29b91144e0?w=2836&h=1426&f=jpeg&s=434309) - 其他组件库 #### 状态管理(10分钟) - flux - redux - saga - react-redux - dva https://dvajs.com/ ![](https://user-gold-cdn.xitu.io/2019/7/4/16bbaf32c138695c?w=1472&h=974&f=jpeg&s=291874) >React and redux based, lightweight and elm-style framework. >D.Va拥有一部强大的机甲,它具有两台全自动的近距离聚变机炮、可以使机甲飞跃敌人或障碍物的推进器、 还有可以抵御来自正面的远程攻击的防御矩阵。 **Dva 是基于 React + Redux + Saga 的最佳实践沉淀** ```js app.model({ namespace: 'count', state: { record: 0, current: 0, }, reducers: { add(state) { const newCurrent = state.current + 1; return { ...state, record: newCurrent > state.record ? newCurrent : state.record, current: newCurrent, }; }, minus(state) { return { ...state, current: state.current - 1}; }, }, effects: { *add(action, { call, put }) { yield call(delay, 1000); yield put({ type: 'minus' }); }, }, subscriptions: { keyboardWatcher({ dispatch }) { key('⌘+up, ctrl+up', () => { dispatch({type:'add'}) }); }, }, }); ``` - immutable(不变性的库) #### 路由(3分钟) - react-router(这个同Vue Router 区别不大) #### node 相关(4分钟) - Umi JS(一个插件,构建,测试,打包工具集) ![](https://user-gold-cdn.xitu.io/2019/7/4/16bbaee70df5d12b?w=1604&h=1268&f=jpeg&s=349626) - SSR *后续会着重研究SSR相关原理和实践* #### 其他(3分钟) - Jest (单元测试相关 facebook 出版,react 默认) 两个优势,第一个是一次安装全部拥有, 二是比之前 Karma 系列多了一个快照测试,主要是用了比对dom结构,进行回归测试相关 - 其他UI框架 *自制简单开源 React UI 计划中...* ### 后记 惨痛经历:本来写了 3400 多字,有次突然发现少了一些篇章,然后急忙按撤回,撤回最后成了全空状态。自动保存后,草稿全被覆盖,丢失了,后来又重新写的,悲惨。 提醒大家如果想写博客,一定不要在线写,直接本地写,写完复制到在线,加图片后直接发布。 ### 感谢阅读 感谢你能阅读到这个地方,还没放弃… **作者能力有限,里面或许有些许文字错误,和一些技术上错误的理解,欢迎在评论中指出改正**。 本篇文章只是记录了本人 3 个小时学习 React 的经历,可能对那些学习的比较零散而没有章法的人有一些帮助,通过**分享出一个学习路线,让他们系统性的构建知识**。要想真正掌握 React 里面的相关技术还是要花很长时间的。 如果你想去深入研究下它的话,希望你能看完本篇文章后,可以花更多时间去琢磨里面的一些点和程序的设计。 最后希望各位的技术都有长足的进步,而不是仅仅局限在一些工作的业务上。 ### 下期预告 找工作结束了,下周大概就会正式入职了,写作博客的时间会相对比较少,但是还是希望多多去研究学习,总结一下学到的点,分享给大家。 下期博文的话,内容大概是**关于 Vue 的一些思考和在工作中运用的实践总结**(时间待定) 还有就是关于上一期后面面试题的研究,也会慢慢研究,之后会出一个系统性的总结(待定) ### 原创声明 本文完全原创,全部是经过作者3个小时的学习,和一天多思考总结出来的成果。允许转载,但需标明**作者和原文链**,谢谢! [issue评论区](https://github.com/suoyuesmile/suo-blog/issues/38) ================================================ FILE: articals/vue/0001.md ================================================ 2019年6月6号,为了爱情,我离开工作了一年多的广州来到了杭州这个互联网城市。开始我的前端面试之旅... 放下拧螺丝的扳手,开始造起了飞机... 面试的第一家,一开始就问 **Vue 双向绑定怎么实现**。 一脸蒙蔽,之前看过源码,但是没有深入研究,只回答出了使用 `Object.defineProperty` ```js Object.defineProperty(obj, prop, { // ... get: function() {} set: function() { // ... } }) ``` 要是再给我一次机会我会这样回答 **Vue 双向绑定,使用数据劫持和发布订阅模式实现的** 然后我再画一个图来描述整个实现过程是怎样的 vue2.0 采用的是 `Object.defineProperty` 进行数据劫持的 主要实现原理是使用描述对象中的set方法进行拦截,并发送订阅器信号 ```js // ... let dep = new Dep() return Object.defineProperty(obj, prop, { // ... get: function(key) { dep.target = this dep.addSub() // ... } set: function(newVal) { val = newVue; // 发送一个dep信号 dep.notify() // ... } }) ``` 而 vue3.0 中可能会采用 `Proxy` 来实现数据劫持 ```js let target = {} let p = new Proxy(target, { set: function() { //... }, get: function() { //... } }) ``` *为啥呢?* 我们知道 `Object.defineProperty` 是有局限性的,他的拦截的 target 就是单纯的对象的key的值 所以呢,对象属性的删减,数组,数组长度的改变,它就没法进行劫持了 而 ES6 的新特性,`Proxy`,它可以拦截对象,数组几乎一切对象包装类型 但是 `Proxy `没法兼容 IE,所以 Vue3.0 底层还是采用 `Object.defineProperty` 而 使用 `Proxy` 作为一个 `api `,也就是说: 我们不兼容IE, 就大胆用 `Proxy` 双向绑定而且不会有属性删减和数组劫持不到的问题 我们要兼容IE,就用原来的双向绑定,但是要注意它的不能劫持部分变化的缺陷 从上图我们可以看到,`Observer` 观察了 `object` 值的变化,这是一种观察者模式 而 `Observer `将观察的信号发布给订阅器这是一种 发布订阅模式 #### 那么观察者模式与发布订阅模式有什么区别呢? 我们先谈观察者模式 *什么是观察者模式,首先有一个观察者,一个被观察者,被观察者这里是数据,而观察者是Observer,被观察者发生变化时,主动发生信号给被观察者* 按照这个思路来说,我们也能想象尤大,当时设计双向绑定时候,思考怎样去监听这个数据的变化,也就是如何使用观察者模式来实现,而恰好对一个对象的处理中有个对象方法我们可以使用,就是 `Object.defineProperty` #### 假如没有这个方法我们怎么实现呢? 这就是 angular 的另外一种实现方式脏检测,也就是不停的轮询数据的变化情况,显然脏检测对性能消耗比较大 #### 再谈谈发布订阅模式 在软件架构中,发布订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。 这里很明显了,区别就在于,不同于观察者和被观察者,发布者和订阅者是互相不知道对方的存在的,发布者只需要把消息发送到订阅器里面,订阅者只管接受自己需要订阅的内容 由此发布订阅模式是一种松耦合的关系,`watcher` 和 `Observer` 之间是互相不受影响 ## 后记 感谢观看,第一次发文章 [issue评论区](https://github.com/suoyuesmile/suo-blog/issues/36) ================================================ FILE: articals/vue/0002.md ================================================ # 前言 之前使用过 Vue 开发后台、中台项目,也做过移动端 H5,弄过一点小的前端架构。每做一个项目都会收获了不一样的经验和理解。下面我把这些点点滴滴的经验总结下来,做一个系列的文章分享和阶段性的总结。 > 常规操作,先点赞后观看哦!你的点赞是我创作的动力之一! ## 概览 ![](https://user-gold-cdn.xitu.io/2019/12/30/16f5676f7940d72a?w=1898&h=1206&f=jpeg&s=294508) ## 问题 > 我将从 16 个方面来论述 vue 开发过程中的一些技巧和原理。当然由于篇幅有限,先论述前 8 个问题,下节将完成全系列内容。 本篇文章将围绕下列问题进行论述: - **如何规范你的 git 提交,并自动生成并提交日志?** - **如何配置和使用 Sass 和 PUG 提升你的编码效率?** - **如何处理你的代码风格问题,以及如何使用 perttier 与 eslint 解决效率风格两难问题?** - **如何管理页面的路由,如何编写异步路由?** - **如何编写组件,引入组件库?** - **如何管理你的资源,如何引入图标,样式?** - **如何封装你的 axios,管理你的api?** - **如何使用 mock 模拟你的数据,实现真正意义的前后端分离?** # 实践 > 实践之前:我希望你有如下准备,或者知识储备。 > - 了解 `npm/yarn/git/sass/pug/vue/vuex/vue-router/axios/mock/ssr/jest` 的使用和原理。 > - 当然上面知识不了解也没关系哈哈哈,文章中会提到大致用法和作用。 ## 如何规范 git 提交 > 代码提交记录是一个很好的代码修改日志。规范的代码提交记录,不管在平时代码开发维护过程中,还是在定位 bug 或者回退版本来说都是极为重要。 ### 原理 两种做法: - 自己手动规范 git 的提交原则或者团队统一制定。这个靠自觉,好习惯养成之后就没问题来 - 使用插件规范,比如下面这种 为了规范提交,我使用了如下插件: - commitizen - conventional-changelog - cz-conventional-changelog - conventional-changelog-cli #### 解决方案 #### 安装系列插件依赖 ```sh yarn add -D commitizen conventional-changelog cz-conventional-changelog ``` > 安装依赖时,要注意是否是生产环境需要的。显然 `commitizen` 只在开发环境中使用。`-D` 只在 `dev` 环境使用 #### 配置依赖路径 在 `package.json` 中添加配置 ```js { //... "config": { "commitizen": { "path": "./node_modules/cz-conventional-changelog" } } } ``` 在命令行中输入 ```sh git add -A git-cz ``` 出现了交互输入方式,规范你的 `commit` 输入格式 ![](https://user-gold-cdn.xitu.io/2019/12/30/16f554235055e8f3?w=2194&h=620&f=jpeg&s=226477) #### 生成 CHANGELOG ```sh npm i -g conventional-changelog-cli ``` 增加一个npm 命令,快速生成日志 ```js "genlog": "conventional-changelog -p angular -i .github/CHANGELOG.md -s" ``` 使用`yarn`命令生成日志 ```sh yarn genlog ``` 自动生成的log ```md # 0.1.0 (2019-12-27) ### Features * **git:** 增加commitizen工具规范提交 ([58e3937](https://github.com/suoyuesmile/suo-design-pro/commit/58e39370aa838fd99312f73b37d092ffadc85990)) ``` ## 如何管理代码风格 > 较统一的代码风格利于阅读,也利于协作。 ### 原理与解决方案 使用 eslint 约束基本风格和语法,使用 prettier 自动格式化你的代码。 ### 实践 #### 安装 eslint 依赖 ```json { "eslint": "^5.16.0", "eslint-config-standard": "^6.2.1", "eslint-friendly-formatter": "^2.0.7", "eslint-loader": "^2.1.2", "eslint-plugin-html": "^2.0.1", "eslint-plugin-promise": "^3.5.0", "eslint-plugin-standard": "^2.3.1", "eslint-plugin-vue": "^5.0.0" } ``` 使用两个插件,一个 `plugin:vue/essential`,一个是 `standard`。 `vue/essential` 为了在 vue 里面也可以生效。另一个是 `standard`。 [standard 标准文档](https://github.com/standard/standard/blob/master/docs/RULES-zhcn.md#javascript-standard-style) > 使用 recommend 也可以,采用推荐 lint,更加轻量化 ```js module.exports = { root: true, env: { node: true }, extends: ['plugin:vue/essential', 'standard'], rules: { quotes: ['error', 'single'], indent: ['error', 2, { MemberExpression: 'off' }], 'arrow-parens': 0, 'no-loop-func': 2, 'space-before-function-paren': ['error', 'never'], indent: ['error', 2, { SwitchCase: 1 }] }, parserOptions: { parser: require.resolve('babel-eslint'), ecmaVersion: 2018, sourceType: 'module' } } ``` #### 可以自定义 rules 的规则 > rules 的规则 { 规则名:[是否关闭/规则等级,配置的值,只对部分配置] } > `indent: ['error', 2, { SwitchCase: 1 }]` 兼容 prettier,prettier 会将代码格式化成 eslint 报错的情况。 > 规则等级:0 关闭 1 警告 2 报错 ### 使用 prettier #### 配置 prettier 文件 ```js { "printWidth": 150, "singleQuote": true, "trailingComma": "none", "semi": false, "tabWidth": 2, "useTabs": false, "bracketSpacing": true, "jsxBracketSameLine": false, "arrowParens": "always", "proseWrap": "preserve", "overrides": [ { "files": ["*.json", ".eslintrc", ".tslintrc", ".prettierrc", ".tern-project"], "options": { "parser": "json", "tabWidth": 2 } }, { "files": "*.{css,sass,scss,less}", "options": { "parser": "css", "tabWidth": 2 } }, { "files": "*.ts", "options": { "parser": "typescript" } }, { "files": "*.vue", "options": { "parser": "vue" } }, { "files": "*.md", "options": { "parser": "markdown" } } ] } ``` #### 开启 vscode 自动格式化 ``` { // prettier "prettier.singleQuote": true, "prettier.semi": false, "prettier.tabWidth": 2, "[javascript]": { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode" } } ``` ## 如何提升编码效率 ### 原理与解决方案 我主要从 3 个方面来做一些编码效率上的改进 - 升级你的 vue-cli 减少 webpack 配置的成本 - 使用 sass,利用里面函数、mixins、变量提升 css 文件的复用 - 使用 pug,减少 html 的代码编写量 #### 实践 > `vue-cli3+、vue-cli4+` 相比于 `vue-cli2+` 最大的改变就是将约定俗称的配置,全部公共化了,也就是做了一次二次封装。这样的好处在于,我们不必要在繁多的配置代码中寻找需要的配置。 简单新建一个配置入口就能操作我们大多数想要的功能。在 `root` 目录下新建一个 `vue.config.js` 文件,作为我们 `webpack` 的配置文件。 **初始化 vue 配置** ``` const autoprefixer = require('autoprefixer') module.exports = { publicPath: process.env === 'production' ? '' : '/', outputDir: 'dist', assetsDir: 'static', filenameHashing: true, lintOnSave: true, runtimeCompiler: false, transpileDependencies: [/\/node_modules\/vue-echarts\//, /\/node_modules\/resize-detector\//], productionSourceMap: false } ``` 简单的配置完成后,我们引入一个 `sass` 工具用于编写 `sass`文件 > 用法见 sass 参考资料! ### 使用 Sass #### 安装与使用 ```sh yarn add -D sass sass-loader ``` ### 如何处理样式 在 `assets` 目录中建立一个 styles 文件专门来存放样式文件,新增入口`index.scss`文件,便于 JavaScript 引入,增加 utils.scss、reset.scss、varibles 文件。 > 这些样式工具都是为了提升我们 `scss` 开发效率,具有畅快的开发体验! #### 使用 varibles 变量文件 为了提升我们代码的可读性,复用性。使用 `sass` 变量必不可少。 还有一点就是利于全局修改样式,如果需要更换皮肤这个功能,我们只需要更改全局的主题色,即可更换主题,那样更加方便。 ```scss // 主题色 $color-red: #ff3333; $color-purple: #ff33a9; $color-orange: #ff8833; $color-blue: #3377ff; // 文字色 $color-black: #000; $color-dark: #333; $color-deep: #555; $color-pl: #999999; $color-weak: #B3B3B3; $color-white: #fff; // 背景色 $bg-bar: #F9F9F9; $bg-page: #F3F3F3; $bg-page-light: #F9F9F9; ``` 使用变量之后,sass 文件不会直接生效,至少在 vue 文件 里面是访问不到的。 需要在 `vue.config.js` 里面增加如下配置。 ```js module.exports = { // ... css: { sourceMap: true, loaderOptions: { sass: { prependData: ` @import "@/assets/styles/variable.scss"; ` } } } } ``` #### 覆盖默认样式 常规操作, 引入 reset.scss 将默认样式覆盖掉 ```scss /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 License: none (public domain) */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } /* HTML5 display-role reset for older browsers */ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } body { line-height: 1; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } table { border-collapse: collapse; border-spacing: 0; } html, body { width: 100%; height: 100%; overflow: auto; margin: 0; scroll-behavior: smooth; -webkit-overflow-scrolling: touch; } ``` #### 使用样式工具集 有时候我们发现,光是引入变量还不够,变量工具只能允许我们在 css 类文件中使用。假如我想着模版中直接使用样式,有没有更快的方案呢? 当然有的,我们可以自定义一个常用的样式工具集。设置一些背景颜色、字体颜色、盒子模型中的常规操作。 > 要是有设计规范更好哦,我也是常常向设计师提出要求,一定要制定出一套产品的设计规范。 ```scss // utils 工具 // 颜色 .bg-red {background-color: $color-red!important;} .bg-purple {background-color: $color-purple!important;} .bg-orange {background-color: $color-orange!important;} .bg-blue {background-color: $color-blue!important;} .color-red {color: $color-red!important;} .color-purple {color: $color-purple!important;} .color-orange {color: $color-orange!important;} .color-blue {color: $color-blue!important;} .text-black {color: #000;} .text-dark {color: #333;} .text-deep {color: #555;} .text-weak {color: #B3B3B3;} .text-white {color: #fff;} // 字体 .f10 {font-size: 10px;} .f12 {font-size: 12px;} .f14 {font-size: 14px;} .f15 {font-size: 15px;} .f17 {font-size: 17px;} .f20 {font-size: 20px;} .f24 {font-size: 24px;} // 文字对齐 .tl {text-align: left;} .tc {text-align: center;} .tr {text-align: right;} // 浮动与清除浮动 .fl {float: left;} .fr {float: right;} .fix {*zoom: 1;} .fix:after{display:table; content:''; clear:both;} // 显示 .dn{display:none;} .di{display:inline;} .db{display:block;} .dib{display:inline-block;} .dt{display:table;} div.dib{*display:inline; *zoom:1;} .vm {vertical-align: middle;} .vib {display:inline-block; vertical-align: middle;} // 定位 .pr {position: relative;} .pa {position: absolute;} .pf {position: fixed;} // 盒子模型 .ml4 {margin-left: 4px;} .mr4 {margin-right: 4px;} .mt4 {margin-top: 4px;} .mb4 {margin-bottom: 4px;} .ml8 {margin-left: 8px;} .mr8 {margin-right: 8px;} .mt8 {margin-top: 8px;} .mb8 {margin-bottom: 8px;} .ml12 {margin-left: 12px;} .mr12 {margin-right: 12px;} .mt12 {margin-top: 12px;} .mb12 {margin-bottom: 12px;} .ml16 {margin-left: 16px;} .mr16 {margin-right: 16px;} .mt16 {margin-top: 16px;} .mb16 {margin-bottom: 16px;} .ml20 {margin-left: 20px;} .mr20 {margin-right: 20px;} .mt20 {margin-top: 20px;} .mb20 {margin-bottom: 20px;} .ml24 {margin-left: 24px;} .mr24 {margin-right: 24px;} .mt24 {margin-top: 24px;} .mb24 {margin-bottom: 24px;} .ml10 {margin-left: 10px;} .mr10 {margin-right: 10px;} .mt10 {margin-top: 10px;} .mb10 {margin-bottom: 10px;} .ml15 {margin-left: 15px;} .mr15 {margin-right: 15px;} .mt15 {margin-top: 15px;} .mb15 {margin-bottom: 15px;} // 按钮禁用 .disabled{outline:0 none; cursor:default!important; opacity:.4; filter:alpha(opacity=40); -ms-pointer-events:none; pointer-events:none;} ``` #### 增加样式入口文件 最后一步,新建一个入口文件,将样式工具类全部导入进来,供主程序引入。 ```scss // index.scss 文件 import './reset.scss'; import './varibles.scss'; improt './utils/scss'; ``` 在 `main.js` 中直接引入 `index.scss` ```js import '@/assets/styles/index.scss' ``` ### vue 中写样式要注意哪些方面,有哪些技巧呢? #### 避免全局污染 在页面中写 `css/scss` 加上 `scoped`,`scoped` 的功能就是使页面的样式是局部的,不让影响其他页面的样式。 #### bem 规范 我们大多数人时候会遇到问题,**样式嵌套太多了怎么命名** > BEM是块(block)、元素(element)、修饰符(modifier)的简写,由 Yandex 团队提出的一种前端 CSS 命名方法论。 名字太长易读性太差 ```scss .cardbox { .cardbox-card { .cardbox-card-wrapper .cardbox-card-wrapper-header { .cardbox-card-wrapper-header-title { // ... } } .cardbox-card-wrapper-body{ .cardbox-card-item { .cardbox-card-item-title { // ... } } } } } } ``` #### bem 使用方式 `block-name__element-name--color` - 区分块,子元素,修饰元素 - 块,页面中独立的单元 - 子元素,块里面的儿子 `card__item` 使用 `__` 连接 - 子元素长命名使用 - 连接 - 修饰(易变的)`card__item--warning` 使用 `--` 我们使用 bem 改造样式 ```scss .cardbox { &__header { &__title { //... } } &__body { &__item { &__title { //... } } } } ``` > bem 一般推荐子元素嵌套尽量在2-3层以内 但是我们发现样式子元素嵌套有点多,使用了两重子元素嵌套。 大致原理是**尝试分离父子元素的关系,把卡片本身当作一个块看待。** 下面来试着去减少嵌套: ```scss .cardbox { &__header { &__title { //... } } &__body { .card { &__title { //... } } } } ``` 现在编写样式效率提高也更加规范了,那么编写 HTML 也是有很多累赘的代码。 比如大多数标签都是前开后闭的。通过 pug 我们可以省略很多字符的敲打,下面我们谈谈如何使用 pug 编写模版。 > 当然喜欢哪种 HTML 编写风格见人见智啦,我自己更加倾向 pug,那种缩进和简洁的表达,有种在写 scss 的感觉。 ### 如何使用 pug #### 类似 sass,首先安装 pug 和 pug 的 loader ``` yarn add -D pug pug-html-loader pug-plain-loader ``` #### 完成配置 ```js module.exports = { // ... chainWebpack: (config) => { config.module .rule('pug') .test(/\.pug$/) .use('pug-html-loader') .loader('pug-html-loader') .end() } } ``` #### 编写 pug 代码 使用 scss 工具与 pug 完美搭配,少写很多代码 ```html // 登陆 ``` 我们已经引入了样式,接下来我将谈谈其他资源的引入 ## 如何管理你的资源 ### 原理与解决方案 我暂时把资源分为下面几种 - 字体 - ICON - 图片 - 样式 ![](https://user-gold-cdn.xitu.io/2019/12/30/16f55578916de772) 把他们各自新建一个目录,都放在 assets 目录下面分门别类,供其他地方调用。 使用 alias 更好重命名,使之更便捷的访问到。 增加 `vue.config.js` 配置 ,设置`assets`别名 ```js const path = require('path') function resolve(dir) { return path.join(__dirname, dir) } module.exports = { //... chainWebpack: (config) => { config.resolve.alias.set('@', resolve('src')).set('@assets', resolve('src/assets')) } } ``` ### ICON #### 引入 iconfont 1. [iconfont](https://www.iconfont.cn/manage/index) 阿里图标项目中下载,将整个项目图标包一起下载下来 ![](https://user-gold-cdn.xitu.io/2019/12/27/16f462a5119bdcdf?w=2000&h=996&f=jpeg&s=179805) 2. 引入 iconfont 样式 需要下面四个文件 - `iconfont.eot` - `iconfont.ttf` - `iconfont.woff` - `iconfont.woff2` 3. 项目中引入 iconfont 让 `icon` 组件化 ```html ``` #### 引入图片作为 ICON 让图片组件化,我们再来写一个 img 组件 ``` ``` ## 如何管理你的路由 ### 原理与解决方案 使用 vue-router,使用`import()` 生成异步路由,只有在访问时候才会加载模块。 为什么使用 `import()` 会异步加载模块? > MDN:在您希望按照一定的条件或者按需加载模块的时候,动态import() 是非常有用的。而静态型的 import 是初始化加载依赖项的最优选择,使用静态 import 更容易从代码静态分析工具和 tree shaking 中受益。 说白了就是起到一个**按需加载**的目的。现在大多数实现的按需加载,基本都是依赖 `import()` 这个方法。 #### 安装 vue-router ```sh yarn add vue-router ``` 安装完 `router`,在编写 `router` 先创建页面 #### 新建一个空页面 src 目录下新增 views 目录存放页面文件。创建 index 目录和 home 页面 ```html ``` #### 编写路由 ```js const routes = [ { // 首页 path: '/', name: 'index', redirect: '/home', component: App, children: [ { // 首页 path: 'home', name: 'home', // 路由懒加载 component: () => import( /* webpackChunkName: "index" */ '../views/index/home.vue' ) } ] } ] Vue.use(VueRouter) const router = new VueRouter({ mode: 'history', routes: routes, base: process.env.BASE_URL, props: true }) export default router ``` #### 为了消除 # 显得路径更加好看简洁,我们采用 history 模式,但是 history 模式有个问题就是,异步路由没有缓存在页面中,第一次进入页面会找不到 在 vue.config.js 中增加配置,开发环境可以访问到,恢复正常 ```js module.exports = { // ... devServer: { historyApiFallback: true } } ``` > 关于路由还有很多可以研究到地方,可以自行研究哦! ## 组件化开发 ### 原理与解决方案 一般来说,我们根据组件的复用度,分给基础(公共)组件和业务组件。 为了节省时间,快速开发,这里基础组件大部分引用开源组件。当然不能直接就用哦。 一般要进行二次封装,也就是高阶组件开发。 1. 通过修改和覆盖当前组件的样式来达到修改样式的作用。 2. 通过拦截事件来更改js的逻辑。 下面我们先引入 `vant` 组件 ### 实践 #### 引入 vant ```sh yarn add vant ``` ### 对基础组件进行二次封装和改造 下面 7 步来写好一个公共组件 1. 新建一个 `components` 目录来存放基础组件 2. 基础组件命名为 `app-xxx` 或 `appXxx`,新建一个 `app-button` 目录,新建 `index.vue` 3. 根据设计稿设计和编写组件 > 编写组件之前首先要设计组件,根据组件的不变性和可变性原则编写。不变性是组件的核心,可变性根据参数对组件对相关部分进行调节,实现可选择的功能。 4. 实现组件 ```html ``` > ::v-deep 样式深覆盖,scoped 情况下覆盖组件样式,不改变其样式 5. 写好基础组件 README,为什么要写文档呢?如果多人开发同一个项目,基础组件会被其他人引用。方便其他人使用,所以要写文档。 > 一句话言:只要可能被其他人用的公共方法和组件,注释或文档是很重要的,对自己的代码负责哈。 其他用法参照 vant 6. 全局引用,基础组件许多页面都会用到,将其设置成全局组件,其他地方就不必再引用了哦。 新建一个文件 `global` 存放全局组件注册,在 `main.js` 引入 ```js import Vue from 'vue' import appButton from '@/components/app-button' Vue.component('app-button', appButton) ``` 7. 写好 `demo`,即使暂时不写单元测试,也要写好一个 `demo`,使之能正常的运行 添加 demo 页面和路由 ```html ``` #### 实现效果 ![](https://user-gold-cdn.xitu.io/2019/12/30/16f55700de463c65?w=1836&h=1156&f=jpeg&s=190534) ## 如何封装请求 ### 原理与解决方案 基本上就是对 axios 的封装,封装主要有两个目的。 - 修改一些基础的配置:请求地址,超时,其他的杂七杂八的 - 统一操作:统一处理错误,统一处理请求参数和格式,响应参数和格式。统一处理 message,统一拦截挂载等等。 网上已经有很多类似的文章了, 我这里给出我常用的封装方案。 ### 实践 #### 根据不同环境设置请求地址 ```js // .env-default.js 文件 // 不同环境访问不同的路径 const api = { develop: 'http://xxxx:8080', mock: 'http://xxxx', feature: 'http://xxxx', test: 'http://xxxx', production: 'http://xxxx' } export const baseURL = api[process.env.NODE_ENV || 'dev'] ``` > 因为每个人开发环境,mock环境不一定相同,这个文件建议 gitignore忽略掉。模版可以写在 readme 文档中,启动项目时加入文件。 #### 新建一个 `utils` 工具 我们现在将 axios 封装成我们自己需要的配置,然后定义四个常用的请求方法供调用 ```js // utils/http.js 文件 import axios from 'axios' import { baseURL } from '../../.env-defalut.js' // axios 配置 const defaultBaseUrl = 'http://localhost:8080/' // 默认超时时间 axios.defaults.timeout = 15000 // 数据接口域名统一配置.env axios.defaults.baseURL = baseURL || defaultBaseUrl // http request 拦截器 axios.interceptors.request.use( (config) => { config.headers = { } return config }, (err) => { return Promise.reject(err) } ) // http response 拦截器 axios.interceptors.response.use( (response) => { return response }, (error) => { const data = error.response.data return Promise.reject(data || error) } ) export default axios /** * fetch 请求方法 * @param {*} url * @param {*} params */ export function fetch(url, params = {}) { return new Promise((resolve, reject) => { axios .get(url, { params: params }) .then((response) => { resolve(response.data) }) .catch((err) => { reject(err) }) }) } /** * post 请求方法,发送数据格式 json * @param {*} url * @param {*} data */ export function post( url, data = {}, config = { transformRequest: [ function(fData, headers) { headers['Content-Type'] = 'application/json' return JSON.stringify(fData) } ] } ) { return new Promise((resolve, reject) => { axios.post(url, data, config).then( (response) => { resolve(response.data) }, (err) => { reject(err) } ) }) } /** * patch 请求方法,发送数据格式 json * @param {*} url * @param {*} data */ export function patch(url, data = {}) { return new Promise((resolve, reject) => { axios .patch(url, data, { transformRequest: [ function(fData, headers) { headers['Content-Type'] = 'application/json' return JSON.stringify(fData) } ] }) .then( (response) => { resolve(response.data) }, (err) => { reject(err) } ) }) } export function del(url, data) { return new Promise((resolve, reject) => { axios.delete(url, { data }).then( (response) => { resolve(response.data) }, (err) => { reject(err) } ) }) } ``` ## 如何管理 api ### 原理 首先要制定一个 api 的原则 我的原则一般是这些: - 干净纯粹 - 尽量不要处理数据 - 独立单一不要互相依赖 好处在于:不在 api 里面处理数据,api里面的接口和接口文档上一样。避免别人引用我的api,还要去看代码,只需要看文档就好了。 > 例子:想象这样一种情况,别人引用了我的 api,突然发现响应数据不对。首先它排查到页面数据没更改。看了api文档,数据也没问题,最后发现我在写 api 的时候进行了处理,这个 api 呢又不能改动,改了影响我自己的模块。只能它在重新写一个api,这样显得很繁杂了,不够干净优雅。 ```js import { fetch, post } from '@/utils/http' // 用户登陆 export const login = data => post('/user/login', data) // 获取用户信息 export const getUserInfo = (data) => fetch('/api/user/info', data) ``` 如果需要处理数据,要么使用一个中间工具处理,要么在页面里面处理。当然还是实际问题实际分析。 ## 如何使用`mock`模拟数据 ### 原理与解决方案 一般就是两种方案,一是模拟后端,使用远程在线 JSON 服务器。另外一种搭建本地 JSON 或者 使用现成的 Node 服务器拦截请求。 > 这两种方式各有千秋,没有优劣之分,适合就是最好的。 ### 远程在线`mock` 我用过的远程在线`mock` - apizza:好用,功能齐全,喜欢他的文件展开目录`api`,免费版只支持 2 个人共同编辑 - swagger:开源免费,`api`管理太凌乱, - rap/rap2:开源免费,可以搭建本地`api`,需要自己搭建 使用远程`mock`的优点: - 不需要在项目内部增加`mock` - 功能更加全面完善 - 可以在接口文档基础上`mock`,与接口文档放在一起查看更加方便。 缺点:需要自己另外搭建服务器,只支持静态的`mock`,不能与单元测试结合使用 ### 本地JSON mock - 使用 `webpack` 内部 mock 配置 ```js devServer: { // 接口未实现情况下,使用mock before: require('./mock') } ``` 基本原理:主要是使用 node 读取文件,转换成 JSON 格式,使用`mock.js` 模拟数据,最后 webpack 拦截请求生成`json`响应数据 ```js const Mock = require('mockjs') module.exports = (app) => { function getJsonFile (filePath) { var json = fs.readFileSync(path.resolve(__dirname, filePath), 'utf-8') return JSON.parse(json) }, const returnMock = (datafile, res, req) => { setTimeout(() => { var json if (/\.json$/.test(datafile)) { // json文件暴露的是mock的模板 json = getJsonFile(datafile) } else if (/\.js$/.test(datafile)) { json = require(datafile)(req.query) } res.json(Mock.mock(json)) }, 500) } } ``` - 使用 `json-server` 搭建 主要分为下面几步 1. `npm` 安装 `json-server` 2. 编写 `npm` 脚本命令,引入 `mock` 配置文件 3. 编写 `mock` 路由匹配规则 > 比较简单这里不详细描述了! 本地的缺点在于需要 - 前端需要根据`api`文档写`mock`数据格式 - 功能没有远程`mock`那么完善,支持`restful`需要去研究下 - 也是需要配置相关`mock`工具 优点在于 - 不用查看编辑`api`文档 - 在代码中就可以更改和查看`mock`数据 - 支持使用`JavaScipt`动态处` mock`,可以与单元测试结合使用 # 总结 本篇文章耗费作者一个多星期的业余时间,存手工敲打 6000+字,同时收集,整理之前很多技巧和边写作边**思考**和**总结**。如果能对你有帮助,便是它最大的价值。都看到这里还不**点赞**,太过不去啦!😄 由于技术水平有限,文章中如有错误地方,请在评论区指出,感谢! 文中大多数代码将在[suo-design-pro]( https://github.com/suoyuesmile/suo-design-pro) 中更新 > 项目有时间会尽量完善 写实践总结性文章真的很耗费时间。如何文章中有帮到你的地方**分享下**呗,让更多人看到! # 下节内容预告 - **如何编写原生组件,以及组件编写的思考与原则?** - **如何使用vuex 以及它的应用场景和原理** - **如何使用过滤器,编写自己的过滤器** - **如何使用 Jest 测试你的代码?TDD 与 BDD 的比较** - **回顾 vue 的生命周期,他们都使用哪些场景?** - **使用 mixins 与 组件的区别,如何充分的复用代码?** - **vue 技术栈架构设计上的思考,如何编写自己的组件库?** - **vue ssr 原理及其应用** # 参考资料 - [commitizen](https://github.com/commitizen/cz-cli) - [MDN import()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/import) - [vant 文档](https://youzan.github.io/vant/#/zh-CN/intro) - [eslint 文档](https://eslint.org/) - [vue-router 文档](https://router.vuejs.org/zh/) - [sass 文档](https://www.sasscss.com/getting-started/) - [axios 文档](https://github.com/axios/axios) # 开源项目 上述功能配置,均**将**在 [suo-design-pro](https://github.com/suoyuesmile/suo-design-pro) 中实现,希望能持续关注! ================================================ FILE: booknotes/bst.md ================================================ # 二叉搜索树 ### 概述 - 循关键码访问call by key: 关键码之间可以比较,比对 - 词条entity: key - value - 比较器:重载操纵符实现 - 判等器:重载操纵符实现 - Binary Search Tree: 节点 ~ 词条 ~ 关键码, 处处满足顺序性 - 顺序性:任意节点均不小于左后代,不大于右后代 - 单调性:中序遍历,必然单调非降,充要性 - 宏微观:微观满足顺序性,宏观满足单调性 ``` template class BST: public public BinTree { public: //二叉树派生 virtual BinNodePosi(T) & search( const T &) ; //查找 virtual BinNodePosi(T) insert( const T &) ; //插入 virtual bool remove( const T &) ; //删除 protected: BinNodePosi(T) _hot; //命中节点的父亲 BinNodePosi(T) connect34(BinNodePosi(T), BinNodePosi(T), //3+4重构 BinNodePosi(T), BinNodePosi(T), BinNodePosi(T), BinNodePosi(T), BinNodePosi(T)); BinNodePosi(T) rotateAt( BinNodePosi(T) ); //旋转 } ``` ### BST : 查找、插入、删除、平衡 #### 查找 - 策略:减而治之,仿照二分查找策略 ``` template BinNodePosi(T) & BST::search(const T & e) { return searchIn( _root, e, _hot = NULL) ; } //典型的尾递归,当前树根目标关键码,记忆热点 static BinNodePosi(T) & searchIn(BinNodePosi(T) & v, const T & e, BinNodePosi(T) & hot ) { if( !v || (e == v->data) ) //确定失败,成功,或者 return v; hot = v; //记下当前节点,然后。。 return searchIn( ( (e < v->data ) ? v->lchild : v->rchild ) , e, hot); } //运行时间正比于返回节点的深度 ``` - 接口语义:返回值的引用值 - - 成功时,指向一个关键码为e且真实存在的节点, 失败时,指向试图转向的空节点NULL - - 增加哨兵,失败时,将此空节点转换为一个关键码为e且真实存在的节点 #### 插入 - 策略:在查找的基础上替换失败的空节点 ``` //BST插入 template BinNodePosi(T) BST:: insert(const T & e) { BinNodePosi(T) & x = search( e ); //查找目标 if( !x ) { //禁止雷同,失败时才插入操作 x = new BinNode(e, _hot); //创建新节点以hot为父亲 _size++; updataHeightAbove(x); //更新全树规模,并更新历代祖先规模 } return x; //无论e是否存在原树中,总有x->data == e } //总体复杂度O(h) ``` #### 删除 - 策略:先确认目标再删除 ``` template bool BST:: remove( const T & e) { BinNodePosi(T) & x = search( e ); //定位目标 if(!x) return false; //确认目标存在 removeAt(x , _hot); //分两大类实施 删除 _size--; //更新规模 updataHeightAbove( _hot ); return true; } //复杂度O(h) ``` - 情况一 ``` template static BinNodePosi(T) removeAt(BinNodePosi(T) & x, BinNodePosi(T) & hot){ BinNodePosi(T) w = x; //实际被摘除的节点 BinNodePosi(T) succ = NULL; //实际被删除的节点的接替者 if( ! HasLchild(*x) ) succ = x = x->rchild; //左子树为空 else if( ! HasRchild(*x) ) succ = x = x->lchild; //右子树为空 else { //左右并存的状况 hot = w->parent; if( succ ) succ->parent = hot; release( w->data ); //释放被摘除的节点 release( w ); return succ; 返回接替者 } } ``` - 情况二 ``` template static BinNodePosi(T) removeAt( BinNodePosi(T) &x, BinNodePosi(T) & hot ) { BinNodePosi(T) w = x; //实际被摘除的节点 BinNodePosi(T) succ = NULL; //实际被删除的节点的接替者 if( ! HasLchild(*x) ) succ = x = x->rchild; //左子树为空 else if( ! HasRchild(*x) ) succ = x = x->lchild; //右子树为空 else { w = w->succ; swap( x->data, w->data); BinNodePosi(T) u = w->parent; ( u == x ? u->rChild : u->lChild ) = succ = w->rChild; }//O(h) ``` #### 平衡与等价 > BST的查找,插入,删除复杂度都为O(h),但是高度不能很好控制,效率并不理想 - 生成BST:随机生成的高度为O(logn),有重复的组合,随机组合的BST生成的O(n^1/2) - 理想平衡:节点数固定,兄弟子树高度越接近(平衡),全树倾向更低 - 由n个节点组成的二叉树,高度不低于logn时-----恰为logn为理想平衡树,概率低,适当降低标准 - 退一步海阔天空:高度渐进不超过O(logn) - 适度平衡的二叉树,称平衡二叉树BBST - 非平衡二叉树等价平衡二叉树 - 中序遍历的歧义性:拓扑结构不同,中序遍历相同 - 等价BST:3个规律,上下可变,左右不能乱,旋转变换 - zig变换(旋转调整) - 准则:局部性(常数节点数),操作数至多O(logn) ### AVL : 重平衡、插入、删除、重构 - 平衡因子:balFac(V) = height( lc(v) ) - height( rc(v) ) - G.Adelson-Velsky & E.Landis (1962) 所有 | balFac | <= 1 - AVL = 适度平衡:高度为h的AVL树,至少包含S(h) = fib(h+3) -1个节点 - 接口: ``` #define Balance(x) ( stature( (x).lChild ) == stature( (x).rChild ) ) #define BalFac(x) ( stature( (x).lChild ) - stature( (x).rChild ) ) #define AvlBalanced(x) ( ( -2 < BalFac(x) ) && ( BalFac(x) < 2 ) ) template class AVL: public BST { public: BinNodePosi(T) insert( const T &); //插入重写 bool remove( const T &); //删除重写 } ``` - 插入节点会导致祖先发生失衡,删除后只有一个节点失衡,相反插入操作更简单 - 插入:单旋 ,g经过单旋后复衡,子树高度复原,更高祖先也必平衡,全树复衡 - 时间:旋转O(1) 一致向右zagzag,一致向左zigzig,双旋,zigzag和zagzig情况 ``` //插入 template BinNodePosi(T) AVL::insert( const T & e) { BinNodePosi(T) & x = search( e ); if( x ) return x; x = new BinNode( e, _hot ); _size++; BinNodePosi(T) xx = x; for ( BinNodePosi(T) g = x->parenr; g; g = g->parent ) if ( !AvlBalanced( *g ) ) { FromParentIo( *g ) = rotateAt( tallerChild( tallerChild(g) ) ); break; }else updateHeight( g ); return xx; } ``` - 删除 ================================================ FILE: booknotes/compute.md ================================================ # 算法分析 ### 计算 *Dijkstra名言:计算机科学,就是计算的科学* - 绳索计算机和算法:古埃及人的算法,线段垂直 - 尺规计算机和算法:线段三等分 - **总结:计算 = 信息处理, 借助某种工具,尊尊某种规则** > 算法:特定计算模型下,解决问题的指令序列 1. 输入:待处理的信息 2. 输出:经处理的信息 3. 正确性:的确可以解决指定的问题 4. 确定性:基本操作组成的序列 5. 可行性:每个操作都可以实现,在常数时间内完成 6. 有穷性:如何输入,有穷次操作可以,得到输出结果 - 可行性:所有操作都可以兑现,例子3步把大象装到冰箱 - 有穷性:Hailstone(n)算法 ``` int hailstone(int n) { int length = 1; while(1 < n){ n%2==0 ? n/=2 : n=3*n+1; length++; } } ``` **结论:所有的n是否都可以有穷的步骤,还没有结论** > 程序 != 算法 ### 计算模型 *凯文名言:如果你需要改进某种东西,你首先的学会如何测量它* - 算法分析两个主要方面:正确性,成本 - 成本:时间成本,空间成本 - 怎么衡量时间成本:特定算法+不同示例 - 稳妥起见:关注最坏情况 - 同一问题多种算法,评价其优劣:实验统计不足够 - 图灵机模型 - - Tape(带):均匀划分单元格,各注一字符,默认为'#' - - Alphabet:字符种类有限 - - Head:总是对准某一单元格,并可以读取修改其中的字符, 每经过一个节拍,可转向左侧或右侧 - - State TM:有限机状态 - - Transition Function:(q, c, d, L/R, p) 若当前状态为q,字符为c,将当前字符改写为d,转向左侧/右侧;转入p状态,一旦转入h停机 功能:二进制非负整数加一,全1的后缀转为0,原低位的0翻转为1 - RAM模型:寄存器顺序编号,总数没有限制 **总结:图灵机,RAM模型为度量算法性能提供了准确的尺度** ### 大O记号 *陶渊明名言:好读书不求甚解(更多的看重长远,主流)* - 渐进分析: 考虑n >> 2, 对规模为n的输入,需执行的基本操作次数,存储单元数 - 大O记号(big-O notation):**T(n) = O( f(n) )** <= **存在c > 0, n >> ,有 T(n) < c * f(n)** - 常系数可忽略: O( c * f(n) )= O ( f(n) ) - 低次项可忽略: O ( n^a + n^b ) = O( n^a ) , a > b - 其他记号:最好,平均情况 - 常数O(1):2 = 2013 = 2013^2013 = O(1),不含转向 - 对数O(logn):**非常高效,无限接近与常数** - - 常底数无所谓 所有 a, b > 0, log(a) n = log(a) b * log(b)n = O( log(b) n ) - - 常数次幂无所谓 - - 对数多项式 - 多项式(O(n ^c)):**直接往高处化,通常认为令人满意了** - - 线性(O(n)) - - 从O(n)~ O(n^2):编程题主要覆盖的范围 - - 幂 - 指数(a ^n):计算成本增长极快, 和多项式之间有个分水岭(有效算法到无效算法) ``` 问题:2-Subset S包含n个正整数,存在S = 2m 是否有子集T,满足存在 T = m? 美国大选说事 ``` **不存在可在多项式时间内解决该问题** ### 算法分析 *夸赞欧拉:像欧拉一样像呼吸一样自如* - 主要任务:正确性+复杂度 - C++基本指令:等价于RAM的基本指令,二者相当 - - 分支转向:goto //出于结构化被隐藏了 - - 迭代循环:for()、while()、…… //本质上就是if + goto - - 调用加递归 //本质上也是goto - 分析方法:迭代(级数求和)、递归(递归跟踪+递推方程)、猜测 - 级数: - - 算数级数(与末项平方同阶):1 + 2 + …… + n = n (n+1) /2 = O(n^2) - - 幂级数(比末项高出一阶):1^C + 2^C + …… n^C = O( n^(C+1) ) - - 几何级数(与末项同阶):a0 + a^1 + …… a^n = O(a^n) - - 收敛级数: O(1) - - 调和级数:1 + 1/2 + …… 1/n = O(logn) - - 对数级数:log1 + log2 + …… + logn = log(n!) = O(nlogn) - 循环与级数: - - 二重循环复杂度:O(n^2) ``` for(int i=0 ; i 估算:1天多少秒? **1天 = 24hr * 60min * 60sec = 25 * 4000 = 100000 sec** ### 迭代与递归 **凡治众如治寡,分数是也** - 例子求和 ``` int SumI(int A[], int n){ int sum = 0; //O(1) for (int i = 0; i < n; ++i) { sum += A[i]; //O(1) } return sum; //O(1) } // 时间复杂度:T(n) = O(n) // 空间复杂度:O(1) ``` - 减而治之: > 求解一个大规模的问题,划分成两个子问题:其一平凡,其二规模缩减(单调性) ``` int SumJ(int A[], int n){ return (n < 1) ? 0 : SumJ(A, n-1) + A[n+1] ; } //递归 递归跟踪:T(n) = O(1)*(n+1) = O(n) 递推方程:T(n) = T(n-1) + O(1) T(0) = O(1) ==> T(n) = O(n) ``` - 例子:数组倒置 ``` void reverse(int * Am int lo, int hi); //递归版 if(lo < hi) { swap(A[lo], A[hi]); reverse(A, lo+1, hi-1); } ``` - 分而治之: > 求解一个大规模的问题,划分成多个子问题,规模相当,分别求解子问题 ``` int sum(int A[], int lo, int hi){ if(lo == hi) return A[lo]; int mi = (lo+hi) >> 1; return sum(A, lo, mi) + sum(A, mi + 1, hi); }//二分递归 递归跟踪:T(n) = O(1) * (2^0 + ... + 2^logn) = O(n) 递推方程:T(n) = O(1) + 2T(n/2), T(1) = O(1) T(n) = O(n); ``` - 例子:MAX2,[lo, hi) 找出最大和次大的 ``` if( A[x1 = lo] < A[x2 = lo + 1]) swap(x1, x2); for(int i = lo + 2; i < hi; i++) if(A[x2] < A[i]) if(A[x1] < A[x2 =i]) swap(x1, x2); 复杂度:最好的 n-1次比较,最坏的2n-3次比较 改进:分而治之 最坏5n/3-2 ``` ### 动态规划(DSA优化) > 运转-->正确-->快速 - 例子:fib()(递归) ``` // fib(n) = f(n-1) + f(n-2) {0, 1, 1, 2, 3, 5, 8 ...} int fib(n) { return (2 > n) ? n : fib(n-1) + fib(n-2); } // fib(43) ==> 巨大的延迟 //时间复杂度分析 //递推公式:T(n-1) + T(n-2) + 1, T(1) = T(0) = 1, S(n) = fib(n+1) = 1.68... ^n //==> O(2^n) 指数复杂度 超过100项,需要几百年 //递归跟踪:大量重复的递归实例 ``` - 例子:fib()(迭代) ``` //方法A(记忆) //制表查询 //方法B(动态规划) //颠倒计算方向,自底而上 int fib2(int n){ int f = 0, g = 1; //用2个参数存储中间指 while(0 < n--){ g = g + f; f = g - f; } return g; } //空间上只需要O(1) ``` - 例子:最长公共子序列(递归-->动态规划) ``` /* * 最长公共子序列 * 可行---->递归策略---->减而治之---->平凡情况 * 效率---->动态规划---->自底而上---->迭代策略 * 对于序列A[0,n],B[0,m], LCS(A,B)无非3种情况 * 1) n=-1或m=-1,作空序列 * 2) A[n] = 'X' = B[m] 则LCS( A[0,n), B[0,m), 'X' ) * 3) A[n] != B[m] 则 LCS( A[0,n], B[0,m) ) 与 LCS( A[0,n), B[0,m] ) 中取更长者(分而治之) * 采用倒推式方式求公共子序列,用二维数组存储中间值 * */ //递归 #include #include using namespace std; int LCS(string, int, string, int); int LCS2(string, int, string, int); int main(void){ string a, b; cin >> a >> b; cout << LCS(a, a.length()-1, b, b.length()-1) << endl; // cout << a << b << endl; return 0; } //递归 int LCS(string a, int m, string b, int n){ if(m == -1 || n == -1) return 0; else if(a[m] == b[n]) return LCS(a, m-1, b, n-1) + 1; else return LCS(a, m, b, n-1) > LCS(a, m-1, b, n) ? LCS(a, m, b, n-1) : LCS(a, m-1, b, n); } //动态规划 int LCS(string a, int m, string b, int n){ int arr[m][n] = {0}; //用数组存储中间值 if(a[0] == a[0]) } ``` ================================================ FILE: booknotes/demo/AVL.class.cpp ================================================ #define Balance(x) ( stature( (x).lChild ) == stature( (x).rChild ) ) #define BalFac(x) ( stature( (x).lChild ) - stature( (x).rChild ) ) #define AvlBalanced(x) ( ( -2 < BalFac(x) ) && ( BalFac(x) < 2 ) ) template class AVL: public BST { public: BinNodePosi(T) insert( const T &); //插入重写 bool remove( const T &); //删除重写 } //插入 template BinNodePosi(T) AVL::insert( const T & e) { BinNodePosi(T) & x = search( e ); if( x ) return x; x = new BinNode( e, _hot ); _size++; BinNodePosi(T) xx = x; for ( BinNodePosi(T) g = x->parenr; g; g = g->parent ) if ( !AvlBalanced( *g ) ) { FromParentIo( *g ) = rotateAt( tallerChild( tallerChild(g) ) ); break; }else updateHeight( g ); return xx; } ================================================ FILE: booknotes/demo/BST.class.cpp ================================================ template class BST: public public BinTree { public: //二叉树派生 virtual BinNodePosi(T) & search( const T &) ; //查找 virtual BinNodePosi(T) insert( const T &) ; //插入 virtual bool remove( const T &) ; //删除 protected: BinNodePosi(T) _hot; //命中节点的父亲 BinNodePosi(T) connect34(BinNodePosi(T), BinNodePosi(T), //3+4重构 BinNodePosi(T), BinNodePosi(T), BinNodePosi(T), BinNodePosi(T), BinNodePosi(T)); BinNodePosi(T) rotateAt( BinNodePosi(T) ); //旋转 } //BST查找 template BinNodePosi(T) & BST::search(const T & e) { return searchIn( _root, e, _hot = NULL) ; } //典型的尾递归,当前树根目标关键码,记忆热点 static BinNodePosi(T) & searchIn(BinNodePosi(T) & v, const T & e, BinNodePosi(T) & hot ) { if( !v || (e == v->data) ) //确定失败,成功,或者 return v; hot = v; //记下当前节点,然后。。 return searchIn( ( (e < v->data ) ? v->lchild : v->rchild ) , e, hot); } //运行时间正比于返回节点的深度 //BST插入 template BinNodePosi(T) BST:: insert(const T & e) { BinNodePosi(T) & x = search( e ); //查找目标 if( !x ) { //禁止雷同,失败时才插入操作 x = new BinNode(e, _hot); //创建新节点以hot为父亲 _size++; updataHeightAbove(x); //更新全树规模,并更新历代祖先规模 } return x; //无论e是否存在原树中,总有x->data == e } //BST删除 template bool BST:: remove( const T & e) { BinNodePosi(T) & x = search( e ); //定位目标 if(!x) return false; //确认目标存在 removeAt(x , _hot); //分两大类实施 删除 _size--; //更新规模 updataHeightAbove( _hot ); return true; } //复杂度O(n) //情况一 template static BinNodePosi(T) removeAt(BinNodePosi(T) & x, BinNodePosi(T) & hot){ BinNodePosi(T) w = x; //实际被摘除的节点 BinNodePosi(T) succ = NULL; //实际被删除的节点的接替者 if( ! HasLchild(*x) ) succ = x = x->rchild; //左子树为空 else if( ! HasRchild(*x) ) succ = x = x->lchild; //右子树为空 else { //左右并存的状况 hot = w->parent; if( succ ) succ->parent = hot; release( w->data ); //释放被摘除的节点 release( w ); return succ; //返回接替者 } } //化繁为简 template static BinNodePosi(T) removeAt( BinNodePosi(T) &x, BinNodePosi(T) & hot ) { BinNodePosi(T) w = x; //实际被摘除的节点 BinNodePosi(T) succ = NULL; //实际被删除的节点的接替者 if( ! HasLchild(*x) ) succ = x = x->rchild; //左子树为空 else if( ! HasRchild(*x) ) succ = x = x->lchild; //右子树为空 else { w = w->succ; swap( x->data, w->data); BinNodePosi(T) u = w->parent; ( u == x ? u->rChild : u->lChild ) = succ = w->rChild; } } //O(h) ================================================ FILE: booknotes/demo/BTNode.h ================================================ template struct BTNode { BTNodePosi(T) parent; //父 Vector key; //数值向量 Vector< BTNodePosi(T) > child; //孩子向量 BTNode() { parent = NULL; child.insert(0, NULL); } BTNode( T e, BTNodePosi(T) lc = NULL, BTNodePosi(T) rc = NULL) { parent = NULL; //根节点 key.insert( 0, e ); //仅一个关键码,以及两个孩子 child.insert( 0, lc ); child.insert( 1, rc ); if( lc ) lc->parent = this; if( rc ) rc->parent = this; } } ================================================ FILE: booknotes/demo/BTree.class.cpp ================================================ ================================================ FILE: booknotes/demo/BinNode.h ================================================ #define BinNodePosi(T) BinNode* template struct BinNode { BinNodePosi(T) parent, lChild, rChild; //父亲孩子 T data; //数据 int height; //高度 int size(); //规模 BinNodePosi(T) insertAsLc(T const &); //插入左子 BinNodePosi(T) insertAsRc(T const &); //插入右子 BinNodePosi(T) succ(); //(中序)后继 template void travLevel( VST & ); //层次遍历 template void travIn( VST & ); //中序遍历 template void travPost( VST & ); //后序遍历 } //O(1) //插入左子 template BinNodePosi(T) BinNode::insertAsLc(T const &) { return lChild = new BinNode( e, this); } //插入右子 template BinNodePosi(T) BinNode::insertAsRc(T const &) { return rChild = new BinNode( e, this); }//O(1) //规模 template int BinNode::size() { int s = 1; if (lChild) s += lChild->size(); if (rChild) s += rChild->size(); return s; }//O(n) ================================================ FILE: booknotes/demo/BinTree.class.cpp ================================================ #define stature ((p) ? (p)->height : -1) template class BinTree { protected: int _size; //规模 BinNodePosi(T) _root; //根节点 virtual int updateHeight( BinNodePosi(T) x ); void updateHeightAbout( BinNodePosi(T) x ); public: int size() const { return _size; } bool empty() const { return _root; } BinNodePosi(T) root() const { return _root; } //接入删除分离 //遍历 } //更新高度 template int BinTree::updateHeight( BinNodePosi(T) x ) { return x->height = 1 + max( stature(x->lChild), stature(x->rChild) ); } //更新祖先高度 template void BinTree::updateHeightAbout( BinNodePosi(T) x ) { while (x) { updateHeight(x); x = x->parent; } } //接入 template BinNodePosi(T) BinTree::insertAsRC( BinNodePosi(T) x, T const &e){ _size++; x->insertAsRC(e); updateHeightAbout(x); return x->rChild; } //先序遍历(递归) template void traverse( BinNodePosi(T) x, VST & visit) { if ( !x ) return; visit( x->data ); //访问根O(1) traverse( x->lChild, visit ); //访问左子树O(a) traverse( x->rChild, visit ); //访问右子树O(n-1-a) } //O(n)渐进的 //改进1(迭代) template void travPre_I1( BinNodePosi(T) x, VST & visit) { Stack S; //辅助栈 if ( x ) //根入栈 S.push(x); while ( !S.empty() ) { x = S.pop(); //出栈并访问当前节点 visit( x->data ); if( HasRChild( *x ) ) //右孩子先进后出 S.push( x->rChild ); if( HasLChild( *x ) ) //左孩子先出后进 S.push( x->lChild ); } } //无法推广 //改进2(迭代) template void travPre_I2( BinNodePosi(T) x, VST & visit ) { Stack S; //辅助栈 while (true) { //以右子树为单位,逐批访问节点 visitAlongLeftBranch(x, visit, S); if( S.empty() ) //栈空即退出 break; x = S.pop(); //弹出下一个子树的根 } //pop = push = visit = O(n) = 分摊O(1) } template static void visitAlongLeftBranch( BinNodePosi(T) x, VST & visit, Stack & S) { while (x) { visit( x->data ); S->pash( x->rChild ); //右孩子入栈 x = x->lChild; //沿左侧下行 } } //中序遍历(递归) template void traverse( BinNodePosi(T) x, VST & visit) { if ( !x ) return; traverse( x->lChild, visit ); //访问左子树O(a) visit( x->data ); //访问根O(1) traverse( x->rChild, visit ); //访问右子树O(n-1-a) } //O(n)渐进的 //中序遍历(改进) template void travPre_I2( BinNodePosi(T) x, VST & visit ) { Stack S; //辅助栈 while (true) { //以右子树为单位,逐批访问节点 goAlongLeftBranch(x, visit, S); if( S.empty() ) //栈空即退出 break; x = S.pop(); visit( x->data ); //立即访问 x = x->rChild; //转向右子树 } //pop = push = visit = O(n) = 分摊O(1) } template static void goAlongLeftBranch( BinNodePosi(T) x, VST & visit, Stack & S) { while (x) { S->pash( x->rChild ); //右孩子入栈 x = x->lChild; //沿左侧下行 } } //层次遍历 template void traverse( VST & visit) { Queue Q; //辅助栈 Q.enqueue( this ); while ( !Q.empty() ) { BinNodePosi(T) x = Q.dequeue(); //出栈并访问当前节点 visit( x->data ); if( HasLChild( *x ) ) //左孩子先进先出 Q.enqueue( x->lChild ); if( HasRChild( *x ) ) //右孩子后进后出 Q.enqueue( x->rChild ); } } ================================================ FILE: booknotes/demo/Edge.h ================================================ typedef enum { UNDETERMINED, TREE, CROSS, FORWORD, BACKWAED } EStatus; template struct Edge { Te data; //数据 int weight; //权重 EStatus status; //类型 Edge( Te const & d, int w ):data(d), weight(w), status(UNDETERMINED) {} }; ================================================ FILE: booknotes/demo/Graph.class.cpp ================================================ template class Graph { private: void reset() { for (int i = 0; i < n; ++i){ //顶点 status(i) = UNDISCOVERED; dTime(i) = fTime(i) = -1; parent(i) = -1; priority(i) = INT_MAX; for (int j = 0; j < n; j++) //边 if (exists(i, j)) status(i, j) = UNDETERMINED; } } public: }; template void Graph::BFS(int v, int &clock) { Queue Q; status(v) = DISC } ================================================ FILE: booknotes/demo/GraphMatrix.class.cpp ================================================ template class GraphMatrix : public Graph { private: Vector< Vertex > V; //顶点集 Vector< Vector< Edge* > > E; //边集 public: //构造与析构 GraphMatrix() { n = e = 0;} ~GraphMatrix() { for (int j = 0; j < n; ++j) for (int k = 0; k < n; ++k) delete E[j][k]; } //顶点操作 Tv & Vertex(int i) { return V[i].data } //... //枚举邻接顶点,逆序查找 int NextNbr(int i, int j) { while ( (-1 < j) && !exists(i, --j) ) ; return j; } int firstNbr(int i) { return NextNbr(i, n); } //顶点插入 int insert(Tv const & vertex) { for (int i = 0; i < n; ++i) E[j].insert(NULL); n++; E.insert( Vector< Edge* >( n, n, NULL) ); return V.insert( Vertex(vertex) ); } //顶点删除 Tv remove(int i) { for (int i = 0; i < n; ++i) if(exists(i, j)){ delete E[i][j]; V[j].inDegree--; } E.remove(i); n--; for (int j = 0; j < n; j++) if ( exists(j ,i) ){ delete E[j].remove(i); V[j].outDegree--; } Tv vBak = vertex(i); V.remove(i); return vBak; } //边操作 bool exists(int i, int j) { return (0 <= i) && (i < n) && (0 <= j) && (j < n) && E[i][j] != NULL; } Te & edge(int i, int j) { return E[i][j]->data; } //... //边插入 void insert( Te const& edge, int w, int i, int j) { if( exists(i, j) ) return ; //忽略已有的边 E[i][j] = new Edge(edge, w); //创建新边 e++; //更新信息 V[i].outDegree++; V[i].inDegree++; } //边删除 Te remove(int i, int j) { Te eBak = edge(i, j); delete E[i][j]; E[i][j] = NULL; e--; V[i].outDegree--; V[j].inDegree--; return eBak; } }; ================================================ FILE: booknotes/demo/Lcs.cpp ================================================ /* * 最长公共子序列 * 可行---->递归策略---->减而治之---->平凡情况 * 效率---->动态规划---->自底而上---->迭代策略 * 对于序列A[0,n],B[0,m], LCS(A,B)无非3种情况 * 1) n=-1或m=-1,作空序列 * 2) A[n] = 'X' = B[m] 则LCS( A[0,n), B[0,m), 'X' ) * 3) A[n] != B[m] 则 LCS( A[0,n], B[0,m) ) 与 LCS( A[0,n), B[0,m] ) 中取更长者(分而治之) * 采用倒推式方式求公共子序列,用二维数组存储中间值 * */ //递归 #include #include using namespace std; int LCS(string, int, string, int); int LCS2(string, int, string, int); int main(void){ string a, b; cin >> a >> b; // cout << LCS(a, a.length()-1, b, b.length()-1) << endl; cout << LCS2(a, a.length(), b, b.length()) << endl; return 0; } //递归 int LCS(string a, int m, string b, int n){ if(m == -1 || n == -1) return 0; else if(a[m] == b[n]) return LCS(a, m-1, b, n-1) + 1; else return LCS(a, m, b, n-1) > LCS(a, m-1, b, n) ? LCS(a, m, b, n-1) : LCS(a, m-1, b, n); } //动态规划 int LCS2(string a, int m, string b, int n){ int i, j, cur, pre; int arr[m+1][n+1]; for (i = 0; i <= m; ++i) arr[i][0] = 0; for (i = 0; i <= n; ++i) arr[0][i] = 0; //动态表为0,两边缘为辅助0 for (i = 1; i <= m; i++ ) { for (j = 1; j <= n; j++) { cur = ( a[i-1] != b[j-1] ? 0 : 1 ); //获取当前元素值 pre = ( arr[i-1][j] > arr[i][j-1] ? arr[i-1][j] : arr[i][j-1] ); arr[i][j] = pre + cur; cout << arr[i][j] << " "; } cout << endl; } return arr[m][n]; } /* 0 n a m e 0 0 0 0 0 0 s 0 0 0 0 0 a 0 0 1 1 1 n 0 1 1 1 1 e 0 1 1 1 2 t 0 1 1 1 2 */ ================================================ FILE: booknotes/demo/List.class.cpp ================================================ #include "ListNode.h" template class List { private: int _size; Posi(T) header; //头元素(不可见) Posi(T) trailer; //末元素(不可见) protected: //内部函数 public: //构造函数 //析构函数 //只读接口 //可写接口 //遍历接口 }; //构造函数 规模为0 template void List::init() { header = new ListNode; trailer = new ListNode; header->succ = trailer; header->pred = NULL; trailer->pred = header; trailer->succ = NULL; _size = 0; } //访问 template T List::operator[](Rank r) const { Posi(T) p = first(); while(0 < r--) p = p->succ; //顺数第r个节点 return p->data; //目标节点 } // 效率低下O(n),难以接受 //查找 template Posi(T) List::find(T const &e, int n, Posi(n) p) const { while (0 < n--) //列表逆向扫描 if (e == ( p = p->pred )->data ) return p; return NULL; } //插入 template Posi(T) List::insertBefore(Posi(T) p, T const & e) { //O(1) _size++; return p->insertAsPred(e); //e当作前驱插入 } template Posi(T) ListNode::insertAsPred(T const & e) { Posi(T) x = new ListNode(e, pred, this); //创建 pred->succ = x; //建立连接 pred = x; return x; } //基于复制的构造 template void List::copyNodes(Posi(T) p, int n) { //O(n) init(); //创建头尾节点初始化 while (n--) { //自p的n下依次作为末节点插入 insertAsLast(p->data); p = p->succ; } } //删除 template T List::remove(Posi(T) p) { //O(1) T e = p->data; //备份待删除的数值 p->pred->succ = p->succ; //跳过p p->succ->pred = p->pred; //对称 delete p; _size--; return e; //返回数值 } //析构 template List::~List() { clear(); //清空列表 delete header; //释放头 delete trailer; //释放尾 } template int List::clear() { int oldSize = _size; while(0 < _size) remove(header->succ); //反复删除首节点 return oldSize; } //O(n) //无序向量唯一化 template int List::deduplicate() { if (_size < 2) //平凡列表自然无重复 return 0; int oldSize = _size; //记录原规模 Posi(T) p = first(); Rank r = 1; //p从首节点开始 while ( trailer != ( p = p->succ ) ) { //依次到末节点 Posi(T) q = find(p->data, r, p); //从前驱中查找雷同的 q ? remove(q) : r++; //若存在删除,否则秩递增 } return oldSize - _size; //列表规模变化,等于删除的元素 } //有序向量唯一化 template int List::uniquify() { if(_size < 2) return 0; int ordSize = _size; //原始规模 ListNodePosi(T) p = first(); ListNodePosi(T) q; while ( trailer != ( q = p->succ ) ) //遍历 if ( p->data != q->data ) //不同 p = q; //连接 else remove(q); //雷同删除 return oldSize - _size; } //O(n) //查找 template Posi(T) List::search(T const &e, int n, Posi(T) p) const { while ( 0 <= n-- ) //从右往左扫描,发现下于即命中 if ( ( ( p = p->pred )->data ) <= e ) break; return p; } //选择排序 template void List::selectionSort(Posi(T) p, int n) { Posi(T) head = p->pred; //待排区间 Posi(T) tail = p; for (int i = 0; i < n; ++i) { tail = tail->succ; } while (1 < n) { //反复从待排区间找出最大的移至有序区间前端 insertBefore( tail, remove( selectMax(head->succ), n) ); tail = tail->pred; n--; } } template Posi(T) List::selectMax(Posi(T) p, int n) { Posi(T) max = p; for (Posi(T) cur = p; 1 < n; n--) { if ( !lt ( (cur = cur->succ )->data, max->data) ) max = cur; return max; //返回最大节点位置 } } ================================================ FILE: booknotes/demo/ListNode.h ================================================ #define Post(T) ListNode* #define sPost(T) sListNode* template struct ListNode { //完全开放,不再过度封装 T data; //数值 Post(T) pred; //前驱 Post(T) succ; //后继 ListNode() {} //针对header和trailer的构造 ListNode(T e, Posi(T) p = NULL, Post(T) s = NULL) : data(e), pred(p), succ(s) {} //默认构造 Posi(T) insertAsPred(T const & e); //前插入 Posi(T) insertAsSucc(T const & e); //后插入 } template struct sListNode { //完全开放,不再过度封装 T data; //数值 Post(T) next; //后继 ListNode() {} //针对header和trailer的构造 ListNode(T e, Posi(T) p = NULL, Post(T) s = NULL) : data(e), pred(p), succ(s) {} //默认构造 Posi(T) insertAsPred(T const & e); //前插入 Posi(T) insertAsSucc(T const & e); //后插入 } ================================================ FILE: booknotes/demo/Node.h ================================================ typedef *Node node(T); template struct Node { T data; node(T) next; } ================================================ FILE: booknotes/demo/PQ.class.cpp ================================================ template struct PQ{ virtual void insert(T) = 0; //按优先级插入词条 virtual T getMax() = 0; //取出优先级最高的词条 virtual T delMax() = 0; //删除优先级最高的词条 }; //与其说是PQ是数据结构,不如说是ADT。根据不同的实现方式,适用于不同的场合 #define Parent(i) ( (i-1) >> 1 ) #define LChild(i) ( 1 + ( ( i ) << 1 ) ) //奇数 #define RChild(i) ( ( 1 + (i) ) << 1 ) //偶数 ================================================ FILE: booknotes/demo/PQ_ComplHeap.class.cpp ================================================ template class PQ_ComplHeap : public PQ , public Vector { protected: Rank percolateDown( Rank n, Rank i); //下滤 Rank percolateUp( Rank i ); // 上滤 void heapify( Rank n); //Floyd建堆算法 public: PQ_ComplHead( T* A, Rank n) { copyFrom(A, 0, n); heapify(n); } //批量构造 void insert(T); //按照比较器确定的优先级次序,插入词条 T getMax() { return _elem[0]; } T delMax(); } ================================================ FILE: booknotes/demo/Queue.class.cpp ================================================ template class Queue : public List{ public: void enqueue(T const &e) { insertAsLast(e); } //入队 T dequeue() { return remove( first() ); } //出队 T & front() { return first()->data; } //队首 }; ================================================ FILE: booknotes/demo/RedBlack.class.cpp ================================================ template class RedBlack: public BST { public: BinNodePosi(T) insert( const T & e); //插入重写 bool remove( const T % e); // 删除重写 protected: void solveDoubleRed( BinNodePosi(T) x); //双红修正 void solveDoubleBlack( BinNodePosi(T) x); //双黑修正 int updateHeight( BinNodePosi(T) x); //更新节点高度 } ================================================ FILE: booknotes/demo/SList.class.cpp ================================================ #include "Node.h" template class SList { SList(int size); ~List(); void ClearSList(); bool SListEmoty(); int ListLength(); } template SList::SList() { } ================================================ FILE: booknotes/demo/Splay.class.cpp ================================================ template class Splay : public BST { protected: BinNodePosi(T) splay( BinNodePosi(T) v); //将v伸展至根 public: //伸展树的查找也会引起整数的结构 BinNodePosi(T) & search( const T & e); //查找 BinNodePosi(T) insert( cosnt T & e); //插入 bool remove( const T & e); //删除 }; ================================================ FILE: booknotes/demo/Stack.class.cpp ================================================ template class Stack :public Vector { public: void push(T const & e) { insert(size(), e); } //入栈 T pop() { return remove( size() -1 ); } //出栈 T & top() { return (*this)[ size() - 1]; } //取顶 }; ================================================ FILE: booknotes/demo/Vector.class.cpp ================================================ typedef int Rank; //秩 #define DEFAULT_CAPACITY 3 //默认容量 template class Vector{ private: Rank _size; //规模 int _capacity; //容量 T* _elem; //数据区 protected: //内部函数 public: //构造函数 Vector(int c = DEFAULT_CAPACITY){ _elem = new T[_capacity = c]; _size = 0; } //默认 Vector(T const *A, Rank lo, Rank hi) { copyFrom(A, lo, hi); } //数组区间复制 Vector(Vector const& V, Rank lo, Rank hi) { copyFrom(V._elem, lo, hi); } //向量区间复制 Vector(Vector const& V) { copyFrom(V._elem, 0, V._size); } //向量整体复制 //析构函数 ~Vector() { delete [] _elem; } //只读接口 //可写接口 //遍历接口 } //复制 template void Vector::copyFrom(T* const A, Rank lo, Rank hi) { _elem = new T[_capacity = 2*(hi - lo)]; //分配空间,预留2倍的空间 _size = 0; //规模清零 while (lo < hi) { _elem[_size++] = A[lo++]; } //元素逐一复制[0, hi-lo) } //扩容 template void Vector::expand() { if(_size < _capacity) return; //尚满,不扩 _capacity = max(_capacity, DEFAULT_CAPACITY); //不低于最小容量 T* oldElem = _elem; _elem = new T[_capacity <<= 1]; //容量加倍 for (int i = 0; i < _size; ++i) //复制原向量内容 _elem[i] = oldElem[i]; // = 重载了的 delete [] oldElem; //释放原空间 } template Rank Vector::insert(Rank r, T const & e) { expand(); //若满,扩容 for(int i = _size; i > r; i--) _elem[i] = _elem[i-1]; //原r后的整体元素后移一位(后开始) _elem[r] = e; //r处赋值 _size++; //规模加一 return r; //返回秩 } template // 删除区间hi-lo int Vector::remove(Rank lo, Rank hi) { if (lo == hi) return 0; //单独处理退化 while (hi < _size) _elem[lo++] = _elem[hi++]; //整体前移一段(前开始) _size = lo; shirnk(); //缩容 return hi - lo; } template T Vector::remove(Rank r) { T e = _elem[r]; remove(r, r+1); return e; } template Rank Vector::find(T const & e, Rank lo, Rank hi) const { while ((lo < hi--) && e != _elem[hi]) //逆向查找 return hi; } template int Vector::deduplicate() { int oldSize = _size; Rank i = 1; //从第二个元素开始 while (i < _size) //由前向后逐步考查 (find(_elem[i], 0, i) < 0) ? i++ : remove(i); //删除雷同者 return oldSize - _size; //删除的总数 } template template void Vector::traverse(TSV & visit) { for (int i = 0; i < _size; i++) visit(_elem[i]); } template int Vector::disordered() const { int n = 0; for (int i = 0; i < _size; i++) //逐一检查各对相邻元素 n += (_elem[i - 1] > _e[i]); //逆序则计数向量有序 return n; //当且仅当n=0时 } //只判断是否有序,首次遇到逆序对直接终止 // template int Vector::uniquift() { // int oldSize = _size; // int i = 0; // while (i < _size-1) //雷同删除后者 // (_elem[i] == _elem[i+1]) ? remove(i+1) : i++; // return oldSize - _size; // } template int Vector::uniquift() { Rank i = 0, j = 0; //相邻互异元素 while(++j < _size) //跳过雷同者,不同者紧靠前者右侧 if(_elem[i] != _elem[j]) _elem[++i] = _elem[j]; _size = ++i; shirnk(); return j - i; } //查找 template int Vector::search(T const & e, Rank lo, Rank hi) { return (rand() % 2) ? binSearch(_elem, e, lo, hi) : fibSearch(_elem, e, lo, hi); } //二分查找A template static Rank binSearch(T * A, T const &e, Rank lo, Rank hi) { while (lo < hi) { Rank mi = (lo + hi) >> 1; if (e < A[mi]) hi = mi; //三种情况 else if ( A[mi] < e) lo = mi + 1; else return mi; } return -1; //查找失败 } //二分查找B template static Rank binSearch(T * A, T const &e, Rank lo, Rank hi) { while (1 < hi - lo) { Rank mi = (lo + hi) >> 1; (e < A[mi]) ? hi = mi : lo = mi; } return (e == A[mi]) ? lo : -1; } //二分查找C template static Rank binSearch(T * A, T const &e, Rank lo, Rank hi) { while (lo < hi) { Rank mi = (lo + hi) >> 1; (e < A[mi]) ? hi = mi : lo = mi + 1; } return --lo; } //fib查找 template static Rank fibSearch(T * A, T const &e, Rank lo, Rank hi) { Fib fib(hi - lo); //创建fib数列 while(lo < hi) { while (hi - lo < fib.get()) fib.prev(); //向前查找确定fib(k)-1的轴点 Rank mi = lo + fib.get() - 1; //切分 if (e < A[mi]) //前半段 hi = mi; else if (A[mi] < e) lo = mi + 1;//后半段 else return mi; //命中 } return -1; } //排序 template void Vector::sort(Rank lo, Rank hi) { switch (rand() % 5) { case 1: bubbleSort(lo, hi); break; //起泡排序 case 2: selectSort(lo, hi); break; //选择排序 case 3: mergeSort(lo, hi); break; //归并排序 case 4: heapSort(lo, hi); break; //堆排序 case 5: quickSort(lo, hi); break; //快速排序 } } //起泡排序(改进) template void Vector::bubbleSort(Rank lo, Rank hi) { while (!bubble(lo, hi--)); //扫描直至全序 } template bool Vector::bubble(Rank lo, Rank hi) { bool sorted = true; while (++lo < hi) if (_elem[lo - 1] > _elem[lo]) { sorted = false; swap(_elem[lo - 1], _elem[lo]); } return sorted; } //起泡排序(再次改进) template void Vector::bubbleSort(Rank lo, Rank hi) { while (lo < ( hi = bubble(lo, hi) ) ); //扫描直至全序 } template Rank Vector::bubble(Rank lo, Rank hi) { Rank last = lo; while (++lo < hi) if (_elem[lo - 1] > _elem[lo]) { last = lo; swap(_elem[lo - 1], _elem[lo]); } return sorted; } //归并排序 template void Vetor::mergeSort(Rank lo, Rank hi) { if (hi -lo < 2) return; //处理递归基,单元素区间自然有序 int mi = (lo + hi) >> 1; //中心点 mergeSort(lo, mi); //前端递归 mergeSort(mi, hi); //后段递归 merge(lo, mi, hi); //归并 } template void Vector::merge(Rank lo, Rank mi, Rank hi) { T * A = _elem + lo; //合并后的向量 int lb = mi - lo; //前子向量 T * B = new T[lb]; //复制前子向量 for (Rank i = 0; i < lb; B[i] = A[i++]) ; int lc = hi - mi; //后子向量 T * C = _elem + mi; //B[j]和C[k]小者转移A末尾 for (Rank i = 0, j = 0, k = 0; (j < lb) || (k < lc); ){ if( (j < lb) && (lc <= k) || (B[j] <= C[k]) ) A[i++] = B[j++]; if( (k < lc) && (lb <= j) || (C[K] <= B[j]) ) A[i++] = C[k++]; } //循环紧凑,效率不如拆分 delete [] B; } ================================================ FILE: booknotes/demo/VectorTest.cpp ================================================ #include #include #include #include using namespace std; int main() { // vector v; // v.push_back(1); // v.push_back(2); // cout << v[0] << v[1] << endl; stack s; s.push(1); s.push(2); cout << s.top(); s.pop(); cout << s.top() << endl; return 0; } ================================================ FILE: booknotes/demo/Vertex.h ================================================ typedef enum { UNDISCOVERED, DISCOVERED, VISITED} VStatus; template struct Vertex { Tc data; //数据 int inDegree, outDegree; //入度出度 VStatus status; //状态 int dTime, fTime; //时间标签 int parent; //父节点 int priority; //优先级 Vertex( Tv const & d) : //构造初始化新顶点 data(d), inDegree(0), outDegree(0), status(UNDISCOVERED), dTime(-1), fTime(-1), priority(INT_MAX) {} } ================================================ FILE: booknotes/demo/a_bubbleSort.cpp ================================================ #include using namespace std; //起泡排序 void bubblesort(int A[], int n){ for( bool sorted = false; sorted = !sorted; n--) for(int i = 1; i < n; i++) if(A[i-1] > A[i]){ swap(A[i-1, A[i]]); sorted = false; } } int main(){ return 0; } ================================================ FILE: booknotes/demo/a_convert.cpp ================================================ #include #include #include using namespace std; //进制转换 void convert( Stack & S, __int64 n, int base) { static char digit[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; while (n > 0) { s.push( digit[ n % base ]); n /= base; } } int main() { Stack S; cin >> n >> base; convert(S, n, base); while ( !S.empty() ) cout << S.pop(); return 0; } ================================================ FILE: booknotes/demo/a_evaluate.cpp ================================================ #include #include #include #include using namespace std; const char pri[N_][] = {}; //逆波兰转换 float evaluate(char * s, char * & RPN) { Stack opnd; Stack optr; optr.push('\0'); while (!optr.empty()) { if (isdigit(*S)) readNumber(S, opnd); else { switch( orderBetween(optr.top(), *S) ) { case '<': optr.push(*S); S++; break; case '=': optr.pop(); S++; break; case '>': { char op = optr.pop(); if ('!' == op) //一元运算符 opnd.push( calcu(op, opnd.pop()) ); else { //二元运算符 float pOpnd2 = opnd.pop(); //操作数 float pOpnd1 = opnd.pop(); opnd.push( calcu(pOpnd1, op, pOpnd2) ); //运算并回收 } break; } } } } return opnd.pop(); } ================================================ FILE: booknotes/demo/a_fib.cpp ================================================ #include //递归 int fib(int n){ return (2 > n) ? n : fib(n-1) + fib(n-2); } //迭代 int fib2(int n){ int f = 0, g = 1; while(0 < n--){ g = g + f; f = g - f; } return g; } int main(void){ // std:: cout << fib(64) << std:: endl; std:: cout << fib2(64) << std:: endl; return 0; } ================================================ FILE: booknotes/demo/a_hailstone.cpp ================================================ /** * Hailstone问题 */ #include using namespace std; int hailstone(int n) { int length = 1; while(1 < n){ n%2==0 ? n/=2 : n=3*n+1; length++; } return length; } int main(){ int n; cin >> n; cout << hailstone(n) << endl; return 0; } ================================================ FILE: booknotes/demo/a_paren.cpp ================================================ #include #include #include bool paren(const char exp[], int lo, int hi) { Stack S; for (int i = lo; i < hi; i++) if( exp[i] == '(' ) S.push(exp[i]); else if( !S.empty() ) S.pop(); else return false; return S.empty(); } int main(void) { char exp[20] = { '(' }; paren(exp, 0, 20); return 0; } ================================================ FILE: booknotes/demo/a_sum.cpp ================================================ #include using namespace std; int SumI(int A[], int n){ int sum = 0; for (int i = 0; i < n; ++i) { sum += A[i]; } return sum; } //迭代 int SumJ(int A[], int n){ return (n < 1) ? 0 : SumJ(A, n-1) + A[n+1] ; } //递归 int sum(int A[], int lo, int hi){ if(lo == hi) return A[lo]; int mi = (lo+hi) >> 1; return sum(A, lo, mi) + sum(A, mi + 1, hi); }//二分递归 int main(){ int A[10] = {1,2,3,4,5,6,7,7,8,9}; // cout << SumI(a, 10) << endl; // cout << SumJ(A, 10) << endl; cout << sum(A, 0, 9); return 0; } ================================================ FILE: booknotes/demo/a_vector.cpp ================================================ #include #include using namespace std; int main(void){ vector v(10, 0); return 0; } ================================================ FILE: booknotes/demo/sort.cpp ================================================ template void Verctor::quickSort( Rank lo, Rank hi) { if( hi - lo < 2) return 0; //平凡解 Rank mi = partition( lo, hi-1 ); //先构造轴点 quickSort(lo, mi); //前缀排序 quickSort(mi+1, hi); //后缀排序 } template Rank Vector::partition( Rank lo, Rank hi) { swap( _elem[ lo ], _elem[ lo + rand() % ( hi - lo + 1 ) ] );//随机交换 T pivot = _elem[ lo ]; int mi = lo; for ( int k = lo + 1; k <= hi; k++ ) //自左向右考查每个[k] if( _elem[ k ] < pivot ) //若k小于轴点,则将其与[mi]交换,L向右扩展 swap( _elem[ ++mi ], _elem[ k ]); swap( _elem[ lo ], _elem[ mi ] ); //候选抽点归位 return mi;//返回轴点的秩 } ================================================ FILE: booknotes/graph.md ================================================ # 图(Graph) ### 概述 - 邻接:邻接关系,顶点与顶点的关系 - 关联:关联关系,顶点与边的关系 - 无向图:次序无所谓 - 有向图(digraph):有次序,起点尾(tail),终点头 (head) - 路径(path):一系列的顶点按照依次邻接的关系构成序列 - 简单路径:不含重复节点的路径 - 环路(cicle):起点终点重合的路径 - 无环路(DAG):不包含任何环路的图 - 欧哈路:覆盖所有的点 - 哈密尔顿:覆盖所有点,每个顶点有且仅经过一次 ### 邻接矩阵(adjacency matrix) - 接口 ``` template class Graph { private: void reset() { for (int i = 0; i < n; ++i){ //顶点 status(i) = UNDISCOVERED; dTime(i) = fTime(i) = -1; parent(i) = -1; priority(i) = INT_MAX; for (int j = 0; j < n; j++) //边 if (exists(i, j)) status(i, j) = UNDETERMINED; } } public: }; ``` - 顶点的实现(Vertex):邻接矩阵 ``` typedef enum { UNDISCOVERED, DISCOVERED, VISITED} VStatus; template struct Vertex { Tc data; //数据 int inDegree, outDegree; //入度出度 VStatus status; //状态 int dTime, fTime; //时间标签 int parent; //父节点 int priority; //优先级 Vertex( Tv const & d) : //构造初始化新顶点 data(d), inDegree(0), outDegree(0), status(UNDISCOVERED), dTime(-1), fTime(-1), priority(INT_MAX) {} }; ``` - 边的实现(Edge): ``` typedef enum { UNDETERMINED, TREE, CROSS, FORWORD, BACKWAED } EStatus; template struct Edge { Te data; //数据 int weight; //权重 EStatus status; //类型 Edge( Te const & d, int w ):data(d), weight(w), status(UNDETERMINED) {} }; ``` - 图的实现(GraphMatrix):利用向量和邻接矩阵实现,适用稠密图,效率高 ``` template class GraphMatrix : public Graph { private: Vector< Vertex > V; //顶点集 Vector< Vector< Edge* > > E; //边集 public: GraphMatrix() { n = e = 0;} ~GraphMatrix() { for (int j = 0; j < n; ++j) for (int k = 0; k < n; ++k) delete E[j][k]; } }; ``` - 顶点操作 ``` //顶点操作 Tv & Vertex(int i) { return V[i].data } //... //枚举邻接顶点,逆序查找 int NextNbr(int i, int j) { while ( (-1 < j) && !exists(i, --j) ) ; return j; } int firstNbr(int i) { return NextNbr(i, n); } //顶点插入 int insert(Tv const & vertex) { for (int i = 0; i < n; ++i) E[j].insert(NULL); n++; E.insert( Vector< Edge* >( n, n, NULL) ); return V.insert( Vertex(vertex) ); } //顶点删除 Tv remove(int i) { for (int i = 0; i < n; ++i) if(exists(i, j)){ delete E[i][j]; V[j].inDegree--; } E.remove(i); n--; for (int j = 0; j < n; j++) if ( exists(j ,i) ){ delete E[j].remove(i); V[j].outDegree--; } Tv vBak = vertex(i); V.remove(i); return vBak; } ``` - 边操作 ``` //边操作 bool exists(int i, int j) { return (0 <= i) && (i < n) && (0 <= j) && (j < n) && E[i][j] != NULL; } Te & edge(int i, int j) { return E[i][j]->data; } //... //边插入 void insert( Te const& edge, int w, int i, int j) { if( exists(i, j) ) return ; //忽略已有的边 E[i][j] = new Edge(edge, w); //创建新边 e++; //更新信息 V[i].outDegree++; V[i].inDegree++; } //边删除 Te remove(int i, int j) { Te eBak = edge(i, j); delete E[i][j]; E[i][j] = NULL; e--; V[i].outDegree--; V[j].inDegree--; return eBak; } ``` ### 广度优先搜索(BF-Search) > 化繁为简:遍历(图->树) - 算法: ``` 1. 访问顶点s 2. 访问s所有尚未访问的邻接顶点 3. 依次访问它们尚未访问的邻接顶点 4. 如此反复 实际上:树的层次遍历 ``` - 图示: ``` a / | \ s | e / \ | | \ 遍历前 d c | f \ / | / b-----g a / \ s e / \ | \ 遍历后 d c | f / | b g 队列 s->a->c->d->e->b->f->g ``` - 实现: ``` //练习 ``` ### 深度优先搜索(DF-Search) - 算法: ``` 1. 访问顶点s 2. 尚有未被访问的邻居,任取其一u,递归执行DFS(u),否则返回 ``` - 图示: ``` j | i---g---h | / \ | d e f | / | | a --b---c j | i---g---h | | d e f | | a --b---c 队列: a->b->c->f->h->g->j->i->d->e ``` - 实现: ``` //练习 ``` ================================================ FILE: booknotes/hash.md ================================================ # 词典 ### 散列(Hash) > 新的访问方式 ``` 寻秩访问:向量 寻位置:列表 寻关键码:BST ``` - 访问方式:寻值访问 - 电话 ### 原理 - 桶Bucket:直接存放或者间接指向一个词条 - 桶数组Bucket array/散列表 Hash Table 容量为M ``` N < M << R 空间 = O(N + M) = O(n) ``` - 定址/杂凑/散列:根据Key直接确定散列表入口 - 散列函数:hash() : key -> & entry ``` hash(key) = key % M 25K / 90K > 25% 节约了较大空间 装填因子 N / M 6278 5001 54304 39514 6277 0211 % 90001 39514 51304 5154 1876 51304 54304 ``` - 冲突:不同关键码,被映射到同一实体上 ``` 5153 1976 % 90001 51304 6278 2001 理论上无法彻底避免,只能根据策略减少冲突 hash 不可能是单射 ``` - 散列策略:近似的单射,往往可行 - - 精心设计散列表和散列函数,尽可能降低冲突的概率 - - 制定可行的预案,以便排解 ### 散列函数 - 评价标准:什么样hash()更好 - - 确定determinism:同一关键码总是被映射至同一地址 - - 快速efficency:expected-O(1) - - 满射surjection:尽可能充分的覆盖整个散列空间 - - 均匀uniformity:关键码映射到散列表各位置的概率尽量接近可有效避免聚集clustering现象 - 除余法 ``` hash(key) = key % M ``` - - 表长为素数时,分布更均匀,更全面 - - gcd(S, M) = G ,M取素数 - - 缺陷:不动点hash(0) = 0,零阶均匀,相邻关键码散列地址必相邻 - MAD法: ``` M为素数,a > 0, b > 0, a % M !=0 hash( key ) = ( a * key + b ) % M ``` - 数字分析法 - 平方取中法:平方后取中间数 ``` hash( key ) = key^2 取中间位数 ``` - 折叠法:将key分隔为等宽的若干端,取其总和作为地址 - 位异或法。。。。 - 总结:越是随机越是没有规律越好 - 伪随机数法: ``` 随机数发生器 循环 rand( x + 1 ) = a * rand( x ) % M x = time() 伪随机数法 hash( key ) = rand( key ) = [ rand(0) * a^key ] % M 种子 rand(0) ``` - 多项式法: ``` hash( s = X0X1X2...Xn-1) = X0a^n-1 + X1a^n-2+... Xn-1 ``` #### 排解冲突 #### 计数排序 ================================================ FILE: booknotes/list.md ================================================ # 列表(List) ### 接口与实现 > 列表是采用**动态存储**策略的典型结构,其中的元素称作节点(node) > 各节点通过指针或者引用彼此联结,在**逻辑**上构成一个线性序列 - 从静态到动态操作 - 1)静态:get O(1), search O(logn) - 2)动态:insert O(n), remove O(n) - 前驱后继:彼此相邻的节点,前驱或后继若存在则必然唯一 - 首末节点:没有前驱后后继的唯一节点 - 寻位置访问:called-by-position,通过节点的相互引用找到特定的节点 - 实现接口:列表节点作为基本单位 操作 | 功能 ---|--- pred() | 取节点前驱 succ() | 取节点后继 data() | 取节点数据对象 insertAsPred(e) | 插入前驱节点,存入e,返回新节点位置 insertAsSucc(e) | 插入后继节点,存入e,返回新节点位置 ``` #define Post(T) ListNode* template struct ListNode { //完全开放,不再过度封装 T data; //数值 Post(T) pred; //前驱 Post(T) succ; //后继 ListNode() {} //针对header和trailer的构造 ListNode(T e, Posi(T) p = NULL, Post(T) s = NULL) : data(e), pred(p), succ(s) {} //默认构造 Posi(T) insertAsPred(T const & e); //前插入 Posi(T) insertAsSucc(T const & e); //后插入 } ``` - 操作接口 - 模板类 ``` #include "ListNode.h" template class List { private: int _size; Posi(T) header; //头元素(不可见) Posi(T) trailer; //末元素(不可见) protected: //内部函数 public: //构造函数 //析构函数 //只读接口 //可写接口 //遍历接口 }; //构造函数 规模为0 template void List::init() { header = new ListNode; trailer = new ListNode; header->succ = trailer; header->pred = NULL; trailer->pred = header; trailer->succ = NULL; _size = 0; } ``` ### 无序列表 - 秩到位置:模仿向量的循秩访问方式,重载下标符 - 查找 ``` template Posi(T) List::find(T const &e, int n, Posi(n) p) const { while (0 < n--) if (e == ( p = p->pred )->data ) return p; return NULL; } ``` - 插入 ``` template Posi(T) List::insertBefore(Posi(T) p, T const & e) { _size++; return p->insertAsPred(e); //e当作前驱插入 } template Posi(T) ListNode::insertAsPred(T const & e) { Posi(T) x = new ListNode(e, pred, this); //创建 pred->succ = x; //建立连接 pred = x; return x; } ``` - 基于复制的构造 ``` //基于复制的构造 template void List::copyNodes(Posi(T) p, int n) { //O(n) init(); //创建头尾节点初始化 while (n--) { //自p的n下依次作为末节点插入 insertAsLast(p->data); p = p->succ; } } ``` - 删除节点 ``` //删除 template T List::remove(Posi(T) p) { //O(1) T e = p->data; //备份待删除的数值 p->pred->succ = p->succ; //跳过p p->succ->pred = p->pred; //对称 delete p; _size--; return e; //返回数值 } ``` - 析构 ``` //析构 template List::~List() { clear(); //清空列表 delete header; //释放头 delete trailer; //释放尾 } template int List::clear() { int oldSize = _size; while(0 < _size) remove(header->succ); //反复删除首节点 return oldSize; } //O(n) ``` - 唯一化 ``` //唯一化 template int List::deduplicate() { if (_size < 2) //平凡列表自然无重复 return 0; int oldSize = _size; //记录原规模 Posi(T) p = first(); Rank r = 1; //p从首节点开始 while ( trailer != ( p = p->succ ) ) { //依次到末节点 Posi(T) q = find(p->data, r, p); //从前驱中查找雷同的 q ? remove(q) : r++; //若存在删除,否则秩递增 } return oldSize - _size; //列表规模变化,等于删除的元素 } ``` ### 有序列表 - 唯一化 ``` //有序向量唯一化 template int List::uniquify() { if(_size < 2) return 0; int ordSize = _size; //原始规模 ListNodePosi(T) p = first(); ListNodePosi(T) q; while ( trailer != ( q = p->succ ) ) //遍历 if ( p->data != q->data ) //不同 p = q; //连接 else remove(q); //雷同删除 return oldSize - _size; } //O(n) ``` - 查找 ``` //查找 template Posi(T) List::search(T const &e, int n, Posi(T) p) const { while ( 0 <= n-- ) //从右往左扫描,发现下于即命中 if ( ( ( p = p->pred )->data ) <= e ) break; return p; } ``` ### 选择排序 ``` template void List::selectionSort(Posi(T) p, int n) { Posi(T) head = p->pred; //待排区间 Posi(T) tail = p; for (int i = 0; i < n; ++i) { tail = tail->succ; } while (1 < n) { //反复从待排区间找出最大的移至有序区间前端 insertBefore( tail, remove( selectMax(head->succ), n) ); tail = tail->pred; n--; } } //尽可能少的使用new delete template Posi(T) List::selectMax(Posi(T) p, int n) { Posi(T) max = p; for (Posi(T) cur = p; 1 < n; n--) { if ( !lt ( (cur = cur->succ )->data, max->data) ) max = cur; return max; //返回最大节点位置 } } //O(n^2) 但是移动操作远远少于起泡排序 //改进比较操作后可以在nlogn下完成 ``` ### 插入排序 ### LightHouse # 栈与队列(Stack) > 一组元素的线性序列,通常只能访问一个元素 > 开放的端top,不开放的bottom > push,pop只能操纵当前的顶部的元素 ### 接口与实现 - 操纵 操纵 | 功能 ---|--- Stack() | 初始化栈 empty() | 判断栈是否为空 push(e) | 进栈 pop(e) | 出栈 size() | 返回元素数量 - 特性:后进先出(LIFO) - 实现:通过向量或列表派生 ``` //向量实现 template class Stack :public Vector { public: //size() empty()直接沿用 void push(T const & e) { insert(size(), e); } //入栈 T pop() { return remove( size() -1 ); } //出栈 T & top() { return (*this)[ size() - 1]; } //取顶 O(1) }; //列表实现 ``` ### 进制转换(逆序输出) ``` #include #include #include using namespace std; void convert( Stack & S, __int64 n, int base) { static char digit[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; while (n > 0) { s.push( digit[ n % base ]); n /= base; } } int main(void) { Stack S; cin >> n >> base; convert(S, n, base); while ( !S.empty() ) cout << S.pop(); return 0; } ``` ### 括号匹配(递归嵌套) ``` #include #include #include bool paren(const char exp[], int lo, int hi) { Stack S; for (int i = lo; i < hi; i++) if( exp[i] == '(' ) S.push(exp[i]); else if( !S.empty() ) S.pop(); else return false; return S.empty(); } int main(void) { char exp[20] = { '(' }; paren(exp, 0, 20); return 0; } //通过计数器也可以实现 //但是通过栈可以拓展到多个括号并存的实例 ``` ### 栈混洗 - 计数:cabula数 (2n!)/ (n!*(n+1)!) - 甄别:n = 3 时 3 1 2 不是栈混洗,与元素无关,这是一个禁型,是充要条件 ``` //高效算法,引入3个栈,模拟混洗过程,使用贪心算法 //练习 ``` - 与括号匹配的联系 ### 中缀表达式求值(延迟缓冲) ``` float evaluate(char * s, char * & RPN) { Stack opnd; Stack optr; optr.push('\0'); while (!optr.empty()) { if (isdigit(*S)) readNumber(S, opnd); else { switch( orderBetween(optr.top(), *S) ) { case '<': optr.push(*S); S++; break; case '=': optr.pop(); S++; break; case '>': { char op = optr.pop(); if ('!' == op) //一元运算符 opnd.push( calcu(op, opnd.pop()) ); else { //二元运算符 float pOpnd2 = opnd.pop(); //操作数 float pOpnd1 = opnd.pop(); opnd.push( calcu(pOpnd1, op, pOpnd2) ); //运算并回收 } break; } } } } return opnd.pop(); } ``` ### 逆波兰表达式(RPN):不需要判断优先级,只要遇到操作符就计算,后缀表达式 - 变形:若欲取之,必先予之 ``` 1. 括号显示表示优先级 2. 将运算符移动对应的右括号之后 3. 抹去所有运算符 4. 稍加整理 ``` - 实现: ``` //练习 ``` ### 队列实现(Queue) > 线性的受限序列 :FIFO > 只允许在队尾插入:enqueue() + rear() > 只允许在队头删除:dequeue() + front() - 列表派生 ``` template class Queue : public List{ public: //size() empty()直接沿用 void enqueue(T const &e) { insertAsLast(e); } //入队 T dequeue() { return remove( first() ); } //出队 T & front() { return first()->data; } //队首 }; //O(1) ``` ================================================ FILE: booknotes/proqueue.md ================================================ # 优先级队列 ### 需求动机 - 门诊的队列 - 电脑中cup的调度 ### 实现 - 接口 ``` template struct PQ{ virtual void insert(T) = 0; //按优先级插入词条 virtual T getMax() = 0; //取出优先级最高的词条 virtual T delMax() = 0; //删除优先级最高的词条 }; //与其说是PQ是数据结构,不如说是ADT。根据不同的实现方式,适用于不同的场合 ``` - 实现: - - 向量,列表都不能使三个接口效率达到最 - - 借助BBST(AVL,Splay,Red-black)均满足O(logn - - 但是BBST的功能超过了PQ的需求 - - 只需查找极值元,不必维护全序,只需维护偏序即可 ### 完全二叉堆(Complate Binary heap) - 逻辑:完全二叉树(Complete Binary Tree) - 物理:向量(vertor) - 对应:依层次遍历彼此对应 ``` #define Parent(i) ( (i-1) >> 1 ) #define LChild(i) ( 1 + ( ( i ) << 1 ) ) //奇数 #define RChild(i) ( ( 1 + (i) ) << 1 ) //偶数 ``` - 实现 ``` template class PQ_ComplHeap : public PQ , public Vector { protected: Rank percolateDown( Rank n, Rank i); //下滤 Rank percolateUp( Rank i ); // 上滤 void heapify( Rank n); //Floyd建堆算法 public: PQ_ComplHead( T* A, Rank n) { copyFrom(A, 0, n); heapify(n); } //批量构造 void insert(T); //按照比较器确定的优先级次序,插入词条 T getMax() { return _elem[0]; } T delMax(); } ``` - 堆序性:H[i] <= H[ Parent(i) ] 故H[0]为最大元素 ### 堆排序 ### 左式堆 ================================================ FILE: booknotes/sort.md ================================================ # 排序 ### 快速排序(QuickSort) - 分而治之 - - 将序列分为2个子序列:S = Sl = Sr //O(n) - - 规模独立:max { |Sl| , |Sr| } < n - - 彼此独立:max( Sl ) <= min( Sr ) - - 在子序列分别递归底排序之后,原序列自然有序sorted(S) = sorted(Sl) + sorted(Sr) - - 平凡解:只剩单个元素时,本身就是解 - - 归并排序在于合,quicksort在于分 - 轴点(pivot) - - 左/右侧的元素,均不比它更大/小 - - 以轴点为届,原序列的划分自然实现:[lo, hi) = [lo,mi) + [mi] + (mi,hi) ``` template void Verctor::quickSort( Rank lo, Rank hi) { if( hi - lo < 2) return 0; //平凡解 Rank mi = partition( lo, hi-1 ); //先构造轴点 quickSort(lo, mi); //前缀排序 quickSort(mi+1, hi); //后缀排序 } ``` - - 坏消息:在原始序列中,轴点未必存在 - - 必要条件:轴点必然已然就位 - - 特别的:在有序序列中,所有元素逐个转换成轴00点2 - - 不变性与单调性:L <= pivot <= G; U = [lo, hi],[lo]和[hi]交替空闲 - 实例: ``` 轴点为6 6 3 8 2 5 9 4 5 1 7 x 3 8 2 5 9 4 5 1 7 1 3 8 2 5 9 4 5 x 7 1 3 x 2 5 9 4 5 8 7 1 3 5 2 5 9 4 x 8 7 1 3 5 2 5 x 4 9 8 7 1 3 5 2 5 4 x 9 8 7 1 3 5 2 5 4 6 9 8 7 ``` - 性能 - - 不稳定 - - 空间:只需要O(1) - - 时间:不能保证划分的均衡性,最好O(nlogn),最坏O(n^2) - - 采取随机选取,三者取中,只能降低最坏的情况,而无法根本的杜绝 - - 总结:平均性能O(nlogn),根据均匀独立分布为例,准确的1.39logn ### 快排变种 - 不变性:四个部分S = [lo] + L(lo, mi] + G(mi, k) + U[k, hi], L < pivot <= G - 单调性:K不小于轴 ? 直接拓展G : G滚动后移,L拓展 pivot <= S[k] ? k++ : swap(S[++mi], S[k++]) - 代码 ``` template Rank Vector::partition( Rank lo, Rank hi) { swap( _elem[ lo ], _elem[ lo + rand() % ( hi - lo + 1 ) ] );//随机交换 T pivot = _elem[ lo ]; int mi = lo; for ( int k = lo + 1; k <= hi; k++ ) //自左向右考查每个[k] if( _elem[ k ] < pivot ) //若k小于轴点,则将其与[mi]交换,L向右扩展 swap( _elem[ ++mi ], _elem[ k ]); swap( _elem[ lo ], _elem[ mi ] ); //候选抽点归位 return mi;//返回轴点的秩 } ``` - 实例 ``` 6 3 8 1 5 9 8 4 5 7 2 6 3 8 1 5 9 8 4 5 7 2 6 3 1 5 8 9 8 4 5 7 2 6 3 1 5 8 9 8 4 5 7 2 6 3 1 5 8 9 8 4 5 7 2 6 3 1 5 4 9 8 8 5 7 2 6 3 1 5 4 5 9 8 8 7 2 6 3 1 5 4 5 9 8 8 7 2 6 3 1 5 4 5 2 8 9 7 8 2 3 1 5 4 5 6 8 9 7 8 //时间O(n) //空间O(1) //不稳定 ``` ### 选取 - k-selection:在任意大小的元素中,如何由小到大,找到次序为k者,亦即 - median:长度为n中选择位于中间的那个数 - majoerity:无序向量,若有一半以上元素同为m,称之为众数 - 平凡算法 排序+扫描,必要性,众数存在必为中位数 - 事实上,只要能够找到中位数,就能判断是否为众数 - 众数若存在,则必为频繁数 - 策略:减而治之 ### 通用算法 ### 希尔排序 ### 更加的序列 ================================================ FILE: booknotes/string.md ================================================ # 串 ### ADT ### 串匹配 ### 蛮力匹配 ### KMP算法 ### BM_BC算法 ### Krap-Rabin算法 ================================================ FILE: booknotes/sum.md ================================================ # 归纳整理 ### 数据结构(Data Structure) - 数组(Array):物理上紧邻的定长线性序列(元素为数) - 向量(Vector):物理上紧邻的一组不定长线性序列(元素不限) - 列表(List):逻辑上紧邻的一组线性序列 - 栈(Stack):受限的列表(一端出入) - 队列(Queue):受限的列表(一端出一端入) - 树(Tree):成树结构的半线性序列 - 图(Graph):成图结构的非线性序列 ### STL序列容器(Sequence Contains) - 定长数组(Array) - 向量(Vector) - 列表(双向链表)(List) - - 单链表(sList):非标准STL - 双端队列(Deque) - - 栈(Stack) - - 队列(Queue) ### STL关联容器(Associative Contains) - 红黑树(Red-Black Tree) - - 集合(Set) - - 映射(Map) - - 扩展集合(mutiMap) - - 扩展映射(mutiSet) - 哈希表(HashTable) - - 哈希集合(HashSet) - - 哈希映射(HashMap) - - 哈希集合扩展(mutiHashSet) - - 哈希映射扩展(mutiHashMap) ### 排序查找搜索 - 排序(Sort) - - 起泡排序 - - 选择排序 - - 归并排序 - - 插入排序 - - 堆排序 - - 桶排序 - - 基数排序 - - 快速排序 - - 希尔排序 - 查找(Find) - - 扫描查找 - - 二分查找 - - fib查找 - 搜索(Search) - - 广度搜索 - - 深度搜索 ================================================ FILE: booknotes/superBST.md ================================================ # 高级搜索树 ### 伸展树 #### 伸展树 - 局部性:刚被访问的数据,极有可能很快的再次被访问,这一现象在信息处理过程中屡见不鲜 - 连续m次查找( m >>n = | BST | ) 时间 O(mlogn) - 逐层伸展:使用zig,zag操作,节点一旦被访问,随即转移至树根,一步一步往上爬,自下而上,逐层单旋 - 最坏情况:旋转次数n,每个周期累计最坏n^2,分摊n^2 #### 双层伸展 - 构思精髓:向上追溯两层,而非一层 - 反复考察祖孙三代:g = parent(p), p = parent(v), v - 根据它们的相对位置,经两次旋转使得v上升两层,成为子树根 - zig-zag/zag-zig:等效AVL双旋 - zig-zig/zag-zag:从祖父开始旋转,旋转两次 #### 实现 ``` template class Splay : public BST { protected: BinNodePosi(T) splay( BinNodePosi(T) v); //将v伸展至根 public: //伸展树的查找也会引起整数的结构 BinNodePosi(T) & search( const T & e); //查找 BinNodePosi(T) insert( cosnt T & e); //插入 bool remove( const T & e); //删除 }; ``` ### B-树 #### 动机:实现高效的IO > 越来越小的内存 > 物理上,容量越大,访问速度越小 - 高速缓存 - - 事实1:不同容量存储器,访问速度差异大 磁盘与内存 ms/ns > 10^5, 一秒之于一天 - - 事实2:从磁盘中读入1B,与读写1KB几乎一样快,习惯式批量式访问,以页和块为单位 #### B树 - 特征:不限于2个孩子,底层都位于同一高度,又宽又矮 - 定义:多路搜索树,适当合并,每2代合并4路。d代合并m = 2^d路,m-1个关键码 - 逻辑:与BBST完全等价 - 应用:多级存储系统中使用B树,可针对外部查找,大大减少I/O次数 - 原理:充分利用外存对批量访问的高效支持,每下降一层,都以超级节点为单位,读入一组关键码 - 具体:视磁盘的数据块大小而定而定,m = key/pg, m = 200 ~ 300 - 结构:m阶B树,m路平衡搜索树(m >= 2), 外部节点的深度统一相等,叶节点的深度统一相等 - 阶数:内部节点各有,不超过m-1个关键码,不超过m个分支,内部节点的分支数n+1也不能太少,树根 2<= n+1 - 表示:紧凑表示,将引用表示成一个点,省略掉外部节点 #### 实现 ### 红黑树 #### 动机 - 一致性结构 - - Persistent structure:支持对历史版本的访问 ``` T.search(ver, key); T.insert(ver, key); T.remove(ver, key); ``` - - 蛮力实现:每个版本独立保存,各个版本入口自成一个搜索结构 - - 单次操作O(logn+logn),累计O(h+n)时间空间 - - 优化:复杂度控制在O(n * logn) - - 重构:大量共享,少量更新:每个版本的新增复杂度,仅为O(logn) - - 结论: 相邻版本的差异不超过O(1) - - 需要:任何动态操作都控制在O(1)范围内 #### 红黑树 - 由红黑两类节点组成的BST - 统一增设外部节点,使之为真二叉树 - 定义: - - 树根:必为黑色 - - 外部节点:均为黑色 - - 其余节点:若为红,只有黑孩子,红之子父都为黑 - - 外部节点到根:途中黑节点数目相等 - (2, 4)树 == 红黑树 - - 提升各红节点,使之与黑父亲等高--于是每课红黑树,都对应一颗(2,4)树 - - 将黑节点与其红孩子视作超级节点 - - 无非四种组合,分别对应4阶B树的一类内部节点 - 红黑树属于BBST - - 由等价性,既然B树是平衡的,红黑树自然也是 - - 证明: #### 实现 ``` template class RedBlack: public BST { public: BinNodePosi(T) insert( const T & e); //插入重写 bool remove( const T % e); // 删除重写 protected: void solveDoubleRed( BinNodePosi(T) x); //双红修正 void solveDoubleBlack( BinNodePosi(T) x); //双黑修正 int updateHeight( BinNodePosi(T) x); //更新节点高度 } ``` ================================================ FILE: booknotes/tree.md ================================================ # 二叉树(BinTree) > 半线性结构,二维的列表,特殊的图 ### 树(tree) - 有根树:指定任一节点r 属于 V作为根后,T即称有根树(rooted tree) - 有序树: - - 子树树根称孩子,同一父亲的子树之间称兄弟 - - 关系:边数 = 所有定点度数之和 = 所有顶点-1 = O(n) - - 定义:指定孩子的顺序,称T为有序数 - 路径环路: - - k条边依次相连,构成一条路径(path) - - 长度:边的数目 - - 环路:其中的某个顶点短路 - 连通无环: - - 连通图:节点之间均有路径(边数多) - - 无环图:不含环路(边数少) - 树与图:无环连通图,任何节点与根之间存在唯一路径,每个顶点都有了一个长度path(V) - 深度层次: - - 路径节点子树可以相互指代 - - 深度:depth(v) = | path(v) | - - 祖先后代:路径上的节点均为v的祖先,v是它们的后代 - - 真祖先后代:除开自己的 - - 半线性:任一深度,祖先唯一,后代未必唯一 - - 根:所有节点的公共祖先,深度为0,无祖先 - - 叶子:没有后代的节点,出度为0 - - 高度:所有叶子深度的最大值称树的高度,空树(一个节点没有)的高度为-1 ### 树的表示 - 接口: 节点 | 功能 ---|--- root() | 根节点 parent() | 父节点 firstChild() | 长子 nexrSibling() | 兄弟 insert(i, e) | 第i个孩子插入 remove(i) | 删除第i个孩子 traverse() | 遍历 - 父节点实现: rank | data | parent ---|---|--- 0 | A | -1 1 | B | 0 2 | C | 0 3 | D | 0 4 | E | 1 5 | F | 1 6 | G | 3 7 | H | 6 8 | I | 6 9 | J | 6 ``` //空间性能: O(n) //时间性能 //parent(): O(1) //root(): O(n)或O(1) //firstChild(): O(n) //不好 //nextSibling(): O(n) //不好 ``` - 子节点实现: rank | data | children ---|---|--- 0 | A | 35 1 | B | -1 2 | C | -1 3 | D | -1 4 | E | 012 5 | F | -1 6 | G | 789 7 | H | -1 8 | I | -1 9 | J | -1 ``` //空间性能: O(n) //时间性能 //parent(): O(n) //不好 //root(): O(n)或O(1) //firstChild(): O(1) //nextSibling(): O(1) ``` - 组合实现: rank | data | parent | children ---|---|---|--- 0 | A | 4 | 35 1 | B | 4 | -1 2 | C | 4 | 6 3 | D | 0 | -1 4 | E | -1 | 012 5 | F | 0 | -1 6 | G | 2 | 789 7 | H | 6 | -1 8 | I | 6 | -1 9 | J | 6 | -1 ``` //空间性能: O(n) //时间性能 //parent(): O(1) //root(): O(n)或O(1) //firstChild(): O(1) //nextSibling(): O(1) //不好 ``` - 长子兄弟法:设2个引用,纵firstChild(), 横nextSibling() ### 二叉树(binary tree):节点度数不超过2 - 左右孩子:lChild-->lSubTree,rChild-->rSubtree隐含了树的有序性 - 基数:深度为k的节点,至多2^k个,含n个节点,高度为h的二叉树 h < n < 2^(h+1) - 满树:顶点树最大,饱和状态,宽度2^h - 度与节点:0度叶子,1度单分支,2度双分支 - 真二叉树:所有节点度数为0或2,补全1度节点(假想策略) - 描述二叉树:二叉树是多叉树的特例,有根有序时能力足以覆盖后者 - 多叉树化二叉树 ``` 1. 长子兄弟法 2. 向左45度旋转 ``` ### 二叉树实现 - 节点实现(BinNode) ``` #define BinNodePosi(T) BinNode* template struct BinNode { BinNodePosi(T) parent, lChild, rChild; //父亲孩子 T data; //数据 int height; //高度 int size(); //规模 BinNodePosi(T) insertAsLc(T const &); //插入左子 BinNodePosi(T) insertAsRc(T const &); //插入右子 BinNodePosi(T) succ(); //(中序)后继 template void travLevel( VST & ); //层次遍历 template void travIn( VST & ); //中序遍历 template void travPost( VST & ); //后序遍历 } //O(1) //插入左子 template BinNodePosi(T) BinNode::insertAsLc(T const &) { return lChild = new BinNode( e, this); } //插入右子 template BinNodePosi(T) BinNode::insertAsRc(T const &) { return rChild = new BinNode( e, this); }//O(1) //规模 template int BinNode::size() { int s = 1; if (lChild) s += lChild->size(); if (rChild) s += rChild->size(); return s; }//O(n) ``` - 二叉树实现接口(BinTree) ``` #define stature ((p) ? (p)->height : -1) template class BinTree { protected: int _size; //规模 BinNodePosi(T) _root; //根节点 virtual int updateHeight( BinNodePosi(T) x ); void updateHeightAbout( BinNodePosi(T) x ); public: int size() const { return _size; } bool empty() const { return _root; } BinNodePosi(T) root() const { return _root; } //接入删除分离 //遍历 } ``` - 更新高度 ``` template int BinTree::updateHeight( BinNodePosi(T) x ) { return x->height = 1 + max( stature(x->lChild), stature(x->rChild) ); } template void BinTree::updateHeightAbout( BinNodePosi(T) x ) { while (x) { updateHeight(x); x = x->parent; } } ``` - 节点插入 ``` template BinNodePosi(T) BinTree::insertAsRC( BinNodePosi(T) x, T const &e){ _size++; x->insertAsRC(e); updateHeightAbout(x); return x->rChild; } ``` ### 先序遍历 *不要从轮子造起,利用之前的工作* - 按照某种次序访问,每个节点被访问恰好一次 - 遍历结果:先序,中序,后序 - 区别:局部的根节点的访问顺序 ``` 先序:V --> L --> R 中序:L --> V --> R 后序:L --> R --> V //左子树总是在右子树之前 ``` - 递归实现: ``` template void traverse( BinNodePosi(T) x, VST & visit) { if ( !x ) return; visit( x->data ); //访问根 traverse( x->lChild, visit ); //访问左子树 traverse( x->rChild, visit ); //访问右子树 } //O(n)渐进的 ``` - 改进1(迭代) ``` template void travPre_I1( BinNodePosi(T) x, VST & visit) { Stack S; //辅助栈 if ( x ) //根入栈 S.push(x); while ( !S.empty() ) { x = S.pop(); //出栈并访问当前节点 visit( x->data ); if( HasRChild( *x ) ) //右孩子先进后出 S.push( x->rChild ); if( HasLChild( *x ) ) //左孩子先出后进 S.push( x->lChild ); } } //无法推广 ``` - 改进2(左侧下行迭代) ``` template void travPre_I2( BinNodePosi(T) x, VST & visit ) { Stack S; //辅助栈 while (true) { //以右子树为单位,逐批访问节点 visitAlongLeftBranch(x, visit, S); if( S.empty() ) //栈空即退出 break; x = S.pop(); //弹出下一个子树的根 } //pop = push = visit = O(n) = 分摊O(1) } template static void visitAlongLeftBranch( BinNodePosi(T) x, VST & visit, Stack & S) { while (x) { visit( x->data ); S->pash( x->rChild ); //右孩子入栈 x = x->lChild; //沿左侧下行 } } ``` ### 中序遍历 - 递归实现 ``` template void traverse( BinNodePosi(T) x, VST & visit) { if ( !x ) return; traverse( x->lChild, visit ); //访问左子树O(a) visit( x->data ); //访问根O(1) traverse( x->rChild, visit ); //访问右子树O(n-1-a) } //O(n)渐进的 ``` - 改进:左侧下行迭代 ``` template void travIn_I2( BinNodePosi(T) x, VST & visit ) { Stack S; //辅助栈 while (true) { //以右子树为单位,逐批访问节点 goAlongLeftBranch(x, visit, S); if( S.empty() ) //栈空即退出 break; x = S.pop(); visit( x->data ); //立即访问 x = x->rChild; //转向右子树 } //pop = push = visit = O(n) = 分摊O(1) } template static void goAlongLeftBranch( BinNodePosi(T) x, VST & visit, Stack & S) { while (x) { S->pash( x->rChild ); //右孩子入栈 x = x->lChild; //沿左侧下行 } }//每一个节点都只有一个入栈动作,实际只有O(n)复杂度,分摊分析,优于递归 ``` ### 层次遍历:借助队列 ``` template void traverse( VST & visit) { Queue Q; //辅助栈 Q.enqueue( this ); while ( !Q.empty() ) { BinNodePosi(T) x = Q.dequeue(); //出列并访问当前节点 visit( x->data ); if( HasLChild( *x ) ) //左孩子先进先出 Q.enqueue( x->lChild ); if( HasRChild( *x ) ) //右孩子后进后出 Q.enqueue( x->rChild ); } } ``` ### 重构:已知三种遍历序列其中2种还原二叉树 - 中序 + 先序/后序:数学归纳法 ``` 证明: preorder: r -> [L] -> [R] inorder: [L] -> r -> [R] postorder:[L]->[R] -> r 定位r,判断左右子树,递归实现 A B C D E F 先序: A B D C E F 中序: D B A E F C 后序: D B F E C A 先+中 1. root:A L:DB R:EFC 2. root:B L:D, root:C , root:C L:EF 3. root:E R:F 后+中 1. root:A L:DB R:EFC 2. root:C L:EF, root:B L:D 3. root:E R:E //技巧,先序后序确定根,中序确定左右分支 ``` - 先序 + 后序 + 真二叉树: ``` A B C D E F G H I 先序: A B D E C F G H I 后序: D E B F H I G C A 1. root: A L: BDE R:CFGHI 2. root: B L: D R:E, root:C L:F R:GHI 3. root: G L: H R:I ``` ================================================ FILE: booknotes/vector.md ================================================ # 向量(Vector) ### 接口与实现 > 抽象数据类型(ADT:Abstract Data Type) = 数据模型 + 一组操作 > 数据结构(DS:Data Structure) = 基于某种特定语言 + 实现ADT的一整套算法 - 数组:每个元素由编号唯一指代,并可以直接访问,亦称为线性数组 - 向量:数组的抽象和泛化,由一组元素按线性次序封装而成 ``` 1)个元素与[0,n)整数一一对应,称成秩(RANK) 2)元素类型不限于基本类型 3)操作,管理,维护,更加简化安全 4)可以为便捷的参与更加复杂的操作定制 ``` - 模板:灵活指定类型,利用组成更复杂的数据结构 ``` template Vector; Vector < int > myvertor; Vector forest; ``` - ADT接口:丰富的操作接口 操作 | 功能 ---|--- size() | 向量的规模 get(r) | 获取秩为r的元素 put(r,e) | 用e替换秩为r的元素 insert(r,e) | e作为秩为r的元素插入,原后继元素后移 remove(r) | 剔除秩为r的元素 disordered() | 判断所有元素是否已按非降序排列 sort() | 调整元素位置,使之按非降序排列 find(e) | 找到目标元素e放回秩 deduplicate() | 剔除重复元素 traverse() | 遍历所有元素 ``` typedef int Rank; //秩 #define DEFAULT_CAPACITY 3 //默认容量 template class Vector{ private: Rank _size; //规模 int _capacity; //容量 T* _elem; //数据区 protected: //内部函数 public: //构造函数 Vector(int c = DEFAULT_CAPACITY){ _elem = new T[_capacity = c]; _size = 0; } //默认 Vector(T const *A, Rank lo, Rank hi) { copyFrom(A, lo, hi); } //数组区间复制 Vector(Vector const& V, Rank lo, Rank hi) { copyFrom(V._elem, lo, hi); } //向量区间复制 Vector(Vector const& V) { copyFrom(V._elem, 0, V._size); } //向量整体复制 //析构函数 ~Vector() { delete [] _elem; } //只读接口 //可写接口 //遍历接口 } //复制 template void Vector::copyFrom(T* const A, Rank lo, Rank hi) { _elem = new T[_capacity = 2*(hi - lo)]; //分配空间,预留2倍的空间 _size = 0; //规模清零 while (lo < hi) { _elem[_size++] = A[lo++]; } //元素逐一复制[0, hi-lo) } //扩容 template void Vector::expand() { if(_size < _capacity) return; //尚满,不扩 _capacity = max(_capacity, DEFAULT_CAPACITY); //不低于最小容量 T* oldElem = _elem; _elem = new T[_capacity <<= 1]; //容量加倍 for (int i = 0; i < _size; ++i) //复制原向量内容 _elem[i] = oldElem[i]; // = 重载了的 delete [] oldElem; //释放原空间 } ``` ### 可扩充向量:可能出现上溢(overflow)或者下溢(underflow) > 上溢:不足以存放所有元素 ,空间不足 > 下溢:寥寥无几,装填因子:_size/_capacity << 50%,空间效率低 - 蝉的哲学:每生长一段时间,蜕掉外壳,生成新的壳 - 即将上溢时适当的增加容量 - 得益于向量的封装,扩容后数据区的指针改变了,但不至于出现野指针 - 容量加倍策略:成本好于容量递增策略 ``` 复杂度:最坏情况,在初始容量为1的满容量中,连续插入n = 2^m 当n = 1,2,4,8,16....时扩容 空间上损失换取时间上的巨大收益 ``` 策略 | 递增策略 | 加倍策略 ---|---|--- 累计增容时间 | O(n^2) | O(n) 分摊增容时间 | O(n) | O(1) 装填因子 | 约100% | >50% > 平均复杂度:加权平均数,独立的考察平均程度 > 分摊分析:整体的考虑,连续的足够多次操作,总体成本分摊到单次操作,更加准确分析数据结构和算法成本 ### 无序向量: - 元素的访问:沿用下标式操作,对下标操纵符进行重载 ``` template T & Vector::operator[](Rank r) const { return _elem[r]; } //循秩访问 ``` - 插入:1.扩容2.后移(从后开始)3.赋值4.规模+1 ``` template Rank Vector::insert(Rank r, T const & e) { expand(); //若满,扩容 for(int i = _size; i > r; i--) _elem[i] = _elem[i-1]; //原r后的整体元素后移一位(后开始) _elem[r] = e; //r处赋值 _size++; //规模加一 return r; //返回秩 } ``` - 删除:1.单独处理2.前移(从前开始)3.更新规模4.缩容 ``` template // 删除区间hi-lo int Vector::remove(Rank lo, Rank hi) { if (lo == hi) return 0; //单独处理退化 while (hi < _size) _elem[lo++] = _elem[hi++]; //整体前移一段(前开始) _size = lo; shirnk(); //缩容 return hi - lo; } ``` - 单元素删除:调用多元素删除 ``` template T Vector::remove(Rank r) { T e = _elem[r]; remove(r, r+1); return e; } ``` - 查找:无序向量,默认重载判等和比较操纵符,逆向扫描 ``` template Rank Vector::find(T const & e, Rank lo, Rank hi) const { while ((lo < hi--) && e != _elem[hi]) //逆向查找 return hi; } //最坏O(n)最好O(1) 输入敏感 ``` - 无序向量唯一化:剔除重复的元素 ``` template int Vector::deduplicate() { int oldSize = _size; Rank i = 1; //从第二个元素开始 while (i < _size) //由前向后逐步考查 (find(_elem[i], 0, i) < 0) ? i++ : remove(i); //删除雷同者 return oldSize - _size; //删除的总数 } //成本:O(n^2) //优化 ``` - 遍历:visit操作 ``` //使用函数指针局部修改 template void Vector::traverse(void (*visit)(T&)) { for (int i = 0; i < _size; i++) visit(_elem[i]); } //使用函数对象 template template void Vector::traverse(TSV & visit)) { for (int i = 0; i < _size; i++) visit(_elem[i]); } ``` ### 有序向量:唯一化 - 相邻逆序对数目可以来度量向量的逆序程度 ``` template int Vector::disordered() const { int n = 0; for (int i = 0; i < _size; i++) //逐一检查各对相邻元素 n += (_elem[i - 1] > _e[i]); //逆序则计数向量有序 return n; //当且仅当n=0时 } //只判断是否有序,首次遇到逆序对直接终止 ``` - 唯一化:低效与高效算法 ``` template int Vector::uniquift() { int oldSize = _size; int i = 0; while (i < _size-1) //雷同删除后者 (_elem[i] == _elem[i+1]) ? remove(i+1) : i++; return oldSize - _size; } //最坏情况:O(n^2) 省去了find但竟然与无序向量竟然相同,低效算法 //反思:每个元素都多次进行多次前移 //改进:成批的删除(移动覆盖删除) template int Vector::uniquift() { Rank i = 0, j = 0; //相邻互异元素 while(++j < _size) //跳过雷同者,不同者紧靠前者右侧 if(_elem[i] != _elem[j]) _elem[++i] = _elem[j]; _size = ++i; shirnk(); return j - i; } //常数迭代时间O(n) ``` ### 有序向量:二分查找 ``` template int Vector::search(T const & e, Rank lo, Rank hi) { return (rand() % 2) ? binSearch(_elem, e, lo, hi) : fibSearch(_elem, e, lo, hi); } ``` - 语义约定:利于有序向量的自身的维护V.insert(1+search(e), e) ``` 约定:在有序向量区间V[lo,hi)中,确定不大于e的最后一个元素 失败:若 < V[lo] 则返回lo-1 若 > V[hi-1] 则返回hi-1 重复:插入到不同的上一位 ``` - 二分查找:折半查找,减而治之 ``` 1)减而治之,以任一元素x=S[mi]为届,将带查找区间分三部分S(在[lo,mi) <= S[mi] <= S[mi,hi] 2)将目标元素e与x作比较,分三种情况处理 1. e < x : 必属左侧子区间,递归深入 2. e > x : 必属右侧子区间,递归深入 3. e = x : 命中目标,随即返回 3)二分折半策略:轴点mi总是取作中点,每经过最多2次比较,或者命中或者将规模缩减至半 //二分查找 template static Rank binSearch(T * A, T const &e, Rank lo, Rank hi) { while (lo < hi) { Rank mi = (lo + hi) >> 1; if (e < A[mi]) hi = mi; //三种情况 else if ( A[mi] < e) lo = mi + 1; else return mi; } return -1; //查找失败 } //复杂度分析 //递推分析:T(n) = T(n/2) + O(1) = O(log(n)) //递归跟踪:递归深度log(n),每次O(1),总的O(log(n)) //查找长度:关键码的比较次数 //精确的为:1.5log(n) ``` ### 有序向量:fibonacci查找 > 二分查找的改进,转向左,右分支前的关键码比较次数不等,递归深度不同,对转向成本进行补偿 ``` //fib查找 template static Rank fibSearch(T * A, T const &e, Rank lo, Rank hi) { Fib fib(hi - lo); //创建fib数列 while(lo < hi) { while (hi - lo < fib.get()) fib.prev(); //向前查找确定fib(k)-1的轴点 Rank mi = lo + fib.get() - 1; //切分 if (e < A[mi]) //前半段 hi = mi; else if (A[mi] < e) lo = mi + 1;//后半段 else return mi; //命中 } return -1; } //时间复杂度:O(log(n)) //精确复杂度:< O(1.5log(n)) 优于二分查找 ``` - 最优轴点:二分查找对应0.5,fibonacci查找对应的0.6180339黄金分割比 ### 有序向量:改进二分查找,缩短长度到1,算法更加稳定 ``` 左右分支不平衡问题 解决方案:只设置两个区间 1. e < x ,若e存在必属S[lo, mi),递归深入 2. x <= e, 若e存在必属S[mi, hi),递归深入 当hi - lo = 1时,判断是否命中 //二分查找B template static Rank binSearch(T * A, T const &e, Rank lo, Rank hi) { while (1 < hi - lo) { Rank mi = (lo + hi) >> 1; (e < A[mi]) ? hi = mi : lo = mi; } return (e == A[mi]) ? lo : -1; } //复杂度分析:最好的情况更坏,更坏的情况更好,稳定性高 //严格兑现了语义约定:多个命中元素,返回最靠右的 //失败时,返回小于e的最大者 //二分查找C template static Rank binSearch(T * A, T const &e, Rank lo, Rank hi) { while (lo < hi) { Rank mi = (lo + hi) >> 1; (e < A[mi]) ? hi = mi : lo = mi + 1; } return --lo; } ``` ### 有序向量:插值查找(以后研究) - 均匀独立的随机分布 ### 起泡排序 ``` //排序接口 template void Vector::sort(Rank lo, Rank hi) { switch (rand() % 5) { case 1: bubbleSort(lo, hi); break; //起泡排序 case 2: selectSort(lo, hi); break; //选择排序 case 3: mergeSort(lo, hi); break; //归并排序 case 4: heapSort(lo, hi); break; //堆排序 case 5: quickSort(lo, hi); break; //快速排序 } } //起泡排序(改进版) template void Vector::bubbleSort(Rank lo, Rank hi) { while (!bubble(lo, hi--)); //扫描直至全序 } template bool Vector::bubble(Rank lo, Rank hi) { bool sorted = true; //有序标志 while (++lo < hi) //整体扫描 if (_elem[lo - 1] > _elem[lo]) { //若存在逆序 sorted = false; //整体尚未有序的 swap(_elem[lo - 1], _elem[lo]); //交换 } return sorted; //返回序标 } //复杂度:O(n^2) 改进节省相当多的时间(三角形变梯形),依然有改进空间 //改进后可以使之为O(n^1.5) //再次改进 //起泡排序(再次改进) template void Vector::bubbleSort(Rank lo, Rank hi) { while (lo < ( hi = bubble(lo, hi) ) ); //扫描直至全序 } template Rank Vector::bubble(Rank lo, Rank hi) { Rank last = lo; while (++lo < hi) if (_elem[lo - 1] > _elem[lo]) { last = lo; swap(_elem[lo - 1], _elem[lo]); } return sorted; } //省去更多的时间,跳过有序的部分,最好的情况一样O(n),最坏的情况依然是O(n^2) ``` - 稳定性:重复的元素在输入,输出相对的次序,是保持不变的 - 起泡排序也是稳定的,元素a,b的相对位置发生变化,只有一种可能: - 1)分别与其他元素交换,二者相互接近和相邻 - 2)接下来的一轮扫描交换中,二者因逆序而交换位置 ### 归并排序:基于**分治策略**(递归分解) > 基于的比较排序:存在的上下界,O(n2) ---bubbleSort-----------mergeSort--> O(nlogn) - 二路归并算法原理: ``` 序列1:21 - 13 - 8 - 5 序列2:29 - 19 - 4 - 2 归并: 2 - 4 - 5 - 8 - 13 - 19 - 21 - 29 ``` ``` //归并排序 template void Vetor::mergeSort(Rank lo, Rank hi) { if (hi -lo < 2) return; //处理递归基,单元素区间自然有序 int mi = (lo + hi) >> 1; //中心点 mergeSort(lo, mi); //前端递归 mergeSort(mi, hi); //后段递归 merge(lo, mi, hi); //归并 } template void Vector::merge(Rank lo, Rank mi, Rank hi) { T * A = _elem + lo; //合并后的向量 int lb = mi - lo; //前子向量 T * B = new T[lb]; //复制前子向量 for (Rank i = 0; i < lb; B[i] = A[i++]) ; int lc = hi - mi; //后子向量 T * C = _elem + mi; //B[j]和C[k]小者转移A末尾 for (Rank i = 0, j = 0, k = 0; (j < lb) || (k < lc); ) { if( (j < lb) && (lc <= k) || (B[j] <= C[k]) ) A[i++] = B[j++]; if( (k < lc) && (lb <= j) || (C[K] <= B[j]) ) A[i++] = C[k++]; } //循环紧凑,效率不如拆分 delete [] B; } //正确性: //复杂度:for (...; (j < lb) || (k < lc); ) { if() { A[i++] = B[j++] ; } if() { A[i++] = C[k++] ; } } for循环为主要消耗: j + k = n 总迭代不过O(n)线性时间 总的 T(n) = 2T(n/2) ==> O(nlogn) 最坏情况下 ``` ================================================ FILE: package.json ================================================ { "name": "suo-blog", "version": "1.0.0", "main": "index.js", "repository": "https://github.com/suoyuesmile/suo-blog.git", "author": "shaosuo ", "license": "MIT", "scripts": { "dev": "tsc --build tsconfig.json" }, "dependencies": { "@babel/core": "^7.12.3", "@babel/preset-env": "^7.12.1", "@babel/traverse": "^7.12.1", "babel": "^6.23.0", "babel-core": "^6.26.3", "babylon": "^6.18.0", "crypto-js": "^4.0.0", "formidable": "^1.2.2", "koa": "^2.12.0", "ky": "^0.20.0", "node-forge": "^0.9.1", "request": "^2.88.2", "ts-node": "^8.9.1", "typescript": "^3.8.3" }, "devDependencies": { "babel-preset-env": "^1.7.0" } } ================================================ FILE: public/html/demo-box-model.html ================================================
    ================================================ FILE: public/html/demo-display.html ================================================



        ================================================ FILE: public/html/demo-float.html ================================================ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus imperdiet, nulla et dictum interdum, nisi lorem egestas odio, vitae scelerisque enim ligula venenatis dolor. Maecenas nisl est, ultrices nec congue eget, auctor vitae massa ================================================ FILE: public/html/demo-position.html ================================================ }
        ================================================ FILE: public/html/layout.css ================================================ .main { width: 100px; margin: 0 auto; } ================================================ FILE: src/README.md ================================================ ================================================ FILE: src/algorithm/array/insert.js ================================================ /** * insert el into array * @param {Array} arr * @param {Number} targetIndex * @param {Number} target * @return null */ function insert(arr, targetIndex, target) { var i = arr.length while (i-- > targetIndex) { arr[i + 1] = arr[i] } arr[targetIndex] = target return arr } console.log(insert([1, 2, 4, 5], 4, 3)) ================================================ FILE: src/algorithm/array/searchInsert.js ================================================ /* * @lc app=leetcode.cn id=35 lang=javascript * * [35] 搜索插入位置 * * https://leetcode-cn.com/problems/search-insert-position/description/ * * algorithms * Easy (44.77%) * Likes: 398 * Dislikes: 0 * Total Accepted: 104K * Total Submissions: 232.2K * Testcase Example: '[1,3,5,6]\n5' * * 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 * * 你可以假设数组中无重复元素。 * * 示例 1: * * 输入: [1,3,5,6], 5 * 输出: 2 * * * 示例 2: * * 输入: [1,3,5,6], 2 * 输出: 1 * * * 示例 3: * * 输入: [1,3,5,6], 7 * 输出: 4 * * * 示例 4: * * 输入: [1,3,5,6], 0 * 输出: 0 * * */ // @lc code=start /** * @param {number[]} nums * @param {number} target * @return {number} */ var searchInsert = function(nums, target) { var hi = nums.length - 1, lo = 0 // 2.迭代,换界 while (hi >= lo) { var mi = (hi - lo) >>> 1 if (target < nums[mi]) { hi = mi - 1 } else if (nums[mi] < target) { lo = mi + 1 } else { return mi } } } searchInsert([1, 2, 4, 5], 3) // @lc code=end ================================================ FILE: src/algorithm/search/binsearch.js ================================================ var arr = [1, 3, 5, 6] var target = 5 function binSearch(target, arr) { // 1.定界 var hi = arr.length - 1, lo = 0 // 2.迭代,换界 while (hi - lo >= 1) { var mi = Math.floor((hi + lo) / 2) if (target < arr[mi]) { hi = mi } else if (arr[mi] < target) { lo = mi } else { return mi } } } console.log(binSearch(target, arr)) ================================================ FILE: src/algorithm/sort/bubblesort.js ================================================ /** * 冒泡排序 * bubblesort * @param {Array} Array * @return {Array} */ function bubble(arr) { for (let i = 0; i < arr.length; i++) { for (let j = 0; j < arr.length - i; j++) { var temp if (arr[j + 1] > arr[j]) { temp = arr[j + 1] arr[j + 1] = arr[j] arr[j] = temp } } } return arr } // 为什么 j 到 arr.length 就可以了 // 因为 i 到 arr.length 已经复位了 // 复杂度 O(n2) 不稳定排序 ================================================ FILE: src/algorithm/sort/quicksort.js ================================================ var originArr = [2, 3, 5, 7, 1, 4, 6, 9, 8, 0] var quickSort = function(arr) { var pivotIndex, // 轴点索引 pivot, // 轴点 leftArr = [], // 轴点左边数组 rightArr = [], // 轴点右边数组 i // for循环索引 // 1.平凡解 if (arr.length <= 1) { return arr } // 2.确定轴点 pivotIndex = Math.floor(arr.length / 2) pivot = arr.splice(pivot, 1)[0] // 3.分组 for (i = 0; i < arr.length; i++) { if (arr[i] < pivot) { leftArr.push(arr[i]) } else { rightArr.push(arr[i]) } } // 4.递归 return quickSort(leftArr).concat(pivot, quickSort(rightArr)) } console.log(quickSort(originArr)) // 最差:O(n2) // 平均:O(nlgn) ================================================ FILE: src/algorithm/string/repeat.js ================================================ function repeat(o, n) { if (n == 1) return o let half = Math.ceil(n / 2); return repeat(o, half) + repeat(o, n - half) } console.log(repeat('abc', 5)); // 输出连续n个字符串 ================================================ FILE: src/babel/tiny-compiler/index.js ================================================ // input (add 2 (sub 4 2)) // output // 词法分析 function tokenizer(input) { let current = 0; let tokens = []; while (current < input.length) { let char = input[current]; if (char === '(') { tokens.push({ type: 'paren', value: '(' }) current++; continue; } if (char === ')') { tokens.push({ type: 'paren', value: ')' }) current++; continue; } let WHITESPACE = /\s/; if (WHITESPACE.test(char)) { current++; continue; } let NUMBERS = /[0-9]/; if (NUMBERS.test(char)) { let value = ''; while (NUMBERS.test(char)) { value += char; char = input[++current]; } tokens.push({ type: 'number', value }) continue; } if (char === '"') { let value = ''; char = input[++current]; while (char !== '"') { value += char; char = input[++current]; } char = input[++current]; tokens.push({ type: 'string', value }) continue; } let LETTERS = /[a-z]/i if (LETTERS.test(char)) { let value = ''; while (LETTERS.test(char)) { value += char; char = input[++current]; } tokens.push({ type: 'name', value }) continue; } throw new TypeError('I dont know what this character is: ' + char); } return tokens; } // 解析 function parsing(tokens) { let current = 0; function walk() { let token = tokens[current]; if (token.type === 'number') { current++; return { type: 'NumberLiteral', value: token.value, }; } if (token.type === 'string') { current++; return { type: 'StringLiteral', value: token.value } } if (token.type === 'paren' && token.value === '(') { token = tokens[++current]; let node = { type: 'CallExpression', name: token.value, params: [], } token = tokens[++current]; while ((token.type !== 'paren') || (token.type === 'paren' && token.value !== ')')) { node.params.push(walk()); token = tokens[current]; } current++; return node; } throw new TypeError(token.type) } let ast = { type: 'Program', body: [], } while (current < tokens.length) { ast.body.push(walk()); } return ast; } // 深度优先访问 function traverse(ast, visitor) { function traverseArray(array, parent) { array.forEach(child => { traverseNode(child, parent); }); } function traverseNode(node, parent) { let methods = visitor[node.type]; if (methods && methods.enter) { methods.enter(node, parent); } switch (node.type) { case 'Program': traverseArray(node.body, node); break; case 'CallExpression': traverseArray(node.params, node); break; case 'NumberLiteral': case 'StringLiteral': break; default: throw new TypeError(node.type); } if (methods && methods.exit) { methods.exit(node, parent); } } traverseNode(ast, null); } // 转换 function transformer(ast) { let newAst = { type: 'Program', body: [] } ast._context = newAst.body; traverse(ast, { NumberLiteral: { enter(node, parent) { parent._context.push({ type: 'NumberLiteral', value: node.value }) } }, StringLiteral: { enter(node, parent) { parent._context.push({ type: 'StringLiteral', value: node.value }) } }, CallExpression: { enter(node, parent) { let expression = { type: 'CallExpression', callee: { type: 'Identifier', name: node.name }, arguments: [] } node._context = expression.arguments; if (parent.type !== 'CallExpression') { expression = { type: 'ExpressionStatement', expression: expression }; } parent._context.push(expression); } } }); return newAst; } // 代码生成 function codeGenerator(node) { switch (node.type) { case 'Program': return node.body.map(codeGenerator).join('\n'); case 'ExpressionStatement': return (codeGenerator(node.expression) + ';'); case 'CallExpression': return (codeGenerator(node.callee) + '(' + node.arguments.map(codeGenerator).join(', ') + ')'); case 'Identifier': return node.name; case 'NumberLiteral': return node.value; case 'StringLiteral': return `"${node.value}"`; default: throw new TypeError(node.type); } } function compiler(input) { const tokens = tokenizer(input); const ast = parsing(tokens); const newAst = transformer(ast); const output = codeGenerator(newAst); return output; } console.log(compiler('(add 5 (sub 4 2))')); ================================================ FILE: src/cryto/sha256.js ================================================ const crypto = require('crypto-js/sha256'); const Base64 = require('crypto-js/enc-base64'); const jsonData = {reqSerialNum: "2020040318241452", agentId: "1000000000000002", memberId: "310000016002378725", photoType: "01" }; // jsonData console.log(JSON.stringify(jsonData) + 'chinapnr'); // checkValue console.log(crypto('{"agentId":"310000015002423502","memberId":"310000016002426182","photoType":"06","reqSerialNum":"1211"}' + 'chinapnr').toString()); // console.log(crypto({"agentId":"310000015002423502","memberId":310000016002426182,"photoType":"06","reqSerialNum":1211}chinapnr, 'chinanpr').toString()); ================================================ FILE: src/css/box-model.html ================================================ box-model
        1
        2
        3
        ================================================ FILE: src/css/center.html ================================================
        水平居中1
        水平居中2
        水平居中3
        ================================================ FILE: src/css/flex.html ================================================ Document
        ================================================ FILE: src/css/float.html ================================================ ================================================ FILE: src/css/hairline.html ================================================
        normal 1px
        hairline
        top hairline
        right hairline
        bottom hairline
        left hairline
        ================================================ FILE: src/css/layout.html ================================================
        ================================================ FILE: src/css/three-layout.html ================================================ ================================================ FILE: src/css/two-layout.html ================================================ ================================================ FILE: src/css/var.html ================================================
        123
        ================================================ FILE: src/data-structure/linklist-circle.js ================================================ // ================================================ FILE: src/data-structure/linklist-curd.js ================================================ const NodeList = function (val) { this.val = val === undefined ? 0 : val; this.next = null; } // 头插法(新结点插在头部) const createByHead = function (nums) { let p = null; let head = new NodeList(null); for (const num of nums) { p = new NodeList(num); p.next = head.next; head.next = p; } return head; } // 尾插法(新结点插在尾部) const createByTail = function (nums) { let head = new NodeList(null); let p = head; for (const num of nums) { s = new NodeList(num); p.next = s; p = p.next; } return head; } // 重置为空 const deleteAll = function (l1) { let p = l1; while(p) { q = p; delete p.next; p = q.next; } } // const l1 = createByHead([1, 3, 5, 6, 7]); // const l2 = createByTail([1, 3, 5, 6, 7]); // console.log(JSON.stringify(l1)); // console.log(JSON.stringify(l2)); // deleteAll(l1); // console.log(JSON.stringify(l1)); // exports.default = { // NodeList, // createByHead, // createByTail, // deleteAll // }; exports.NodeList = NodeList; exports.createByTail = createByTail; ================================================ FILE: src/data-structure/linklist.js ================================================ // 单链表 function ListNode(val) { this.val = val this.next = null } // 生成 // const l1 = new ListNode(1); // l1.next = new ListNode(2); // l1.next.next = new ListNode(3); function create(arr) { let head = null; let p = null; for (const item of arr) { if (p) { p.next = new ListNode(item); p = p.next; } else { head = p = new ListNode(item); } } return head; } function get(list, index) { let p = list; let i = 1; while(p) { if (i == index) { return p; } p = p.next i++; if (!p && index >= i) { throw new Error('过界'); } } } function insertAt(list, index, el) { let p = list; let i = 1; while (p) { if (i === index) { el.next = p.next; p.next = el; } p = p.next; i++; } } function deleteAt(list, index) { let p = list; let i = 1; // 无头结点的操作 if (!index) { list = list.next; return; } while (p) { if (i === index) { p.next = p.next.next; } p = p.next; i++; } } const l1 = create([1, 2, 3]); insertAt(l1, 1, new ListNode(4)); console.log(JSON.stringify(l1)); deleteAt(l1, 1); console.log(JSON.stringify(l1)); deleteAt(l1, 0); console.log(JSON.stringify(l1)); ================================================ FILE: src/data-structure/list.js ================================================ // 单链表 function ListNode(val) { this.val = val this.next = null } var l1 = new ListNode(1) var node2 = new ListNode(2) l1.next = node2 console.log(l1) console.log(l1.next) console.log(l1.next.val) console.log(l1.next.next) abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc ================================================ FILE: src/javascript/array.js ================================================ const arr = [ 1, 3, 5, 7, 9]; const arr2 = [1, [2, 3], [4, 5, 6, 7, [8, 9]]]; const result1 = arr.reduce((prev, current) => prev + current); // 递归 function flat(array) { return array.reduce((prev, current) => prev.concat(Array.isArray(current) ? flat(current) : current), []); } console.log(flat(arr2)); console.log(result1); ================================================ FILE: src/javascript/async_sync.js ================================================ setTimeout(() => { console.log(1) }, 1000) var a = new Promise(() => { console.log(2) b = new Promise(() => { console.log(3) }) }) setTimeout(() => { console.log(4) }) // 2 3 4 1 ================================================ FILE: src/javascript/block-scope.js ================================================ // 块级作用域 for (var index = 0; index < 10; index++) { console.log(index) } console.log(index) // 会影响函数作用域和全局作用域 // with // try/catch try { undefined() } catch (err) { // console.log(1, err) } // console.log(err) // let 改变现状 增强了块级作用域,不会被变量提升 ================================================ FILE: src/javascript/call.js ================================================ var origin = { c: 1000, a() { console.log(this.c) } } var c = 2; // console.log(origin.a()); function d(a, b) { console.log(a, b, this, this.c); } Function.prototype.fakeCall = function(context, ...nums) { if (typeof this !== 'function') { throw new Error(); } if (context == null) { globalThis.fn = this; return globalThis.fn(...nums); } if (typeof context !== 'object') { context = new Object(context); } context.fn = this; const result = context.fn(...nums); delete context.fn; return result; } Function.prototype.fakeApply = function (context, nums) { if (typeof this !== 'function') { throw new Error(); } if (context == null) { globalThis.fn = this; return globalThis.fn(...nums); } if (typeof context !== 'object') { context = new Object(context); } context.fn = this; if (!Array.isArray(nums)) { if (typeof nums === 'object' && nums !== null && nums.length) { // } else { throw new Error(); } } const result = context.fn(args); delete context.fn; return result; } // Function.prototype.fakeBind = function(context, nums) { // if (typeof this !== 'function') { // throw new Error(); // } // context.fn = this // return context.fn(...nums); // } // d(); // d.fakeCall(origin, 1, 2); // d.call(null, 1, 2); // d.fakeCall(null, 2, 2); d.fakeApply(origin, { 0: 2, 1: 2, length: 2 }); // d.apply(origin, { 0: 2, 1: 2, length: 2 }); // d.fakeBind(origin, [1, 2](); ================================================ FILE: src/javascript/callback.js ================================================ // callback function function A() { console.log('I am callback') } function B(callback) { console.log('I am B, I do something!') callback() } B(A) function C(callback) { console.log('I am B, I do something!') callback() } C(function () { console.log('I am callback!') }) ================================================ FILE: src/javascript/class/construct.js ================================================ function FakeClass(val) { this.property = val; this.someFunction = function() { console.log(1); } } FakeClass.prototype.a = 2; FakeClass.prototype.b = function() { console.log(2) } const obj = new FakeClass(2); console.log(FakeClass); ================================================ FILE: src/javascript/class.js ================================================ ================================================ FILE: src/javascript/closure/closure-circle.js ================================================ ================================================ FILE: src/javascript/closure/proxy.js ================================================ function dos() { var pipe = function (value) { var funcStack = []; var oproxy = new Proxy({}, { get: function (pipeObject, fnName) { if (fnName === 'get') { return funcStack.reduce(function (val, fn) { console.log(1); return fn(val); }, value); } // console.log(global.double); funcStack.push(global[fnName]); return oproxy; } }); return oproxy; } global.double = n => n * 2; global.pow = n => n * n; global.reverseInt = n => n.toString().split("").reverse().join("") | 0; // pipe(3).double.pow.reverseInt.get; // 63 console.log(pipe(3).double.pow.reverseInt.get); } dos(); console.log(1, 2); ================================================ FILE: src/javascript/code/huiwen-longest-str.js ================================================ // Input babad // Output bab // isHuiwen // ab function solve(s) { const len = s.length; const middle = len / 2; let i = 0, j = len -1; while (i < middle + 1 && j >= middle - 1) { if (s[i] !== s[j]) { return false; } i++; j--; } return true; } console.log(solve('abac')); ================================================ FILE: src/javascript/code/is-huiwen-num.js ================================================ // Input: 121 // OutPut ture // Input: -121 // OutPut false // Input: 100 // OutPut false // 1 2 1 function solve(x) { let tmp = x; const stack = []; if (x < 0) { return false; } while(tmp) { stack.push(tmp % 10); tmp = Math.floor(tmp / 10); } tmp = x; while (tmp) { if (stack.pop() !== Math.floor(tmp % 10)) { return false; } tmp = Math.floor(tmp / 10) } return true; } console.log(solve(101)); ================================================ FILE: src/javascript/code/is-huiwen-string.js ================================================ // Input babad // Output bab // isHuiwen // ab function solve(s) { const len = s.length; const middle = len / 2; let i = 0, j = len - 1; while (i < middle + 1 && j >= middle - 1) { if (s[i] !== s[j]) { return false; } i++; j--; } return true; } console.log(solve('abac')); ================================================ FILE: src/javascript/code/longest-asc-str.js ================================================ function longestAseStr() {} console.log(longestAseStr([1, 3, 2, 5, 7])); ================================================ FILE: src/javascript/code/longest-norepeat-str.js ================================================ // Input abcadc // Output 4(bcad) // 1 // abc -> set // a // 2 // '' // 3 // abc function solve(s) { const len = s.length; const tmpSet = new Set(); let i = 0, maxlen = 0; while(i < len) { if (!tmpSet.has(s[i]) && i === len - 1) { maxlen = Math.max(tmpSet.size, maxlen); } if (!tmpSet.has(s[i])) { tmpSet.add(s[i]); } else { maxlen = Math.max(tmpSet.size, maxlen); i = i - tmpSet.size; tmpSet.clear(); } i++; } return maxlen; } ================================================ FILE: src/javascript/code/merge-two-array.js ================================================ function mergeTwoArray(l1, l2) { const len1 = l1.length, len2 = l2.length; const newArr = []; let i = 0, j = 0; while(i < len1 || j < len2) { if (l1[i] < l2[j]) { newArr.push(l1[i]); i++ } else { newArr.push(l2[j]); j++ } } return newArr; } console.log(mergeTwoArray([1, 3, 8], [2, 4, 9])); // [1, 3, 8] // [2, 4, 9] // ================================================ FILE: src/javascript/code/merge-two-lists.js ================================================ const Linklist = require('../../data-structure/linklist-curd'); // function insertByTail(val, p) { // if (!p) { // p = new Linklist.NodeList(val); // } else { // p.next = new Linklist.NodeList(val); // p = p.next; // } // } function mergeTwoLists(l1, l2) { let head = null, p = null; if (!l1) { return l2; } if (!l2) { return l1; } while(l1 || l2 ) { if (!l1) { p.next = l2; l2 = null; continue; } if (!l2) { p.next = l1; l1 = null; continue; } let val = l1.val < l2.val ? l1.val : l2.val; if (!p) { head = p = new Linklist.NodeList(val); } else { p.next = new Linklist.NodeList(val); p = p.next; } l1.val < l2.val ? l1 = l1.next : l2 = l2.next } return head; } const l1 = Linklist.createByTail([1, 3, 8]) const l2 = Linklist.createByTail([2, 4, 9]) // console.log(JSON.stringify(l1.next), JSON.stringify(l2.next)); console.log(JSON.stringify(mergeTwoLists(l1, l2))); // 1 -> 3 -> 8 // 2 -> 4 -> 9 // 1 -> 2 -> 3 -> 4 -> 8 -> 9 ================================================ FILE: src/javascript/code/two-nums-2.js ================================================ function twoNums(nums, target) { const map = new Map(); const length = nums.length; for (let i = 1; i < length; i++) { map.set(nums[i], i); } for (let i = 0; i < length; i++) { let pattern = target - nums[i]; const patternkey = map.get(pattern); if (patternkey && i !== patternkey) { return [i, patternkey]; } } throw new Error('没有找到'); } console.log(twoNums([1, 5, 3, 7], 10)); ================================================ FILE: src/javascript/code/two-nums-add.js ================================================ function twoNumsAdd(l1, l2) { } ================================================ FILE: src/javascript/code/two-nums.js ================================================ function twoNums(nums, target) { const set = new Set(nums); for (const num of nums) { const pattern = target - num; if (set.has(pattern)) { return [num, pattern] } } } console.log(twoNums([1, 3, 5, 7, 9, 10], 19)); ================================================ FILE: src/javascript/code/valid-parent.js ================================================ // [({}[]) function validParent(s) { const len = s.length; const tmpStack = []; const patternMap = new Map(); patternMap.set('{', '}'); patternMap.set('(', ')'); patternMap.set('[', ']'); let i = 0; while(i < len) { if (patternMap.has(s[i])) { tmpStack.push(s[i]); } else { if (patternMap.get(tmpStack.pop()) !== s[i]) { return false } } i++ } return tmpStack.length === 0; } console.log(validParent('()')); ================================================ FILE: src/javascript/curry.js ================================================ // 函数柯里化 function curry(fn, len = fn.length) { return _curry.call(this, fn, len) } function _curry(fn, len, ...args) { return function(...params) { let _args = [...args, ...params] if (_args.length >= len) { return fn.apply(this, _args) } else { return _curry.call(this, fn, len, ..._args) } } } ================================================ FILE: src/javascript/debounce.js ================================================ /** * 防抖-任务频繁触发下,只有当任务触发超过指定间隔,任务再次才会触发 */ function debounce(fn, intervalTime) { let timer return function() { if (timer) { clearTimeout(timer) } setTimeout(() => { fn.call(this, arguments) }, intervalTime) } } function task() { console.log('ok') } debounce(task, 1000) ================================================ FILE: src/javascript/dom.js ================================================ ================================================ FILE: src/javascript/event-loop.js ================================================ ================================================ FILE: src/javascript/event.js ================================================ ================================================ FILE: src/javascript/flat.js ================================================ // Array.prototype.flat const origin = [1, [2, 3], [4, [5, 6], [7, 8, 9]]] function flat(origin) { let res = [] for (let i = 0; i < origin.length; i++) { if (Array.isArray(origin[i])) { res = res.concat(flat(origin[i])) } else { res.push(origin[i]) } } return res } function reduce_flat(origin) { return origin.reduce((a, b) => { if (Array.isArray(b)) { return a.concat(reduce_flat(b)) } else { return a.concat(b) } }, []) } console.log(reduce_flat(origin)) console.log(flat(origin)) ================================================ FILE: src/javascript/function-scope.js ================================================ // 函数作用域 // 函数的全部变量都可以在整个函数范围内使用及复用 // 使用函数作用域隐藏部分变量和函数-最小暴露原则 // 规避冲突 // 1.全局命名空间 // 2.模块管理 var a = 2 function foo() { var a = 3 console.log(3) } foo() console.log(a) // 包装函数缺点 // 1.函数自身污染作用域 // 2.必须显示调用 // 两种解决方案 // 立即执行函数 ;(function foo() { var a = 3 console.log(a) })() // 函数声明不可以省略函数名,回调参数等可以 // 缺点1:调试困难 // 2.无法递归 // 3.说明不了作用 // 立即执行函数表达式 IIFE(immediately invoked function expression) // 改进版 ;(function() { var a = 4 console.log(a) })() // 改进全局参数写法 // var a = 2 // ;(function(global) { // console.log(global.a) // })(window) // 倒置代码运行顺序 // var d = 2 // ;(function IIFE(def) { // def(window) // })(function def(globle) { // console.log(global.d) // }) ================================================ FILE: src/javascript/function-this.js ================================================ function b() { this.a = 3 } a = 5 b() console.log(a) ================================================ FILE: src/javascript/hoisting.js ================================================ // 理解变量函数提升 // var a = 1 var a = 2 console.log(a) a() function a() { console.log(100) } // ====> function a() {} var a a = 2 console.log(a) a() // 优先级函数声明提升高于变量声明提升,不会被变量声明提升覆盖,但是会被变量赋值覆盖 // 只有函数声明才会提升,函数字面量不会提升 ================================================ FILE: src/javascript/implement/apply.js ================================================ ================================================ FILE: src/javascript/implement/async.js ================================================ ================================================ FILE: src/javascript/implement/bind.js ================================================ Function.prototype.mockBind = function() { // 使用apply 实现 that = this; var thatArgs = Array.prototype.slice.call(arguments, 1); var arg = arguments[0]; var bound = function() { var args = thatArgs.concat(Array.prototype.slice.call(arguments)); return that.apply(this instanceof bound ? this : arg, args); } var TmpProto = function() {} if (that.prototype) { TmpProto.prototype = that.prototype; } bound.prototype = new TmpProto(); return bound; } var obj = { a: 'a', } function test(b) { this.c = 'c'; console.log(this.a, b); } test.mockBind(obj, 'b')(); // var Fn = test.mockBind(obj, 'b'); // var objFn = new Fn('a'); // console.log(objFn.c); // todo: 理解new的过程 ================================================ FILE: src/javascript/implement/class.js ================================================ ================================================ FILE: src/javascript/implement/compose.js ================================================ ================================================ FILE: src/javascript/implement/copy.js ================================================ ================================================ FILE: src/javascript/implement/inherit.js ================================================ ================================================ FILE: src/javascript/implement/new.js ================================================ ================================================ FILE: src/javascript/implement/pipe.js ================================================ ================================================ FILE: src/javascript/implement/promise.js ================================================ ================================================ FILE: src/javascript/implement/reduce.js ================================================ ================================================ FILE: src/javascript/implement/sleep.js ================================================ function sleep(ms) { return new Promise((resolve) => setTimeout(() => resolve(), ms)); } async function test() { console.log('start'); await sleep(3000); console.log('end'); } test(); // 强行占线 while (new Date().getTime() < start + ms); ================================================ FILE: src/javascript/inherit.js ================================================ // 如果试图引用对象(实例instance)的某个属性,会首先在对象内部寻找该属性,直至找不到,然后才在该对象的原型(instance.prototype)里去找这个属性. // 构造函数、原型、实例关系 /** * 构造函数 * 构造属性方法 * 原型属性方法 * 实例属性 */ function Base() { this.property = true } Base.prototype.getProperty = function() { return this.property } /** * 原型链继承 * 原理:基类的实例复制给构造函数的原型 * 缺点:多个实例对引用类型的操作会被串改 */ function PrototypeListInherit() { this.property = false } PrototypeListInherit.prototype = new Base() var b = new PrototypeListInherit() console.log(b.getProperty()) /** * 构造继承 * 原理:基类call、this调用 * 缺点: 只能继承实例,无法继承基类原型的方法 */ function ConstructInherit() { Base.call(this) } ConstructInherit.prototype.getProperty = function() { return this.property } var c = new ConstructInherit() console.log(c.getProperty()) /** * 组合继承 * 原理:原型链与构造函数的组合,最后改回原型构造的值 * 优点:既能共享又能单独处理 */ function ComposeInherit() { this.property = false Base.call(this) } ComposeInherit.prototype = new Base() ComposeInherit.prototype.constructor = ComposeInherit var d = new ComposeInherit() console.log(d.getProperty()) /** * 原型继承 * 原理:空对象为中介 */ function PrototypeInherit() {} ================================================ FILE: src/javascript/map.js ================================================ ================================================ FILE: src/javascript/new.js ================================================ function A() { a = 3 } var a = 5 A() console.log(a) ================================================ FILE: src/javascript/object/copy.js ================================================ const refer1 = { a: 1 } const refer2 = { refer: refer1 } const refer3 = function() { console.log(1) } const origin = { a: 1, b: '1', c: true, d: { e: 1 }, f: [1, 2], g: refer2, h: refer3 } function shadowCopy(origin) { let target = {} for (const key in origin) { target[key] = origin[key] } return target } function isObject(origin) { return origin !== null && typeof origin === 'object' } function deepCopy(origin, map = new Map()) { if (isObject(origin)) { let target = Array.isArray(origin) ? [] : {} if (map.get(origin)) return map.get(origin) map.set(origin, target) for (const key in origin) { target[key] = deepCopy(origin[key]) } return target } return origin } // console.log('shadowCopy1:', shadowCopy(origin)); console.log(deepCopy(origin)); console.log(Object.assign({}, origin)); console.log(JSON.parse(JSON.stringify(origin))); ================================================ FILE: src/javascript/object/enum.js ================================================ var origin = { a: 1, b: 2 }; for (const property in origin) { console.log(property); } Object.defineProperty(origin, 'a', { enumerable: false }) for (const property in origin) { console.log(origin[property]); } // 最好只在Object 遍历数组 var originArray = [1, 2, 4, 6]; originArray.a = 12 for (const property in originArray) { console.log(originArray[property]); } ================================================ FILE: src/javascript/object/exist.js ================================================ var origin = { a: 2 } // in 检查对象及其原型链上的属性 无法检查数组 const existIn = 'a' in origin; // 不会检查原型链上的属性/ 所有普通对象都可以访问,Object.create(null) 不行 const existHasProperty = origin.hasOwnProperty('a'); for(const property in origin) { console.log(property); } console.log(existIn, existHasProperty); ================================================ FILE: src/javascript/object/get-set.js ================================================ var origin = { a: 2 } origin = { get b() { return 2; }, get c() { return this._a_; }, set c(val) { this._a_ = 2 * val; } } const b = origin.b; origin.c = 4; const c = origin.c; console.log(b, c); ================================================ FILE: src/javascript/object/iterator.js ================================================ // 本身Object 没有迭代器,无法使用 for of var origin = { a: 1, b: 2 }; Object.defineProperty(origin, Symbol.iterator, { enumerable: false, writable: false, configurable: true, value: function() { var o = this; var idx = 0; var ks = Object.keys(o); return { next: function() { return { value: o[ks[idx++]], done: (idx > ks.length) } } } } }) ================================================ FILE: src/javascript/object/property-desciptor.js ================================================ var origin = { a: 1 } const descriptor = Object.getOwnPropertyDescriptor(origin, 'a'); Object.defineProperty(origin, 'a', { value: 2, writable: false, // 无法改变 configurable: false, // 无法再通过defineProperty 修改,也无法删除 emumerable: false // 无法通过 for in 来枚举 }) console.log(origin); origin.a = 3; console.log(origin); ================================================ FILE: src/javascript/object/traverse.js ================================================ // 两种 var origin = { a: 1, b: true, c: 'c' }; var originArr = [1, 3, 4, 5]; // 遍历属性或者下标, 遍历对象 for (const property in origin) { console.log(property); } for (const property in originArr) { console.log(property); } // 遍历值, 遍历数组 for (const item of origin) { console.log(item); } for (const item of originArr) { console.log(item); } ================================================ FILE: src/javascript/promise.js ================================================ const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' function Promise() { let that = this that.status = PENDING this.value = undefined this.rejectedReason = undefined that.fulfilledCallbackInfo = undefined that.rejectedCallbackInfo = undefined that.onFulfillCallbacks = [] that.onRejectedCallbacks = [] function resolve(value) { if (val instanceof Promise) { return val.then(resolve, reject) } setTimeout(() => { if (that.status === PENDING) { that.status = FULFILLED that.value = value this.onFulfillCallbacks.forEach(cb => cb(that.value)) } }) } function rejected(val) { setTimeout(() => { if (that.status === PENDING) { that.status = REJECTED that.rejectedReason = value that.onRejectedCallbacks.forEach(cb => cb(that.rejectedReason)) } }) } } function resolvePromise() {} Promise.prototype.then = function(onResolve, onRejected) {} Promise.all = function() {} Promise.race = function() {} Promise.resolve = function() {} Promise.reject = function() {} Promise.catch = function() {} ================================================ FILE: src/javascript/proto.js ================================================ var a = { name: '123' } function B() {} var b = new B() console.log(a.__proto__) // {} console.log(b.__proto__) // B {} console.log(B.prototype) // B {} console.log(B.__proto__) // [Function] console.log(b.__proto__ === B.prototype) // true console.log(B.prototype.constructor === B) // true console.log(B.prototype.constructor === b.__proto__.constructor) console.log(B.prototype.__proto__) // {} var c = Object.create(a) console.log(c.__proto__ === a) // true // B 为构造函数 // b 为实例 // B 里面有个原型prototype对象,原型对象里面有个contructor指向自身 // B 里面有个 __proto__ 指向函数,函数里面有个__proto__ 指向对象 // b 里面有个 __proto__ 指向B的原型 b.__proto__ === B.prototype // 因此 b里面的__proto__ 也有个contructor 指向 B, b.__proto__.constructor === B.prototype.constructor === B ================================================ FILE: src/javascript/proxy/base.js ================================================ // 用于定义基本操作的自定义行为 const p = new Proxy({}, {}); console.log(p); var pipe = function (value) { var funcStack = []; var oproxy = new Proxy({}, { get: function (pipeObject, fnName) { if (fnName === 'get') { return funcStack.reduce(function (val, fn) { return fn(val); }, value); } funcStack.push(window[fnName]); return oproxy; } }); return oproxy; } var double = n => n * 2; var pow = n => n * n; var reverseInt = n => n.toString().split("").reverse().join("") | 0; pipe(3) ================================================ FILE: src/javascript/recursion/base.js ================================================ // 计算函数运行时间 function speed(n, callback) { const start = new Date().getTime(); console.log(callback(n)); const time = new Date().getTime() - start; return time; } // 例子1: n! function recursion(n) { if (n === 1) { return 1; } return n * recursion(n - 1); } // f(n) = n * f(n - 1) 数列,递推公式 console.log(recursion(10)); // 例子2: 斐波拉契数列 // 1 1 2 3 5 8 n (fn = f(n-1) + fn(n -2)) function feibulaqi(n) { if (n === 1 || n === 2) { return 1; } return feibulaqi(n - 1) + feibulaqi(n - 2); } console.log(feibulaqi(10)); // 例子3: 小青蛙跳台阶 // 一次可跳一台阶、可跳二台阶,跳n台阶多少总跳法 // 1 2 3 5 8 // 第一次跳1, 剩下f(n-1)没有跳 // 第一次跳2, 剩下f(n-2)没有跳 // 总共有 f(n-1) + f(n-2) 种 function jumpStep(n) { if (n === 1) { return 1; } if (n === 2) { return 2; } return jumpStep(n - 1) + jumpStep(n - 2); } console.log(jumpStep(10)); // 例子4: 反转链表 // 1 -> 2 -> 3 -> 4 // 4 -> 3 -> 2 -> 1 function Node() { this.data = ''; this.next = null; } // todo // 递归优化 // 子问题的重复计算 --- 保存计算的结果 const tmpArr = []; function recursionReduce(n) { if (n === 1 || n === 2) { return 1; } if (tmpArr[n]) { return tmpArr[n]; } else { tmpArr[n] = recursionReduce(n - 1) + recursionReduce(n - 2); return tmpArr[n] } } // 自底而上, 采用递推: 最优 function febulaqi2(n) { let f1 = 1; let f2 = 1; let sum = 0; for (let i = 0; i < n; i++) { f2 = f1; f1 = sum; sum = f1 + f2; } return sum; } console.log(`优化前:${speed(40, feibulaqi)}ms`); console.log(`优化后:${speed(40, recursionReduce)}ms`); // 速度快,消耗内存大 console.log(`递推后:${speed(40, febulaqi2)}ms`); ================================================ FILE: src/javascript/regExp.js ================================================ // assert 断言 // match // exec // test // search // replace // split // filter const text = '09:00-19:00'; const pattern = /^[0-2][0-9]:[0-5][0-9]-[0-2][0-9]:[0-5][0-9]$/; // console.log(text.match(pattern)); // console.log(text.search(pattern)); // console.log(text.split(pattern)); // // console.log(text.filter(pattern)); // console.log(pattern.test(text)); // console.log(pattern.exec(text)); let demo = 'https://developer.mozilla.org///en-US//docs/Web/JavaScript/Guide/Regular_Expressions'; demo = demo.replace(/([\/]{2,})/g, '/'); console.log(demo); ================================================ FILE: src/javascript/scope.js ================================================ function a() { b = 2 // this.b = 2 } var b = 1 a() console.log(b) ================================================ FILE: src/javascript/set/set.js ================================================ const s1 = new Set([1, 3, 2, 3]); console.log(s1); // console.log([...new Set([1, 3, 2, 3])]); // 取唯一 // 判断是否存在某个值 // console.log(s1.has(2)); // 判断交集 function intersection(s1, s2) { // 短的取比长的 if (s1.size > s2.size) { return intersection(s2, s1); } const intersectionSet = new Set(); for (const num of s1) { if (s2.has(num)) { intersectionSet.add(num) } } return [...intersectionSet]; } console.log(intersection(new Set([1, 3, 5, 7, 9]), new Set([2, 4, 6, 7]))); ================================================ FILE: src/javascript/set.js ================================================ const s1 = new Set([1, 3, 2, 3]); console.log(s1); // console.log([...new Set([1, 3, 2, 3])]); // 取唯一 // 判断是否存在某个值 // console.log(s1.has(2)); // 判断交集 function intersection(s1, s2) { // 短的取比长的 if (s1.size > s2.size) { return intersection(s2, s1); } const intersectionSet = new Set(); for (const num of s1) { if (s2.has(num)) { intersectionSet.add(num) } } return [...intersectionSet]; } console.log(intersection(new Set([1, 3, 5, 7, 9]), new Set([2, 4, 6, 7]))); ================================================ FILE: src/javascript/sleep.js ================================================ function sleep(milliseconds) { const startTime = new Date().getTime(); while(new Date().getTime() < startTime + milliseconds); } sleep(10000); ================================================ FILE: src/javascript/string.js ================================================ ================================================ FILE: src/javascript/this.js ================================================ ================================================ FILE: src/javascript/throttle.js ================================================ /** * 任务在某一特定的时间内,不会被调用两次 */ function throttle(fn, wait) { let runable = false setTimeout(() => { fn.call(this, arguments) runable = true }, wait) } /** * 使用时间轴存值 */ function throttle(fn, wait) { let last = 0 return function() { setTimeout(() => { let start = +new Date() if (start - last > wait) { fn.apply(this, arguments) last = start } }, wait) } } ================================================ FILE: src/javascript/type.js ================================================ const object = { a: undefined, b: 1, c: '1', d: true, e: {}, f: [], g: function() {}, h: NaN, i: null, j: new Date(), k: new String(), l: new RegExp() } // 通用方法 for (const key in object) { console.log(Object.prototype.toString.call(object[key])) } // [object Undefined] // [object Number] // [object String] // [object Boolean] // [object Object] // [object Array] // [object Function] // [object Number] // [object Null] // [object Date] for (const key in object) { console.log(typeof object[key]) } // undefined // number // string // boolean // object // object // function // number // object // object // object // object ================================================ FILE: src/javascript/uniqu.js ================================================ const array = [1, 3, 2, 6, 2, 3, 4, 7, 8, 9, 10] function set_uniqu(array) { return [...new Set(array)] } function filter_uniqu(array) { return array.filter((item, index) => array.indexOf(item) === index) } function filter_map_uniqu(array) {} function reduce_uniqu(array) { return array.reduce( (prev, cur, index, array) => prev.includes(cur) ? prev : prev.concat(cur), [] ) } console.log('newSet', set_uniqu(array)) console.log('filter', filter_uniqu(array)) console.log('reduce', reduce_uniqu(array)) ================================================ FILE: src/json/data.json ================================================ ================================================ FILE: src/json/distinct_data.json ================================================ { "data": [ { "children": [ { "children": [ { "value": "东城区", "label": "东城区" }, { "value": "西城区", "label": "西城区" }, { "value": "朝阳区", "label": "朝阳区" }, { "value": "丰台区", "label": "丰台区" }, { "value": "石景山区", "label": "石景山区" }, { "value": "海淀区", "label": "海淀区" }, { "value": "门头沟区", "label": "门头沟区" }, { "value": "房山区", "label": "房山区" }, { "value": "通州区", "label": "通州区" }, { "value": "顺义区", "label": "顺义区" }, { "value": "昌平区", "label": "昌平区" }, { "value": "大兴区", "label": "大兴区" }, { "value": "怀柔区", "label": "怀柔区" }, { "value": "平谷区", "label": "平谷区" }, { "value": "密云区", "label": "密云区" }, { "value": "延庆区", "label": "延庆区" } ], "value": "北京市", "label": "北京市" } ], "value": "北京市", "label": "北京市" }, { "children": [ { "children": [ { "value": "和平区", "label": "和平区" }, { "value": "河东区", "label": "河东区" }, { "value": "河西区", "label": "河西区" }, { "value": "南开区", "label": "南开区" }, { "value": "河北区", "label": "河北区" }, { "value": "红桥区", "label": "红桥区" }, { "value": "东丽区", "label": "东丽区" }, { "value": "西青区", "label": "西青区" }, { "value": "津南区", "label": "津南区" }, { "value": "北辰区", "label": "北辰区" }, { "value": "武清区", "label": "武清区" }, { "value": "宝坻区", "label": "宝坻区" }, { "value": "滨海新区", "label": "滨海新区" }, { "value": "宁河区", "label": "宁河区" }, { "value": "静海区", "label": "静海区" }, { "value": "蓟州区", "label": "蓟州区" } ], "value": "天津市", "label": "天津市" } ], "value": "天津市", "label": "天津市" }, { "children": [ { "children": [ { "value": "长安区", "label": "长安区" }, { "value": "桥西区", "label": "桥西区" }, { "value": "新华区", "label": "新华区" }, { "value": "井陉矿区", "label": "井陉矿区" }, { "value": "裕华区", "label": "裕华区" }, { "value": "藁城区", "label": "藁城区" }, { "value": "鹿泉区", "label": "鹿泉区" }, { "value": "栾城区", "label": "栾城区" }, { "value": "井陉县", "label": "井陉县" }, { "value": "正定县", "label": "正定县" }, { "value": "行唐县", "label": "行唐县" }, { "value": "灵寿县", "label": "灵寿县" }, { "value": "高邑县", "label": "高邑县" }, { "value": "深泽县", "label": "深泽县" }, { "value": "赞皇县", "label": "赞皇县" }, { "value": "无极县", "label": "无极县" }, { "value": "平山县", "label": "平山县" }, { "value": "元氏县", "label": "元氏县" }, { "value": "赵县", "label": "赵县" }, { "value": "辛集市", "label": "辛集市" }, { "value": "晋州市", "label": "晋州市" }, { "value": "新乐市", "label": "新乐市" } ], "value": "石家庄市", "label": "石家庄市" }, { "children": [ { "value": "路南区", "label": "路南区" }, { "value": "路北区", "label": "路北区" }, { "value": "古冶区", "label": "古冶区" }, { "value": "开平区", "label": "开平区" }, { "value": "丰南区", "label": "丰南区" }, { "value": "丰润区", "label": "丰润区" }, { "value": "曹妃甸区", "label": "曹妃甸区" }, { "value": "滦县", "label": "滦县" }, { "value": "滦南县", "label": "滦南县" }, { "value": "乐亭县", "label": "乐亭县" }, { "value": "迁西县", "label": "迁西县" }, { "value": "玉田县", "label": "玉田县" }, { "value": "遵化市", "label": "遵化市" }, { "value": "迁安市", "label": "迁安市" } ], "value": "唐山市", "label": "唐山市" }, { "children": [ { "value": "海港区", "label": "海港区" }, { "value": "山海关区", "label": "山海关区" }, { "value": "北戴河区", "label": "北戴河区" }, { "value": "抚宁区", "label": "抚宁区" }, { "value": "青龙满族自治县", "label": "青龙满族自治县" }, { "value": "昌黎县", "label": "昌黎县" }, { "value": "卢龙县", "label": "卢龙县" } ], "value": "秦皇岛市", "label": "秦皇岛市" }, { "children": [ { "value": "邯山区", "label": "邯山区" }, { "value": "丛台区", "label": "丛台区" }, { "value": "复兴区", "label": "复兴区" }, { "value": "峰峰矿区", "label": "峰峰矿区" }, { "value": "肥乡区", "label": "肥乡区" }, { "value": "永年区", "label": "永年区" }, { "value": "临漳县", "label": "临漳县" }, { "value": "成安县", "label": "成安县" }, { "value": "大名县", "label": "大名县" }, { "value": "涉县", "label": "涉县" }, { "value": "磁县", "label": "磁县" }, { "value": "邱县", "label": "邱县" }, { "value": "鸡泽县", "label": "鸡泽县" }, { "value": "广平县", "label": "广平县" }, { "value": "馆陶县", "label": "馆陶县" }, { "value": "魏县", "label": "魏县" }, { "value": "曲周县", "label": "曲周县" }, { "value": "武安市", "label": "武安市" } ], "value": "邯郸市", "label": "邯郸市" }, { "children": [ { "value": "桥东区", "label": "桥东区" }, { "value": "桥西区", "label": "桥西区" }, { "value": "邢台县", "label": "邢台县" }, { "value": "临城县", "label": "临城县" }, { "value": "内丘县", "label": "内丘县" }, { "value": "柏乡县", "label": "柏乡县" }, { "value": "隆尧县", "label": "隆尧县" }, { "value": "任县", "label": "任县" }, { "value": "南和县", "label": "南和县" }, { "value": "宁晋县", "label": "宁晋县" }, { "value": "巨鹿县", "label": "巨鹿县" }, { "value": "新河县", "label": "新河县" }, { "value": "广宗县", "label": "广宗县" }, { "value": "平乡县", "label": "平乡县" }, { "value": "威县", "label": "威县" }, { "value": "清河县", "label": "清河县" }, { "value": "临西县", "label": "临西县" }, { "value": "南宫市", "label": "南宫市" }, { "value": "沙河市", "label": "沙河市" } ], "value": "邢台市", "label": "邢台市" }, { "children": [ { "value": "竞秀区", "label": "竞秀区" }, { "value": "莲池区", "label": "莲池区" }, { "value": "满城区", "label": "满城区" }, { "value": "清苑区", "label": "清苑区" }, { "value": "徐水区", "label": "徐水区" }, { "value": "涞水县", "label": "涞水县" }, { "value": "阜平县", "label": "阜平县" }, { "value": "定兴县", "label": "定兴县" }, { "value": "唐县", "label": "唐县" }, { "value": "高阳县", "label": "高阳县" }, { "value": "容城县", "label": "容城县" }, { "value": "涞源县", "label": "涞源县" }, { "value": "望都县", "label": "望都县" }, { "value": "安新县", "label": "安新县" }, { "value": "易县", "label": "易县" }, { "value": "曲阳县", "label": "曲阳县" }, { "value": "蠡县", "label": "蠡县" }, { "value": "顺平县", "label": "顺平县" }, { "value": "博野县", "label": "博野县" }, { "value": "雄县", "label": "雄县" } ], "value": "保定市", "label": "保定市" }, { "children": [], "value": "涿州市", "label": "涿州市" }, { "children": [], "value": "定州市", "label": "定州市" }, { "children": [], "value": "安国市", "label": "安国市" }, { "children": [], "value": "高碑店市", "label": "高碑店市" }, { "children": [ { "value": "桥东区", "label": "桥东区" }, { "value": "桥西区", "label": "桥西区" }, { "value": "宣化区", "label": "宣化区" }, { "value": "下花园区", "label": "下花园区" }, { "value": "万全区", "label": "万全区" }, { "value": "崇礼区", "label": "崇礼区" }, { "value": "张北县", "label": "张北县" }, { "value": "康保县", "label": "康保县" }, { "value": "沽源县", "label": "沽源县" }, { "value": "尚义县", "label": "尚义县" }, { "value": "蔚县", "label": "蔚县" }, { "value": "阳原县", "label": "阳原县" }, { "value": "怀安县", "label": "怀安县" }, { "value": "怀来县", "label": "怀来县" }, { "value": "涿鹿县", "label": "涿鹿县" }, { "value": "赤城县", "label": "赤城县" } ], "value": "张家口市", "label": "张家口市" }, { "children": [ { "value": "双桥区", "label": "双桥区" }, { "value": "双滦区", "label": "双滦区" }, { "value": "鹰手营子矿区", "label": "鹰手营子矿区" }, { "value": "承德县", "label": "承德县" }, { "value": "兴隆县", "label": "兴隆县" }, { "value": "滦平县", "label": "滦平县" }, { "value": "隆化县", "label": "隆化县" }, { "value": "丰宁满族自治县", "label": "丰宁满族自治县" }, { "value": "宽城满族自治县", "label": "宽城满族自治县" }, { "value": "围场满族蒙古族自治县", "label": "围场满族蒙古族自治县" }, { "value": "平泉市", "label": "平泉市" } ], "value": "承德市", "label": "承德市" }, { "children": [ { "value": "新华区", "label": "新华区" }, { "value": "运河区", "label": "运河区" }, { "value": "沧县", "label": "沧县" }, { "value": "青县", "label": "青县" }, { "value": "东光县", "label": "东光县" }, { "value": "海兴县", "label": "海兴县" }, { "value": "盐山县", "label": "盐山县" }, { "value": "肃宁县", "label": "肃宁县" }, { "value": "南皮县", "label": "南皮县" }, { "value": "吴桥县", "label": "吴桥县" }, { "value": "献县", "label": "献县" }, { "value": "孟村回族自治县", "label": "孟村回族自治县" }, { "value": "泊头市", "label": "泊头市" }, { "value": "任丘市", "label": "任丘市" }, { "value": "黄骅市", "label": "黄骅市" }, { "value": "河间市", "label": "河间市" } ], "value": "沧州市", "label": "沧州市" }, { "children": [ { "value": "安次区", "label": "安次区" }, { "value": "广阳区", "label": "广阳区" }, { "value": "固安县", "label": "固安县" }, { "value": "永清县", "label": "永清县" }, { "value": "香河县", "label": "香河县" }, { "value": "大城县", "label": "大城县" }, { "value": "文安县", "label": "文安县" }, { "value": "大厂回族自治县", "label": "大厂回族自治县" }, { "value": "霸州市", "label": "霸州市" }, { "value": "三河市", "label": "三河市" } ], "value": "廊坊市", "label": "廊坊市" }, { "children": [ { "value": "桃城区", "label": "桃城区" }, { "value": "冀州区", "label": "冀州区" }, { "value": "枣强县", "label": "枣强县" }, { "value": "武邑县", "label": "武邑县" }, { "value": "武强县", "label": "武强县" }, { "value": "饶阳县", "label": "饶阳县" }, { "value": "安平县", "label": "安平县" }, { "value": "故城县", "label": "故城县" }, { "value": "景县", "label": "景县" }, { "value": "阜城县", "label": "阜城县" }, { "value": "深州市", "label": "深州市" } ], "value": "衡水市", "label": "衡水市" } ], "value": "河北省", "label": "河北省" }, { "children": [ { "children": [ { "value": "小店区", "label": "小店区" }, { "value": "迎泽区", "label": "迎泽区" }, { "value": "杏花岭区", "label": "杏花岭区" }, { "value": "尖草坪区", "label": "尖草坪区" }, { "value": "万柏林区", "label": "万柏林区" }, { "value": "晋源区", "label": "晋源区" }, { "value": "清徐县", "label": "清徐县" }, { "value": "阳曲县", "label": "阳曲县" }, { "value": "娄烦县", "label": "娄烦县" }, { "value": "古交市", "label": "古交市" } ], "value": "太原市", "label": "太原市" }, { "children": [ { "value": "城区", "label": "城区" }, { "value": "矿区", "label": "矿区" }, { "value": "南郊区", "label": "南郊区" }, { "value": "新荣区", "label": "新荣区" }, { "value": "阳高县", "label": "阳高县" }, { "value": "天镇县", "label": "天镇县" }, { "value": "广灵县", "label": "广灵县" }, { "value": "灵丘县", "label": "灵丘县" }, { "value": "浑源县", "label": "浑源县" }, { "value": "左云县", "label": "左云县" }, { "value": "大同县", "label": "大同县" } ], "value": "大同市", "label": "大同市" }, { "children": [ { "value": "城区", "label": "城区" }, { "value": "矿区", "label": "矿区" }, { "value": "郊区", "label": "郊区" }, { "value": "平定县", "label": "平定县" }, { "value": "盂县", "label": "盂县" } ], "value": "阳泉市", "label": "阳泉市" }, { "children": [ { "value": "城区", "label": "城区" }, { "value": "郊区", "label": "郊区" }, { "value": "长治县", "label": "长治县" }, { "value": "襄垣县", "label": "襄垣县" }, { "value": "屯留县", "label": "屯留县" }, { "value": "平顺县", "label": "平顺县" }, { "value": "黎城县", "label": "黎城县" }, { "value": "壶关县", "label": "壶关县" }, { "value": "长子县", "label": "长子县" }, { "value": "武乡县", "label": "武乡县" }, { "value": "沁县", "label": "沁县" }, { "value": "沁源县", "label": "沁源县" }, { "value": "潞城市", "label": "潞城市" } ], "value": "长治市", "label": "长治市" }, { "children": [ { "value": "城区", "label": "城区" }, { "value": "沁水县", "label": "沁水县" }, { "value": "阳城县", "label": "阳城县" }, { "value": "陵川县", "label": "陵川县" }, { "value": "泽州县", "label": "泽州县" }, { "value": "高平市", "label": "高平市" } ], "value": "晋城市", "label": "晋城市" }, { "children": [ { "value": "朔城区", "label": "朔城区" }, { "value": "平鲁区", "label": "平鲁区" }, { "value": "山阴县", "label": "山阴县" }, { "value": "应县", "label": "应县" }, { "value": "右玉县", "label": "右玉县" }, { "value": "怀仁县", "label": "怀仁县" } ], "value": "朔州市", "label": "朔州市" }, { "children": [ { "value": "榆次区", "label": "榆次区" }, { "value": "榆社县", "label": "榆社县" }, { "value": "左权县", "label": "左权县" }, { "value": "和顺县", "label": "和顺县" }, { "value": "昔阳县", "label": "昔阳县" }, { "value": "寿阳县", "label": "寿阳县" }, { "value": "太谷县", "label": "太谷县" }, { "value": "祁县", "label": "祁县" }, { "value": "平遥县", "label": "平遥县" }, { "value": "灵石县", "label": "灵石县" }, { "value": "介休市", "label": "介休市" } ], "value": "晋中市", "label": "晋中市" }, { "children": [ { "value": "盐湖区", "label": "盐湖区" }, { "value": "临猗县", "label": "临猗县" }, { "value": "万荣县", "label": "万荣县" }, { "value": "闻喜县", "label": "闻喜县" }, { "value": "稷山县", "label": "稷山县" }, { "value": "新绛县", "label": "新绛县" }, { "value": "绛县", "label": "绛县" }, { "value": "垣曲县", "label": "垣曲县" }, { "value": "夏县", "label": "夏县" }, { "value": "平陆县", "label": "平陆县" }, { "value": "芮城县", "label": "芮城县" }, { "value": "永济市", "label": "永济市" }, { "value": "河津市", "label": "河津市" } ], "value": "运城市", "label": "运城市" }, { "children": [ { "value": "忻府区", "label": "忻府区" }, { "value": "定襄县", "label": "定襄县" }, { "value": "五台县", "label": "五台县" }, { "value": "代县", "label": "代县" }, { "value": "繁峙县", "label": "繁峙县" }, { "value": "宁武县", "label": "宁武县" }, { "value": "静乐县", "label": "静乐县" }, { "value": "神池县", "label": "神池县" }, { "value": "五寨县", "label": "五寨县" }, { "value": "岢岚县", "label": "岢岚县" }, { "value": "河曲县", "label": "河曲县" }, { "value": "保德县", "label": "保德县" }, { "value": "偏关县", "label": "偏关县" }, { "value": "原平市", "label": "原平市" } ], "value": "忻州市", "label": "忻州市" }, { "children": [ { "value": "尧都区", "label": "尧都区" }, { "value": "曲沃县", "label": "曲沃县" }, { "value": "翼城县", "label": "翼城县" }, { "value": "襄汾县", "label": "襄汾县" }, { "value": "洪洞县", "label": "洪洞县" }, { "value": "古县", "label": "古县" }, { "value": "安泽县", "label": "安泽县" }, { "value": "浮山县", "label": "浮山县" }, { "value": "吉县", "label": "吉县" }, { "value": "乡宁县", "label": "乡宁县" }, { "value": "大宁县", "label": "大宁县" }, { "value": "隰县", "label": "隰县" }, { "value": "永和县", "label": "永和县" }, { "value": "蒲县", "label": "蒲县" }, { "value": "汾西县", "label": "汾西县" }, { "value": "侯马市", "label": "侯马市" }, { "value": "霍州市", "label": "霍州市" } ], "value": "临汾市", "label": "临汾市" }, { "children": [ { "value": "离石区", "label": "离石区" }, { "value": "文水县", "label": "文水县" }, { "value": "交城县", "label": "交城县" }, { "value": "兴县", "label": "兴县" }, { "value": "临县", "label": "临县" }, { "value": "柳林县", "label": "柳林县" }, { "value": "石楼县", "label": "石楼县" }, { "value": "岚县", "label": "岚县" }, { "value": "方山县", "label": "方山县" }, { "value": "中阳县", "label": "中阳县" }, { "value": "交口县", "label": "交口县" }, { "value": "孝义市", "label": "孝义市" }, { "value": "汾阳市", "label": "汾阳市" } ], "value": "吕梁市", "label": "吕梁市" } ], "value": "山西省", "label": "山西省" }, { "children": [ { "children": [ { "value": "新城区", "label": "新城区" }, { "value": "回民区", "label": "回民区" }, { "value": "玉泉区", "label": "玉泉区" }, { "value": "赛罕区", "label": "赛罕区" }, { "value": "土默特左旗", "label": "土默特左旗" }, { "value": "托克托县", "label": "托克托县" }, { "value": "和林格尔县", "label": "和林格尔县" }, { "value": "清水河县", "label": "清水河县" }, { "value": "武川县", "label": "武川县" } ], "value": "呼和浩特市", "label": "呼和浩特市" }, { "children": [ { "value": "东河区", "label": "东河区" }, { "value": "昆都仑区", "label": "昆都仑区" }, { "value": "青山区", "label": "青山区" }, { "value": "石拐区", "label": "石拐区" }, { "value": "白云鄂博矿区", "label": "白云鄂博矿区" }, { "value": "九原区", "label": "九原区" }, { "value": "土默特右旗", "label": "土默特右旗" }, { "value": "固阳县", "label": "固阳县" }, { "value": "达尔罕茂明安联合旗", "label": "达尔罕茂明安联合旗" } ], "value": "包头市", "label": "包头市" }, { "children": [ { "value": "海勃湾区", "label": "海勃湾区" }, { "value": "海南区", "label": "海南区" }, { "value": "乌达区", "label": "乌达区" } ], "value": "乌海市", "label": "乌海市" }, { "children": [ { "value": "红山区", "label": "红山区" }, { "value": "元宝山区", "label": "元宝山区" }, { "value": "松山区", "label": "松山区" }, { "value": "阿鲁科尔沁旗", "label": "阿鲁科尔沁旗" }, { "value": "巴林左旗", "label": "巴林左旗" }, { "value": "巴林右旗", "label": "巴林右旗" }, { "value": "林西县", "label": "林西县" }, { "value": "克什克腾旗", "label": "克什克腾旗" }, { "value": "翁牛特旗", "label": "翁牛特旗" }, { "value": "喀喇沁旗", "label": "喀喇沁旗" }, { "value": "宁城县", "label": "宁城县" }, { "value": "敖汉旗", "label": "敖汉旗" } ], "value": "赤峰市", "label": "赤峰市" }, { "children": [ { "value": "科尔沁区", "label": "科尔沁区" }, { "value": "科尔沁左翼中旗", "label": "科尔沁左翼中旗" }, { "value": "科尔沁左翼后旗", "label": "科尔沁左翼后旗" }, { "value": "开鲁县", "label": "开鲁县" }, { "value": "库伦旗", "label": "库伦旗" }, { "value": "奈曼旗", "label": "奈曼旗" }, { "value": "扎鲁特旗", "label": "扎鲁特旗" }, { "value": "霍林郭勒市", "label": "霍林郭勒市" } ], "value": "通辽市", "label": "通辽市" }, { "children": [ { "value": "东胜区", "label": "东胜区" }, { "value": "康巴什区", "label": "康巴什区" }, { "value": "达拉特旗", "label": "达拉特旗" }, { "value": "准格尔旗", "label": "准格尔旗" }, { "value": "鄂托克前旗", "label": "鄂托克前旗" }, { "value": "鄂托克旗", "label": "鄂托克旗" }, { "value": "杭锦旗", "label": "杭锦旗" }, { "value": "乌审旗", "label": "乌审旗" }, { "value": "伊金霍洛旗", "label": "伊金霍洛旗" } ], "value": "鄂尔多斯市", "label": "鄂尔多斯市" }, { "children": [ { "value": "海拉尔区", "label": "海拉尔区" }, { "value": "扎赉诺尔区", "label": "扎赉诺尔区" }, { "value": "阿荣旗", "label": "阿荣旗" }, { "value": "莫力达瓦达斡尔族自治旗", "label": "莫力达瓦达斡尔族自治旗" }, { "value": "鄂伦春自治旗", "label": "鄂伦春自治旗" }, { "value": "鄂温克族自治旗", "label": "鄂温克族自治旗" }, { "value": "陈巴尔虎旗", "label": "陈巴尔虎旗" }, { "value": "新巴尔虎左旗", "label": "新巴尔虎左旗" }, { "value": "新巴尔虎右旗", "label": "新巴尔虎右旗" }, { "value": "满洲里市", "label": "满洲里市" }, { "value": "牙克石市", "label": "牙克石市" }, { "value": "扎兰屯市", "label": "扎兰屯市" }, { "value": "额尔古纳市", "label": "额尔古纳市" }, { "value": "根河市", "label": "根河市" } ], "value": "呼伦贝尔市", "label": "呼伦贝尔市" }, { "children": [ { "value": "临河区", "label": "临河区" }, { "value": "五原县", "label": "五原县" }, { "value": "磴口县", "label": "磴口县" }, { "value": "乌拉特前旗", "label": "乌拉特前旗" }, { "value": "乌拉特中旗", "label": "乌拉特中旗" }, { "value": "乌拉特后旗", "label": "乌拉特后旗" }, { "value": "杭锦后旗", "label": "杭锦后旗" } ], "value": "巴彦淖尔市", "label": "巴彦淖尔市" }, { "children": [ { "value": "集宁区", "label": "集宁区" }, { "value": "卓资县", "label": "卓资县" }, { "value": "化德县", "label": "化德县" }, { "value": "商都县", "label": "商都县" }, { "value": "兴和县", "label": "兴和县" }, { "value": "凉城县", "label": "凉城县" }, { "value": "察哈尔右翼前旗", "label": "察哈尔右翼前旗" }, { "value": "察哈尔右翼中旗", "label": "察哈尔右翼中旗" }, { "value": "察哈尔右翼后旗", "label": "察哈尔右翼后旗" }, { "value": "四子王旗", "label": "四子王旗" }, { "value": "丰镇市", "label": "丰镇市" } ], "value": "乌兰察布市", "label": "乌兰察布市" }, { "children": [ { "value": "乌兰浩特市", "label": "乌兰浩特市" }, { "value": "阿尔山市", "label": "阿尔山市" }, { "value": "科尔沁右翼前旗", "label": "科尔沁右翼前旗" }, { "value": "科尔沁右翼中旗", "label": "科尔沁右翼中旗" }, { "value": "扎赉特旗", "label": "扎赉特旗" }, { "value": "突泉县", "label": "突泉县" } ], "value": "兴安盟", "label": "兴安盟" }, { "children": [ { "value": "二连浩特市", "label": "二连浩特市" }, { "value": "锡林浩特市", "label": "锡林浩特市" }, { "value": "阿巴嘎旗", "label": "阿巴嘎旗" }, { "value": "苏尼特左旗", "label": "苏尼特左旗" }, { "value": "苏尼特右旗", "label": "苏尼特右旗" }, { "value": "东乌珠穆沁旗", "label": "东乌珠穆沁旗" }, { "value": "西乌珠穆沁旗", "label": "西乌珠穆沁旗" }, { "value": "太仆寺旗", "label": "太仆寺旗" }, { "value": "镶黄旗", "label": "镶黄旗" }, { "value": "正镶白旗", "label": "正镶白旗" }, { "value": "正蓝旗", "label": "正蓝旗" }, { "value": "多伦县", "label": "多伦县" } ], "value": "锡林郭勒盟", "label": "锡林郭勒盟" }, { "children": [ { "value": "阿拉善左旗", "label": "阿拉善左旗" }, { "value": "阿拉善右旗", "label": "阿拉善右旗" }, { "value": "额济纳旗", "label": "额济纳旗" } ], "value": "阿拉善盟", "label": "阿拉善盟" } ], "value": "内蒙古自治区", "label": "内蒙古自治区" }, { "children": [ { "children": [ { "value": "和平区", "label": "和平区" }, { "value": "沈河区", "label": "沈河区" }, { "value": "大东区", "label": "大东区" }, { "value": "皇姑区", "label": "皇姑区" }, { "value": "铁西区", "label": "铁西区" }, { "value": "苏家屯区", "label": "苏家屯区" }, { "value": "浑南区", "label": "浑南区" }, { "value": "沈北新区", "label": "沈北新区" }, { "value": "于洪区", "label": "于洪区" }, { "value": "辽中区", "label": "辽中区" }, { "value": "康平县", "label": "康平县" }, { "value": "法库县", "label": "法库县" }, { "value": "新民市", "label": "新民市" } ], "value": "沈阳市", "label": "沈阳市" }, { "children": [ { "value": "中山区", "label": "中山区" }, { "value": "西岗区", "label": "西岗区" }, { "value": "沙河口区", "label": "沙河口区" }, { "value": "甘井子区", "label": "甘井子区" }, { "value": "旅顺口区", "label": "旅顺口区" }, { "value": "金州区", "label": "金州区" }, { "value": "普兰店区", "label": "普兰店区" }, { "value": "长海县", "label": "长海县" }, { "value": "瓦房店市", "label": "瓦房店市" }, { "value": "庄河市", "label": "庄河市" } ], "value": "大连市", "label": "大连市" }, { "children": [ { "value": "铁东区", "label": "铁东区" }, { "value": "铁西区", "label": "铁西区" }, { "value": "立山区", "label": "立山区" }, { "value": "千山区", "label": "千山区" }, { "value": "台安县", "label": "台安县" }, { "value": "岫岩满族自治县", "label": "岫岩满族自治县" }, { "value": "海城市", "label": "海城市" } ], "value": "鞍山市", "label": "鞍山市" }, { "children": [ { "value": "新抚区", "label": "新抚区" }, { "value": "东洲区", "label": "东洲区" }, { "value": "望花区", "label": "望花区" }, { "value": "顺城区", "label": "顺城区" }, { "value": "抚顺县", "label": "抚顺县" }, { "value": "新宾满族自治县", "label": "新宾满族自治县" }, { "value": "清原满族自治县", "label": "清原满族自治县" } ], "value": "抚顺市", "label": "抚顺市" }, { "children": [ { "value": "平山区", "label": "平山区" }, { "value": "溪湖区", "label": "溪湖区" }, { "value": "明山区", "label": "明山区" }, { "value": "南芬区", "label": "南芬区" }, { "value": "本溪满族自治县", "label": "本溪满族自治县" }, { "value": "桓仁满族自治县", "label": "桓仁满族自治县" } ], "value": "本溪市", "label": "本溪市" }, { "children": [ { "value": "元宝区", "label": "元宝区" }, { "value": "振兴区", "label": "振兴区" }, { "value": "振安区", "label": "振安区" }, { "value": "宽甸满族自治县", "label": "宽甸满族自治县" }, { "value": "东港市", "label": "东港市" }, { "value": "凤城市", "label": "凤城市" } ], "value": "丹东市", "label": "丹东市" }, { "children": [ { "value": "古塔区", "label": "古塔区" }, { "value": "凌河区", "label": "凌河区" }, { "value": "太和区", "label": "太和区" }, { "value": "黑山县", "label": "黑山县" }, { "value": "义县", "label": "义县" }, { "value": "凌海市", "label": "凌海市" }, { "value": "北镇市", "label": "北镇市" } ], "value": "锦州市", "label": "锦州市" }, { "children": [ { "value": "站前区", "label": "站前区" }, { "value": "西市区", "label": "西市区" }, { "value": "鲅鱼圈区", "label": "鲅鱼圈区" }, { "value": "老边区", "label": "老边区" }, { "value": "盖州市", "label": "盖州市" }, { "value": "大石桥市", "label": "大石桥市" } ], "value": "营口市", "label": "营口市" }, { "children": [ { "value": "海州区", "label": "海州区" }, { "value": "新邱区", "label": "新邱区" }, { "value": "太平区", "label": "太平区" }, { "value": "清河门区", "label": "清河门区" }, { "value": "细河区", "label": "细河区" }, { "value": "阜新蒙古族自治县", "label": "阜新蒙古族自治县" }, { "value": "彰武县", "label": "彰武县" } ], "value": "阜新市", "label": "阜新市" }, { "children": [ { "value": "白塔区", "label": "白塔区" }, { "value": "文圣区", "label": "文圣区" }, { "value": "宏伟区", "label": "宏伟区" }, { "value": "弓长岭区", "label": "弓长岭区" }, { "value": "太子河区", "label": "太子河区" }, { "value": "辽阳县", "label": "辽阳县" }, { "value": "灯塔市", "label": "灯塔市" } ], "value": "辽阳市", "label": "辽阳市" }, { "children": [ { "value": "双台子区", "label": "双台子区" }, { "value": "兴隆台区", "label": "兴隆台区" }, { "value": "大洼区", "label": "大洼区" }, { "value": "盘山县", "label": "盘山县" } ], "value": "盘锦市", "label": "盘锦市" }, { "children": [ { "value": "银州区", "label": "银州区" }, { "value": "清河区", "label": "清河区" }, { "value": "铁岭县", "label": "铁岭县" }, { "value": "西丰县", "label": "西丰县" }, { "value": "昌图县", "label": "昌图县" }, { "value": "调兵山市", "label": "调兵山市" }, { "value": "开原市", "label": "开原市" } ], "value": "铁岭市", "label": "铁岭市" }, { "children": [ { "value": "双塔区", "label": "双塔区" }, { "value": "龙城区", "label": "龙城区" }, { "value": "朝阳县", "label": "朝阳县" }, { "value": "建平县", "label": "建平县" }, { "value": "喀喇沁左翼蒙古族自治县", "label": "喀喇沁左翼蒙古族自治县" }, { "value": "北票市", "label": "北票市" }, { "value": "凌源市", "label": "凌源市" } ], "value": "朝阳市", "label": "朝阳市" }, { "children": [ { "value": "连山区", "label": "连山区" }, { "value": "龙港区", "label": "龙港区" }, { "value": "南票区", "label": "南票区" }, { "value": "绥中县", "label": "绥中县" }, { "value": "建昌县", "label": "建昌县" }, { "value": "兴城市", "label": "兴城市" } ], "value": "葫芦岛市", "label": "葫芦岛市" } ], "value": "辽宁省", "label": "辽宁省" }, { "children": [ { "children": [ { "value": "南关区", "label": "南关区" }, { "value": "宽城区", "label": "宽城区" }, { "value": "朝阳区", "label": "朝阳区" }, { "value": "二道区", "label": "二道区" }, { "value": "绿园区", "label": "绿园区" }, { "value": "双阳区", "label": "双阳区" }, { "value": "九台区", "label": "九台区" }, { "value": "农安县", "label": "农安县" }, { "value": "榆树市", "label": "榆树市" }, { "value": "德惠市", "label": "德惠市" } ], "value": "长春市", "label": "长春市" }, { "children": [ { "value": "昌邑区", "label": "昌邑区" }, { "value": "龙潭区", "label": "龙潭区" }, { "value": "船营区", "label": "船营区" }, { "value": "丰满区", "label": "丰满区" }, { "value": "永吉县", "label": "永吉县" }, { "value": "蛟河市", "label": "蛟河市" }, { "value": "桦甸市", "label": "桦甸市" }, { "value": "舒兰市", "label": "舒兰市" }, { "value": "磐石市", "label": "磐石市" } ], "value": "吉林市", "label": "吉林市" }, { "children": [ { "value": "铁西区", "label": "铁西区" }, { "value": "铁东区", "label": "铁东区" }, { "value": "梨树县", "label": "梨树县" }, { "value": "伊通满族自治县", "label": "伊通满族自治县" }, { "value": "公主岭市", "label": "公主岭市" }, { "value": "双辽市", "label": "双辽市" } ], "value": "四平市", "label": "四平市" }, { "children": [ { "value": "龙山区", "label": "龙山区" }, { "value": "西安区", "label": "西安区" }, { "value": "东丰县", "label": "东丰县" }, { "value": "东辽县", "label": "东辽县" } ], "value": "辽源市", "label": "辽源市" }, { "children": [ { "value": "东昌区", "label": "东昌区" }, { "value": "二道江区", "label": "二道江区" }, { "value": "通化县", "label": "通化县" }, { "value": "辉南县", "label": "辉南县" }, { "value": "柳河县", "label": "柳河县" }, { "value": "梅河口市", "label": "梅河口市" }, { "value": "集安市", "label": "集安市" } ], "value": "通化市", "label": "通化市" }, { "children": [ { "value": "浑江区", "label": "浑江区" }, { "value": "江源区", "label": "江源区" }, { "value": "抚松县", "label": "抚松县" }, { "value": "靖宇县", "label": "靖宇县" }, { "value": "长白朝鲜族自治县", "label": "长白朝鲜族自治县" }, { "value": "临江市", "label": "临江市" } ], "value": "白山市", "label": "白山市" }, { "children": [ { "value": "宁江区", "label": "宁江区" }, { "value": "前郭尔罗斯蒙古族自治县", "label": "前郭尔罗斯蒙古族自治县" }, { "value": "长岭县", "label": "长岭县" }, { "value": "乾安县", "label": "乾安县" }, { "value": "扶余市", "label": "扶余市" } ], "value": "松原市", "label": "松原市" }, { "children": [ { "value": "洮北区", "label": "洮北区" }, { "value": "镇赉县", "label": "镇赉县" }, { "value": "通榆县", "label": "通榆县" }, { "value": "洮南市", "label": "洮南市" }, { "value": "大安市", "label": "大安市" } ], "value": "白城市", "label": "白城市" }, { "children": [ { "value": "延吉市", "label": "延吉市" }, { "value": "图们市", "label": "图们市" }, { "value": "敦化市", "label": "敦化市" }, { "value": "珲春市", "label": "珲春市" }, { "value": "龙井市", "label": "龙井市" }, { "value": "和龙市", "label": "和龙市" }, { "value": "汪清县", "label": "汪清县" }, { "value": "安图县", "label": "安图县" } ], "value": "延边朝鲜族自治州", "label": "延边朝鲜族自治州" } ], "value": "吉林省", "label": "吉林省" }, { "children": [ { "children": [ { "value": "道里区", "label": "道里区" }, { "value": "南岗区", "label": "南岗区" }, { "value": "道外区", "label": "道外区" }, { "value": "平房区", "label": "平房区" }, { "value": "松北区", "label": "松北区" }, { "value": "香坊区", "label": "香坊区" }, { "value": "呼兰区", "label": "呼兰区" }, { "value": "阿城区", "label": "阿城区" }, { "value": "双城区", "label": "双城区" }, { "value": "依兰县", "label": "依兰县" }, { "value": "方正县", "label": "方正县" }, { "value": "宾县", "label": "宾县" }, { "value": "巴彦县", "label": "巴彦县" }, { "value": "木兰县", "label": "木兰县" }, { "value": "通河县", "label": "通河县" }, { "value": "延寿县", "label": "延寿县" }, { "value": "尚志市", "label": "尚志市" }, { "value": "五常市", "label": "五常市" } ], "value": "哈尔滨市", "label": "哈尔滨市" }, { "children": [ { "value": "龙沙区", "label": "龙沙区" }, { "value": "建华区", "label": "建华区" }, { "value": "铁锋区", "label": "铁锋区" }, { "value": "昂昂溪区", "label": "昂昂溪区" }, { "value": "富拉尔基区", "label": "富拉尔基区" }, { "value": "碾子山区", "label": "碾子山区" }, { "value": "梅里斯达斡尔族区", "label": "梅里斯达斡尔族区" }, { "value": "龙江县", "label": "龙江县" }, { "value": "依安县", "label": "依安县" }, { "value": "泰来县", "label": "泰来县" }, { "value": "甘南县", "label": "甘南县" }, { "value": "富裕县", "label": "富裕县" }, { "value": "克山县", "label": "克山县" }, { "value": "克东县", "label": "克东县" }, { "value": "拜泉县", "label": "拜泉县" }, { "value": "讷河市", "label": "讷河市" } ], "value": "齐齐哈尔市", "label": "齐齐哈尔市" }, { "children": [ { "value": "鸡冠区", "label": "鸡冠区" }, { "value": "恒山区", "label": "恒山区" }, { "value": "滴道区", "label": "滴道区" }, { "value": "梨树区", "label": "梨树区" }, { "value": "城子河区", "label": "城子河区" }, { "value": "麻山区", "label": "麻山区" }, { "value": "鸡东县", "label": "鸡东县" }, { "value": "虎林市", "label": "虎林市" }, { "value": "密山市", "label": "密山市" } ], "value": "鸡西市", "label": "鸡西市" }, { "children": [ { "value": "向阳区", "label": "向阳区" }, { "value": "工农区", "label": "工农区" }, { "value": "南山区", "label": "南山区" }, { "value": "兴安区", "label": "兴安区" }, { "value": "东山区", "label": "东山区" }, { "value": "兴山区", "label": "兴山区" }, { "value": "萝北县", "label": "萝北县" }, { "value": "绥滨县", "label": "绥滨县" } ], "value": "鹤岗市", "label": "鹤岗市" }, { "children": [ { "value": "尖山区", "label": "尖山区" }, { "value": "岭东区", "label": "岭东区" }, { "value": "四方台区", "label": "四方台区" }, { "value": "宝山区", "label": "宝山区" }, { "value": "集贤县", "label": "集贤县" }, { "value": "友谊县", "label": "友谊县" }, { "value": "宝清县", "label": "宝清县" }, { "value": "饶河县", "label": "饶河县" } ], "value": "双鸭山市", "label": "双鸭山市" }, { "children": [ { "value": "萨尔图区", "label": "萨尔图区" }, { "value": "龙凤区", "label": "龙凤区" }, { "value": "让胡路区", "label": "让胡路区" }, { "value": "红岗区", "label": "红岗区" }, { "value": "大同区", "label": "大同区" }, { "value": "肇州县", "label": "肇州县" }, { "value": "肇源县", "label": "肇源县" }, { "value": "林甸县", "label": "林甸县" }, { "value": "杜尔伯特蒙古族自治县", "label": "杜尔伯特蒙古族自治县" } ], "value": "大庆市", "label": "大庆市" }, { "children": [ { "value": "伊春区", "label": "伊春区" }, { "value": "南岔区", "label": "南岔区" }, { "value": "友好区", "label": "友好区" }, { "value": "西林区", "label": "西林区" }, { "value": "翠峦区", "label": "翠峦区" }, { "value": "新青区", "label": "新青区" }, { "value": "美溪区", "label": "美溪区" }, { "value": "金山屯区", "label": "金山屯区" }, { "value": "五营区", "label": "五营区" }, { "value": "乌马河区", "label": "乌马河区" }, { "value": "汤旺河区", "label": "汤旺河区" }, { "value": "带岭区", "label": "带岭区" }, { "value": "乌伊岭区", "label": "乌伊岭区" }, { "value": "红星区", "label": "红星区" }, { "value": "上甘岭区", "label": "上甘岭区" }, { "value": "嘉荫县", "label": "嘉荫县" }, { "value": "铁力市", "label": "铁力市" } ], "value": "伊春市", "label": "伊春市" }, { "children": [ { "value": "向阳区", "label": "向阳区" }, { "value": "前进区", "label": "前进区" }, { "value": "东风区", "label": "东风区" }, { "value": "郊区", "label": "郊区" }, { "value": "桦南县", "label": "桦南县" }, { "value": "桦川县", "label": "桦川县" }, { "value": "汤原县", "label": "汤原县" }, { "value": "同江市", "label": "同江市" }, { "value": "富锦市", "label": "富锦市" }, { "value": "抚远市", "label": "抚远市" } ], "value": "佳木斯市", "label": "佳木斯市" }, { "children": [ { "value": "新兴区", "label": "新兴区" }, { "value": "桃山区", "label": "桃山区" }, { "value": "茄子河区", "label": "茄子河区" }, { "value": "勃利县", "label": "勃利县" } ], "value": "七台河市", "label": "七台河市" }, { "children": [ { "value": "东安区", "label": "东安区" }, { "value": "阳明区", "label": "阳明区" }, { "value": "爱民区", "label": "爱民区" }, { "value": "西安区", "label": "西安区" }, { "value": "林口县", "label": "林口县" }, { "value": "绥芬河市", "label": "绥芬河市" }, { "value": "海林市", "label": "海林市" }, { "value": "宁安市", "label": "宁安市" }, { "value": "穆棱市", "label": "穆棱市" }, { "value": "东宁市", "label": "东宁市" } ], "value": "牡丹江市", "label": "牡丹江市" }, { "children": [ { "value": "爱辉区", "label": "爱辉区" }, { "value": "嫩江县", "label": "嫩江县" }, { "value": "逊克县", "label": "逊克县" }, { "value": "孙吴县", "label": "孙吴县" }, { "value": "北安市", "label": "北安市" }, { "value": "五大连池市", "label": "五大连池市" } ], "value": "黑河市", "label": "黑河市" }, { "children": [ { "value": "北林区", "label": "北林区" }, { "value": "望奎县", "label": "望奎县" }, { "value": "兰西县", "label": "兰西县" }, { "value": "青冈县", "label": "青冈县" }, { "value": "庆安县", "label": "庆安县" }, { "value": "明水县", "label": "明水县" }, { "value": "绥棱县", "label": "绥棱县" }, { "value": "安达市", "label": "安达市" }, { "value": "肇东市", "label": "肇东市" }, { "value": "海伦市", "label": "海伦市" } ], "value": "绥化市", "label": "绥化市" }, { "children": [ { "value": "呼玛县", "label": "呼玛县" }, { "value": "塔河县", "label": "塔河县" }, { "value": "漠河县", "label": "漠河县" } ], "value": "大兴安岭地区", "label": "大兴安岭地区" } ], "value": "黑龙江省", "label": "黑龙江省" }, { "children": [ { "children": [ { "value": "黄浦区", "label": "黄浦区" }, { "value": "徐汇区", "label": "徐汇区" }, { "value": "长宁区", "label": "长宁区" }, { "value": "静安区", "label": "静安区" }, { "value": "普陀区", "label": "普陀区" }, { "value": "虹口区", "label": "虹口区" }, { "value": "杨浦区", "label": "杨浦区" }, { "value": "闵行区", "label": "闵行区" }, { "value": "宝山区", "label": "宝山区" }, { "value": "嘉定区", "label": "嘉定区" }, { "value": "浦东新区", "label": "浦东新区" }, { "value": "金山区", "label": "金山区" }, { "value": "松江区", "label": "松江区" }, { "value": "青浦区", "label": "青浦区" }, { "value": "奉贤区", "label": "奉贤区" }, { "value": "崇明区", "label": "崇明区" } ], "value": "上海市", "label": "上海市" } ], "value": "上海市", "label": "上海市" }, { "children": [ { "children": [ { "value": "玄武区", "label": "玄武区" }, { "value": "秦淮区", "label": "秦淮区" }, { "value": "建邺区", "label": "建邺区" }, { "value": "鼓楼区", "label": "鼓楼区" }, { "value": "浦口区", "label": "浦口区" }, { "value": "栖霞区", "label": "栖霞区" }, { "value": "雨花台区", "label": "雨花台区" }, { "value": "江宁区", "label": "江宁区" }, { "value": "六合区", "label": "六合区" }, { "value": "溧水区", "label": "溧水区" }, { "value": "高淳区", "label": "高淳区" } ], "value": "南京市", "label": "南京市" }, { "children": [ { "value": "锡山区", "label": "锡山区" }, { "value": "惠山区", "label": "惠山区" }, { "value": "滨湖区", "label": "滨湖区" }, { "value": "梁溪区", "label": "梁溪区" }, { "value": "新吴区", "label": "新吴区" }, { "value": "江阴市", "label": "江阴市" }, { "value": "宜兴市", "label": "宜兴市" } ], "value": "无锡市", "label": "无锡市" }, { "children": [ { "value": "鼓楼区", "label": "鼓楼区" }, { "value": "云龙区", "label": "云龙区" }, { "value": "贾汪区", "label": "贾汪区" }, { "value": "泉山区", "label": "泉山区" }, { "value": "铜山区", "label": "铜山区" }, { "value": "丰县", "label": "丰县" }, { "value": "沛县", "label": "沛县" }, { "value": "睢宁县", "label": "睢宁县" }, { "value": "新沂市", "label": "新沂市" }, { "value": "邳州市", "label": "邳州市" } ], "value": "徐州市", "label": "徐州市" }, { "children": [ { "value": "天宁区", "label": "天宁区" }, { "value": "钟楼区", "label": "钟楼区" }, { "value": "新北区", "label": "新北区" }, { "value": "武进区", "label": "武进区" }, { "value": "金坛区", "label": "金坛区" }, { "value": "溧阳市", "label": "溧阳市" } ], "value": "常州市", "label": "常州市" }, { "children": [ { "value": "虎丘区", "label": "虎丘区" }, { "value": "吴中区", "label": "吴中区" }, { "value": "相城区", "label": "相城区" }, { "value": "姑苏区", "label": "姑苏区" }, { "value": "吴江区", "label": "吴江区" }, { "value": "常熟市", "label": "常熟市" }, { "value": "张家港市", "label": "张家港市" }, { "value": "昆山市", "label": "昆山市" }, { "value": "太仓市", "label": "太仓市" } ], "value": "苏州市", "label": "苏州市" }, { "children": [ { "value": "崇川区", "label": "崇川区" }, { "value": "港闸区", "label": "港闸区" }, { "value": "通州区", "label": "通州区" }, { "value": "海安县", "label": "海安县" }, { "value": "如东县", "label": "如东县" }, { "value": "启东市", "label": "启东市" }, { "value": "如皋市", "label": "如皋市" }, { "value": "海门市", "label": "海门市" } ], "value": "南通市", "label": "南通市" }, { "children": [ { "value": "连云区", "label": "连云区" }, { "value": "海州区", "label": "海州区" }, { "value": "赣榆区", "label": "赣榆区" }, { "value": "东海县", "label": "东海县" }, { "value": "灌云县", "label": "灌云县" }, { "value": "灌南县", "label": "灌南县" } ], "value": "连云港市", "label": "连云港市" }, { "children": [ { "value": "淮安区", "label": "淮安区" }, { "value": "淮阴区", "label": "淮阴区" }, { "value": "清江浦区", "label": "清江浦区" }, { "value": "洪泽区", "label": "洪泽区" }, { "value": "涟水县", "label": "涟水县" }, { "value": "盱眙县", "label": "盱眙县" }, { "value": "金湖县", "label": "金湖县" } ], "value": "淮安市", "label": "淮安市" }, { "children": [ { "value": "亭湖区", "label": "亭湖区" }, { "value": "盐都区", "label": "盐都区" }, { "value": "大丰区", "label": "大丰区" }, { "value": "响水县", "label": "响水县" }, { "value": "滨海县", "label": "滨海县" }, { "value": "阜宁县", "label": "阜宁县" }, { "value": "射阳县", "label": "射阳县" }, { "value": "建湖县", "label": "建湖县" }, { "value": "东台市", "label": "东台市" } ], "value": "盐城市", "label": "盐城市" }, { "children": [ { "value": "广陵区", "label": "广陵区" }, { "value": "邗江区", "label": "邗江区" }, { "value": "江都区", "label": "江都区" }, { "value": "宝应县", "label": "宝应县" }, { "value": "仪征市", "label": "仪征市" }, { "value": "高邮市", "label": "高邮市" } ], "value": "扬州市", "label": "扬州市" }, { "children": [ { "value": "京口区", "label": "京口区" }, { "value": "润州区", "label": "润州区" }, { "value": "丹徒区", "label": "丹徒区" }, { "value": "丹阳市", "label": "丹阳市" }, { "value": "扬中市", "label": "扬中市" }, { "value": "句容市", "label": "句容市" } ], "value": "镇江市", "label": "镇江市" }, { "children": [ { "value": "海陵区", "label": "海陵区" }, { "value": "高港区", "label": "高港区" }, { "value": "姜堰区", "label": "姜堰区" }, { "value": "兴化市", "label": "兴化市" }, { "value": "靖江市", "label": "靖江市" }, { "value": "泰兴市", "label": "泰兴市" } ], "value": "泰州市", "label": "泰州市" }, { "children": [ { "value": "宿城区", "label": "宿城区" }, { "value": "宿豫区", "label": "宿豫区" }, { "value": "沭阳县", "label": "沭阳县" }, { "value": "泗阳县", "label": "泗阳县" }, { "value": "泗洪县", "label": "泗洪县" } ], "value": "宿迁市", "label": "宿迁市" } ], "value": "江苏省", "label": "江苏省" }, { "children": [ { "children": [ { "value": "上城区", "label": "上城区" }, { "value": "下城区", "label": "下城区" }, { "value": "江干区", "label": "江干区" }, { "value": "拱墅区", "label": "拱墅区" }, { "value": "西湖区", "label": "西湖区" }, { "value": "滨江区", "label": "滨江区" }, { "value": "萧山区", "label": "萧山区" }, { "value": "余杭区", "label": "余杭区" }, { "value": "富阳区", "label": "富阳区" }, { "value": "临安区", "label": "临安区" }, { "value": "桐庐县", "label": "桐庐县" }, { "value": "淳安县", "label": "淳安县" }, { "value": "建德市", "label": "建德市" } ], "value": "杭州市", "label": "杭州市" }, { "children": [ { "value": "海曙区", "label": "海曙区" }, { "value": "江北区", "label": "江北区" }, { "value": "北仑区", "label": "北仑区" }, { "value": "镇海区", "label": "镇海区" }, { "value": "鄞州区", "label": "鄞州区" }, { "value": "奉化区", "label": "奉化区" }, { "value": "象山县", "label": "象山县" }, { "value": "宁海县", "label": "宁海县" }, { "value": "余姚市", "label": "余姚市" }, { "value": "慈溪市", "label": "慈溪市" } ], "value": "宁波市", "label": "宁波市" }, { "children": [ { "value": "鹿城区", "label": "鹿城区" }, { "value": "龙湾区", "label": "龙湾区" }, { "value": "瓯海区", "label": "瓯海区" }, { "value": "洞头区", "label": "洞头区" }, { "value": "永嘉县", "label": "永嘉县" }, { "value": "平阳县", "label": "平阳县" }, { "value": "苍南县", "label": "苍南县" }, { "value": "文成县", "label": "文成县" }, { "value": "泰顺县", "label": "泰顺县" }, { "value": "瑞安市", "label": "瑞安市" }, { "value": "乐清市", "label": "乐清市" } ], "value": "温州市", "label": "温州市" }, { "children": [ { "value": "南湖区", "label": "南湖区" }, { "value": "秀洲区", "label": "秀洲区" }, { "value": "嘉善县", "label": "嘉善县" }, { "value": "海盐县", "label": "海盐县" }, { "value": "海宁市", "label": "海宁市" }, { "value": "平湖市", "label": "平湖市" }, { "value": "桐乡市", "label": "桐乡市" } ], "value": "嘉兴市", "label": "嘉兴市" }, { "children": [ { "value": "吴兴区", "label": "吴兴区" }, { "value": "南浔区", "label": "南浔区" }, { "value": "德清县", "label": "德清县" }, { "value": "长兴县", "label": "长兴县" }, { "value": "安吉县", "label": "安吉县" } ], "value": "湖州市", "label": "湖州市" }, { "children": [ { "value": "越城区", "label": "越城区" }, { "value": "柯桥区", "label": "柯桥区" }, { "value": "上虞区", "label": "上虞区" }, { "value": "新昌县", "label": "新昌县" }, { "value": "诸暨市", "label": "诸暨市" }, { "value": "嵊州市", "label": "嵊州市" } ], "value": "绍兴市", "label": "绍兴市" }, { "children": [ { "value": "婺城区", "label": "婺城区" }, { "value": "金东区", "label": "金东区" }, { "value": "武义县", "label": "武义县" }, { "value": "浦江县", "label": "浦江县" }, { "value": "磐安县", "label": "磐安县" }, { "value": "兰溪市", "label": "兰溪市" }, { "value": "义乌市", "label": "义乌市" }, { "value": "东阳市", "label": "东阳市" }, { "value": "永康市", "label": "永康市" } ], "value": "金华市", "label": "金华市" }, { "children": [ { "value": "柯城区", "label": "柯城区" }, { "value": "衢江区", "label": "衢江区" }, { "value": "常山县", "label": "常山县" }, { "value": "开化县", "label": "开化县" }, { "value": "龙游县", "label": "龙游县" }, { "value": "江山市", "label": "江山市" } ], "value": "衢州市", "label": "衢州市" }, { "children": [ { "value": "定海区", "label": "定海区" }, { "value": "普陀区", "label": "普陀区" }, { "value": "岱山县", "label": "岱山县" }, { "value": "嵊泗县", "label": "嵊泗县" } ], "value": "舟山市", "label": "舟山市" }, { "children": [ { "value": "椒江区", "label": "椒江区" }, { "value": "黄岩区", "label": "黄岩区" }, { "value": "路桥区", "label": "路桥区" }, { "value": "三门县", "label": "三门县" }, { "value": "天台县", "label": "天台县" }, { "value": "仙居县", "label": "仙居县" }, { "value": "温岭市", "label": "温岭市" }, { "value": "临海市", "label": "临海市" }, { "value": "玉环市", "label": "玉环市" } ], "value": "台州市", "label": "台州市" }, { "children": [ { "value": "莲都区", "label": "莲都区" }, { "value": "青田县", "label": "青田县" }, { "value": "缙云县", "label": "缙云县" }, { "value": "遂昌县", "label": "遂昌县" }, { "value": "松阳县", "label": "松阳县" }, { "value": "云和县", "label": "云和县" }, { "value": "庆元县", "label": "庆元县" }, { "value": "景宁畲族自治县", "label": "景宁畲族自治县" }, { "value": "龙泉市", "label": "龙泉市" } ], "value": "丽水市", "label": "丽水市" } ], "value": "浙江省", "label": "浙江省" }, { "children": [ { "children": [ { "value": "瑶海区", "label": "瑶海区" }, { "value": "庐阳区", "label": "庐阳区" }, { "value": "蜀山区", "label": "蜀山区" }, { "value": "包河区", "label": "包河区" }, { "value": "长丰县", "label": "长丰县" }, { "value": "肥东县", "label": "肥东县" }, { "value": "肥西县", "label": "肥西县" }, { "value": "庐江县", "label": "庐江县" }, { "value": "巢湖市", "label": "巢湖市" } ], "value": "合肥市", "label": "合肥市" }, { "children": [ { "value": "镜湖区", "label": "镜湖区" }, { "value": "弋江区", "label": "弋江区" }, { "value": "鸠江区", "label": "鸠江区" }, { "value": "三山区", "label": "三山区" }, { "value": "芜湖县", "label": "芜湖县" }, { "value": "繁昌县", "label": "繁昌县" }, { "value": "南陵县", "label": "南陵县" }, { "value": "无为县", "label": "无为县" } ], "value": "芜湖市", "label": "芜湖市" }, { "children": [ { "value": "龙子湖区", "label": "龙子湖区" }, { "value": "蚌山区", "label": "蚌山区" }, { "value": "禹会区", "label": "禹会区" }, { "value": "淮上区", "label": "淮上区" }, { "value": "怀远县", "label": "怀远县" }, { "value": "五河县", "label": "五河县" }, { "value": "固镇县", "label": "固镇县" } ], "value": "蚌埠市", "label": "蚌埠市" }, { "children": [ { "value": "大通区", "label": "大通区" }, { "value": "田家庵区", "label": "田家庵区" }, { "value": "谢家集区", "label": "谢家集区" }, { "value": "八公山区", "label": "八公山区" }, { "value": "潘集区", "label": "潘集区" }, { "value": "凤台县", "label": "凤台县" }, { "value": "寿县", "label": "寿县" } ], "value": "淮南市", "label": "淮南市" }, { "children": [ { "value": "花山区", "label": "花山区" }, { "value": "雨山区", "label": "雨山区" }, { "value": "博望区", "label": "博望区" }, { "value": "当涂县", "label": "当涂县" }, { "value": "含山县", "label": "含山县" }, { "value": "和县", "label": "和县" } ], "value": "马鞍山市", "label": "马鞍山市" }, { "children": [ { "value": "杜集区", "label": "杜集区" }, { "value": "相山区", "label": "相山区" }, { "value": "烈山区", "label": "烈山区" }, { "value": "濉溪县", "label": "濉溪县" } ], "value": "淮北市", "label": "淮北市" }, { "children": [ { "value": "铜官区", "label": "铜官区" }, { "value": "义安区", "label": "义安区" }, { "value": "郊区", "label": "郊区" }, { "value": "枞阳县", "label": "枞阳县" } ], "value": "铜陵市", "label": "铜陵市" }, { "children": [ { "value": "迎江区", "label": "迎江区" }, { "value": "大观区", "label": "大观区" }, { "value": "宜秀区", "label": "宜秀区" }, { "value": "怀宁县", "label": "怀宁县" }, { "value": "潜山县", "label": "潜山县" }, { "value": "太湖县", "label": "太湖县" }, { "value": "宿松县", "label": "宿松县" }, { "value": "望江县", "label": "望江县" }, { "value": "岳西县", "label": "岳西县" }, { "value": "桐城市", "label": "桐城市" } ], "value": "安庆市", "label": "安庆市" }, { "children": [ { "value": "屯溪区", "label": "屯溪区" }, { "value": "黄山区", "label": "黄山区" }, { "value": "徽州区", "label": "徽州区" }, { "value": "歙县", "label": "歙县" }, { "value": "休宁县", "label": "休宁县" }, { "value": "黟县", "label": "黟县" }, { "value": "祁门县", "label": "祁门县" } ], "value": "黄山市", "label": "黄山市" }, { "children": [ { "value": "琅琊区", "label": "琅琊区" }, { "value": "南谯区", "label": "南谯区" }, { "value": "来安县", "label": "来安县" }, { "value": "全椒县", "label": "全椒县" }, { "value": "定远县", "label": "定远县" }, { "value": "凤阳县", "label": "凤阳县" }, { "value": "天长市", "label": "天长市" }, { "value": "明光市", "label": "明光市" } ], "value": "滁州市", "label": "滁州市" }, { "children": [ { "value": "颍州区", "label": "颍州区" }, { "value": "颍东区", "label": "颍东区" }, { "value": "颍泉区", "label": "颍泉区" }, { "value": "临泉县", "label": "临泉县" }, { "value": "太和县", "label": "太和县" }, { "value": "阜南县", "label": "阜南县" }, { "value": "颍上县", "label": "颍上县" }, { "value": "界首市", "label": "界首市" } ], "value": "阜阳市", "label": "阜阳市" }, { "children": [ { "value": "埇桥区", "label": "埇桥区" }, { "value": "砀山县", "label": "砀山县" }, { "value": "萧县", "label": "萧县" }, { "value": "灵璧县", "label": "灵璧县" }, { "value": "泗县", "label": "泗县" } ], "value": "宿州市", "label": "宿州市" }, { "children": [ { "value": "金安区", "label": "金安区" }, { "value": "裕安区", "label": "裕安区" }, { "value": "叶集区", "label": "叶集区" }, { "value": "霍邱县", "label": "霍邱县" }, { "value": "舒城县", "label": "舒城县" }, { "value": "金寨县", "label": "金寨县" }, { "value": "霍山县", "label": "霍山县" } ], "value": "六安市", "label": "六安市" }, { "children": [ { "value": "谯城区", "label": "谯城区" }, { "value": "涡阳县", "label": "涡阳县" }, { "value": "蒙城县", "label": "蒙城县" }, { "value": "利辛县", "label": "利辛县" } ], "value": "亳州市", "label": "亳州市" }, { "children": [ { "value": "贵池区", "label": "贵池区" }, { "value": "东至县", "label": "东至县" }, { "value": "石台县", "label": "石台县" }, { "value": "青阳县", "label": "青阳县" } ], "value": "池州市", "label": "池州市" }, { "children": [ { "value": "宣州区", "label": "宣州区" }, { "value": "郎溪县", "label": "郎溪县" }, { "value": "广德县", "label": "广德县" }, { "value": "泾县", "label": "泾县" }, { "value": "绩溪县", "label": "绩溪县" }, { "value": "旌德县", "label": "旌德县" }, { "value": "宁国市", "label": "宁国市" } ], "value": "宣城市", "label": "宣城市" } ], "value": "安徽省", "label": "安徽省" }, { "children": [ { "children": [ { "value": "鼓楼区", "label": "鼓楼区" }, { "value": "台江区", "label": "台江区" }, { "value": "仓山区", "label": "仓山区" }, { "value": "马尾区", "label": "马尾区" }, { "value": "晋安区", "label": "晋安区" }, { "value": "长乐区", "label": "长乐区" }, { "value": "闽侯县", "label": "闽侯县" }, { "value": "连江县", "label": "连江县" }, { "value": "罗源县", "label": "罗源县" }, { "value": "闽清县", "label": "闽清县" }, { "value": "永泰县", "label": "永泰县" }, { "value": "平潭县", "label": "平潭县" }, { "value": "福清市", "label": "福清市" } ], "value": "福州市", "label": "福州市" }, { "children": [ { "value": "思明区", "label": "思明区" }, { "value": "海沧区", "label": "海沧区" }, { "value": "湖里区", "label": "湖里区" }, { "value": "集美区", "label": "集美区" }, { "value": "同安区", "label": "同安区" }, { "value": "翔安区", "label": "翔安区" } ], "value": "厦门市", "label": "厦门市" }, { "children": [ { "value": "城厢区", "label": "城厢区" }, { "value": "涵江区", "label": "涵江区" }, { "value": "荔城区", "label": "荔城区" }, { "value": "秀屿区", "label": "秀屿区" }, { "value": "仙游县", "label": "仙游县" } ], "value": "莆田市", "label": "莆田市" }, { "children": [ { "value": "梅列区", "label": "梅列区" }, { "value": "三元区", "label": "三元区" }, { "value": "明溪县", "label": "明溪县" }, { "value": "清流县", "label": "清流县" }, { "value": "宁化县", "label": "宁化县" }, { "value": "大田县", "label": "大田县" }, { "value": "尤溪县", "label": "尤溪县" }, { "value": "沙县", "label": "沙县" }, { "value": "将乐县", "label": "将乐县" }, { "value": "泰宁县", "label": "泰宁县" }, { "value": "建宁县", "label": "建宁县" }, { "value": "永安市", "label": "永安市" } ], "value": "三明市", "label": "三明市" }, { "children": [ { "value": "鲤城区", "label": "鲤城区" }, { "value": "丰泽区", "label": "丰泽区" }, { "value": "洛江区", "label": "洛江区" }, { "value": "泉港区", "label": "泉港区" }, { "value": "惠安县", "label": "惠安县" }, { "value": "安溪县", "label": "安溪县" }, { "value": "永春县", "label": "永春县" }, { "value": "德化县", "label": "德化县" }, { "value": "金门县", "label": "金门县" }, { "value": "石狮市", "label": "石狮市" }, { "value": "晋江市", "label": "晋江市" }, { "value": "南安市", "label": "南安市" } ], "value": "泉州市", "label": "泉州市" }, { "children": [ { "value": "芗城区", "label": "芗城区" }, { "value": "龙文区", "label": "龙文区" }, { "value": "云霄县", "label": "云霄县" }, { "value": "漳浦县", "label": "漳浦县" }, { "value": "诏安县", "label": "诏安县" }, { "value": "长泰县", "label": "长泰县" }, { "value": "东山县", "label": "东山县" }, { "value": "南靖县", "label": "南靖县" }, { "value": "平和县", "label": "平和县" }, { "value": "华安县", "label": "华安县" }, { "value": "龙海市", "label": "龙海市" } ], "value": "漳州市", "label": "漳州市" }, { "children": [ { "value": "延平区", "label": "延平区" }, { "value": "建阳区", "label": "建阳区" }, { "value": "顺昌县", "label": "顺昌县" }, { "value": "浦城县", "label": "浦城县" }, { "value": "光泽县", "label": "光泽县" }, { "value": "松溪县", "label": "松溪县" }, { "value": "政和县", "label": "政和县" }, { "value": "邵武市", "label": "邵武市" }, { "value": "武夷山市", "label": "武夷山市" }, { "value": "建瓯市", "label": "建瓯市" } ], "value": "南平市", "label": "南平市" }, { "children": [ { "value": "新罗区", "label": "新罗区" }, { "value": "永定区", "label": "永定区" }, { "value": "长汀县", "label": "长汀县" }, { "value": "上杭县", "label": "上杭县" }, { "value": "武平县", "label": "武平县" }, { "value": "连城县", "label": "连城县" }, { "value": "漳平市", "label": "漳平市" } ], "value": "龙岩市", "label": "龙岩市" }, { "children": [ { "value": "蕉城区", "label": "蕉城区" }, { "value": "霞浦县", "label": "霞浦县" }, { "value": "古田县", "label": "古田县" }, { "value": "屏南县", "label": "屏南县" }, { "value": "寿宁县", "label": "寿宁县" }, { "value": "周宁县", "label": "周宁县" }, { "value": "柘荣县", "label": "柘荣县" }, { "value": "福安市", "label": "福安市" }, { "value": "福鼎市", "label": "福鼎市" } ], "value": "宁德市", "label": "宁德市" } ], "value": "福建省", "label": "福建省" }, { "children": [ { "children": [ { "value": "东湖区", "label": "东湖区" }, { "value": "西湖区", "label": "西湖区" }, { "value": "青云谱区", "label": "青云谱区" }, { "value": "湾里区", "label": "湾里区" }, { "value": "青山湖区", "label": "青山湖区" }, { "value": "新建区", "label": "新建区" }, { "value": "南昌县", "label": "南昌县" }, { "value": "安义县", "label": "安义县" }, { "value": "进贤县", "label": "进贤县" } ], "value": "南昌市", "label": "南昌市" }, { "children": [ { "value": "昌江区", "label": "昌江区" }, { "value": "珠山区", "label": "珠山区" }, { "value": "浮梁县", "label": "浮梁县" }, { "value": "乐平市", "label": "乐平市" } ], "value": "景德镇市", "label": "景德镇市" }, { "children": [ { "value": "安源区", "label": "安源区" }, { "value": "湘东区", "label": "湘东区" }, { "value": "莲花县", "label": "莲花县" }, { "value": "上栗县", "label": "上栗县" }, { "value": "芦溪县", "label": "芦溪县" } ], "value": "萍乡市", "label": "萍乡市" }, { "children": [ { "value": "濂溪区", "label": "濂溪区" }, { "value": "浔阳区", "label": "浔阳区" }, { "value": "柴桑区", "label": "柴桑区" }, { "value": "武宁县", "label": "武宁县" }, { "value": "修水县", "label": "修水县" }, { "value": "永修县", "label": "永修县" }, { "value": "德安县", "label": "德安县" }, { "value": "都昌县", "label": "都昌县" }, { "value": "湖口县", "label": "湖口县" }, { "value": "彭泽县", "label": "彭泽县" }, { "value": "瑞昌市", "label": "瑞昌市" }, { "value": "共青城市", "label": "共青城市" }, { "value": "庐山市", "label": "庐山市" } ], "value": "九江市", "label": "九江市" }, { "children": [ { "value": "渝水区", "label": "渝水区" }, { "value": "分宜县", "label": "分宜县" } ], "value": "新余市", "label": "新余市" }, { "children": [ { "value": "月湖区", "label": "月湖区" }, { "value": "余江县", "label": "余江县" }, { "value": "贵溪市", "label": "贵溪市" } ], "value": "鹰潭市", "label": "鹰潭市" }, { "children": [ { "value": "章贡区", "label": "章贡区" }, { "value": "南康区", "label": "南康区" }, { "value": "赣县区", "label": "赣县区" }, { "value": "信丰县", "label": "信丰县" }, { "value": "大余县", "label": "大余县" }, { "value": "上犹县", "label": "上犹县" }, { "value": "崇义县", "label": "崇义县" }, { "value": "安远县", "label": "安远县" }, { "value": "龙南县", "label": "龙南县" }, { "value": "定南县", "label": "定南县" }, { "value": "全南县", "label": "全南县" }, { "value": "宁都县", "label": "宁都县" }, { "value": "于都县", "label": "于都县" }, { "value": "兴国县", "label": "兴国县" }, { "value": "会昌县", "label": "会昌县" }, { "value": "寻乌县", "label": "寻乌县" }, { "value": "石城县", "label": "石城县" }, { "value": "瑞金市", "label": "瑞金市" } ], "value": "赣州市", "label": "赣州市" }, { "children": [ { "value": "吉州区", "label": "吉州区" }, { "value": "青原区", "label": "青原区" }, { "value": "吉安县", "label": "吉安县" }, { "value": "吉水县", "label": "吉水县" }, { "value": "峡江县", "label": "峡江县" }, { "value": "新干县", "label": "新干县" }, { "value": "永丰县", "label": "永丰县" }, { "value": "泰和县", "label": "泰和县" }, { "value": "遂川县", "label": "遂川县" }, { "value": "万安县", "label": "万安县" }, { "value": "安福县", "label": "安福县" }, { "value": "永新县", "label": "永新县" }, { "value": "井冈山市", "label": "井冈山市" } ], "value": "吉安市", "label": "吉安市" }, { "children": [ { "value": "袁州区", "label": "袁州区" }, { "value": "奉新县", "label": "奉新县" }, { "value": "万载县", "label": "万载县" }, { "value": "上高县", "label": "上高县" }, { "value": "宜丰县", "label": "宜丰县" }, { "value": "靖安县", "label": "靖安县" }, { "value": "铜鼓县", "label": "铜鼓县" }, { "value": "丰城市", "label": "丰城市" }, { "value": "樟树市", "label": "樟树市" }, { "value": "高安市", "label": "高安市" } ], "value": "宜春市", "label": "宜春市" }, { "children": [ { "value": "临川区", "label": "临川区" }, { "value": "东乡区", "label": "东乡区" }, { "value": "南城县", "label": "南城县" }, { "value": "黎川县", "label": "黎川县" }, { "value": "南丰县", "label": "南丰县" }, { "value": "崇仁县", "label": "崇仁县" }, { "value": "乐安县", "label": "乐安县" }, { "value": "宜黄县", "label": "宜黄县" }, { "value": "金溪县", "label": "金溪县" }, { "value": "资溪县", "label": "资溪县" }, { "value": "广昌县", "label": "广昌县" } ], "value": "抚州市", "label": "抚州市" }, { "children": [ { "value": "信州区", "label": "信州区" }, { "value": "广丰区", "label": "广丰区" }, { "value": "上饶县", "label": "上饶县" }, { "value": "玉山县", "label": "玉山县" }, { "value": "铅山县", "label": "铅山县" }, { "value": "横峰县", "label": "横峰县" }, { "value": "弋阳县", "label": "弋阳县" }, { "value": "余干县", "label": "余干县" }, { "value": "鄱阳县", "label": "鄱阳县" }, { "value": "万年县", "label": "万年县" }, { "value": "婺源县", "label": "婺源县" }, { "value": "德兴市", "label": "德兴市" } ], "value": "上饶市", "label": "上饶市" } ], "value": "江西省", "label": "江西省" }, { "children": [ { "children": [ { "value": "历下区", "label": "历下区" }, { "value": "市中区", "label": "市中区" }, { "value": "槐荫区", "label": "槐荫区" }, { "value": "天桥区", "label": "天桥区" }, { "value": "历城区", "label": "历城区" }, { "value": "长清区", "label": "长清区" }, { "value": "章丘区", "label": "章丘区" }, { "value": "平阴县", "label": "平阴县" }, { "value": "济阳县", "label": "济阳县" }, { "value": "商河县", "label": "商河县" } ], "value": "济南市", "label": "济南市" }, { "children": [ { "value": "市南区", "label": "市南区" }, { "value": "市北区", "label": "市北区" }, { "value": "黄岛区", "label": "黄岛区" }, { "value": "崂山区", "label": "崂山区" }, { "value": "李沧区", "label": "李沧区" }, { "value": "城阳区", "label": "城阳区" }, { "value": "即墨区", "label": "即墨区" }, { "value": "胶州市", "label": "胶州市" }, { "value": "平度市", "label": "平度市" }, { "value": "莱西市", "label": "莱西市" } ], "value": "青岛市", "label": "青岛市" }, { "children": [ { "value": "淄川区", "label": "淄川区" }, { "value": "张店区", "label": "张店区" }, { "value": "博山区", "label": "博山区" }, { "value": "临淄区", "label": "临淄区" }, { "value": "周村区", "label": "周村区" }, { "value": "桓台县", "label": "桓台县" }, { "value": "高青县", "label": "高青县" }, { "value": "沂源县", "label": "沂源县" } ], "value": "淄博市", "label": "淄博市" }, { "children": [ { "value": "市中区", "label": "市中区" }, { "value": "薛城区", "label": "薛城区" }, { "value": "峄城区", "label": "峄城区" }, { "value": "台儿庄区", "label": "台儿庄区" }, { "value": "山亭区", "label": "山亭区" }, { "value": "滕州市", "label": "滕州市" } ], "value": "枣庄市", "label": "枣庄市" }, { "children": [ { "value": "东营区", "label": "东营区" }, { "value": "河口区", "label": "河口区" }, { "value": "垦利区", "label": "垦利区" }, { "value": "利津县", "label": "利津县" }, { "value": "广饶县", "label": "广饶县" } ], "value": "东营市", "label": "东营市" }, { "children": [ { "value": "芝罘区", "label": "芝罘区" }, { "value": "福山区", "label": "福山区" }, { "value": "牟平区", "label": "牟平区" }, { "value": "莱山区", "label": "莱山区" }, { "value": "长岛县", "label": "长岛县" }, { "value": "龙口市", "label": "龙口市" }, { "value": "莱阳市", "label": "莱阳市" }, { "value": "莱州市", "label": "莱州市" }, { "value": "蓬莱市", "label": "蓬莱市" }, { "value": "招远市", "label": "招远市" }, { "value": "栖霞市", "label": "栖霞市" }, { "value": "海阳市", "label": "海阳市" } ], "value": "烟台市", "label": "烟台市" }, { "children": [ { "value": "潍城区", "label": "潍城区" }, { "value": "寒亭区", "label": "寒亭区" }, { "value": "坊子区", "label": "坊子区" }, { "value": "奎文区", "label": "奎文区" }, { "value": "临朐县", "label": "临朐县" }, { "value": "昌乐县", "label": "昌乐县" }, { "value": "青州市", "label": "青州市" }, { "value": "诸城市", "label": "诸城市" }, { "value": "寿光市", "label": "寿光市" }, { "value": "安丘市", "label": "安丘市" }, { "value": "高密市", "label": "高密市" }, { "value": "昌邑市", "label": "昌邑市" } ], "value": "潍坊市", "label": "潍坊市" }, { "children": [ { "value": "任城区", "label": "任城区" }, { "value": "兖州区", "label": "兖州区" }, { "value": "微山县", "label": "微山县" }, { "value": "鱼台县", "label": "鱼台县" }, { "value": "金乡县", "label": "金乡县" }, { "value": "嘉祥县", "label": "嘉祥县" }, { "value": "汶上县", "label": "汶上县" }, { "value": "泗水县", "label": "泗水县" }, { "value": "梁山县", "label": "梁山县" }, { "value": "曲阜市", "label": "曲阜市" }, { "value": "邹城市", "label": "邹城市" } ], "value": "济宁市", "label": "济宁市" }, { "children": [ { "value": "泰山区", "label": "泰山区" }, { "value": "岱岳区", "label": "岱岳区" }, { "value": "宁阳县", "label": "宁阳县" }, { "value": "东平县", "label": "东平县" }, { "value": "新泰市", "label": "新泰市" }, { "value": "肥城市", "label": "肥城市" } ], "value": "泰安市", "label": "泰安市" }, { "children": [ { "value": "环翠区", "label": "环翠区" }, { "value": "文登区", "label": "文登区" }, { "value": "荣成市", "label": "荣成市" }, { "value": "乳山市", "label": "乳山市" } ], "value": "威海市", "label": "威海市" }, { "children": [ { "value": "东港区", "label": "东港区" }, { "value": "岚山区", "label": "岚山区" }, { "value": "五莲县", "label": "五莲县" }, { "value": "莒县", "label": "莒县" } ], "value": "日照市", "label": "日照市" }, { "children": [ { "value": "莱城区", "label": "莱城区" }, { "value": "钢城区", "label": "钢城区" } ], "value": "莱芜市", "label": "莱芜市" }, { "children": [ { "value": "兰山区", "label": "兰山区" }, { "value": "罗庄区", "label": "罗庄区" }, { "value": "河东区", "label": "河东区" }, { "value": "沂南县", "label": "沂南县" }, { "value": "郯城县", "label": "郯城县" }, { "value": "沂水县", "label": "沂水县" }, { "value": "兰陵县", "label": "兰陵县" }, { "value": "费县", "label": "费县" }, { "value": "平邑县", "label": "平邑县" }, { "value": "莒南县", "label": "莒南县" }, { "value": "蒙阴县", "label": "蒙阴县" }, { "value": "临沭县", "label": "临沭县" } ], "value": "临沂市", "label": "临沂市" }, { "children": [ { "value": "德城区", "label": "德城区" }, { "value": "陵城区", "label": "陵城区" }, { "value": "宁津县", "label": "宁津县" }, { "value": "庆云县", "label": "庆云县" }, { "value": "临邑县", "label": "临邑县" }, { "value": "齐河县", "label": "齐河县" }, { "value": "平原县", "label": "平原县" }, { "value": "夏津县", "label": "夏津县" }, { "value": "武城县", "label": "武城县" }, { "value": "乐陵市", "label": "乐陵市" }, { "value": "禹城市", "label": "禹城市" } ], "value": "德州市", "label": "德州市" }, { "children": [ { "value": "东昌府区", "label": "东昌府区" }, { "value": "阳谷县", "label": "阳谷县" }, { "value": "莘县", "label": "莘县" }, { "value": "茌平县", "label": "茌平县" }, { "value": "东阿县", "label": "东阿县" }, { "value": "冠县", "label": "冠县" }, { "value": "高唐县", "label": "高唐县" }, { "value": "临清市", "label": "临清市" } ], "value": "聊城市", "label": "聊城市" }, { "children": [ { "value": "滨城区", "label": "滨城区" }, { "value": "沾化区", "label": "沾化区" }, { "value": "惠民县", "label": "惠民县" }, { "value": "阳信县", "label": "阳信县" }, { "value": "无棣县", "label": "无棣县" }, { "value": "博兴县", "label": "博兴县" }, { "value": "邹平县", "label": "邹平县" } ], "value": "滨州市", "label": "滨州市" }, { "children": [ { "value": "牡丹区", "label": "牡丹区" }, { "value": "定陶区", "label": "定陶区" }, { "value": "曹县", "label": "曹县" }, { "value": "单县", "label": "单县" }, { "value": "成武县", "label": "成武县" }, { "value": "巨野县", "label": "巨野县" }, { "value": "郓城县", "label": "郓城县" }, { "value": "鄄城县", "label": "鄄城县" }, { "value": "东明县", "label": "东明县" } ], "value": "菏泽市", "label": "菏泽市" } ], "value": "山东省", "label": "山东省" }, { "children": [ { "children": [ { "value": "中原区", "label": "中原区" }, { "value": "二七区", "label": "二七区" }, { "value": "管城回族区", "label": "管城回族区" }, { "value": "金水区", "label": "金水区" }, { "value": "上街区", "label": "上街区" }, { "value": "惠济区", "label": "惠济区" }, { "value": "中牟县", "label": "中牟县" }, { "value": "巩义市", "label": "巩义市" }, { "value": "荥阳市", "label": "荥阳市" }, { "value": "新密市", "label": "新密市" }, { "value": "新郑市", "label": "新郑市" }, { "value": "登封市", "label": "登封市" } ], "value": "郑州市", "label": "郑州市" }, { "children": [ { "value": "龙亭区", "label": "龙亭区" }, { "value": "顺河回族区", "label": "顺河回族区" }, { "value": "鼓楼区", "label": "鼓楼区" }, { "value": "禹王台区", "label": "禹王台区" }, { "value": "祥符区", "label": "祥符区" }, { "value": "杞县", "label": "杞县" }, { "value": "通许县", "label": "通许县" }, { "value": "尉氏县", "label": "尉氏县" }, { "value": "兰考县", "label": "兰考县" } ], "value": "开封市", "label": "开封市" }, { "children": [ { "value": "老城区", "label": "老城区" }, { "value": "西工区", "label": "西工区" }, { "value": "瀍河回族区", "label": "瀍河回族区" }, { "value": "涧西区", "label": "涧西区" }, { "value": "吉利区", "label": "吉利区" }, { "value": "洛龙区", "label": "洛龙区" }, { "value": "孟津县", "label": "孟津县" }, { "value": "新安县", "label": "新安县" }, { "value": "栾川县", "label": "栾川县" }, { "value": "嵩县", "label": "嵩县" }, { "value": "汝阳县", "label": "汝阳县" }, { "value": "宜阳县", "label": "宜阳县" }, { "value": "洛宁县", "label": "洛宁县" }, { "value": "伊川县", "label": "伊川县" }, { "value": "偃师市", "label": "偃师市" } ], "value": "洛阳市", "label": "洛阳市" }, { "children": [ { "value": "新华区", "label": "新华区" }, { "value": "卫东区", "label": "卫东区" }, { "value": "石龙区", "label": "石龙区" }, { "value": "湛河区", "label": "湛河区" }, { "value": "宝丰县", "label": "宝丰县" }, { "value": "叶县", "label": "叶县" }, { "value": "鲁山县", "label": "鲁山县" }, { "value": "郏县", "label": "郏县" }, { "value": "舞钢市", "label": "舞钢市" }, { "value": "汝州市", "label": "汝州市" } ], "value": "平顶山市", "label": "平顶山市" }, { "children": [ { "value": "文峰区", "label": "文峰区" }, { "value": "北关区", "label": "北关区" }, { "value": "殷都区", "label": "殷都区" }, { "value": "龙安区", "label": "龙安区" }, { "value": "安阳县", "label": "安阳县" }, { "value": "汤阴县", "label": "汤阴县" }, { "value": "滑县", "label": "滑县" }, { "value": "内黄县", "label": "内黄县" }, { "value": "林州市", "label": "林州市" } ], "value": "安阳市", "label": "安阳市" }, { "children": [ { "value": "鹤山区", "label": "鹤山区" }, { "value": "山城区", "label": "山城区" }, { "value": "淇滨区", "label": "淇滨区" }, { "value": "浚县", "label": "浚县" }, { "value": "淇县", "label": "淇县" } ], "value": "鹤壁市", "label": "鹤壁市" }, { "children": [ { "value": "红旗区", "label": "红旗区" }, { "value": "卫滨区", "label": "卫滨区" }, { "value": "凤泉区", "label": "凤泉区" }, { "value": "牧野区", "label": "牧野区" }, { "value": "新乡县", "label": "新乡县" }, { "value": "获嘉县", "label": "获嘉县" }, { "value": "原阳县", "label": "原阳县" }, { "value": "延津县", "label": "延津县" }, { "value": "封丘县", "label": "封丘县" }, { "value": "长垣县", "label": "长垣县" }, { "value": "卫辉市", "label": "卫辉市" }, { "value": "辉县市", "label": "辉县市" } ], "value": "新乡市", "label": "新乡市" }, { "children": [ { "value": "解放区", "label": "解放区" }, { "value": "中站区", "label": "中站区" }, { "value": "马村区", "label": "马村区" }, { "value": "山阳区", "label": "山阳区" }, { "value": "修武县", "label": "修武县" }, { "value": "博爱县", "label": "博爱县" }, { "value": "武陟县", "label": "武陟县" }, { "value": "温县", "label": "温县" }, { "value": "沁阳市", "label": "沁阳市" }, { "value": "孟州市", "label": "孟州市" } ], "value": "焦作市", "label": "焦作市" }, { "children": [ { "value": "华龙区", "label": "华龙区" }, { "value": "清丰县", "label": "清丰县" }, { "value": "南乐县", "label": "南乐县" }, { "value": "范县", "label": "范县" }, { "value": "台前县", "label": "台前县" }, { "value": "濮阳县", "label": "濮阳县" } ], "value": "濮阳市", "label": "濮阳市" }, { "children": [ { "value": "魏都区", "label": "魏都区" }, { "value": "建安区", "label": "建安区" }, { "value": "鄢陵县", "label": "鄢陵县" }, { "value": "襄城县", "label": "襄城县" }, { "value": "禹州市", "label": "禹州市" }, { "value": "长葛市", "label": "长葛市" } ], "value": "许昌市", "label": "许昌市" }, { "children": [ { "value": "源汇区", "label": "源汇区" }, { "value": "郾城区", "label": "郾城区" }, { "value": "召陵区", "label": "召陵区" }, { "value": "舞阳县", "label": "舞阳县" }, { "value": "临颍县", "label": "临颍县" } ], "value": "漯河市", "label": "漯河市" }, { "children": [ { "value": "湖滨区", "label": "湖滨区" }, { "value": "陕州区", "label": "陕州区" }, { "value": "渑池县", "label": "渑池县" }, { "value": "卢氏县", "label": "卢氏县" }, { "value": "义马市", "label": "义马市" }, { "value": "灵宝市", "label": "灵宝市" } ], "value": "三门峡市", "label": "三门峡市" }, { "children": [ { "value": "宛城区", "label": "宛城区" }, { "value": "卧龙区", "label": "卧龙区" }, { "value": "南召县", "label": "南召县" }, { "value": "方城县", "label": "方城县" }, { "value": "西峡县", "label": "西峡县" }, { "value": "镇平县", "label": "镇平县" }, { "value": "内乡县", "label": "内乡县" }, { "value": "淅川县", "label": "淅川县" }, { "value": "社旗县", "label": "社旗县" }, { "value": "唐河县", "label": "唐河县" }, { "value": "新野县", "label": "新野县" }, { "value": "桐柏县", "label": "桐柏县" }, { "value": "邓州市", "label": "邓州市" } ], "value": "南阳市", "label": "南阳市" }, { "children": [ { "value": "梁园区", "label": "梁园区" }, { "value": "睢阳区", "label": "睢阳区" }, { "value": "民权县", "label": "民权县" }, { "value": "睢县", "label": "睢县" }, { "value": "宁陵县", "label": "宁陵县" }, { "value": "柘城县", "label": "柘城县" }, { "value": "虞城县", "label": "虞城县" }, { "value": "夏邑县", "label": "夏邑县" }, { "value": "永城市", "label": "永城市" } ], "value": "商丘市", "label": "商丘市" }, { "children": [ { "value": "浉河区", "label": "浉河区" }, { "value": "平桥区", "label": "平桥区" }, { "value": "罗山县", "label": "罗山县" }, { "value": "光山县", "label": "光山县" }, { "value": "新县", "label": "新县" }, { "value": "商城县", "label": "商城县" }, { "value": "固始县", "label": "固始县" }, { "value": "潢川县", "label": "潢川县" }, { "value": "淮滨县", "label": "淮滨县" }, { "value": "息县", "label": "息县" } ], "value": "信阳市", "label": "信阳市" }, { "children": [ { "value": "川汇区", "label": "川汇区" }, { "value": "扶沟县", "label": "扶沟县" }, { "value": "西华县", "label": "西华县" }, { "value": "商水县", "label": "商水县" }, { "value": "沈丘县", "label": "沈丘县" }, { "value": "郸城县", "label": "郸城县" }, { "value": "淮阳县", "label": "淮阳县" }, { "value": "太康县", "label": "太康县" }, { "value": "鹿邑县", "label": "鹿邑县" }, { "value": "项城市", "label": "项城市" } ], "value": "周口市", "label": "周口市" }, { "children": [ { "value": "驿城区", "label": "驿城区" }, { "value": "西平县", "label": "西平县" }, { "value": "上蔡县", "label": "上蔡县" }, { "value": "平舆县", "label": "平舆县" }, { "value": "正阳县", "label": "正阳县" }, { "value": "确山县", "label": "确山县" }, { "value": "泌阳县", "label": "泌阳县" }, { "value": "汝南县", "label": "汝南县" }, { "value": "遂平县", "label": "遂平县" }, { "value": "新蔡县", "label": "新蔡县" } ], "value": "驻马店市", "label": "驻马店市" }, { "children": [], "value": "济源市", "label": "济源市" } ], "value": "河南省", "label": "河南省" }, { "children": [ { "children": [ { "value": "江岸区", "label": "江岸区" }, { "value": "江汉区", "label": "江汉区" }, { "value": "硚口区", "label": "硚口区" }, { "value": "汉阳区", "label": "汉阳区" }, { "value": "武昌区", "label": "武昌区" }, { "value": "青山区", "label": "青山区" }, { "value": "洪山区", "label": "洪山区" }, { "value": "东西湖区", "label": "东西湖区" }, { "value": "汉南区", "label": "汉南区" }, { "value": "蔡甸区", "label": "蔡甸区" }, { "value": "江夏区", "label": "江夏区" }, { "value": "黄陂区", "label": "黄陂区" }, { "value": "新洲区", "label": "新洲区" } ], "value": "武汉市", "label": "武汉市" }, { "children": [ { "value": "黄石港区", "label": "黄石港区" }, { "value": "西塞山区", "label": "西塞山区" }, { "value": "下陆区", "label": "下陆区" }, { "value": "铁山区", "label": "铁山区" }, { "value": "阳新县", "label": "阳新县" }, { "value": "大冶市", "label": "大冶市" } ], "value": "黄石市", "label": "黄石市" }, { "children": [ { "value": "茅箭区", "label": "茅箭区" }, { "value": "张湾区", "label": "张湾区" }, { "value": "郧阳区", "label": "郧阳区" }, { "value": "郧西县", "label": "郧西县" }, { "value": "竹山县", "label": "竹山县" }, { "value": "竹溪县", "label": "竹溪县" }, { "value": "房县", "label": "房县" }, { "value": "丹江口市", "label": "丹江口市" } ], "value": "十堰市", "label": "十堰市" }, { "children": [ { "value": "西陵区", "label": "西陵区" }, { "value": "伍家岗区", "label": "伍家岗区" }, { "value": "点军区", "label": "点军区" }, { "value": "猇亭区", "label": "猇亭区" }, { "value": "夷陵区", "label": "夷陵区" }, { "value": "远安县", "label": "远安县" }, { "value": "兴山县", "label": "兴山县" }, { "value": "秭归县", "label": "秭归县" }, { "value": "长阳土家族自治县", "label": "长阳土家族自治县" }, { "value": "五峰土家族自治县", "label": "五峰土家族自治县" }, { "value": "宜都市", "label": "宜都市" }, { "value": "当阳市", "label": "当阳市" }, { "value": "枝江市", "label": "枝江市" } ], "value": "宜昌市", "label": "宜昌市" }, { "children": [ { "value": "襄城区", "label": "襄城区" }, { "value": "樊城区", "label": "樊城区" }, { "value": "襄州区", "label": "襄州区" }, { "value": "南漳县", "label": "南漳县" }, { "value": "谷城县", "label": "谷城县" }, { "value": "保康县", "label": "保康县" }, { "value": "老河口市", "label": "老河口市" }, { "value": "枣阳市", "label": "枣阳市" }, { "value": "宜城市", "label": "宜城市" } ], "value": "襄阳市", "label": "襄阳市" }, { "children": [ { "value": "梁子湖区", "label": "梁子湖区" }, { "value": "华容区", "label": "华容区" }, { "value": "鄂城区", "label": "鄂城区" } ], "value": "鄂州市", "label": "鄂州市" }, { "children": [ { "value": "东宝区", "label": "东宝区" }, { "value": "掇刀区", "label": "掇刀区" }, { "value": "京山县", "label": "京山县" }, { "value": "沙洋县", "label": "沙洋县" }, { "value": "钟祥市", "label": "钟祥市" } ], "value": "荆门市", "label": "荆门市" }, { "children": [ { "value": "孝南区", "label": "孝南区" }, { "value": "孝昌县", "label": "孝昌县" }, { "value": "大悟县", "label": "大悟县" }, { "value": "云梦县", "label": "云梦县" }, { "value": "应城市", "label": "应城市" }, { "value": "安陆市", "label": "安陆市" }, { "value": "汉川市", "label": "汉川市" } ], "value": "孝感市", "label": "孝感市" }, { "children": [ { "value": "沙市区", "label": "沙市区" }, { "value": "荆州区", "label": "荆州区" }, { "value": "公安县", "label": "公安县" }, { "value": "监利县", "label": "监利县" }, { "value": "江陵县", "label": "江陵县" }, { "value": "石首市", "label": "石首市" }, { "value": "洪湖市", "label": "洪湖市" }, { "value": "松滋市", "label": "松滋市" } ], "value": "荆州市", "label": "荆州市" }, { "children": [ { "value": "黄州区", "label": "黄州区" }, { "value": "团风县", "label": "团风县" }, { "value": "红安县", "label": "红安县" }, { "value": "罗田县", "label": "罗田县" }, { "value": "英山县", "label": "英山县" }, { "value": "浠水县", "label": "浠水县" }, { "value": "蕲春县", "label": "蕲春县" }, { "value": "黄梅县", "label": "黄梅县" }, { "value": "麻城市", "label": "麻城市" }, { "value": "武穴市", "label": "武穴市" } ], "value": "黄冈市", "label": "黄冈市" }, { "children": [ { "value": "咸安区", "label": "咸安区" }, { "value": "嘉鱼县", "label": "嘉鱼县" }, { "value": "通城县", "label": "通城县" }, { "value": "崇阳县", "label": "崇阳县" }, { "value": "通山县", "label": "通山县" }, { "value": "赤壁市", "label": "赤壁市" } ], "value": "咸宁市", "label": "咸宁市" }, { "children": [ { "value": "曾都区", "label": "曾都区" }, { "value": "随县", "label": "随县" }, { "value": "广水市", "label": "广水市" } ], "value": "随州市", "label": "随州市" }, { "children": [ { "value": "恩施市", "label": "恩施市" }, { "value": "利川市", "label": "利川市" }, { "value": "建始县", "label": "建始县" }, { "value": "巴东县", "label": "巴东县" }, { "value": "宣恩县", "label": "宣恩县" }, { "value": "咸丰县", "label": "咸丰县" }, { "value": "来凤县", "label": "来凤县" }, { "value": "鹤峰县", "label": "鹤峰县" } ], "value": "恩施土家族苗族自治州", "label": "恩施土家族苗族自治州" }, { "children": [], "value": "仙桃市", "label": "仙桃市" }, { "children": [], "value": "潜江市", "label": "潜江市" }, { "children": [], "value": "天门市", "label": "天门市" }, { "children": [], "value": "神农架林区", "label": "神农架林区" } ], "value": "湖北省", "label": "湖北省" }, { "children": [ { "children": [ { "value": "芙蓉区", "label": "芙蓉区" }, { "value": "天心区", "label": "天心区" }, { "value": "岳麓区", "label": "岳麓区" }, { "value": "开福区", "label": "开福区" }, { "value": "雨花区", "label": "雨花区" }, { "value": "望城区", "label": "望城区" }, { "value": "长沙县", "label": "长沙县" }, { "value": "浏阳市", "label": "浏阳市" }, { "value": "宁乡市", "label": "宁乡市" } ], "value": "长沙市", "label": "长沙市" }, { "children": [ { "value": "荷塘区", "label": "荷塘区" }, { "value": "芦淞区", "label": "芦淞区" }, { "value": "石峰区", "label": "石峰区" }, { "value": "天元区", "label": "天元区" }, { "value": "株洲县", "label": "株洲县" }, { "value": "攸县", "label": "攸县" }, { "value": "茶陵县", "label": "茶陵县" }, { "value": "炎陵县", "label": "炎陵县" }, { "value": "醴陵市", "label": "醴陵市" } ], "value": "株洲市", "label": "株洲市" }, { "children": [ { "value": "雨湖区", "label": "雨湖区" }, { "value": "岳塘区", "label": "岳塘区" }, { "value": "湘潭县", "label": "湘潭县" }, { "value": "湘乡市", "label": "湘乡市" }, { "value": "韶山市", "label": "韶山市" } ], "value": "湘潭市", "label": "湘潭市" }, { "children": [ { "value": "珠晖区", "label": "珠晖区" }, { "value": "雁峰区", "label": "雁峰区" }, { "value": "石鼓区", "label": "石鼓区" }, { "value": "蒸湘区", "label": "蒸湘区" }, { "value": "南岳区", "label": "南岳区" }, { "value": "衡阳县", "label": "衡阳县" }, { "value": "衡南县", "label": "衡南县" }, { "value": "衡山县", "label": "衡山县" }, { "value": "衡东县", "label": "衡东县" }, { "value": "祁东县", "label": "祁东县" }, { "value": "耒阳市", "label": "耒阳市" }, { "value": "常宁市", "label": "常宁市" } ], "value": "衡阳市", "label": "衡阳市" }, { "children": [ { "value": "双清区", "label": "双清区" }, { "value": "大祥区", "label": "大祥区" }, { "value": "北塔区", "label": "北塔区" }, { "value": "邵东县", "label": "邵东县" }, { "value": "新邵县", "label": "新邵县" }, { "value": "邵阳县", "label": "邵阳县" }, { "value": "隆回县", "label": "隆回县" }, { "value": "洞口县", "label": "洞口县" }, { "value": "绥宁县", "label": "绥宁县" }, { "value": "新宁县", "label": "新宁县" }, { "value": "城步苗族自治县", "label": "城步苗族自治县" }, { "value": "武冈市", "label": "武冈市" } ], "value": "邵阳市", "label": "邵阳市" }, { "children": [ { "value": "岳阳楼区", "label": "岳阳楼区" }, { "value": "云溪区", "label": "云溪区" }, { "value": "君山区", "label": "君山区" }, { "value": "岳阳县", "label": "岳阳县" }, { "value": "华容县", "label": "华容县" }, { "value": "湘阴县", "label": "湘阴县" }, { "value": "平江县", "label": "平江县" }, { "value": "汨罗市", "label": "汨罗市" }, { "value": "临湘市", "label": "临湘市" } ], "value": "岳阳市", "label": "岳阳市" }, { "children": [ { "value": "武陵区", "label": "武陵区" }, { "value": "鼎城区", "label": "鼎城区" }, { "value": "安乡县", "label": "安乡县" }, { "value": "汉寿县", "label": "汉寿县" }, { "value": "澧县", "label": "澧县" }, { "value": "临澧县", "label": "临澧县" }, { "value": "桃源县", "label": "桃源县" }, { "value": "石门县", "label": "石门县" }, { "value": "津市市", "label": "津市市" } ], "value": "常德市", "label": "常德市" }, { "children": [ { "value": "永定区", "label": "永定区" }, { "value": "武陵源区", "label": "武陵源区" }, { "value": "慈利县", "label": "慈利县" }, { "value": "桑植县", "label": "桑植县" } ], "value": "张家界市", "label": "张家界市" }, { "children": [ { "value": "资阳区", "label": "资阳区" }, { "value": "赫山区", "label": "赫山区" }, { "value": "南县", "label": "南县" }, { "value": "桃江县", "label": "桃江县" }, { "value": "安化县", "label": "安化县" }, { "value": "沅江市", "label": "沅江市" } ], "value": "益阳市", "label": "益阳市" }, { "children": [ { "value": "北湖区", "label": "北湖区" }, { "value": "苏仙区", "label": "苏仙区" }, { "value": "桂阳县", "label": "桂阳县" }, { "value": "宜章县", "label": "宜章县" }, { "value": "永兴县", "label": "永兴县" }, { "value": "嘉禾县", "label": "嘉禾县" }, { "value": "临武县", "label": "临武县" }, { "value": "汝城县", "label": "汝城县" }, { "value": "桂东县", "label": "桂东县" }, { "value": "安仁县", "label": "安仁县" }, { "value": "资兴市", "label": "资兴市" } ], "value": "郴州市", "label": "郴州市" }, { "children": [ { "value": "零陵区", "label": "零陵区" }, { "value": "冷水滩区", "label": "冷水滩区" }, { "value": "祁阳县", "label": "祁阳县" }, { "value": "东安县", "label": "东安县" }, { "value": "双牌县", "label": "双牌县" }, { "value": "道县", "label": "道县" }, { "value": "江永县", "label": "江永县" }, { "value": "宁远县", "label": "宁远县" }, { "value": "蓝山县", "label": "蓝山县" }, { "value": "新田县", "label": "新田县" }, { "value": "江华瑶族自治县", "label": "江华瑶族自治县" } ], "value": "永州市", "label": "永州市" }, { "children": [ { "value": "鹤城区", "label": "鹤城区" }, { "value": "中方县", "label": "中方县" }, { "value": "沅陵县", "label": "沅陵县" }, { "value": "辰溪县", "label": "辰溪县" }, { "value": "溆浦县", "label": "溆浦县" }, { "value": "会同县", "label": "会同县" }, { "value": "麻阳苗族自治县", "label": "麻阳苗族自治县" }, { "value": "新晃侗族自治县", "label": "新晃侗族自治县" }, { "value": "芷江侗族自治县", "label": "芷江侗族自治县" }, { "value": "靖州苗族侗族自治县", "label": "靖州苗族侗族自治县" }, { "value": "通道侗族自治县", "label": "通道侗族自治县" }, { "value": "洪江市", "label": "洪江市" } ], "value": "怀化市", "label": "怀化市" }, { "children": [ { "value": "娄星区", "label": "娄星区" }, { "value": "双峰县", "label": "双峰县" }, { "value": "新化县", "label": "新化县" }, { "value": "冷水江市", "label": "冷水江市" }, { "value": "涟源市", "label": "涟源市" } ], "value": "娄底市", "label": "娄底市" }, { "children": [ { "value": "吉首市", "label": "吉首市" }, { "value": "泸溪县", "label": "泸溪县" }, { "value": "凤凰县", "label": "凤凰县" }, { "value": "花垣县", "label": "花垣县" }, { "value": "保靖县", "label": "保靖县" }, { "value": "古丈县", "label": "古丈县" }, { "value": "永顺县", "label": "永顺县" }, { "value": "龙山县", "label": "龙山县" } ], "value": "湘西土家族苗族自治州", "label": "湘西土家族苗族自治州" } ], "value": "湖南省", "label": "湖南省" }, { "children": [ { "children": [ { "value": "荔湾区", "label": "荔湾区" }, { "value": "越秀区", "label": "越秀区" }, { "value": "海珠区", "label": "海珠区" }, { "value": "天河区", "label": "天河区" }, { "value": "白云区", "label": "白云区" }, { "value": "黄埔区", "label": "黄埔区" }, { "value": "番禺区", "label": "番禺区" }, { "value": "花都区", "label": "花都区" }, { "value": "南沙区", "label": "南沙区" }, { "value": "从化区", "label": "从化区" }, { "value": "增城区", "label": "增城区" } ], "value": "广州市", "label": "广州市" }, { "children": [ { "value": "武江区", "label": "武江区" }, { "value": "浈江区", "label": "浈江区" }, { "value": "曲江区", "label": "曲江区" }, { "value": "始兴县", "label": "始兴县" }, { "value": "仁化县", "label": "仁化县" }, { "value": "翁源县", "label": "翁源县" }, { "value": "乳源瑶族自治县", "label": "乳源瑶族自治县" }, { "value": "新丰县", "label": "新丰县" }, { "value": "乐昌市", "label": "乐昌市" }, { "value": "南雄市", "label": "南雄市" } ], "value": "韶关市", "label": "韶关市" }, { "children": [ { "value": "罗湖区", "label": "罗湖区" }, { "value": "福田区", "label": "福田区" }, { "value": "南山区", "label": "南山区" }, { "value": "宝安区", "label": "宝安区" }, { "value": "龙岗区", "label": "龙岗区" }, { "value": "盐田区", "label": "盐田区" }, { "value": "龙华区", "label": "龙华区" }, { "value": "坪山区", "label": "坪山区" } ], "value": "深圳市", "label": "深圳市" }, { "children": [ { "value": "香洲区", "label": "香洲区" }, { "value": "斗门区", "label": "斗门区" }, { "value": "金湾区", "label": "金湾区" } ], "value": "珠海市", "label": "珠海市" }, { "children": [ { "value": "龙湖区", "label": "龙湖区" }, { "value": "金平区", "label": "金平区" }, { "value": "濠江区", "label": "濠江区" }, { "value": "潮阳区", "label": "潮阳区" }, { "value": "潮南区", "label": "潮南区" }, { "value": "澄海区", "label": "澄海区" }, { "value": "南澳县", "label": "南澳县" } ], "value": "汕头市", "label": "汕头市" }, { "children": [ { "value": "禅城区", "label": "禅城区" }, { "value": "南海区", "label": "南海区" }, { "value": "顺德区", "label": "顺德区" }, { "value": "三水区", "label": "三水区" }, { "value": "高明区", "label": "高明区" } ], "value": "佛山市", "label": "佛山市" }, { "children": [ { "value": "蓬江区", "label": "蓬江区" }, { "value": "江海区", "label": "江海区" }, { "value": "新会区", "label": "新会区" }, { "value": "台山市", "label": "台山市" }, { "value": "开平市", "label": "开平市" }, { "value": "鹤山市", "label": "鹤山市" }, { "value": "恩平市", "label": "恩平市" } ], "value": "江门市", "label": "江门市" }, { "children": [ { "value": "赤坎区", "label": "赤坎区" }, { "value": "霞山区", "label": "霞山区" }, { "value": "坡头区", "label": "坡头区" }, { "value": "麻章区", "label": "麻章区" }, { "value": "遂溪县", "label": "遂溪县" }, { "value": "徐闻县", "label": "徐闻县" }, { "value": "廉江市", "label": "廉江市" }, { "value": "雷州市", "label": "雷州市" }, { "value": "吴川市", "label": "吴川市" } ], "value": "湛江市", "label": "湛江市" }, { "children": [ { "value": "茂南区", "label": "茂南区" }, { "value": "电白区", "label": "电白区" }, { "value": "高州市", "label": "高州市" }, { "value": "化州市", "label": "化州市" }, { "value": "信宜市", "label": "信宜市" } ], "value": "茂名市", "label": "茂名市" }, { "children": [ { "value": "端州区", "label": "端州区" }, { "value": "鼎湖区", "label": "鼎湖区" }, { "value": "高要区", "label": "高要区" }, { "value": "广宁县", "label": "广宁县" }, { "value": "怀集县", "label": "怀集县" }, { "value": "封开县", "label": "封开县" }, { "value": "德庆县", "label": "德庆县" }, { "value": "四会市", "label": "四会市" } ], "value": "肇庆市", "label": "肇庆市" }, { "children": [ { "value": "惠城区", "label": "惠城区" }, { "value": "惠阳区", "label": "惠阳区" }, { "value": "博罗县", "label": "博罗县" }, { "value": "惠东县", "label": "惠东县" }, { "value": "龙门县", "label": "龙门县" } ], "value": "惠州市", "label": "惠州市" }, { "children": [ { "value": "梅江区", "label": "梅江区" }, { "value": "梅县区", "label": "梅县区" }, { "value": "大埔县", "label": "大埔县" }, { "value": "丰顺县", "label": "丰顺县" }, { "value": "五华县", "label": "五华县" }, { "value": "平远县", "label": "平远县" }, { "value": "蕉岭县", "label": "蕉岭县" }, { "value": "兴宁市", "label": "兴宁市" } ], "value": "梅州市", "label": "梅州市" }, { "children": [ { "value": "城区", "label": "城区" }, { "value": "海丰县", "label": "海丰县" }, { "value": "陆河县", "label": "陆河县" }, { "value": "陆丰市", "label": "陆丰市" } ], "value": "汕尾市", "label": "汕尾市" }, { "children": [ { "value": "源城区", "label": "源城区" }, { "value": "紫金县", "label": "紫金县" }, { "value": "龙川县", "label": "龙川县" }, { "value": "连平县", "label": "连平县" }, { "value": "和平县", "label": "和平县" }, { "value": "东源县", "label": "东源县" } ], "value": "河源市", "label": "河源市" }, { "children": [ { "value": "江城区", "label": "江城区" }, { "value": "阳东区", "label": "阳东区" }, { "value": "阳西县", "label": "阳西县" }, { "value": "阳春市", "label": "阳春市" } ], "value": "阳江市", "label": "阳江市" }, { "children": [ { "value": "清城区", "label": "清城区" }, { "value": "清新区", "label": "清新区" }, { "value": "佛冈县", "label": "佛冈县" }, { "value": "阳山县", "label": "阳山县" }, { "value": "连山壮族瑶族自治县", "label": "连山壮族瑶族自治县" }, { "value": "连南瑶族自治县", "label": "连南瑶族自治县" }, { "value": "英德市", "label": "英德市" }, { "value": "连州市", "label": "连州市" } ], "value": "清远市", "label": "清远市" }, { "children": [], "value": "东莞市", "label": "东莞市" }, { "children": [], "value": "中山市", "label": "中山市" }, { "children": [ { "value": "湘桥区", "label": "湘桥区" }, { "value": "潮安区", "label": "潮安区" }, { "value": "饶平县", "label": "饶平县" } ], "value": "潮州市", "label": "潮州市" }, { "children": [ { "value": "榕城区", "label": "榕城区" }, { "value": "揭东区", "label": "揭东区" }, { "value": "揭西县", "label": "揭西县" }, { "value": "惠来县", "label": "惠来县" }, { "value": "普宁市", "label": "普宁市" } ], "value": "揭阳市", "label": "揭阳市" }, { "children": [ { "value": "云城区", "label": "云城区" }, { "value": "云安区", "label": "云安区" }, { "value": "新兴县", "label": "新兴县" }, { "value": "郁南县", "label": "郁南县" }, { "value": "罗定市", "label": "罗定市" } ], "value": "云浮市", "label": "云浮市" } ], "value": "广东省", "label": "广东省" }, { "children": [ { "children": [ { "value": "兴宁区", "label": "兴宁区" }, { "value": "青秀区", "label": "青秀区" }, { "value": "江南区", "label": "江南区" }, { "value": "西乡塘区", "label": "西乡塘区" }, { "value": "良庆区", "label": "良庆区" }, { "value": "邕宁区", "label": "邕宁区" }, { "value": "武鸣区", "label": "武鸣区" }, { "value": "隆安县", "label": "隆安县" }, { "value": "马山县", "label": "马山县" }, { "value": "上林县", "label": "上林县" }, { "value": "宾阳县", "label": "宾阳县" }, { "value": "横县", "label": "横县" } ], "value": "南宁市", "label": "南宁市" }, { "children": [ { "value": "城中区", "label": "城中区" }, { "value": "鱼峰区", "label": "鱼峰区" }, { "value": "柳南区", "label": "柳南区" }, { "value": "柳北区", "label": "柳北区" }, { "value": "柳江区", "label": "柳江区" }, { "value": "柳城县", "label": "柳城县" }, { "value": "鹿寨县", "label": "鹿寨县" }, { "value": "融安县", "label": "融安县" }, { "value": "融水苗族自治县", "label": "融水苗族自治县" }, { "value": "三江侗族自治县", "label": "三江侗族自治县" } ], "value": "柳州市", "label": "柳州市" }, { "children": [ { "value": "秀峰区", "label": "秀峰区" }, { "value": "叠彩区", "label": "叠彩区" }, { "value": "象山区", "label": "象山区" }, { "value": "七星区", "label": "七星区" }, { "value": "雁山区", "label": "雁山区" }, { "value": "临桂区", "label": "临桂区" }, { "value": "阳朔县", "label": "阳朔县" }, { "value": "灵川县", "label": "灵川县" }, { "value": "全州县", "label": "全州县" }, { "value": "兴安县", "label": "兴安县" }, { "value": "永福县", "label": "永福县" }, { "value": "灌阳县", "label": "灌阳县" }, { "value": "龙胜各族自治县", "label": "龙胜各族自治县" }, { "value": "资源县", "label": "资源县" }, { "value": "平乐县", "label": "平乐县" }, { "value": "荔浦县", "label": "荔浦县" }, { "value": "恭城瑶族自治县", "label": "恭城瑶族自治县" } ], "value": "桂林市", "label": "桂林市" }, { "children": [ { "value": "万秀区", "label": "万秀区" }, { "value": "长洲区", "label": "长洲区" }, { "value": "龙圩区", "label": "龙圩区" }, { "value": "苍梧县", "label": "苍梧县" }, { "value": "藤县", "label": "藤县" }, { "value": "蒙山县", "label": "蒙山县" }, { "value": "岑溪市", "label": "岑溪市" } ], "value": "梧州市", "label": "梧州市" }, { "children": [ { "value": "海城区", "label": "海城区" }, { "value": "银海区", "label": "银海区" }, { "value": "铁山港区", "label": "铁山港区" }, { "value": "合浦县", "label": "合浦县" } ], "value": "北海市", "label": "北海市" }, { "children": [ { "value": "港口区", "label": "港口区" }, { "value": "防城区", "label": "防城区" }, { "value": "上思县", "label": "上思县" }, { "value": "东兴市", "label": "东兴市" } ], "value": "防城港市", "label": "防城港市" }, { "children": [ { "value": "钦南区", "label": "钦南区" }, { "value": "钦北区", "label": "钦北区" }, { "value": "灵山县", "label": "灵山县" }, { "value": "浦北县", "label": "浦北县" } ], "value": "钦州市", "label": "钦州市" }, { "children": [ { "value": "港北区", "label": "港北区" }, { "value": "港南区", "label": "港南区" }, { "value": "覃塘区", "label": "覃塘区" }, { "value": "平南县", "label": "平南县" }, { "value": "桂平市", "label": "桂平市" } ], "value": "贵港市", "label": "贵港市" }, { "children": [ { "value": "玉州区", "label": "玉州区" }, { "value": "福绵区", "label": "福绵区" }, { "value": "容县", "label": "容县" }, { "value": "陆川县", "label": "陆川县" }, { "value": "博白县", "label": "博白县" }, { "value": "兴业县", "label": "兴业县" }, { "value": "北流市", "label": "北流市" } ], "value": "玉林市", "label": "玉林市" }, { "children": [ { "value": "右江区", "label": "右江区" }, { "value": "田阳县", "label": "田阳县" }, { "value": "田东县", "label": "田东县" }, { "value": "平果县", "label": "平果县" }, { "value": "德保县", "label": "德保县" }, { "value": "那坡县", "label": "那坡县" }, { "value": "凌云县", "label": "凌云县" }, { "value": "乐业县", "label": "乐业县" }, { "value": "田林县", "label": "田林县" }, { "value": "西林县", "label": "西林县" }, { "value": "隆林各族自治县", "label": "隆林各族自治县" }, { "value": "靖西市", "label": "靖西市" } ], "value": "百色市", "label": "百色市" }, { "children": [ { "value": "八步区", "label": "八步区" }, { "value": "平桂区", "label": "平桂区" }, { "value": "昭平县", "label": "昭平县" }, { "value": "钟山县", "label": "钟山县" }, { "value": "富川瑶族自治县", "label": "富川瑶族自治县" } ], "value": "贺州市", "label": "贺州市" }, { "children": [ { "value": "金城江区", "label": "金城江区" }, { "value": "宜州区", "label": "宜州区" }, { "value": "南丹县", "label": "南丹县" }, { "value": "天峨县", "label": "天峨县" }, { "value": "凤山县", "label": "凤山县" }, { "value": "东兰县", "label": "东兰县" }, { "value": "罗城仫佬族自治县", "label": "罗城仫佬族自治县" }, { "value": "环江毛南族自治县", "label": "环江毛南族自治县" }, { "value": "巴马瑶族自治县", "label": "巴马瑶族自治县" }, { "value": "都安瑶族自治县", "label": "都安瑶族自治县" }, { "value": "大化瑶族自治县", "label": "大化瑶族自治县" } ], "value": "河池市", "label": "河池市" }, { "children": [ { "value": "兴宾区", "label": "兴宾区" }, { "value": "忻城县", "label": "忻城县" }, { "value": "象州县", "label": "象州县" }, { "value": "武宣县", "label": "武宣县" }, { "value": "金秀瑶族自治县", "label": "金秀瑶族自治县" }, { "value": "合山市", "label": "合山市" } ], "value": "来宾市", "label": "来宾市" }, { "children": [ { "value": "江州区", "label": "江州区" }, { "value": "扶绥县", "label": "扶绥县" }, { "value": "宁明县", "label": "宁明县" }, { "value": "龙州县", "label": "龙州县" }, { "value": "大新县", "label": "大新县" }, { "value": "天等县", "label": "天等县" }, { "value": "凭祥市", "label": "凭祥市" } ], "value": "崇左市", "label": "崇左市" } ], "value": "广西壮族自治区", "label": "广西壮族自治区" }, { "children": [ { "children": [ { "value": "秀英区", "label": "秀英区" }, { "value": "龙华区", "label": "龙华区" }, { "value": "琼山区", "label": "琼山区" }, { "value": "美兰区", "label": "美兰区" } ], "value": "海口市", "label": "海口市" }, { "children": [ { "value": "海棠区", "label": "海棠区" }, { "value": "吉阳区", "label": "吉阳区" }, { "value": "天涯区", "label": "天涯区" }, { "value": "崖州区", "label": "崖州区" } ], "value": "三亚市", "label": "三亚市" }, { "children": [], "value": "三沙市", "label": "三沙市" }, { "children": [], "value": "儋州市", "label": "儋州市" }, { "children": [], "value": "五指山市", "label": "五指山市" }, { "children": [], "value": "琼海市", "label": "琼海市" }, { "children": [], "value": "文昌市", "label": "文昌市" }, { "children": [], "value": "万宁市", "label": "万宁市" }, { "children": [], "value": "东方市", "label": "东方市" }, { "children": [], "value": "定安县", "label": "定安县" }, { "children": [], "value": "屯昌县", "label": "屯昌县" }, { "children": [], "value": "澄迈县", "label": "澄迈县" }, { "children": [], "value": "临高县", "label": "临高县" }, { "children": [], "value": "白沙黎族自治县", "label": "白沙黎族自治县" }, { "children": [], "value": "昌江黎族自治县", "label": "昌江黎族自治县" }, { "children": [], "value": "乐东黎族自治县", "label": "乐东黎族自治县" }, { "children": [], "value": "陵水黎族自治县", "label": "陵水黎族自治县" }, { "children": [], "value": "保亭黎族苗族自治县", "label": "保亭黎族苗族自治县" }, { "children": [], "value": "琼中黎族苗族自治县", "label": "琼中黎族苗族自治县" } ], "value": "海南省", "label": "海南省" }, { "children": [ { "children": [ { "value": "万州区", "label": "万州区" }, { "value": "涪陵区", "label": "涪陵区" }, { "value": "渝中区", "label": "渝中区" }, { "value": "大渡口区", "label": "大渡口区" }, { "value": "江北区", "label": "江北区" }, { "value": "沙坪坝区", "label": "沙坪坝区" }, { "value": "九龙坡区", "label": "九龙坡区" }, { "value": "南岸区", "label": "南岸区" }, { "value": "北碚区", "label": "北碚区" }, { "value": "綦江区", "label": "綦江区" }, { "value": "大足区", "label": "大足区" }, { "value": "渝北区", "label": "渝北区" }, { "value": "巴南区", "label": "巴南区" }, { "value": "黔江区", "label": "黔江区" }, { "value": "长寿区", "label": "长寿区" }, { "value": "江津区", "label": "江津区" }, { "value": "合川区", "label": "合川区" }, { "value": "永川区", "label": "永川区" }, { "value": "南川区", "label": "南川区" }, { "value": "璧山区", "label": "璧山区" }, { "value": "铜梁区", "label": "铜梁区" }, { "value": "潼南区", "label": "潼南区" }, { "value": "荣昌区", "label": "荣昌区" }, { "value": "开州区", "label": "开州区" }, { "value": "梁平区", "label": "梁平区" }, { "value": "武隆区", "label": "武隆区" }, { "value": "城口县", "label": "城口县" }, { "value": "丰都县", "label": "丰都县" }, { "value": "垫江县", "label": "垫江县" }, { "value": "忠县", "label": "忠县" }, { "value": "云阳县", "label": "云阳县" }, { "value": "奉节县", "label": "奉节县" }, { "value": "巫山县", "label": "巫山县" }, { "value": "巫溪县", "label": "巫溪县" }, { "value": "石柱土家族自治县", "label": "石柱土家族自治县" }, { "value": "秀山土家族苗族自治县", "label": "秀山土家族苗族自治县" }, { "value": "酉阳土家族苗族自治县", "label": "酉阳土家族苗族自治县" }, { "value": "彭水苗族土家族自治县", "label": "彭水苗族土家族自治县" } ], "value": "重庆市", "label": "重庆市" } ], "value": "重庆市", "label": "重庆市" }, { "children": [ { "children": [ { "value": "锦江区", "label": "锦江区" }, { "value": "青羊区", "label": "青羊区" }, { "value": "金牛区", "label": "金牛区" }, { "value": "武侯区", "label": "武侯区" }, { "value": "成华区", "label": "成华区" }, { "value": "龙泉驿区", "label": "龙泉驿区" }, { "value": "青白江区", "label": "青白江区" }, { "value": "新都区", "label": "新都区" }, { "value": "温江区", "label": "温江区" }, { "value": "双流区", "label": "双流区" }, { "value": "郫都区", "label": "郫都区" }, { "value": "金堂县", "label": "金堂县" }, { "value": "大邑县", "label": "大邑县" }, { "value": "蒲江县", "label": "蒲江县" }, { "value": "新津县", "label": "新津县" }, { "value": "都江堰市", "label": "都江堰市" }, { "value": "彭州市", "label": "彭州市" }, { "value": "邛崃市", "label": "邛崃市" }, { "value": "崇州市", "label": "崇州市" }, { "value": "简阳市", "label": "简阳市" } ], "value": "成都市", "label": "成都市" }, { "children": [ { "value": "自流井区", "label": "自流井区" }, { "value": "贡井区", "label": "贡井区" }, { "value": "大安区", "label": "大安区" }, { "value": "沿滩区", "label": "沿滩区" }, { "value": "荣县", "label": "荣县" }, { "value": "富顺县", "label": "富顺县" } ], "value": "自贡市", "label": "自贡市" }, { "children": [ { "value": "东区", "label": "东区" }, { "value": "西区", "label": "西区" }, { "value": "仁和区", "label": "仁和区" }, { "value": "米易县", "label": "米易县" }, { "value": "盐边县", "label": "盐边县" } ], "value": "攀枝花市", "label": "攀枝花市" }, { "children": [ { "value": "江阳区", "label": "江阳区" }, { "value": "纳溪区", "label": "纳溪区" }, { "value": "龙马潭区", "label": "龙马潭区" }, { "value": "泸县", "label": "泸县" }, { "value": "合江县", "label": "合江县" }, { "value": "叙永县", "label": "叙永县" }, { "value": "古蔺县", "label": "古蔺县" } ], "value": "泸州市", "label": "泸州市" }, { "children": [ { "value": "旌阳区", "label": "旌阳区" }, { "value": "中江县", "label": "中江县" }, { "value": "罗江县", "label": "罗江县" }, { "value": "广汉市", "label": "广汉市" }, { "value": "什邡市", "label": "什邡市" }, { "value": "绵竹市", "label": "绵竹市" } ], "value": "德阳市", "label": "德阳市" }, { "children": [ { "value": "涪城区", "label": "涪城区" }, { "value": "游仙区", "label": "游仙区" }, { "value": "安州区", "label": "安州区" }, { "value": "三台县", "label": "三台县" }, { "value": "盐亭县", "label": "盐亭县" }, { "value": "梓潼县", "label": "梓潼县" }, { "value": "北川羌族自治县", "label": "北川羌族自治县" }, { "value": "平武县", "label": "平武县" }, { "value": "江油市", "label": "江油市" } ], "value": "绵阳市", "label": "绵阳市" }, { "children": [ { "value": "利州区", "label": "利州区" }, { "value": "昭化区", "label": "昭化区" }, { "value": "朝天区", "label": "朝天区" }, { "value": "旺苍县", "label": "旺苍县" }, { "value": "青川县", "label": "青川县" }, { "value": "剑阁县", "label": "剑阁县" }, { "value": "苍溪县", "label": "苍溪县" } ], "value": "广元市", "label": "广元市" }, { "children": [ { "value": "船山区", "label": "船山区" }, { "value": "安居区", "label": "安居区" }, { "value": "蓬溪县", "label": "蓬溪县" }, { "value": "射洪县", "label": "射洪县" }, { "value": "大英县", "label": "大英县" } ], "value": "遂宁市", "label": "遂宁市" }, { "children": [ { "value": "市中区", "label": "市中区" }, { "value": "东兴区", "label": "东兴区" }, { "value": "威远县", "label": "威远县" }, { "value": "资中县", "label": "资中县" }, { "value": "隆昌市", "label": "隆昌市" } ], "value": "内江市", "label": "内江市" }, { "children": [ { "value": "市中区", "label": "市中区" }, { "value": "沙湾区", "label": "沙湾区" }, { "value": "五通桥区", "label": "五通桥区" }, { "value": "金口河区", "label": "金口河区" }, { "value": "犍为县", "label": "犍为县" }, { "value": "井研县", "label": "井研县" }, { "value": "夹江县", "label": "夹江县" }, { "value": "沐川县", "label": "沐川县" }, { "value": "峨边彝族自治县", "label": "峨边彝族自治县" }, { "value": "马边彝族自治县", "label": "马边彝族自治县" }, { "value": "峨眉山市", "label": "峨眉山市" } ], "value": "乐山市", "label": "乐山市" }, { "children": [ { "value": "顺庆区", "label": "顺庆区" }, { "value": "高坪区", "label": "高坪区" }, { "value": "嘉陵区", "label": "嘉陵区" }, { "value": "南部县", "label": "南部县" }, { "value": "营山县", "label": "营山县" }, { "value": "蓬安县", "label": "蓬安县" }, { "value": "仪陇县", "label": "仪陇县" }, { "value": "西充县", "label": "西充县" }, { "value": "阆中市", "label": "阆中市" } ], "value": "南充市", "label": "南充市" }, { "children": [ { "value": "东坡区", "label": "东坡区" }, { "value": "彭山区", "label": "彭山区" }, { "value": "仁寿县", "label": "仁寿县" }, { "value": "洪雅县", "label": "洪雅县" }, { "value": "丹棱县", "label": "丹棱县" }, { "value": "青神县", "label": "青神县" } ], "value": "眉山市", "label": "眉山市" }, { "children": [ { "value": "翠屏区", "label": "翠屏区" }, { "value": "南溪区", "label": "南溪区" }, { "value": "宜宾县", "label": "宜宾县" }, { "value": "江安县", "label": "江安县" }, { "value": "长宁县", "label": "长宁县" }, { "value": "高县", "label": "高县" }, { "value": "珙县", "label": "珙县" }, { "value": "筠连县", "label": "筠连县" }, { "value": "兴文县", "label": "兴文县" }, { "value": "屏山县", "label": "屏山县" } ], "value": "宜宾市", "label": "宜宾市" }, { "children": [ { "value": "广安区", "label": "广安区" }, { "value": "前锋区", "label": "前锋区" }, { "value": "岳池县", "label": "岳池县" }, { "value": "武胜县", "label": "武胜县" }, { "value": "邻水县", "label": "邻水县" }, { "value": "华蓥市", "label": "华蓥市" } ], "value": "广安市", "label": "广安市" }, { "children": [ { "value": "通川区", "label": "通川区" }, { "value": "达川区", "label": "达川区" }, { "value": "宣汉县", "label": "宣汉县" }, { "value": "开江县", "label": "开江县" }, { "value": "大竹县", "label": "大竹县" }, { "value": "渠县", "label": "渠县" }, { "value": "万源市", "label": "万源市" } ], "value": "达州市", "label": "达州市" }, { "children": [ { "value": "雨城区", "label": "雨城区" }, { "value": "名山区", "label": "名山区" }, { "value": "荥经县", "label": "荥经县" }, { "value": "汉源县", "label": "汉源县" }, { "value": "石棉县", "label": "石棉县" }, { "value": "天全县", "label": "天全县" }, { "value": "芦山县", "label": "芦山县" }, { "value": "宝兴县", "label": "宝兴县" } ], "value": "雅安市", "label": "雅安市" }, { "children": [ { "value": "巴州区", "label": "巴州区" }, { "value": "恩阳区", "label": "恩阳区" }, { "value": "通江县", "label": "通江县" }, { "value": "南江县", "label": "南江县" }, { "value": "平昌县", "label": "平昌县" } ], "value": "巴中市", "label": "巴中市" }, { "children": [ { "value": "雁江区", "label": "雁江区" }, { "value": "安岳县", "label": "安岳县" }, { "value": "乐至县", "label": "乐至县" } ], "value": "资阳市", "label": "资阳市" }, { "children": [ { "value": "马尔康市", "label": "马尔康市" }, { "value": "汶川县", "label": "汶川县" }, { "value": "理县", "label": "理县" }, { "value": "茂县", "label": "茂县" }, { "value": "松潘县", "label": "松潘县" }, { "value": "九寨沟县", "label": "九寨沟县" }, { "value": "金川县", "label": "金川县" }, { "value": "小金县", "label": "小金县" }, { "value": "黑水县", "label": "黑水县" }, { "value": "壤塘县", "label": "壤塘县" }, { "value": "阿坝县", "label": "阿坝县" }, { "value": "若尔盖县", "label": "若尔盖县" }, { "value": "红原县", "label": "红原县" } ], "value": "阿坝藏族羌族自治州", "label": "阿坝藏族羌族自治州" }, { "children": [ { "value": "康定市", "label": "康定市" }, { "value": "泸定县", "label": "泸定县" }, { "value": "丹巴县", "label": "丹巴县" }, { "value": "九龙县", "label": "九龙县" }, { "value": "雅江县", "label": "雅江县" }, { "value": "道孚县", "label": "道孚县" }, { "value": "炉霍县", "label": "炉霍县" }, { "value": "甘孜县", "label": "甘孜县" }, { "value": "新龙县", "label": "新龙县" }, { "value": "德格县", "label": "德格县" }, { "value": "白玉县", "label": "白玉县" }, { "value": "石渠县", "label": "石渠县" }, { "value": "色达县", "label": "色达县" }, { "value": "理塘县", "label": "理塘县" }, { "value": "巴塘县", "label": "巴塘县" }, { "value": "乡城县", "label": "乡城县" }, { "value": "稻城县", "label": "稻城县" }, { "value": "得荣县", "label": "得荣县" } ], "value": "甘孜藏族自治州", "label": "甘孜藏族自治州" }, { "children": [ { "value": "西昌市", "label": "西昌市" }, { "value": "木里藏族自治县", "label": "木里藏族自治县" }, { "value": "盐源县", "label": "盐源县" }, { "value": "德昌县", "label": "德昌县" }, { "value": "会理县", "label": "会理县" }, { "value": "会东县", "label": "会东县" }, { "value": "宁南县", "label": "宁南县" }, { "value": "普格县", "label": "普格县" }, { "value": "布拖县", "label": "布拖县" }, { "value": "金阳县", "label": "金阳县" }, { "value": "昭觉县", "label": "昭觉县" }, { "value": "喜德县", "label": "喜德县" }, { "value": "冕宁县", "label": "冕宁县" }, { "value": "越西县", "label": "越西县" }, { "value": "甘洛县", "label": "甘洛县" }, { "value": "美姑县", "label": "美姑县" }, { "value": "雷波县", "label": "雷波县" } ], "value": "凉山彝族自治州", "label": "凉山彝族自治州" } ], "value": "四川省", "label": "四川省" }, { "children": [ { "children": [ { "value": "南明区", "label": "南明区" }, { "value": "云岩区", "label": "云岩区" }, { "value": "花溪区", "label": "花溪区" }, { "value": "乌当区", "label": "乌当区" }, { "value": "白云区", "label": "白云区" }, { "value": "观山湖区", "label": "观山湖区" }, { "value": "开阳县", "label": "开阳县" }, { "value": "息烽县", "label": "息烽县" }, { "value": "修文县", "label": "修文县" }, { "value": "清镇市", "label": "清镇市" } ], "value": "贵阳市", "label": "贵阳市" }, { "children": [ { "value": "钟山区", "label": "钟山区" }, { "value": "六枝特区", "label": "六枝特区" }, { "value": "水城县", "label": "水城县" }, { "value": "盘州市", "label": "盘州市" } ], "value": "六盘水市", "label": "六盘水市" }, { "children": [ { "value": "红花岗区", "label": "红花岗区" }, { "value": "汇川区", "label": "汇川区" }, { "value": "播州区", "label": "播州区" }, { "value": "桐梓县", "label": "桐梓县" }, { "value": "绥阳县", "label": "绥阳县" }, { "value": "正安县", "label": "正安县" }, { "value": "道真仡佬族苗族自治县", "label": "道真仡佬族苗族自治县" }, { "value": "务川仡佬族苗族自治县", "label": "务川仡佬族苗族自治县" }, { "value": "凤冈县", "label": "凤冈县" }, { "value": "湄潭县", "label": "湄潭县" }, { "value": "余庆县", "label": "余庆县" }, { "value": "习水县", "label": "习水县" }, { "value": "赤水市", "label": "赤水市" }, { "value": "仁怀市", "label": "仁怀市" } ], "value": "遵义市", "label": "遵义市" }, { "children": [ { "value": "西秀区", "label": "西秀区" }, { "value": "平坝区", "label": "平坝区" }, { "value": "普定县", "label": "普定县" }, { "value": "镇宁布依族苗族自治县", "label": "镇宁布依族苗族自治县" }, { "value": "关岭布依族苗族自治县", "label": "关岭布依族苗族自治县" }, { "value": "紫云苗族布依族自治县", "label": "紫云苗族布依族自治县" } ], "value": "安顺市", "label": "安顺市" }, { "children": [ { "value": "七星关区", "label": "七星关区" }, { "value": "大方县", "label": "大方县" }, { "value": "黔西县", "label": "黔西县" }, { "value": "金沙县", "label": "金沙县" }, { "value": "织金县", "label": "织金县" }, { "value": "纳雍县", "label": "纳雍县" }, { "value": "威宁彝族回族苗族自治县", "label": "威宁彝族回族苗族自治县" }, { "value": "赫章县", "label": "赫章县" } ], "value": "毕节市", "label": "毕节市" }, { "children": [ { "value": "碧江区", "label": "碧江区" }, { "value": "万山区", "label": "万山区" }, { "value": "江口县", "label": "江口县" }, { "value": "玉屏侗族自治县", "label": "玉屏侗族自治县" }, { "value": "石阡县", "label": "石阡县" }, { "value": "思南县", "label": "思南县" }, { "value": "印江土家族苗族自治县", "label": "印江土家族苗族自治县" }, { "value": "德江县", "label": "德江县" }, { "value": "沿河土家族自治县", "label": "沿河土家族自治县" }, { "value": "松桃苗族自治县", "label": "松桃苗族自治县" } ], "value": "铜仁市", "label": "铜仁市" }, { "children": [ { "value": "兴义市", "label": "兴义市" }, { "value": "兴仁县", "label": "兴仁县" }, { "value": "普安县", "label": "普安县" }, { "value": "晴隆县", "label": "晴隆县" }, { "value": "贞丰县", "label": "贞丰县" }, { "value": "望谟县", "label": "望谟县" }, { "value": "册亨县", "label": "册亨县" }, { "value": "安龙县", "label": "安龙县" } ], "value": "黔西南布依族苗族自治州", "label": "黔西南布依族苗族自治州" }, { "children": [ { "value": "凯里市", "label": "凯里市" }, { "value": "黄平县", "label": "黄平县" }, { "value": "施秉县", "label": "施秉县" }, { "value": "三穗县", "label": "三穗县" }, { "value": "镇远县", "label": "镇远县" }, { "value": "岑巩县", "label": "岑巩县" }, { "value": "天柱县", "label": "天柱县" }, { "value": "锦屏县", "label": "锦屏县" }, { "value": "剑河县", "label": "剑河县" }, { "value": "台江县", "label": "台江县" }, { "value": "黎平县", "label": "黎平县" }, { "value": "榕江县", "label": "榕江县" }, { "value": "从江县", "label": "从江县" }, { "value": "雷山县", "label": "雷山县" }, { "value": "麻江县", "label": "麻江县" }, { "value": "丹寨县", "label": "丹寨县" } ], "value": "黔东南苗族侗族自治州", "label": "黔东南苗族侗族自治州" }, { "children": [ { "value": "都匀市", "label": "都匀市" }, { "value": "福泉市", "label": "福泉市" }, { "value": "荔波县", "label": "荔波县" }, { "value": "贵定县", "label": "贵定县" }, { "value": "瓮安县", "label": "瓮安县" }, { "value": "独山县", "label": "独山县" }, { "value": "平塘县", "label": "平塘县" }, { "value": "罗甸县", "label": "罗甸县" }, { "value": "长顺县", "label": "长顺县" }, { "value": "龙里县", "label": "龙里县" }, { "value": "惠水县", "label": "惠水县" }, { "value": "三都水族自治县", "label": "三都水族自治县" } ], "value": "黔南布依族苗族自治州", "label": "黔南布依族苗族自治州" } ], "value": "贵州省", "label": "贵州省" }, { "children": [ { "children": [ { "value": "五华区", "label": "五华区" }, { "value": "盘龙区", "label": "盘龙区" }, { "value": "官渡区", "label": "官渡区" }, { "value": "西山区", "label": "西山区" }, { "value": "东川区", "label": "东川区" }, { "value": "呈贡区", "label": "呈贡区" }, { "value": "晋宁区", "label": "晋宁区" }, { "value": "富民县", "label": "富民县" }, { "value": "宜良县", "label": "宜良县" }, { "value": "石林彝族自治县", "label": "石林彝族自治县" }, { "value": "嵩明县", "label": "嵩明县" }, { "value": "禄劝彝族苗族自治县", "label": "禄劝彝族苗族自治县" }, { "value": "寻甸回族彝族自治县", "label": "寻甸回族彝族自治县" }, { "value": "安宁市", "label": "安宁市" } ], "value": "昆明市", "label": "昆明市" }, { "children": [ { "value": "麒麟区", "label": "麒麟区" }, { "value": "沾益区", "label": "沾益区" }, { "value": "马龙县", "label": "马龙县" }, { "value": "陆良县", "label": "陆良县" }, { "value": "师宗县", "label": "师宗县" }, { "value": "罗平县", "label": "罗平县" }, { "value": "富源县", "label": "富源县" }, { "value": "会泽县", "label": "会泽县" }, { "value": "宣威市", "label": "宣威市" } ], "value": "曲靖市", "label": "曲靖市" }, { "children": [ { "value": "红塔区", "label": "红塔区" }, { "value": "江川区", "label": "江川区" }, { "value": "澄江县", "label": "澄江县" }, { "value": "通海县", "label": "通海县" }, { "value": "华宁县", "label": "华宁县" }, { "value": "易门县", "label": "易门县" }, { "value": "峨山彝族自治县", "label": "峨山彝族自治县" }, { "value": "新平彝族傣族自治县", "label": "新平彝族傣族自治县" }, { "value": "元江哈尼族彝族傣族自治县", "label": "元江哈尼族彝族傣族自治县" } ], "value": "玉溪市", "label": "玉溪市" }, { "children": [ { "value": "隆阳区", "label": "隆阳区" }, { "value": "施甸县", "label": "施甸县" }, { "value": "龙陵县", "label": "龙陵县" }, { "value": "昌宁县", "label": "昌宁县" }, { "value": "腾冲市", "label": "腾冲市" } ], "value": "保山市", "label": "保山市" }, { "children": [ { "value": "昭阳区", "label": "昭阳区" }, { "value": "鲁甸县", "label": "鲁甸县" }, { "value": "巧家县", "label": "巧家县" }, { "value": "盐津县", "label": "盐津县" }, { "value": "大关县", "label": "大关县" }, { "value": "永善县", "label": "永善县" }, { "value": "绥江县", "label": "绥江县" }, { "value": "镇雄县", "label": "镇雄县" }, { "value": "彝良县", "label": "彝良县" }, { "value": "威信县", "label": "威信县" }, { "value": "水富县", "label": "水富县" } ], "value": "昭通市", "label": "昭通市" }, { "children": [ { "value": "古城区", "label": "古城区" }, { "value": "玉龙纳西族自治县", "label": "玉龙纳西族自治县" }, { "value": "永胜县", "label": "永胜县" }, { "value": "华坪县", "label": "华坪县" }, { "value": "宁蒗彝族自治县", "label": "宁蒗彝族自治县" } ], "value": "丽江市", "label": "丽江市" }, { "children": [ { "value": "思茅区", "label": "思茅区" }, { "value": "宁洱哈尼族彝族自治县", "label": "宁洱哈尼族彝族自治县" }, { "value": "墨江哈尼族自治县", "label": "墨江哈尼族自治县" }, { "value": "景东彝族自治县", "label": "景东彝族自治县" }, { "value": "景谷傣族彝族自治县", "label": "景谷傣族彝族自治县" }, { "value": "镇沅彝族哈尼族拉祜族自治县", "label": "镇沅彝族哈尼族拉祜族自治县" }, { "value": "江城哈尼族彝族自治县", "label": "江城哈尼族彝族自治县" }, { "value": "孟连傣族拉祜族佤族自治县", "label": "孟连傣族拉祜族佤族自治县" }, { "value": "澜沧拉祜族自治县", "label": "澜沧拉祜族自治县" }, { "value": "西盟佤族自治县", "label": "西盟佤族自治县" } ], "value": "普洱市", "label": "普洱市" }, { "children": [ { "value": "临翔区", "label": "临翔区" }, { "value": "凤庆县", "label": "凤庆县" }, { "value": "云县", "label": "云县" }, { "value": "永德县", "label": "永德县" }, { "value": "镇康县", "label": "镇康县" }, { "value": "双江拉祜族佤族布朗族傣族自治县", "label": "双江拉祜族佤族布朗族傣族自治县" }, { "value": "耿马傣族佤族自治县", "label": "耿马傣族佤族自治县" }, { "value": "沧源佤族自治县", "label": "沧源佤族自治县" } ], "value": "临沧市", "label": "临沧市" }, { "children": [ { "value": "楚雄市", "label": "楚雄市" }, { "value": "双柏县", "label": "双柏县" }, { "value": "牟定县", "label": "牟定县" }, { "value": "南华县", "label": "南华县" }, { "value": "姚安县", "label": "姚安县" }, { "value": "大姚县", "label": "大姚县" }, { "value": "永仁县", "label": "永仁县" }, { "value": "元谋县", "label": "元谋县" }, { "value": "武定县", "label": "武定县" }, { "value": "禄丰县", "label": "禄丰县" } ], "value": "楚雄彝族自治州", "label": "楚雄彝族自治州" }, { "children": [ { "value": "个旧市", "label": "个旧市" }, { "value": "开远市", "label": "开远市" }, { "value": "蒙自市", "label": "蒙自市" }, { "value": "弥勒市", "label": "弥勒市" }, { "value": "屏边苗族自治县", "label": "屏边苗族自治县" }, { "value": "建水县", "label": "建水县" }, { "value": "石屏县", "label": "石屏县" }, { "value": "泸西县", "label": "泸西县" }, { "value": "元阳县", "label": "元阳县" }, { "value": "红河县", "label": "红河县" }, { "value": "金平苗族瑶族傣族自治县", "label": "金平苗族瑶族傣族自治县" }, { "value": "绿春县", "label": "绿春县" }, { "value": "河口瑶族自治县", "label": "河口瑶族自治县" } ], "value": "红河哈尼族彝族自治州", "label": "红河哈尼族彝族自治州" }, { "children": [ { "value": "文山市", "label": "文山市" }, { "value": "砚山县", "label": "砚山县" }, { "value": "西畴县", "label": "西畴县" }, { "value": "麻栗坡县", "label": "麻栗坡县" }, { "value": "马关县", "label": "马关县" }, { "value": "丘北县", "label": "丘北县" }, { "value": "广南县", "label": "广南县" }, { "value": "富宁县", "label": "富宁县" } ], "value": "文山壮族苗族自治州", "label": "文山壮族苗族自治州" }, { "children": [ { "value": "景洪市", "label": "景洪市" }, { "value": "勐海县", "label": "勐海县" }, { "value": "勐腊县", "label": "勐腊县" } ], "value": "西双版纳傣族自治州", "label": "西双版纳傣族自治州" }, { "children": [ { "value": "大理市", "label": "大理市" }, { "value": "漾濞彝族自治县", "label": "漾濞彝族自治县" }, { "value": "祥云县", "label": "祥云县" }, { "value": "宾川县", "label": "宾川县" }, { "value": "弥渡县", "label": "弥渡县" }, { "value": "南涧彝族自治县", "label": "南涧彝族自治县" }, { "value": "巍山彝族回族自治县", "label": "巍山彝族回族自治县" }, { "value": "永平县", "label": "永平县" }, { "value": "云龙县", "label": "云龙县" }, { "value": "洱源县", "label": "洱源县" }, { "value": "剑川县", "label": "剑川县" }, { "value": "鹤庆县", "label": "鹤庆县" } ], "value": "大理白族自治州", "label": "大理白族自治州" }, { "children": [ { "value": "瑞丽市", "label": "瑞丽市" }, { "value": "芒市", "label": "芒市" }, { "value": "梁河县", "label": "梁河县" }, { "value": "盈江县", "label": "盈江县" }, { "value": "陇川县", "label": "陇川县" } ], "value": "德宏傣族景颇族自治州", "label": "德宏傣族景颇族自治州" }, { "children": [ { "value": "泸水市", "label": "泸水市" }, { "value": "福贡县", "label": "福贡县" }, { "value": "贡山独龙族怒族自治县", "label": "贡山独龙族怒族自治县" }, { "value": "兰坪白族普米族自治县", "label": "兰坪白族普米族自治县" } ], "value": "怒江傈僳族自治州", "label": "怒江傈僳族自治州" }, { "children": [ { "value": "香格里拉市", "label": "香格里拉市" }, { "value": "德钦县", "label": "德钦县" }, { "value": "维西傈僳族自治县", "label": "维西傈僳族自治县" } ], "value": "迪庆藏族自治州", "label": "迪庆藏族自治州" } ], "value": "云南省", "label": "云南省" }, { "children": [ { "children": [ { "value": "城关区", "label": "城关区" }, { "value": "堆龙德庆区", "label": "堆龙德庆区" }, { "value": "达孜区", "label": "达孜区" }, { "value": "林周县", "label": "林周县" }, { "value": "当雄县", "label": "当雄县" }, { "value": "尼木县", "label": "尼木县" }, { "value": "曲水县", "label": "曲水县" }, { "value": "墨竹工卡县", "label": "墨竹工卡县" } ], "value": "拉萨市", "label": "拉萨市" }, { "children": [ { "value": "桑珠孜区", "label": "桑珠孜区" }, { "value": "南木林县", "label": "南木林县" }, { "value": "江孜县", "label": "江孜县" }, { "value": "定日县", "label": "定日县" }, { "value": "萨迦县", "label": "萨迦县" }, { "value": "拉孜县", "label": "拉孜县" }, { "value": "昂仁县", "label": "昂仁县" }, { "value": "谢通门县", "label": "谢通门县" }, { "value": "白朗县", "label": "白朗县" }, { "value": "仁布县", "label": "仁布县" }, { "value": "康马县", "label": "康马县" }, { "value": "定结县", "label": "定结县" }, { "value": "仲巴县", "label": "仲巴县" }, { "value": "亚东县", "label": "亚东县" }, { "value": "吉隆县", "label": "吉隆县" }, { "value": "聂拉木县", "label": "聂拉木县" }, { "value": "萨嘎县", "label": "萨嘎县" }, { "value": "岗巴县", "label": "岗巴县" } ], "value": "日喀则市", "label": "日喀则市" }, { "children": [ { "value": "卡若区", "label": "卡若区" }, { "value": "江达县", "label": "江达县" }, { "value": "贡觉县", "label": "贡觉县" }, { "value": "类乌齐县", "label": "类乌齐县" }, { "value": "丁青县", "label": "丁青县" }, { "value": "察雅县", "label": "察雅县" }, { "value": "八宿县", "label": "八宿县" }, { "value": "左贡县", "label": "左贡县" }, { "value": "芒康县", "label": "芒康县" }, { "value": "洛隆县", "label": "洛隆县" }, { "value": "边坝县", "label": "边坝县" } ], "value": "昌都市", "label": "昌都市" }, { "children": [ { "value": "巴宜区", "label": "巴宜区" }, { "value": "工布江达县", "label": "工布江达县" }, { "value": "米林县", "label": "米林县" }, { "value": "墨脱县", "label": "墨脱县" }, { "value": "波密县", "label": "波密县" }, { "value": "察隅县", "label": "察隅县" }, { "value": "朗县", "label": "朗县" } ], "value": "林芝市", "label": "林芝市" }, { "children": [ { "value": "乃东区", "label": "乃东区" }, { "value": "扎囊县", "label": "扎囊县" }, { "value": "贡嘎县", "label": "贡嘎县" }, { "value": "桑日县", "label": "桑日县" }, { "value": "琼结县", "label": "琼结县" }, { "value": "曲松县", "label": "曲松县" }, { "value": "措美县", "label": "措美县" }, { "value": "洛扎县", "label": "洛扎县" }, { "value": "加查县", "label": "加查县" }, { "value": "隆子县", "label": "隆子县" }, { "value": "错那县", "label": "错那县" }, { "value": "浪卡子县", "label": "浪卡子县" } ], "value": "山南市", "label": "山南市" }, { "children": [ { "value": "色尼区", "label": "色尼区" }, { "value": "嘉黎县", "label": "嘉黎县" }, { "value": "比如县", "label": "比如县" }, { "value": "聂荣县", "label": "聂荣县" }, { "value": "安多县", "label": "安多县" }, { "value": "申扎县", "label": "申扎县" }, { "value": "索县", "label": "索县" }, { "value": "班戈县", "label": "班戈县" }, { "value": "巴青县", "label": "巴青县" }, { "value": "尼玛县", "label": "尼玛县" }, { "value": "双湖县", "label": "双湖县" } ], "value": "那曲市", "label": "那曲市" }, { "children": [ { "value": "普兰县", "label": "普兰县" }, { "value": "札达县", "label": "札达县" }, { "value": "噶尔县", "label": "噶尔县" }, { "value": "日土县", "label": "日土县" }, { "value": "革吉县", "label": "革吉县" }, { "value": "改则县", "label": "改则县" }, { "value": "措勤县", "label": "措勤县" } ], "value": "阿里地区", "label": "阿里地区" } ], "value": "西藏自治区", "label": "西藏自治区" }, { "children": [ { "children": [ { "value": "新城区", "label": "新城区" }, { "value": "碑林区", "label": "碑林区" }, { "value": "莲湖区", "label": "莲湖区" }, { "value": "灞桥区", "label": "灞桥区" }, { "value": "未央区", "label": "未央区" }, { "value": "雁塔区", "label": "雁塔区" }, { "value": "阎良区", "label": "阎良区" }, { "value": "临潼区", "label": "临潼区" }, { "value": "长安区", "label": "长安区" }, { "value": "高陵区", "label": "高陵区" }, { "value": "鄠邑区", "label": "鄠邑区" }, { "value": "蓝田县", "label": "蓝田县" }, { "value": "周至县", "label": "周至县" } ], "value": "西安市", "label": "西安市" }, { "children": [ { "value": "王益区", "label": "王益区" }, { "value": "印台区", "label": "印台区" }, { "value": "耀州区", "label": "耀州区" }, { "value": "宜君县", "label": "宜君县" } ], "value": "铜川市", "label": "铜川市" }, { "children": [ { "value": "渭滨区", "label": "渭滨区" }, { "value": "金台区", "label": "金台区" }, { "value": "陈仓区", "label": "陈仓区" }, { "value": "凤翔县", "label": "凤翔县" }, { "value": "岐山县", "label": "岐山县" }, { "value": "扶风县", "label": "扶风县" }, { "value": "眉县", "label": "眉县" }, { "value": "陇县", "label": "陇县" }, { "value": "千阳县", "label": "千阳县" }, { "value": "麟游县", "label": "麟游县" }, { "value": "凤县", "label": "凤县" }, { "value": "太白县", "label": "太白县" } ], "value": "宝鸡市", "label": "宝鸡市" }, { "children": [ { "value": "秦都区", "label": "秦都区" }, { "value": "杨陵区", "label": "杨陵区" }, { "value": "渭城区", "label": "渭城区" }, { "value": "三原县", "label": "三原县" }, { "value": "泾阳县", "label": "泾阳县" }, { "value": "乾县", "label": "乾县" }, { "value": "礼泉县", "label": "礼泉县" }, { "value": "永寿县", "label": "永寿县" }, { "value": "彬县", "label": "彬县" }, { "value": "长武县", "label": "长武县" }, { "value": "旬邑县", "label": "旬邑县" }, { "value": "淳化县", "label": "淳化县" }, { "value": "武功县", "label": "武功县" }, { "value": "兴平市", "label": "兴平市" } ], "value": "咸阳市", "label": "咸阳市" }, { "children": [ { "value": "临渭区", "label": "临渭区" }, { "value": "华州区", "label": "华州区" }, { "value": "潼关县", "label": "潼关县" }, { "value": "大荔县", "label": "大荔县" }, { "value": "合阳县", "label": "合阳县" }, { "value": "澄城县", "label": "澄城县" }, { "value": "蒲城县", "label": "蒲城县" }, { "value": "白水县", "label": "白水县" }, { "value": "富平县", "label": "富平县" }, { "value": "韩城市", "label": "韩城市" }, { "value": "华阴市", "label": "华阴市" } ], "value": "渭南市", "label": "渭南市" }, { "children": [ { "value": "宝塔区", "label": "宝塔区" }, { "value": "安塞区", "label": "安塞区" }, { "value": "延长县", "label": "延长县" }, { "value": "延川县", "label": "延川县" }, { "value": "子长县", "label": "子长县" }, { "value": "志丹县", "label": "志丹县" }, { "value": "吴起县", "label": "吴起县" }, { "value": "甘泉县", "label": "甘泉县" }, { "value": "富县", "label": "富县" }, { "value": "洛川县", "label": "洛川县" }, { "value": "宜川县", "label": "宜川县" }, { "value": "黄龙县", "label": "黄龙县" }, { "value": "黄陵县", "label": "黄陵县" } ], "value": "延安市", "label": "延安市" }, { "children": [ { "value": "汉台区", "label": "汉台区" }, { "value": "南郑区", "label": "南郑区" }, { "value": "城固县", "label": "城固县" }, { "value": "洋县", "label": "洋县" }, { "value": "西乡县", "label": "西乡县" }, { "value": "勉县", "label": "勉县" }, { "value": "宁强县", "label": "宁强县" }, { "value": "略阳县", "label": "略阳县" }, { "value": "镇巴县", "label": "镇巴县" }, { "value": "留坝县", "label": "留坝县" }, { "value": "佛坪县", "label": "佛坪县" } ], "value": "汉中市", "label": "汉中市" }, { "children": [ { "value": "榆阳区", "label": "榆阳区" }, { "value": "横山区", "label": "横山区" }, { "value": "府谷县", "label": "府谷县" }, { "value": "靖边县", "label": "靖边县" }, { "value": "定边县", "label": "定边县" }, { "value": "绥德县", "label": "绥德县" }, { "value": "米脂县", "label": "米脂县" }, { "value": "佳县", "label": "佳县" }, { "value": "吴堡县", "label": "吴堡县" }, { "value": "清涧县", "label": "清涧县" }, { "value": "子洲县", "label": "子洲县" }, { "value": "神木市", "label": "神木市" } ], "value": "榆林市", "label": "榆林市" }, { "children": [ { "value": "汉滨区", "label": "汉滨区" }, { "value": "汉阴县", "label": "汉阴县" }, { "value": "石泉县", "label": "石泉县" }, { "value": "宁陕县", "label": "宁陕县" }, { "value": "紫阳县", "label": "紫阳县" }, { "value": "岚皋县", "label": "岚皋县" }, { "value": "平利县", "label": "平利县" }, { "value": "镇坪县", "label": "镇坪县" }, { "value": "旬阳县", "label": "旬阳县" }, { "value": "白河县", "label": "白河县" } ], "value": "安康市", "label": "安康市" }, { "children": [ { "value": "商州区", "label": "商州区" }, { "value": "洛南县", "label": "洛南县" }, { "value": "丹凤县", "label": "丹凤县" }, { "value": "商南县", "label": "商南县" }, { "value": "山阳县", "label": "山阳县" }, { "value": "镇安县", "label": "镇安县" }, { "value": "柞水县", "label": "柞水县" } ], "value": "商洛市", "label": "商洛市" } ], "value": "陕西省", "label": "陕西省" }, { "children": [ { "children": [ { "value": "城关区", "label": "城关区" }, { "value": "七里河区", "label": "七里河区" }, { "value": "西固区", "label": "西固区" }, { "value": "安宁区", "label": "安宁区" }, { "value": "红古区", "label": "红古区" }, { "value": "永登县", "label": "永登县" }, { "value": "皋兰县", "label": "皋兰县" }, { "value": "榆中县", "label": "榆中县" } ], "value": "兰州市", "label": "兰州市" }, { "children": [], "value": "嘉峪关市", "label": "嘉峪关市" }, { "children": [ { "value": "金川区", "label": "金川区" }, { "value": "永昌县", "label": "永昌县" } ], "value": "金昌市", "label": "金昌市" }, { "children": [ { "value": "白银区", "label": "白银区" }, { "value": "平川区", "label": "平川区" }, { "value": "靖远县", "label": "靖远县" }, { "value": "会宁县", "label": "会宁县" }, { "value": "景泰县", "label": "景泰县" } ], "value": "白银市", "label": "白银市" }, { "children": [ { "value": "秦州区", "label": "秦州区" }, { "value": "麦积区", "label": "麦积区" }, { "value": "清水县", "label": "清水县" }, { "value": "秦安县", "label": "秦安县" }, { "value": "甘谷县", "label": "甘谷县" }, { "value": "武山县", "label": "武山县" }, { "value": "张家川回族自治县", "label": "张家川回族自治县" } ], "value": "天水市", "label": "天水市" }, { "children": [ { "value": "凉州区", "label": "凉州区" }, { "value": "民勤县", "label": "民勤县" }, { "value": "古浪县", "label": "古浪县" }, { "value": "天祝藏族自治县", "label": "天祝藏族自治县" } ], "value": "武威市", "label": "武威市" }, { "children": [ { "value": "甘州区", "label": "甘州区" }, { "value": "肃南裕固族自治县", "label": "肃南裕固族自治县" }, { "value": "民乐县", "label": "民乐县" }, { "value": "临泽县", "label": "临泽县" }, { "value": "高台县", "label": "高台县" }, { "value": "山丹县", "label": "山丹县" } ], "value": "张掖市", "label": "张掖市" }, { "children": [ { "value": "崆峒区", "label": "崆峒区" }, { "value": "泾川县", "label": "泾川县" }, { "value": "灵台县", "label": "灵台县" }, { "value": "崇信县", "label": "崇信县" }, { "value": "华亭县", "label": "华亭县" }, { "value": "庄浪县", "label": "庄浪县" }, { "value": "静宁县", "label": "静宁县" } ], "value": "平凉市", "label": "平凉市" }, { "children": [ { "value": "肃州区", "label": "肃州区" }, { "value": "金塔县", "label": "金塔县" }, { "value": "瓜州县", "label": "瓜州县" }, { "value": "肃北蒙古族自治县", "label": "肃北蒙古族自治县" }, { "value": "阿克塞哈萨克族自治县", "label": "阿克塞哈萨克族自治县" }, { "value": "玉门市", "label": "玉门市" }, { "value": "敦煌市", "label": "敦煌市" } ], "value": "酒泉市", "label": "酒泉市" }, { "children": [ { "value": "西峰区", "label": "西峰区" }, { "value": "庆城县", "label": "庆城县" }, { "value": "环县", "label": "环县" }, { "value": "华池县", "label": "华池县" }, { "value": "合水县", "label": "合水县" }, { "value": "正宁县", "label": "正宁县" }, { "value": "宁县", "label": "宁县" }, { "value": "镇原县", "label": "镇原县" } ], "value": "庆阳市", "label": "庆阳市" }, { "children": [ { "value": "安定区", "label": "安定区" }, { "value": "通渭县", "label": "通渭县" }, { "value": "陇西县", "label": "陇西县" }, { "value": "渭源县", "label": "渭源县" }, { "value": "临洮县", "label": "临洮县" }, { "value": "漳县", "label": "漳县" }, { "value": "岷县", "label": "岷县" } ], "value": "定西市", "label": "定西市" }, { "children": [ { "value": "武都区", "label": "武都区" }, { "value": "成县", "label": "成县" }, { "value": "文县", "label": "文县" }, { "value": "宕昌县", "label": "宕昌县" }, { "value": "康县", "label": "康县" }, { "value": "西和县", "label": "西和县" }, { "value": "礼县", "label": "礼县" }, { "value": "徽县", "label": "徽县" }, { "value": "两当县", "label": "两当县" } ], "value": "陇南市", "label": "陇南市" }, { "children": [ { "value": "临夏市", "label": "临夏市" }, { "value": "临夏县", "label": "临夏县" }, { "value": "康乐县", "label": "康乐县" }, { "value": "永靖县", "label": "永靖县" }, { "value": "广河县", "label": "广河县" }, { "value": "和政县", "label": "和政县" }, { "value": "东乡族自治县", "label": "东乡族自治县" }, { "value": "积石山保安族东乡族撒拉族自治县", "label": "积石山保安族东乡族撒拉族自治县" } ], "value": "临夏回族自治州", "label": "临夏回族自治州" }, { "children": [ { "value": "合作市", "label": "合作市" }, { "value": "临潭县", "label": "临潭县" }, { "value": "卓尼县", "label": "卓尼县" }, { "value": "舟曲县", "label": "舟曲县" }, { "value": "迭部县", "label": "迭部县" }, { "value": "玛曲县", "label": "玛曲县" }, { "value": "碌曲县", "label": "碌曲县" }, { "value": "夏河县", "label": "夏河县" } ], "value": "甘南藏族自治州", "label": "甘南藏族自治州" } ], "value": "甘肃省", "label": "甘肃省" }, { "children": [ { "children": [ { "value": "城东区", "label": "城东区" }, { "value": "城中区", "label": "城中区" }, { "value": "城西区", "label": "城西区" }, { "value": "城北区", "label": "城北区" }, { "value": "大通回族土族自治县", "label": "大通回族土族自治县" }, { "value": "湟中县", "label": "湟中县" }, { "value": "湟源县", "label": "湟源县" } ], "value": "西宁市", "label": "西宁市" }, { "children": [ { "value": "乐都区", "label": "乐都区" }, { "value": "平安区", "label": "平安区" }, { "value": "民和回族土族自治县", "label": "民和回族土族自治县" }, { "value": "互助土族自治县", "label": "互助土族自治县" }, { "value": "化隆回族自治县", "label": "化隆回族自治县" }, { "value": "循化撒拉族自治县", "label": "循化撒拉族自治县" } ], "value": "海东市", "label": "海东市" }, { "children": [ { "value": "门源回族自治县", "label": "门源回族自治县" }, { "value": "祁连县", "label": "祁连县" }, { "value": "海晏县", "label": "海晏县" }, { "value": "刚察县", "label": "刚察县" } ], "value": "海北藏族自治州", "label": "海北藏族自治州" }, { "children": [ { "value": "同仁县", "label": "同仁县" }, { "value": "尖扎县", "label": "尖扎县" }, { "value": "泽库县", "label": "泽库县" }, { "value": "河南蒙古族自治县", "label": "河南蒙古族自治县" } ], "value": "黄南藏族自治州", "label": "黄南藏族自治州" }, { "children": [ { "value": "共和县", "label": "共和县" }, { "value": "同德县", "label": "同德县" }, { "value": "贵德县", "label": "贵德县" }, { "value": "兴海县", "label": "兴海县" }, { "value": "贵南县", "label": "贵南县" } ], "value": "海南藏族自治州", "label": "海南藏族自治州" }, { "children": [ { "value": "玛沁县", "label": "玛沁县" }, { "value": "班玛县", "label": "班玛县" }, { "value": "甘德县", "label": "甘德县" }, { "value": "达日县", "label": "达日县" }, { "value": "久治县", "label": "久治县" }, { "value": "玛多县", "label": "玛多县" } ], "value": "果洛藏族自治州", "label": "果洛藏族自治州" }, { "children": [ { "value": "玉树市", "label": "玉树市" }, { "value": "杂多县", "label": "杂多县" }, { "value": "称多县", "label": "称多县" }, { "value": "治多县", "label": "治多县" }, { "value": "囊谦县", "label": "囊谦县" }, { "value": "曲麻莱县", "label": "曲麻莱县" } ], "value": "玉树藏族自治州", "label": "玉树藏族自治州" }, { "children": [ { "value": "格尔木市", "label": "格尔木市" }, { "value": "德令哈市", "label": "德令哈市" }, { "value": "乌兰县", "label": "乌兰县" }, { "value": "都兰县", "label": "都兰县" }, { "value": "天峻县", "label": "天峻县" } ], "value": "海西蒙古族藏族自治州", "label": "海西蒙古族藏族自治州" } ], "value": "青海省", "label": "青海省" }, { "children": [ { "children": [ { "value": "兴庆区", "label": "兴庆区" }, { "value": "西夏区", "label": "西夏区" }, { "value": "金凤区", "label": "金凤区" }, { "value": "永宁县", "label": "永宁县" }, { "value": "贺兰县", "label": "贺兰县" }, { "value": "灵武市", "label": "灵武市" } ], "value": "银川市", "label": "银川市" }, { "children": [ { "value": "大武口区", "label": "大武口区" }, { "value": "惠农区", "label": "惠农区" }, { "value": "平罗县", "label": "平罗县" } ], "value": "石嘴山市", "label": "石嘴山市" }, { "children": [ { "value": "利通区", "label": "利通区" }, { "value": "红寺堡区", "label": "红寺堡区" }, { "value": "盐池县", "label": "盐池县" }, { "value": "同心县", "label": "同心县" }, { "value": "青铜峡市", "label": "青铜峡市" } ], "value": "吴忠市", "label": "吴忠市" }, { "children": [ { "value": "原州区", "label": "原州区" }, { "value": "西吉县", "label": "西吉县" }, { "value": "隆德县", "label": "隆德县" }, { "value": "泾源县", "label": "泾源县" }, { "value": "彭阳县", "label": "彭阳县" } ], "value": "固原市", "label": "固原市" }, { "children": [ { "value": "沙坡头区", "label": "沙坡头区" }, { "value": "中宁县", "label": "中宁县" }, { "value": "海原县", "label": "海原县" } ], "value": "中卫市", "label": "中卫市" } ], "value": "宁夏回族自治区", "label": "宁夏回族自治区" }, { "children": [ { "children": [ { "value": "天山区", "label": "天山区" }, { "value": "沙依巴克区", "label": "沙依巴克区" }, { "value": "新市区", "label": "新市区" }, { "value": "水磨沟区", "label": "水磨沟区" }, { "value": "头屯河区", "label": "头屯河区" }, { "value": "达坂城区", "label": "达坂城区" }, { "value": "米东区", "label": "米东区" }, { "value": "乌鲁木齐县", "label": "乌鲁木齐县" } ], "value": "乌鲁木齐市", "label": "乌鲁木齐市" }, { "children": [ { "value": "独山子区", "label": "独山子区" }, { "value": "克拉玛依区", "label": "克拉玛依区" }, { "value": "白碱滩区", "label": "白碱滩区" }, { "value": "乌尔禾区", "label": "乌尔禾区" } ], "value": "克拉玛依市", "label": "克拉玛依市" }, { "children": [ { "value": "高昌区", "label": "高昌区" }, { "value": "鄯善县", "label": "鄯善县" }, { "value": "托克逊县", "label": "托克逊县" } ], "value": "吐鲁番市", "label": "吐鲁番市" }, { "children": [ { "value": "伊州区", "label": "伊州区" }, { "value": "巴里坤哈萨克自治县", "label": "巴里坤哈萨克自治县" }, { "value": "伊吾县", "label": "伊吾县" } ], "value": "哈密市", "label": "哈密市" }, { "children": [ { "value": "昌吉市", "label": "昌吉市" }, { "value": "阜康市", "label": "阜康市" }, { "value": "呼图壁县", "label": "呼图壁县" }, { "value": "玛纳斯县", "label": "玛纳斯县" }, { "value": "奇台县", "label": "奇台县" }, { "value": "吉木萨尔县", "label": "吉木萨尔县" }, { "value": "木垒哈萨克自治县", "label": "木垒哈萨克自治县" } ], "value": "昌吉回族自治州", "label": "昌吉回族自治州" }, { "children": [ { "value": "博乐市", "label": "博乐市" }, { "value": "阿拉山口市", "label": "阿拉山口市" }, { "value": "精河县", "label": "精河县" }, { "value": "温泉县", "label": "温泉县" } ], "value": "博尔塔拉蒙古自治州", "label": "博尔塔拉蒙古自治州" }, { "children": [ { "value": "库尔勒市", "label": "库尔勒市" }, { "value": "轮台县", "label": "轮台县" }, { "value": "尉犁县", "label": "尉犁县" }, { "value": "若羌县", "label": "若羌县" }, { "value": "且末县", "label": "且末县" }, { "value": "焉耆回族自治县", "label": "焉耆回族自治县" }, { "value": "和静县", "label": "和静县" }, { "value": "和硕县", "label": "和硕县" }, { "value": "博湖县", "label": "博湖县" } ], "value": "巴音郭楞蒙古自治州", "label": "巴音郭楞蒙古自治州" }, { "children": [ { "value": "阿克苏市", "label": "阿克苏市" }, { "value": "温宿县", "label": "温宿县" }, { "value": "库车县", "label": "库车县" }, { "value": "沙雅县", "label": "沙雅县" }, { "value": "新和县", "label": "新和县" }, { "value": "拜城县", "label": "拜城县" }, { "value": "乌什县", "label": "乌什县" }, { "value": "阿瓦提县", "label": "阿瓦提县" }, { "value": "柯坪县", "label": "柯坪县" } ], "value": "阿克苏地区", "label": "阿克苏地区" }, { "children": [ { "value": "阿图什市", "label": "阿图什市" }, { "value": "阿克陶县", "label": "阿克陶县" }, { "value": "阿合奇县", "label": "阿合奇县" }, { "value": "乌恰县", "label": "乌恰县" } ], "value": "克孜勒苏柯尔克孜自治州", "label": "克孜勒苏柯尔克孜自治州" }, { "children": [ { "value": "喀什市", "label": "喀什市" }, { "value": "疏附县", "label": "疏附县" }, { "value": "疏勒县", "label": "疏勒县" }, { "value": "英吉沙县", "label": "英吉沙县" }, { "value": "泽普县", "label": "泽普县" }, { "value": "莎车县", "label": "莎车县" }, { "value": "叶城县", "label": "叶城县" }, { "value": "麦盖提县", "label": "麦盖提县" }, { "value": "岳普湖县", "label": "岳普湖县" }, { "value": "伽师县", "label": "伽师县" }, { "value": "巴楚县", "label": "巴楚县" }, { "value": "塔什库尔干塔吉克自治县", "label": "塔什库尔干塔吉克自治县" } ], "value": "喀什地区", "label": "喀什地区" }, { "children": [ { "value": "和田市", "label": "和田市" }, { "value": "和田县", "label": "和田县" }, { "value": "墨玉县", "label": "墨玉县" }, { "value": "皮山县", "label": "皮山县" }, { "value": "洛浦县", "label": "洛浦县" }, { "value": "策勒县", "label": "策勒县" }, { "value": "于田县", "label": "于田县" }, { "value": "民丰县", "label": "民丰县" } ], "value": "和田地区", "label": "和田地区" }, { "children": [ { "value": "伊宁市", "label": "伊宁市" }, { "value": "奎屯市", "label": "奎屯市" }, { "value": "霍尔果斯市", "label": "霍尔果斯市" }, { "value": "伊宁县", "label": "伊宁县" }, { "value": "察布查尔锡伯自治县", "label": "察布查尔锡伯自治县" }, { "value": "霍城县", "label": "霍城县" }, { "value": "巩留县", "label": "巩留县" }, { "value": "新源县", "label": "新源县" }, { "value": "昭苏县", "label": "昭苏县" }, { "value": "特克斯县", "label": "特克斯县" }, { "value": "尼勒克县", "label": "尼勒克县" } ], "value": "伊犁哈萨克自治州", "label": "伊犁哈萨克自治州" }, { "children": [ { "value": "塔城市", "label": "塔城市" }, { "value": "乌苏市", "label": "乌苏市" }, { "value": "额敏县", "label": "额敏县" }, { "value": "沙湾县", "label": "沙湾县" }, { "value": "托里县", "label": "托里县" }, { "value": "裕民县", "label": "裕民县" }, { "value": "和布克赛尔蒙古自治县", "label": "和布克赛尔蒙古自治县" } ], "value": "塔城地区", "label": "塔城地区" }, { "children": [ { "value": "阿勒泰市", "label": "阿勒泰市" }, { "value": "布尔津县", "label": "布尔津县" }, { "value": "富蕴县", "label": "富蕴县" }, { "value": "福海县", "label": "福海县" }, { "value": "哈巴河县", "label": "哈巴河县" }, { "value": "青河县", "label": "青河县" }, { "value": "吉木乃县", "label": "吉木乃县" } ], "value": "阿勒泰地区", "label": "阿勒泰地区" }, { "children": [], "value": "石河子市", "label": "石河子市" }, { "children": [], "value": "阿拉尔市", "label": "阿拉尔市" }, { "children": [], "value": "图木舒克市", "label": "图木舒克市" }, { "children": [], "value": "五家渠市", "label": "五家渠市" }, { "children": [], "value": "北屯市", "label": "北屯市" }, { "children": [], "value": "铁门关市", "label": "铁门关市" }, { "children": [], "value": "双河市", "label": "双河市" }, { "children": [], "value": "可克达拉市", "label": "可克达拉市" }, { "children": [], "value": "昆玉市", "label": "昆玉市" } ], "value": "新疆维吾尔自治区", "label": "新疆维吾尔自治区" }, { "children": [], "value": "台湾省", "label": "台湾省" }, { "children": [], "value": "香港特别行政区", "label": "香港特别行政区" }, { "children": [], "value": "澳门特别行政区", "label": "澳门特别行政区" } ] } ================================================ FILE: src/json/manage__origin_data.json ================================================ 网上服务平台 团购服务平台 2 网上服务平台 旅游服务平台 24 网上服务平台 订餐服务平台 522 网上服务平台 综合生活服务平台 95 网上购物 线上商超 203 线下零售 运动户外 6 线下零售 黄金珠宝石 9 线下零售 计生用品 13 线下零售 母婴用品/儿童玩具 19 线下零售 超市 204 线下零售 便利店 205 线下零售 自动贩卖机 206 线下零售 数码电器/电脑办公 310 线下零售 百货 207 线下零售 家具建材/家居厨具 266 线下零售 美妆个护 267 线下零售 钟表眼镜 268 线下零售 食品生鲜 270 线下零售 服饰箱包 271 线下零售 礼品鲜花/农资绿植 272 线下零售 批发业 585 线下零售 宠物/宠物用品 284 线下零售 图书音像/文具乐器 315 生活缴费 水电煤缴费/交通罚款等生活缴费 57 生活缴费 有线电视缴费 58 生活缴费 物业管理费 60 生活缴费 其他生活缴费 62 生活缴费 电信运营商 80 生活缴费 宽带收费 81 生活缴费 话费通讯 92 金融 财经资讯 96 金融 股票软件类 97 金融 众筹 112 金融 信用还款 326 金融 保险业务 318 餐饮 其他中餐 539 餐饮 西餐 540 餐饮 日韩/东南亚菜 541 餐饮 咖啡厅 542 餐饮 火锅 543 餐饮 烧烤 544 餐饮 快餐 545 餐饮 小吃/熟食 548 餐饮 烘焙糕点 549 餐饮 甜品饮品 550 居民生活/商业服务 咨询/法律咨询/金融咨询等 42 居民生活/商业服务 物流/快递公司 70 居民生活/商业服务 人才中介机构/招聘/猎头 93 居民生活/商业服务 职业社交/婚介/交友 94 居民生活/商业服务 婚庆/摄影 273 居民生活/商业服务 装饰/设计 289 居民生活/商业服务 房地产 316 居民生活/商业服务 家政/维修服务 311 居民生活/商业服务 广告/会展/活动策划 312 居民生活/商业服务 苗木种植/园林绿化 317 居民生活/商业服务 共享服务 538 居民生活/商业服务 丧仪殡葬服务 564 居民生活/商业服务 搬家/回收 565 居民生活/商业服务 宠物医院 566 交通出行/票旅游 旅行社 23 交通出行/票务旅游 机票/机票代理 274 交通出行/票务旅游 旅馆/酒店/度假区 275 交通出行/票务旅游 加油 259 交通出行/票务旅游 汽车用品 269 交通出行/票务旅游 船舶/海运服务 75 交通出行/票务旅游 租车 77 交通出行/票务旅游 停车缴费 287 交通出行/票务旅游 城市公共交通 288 交通出行/票务 铁路客运旅游 283 交通出行/票务旅游 景区 354 交通出行/票务旅游 汽车美容/维修保养 563 交通出行/票务旅游 高速收费 610 休闲娱乐 运动健身场馆 54 休闲娱乐 游艺厅/KTV/网吧 56 休闲娱乐 俱乐部/休闲会所 280 休闲娱乐 娱乐票务 281 休闲娱乐 酒吧 571 休闲娱乐 院线影城 572 休闲娱乐 演出赛事 573 休闲娱乐 美发/美容/美甲店 574 教育/医疗 教育/培训/考试缴费/学费 52 教育/医疗 私立院校 53 教育/医疗 私立/民营医院/诊所 66 教育/医疗 挂号平台 67 教育/医疗 保健器械/医疗器械/非处方药品 314 教育/医疗 保健信息咨询平台 282 网络媒体/计算机服务/游戏 在线图书/视频/音乐 276 网络媒体/计算机服务/游戏 软件/建站/技术开发 277 网络媒体/计算机服务/游戏 网络推广/网络广告 278 网络媒体/计算机服务/游戏 门户/资讯/论坛 104 网络媒体/计算机服务/游戏 游戏 501 网络媒体/计算机服务/游戏 网络直播 521 收藏/拍卖 非文物类收藏品 31 收藏/拍卖 拍卖/典当 325 收藏/拍卖 文物经营/文物复制品销售 285 其他 其他行业 111 ================================================ FILE: src/json/manage_cata_data.js ================================================ [{ label: '网上服务平台', value: '01', children: [{ label: '团购服务平台', value: '01' }, { label: '旅游服务平台', value: '24' }, { label: '订餐服务平台', value: '522' }, { label: '综合生活服务平台', value: '95' }, ] }, { label: '网上购物', value: '02', children: [{ label: '线上商超', value: ' 203' }, ] }, { label: '线下零售', value: '03', children: [{ label: '运动户外', value: '6' }, { label: '黄金珠宝石', value: '9' }, { label: '计生用品', value: '13' }, { label: '母婴用品/儿童玩具', value: '19' }, { label: '超市', value: '204' }, { label: '便利店', value: '205' }, { label: '自动贩卖机', value: '206' }, { label: '数码电器/电脑办公 ', value: '310' }, { label: '百货', value: '207' }, { label: '家具建材/家居厨具', value: '266' }, { label: '美妆个护', value: '267' }, { label: '钟表眼镜', value: '268' }, { label: '食品生鲜', value: '270' }, { label: '服饰箱包', value: '271' }, { label: '礼品鲜花/农资绿植', value: '272' }, { label: '批发业', value: '585' }, { label: '宠物/宠物用品', value: '284' }, { label: '图书音像/文具乐器', value: '315' }, ] }, { label: '生活缴费', value: '04', children: [{ label: '水电煤缴费/交通罚款等', value: '57' }, { label: '有线电视缴费', value: '58' }, { label: '物业管理费', value: '60' }, { label: '其他', value: ' 62' }, { label: '电信运营商', value: '80' }, { label: '宽带收费', value: '81' }, { label: '话费通讯', value: '92' }, ] }, { label: '金融', value: '05', children: [{ label: '财经资讯', value: '96' }, { label: '股票软件类', value: '97' }, { label: '众筹', value: '112' }, { label: '信用还款', value: '326' }, { label: '保险业务', value: '318' }, ] }, { label: '餐饮', value: '06', children: [{ label: '其他中餐', value: '539' }, { label: '西餐', value: '540' }, { label: '日韩/东南亚菜', value: '541' }, { label: '咖啡厅', value: '542' }, { label: '火锅', value: '543' }, { label: '烧烤', value: '544' }, { label: '快餐', value: '545' }, { label: '小吃/熟食', value: '548' }, { label: '烘焙糕点', value: '549' }, { label: '甜品饮品', value: '550' }, ] }, { label: '居民生活/商业服务', value: '07', children: [{ label: '咨询/法律咨询/金融咨询等', value: '42' }, { label: '物流/快递公司', value: '70' }, { label: '人才中介机构/招聘/猎头', value: '93' }, { label: '职业社交/婚介/交友 ', value: '94' }, { label: '婚庆/摄影 ', value: '273' }, { label: '装饰/设计 ', value: '289' }, { label: '房地产', value: '316' }, { label: '家政/维修服务', value: '311' }, { label: '广告/会展/活动策划 ', value: '312' }, { label: '苗木种植/园林绿化 ', value: '317' }, { label: '共享服务', value: '538' }, { label: '丧仪殡葬服务', value: '564' }, { label: '搬家/回收 ', value: '565' }, { label: '宠物医院', value: '566' }, ] }, { label: '交通出行/票务旅游', value: '08', children: [{ label: '旅行社', value: '23' }, { label: '机票/机票代理 ', value: '274' }, { label: '旅馆/酒店/度假区', value: '275' }, { label: '加油', value: '259' }, { label: '汽车用品', value: '269' }, { label: '船舶/海运服务', value: '75' }, { label: '租车', value: '77' }, { label: '停车缴费', value: '287' }, { label: '城市公共交通', value: '288' }, { label: '铁路客运旅游', value: '283' }, { label: '景区', value: '354' }, { label: '汽车美容/维修保养', value: '563' }, { label: '高速收费', value: '610' }, ] }, { label: '休闲娱乐', value: '09', children: [{ label: '运动健身场馆', value: '54' }, { label: '游艺厅/KTV/网吧', value: '56' }, { label: '俱乐部/休闲会所', value: '280' }, { label: '娱乐票务', value: '281' }, { label: '酒吧', value: '571' }, { label: '院线影城', value: '572' }, { label: '演出赛事', value: '573' }, { label: '美发/美容/美甲店', value: '574' }, ] }, { label: '教育/医疗', value: '10', children: [{ label: '教育/培训/考试缴费/学费', value: '52' }, { label: '私立院校', value: '53' }, { label: '私立/民营医院/诊所 ', value: '66' }, { label: '挂号平台', value: '67' }, { label: '保健器械/医疗器械/非处方药品', value: '314' }, { label: '保健信息咨询平台', value: '282' }, ] }, { label: '网络媒体/计算机服务/游戏', value: '11', children: [{ label: '在线图书/视频/音乐', value: '276' }, { label: '软件/建站/技术开发', value: '277' }, { label: '网络推广/网络广告', value: '278' }, { label: '门户/资讯/论坛 ', value: '104' }, { label: '游戏', value: '501' }, { label: '网络直播', value: '521' }, ] }, { label: '收藏/拍卖', value: '12', children: [{ label: '非文物类收藏品', value: '31' }, { label: '拍卖/典当', value: '325' }, { label: '文物经营/文物复制品销售', value: '285' }, ] }, { label: '其他', value: '13', children: [{ label: '其他行业', value: '111' }, ] }] ================================================ FILE: src/json/manage_cata_data.json ================================================ [{"label":"网上服务平台","value":"01","children":[{"label":"团购服务平台","value":"01"},{"label":"旅游服务平台","value":"24"},{"label":"订餐服务平台","value":"522"},{"label":"综合生活服务平台","value":"95"}]},{"label":"网上购物","value":"02","children":[{"label":"线上商超","value":" 203"}]},{"label":"线下零售","value":"03","children":[{"label":"运动户外","value":"6"},{"label":"黄金珠宝石","value":"9"},{"label":"计生用品","value":"13"},{"label":"母婴用品/儿童玩具","value":"19"},{"label":"超市","value":"204"},{"label":"便利店","value":"205"},{"label":"自动贩卖机","value":"206"},{"label":"数码电器/电脑办公 ","value":"310"},{"label":"百货","value":"207"},{"label":"家具建材/家居厨具","value":"266"},{"label":"美妆个护","value":"267"},{"label":"钟表眼镜","value":"268"},{"label":"食品生鲜","value":"270"},{"label":"服饰箱包","value":"271"},{"label":"礼品鲜花/农资绿植","value":"272"},{"label":"批发业","value":"585"},{"label":"宠物/宠物用品","value":"284"},{"label":"图书音像/文具乐器","value":"315"}]},{"label":"生活缴费","value":"04","children":[{"label":"水电煤缴费/交通罚款等","value":"57"},{"label":"有线电视缴费","value":"58"},{"label":"物业管理费","value":"60"},{"label":"其他","value":" 62"},{"label":"电信运营商","value":"80"},{"label":"宽带收费","value":"81"},{"label":"话费通讯","value":"92"}]},{"label":"金融","value":"05","children":[{"label":"财经资讯","value":"96"},{"label":"股票软件类","value":"97"},{"label":"众筹","value":"112"},{"label":"信用还款","value":"326"},{"label":"保险业务","value":"318"}]},{"label":"餐饮","value":"06","children":[{"label":"其他中餐","value":"539"},{"label":"西餐","value":"540"},{"label":"日韩/东南亚菜","value":"541"},{"label":"咖啡厅","value":"542"},{"label":"火锅","value":"543"},{"label":"烧烤","value":"544"},{"label":"快餐","value":"545"},{"label":"小吃/熟食","value":"548"},{"label":"烘焙糕点","value":"549"},{"label":"甜品饮品","value":"550"}]},{"label":"居民生活/商业服务","value":"07","children":[{"label":"咨询/法律咨询/金融咨询等","value":"42"},{"label":"物流/快递公司","value":"70"},{"label":"人才中介机构/招聘/猎头","value":"93"},{"label":"职业社交/婚介/交友 ","value":"94"},{"label":"婚庆/摄影 ","value":"273"},{"label":"装饰/设计 ","value":"289"},{"label":"房地产","value":"316"},{"label":"家政/维修服务","value":"311"},{"label":"广告/会展/活动策划 ","value":"312"},{"label":"苗木种植/园林绿化 ","value":"317"},{"label":"共享服务","value":"538"},{"label":"丧仪殡葬服务","value":"564"},{"label":"搬家/回收 ","value":"565"},{"label":"宠物医院","value":"566"}]},{"label":"交通出行/票务旅游","value":"08","children":[{"label":"旅行社","value":"23"},{"label":"机票/机票代理 ","value":"274"},{"label":"旅馆/酒店/度假区","value":"275"},{"label":"加油","value":"259"},{"label":"汽车用品","value":"269"},{"label":"船舶/海运服务","value":"75"},{"label":"租车","value":"77"},{"label":"停车缴费","value":"287"},{"label":"城市公共交通","value":"288"},{"label":"铁路客运旅游","value":"283"},{"label":"景区","value":"354"},{"label":"汽车美容/维修保养","value":"563"},{"label":"高速收费","value":"610"}]},{"label":"休闲娱乐","value":"09","children":[{"label":"运动健身场馆","value":"54"},{"label":"游艺厅/KTV/网吧","value":"56"},{"label":"俱乐部/休闲会所","value":"280"},{"label":"娱乐票务","value":"281"},{"label":"酒吧","value":"571"},{"label":"院线影城","value":"572"},{"label":"演出赛事","value":"573"},{"label":"美发/美容/美甲店","value":"574"}]},{"label":"教育/医疗","value":"10","children":[{"label":"教育/培训/考试缴费/学费","value":"52"},{"label":"私立院校","value":"53"},{"label":"私立/民营医院/诊所 ","value":"66"},{"label":"挂号平台","value":"67"},{"label":"保健器械/医疗器械/非处方药品","value":"314"},{"label":"保健信息咨询平台","value":"282"}]},{"label":"网络媒体/计算机服务/游戏","value":"11","children":[{"label":"在线图书/视频/音乐","value":"276"},{"label":"软件/建站/技术开发","value":"277"},{"label":"网络推广/网络广告","value":"278"},{"label":"门户/资讯/论坛 ","value":"104"},{"label":"游戏","value":"501"},{"label":"网络直播","value":"521"}]},{"label":"收藏/拍卖","value":"12","children":[{"label":"非文物类收藏品","value":"31"},{"label":"拍卖/典当","value":"325"},{"label":"文物经营/文物复制品销售","value":"285"}]},{"label":"其他","value":"13","children":[{"label":"其他行业","value":"111"}]}] ================================================ FILE: src/koa/db/index.js ================================================ ================================================ FILE: src/koa/index.js ================================================ const koa = require('koa') const app = new koa(); app.use(async ctx => { ctx.body = 'hello world'; }) app.listen(3000); ================================================ FILE: src/leetcode/1.两数之和.js ================================================ /* * @lc app=leetcode.cn id=1 lang=javascript * * [1] 两数之和 */ // @lc code=start /** * @param {number[]} nums * @param {number} target * @return {number[]} */ var twoSum = function(nums, target) { const len = nums.length const map = new Map() for (let i = 0; i < len; i++) { map.set(nums[i], i) } for (let i = 0; i < len; i++) { const j = map.get(target - nums[i]) if (map.has(target - nums[i])) { if (2 * nums[i] === target && i === j) continue return [i, j] } } } // @lc code=end ================================================ FILE: src/leetcode/13.罗马数字转整数.js ================================================ /* * @lc app=leetcode.cn id=13 lang=javascript * * [13] 罗马数字转整数 * * https://leetcode-cn.com/problems/roman-to-integer/description/ * * algorithms * Easy (60.11%) * Likes: 721 * Dislikes: 0 * Total Accepted: 132.3K * Total Submissions: 220.1K * Testcase Example: '"III"' * * 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。 * * 字符 数值 * I 1 * V 5 * X 10 * L 50 * C 100 * D 500 * M 1000 * * 例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做  XXVII, 即为 XX + V + * II 。 * * 通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 * 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况: * * * I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。 * X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。 * C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。 * * * 给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。 * * 示例 1: * * 输入: "III" * 输出: 3 * * 示例 2: * * 输入: "IV" * 输出: 4 * * 示例 3: * * 输入: "IX" * 输出: 9 * * 示例 4: * * 输入: "LVIII" * 输出: 58 * 解释: L = 50, V= 5, III = 3. * * * 示例 5: * * 输入: "MCMXCIV" * 输出: 1994 * 解释: M = 1000, CM = 900, XC = 90, IV = 4. * */ // @lc code=start /** * @param {string} s * @return {number} */ var romanToInt = function(s) { var translate = { I: 1, IV: 4, V: 5, IX: 9, X: 10, XL: 40, L: 50, XC: 90, C: 100, CD: 400, D: 500, CM: 900, M: 1000 } var sum = 0 var i = 0 while (i < s.length) { if (translate.hasOwnProperty(s[i] + s[i + 1])) { sum = sum + translate[s[i] + s[i + 1]] i = i + 2 } else { sum = sum + translate[s[i]] i = i + 1 } } return sum } // @lc code=end ================================================ FILE: src/leetcode/14.最长公共前缀.js ================================================ /* * @lc app=leetcode.cn id=14 lang=javascript * * [14] 最长公共前缀 * * https://leetcode-cn.com/problems/longest-common-prefix/description/ * * algorithms * Easy (35.67%) * Likes: 820 * Dislikes: 0 * Total Accepted: 167.6K * Total Submissions: 469.7K * Testcase Example: '["flower","flow","flight"]' * * 编写一个函数来查找字符串数组中的最长公共前缀。 * * 如果不存在公共前缀,返回空字符串 ""。 * * 示例 1: * * 输入: ["flower","flow","flight"] * 输出: "fl" * * * 示例 2: * * 输入: ["dog","racecar","car"] * 输出: "" * 解释: 输入不存在公共前缀。 * * * 说明: * * 所有输入只包含小写字母 a-z 。 * */ // @lc code=start /** * @param {string[]} strs * @return {string} */ var longestCommonPrefix = function(strs) { var result = strs[0] var i = 0 while (i < strs.length) { result = commonStr(result, strs[i]) i++ } return result || '' } /** * @param {String} str * @param {String} str * @return {String} */ var commonStr = function(str1, str2) { let result = '' let len = str1.length > str2.length ? str2.length : str1.length for (let index = 0; index < len; index++) { if (str1[index] === str2[index]) { result = result + str1[index] } else { return result } } return result } console.log(longestCommonPrefix(['flower', 'flow', 'flight'])) // @lc code=end ================================================ FILE: src/leetcode/165.比较版本号.js ================================================ /* * @lc app=leetcode.cn id=165 lang=javascript * * [165] 比较版本号 * * https://leetcode-cn.com/problems/compare-version-numbers/description/ * * algorithms * Medium (37.57%) * Likes: 52 * Dislikes: 0 * Total Accepted: 9.6K * Total Submissions: 25.6K * Testcase Example: '"0.1"\n"1.1"' * * 比较两个版本号 version1 和 version2。 * 如果 version1 > version2 返回 1,如果 version1 < version2 返回 -1, 除此之外返回 0。 * * 你可以假设版本字符串非空,并且只包含数字和 . 字符。 * * . 字符不代表小数点,而是用于分隔数字序列。 * * 例如,2.5 不是“两个半”,也不是“差一半到三”,而是第二版中的第五个小版本。 * * 你可以假设版本号的每一级的默认修订版号为 0。例如,版本号 3.4 的第一级(大版本)和第二级(小版本)修订号分别为 3 和 * 4。其第三级和第四级修订号均为 0。 * * * 示例 1: * * 输入: version1 = "0.1", version2 = "1.1" * 输出: -1 * * 示例 2: * * 输入: version1 = "1.0.1", version2 = "1" * 输出: 1 * * 示例 3: * * 输入: version1 = "7.5.2.4", version2 = "7.5.3" * 输出: -1 * * 示例 4: * * 输入:version1 = "1.01", version2 = "1.001" * 输出:0 * 解释:忽略前导零,“01” 和 “001” 表示相同的数字 “1”。 * * 示例 5: * * 输入:version1 = "1.0", version2 = "1.0.0" * 输出:0 * 解释:version1 没有第三级修订号,这意味着它的第三级修订号默认为 “0”。 * * * * 提示: * * * 版本字符串由以点 (.) 分隔的数字字符串组成。这个数字字符串可能有前导零。 * 版本字符串不以点开始或结束,并且其中不会有两个连续的点。 * * */ // @lc code=start /** * @param {string} version1 * @param {string} version2 * @return {number} */ var compareVersion = function(version1, version2) { const verson1Arr = version1.split('.'); const verson2Arr = version2.split('.'); const length = verson1Arr.length > verson2Arr.length ? verson1Arr.length : verson2Arr.length; for (let index = 0; index < length; index++) { const item1 = verson1Arr[index]; const item2 = verson2Arr[index]; return item1 > } }; // @lc code=end ================================================ FILE: src/leetcode/2.两数相加.js ================================================ /* * @lc app=leetcode.cn id=2 lang=javascript * * [2] 两数相加 * * https://leetcode-cn.com/problems/add-two-numbers/description/ * * algorithms * Medium (36.28%) * Likes: 3672 * Dislikes: 0 * Total Accepted: 292.3K * Total Submissions: 805.4K * Testcase Example: '[2,4,3]\n[5,6,4]' * * 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 * * 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 * * 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 * * 示例: * * 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) * 输出:7 -> 0 -> 8 * 原因:342 + 465 = 807 * * */ // @lc code=start /** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */ /** * @param {ListNode} l1 * @param {ListNode} l2 * @return {ListNode} */ var addTwoNumbers = function(l1, l2) { console.log(l1, l2) } var l1 = new ListNode() // @lc code=end ================================================ FILE: src/leetcode/20.有效的括号.js ================================================ /* * @lc app=leetcode.cn id=20 lang=javascript * * [20] 有效的括号 * * https://leetcode-cn.com/problems/valid-parentheses/description/ * * algorithms * Easy (40.37%) * Likes: 1293 * Dislikes: 0 * Total Accepted: 178.1K * Total Submissions: 441K * Testcase Example: '"()"' * * 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 * * 有效字符串需满足: * * * 左括号必须用相同类型的右括号闭合。 * 左括号必须以正确的顺序闭合。 * * * 注意空字符串可被认为是有效字符串。 * * 示例 1: * * 输入: "()" * 输出: true * * * 示例 2: * * 输入: "()[]{}" * 输出: true * * * 示例 3: * * 输入: "(]" * 输出: false * * * 示例 4: * * 输入: "([)]" * 输出: false * * * 示例 5: * * 输入: "{[]}" * 输出: true * */ // @lc code=start /** * @param {string} s * @return {boolean} */ var isMatch = function(left, right) { return ( (left === '{' && right === '}') || (left === '(' && right === ')') || (left === '[' && right === ']') ) } var isValid = function(s) { var stack = [] var i = -1 var left = '{[(' while (++i < s.length) { if (left.indexOf(s[i]) !== -1) { stack.push(s[i]) } else { if (stack.length > 0 && isMatch(stack[stack.length - 1], s[i])) { stack.pop() } else { return false } } } return stack.length ? false : true } // @lc code=end ================================================ FILE: src/leetcode/21.合并两个有序链表.js ================================================ /* * @lc app=leetcode.cn id=21 lang=javascript * * [21] 合并两个有序链表 * * https://leetcode-cn.com/problems/merge-two-sorted-lists/description/ * * algorithms * Easy (58.91%) * Likes: 791 * Dislikes: 0 * Total Accepted: 160.9K * Total Submissions: 273K * Testcase Example: '[1,2,4]\n[1,3,4]' * * 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 * * 示例: * * 输入:1->2->4, 1->3->4 * 输出:1->1->2->3->4->4 * * */ // @lc code=start /** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */ /** * @param {ListNode} l1 * @param {ListNode} l2 * @return {ListNode} */ var mergeTwoLists = function(l1, l2) { return l1.next } // @lc code=end ================================================ FILE: src/leetcode/26.删除排序数组中的重复项.js ================================================ /* * @lc app=leetcode.cn id=26 lang=javascript * * [26] 删除排序数组中的重复项 * * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/description/ * * algorithms * Easy (47.83%) * Likes: 1258 * Dislikes: 0 * Total Accepted: 223.1K * Total Submissions: 466.1K * Testcase Example: '[1,1,2]' * * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 * * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 * * 示例 1: * * 给定数组 nums = [1,1,2], * * 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 * * 你不需要考虑数组中超出新长度后面的元素。 * * 示例 2: * * 给定 nums = [0,0,1,1,1,2,2,3,3,4], * * 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 * * 你不需要考虑数组中超出新长度后面的元素。 * * * 说明: * * 为什么返回数值是整数,但输出的答案是数组呢? * * 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 * * 你可以想象内部操作如下: * * // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 * int len = removeDuplicates(nums); * * // 在函数里修改输入数组对于调用者是可见的。 * // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 * for (int i = 0; i < len; i++) { * print(nums[i]); * } * * */ // @lc code=start /** * @param {number[]} nums * @return {number} */ var removeDuplicates = function(nums) { var len = nums.length var count = 0 for (let i = len - 1; i >= 0; i--) { if (nums[i - 1] === nums[i]) { count++ for (let j = i - 1; j < len; j++) { nums[j] = nums[j + 1] } } } return len - count } // console.log(removeDuplicates([0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4])) // 1 2 // i-1 = i // @lc code=end ================================================ FILE: src/leetcode/27.移除元素.js ================================================ /* * @lc app=leetcode.cn id=27 lang=javascript * * [27] 移除元素 * * https://leetcode-cn.com/problems/remove-element/description/ * * algorithms * Easy (56.92%) * Likes: 455 * Dislikes: 0 * Total Accepted: 120.4K * Total Submissions: 211.4K * Testcase Example: '[3,2,2,3]\n3' * * 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。 * * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 * * 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 * * 示例 1: * * 给定 nums = [3,2,2,3], val = 3, * * 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 * * 你不需要考虑数组中超出新长度后面的元素。 * * * 示例 2: * * 给定 nums = [0,1,2,2,3,0,4,2], val = 2, * * 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。 * * 注意这五个元素可为任意顺序。 * * 你不需要考虑数组中超出新长度后面的元素。 * * * 说明: * * 为什么返回数值是整数,但输出的答案是数组呢? * * 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 * * 你可以想象内部操作如下: * * // nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝 * int len = removeElement(nums, val); * * // 在函数里修改输入数组对于调用者是可见的。 * // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 * for (int i = 0; i < len; i++) { * print(nums[i]); * } * * */ // @lc code=start /** * @param {number[]} nums * @param {number} val * @return {number} */ var removeElement = function(nums, val) { var i = nums.length var len = nums.length var count = 0 while (i--) { if (nums[i] === val) { count++ while (i++ < len) { nums[i - 1] = nums[i] } } } return len - count } // @lc code=end ================================================ FILE: src/leetcode/28.实现-str-str.js ================================================ /* * @lc app=leetcode.cn id=28 lang=javascript * * [28] 实现 strStr() * * https://leetcode-cn.com/problems/implement-strstr/description/ * * algorithms * Easy (39.26%) * Likes: 335 * Dislikes: 0 * Total Accepted: 114.1K * Total Submissions: 290.4K * Testcase Example: '"hello"\n"ll"' * * 实现 strStr() 函数。 * * 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 * (从0开始)。如果不存在,则返回  -1。 * * 示例 1: * * 输入: haystack = "hello", needle = "ll" * 输出: 2 * * * 示例 2: * * 输入: haystack = "aaaaa", needle = "bba" * 输出: -1 * * * 说明: * * 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 * * 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。 * */ // @lc code=start /** * @param {string} haystack * @param {string} needle * @return {number} */ var strStr = function(haystack, needle) { return haystack.indexOf(needle) } // @lc code=end ================================================ FILE: src/leetcode/3.无重复字符的最长子串.js ================================================ /* * @lc app=leetcode.cn id=3 lang=javascript * * [3] 无重复字符的最长子串 * * https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/description/ * * algorithms * Medium (32.36%) * Likes: 2972 * Dislikes: 0 * Total Accepted: 314K * Total Submissions: 968.3K * Testcase Example: '"abcabcbb"' * * 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 * * 示例 1: * * 输入: "abcabcbb" * 输出: 3 * 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 * * * 示例 2: * * 输入: "bbbbb" * 输出: 1 * 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 * * * 示例 3: * * 输入: "pwwkew" * 输出: 3 * 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 * 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。 * * */ // @lc code=start /** * @param {string} s * @return {number} */ var lengthOfLongestSubstring = function(s) { if (s.length <= 1) { return s.length } var max = 1 var tempIndex = 0 for (let i = 0; i < s.length; i++) { for (let j = i; j < s.length; j++) { if (s[j] === s[tempIndex]) { max = Math.max(max, j - tempIndex) tempIndex = j } } } return max > 1 ? max : s.length } // @lc code=end ================================================ FILE: src/leetcode/341.扁平化嵌套列表迭代器.js ================================================ /* * @lc app=leetcode.cn id=341 lang=javascript * * [341] 扁平化嵌套列表迭代器 * * https://leetcode-cn.com/problems/flatten-nested-list-iterator/description/ * * algorithms * Medium (61.29%) * Likes: 59 * Dislikes: 0 * Total Accepted: 4.9K * Total Submissions: 8K * Testcase Example: '[[1,1],2,[1,1]]' * * 给定一个嵌套的整型列表。设计一个迭代器,使其能够遍历这个整型列表中的所有整数。 * * 列表中的项或者为一个整数,或者是另一个列表。 * * 示例 1: * * 输入: [[1,1],2,[1,1]] * 输出: [1,1,2,1,1] * 解释: 通过重复调用 next 直到 hasNext 返回false,next 返回的元素的顺序应该是: [1,1,2,1,1]。 * * 示例 2: * * 输入: [1,[4,[6]]] * 输出: [1,4,6] * 解释: 通过重复调用 next 直到 hasNext 返回false,next 返回的元素的顺序应该是: [1,4,6]。 * * */ // @lc code=start /** * // This is the interface that allows for creating nested lists. * // You should not implement it, or speculate about its implementation * function NestedInteger() { * * Return true if this NestedInteger holds a single integer, rather than a nested list. * @return {boolean} * this.isInteger = function() { * ... * }; * * Return the single integer that this NestedInteger holds, if it holds a single integer * Return null if this NestedInteger holds a nested list * @return {integer} * this.getInteger = function() { * ... * }; * * Return the nested list that this NestedInteger holds, if it holds a nested list * Return null if this NestedInteger holds a single integer * @return {NestedInteger[]} * this.getList = function() { * ... * }; * }; */ /** * @constructor * @param {NestedInteger[]} nestedList */ var NestedIterator = function(nestedList) { }; /** * @this NestedIterator * @returns {boolean} */ NestedIterator.prototype.hasNext = function() { }; /** * @this NestedIterator * @returns {integer} */ NestedIterator.prototype.next = function() { }; /** * Your NestedIterator will be called like this: * var i = new NestedIterator(nestedList), a = []; * while (i.hasNext()) a.push(i.next()); */ // @lc code=end ================================================ FILE: src/leetcode/35.搜索插入位置.js ================================================ /* * @lc app=leetcode.cn id=35 lang=javascript * * [35] 搜索插入位置 * * https://leetcode-cn.com/problems/search-insert-position/description/ * * algorithms * Easy (44.77%) * Likes: 398 * Dislikes: 0 * Total Accepted: 104K * Total Submissions: 232.2K * Testcase Example: '[1,3,5,6]\n5' * * 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 * * 你可以假设数组中无重复元素。 * * 示例 1: * * 输入: [1,3,5,6], 5 * 输出: 2 * * * 示例 2: * * 输入: [1,3,5,6], 2 * 输出: 1 * * * 示例 3: * * 输入: [1,3,5,6], 7 * 输出: 4 * * * 示例 4: * * 输入: [1,3,5,6], 0 * 输出: 0 * * */ // @lc code=start /** * @param {number[]} nums * @param {number} target * @return {number} */ var searchInsert = function(nums, target) { var hi = nums.length - 1, lo = 0 // 2.迭代,换界 while (hi - lo >= 0) { var mi = (hi + lo) >>> 1 if (target < nums[mi]) { hi = mi - 1 } else if (nums[mi] < target) { lo = mi + 1 } else { return mi } } return lo } searchInsert([1, 3, 5, 6], 2) // @lc code=end ================================================ FILE: src/leetcode/38.外观数列.js ================================================ /* * @lc app=leetcode.cn id=38 lang=javascript * * [38] 外观数列 * * https://leetcode-cn.com/problems/count-and-say/description/ * * algorithms * Easy (53.87%) * Likes: 369 * Dislikes: 0 * Total Accepted: 66K * Total Submissions: 122.3K * Testcase Example: '1' * * 「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。前五项如下: * * 1. 1 * 2. 11 * 3. 21 * 4. 1211 * 5. 111221 * * * 1 被读作  "one 1"  ("一个一") , 即 11。 * 11 被读作 "two 1s" ("两个一"), 即 21。 * 21 被读作 "one 2",  "one 1" ("一个二" ,  "一个一") , 即 1211。 * * 给定一个正整数 n(1 ≤ n ≤ 30),输出外观数列的第 n 项。 * * 注意:整数序列中的每一项将表示为一个字符串。 * * * * 示例 1: * * 输入: 1 * 输出: "1" * * * 示例 2: * * 输入: 4 * 输出: "1211" * * */ // @lc code=start /** * @param {number} n * @return {string} */ var countAndSay = function(n) { if (n === 1) return '1' var last = countAndSay(n - 1) var tempIndex = 0 var result = '' var i = 0 var allEqual = true while (++i <= last.length) { if (last[i] !== last[i - 1] || last[i] === 0) { allEqual = false result = result + String(i - tempIndex) + String(last[i - 1]) tempIndex = i } } if (allEqual) { result = String(last.length) + String(last[0]) } return result } ================================================ FILE: src/leetcode/53.最大子序和.js ================================================ /* * @lc app=leetcode.cn id=53 lang=javascript * * [53] 最大子序和 * * https://leetcode-cn.com/problems/maximum-subarray/description/ * * algorithms * Easy (48.54%) * Likes: 1478 * Dislikes: 0 * Total Accepted: 141.2K * Total Submissions: 290.6K * Testcase Example: '[-2,1,-3,4,-1,2,1,-5,4]' * * 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 * * 示例: * * 输入: [-2,1,-3,4,-1,2,1,-5,4], * 输出: 6 * 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 * * * 进阶: * * 如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 * */ // @lc code=start /** * @param {number[]} nums * @return {number} */ var maxSubArray = function(nums) {} // @lc code=end ================================================ FILE: src/leetcode/58.最后一个单词的长度.js ================================================ /* * @lc app=leetcode.cn id=58 lang=javascript * * [58] 最后一个单词的长度 * * https://leetcode-cn.com/problems/length-of-last-word/description/ * * algorithms * Easy (31.95%) * Likes: 164 * Dislikes: 0 * Total Accepted: 60.5K * Total Submissions: 189K * Testcase Example: '"Hello World"' * * 给定一个仅包含大小写字母和空格 ' ' 的字符串,返回其最后一个单词的长度。 * * 如果不存在最后一个单词,请返回 0 。 * * 说明:一个单词是指由字母组成,但不包含任何空格的字符串。 * * 示例: * * 输入: "Hello World" * 输出: 5 * * */ // @lc code=start /** * @param {string} s * @return {number} */ // var trimRight = function(s) { // var i = s.length // while (--i && s[i] === ' ') { // s = s.slice(0, i) // } // return s // } // var lengthOfLastWord = function(s) { // var i = s.length // if (!i) return 0 // s = trimRight(s) // while (--i >= 0) { // if (s[i] === ' ') { // return s.length - 1 - i // } // } // return s.length // } var lengthOfLastWord = function(s) { s = s.trim() return s.length - 1 - s.lastIndexOf(' ') } // @lc code=end ================================================ FILE: src/leetcode/66.加一.js ================================================ /* * @lc app=leetcode.cn id=66 lang=javascript * * [66] 加一 * * https://leetcode-cn.com/problems/plus-one/description/ * * algorithms * Easy (42.30%) * Likes: 402 * Dislikes: 0 * Total Accepted: 107.1K * Total Submissions: 252.6K * Testcase Example: '[1,2,3]' * * 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 * * 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 * * 你可以假设除了整数 0 之外,这个整数不会以零开头。 * * 示例 1: * * 输入: [1,2,3] * 输出: [1,2,4] * 解释: 输入数组表示数字 123。 * * * 示例 2: * * 输入: [4,3,2,1] * 输出: [4,3,2,2] * 解释: 输入数组表示数字 4321。 * * */ // @lc code=start /** * @param {number[]} digits * @return {number[]} */ var plusOne = function(digits) { digits[digits.length - 1] = digits[digits.length - 1] + 1 for (let i = digits.length - 1; i >= 0; i--) { if (digits[i] !== 10) return digits digits[i] = 0 if (i > 0) { digits[i - 1] = digits[i - 1] + 1 } else { digits.splice(0, 0, 1) } } return digits } // @lc code=end ================================================ FILE: src/leetcode/67.二进制求和.js ================================================ /* * @lc app=leetcode.cn id=67 lang=javascript * * [67] 二进制求和 * * https://leetcode-cn.com/problems/add-binary/description/ * * algorithms * Easy (51.70%) * Likes: 283 * Dislikes: 0 * Total Accepted: 56.3K * Total Submissions: 108.5K * Testcase Example: '"11"\n"1"' * * 给定两个二进制字符串,返回他们的和(用二进制表示)。 * * 输入为非空字符串且只包含数字 1 和 0。 * * 示例 1: * * 输入: a = "11", b = "1" * 输出: "100" * * 示例 2: * * 输入: a = "1010", b = "1011" * 输出: "10101" * */ // @lc code=start /** * @param {string} a * @param {string} b * @return {string} */ var addBinary = function(a, b) { // return (parseInt(a, 2) + parseInt(b, 2)).toString(2) } addBinary( '10100000100100110110010000010101111011011001101110111111111101000000101111001110001111100001101', '110101001011101110001111100110001010100001101011101010000011011011001011101111001100000011011110011' ) // @lc code=end ================================================ FILE: src/leetcode/69.x-的平方根.js ================================================ /* * @lc app=leetcode.cn id=69 lang=javascript * * [69] x 的平方根 * * https://leetcode-cn.com/problems/sqrtx/description/ * * algorithms * Easy (37.32%) * Likes: 277 * Dislikes: 0 * Total Accepted: 83.8K * Total Submissions: 224.3K * Testcase Example: '4' * * 实现 int sqrt(int x) 函数。 * * 计算并返回 x 的平方根,其中 x 是非负整数。 * * 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 * * 示例 1: * * 输入: 4 * 输出: 2 * * * 示例 2: * * 输入: 8 * 输出: 2 * 说明: 8 的平方根是 2.82842..., * 由于返回类型是整数,小数部分将被舍去。 * * */ // @lc code=start /** * @param {number} x * @return {number} */ var mySqrt = function(x) { if (x === 0) return 0 if (x <= 3) return 1 if (x <= 5) return 2 for (let i = 2; i <= x / 2; i++) { if (i * i > x) { return i - 1 } } } // @lc code=end ================================================ FILE: src/leetcode/7.整数反转.js ================================================ /* * @lc app=leetcode.cn id=7 lang=javascript * * [7] 整数反转 */ // @lc code=start /** * @param {number} x * @return {number} */ var reverse = function(x) { var max = Math.pow(2, 31) - 1 var min = -Math.pow(2, 31) var temp = x > 0 ? x : -1 * x var stack = [] var result = 0 while (temp > 0) { stack.push(Math.floor(temp % 10)) temp = Math.floor(temp / 10) } temp = 1 var i = stack.length while (i-- > 0) { result = result + stack[i] * temp temp = temp * 10 } if (x > 0) { return result <= max ? result : 0 } else { return -result >= min ? -result : 0 } } // @lc code=end ================================================ FILE: src/leetcode/9.回文数.js ================================================ /* * @lc app=leetcode.cn id=9 lang=javascript * * [9] 回文数 */ // @lc code=start /** * @param {number} x * @return {boolean} */ var isPalindrome = function(x) { var str = String(x) return ( str .split('') .reverse() .join('') === str ) } // @lc code=end ================================================ FILE: src/linux/process_manage.sh ================================================ # sh # top # ps # 查找进程 ps -fA | grep [name] ================================================ FILE: src/node/api-test/image.js ================================================ const fetch = require('node-fetch'); const FormData = require('form-data'); const fs = require('fs'); const path = require('path'); const request = require('request'); var dirPath = path.join(__dirname, "file"); if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath); console.log("文件夹创建成功"); } else { console.log("文件夹已存在"); } let stream = fs.createWriteStream(dirPath + 'aa.jpg'); request(url).pipe(stream).on("close", function (err) { console.log("文件下载完毕"); }); const const form = new FormData(); form.append('checkValue', '3f1f3fb5b7fa79d4cdf9aaaea1558eb5322bfd7f0f8f09d6f37fd93154ec71be'); form.append('jsonData', '{"agentId":"310000015002423502","memberId":310000016002426182,"photoType":"06","reqSerialNum":1211}'); form.append('picture', file); (async () => { const response = await fetch('https://nsposf.cloudpnr.com/nsposfweb/webB9002/uploadWebMerPic', {method: 'POST', body: form}); const json = await response.json(); console.log(json) })(); // OR, using custom headers // NOTE: getHeaders() is non-standard API // const options = { // method: 'POST', // body: form, // headers: form.getHeaders() // }; // (async () => { // const response = await fetch('https://httpbin.org/post', options); // const json = await response.json(); // console.log(json) // })(); ================================================ FILE: src/node/app/index.js ================================================ const server = require('./server'); const router = require('./router'); const requestHandles = require('./requestHandles'); const handles = {}; handles['/'] = requestHandles.start; handles['/upload'] = requestHandles.upload; handles['/show'] = requestHandles.show; server.createServer(router.route, handles); ================================================ FILE: src/node/app/requestHandles.js ================================================ // const exec = require('child_process').exec; // const querystring = require('querystring'); const fs = require('fs'); const formidable = require('formidable'); function start(response, request) { console.log('start ok!') var body = ''+ ''+ ''+ ''+ ''+ '
        '+ ''+ ''+ '
        '+ ''+ ''; response.writeHead(200, {"Content-Type": "text/html"}); response.write(body); response.end() } function upload(response, request) { console.log('upload ok!') const form = new formidable.IncomingForm(); form.parse(request, function(error, fields, files) { try { fs.renameSync(files.upload.path, '/tmp/test.png') response.writeHead(200, {"Content-Type": "text/html"}); response.write('upload ok!'); response.write(''); response.end() } catch(e) { response.writeHead(500, {"Content-Type": "text/plain"}); response.write(error); response.end() } }) } function show(response, request) { console.log('show ok!'); fs.readFile('/tmp/test.png', 'binary', function(error, file) { if (error) { response.writeHead(500, {"Content-Type": "text/plain"}); response.write(error, '/n'); response.end() } else { response.writeHead(200, {"Content-Type": "image/jpeg"}); response.write(file, 'binary'); response.end() } }) } exports.start = start; exports.upload = upload; exports.show = show; ================================================ FILE: src/node/app/router.js ================================================ function route(pathname, handles, response, request) { console.log(pathname); if (typeof handles[pathname] === 'function') { return handles[pathname](response, request); } else { response.writeHead(200, {'Content-Type': 'text/plain'}); response.write('404 not found!'); response.end() } } exports.route = route; ================================================ FILE: src/node/app/server.js ================================================ const http = require('http'); const url = require('url'); function createServer(route, handles) { http.createServer(function(request, response) { const pathname = url.parse(request.url).pathname; route(pathname, handles, response, request); }).listen(8888); console.log('server ok!') } exports.createServer = createServer; ================================================ FILE: src/node/file/file-download.js ================================================ const fs = require('fs'); const path = require('path'); const request = require('request'); const url = ''; // fs.readFile(url, (err, data) => { // if (err) { // console.log(err) // } // console.log(data.toString()); // }) var dirPath = path.join(__dirname, "file"); if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath); console.log("文件夹创建成功"); } else { console.log("文件夹已存在"); } let stream = fs.createWriteStream(dirPath + 'aa.jpg'); request(url).pipe(stream).on("close", function (err) { console.log("文件下载完毕"); }); ================================================ FILE: src/node/file/file-read.js ================================================ const fs = require('fs'); const path = require('path'); const dirPath = path.join(__dirname, "file"); const url = dirPath + 'fileaa.js'; fs.readFileSync(dirPath + 'aa.js', (err, data) => { console.log(data.toString()) }) ================================================ FILE: src/node/node-fetch/index.js ================================================ const fetch = require('node-fetch'); const FormData = require('form-data'); const form = new FormData(); form.append('a', 1); (async () => { const response = await fetch('https://httpbin.org/post', {method: 'POST', body: form}); const json = await response.json(); console.log(json) })(); // OR, using custom headers // NOTE: getHeaders() is non-standard API const options = { method: 'POST', body: form, headers: form.getHeaders() }; (async () => { const response = await fetch('https://httpbin.org/post', options); const json = await response.json(); console.log(json) })(); ================================================ FILE: src/question/interserction.js ================================================ function set_intersection(set1, set2) { if (set1.size > set2.size) { return set_intersection(set2, set1); } const intersection = new Set(); for (const num of set1) { if (set2.has(num)) { intersection.add(num); } } return [...intersection]; } function intersection(nums1, nums2) { const set1 = new Set(nums1); const set2 = new Set(nums2); return set_intersection(set1, set2); } console.log(intersection([1, 2, 4], [2, 3])); ================================================ FILE: src/react/app/.gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies /node_modules /.pnp .pnp.js # testing /coverage # production /build # misc .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* ================================================ FILE: src/react/app/README.md ================================================ This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). ## Available Scripts In the project directory, you can run: ### `yarn start` Runs the app in the development mode.
        Open [http://localhost:3000](http://localhost:3000) to view it in the browser. The page will reload if you make edits.
        You will also see any lint errors in the console. ### `yarn test` Launches the test runner in the interactive watch mode.
        See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. ### `yarn build` Builds the app for production to the `build` folder.
        It correctly bundles React in production mode and optimizes the build for the best performance. The build is minified and the filenames include the hashes.
        Your app is ready to be deployed! See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. ### `yarn eject` **Note: this is a one-way operation. Once you `eject`, you can’t go back!** If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. ## Learn More You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). To learn React, check out the [React documentation](https://reactjs.org/). ### Code Splitting This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting ### Analyzing the Bundle Size This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size ### Making a Progressive Web App This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app ### Advanced Configuration This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration ### Deployment This section has moved here: https://facebook.github.io/create-react-app/docs/deployment ### `yarn build` fails to minify This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify ================================================ FILE: src/react/app/package.json ================================================ { "name": "app", "version": "0.1.0", "private": true, "dependencies": { "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", "antd": "^4.2.0", "antd-mobile": "^2.3.1", "ky-universal": "^0.7.0", "node-sass": "^4.14.1", "react": "^16.13.1", "react-dom": "^16.13.1", "react-router": "^5.1.2", "react-router-dom": "^5.1.2", "react-scripts": "3.4.1" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": "react-app" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } } ================================================ FILE: src/react/app/public/index.html ================================================ React App
        ================================================ FILE: src/react/app/public/manifest.json ================================================ { "short_name": "React App", "name": "Create React App Sample", "icons": [ { "src": "favicon.ico", "sizes": "64x64 32x32 24x24 16x16", "type": "image/x-icon" }, { "src": "logo192.png", "type": "image/png", "sizes": "192x192" }, { "src": "logo512.png", "type": "image/png", "sizes": "512x512" } ], "start_url": ".", "display": "standalone", "theme_color": "#000000", "background_color": "#ffffff" } ================================================ FILE: src/react/app/public/robots.txt ================================================ # https://www.robotstxt.org/robotstxt.html User-agent: * Disallow: ================================================ FILE: src/react/app/src/antd/searchDemo.js ================================================ import React from 'react' import { Input } from 'antd' export default function ImagePickerDemo() { onChange = () => { console.log() } render() { return ( ) } } ================================================ FILE: src/react/app/src/antd/upload.js ================================================ import React from 'react' import { Upload } from 'antd' import ky from 'ky-universal'; const forge = require('node-forge'); export default class UploadDemo extends React.Component { async onImageClick(files) { const FormData = require('form-data'); const formData = new FormData(); const params = { reqSerialNum: '1212', memberId: '310000016002426182', agentId: '310000015002423502', photoType: '06', }; const jsonData = JSON.stringify(params); const checkValue = forge.md.sha256.create().update(`${jsonData}chinapnr`).digest().toHex() formData.append('file', files[0].file); formData.append('jsonData', jsonData); formData.append('checkValue', checkValue); const postUrl = `https://nsposf.cloudpnr.com/nsposfweb/webB9002/uploadWebMerPic`; try { const resp = await ky.post(postUrl, { body: formData, }); const respData = resp.json(); return { pictureID: respData.body.pictureID, }; } catch (error) { console.log(error); } } render() { return ( ) } } ================================================ FILE: src/react/app/src/antd-mobile/input.js ================================================ import React from 'react'; import './steps-demo.scss' import { InputItem } from 'antd-mobile'; export default InputItem() { state = { value: '' }; render() { return
        } } ================================================ FILE: src/react/app/src/antd-mobile/picker-demo.js ================================================ import React from 'react'; import { Picker, List } from 'antd-mobile'; const district = [{ label: '浙江省', value: '1', children: [ { label: '杭州市', value: '11', children: [ { label: '西湖区', value: '111' } ] }] }, { label: '北京市', value: '2', children: [ { label: '北京市', value: '21', children: [ { label: '朝阳区', value: '211' } ] } ] }] const district2 = [{ label: '浙江省使得丰富的水分', value: '1', children: [ { label: '杭州市水电费水电费', value: '11' }] }, { label: '北京市', value: '2', children: [ { label: '北京市', value: '21' } ] }] const district3 = [{ label: '一二三四五六七八九十一二三四五六七八九十一', value: '1' }] export default class AMPicker extends React.Component { render() { return
        12 Multiple & cascader
        } } ================================================ FILE: src/react/app/src/antd-mobile/steps-demo.js ================================================ import React from 'react'; import './steps-demo.scss' import { Steps } from 'antd-mobile' const Step = Steps.Step; export default class StepsDemo extends React.Component { render() { return
        } } ================================================ FILE: src/react/app/src/antd-mobile/steps-demo.scss ================================================ .am-steps-item-finish .am-steps-item-tail:after { top: -6px; height: calc(100% + 10px); background-color: #888888; } ================================================ FILE: src/react/app/src/assets/font/PingFangSC-Regular.fft ================================================ [File too large to display: 13.4 MB] ================================================ FILE: src/react/app/src/assets/scss/font.scss ================================================ /*声明 WebFont*/ @font-face { font-family: 'PingFangSC'; src: url('../font/PingFangSC-Regular.ttf') format('truetype'); font-weight: normal; font-style: normal; } ================================================ FILE: src/react/app/src/components/count-down.js ================================================ import React from 'react'; const { useState, useEffect } = React; export default function CountDown(props) { const [timecount, clearTimeCount] = useState(60); useEffect(() => { const timer = setTimeout(() => { clearTimeCount(timecount - 1) }, 1000); if (timecount <= 0) { clearTimeout(timer); } }); return
        {timecount}
        } ================================================ FILE: src/react/app/src/components/steps-hooks.js ================================================ import React from 'react'; import './steps.scss' const showMax = 3 const { useState } = React; const StepHooks = (props) => { const {options, expand} = props; const [optionsDisplay, setOptionsDisplay] = useState(options); const [expandStatus, setExpandStatus] = useState(expand); const hidenOptions = expandStatus && options.slice(0, showMax); const change = () => { setExpandStatus(!expandStatus) setOptionsDisplay(hidenOptions) } return (
        { optionsDisplay.map((item, index, arr) => (
        { arr.length > index + 1 &&
        }
        {item.title}
        {item.description}
        {item.datetime}
        )) } { expandStatus &&
        收起
        }
        ) } export default StepHooks; ================================================ FILE: src/react/app/src/components/steps.js ================================================ import React from 'react'; import './steps.scss' const dataSource = [ { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理额外任务而温热温热我认为儿惹我认为热舞但是发生地方', datetime: '2014-10-11 16:46' }, { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理因收方客户拒收快递,待进一步处理额外任务而温热温热我认为儿惹我认为热舞但是发生地方因收方客户拒收快递,待进一步处理因收方客户拒收快递,待进一步处理额外任务而温热温热我认为儿惹我认为热舞但是发生地方', datetime: '2014-10-11 16:46' }, { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理', datetime: '2014-10-11 16:46' }, { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理', datetime: '2014-10-11 16:46' }, { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理', datetime: '2014-10-11 16:46' }, { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理', datetime: '2014-10-11 16:46' }, { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理', datetime: '2014-10-11 16:46' }, { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理', datetime: '2014-10-11 16:46' } ] const showMax = 3 export default class Steps extends React.Component { constructor(props) { super(props) this.state = { data: dataSource, showBtn: false } } componentDidMount() { if (dataSource.length > showMax) { this.setState({ data: dataSource.slice(0, showMax), showBtn: true }) } } handleClickExpand = () => { this.setState({ data: dataSource, showBtn: false }) } handleClickHide = () => { if (dataSource.length > 3) { this.setState({ data: dataSource.slice(0, showMax), showBtn: true }) } } render() { return (
        { this.state.data.map((item, index, arr) => (
        { arr.length > index + 1 &&
        }
        {item.title}
        {item.description}
        {item.datetime}
        )) } { this.state.showBtn ?
        展开
        :
        收起
        }
        ) } } ================================================ FILE: src/react/app/src/components/steps.scss ================================================ .steps { font-size: 14px; &-item { position: relative; display: block; flex: 1 1; &-icon, &-icon--active { top: 5px; z-index: 1; position: absolute; border-radius: 50%; margin-left: 18px; width: 5px; height: 5px; background-color: #dddddd; } &-icon--active { margin-left: 17px; width: 7px; height: 7px; background-color: #888888; } &-line { position: absolute; top: 5px; margin-left: 20px; height: 100%; width: 1px; display: inline-block; background-color: #dddddd; &::after { content: ''; height: 100%; width: 1px; display: inline-block; } } &-content { position: relative; display: inline-block; margin-left: 35px; &-title { color: #000000; font-size: 14px; } &-description { overflow: hidden; font-size: 12px; color: #888888; } &-datetime { margin-top: 7.5px; font-size: 12px; color: #888888; } } } &-expand { text-align: center; clear: both; zoom: 1; } } ================================================ FILE: src/react/app/src/examples/steps-demo.js ================================================ import StepHooks from '../components/steps-hooks' import React from 'react'; const options = [ { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理额外任务而温热温热我认为儿惹我认为热舞但是发生地方', datetime: '2014-10-11 16:46' }, { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理因收方客户拒收快递,待进一步处理额外任务而温热温热我认为儿惹我认为热舞但是发生地方因收方客户拒收快递,待进一步处理因收方客户拒收快递,待进一步处理额外任务而温热温热我认为儿惹我认为热舞但是发生地方', datetime: '2014-10-11 16:46' }, { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理', datetime: '2014-10-11 16:46' }, { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理', datetime: '2014-10-11 16:46' }, { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理', datetime: '2014-10-11 16:46' }, { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理', datetime: '2014-10-11 16:46' }, { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理', datetime: '2014-10-11 16:46' }, { title: '快递签收不成功', description: '因收方客户拒收快递,待进一步处理', datetime: '2014-10-11 16:46' } ] export default function stepsDemo() { return
        } ================================================ FILE: src/react/app/src/font/pingfangsc-demo.js ================================================ import React from 'react' export default function PingFangScDemo() { return (
        测试test 邵锁
        测试test 邵锁
        ) } ================================================ FILE: src/react/app/src/index.js ================================================ import React from 'react'; import ReactDOM from 'react-dom'; import RouterDOM from './router/index' import { BrowserRouter as Router, Route} from 'react-router-dom'; import * as serviceWorker from './serviceWorker'; import 'antd-mobile/dist/antd-mobile.css'; ReactDOM.render( , document.getElementById('root') ); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: https://bit.ly/CRA-PWA serviceWorker.unregister(); ================================================ FILE: src/react/app/src/paratice/hook.js ================================================ import React, { useState, useEffect } from 'react'; export default class Hook extends React.Component { render() { return
        } } // useState & useEffect // 它类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并 function HookExample() { const [count, setCount] = useState(0); useEffect(() => { document.title = `you clicked ${count}`; }) return

        {count}

        } // todo 自定义hook ================================================ FILE: src/react/app/src/paratice/index.css ================================================ body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } ================================================ FILE: src/react/app/src/paratice/index.js ================================================ import React, { Suspense } from 'react'; import './index.css'; import logo from '../images/logo.svg' import Hook from './hook'; const name = 'shaosuo' const numbers = [2, 2, 3, 4, 5] const nameVisiable = false function filterShao(str) { return str.replace('shao', ''); } // 函数组件 & 条件渲染 & 列表渲染 // props 只读 function CreatEl(props) { if (nameVisiable) { return

        {filterShao(name)} luck!

        } return (

        {props.name} ok

        {props.name === 'shaosuo' && very good!} {props.name === 'shaosuo' ? very good! : null} {numbers.map((item, index) => (
      • {item}
      • ))} 123
        ) } // 类组件 // 不能直接修改state // setState 会合并成一个调用,可能异步更新 class Clock extends React.Component { constructor(props) { super(props); this.state = { date: new Date() }; } componentDidMount() { this.timer = setInterval(() => this.tick(), 1000); } componentWillUnmount() { clearInterval(this.timer) } tick() { this.setState({ date: new Date() }) } render() { return

        {this.state.date.toLocaleTimeString()}

        } } // 表单 & 受控组件 class FormDemo extends React.Component { constructor(props) { super(props) this.state = { name: '', selected: 1, file: '' } } handleNameChange = (event) => { this.setState({ name: event.target.value }) } handleSelectChange = (event) => { // todo: not immediately change this.setState({ selected: event.target.value }) // this.setState((state) => ({ // selected: state.selected // })) // console.log(event.target.value) } handleSubmit = (event) => { event.preventDefault(); } render() { const options = [{ id: 1, name: 'apple' }, { id: 2, name: 'banana' }] return
        {this.state.name}
        {this.state.selected}
        {this.state.file}
        } } // 事件处理 class EventHandles extends React.Component { constructor() { super() this.state = { count: 1 } } handleClick = (e, id) => { // console.log(e.target); this.setState({ count: this.state.count + 1 }) } render() { return } } // 状态提升 // 共享状态提升到父组件 // 自组件 input 中 props 来接管 state // 通过 props 将事件调用函数传递给自组件,分别处理改变 function BoilingVerdict(props) { if (props.celsius >= 100) { return

        水沸腾!

        } return

        水不会沸腾!

        } const modeNames = { c: 'Celsius', f: 'Fahreheit' }; class TemperatureInput extends React.Component { constructor(props) { super(props) this.state = { temperature: '' } } handleChange = (e) => { this.props.onTemperatureChange(e.target.value) } render() { const temperature = this.props.temperature const mode = this.props.mode return

        {modeNames[mode]} 温度

        } } class Calculator extends React.Component { constructor(props) { super(props) this.state = { mode: '', temperature: '' } } handleCelChange = (temperature) => { this.setState({ mode: 'c', temperature: temperature }) } handleFahChange = (temperature) => { this.setState({ mode: 'f', temperature: temperature }) } render() { const mode = this.state.mode; const temperature = this.state.temperature; const celsius = mode === 'f' ? tryConvert(temperature, toCelsius) : temperature; const fahrenheit = mode === 'c' ? tryConvert(temperature, toFahrenheit) : temperature; return
        } } function toFahrenheit(fahrenheit) { return (fahrenheit - 32) * 5 / 9; } function toCelsius(celsius) { return celsius * 9 / 5 + 32; } function tryConvert(temperature, convert) { const input = parseFloat(temperature); if (Number.isNaN(input)) { return ''; } const output = convert(input); const rounded = Math.round(output * 1000) / 1000; return rounded; } // 组合组件 function Child() { return

        I am child!

        } // 特例关系 function ComposeCompontent() { return } // 包含关系 function PropsComponent(props) { return
        good {props.child}
        } // 代码分割 // 动态引入组件 渲染常规组件一样处理动态引入 const LasyComponent = React.lazy(() => import('./lasy-compontent')); // context // todo Context.Consumer // todo 动态 Context // todo 在嵌套组件中更新 Context const ThemeContext = React.createContext('light'); class Toolbar extends React.Component { // constructor(props) { // super(props); // } render() { return } } class ThemeButton extends React.Component { render() { return } } class Button extends React.Component { // constructor(props) { // super(props) // } static contextType = ThemeContext; render() { const themes = { light: { textColor: '#000', bgColor: '#eee', }, dark: { textColor: '#eee', bgColor: '#000', } }; const color = themes.hasOwnProperty(this.context) ? themes[this.context] : ''; return
        button
        } } // 错误边界 ErrorBoundary class ErrorBoundary extends React.Component { // constructor(props) { // super(props) // } componentDidCatch(error, errorInfo) { // todo // LogErrorToMyService(error, errorInfo) } render() { return
        {this.props.data}
        } } // todo 高阶组件 export default function App() { return (
        } /> loading...
        }>
        ) } ================================================ FILE: src/react/app/src/paratice/lasy-compontent.js ================================================ import React from 'react'; export default function LasyCompontent() { return

        lazy import

        ; } ================================================ FILE: src/react/app/src/redux.js ================================================ ================================================ FILE: src/react/app/src/router/index.js ================================================ import React from 'react'; import { HashRouter as Router, Route, Link } from 'react-router-dom'; import './index.scss'; import App from '../paratice'; import Steps from '../examples/steps-demo'; import StepsHooks from '../components/steps-hooks'; import AMSteps from '../antd-mobile/steps-demo'; import AMImagePicker from '../antd-mobile/image-picker-demo'; // import AMImagePicker from '../antd/image-picker-demo'; import UploadDemo from '../antd/upload'; import InputDemo from '../antd-mobile/input'; import CountDown from '../components/count-down'; import FontDemo from '../font/pingfangsc-demo'; export default function RouterDOM() { return (
        • 相关练习
        • 相关练习
        • antd steps 组件
        • steps 组件
        • steps 函数组件
        • image-picker 组件
        • upload 组件
        • picker 组件
        • input 组件
        • count-down组件
        ) } ================================================ FILE: src/react/app/src/router/index.scss ================================================ .menu { width: 370px; overflow: hidden; &__item { color: #000; padding: 8px; display: inline-block; height: 24px; line-height: 24px; // width: 100px; list-style: none; } } ================================================ FILE: src/react/app/src/serviceWorker.js ================================================ // This optional code is used to register a service worker. // register() is not called by default. // This lets the app load faster on subsequent visits in production, and gives // it offline capabilities. However, it also means that developers (and users) // will only see deployed updates on subsequent visits to a page, after all the // existing tabs open on the page have been closed, since previously cached // resources are updated in the background. // To learn more about the benefits of this model and instructions on how to // opt-in, read https://bit.ly/CRA-PWA const isLocalhost = Boolean( window.location.hostname === 'localhost' || // [::1] is the IPv6 localhost address. window.location.hostname === '[::1]' || // 127.0.0.0/8 are considered localhost for IPv4. window.location.hostname.match( /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ ) ); export function register(config) { if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { // The URL constructor is available in all browsers that support SW. const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); if (publicUrl.origin !== window.location.origin) { // Our service worker won't work if PUBLIC_URL is on a different origin // from what our page is served on. This might happen if a CDN is used to // serve assets; see https://github.com/facebook/create-react-app/issues/2374 return; } window.addEventListener('load', () => { const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; if (isLocalhost) { // This is running on localhost. Let's check if a service worker still exists or not. checkValidServiceWorker(swUrl, config); // Add some additional logging to localhost, pointing developers to the // service worker/PWA documentation. navigator.serviceWorker.ready.then(() => { console.log( 'This web app is being served cache-first by a service ' + 'worker. To learn more, visit https://bit.ly/CRA-PWA' ); }); } else { // Is not localhost. Just register service worker registerValidSW(swUrl, config); } }); } } function registerValidSW(swUrl, config) { navigator.serviceWorker .register(swUrl) .then(registration => { registration.onupdatefound = () => { const installingWorker = registration.installing; if (installingWorker == null) { return; } installingWorker.onstatechange = () => { if (installingWorker.state === 'installed') { if (navigator.serviceWorker.controller) { // At this point, the updated precached content has been fetched, // but the previous service worker will still serve the older // content until all client tabs are closed. console.log( 'New content is available and will be used when all ' + 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' ); // Execute callback if (config && config.onUpdate) { config.onUpdate(registration); } } else { // At this point, everything has been precached. // It's the perfect time to display a // "Content is cached for offline use." message. console.log('Content is cached for offline use.'); // Execute callback if (config && config.onSuccess) { config.onSuccess(registration); } } } }; }; }) .catch(error => { console.error('Error during service worker registration:', error); }); } function checkValidServiceWorker(swUrl, config) { // Check if the service worker can be found. If it can't reload the page. fetch(swUrl, { headers: { 'Service-Worker': 'script' }, }) .then(response => { // Ensure service worker exists, and that we really are getting a JS file. const contentType = response.headers.get('content-type'); if ( response.status === 404 || (contentType != null && contentType.indexOf('javascript') === -1) ) { // No service worker found. Probably a different app. Reload the page. navigator.serviceWorker.ready.then(registration => { registration.unregister().then(() => { window.location.reload(); }); }); } else { // Service worker found. Proceed as normal. registerValidSW(swUrl, config); } }) .catch(() => { console.log( 'No internet connection found. App is running in offline mode.' ); }); } export function unregister() { if ('serviceWorker' in navigator) { navigator.serviceWorker.ready .then(registration => { registration.unregister(); }) .catch(error => { console.error(error.message); }); } } ================================================ FILE: src/react/app/src/setupTests.js ================================================ // jest-dom adds custom jest matchers for asserting on DOM nodes. // allows you to do things like: // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom import '@testing-library/jest-dom/extend-expect'; ================================================ FILE: src/react/demo.html ================================================ Document
        ================================================ FILE: src/react/demo.jsx ================================================ ================================================ FILE: src/shell/image_filter.sh ================================================ #! /bin/bash # use some rules to filter image files in dir # some rules: # 1. width equal height, image size max 100k # 2. width not equal height, image size max 500k # 3. width not equal height, width should equal 1125px, height equal 744px # gen_td() { # return $1 # } html_gen='' function read_dir() { rootTmpPath=$1 OLD_IFS="${IFS}" IFS=$'\n' for file in `ls $1` do if [ -d $1"/"$file ];then read_dir $1"/"$file continue; fi # echo "------------------------------------start--------------------------------------------\t" # echo $1"/"$file\t html_gen=$html_gen'' IFS="${OLD_IFS}" tmpFile=$(echo $(file $1"/"$file)) # echo $tmpFile x=0 y=0 result='' pixic='' pixic_array='' if [ $(expr "$file" : '.*\(\.[j|J][p|P][g|G]\)') ] || [ $(expr "$file" : '.*\(\.[j|J][P|p][E|e][G|g]\)') ]; then result=$(expr "$tmpFile" : '.*\( [0-9]*\x[0-9]*, components\).*') pixic=${result%, components} # echo $pixic # # echo ${OLD_IFS} # pixic_array=${pixic//x/ } IFS="x" pixic_array=($pixic) IFS="${OLD_IFS}" # echo ${#pixic_array[@]} # echo ${pixic_array[0]} # echo ${pixic_array[1]} # echo $pixic_array # echo ${pixic_array[0]}${pixic_array[1]} # for (( i=0 ; i < ${#pixic_array[@] + 1} ; i++ )) # do # echo $i ${pixic_array[i]} # if [ $i -eq 0 ]; then # x=${pixic_array[i]} # fi # if [ $i -eq 1 ]; then # y=${pixic_array[i]} # fi # # x=$pixic # done x=${pixic_array[0]} y=${pixic_array[1]} fi if [ $(expr "$file" : '.*\(\.[p|P][n|N][g|G]\)') ]; then result=$(expr "$tmpFile" : '.*\(, [0-9]* x [0-9]*\).*') IFS="x" pixic=${result#, } pixic_array=($pixic) IFS="${OLD_IFS}" x=${pixic_array[0]} y=${pixic_array[1]} fi size=$(ls -l $1"/"$file | awk '{print $5}') x=`eval echo $x` y=`eval echo $y` # rootTmpPath=$($rootTmpPath$1) # echo $rootTmpPath, $1 # echo $x-$y if [ ! $x ] || [ ! $y ]; then # echo -e "像素缺失 $1/$file: 像素: $x x $y\033[0m" continue fi if [ ! $size ]; then # echo -e "\033[31m 图片大小缺失 $1/$file: 像素: $x x $y \033[0m" continue fi main="\033[32m $rootTmpPath\t $file \t $x x $y \t $[$size/1000]k \033[0m" # echo -e $main html_size="" html_px="" if [ $x -eq $y ] && [ $size -gt 100000 ];then # echo -e "\033[31m Warn: 正方形,大小 $size 字节即 $[$size/1000]k超过100k \033[0m" html_size="" fi if [ $x -eq $y ] && ([ $x -ne 150 ] || [ $y -ne 150 ]);then # echo -e "\033[31m Warn: 正方形,尺寸不为150 * 150 \033[0m" html_px="" # html_gen="$html_gen" fi if [ $x -ne $y ] && ([ $x -ne 1125 ] || [ $y -ne 744 ]);then # echo -e "\033[31m Warn: 长方形尺寸不为1125x744 图片不合适 \033[0m" html_px="" fi # if [ $x -ne $y ] && ([ $[$x * 744] -ne $[$y * 1125] ]);then # echo -e "\033[31m Warn: 长方形比例也不为 1125:744,图片不合适 \033[0m" # fi if [ $x -ne $y ] && [ $size -gt 500000 ];then # echo -e "\t \033[31m Warn: 大小$size 字节即$[$size/1000]k超出500K大小 \033[0m" html_size="" fi html_gen="$html_gen$html_px$html_size" done } echo 生成报表中... read_dir $1 result_0=`read_dir $1`; html_gen=$html_gen'
        图片目录图片名图片尺寸图片大小
        $[$size/1000]k $x x $y
        $[$size/1000]k 超过100k
        $x x $y 尺寸不合适
        不为150*150
        $x x $y 尺寸不合适
        $[$size/1000]k 超过500k
        $rootTmpPath$file
        ' echo -e "$html_gen" > $1图片扫描包.html echo -e "\033[32m生成报告成功! 请查看文件$1.html \033[0m" ================================================ FILE: src/typescript/js/class-demo.js ================================================ "use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; // 创建 var Person = /** @class */ (function () { function Person(name) { this.name = name; } Person.prototype.run = function () { return this.name + 'run'; }; return Person; }()); var somePerson = new Person('shaosuo'); somePerson.run(); // 继承 var Child = /** @class */ (function (_super) { __extends(Child, _super); function Child(name) { return _super.call(this, name) || this; } Child.prototype.study = function () { return this.name + 'study'; }; return Child; }(Person)); var child = new Child('shaosuo'); child.study(); // 静态属性和方法 // 创建 var Person2 = /** @class */ (function () { function Person2(name) { this.name = name; } Person2.active = function () { // 不能调用非静态属性和方法 return this.type + 'active'; }; Person2.prototype.run = function () { return this.name + 'run'; }; Person2.type = 'animal'; Person2 = __decorate([], Person2); return Person2; }()); console.log(Person2.active()); // 多态,继承 // 抽象类 // 不能被实例,含有抽象方法,子类不含抽象方法的可以被实例。子类必须要实现抽象方法 var Animal = /** @class */ (function () { function Animal() { } Animal.prototype.run = function () { return 'run'; }; return Animal; }()); var Cat = /** @class */ (function (_super) { __extends(Cat, _super); function Cat() { return _super !== null && _super.apply(this, arguments) || this; } Cat.prototype.eat = function () { return 'eat fish'; }; return Cat; }(Animal)); var cat = new Cat(); cat.eat(); ================================================ FILE: src/typescript/js/decorators-demo.js ================================================ "use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; // 装饰器函数 function Age(v) { return function (constructor) { var PersonAge = /** @class */ (function (_super) { __extends(PersonAge, _super); function PersonAge() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.age = v; return _this; } return PersonAge; }(constructor)); return PersonAge; }; } var CatCat = /** @class */ (function () { function CatCat() { this.name = 'cat'; } CatCat = __decorate([ Age(1) ], CatCat); return CatCat; }()); var catcat = new CatCat(); console.log(catcat); ================================================ FILE: src/typescript/js/demo.js ================================================ "use strict"; console.log('测试'); ================================================ FILE: src/typescript/js/fn-demo.js ================================================ "use strict"; function add(num1, num2) { return num1 + num2; } var mob = function (num1, num2) { return num1 - num2; }; // 可选参数必须在最后 var personInfo = function (name, age) { if (!age) { return name; } return name + age; }; // 默认参数 var personInfo2 = function (name, age) { if (name === void 0) { name = 'shaosuo'; } if (!age) { return name; } return name + age; }; // 剩余参数 var personInfo3 = function (name, age) { if (name === void 0) { name = 'shaosuo'; } var result = []; for (var _i = 2; _i < arguments.length; _i++) { result[_i - 2] = arguments[_i]; } if (!age) { return name; } return name + age; }; // 函数重载 同名不同参数类型 // 箭头函数与es6一样 ================================================ FILE: src/typescript/js/function-demo.js ================================================ "use strict"; function add(num1, num2) { return num1 + num2; } var mob = function (num1, num2) { return num1 - num2; }; // 可选参数必须在最后 var personInfo = function (name, age) { if (!age) { return name; } return name + age; }; // 默认参数 var personInfo2 = function (name, age) { if (name === void 0) { name = 'shaosuo'; } if (!age) { return name; } return name + age; }; // 剩余参数 var personInfo3 = function (name, age) { if (name === void 0) { name = 'shaosuo'; } var result = []; for (var _i = 2; _i < arguments.length; _i++) { result[_i - 2] = arguments[_i]; } if (!age) { return name; } return name + age; }; // 函数重载 同名不同参数类型 // 箭头函数与es6一样 ================================================ FILE: src/typescript/js/generics-demo.js ================================================ "use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; // 范型函数 function getData1(val) { return val; } function getData2(val) { return val; } function getData(val) { return val; } getData(123); // 范型类 var PersonAny = /** @class */ (function () { function PersonAny(name, age) { this.name = name; this.age = age; } PersonAny.prototype.run = function (val) { return val; }; ; return PersonAny; }()); PersonAny = __decorate([], PersonAny); var somePerson1 = new PersonAny('shao', '12'); var PersonClassAny = /** @class */ (function () { function PersonClassAny(name) { this.name = name; } PersonClassAny.prototype.run = function (val) { return val + '...'; }; return PersonClassAny; }()); var somePerson2 = new PersonClassAny('shaosuo'); ================================================ FILE: src/typescript/js/interface-demo.js ================================================ "use strict"; var somePersonInfo = { name: 'shao', age: 12, gender: 'man' }; function ajax(config) { var xhr = new XMLHttpRequest; xhr.open(config.type, config.url, true); xhr.send(config.data); } var run = function (key, value) { return ''; }; var users = []; var users2 = {}; var PersonClass = /** @class */ (function () { function PersonClass() { this.name = ''; } PersonClass.prototype.run = function () { return 'run'; }; return PersonClass; }()); var ChildClass = /** @class */ (function () { function ChildClass(name) { this.name = name; } ChildClass.prototype.run = function () { return 'run'; }; ChildClass.prototype.cry = function () { return 'wawwaaw'; }; return ChildClass; }()); ================================================ FILE: src/typescript/js/overload-demo.js ================================================ "use strict"; function overload(a) { return "overload1 test: " + a; } overload(1, 'a'); ================================================ FILE: src/typescript/js/type-advanced-demo.js ================================================ "use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; // 交叉类型 function extend(first, second) { var result = {}; for (var id in first) { result[id] = first[id]; } for (var id in second) { if (!result.hasOwnProperty(id)) { result[id] = second[id]; } } return result; } var PersonIntersect = /** @class */ (function () { function PersonIntersect(name) { this.name = name; } return PersonIntersect; }()); PersonIntersect = __decorate([], PersonIntersect); var ConsoleLoggable = /** @class */ (function () { function ConsoleLoggable() { } ConsoleLoggable.prototype.log = function () { console.log('log'); }; return ConsoleLoggable; }()); var shao = extend(new PersonIntersect('name'), new ConsoleLoggable()); // 联合类型 // 类型守卫 // 类型别名 ================================================ FILE: src/typescript/js/type-demo.js ================================================ "use strict"; var flag = true; var str = 'i am god'; var undefined0 = undefined; var num = undefined; var arr = [1, 3, 4]; var arr2 = [2, 4, 3]; var tuple = ['123', 3434]; var Flag; (function (Flag) { Flag[Flag["success"] = 1] = "success"; Flag[Flag["error"] = 2] = "error"; })(Flag || (Flag = {})); var a; ================================================ FILE: src/typescript/js/type-inference-demo.js ================================================ "use strict"; var ab = '123'; ================================================ FILE: src/typescript/ts/class-demo.ts ================================================ // 创建 class Person { name: string; constructor(name: string) { this.name = name; } run(): string { return this.name + 'run'; } } var somePerson = new Person('shaosuo'); somePerson.run(); // 继承 class Child extends Person { constructor(name: string) { super(name) } study(): string { return this.name + 'study'; } } var child = new Child('shaosuo'); child.study(); // 静态属性和方法 // 创建 class Person2 { name: string; constructor(name: string) { this.name = name; } static type = 'animal'; static active() { // 不能调用非静态属性和方法 return this.type + 'active'; } run(): string { return this.name + 'run'; } } console.log(Person2.active()); // 多态,继承 // 抽象类 // 不能被实例,含有抽象方法,子类不含抽象方法的可以被实例。子类必须要实现抽象方法 abstract class Animal { run(): string { return 'run'; } abstract eat(): string; } class Cat extends Animal { eat(): string { return 'eat fish'; } } var cat = new Cat(); cat.eat(); ================================================ FILE: src/typescript/ts/decorators-demo.ts ================================================ // 装饰器函数 function Age(v: number) { return function (constructor: T): T { class PersonAge extends constructor { age: number = v } return PersonAge; } } @Age(1) class CatCat { name = 'cat'; } var catcat = new CatCat(); console.log(catcat); ================================================ FILE: src/typescript/ts/demo.ts ================================================ console.log('测试'); ================================================ FILE: src/typescript/ts/function-demo.ts ================================================ function add(num1: number, num2: number): number { return num1 + num2; } var mob = (num1: number, num2: number): number => { return num1 - num2; } // 可选参数必须在最后 var personInfo = (name: string, age?: number) => { if (!age) { return name; } return name + age; } // 默认参数 var personInfo2 = (name: string = 'shaosuo', age?: number) => { if (!age) { return name; } return name + age; } // 剩余参数 var personInfo3 = (name: string = 'shaosuo', age: number, ...result: any[]) => { if (!age) { return name; } return name + age; } // 函数重载 同名不同参数类型 // 箭头函数与es6一样 ================================================ FILE: src/typescript/ts/generics-demo.ts ================================================ // 范型函数 function getData1(val: string): string { return val; } function getData2(val: number): number { return val; } function getData(val: T): T { return val; } getData(123); // 范型类 class PersonAny { constructor(name: T, age: T) { this.name = name; this.age = age; } name: T; age: T; run(val: T): T { return val; }; } var somePerson1 = new PersonAny('shao', '12'); // 范型接口 // 属性范型接口 interface PersonInfoAny { (name:T):T; age: string; } interface PersonInfoAny2 { (name: T): T; age: string; } // 类范型接口 interface PersonInterfaceAny { name: T; run(val: T): T; } class PersonClassAny implements PersonInterfaceAny { name: string; constructor(name: string) { this.name = name; } run(val: string) { return val + '...'; } } var somePerson2 = new PersonClassAny('shaosuo'); ================================================ FILE: src/typescript/ts/interface-demo.ts ================================================ // 属性接口 interface PersonInfo { name: string; age: number; gender: string; school?: string; } var somePersonInfo:PersonInfo = { name: 'shao', age: 12, gender: 'man' } // 属性接口封装ajax interface Config { type: string; url: string; data?: string; dataType: string; } function ajax(config: Config) { var xhr = new XMLHttpRequest; xhr.open(config.type, config.url, true); xhr.send(config.data); } // 函数接口 interface kv { (key: string, value: any): string; } var run:kv = (key: string, value: any) => { return ''} // 可索引接口 interface UserArr { [index: number]: string; } interface UserObj { [index: string]: string; } var users: UserArr = []; var users2: UserObj = {}; // 类接口 interface PersonInterface { name: string; run(): string; } class PersonClass implements PersonInterface { name: string; constructor() { this.name = '' } run() { return 'run'; } } // 接口继承 interface ChildInterface extends PersonInterface { cry(): string; } class ChildClass implements ChildInterface { name: string; constructor(name: string) { this.name = name; } run() { return 'run'; } cry() { return 'wawwaaw' } } ================================================ FILE: src/typescript/ts/overload-demo.ts ================================================ function overload(a: number): string; function overload(a: string): string; function overload(a: number, b: string): string; function overload(a: any): string { return `overload1 test: ${a}` } overload(1, 'a') ================================================ FILE: src/typescript/ts/tsconfig.json ================================================ { "compilerOptions": { /* Basic Options */ "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ // "declaration": true, /* Generates corresponding '.d.ts' file. */ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ // "sourceMap": true, /* Generates corresponding '.map' file. */ // "outFile": "./", /* Concatenate and emit output to single file. */ "outDir": "../js", /* Redirect output structure to the directory. */ "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ // "composite": true, /* Enable project compilation */ // "removeComments": true, /* Do not emit comments to output. */ // "noEmit": true, /* Do not emit outputs. */ // "importHelpers": true, /* Import emit helpers from 'tslib'. */ // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ /* Additional Checks */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ /* Module Resolution Options */ // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ /* Source Map Options */ // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ /* Experimental Options */ "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ } } ================================================ FILE: src/typescript/ts/type-advanced-demo.ts ================================================ // 交叉类型 function extend(first: T, second: U): T & U { let result = {}; for(let id in first) { (result)[id] = (first)[id]; } for(let id in second) { if (!(result).hasOwnProperty(id)) { (result)[id] = (second)[id]; } } return result; } class PersonIntersect { constructor(public name: string) {} } interface Loggable { log(): void; } class ConsoleLoggable implements Loggable { log() { console.log('log'); } } var shao = extend(new PersonIntersect('name'), new ConsoleLoggable()); // 联合类型 // 类型守卫 // 类型别名 ================================================ FILE: src/typescript/ts/type-demo.ts ================================================ var flag: boolean = true; var str: string = 'i am god'; var undefined0: undefined = undefined; var num: number | undefined = undefined; var arr: number[] = [1, 3, 4]; var arr2: Array = [2, 4, 3]; var tuple: [string, number] = ['123', 3434]; enum Flag { success = 1, error = 2 } var a: never; ================================================ FILE: src/typescript/ts/type-inference-demo.ts ================================================ let ab = '123'; ================================================ FILE: src/web-api/localstorage.js ================================================ ================================================ FILE: src/web-api/sessionstorage.js ================================================ ================================================ FILE: src/webpack/simple-webpack/buddle.js ================================================ const fs = require('fs'); const path = require('path'); const babylon = require('babylon'); const traverse = require('@babel/traverse').default; const babel = require('babel-core'); let ID = 0; function createAssets(filename) { const content = fs.readFileSync(filename, 'utf-8'); const ast = babylon.parse(content, { sourceType: "module" }) const dependencies = [] traverse(ast, { ImportDeclaration: ({node}) => { dependencies.push(node.source.value) } }) const { code } = babel.transformFromAst(ast, null, { presets: ['env'] }); const id = ID++; return { id, code, filename, dependencies } } function createGraph(entry) { const mainAssets = createAssets(entry); const queue = [mainAssets]; for (const asset of queue) { const dirname = path.dirname(asset.filename) asset.mapping = {}; asset.dependencies.forEach(relativePath => { const absolutePath = path.join(dirname, relativePath); const child = createAssets(absolutePath); asset.mapping[relativePath] = child.id; queue.push(child); }); } return queue; } function buddle(graph) { let modules = ''; graph.forEach(mod => { modules += `${mod.id}: [ function(require, module, exports) { ${mod.code} }, ${JSON.stringify(mod.mapping)} ],` }) const result = `(function(modules) { function require(id) { const [fn, mapping] = modules[id]; function localRequire(relativePath) { return require(mapping[relativePath]); } const module = { exports: {} }; fn(localRequire, module, module.exports); return module.exports; } require(0); })({${modules}})` return result; } const graph = createGraph('./example/entry.js') console.log(buddle(graph)); ================================================ FILE: src/webpack/simple-webpack/example/entry.js ================================================ import message from './message.js'; console.log(message); ================================================ FILE: src/webpack/simple-webpack/example/message.js ================================================ import { name } from './name.js' export default `hello ${name}`; ================================================ FILE: src/webpack/simple-webpack/example/name.js ================================================ export const name = 'shaosuo'; ================================================ FILE: yarn-error.log ================================================ Arguments: /usr/local/Cellar/node@12/12.16.1/bin/node /usr/local/Cellar/yarn/1.22.4/libexec/bin/yarn.js add crypto-js PATH: /usr/local/opt/node@12/bin:/usr/local/opt/php@5.6/sbin:/usr/local/opt/php@5.6/sbin:/usr/local/opt/php@5.6/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin:/Library/Frameworks/Mono.framework/Versions/Current/Commands:/Applications/Wireshark.app/Contents/MacOS:/usr/local/opt/node@12/bin:/usr/local/opt/php@5.6/sbin:/usr/local/opt/php@5.6/bin Yarn version: 1.22.4 Node version: 12.16.1 Platform: darwin x64 Trace: Error: http://registry.npm.chengfayun.net/ts-node: ETIMEDOUT at Timeout._onTimeout (/usr/local/Cellar/yarn/1.22.4/libexec/lib/cli.js:141408:19) at listOnTimeout (internal/timers.js:549:17) at processTimers (internal/timers.js:492:7) npm manifest: { "name": "suo-blog", "version": "1.0.0", "main": "index.js", "repository": "https://github.com/suoyuesmile/suo-blog.git", "author": "shaosuo ", "license": "MIT", "scripts": { "dev": "tsc --build tsconfig.json" }, "dependencies": { "formidable": "^1.2.2", "koa": "^2.12.0", "ts-node": "^8.9.1", "typescript": "^3.8.3" } } yarn manifest: No manifest Lockfile: # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 "@triones/biz-compiler@>=0.0.0": version "0.0.20200427202107" resolved "http://registry.npm.chengfayun.net/@triones/biz-compiler/download/@triones/biz-compiler-0.0.20200427202107.tgz#870974eff9ff2b88b8707324463322a76d1f914b" integrity sha1-hwl07/n/K4i4cHMkRjMip20fkUs= dependencies: "@types/scheduler" "^0.16.1" remark-parse "^6.0.3" scheduler "^0.19.1" unified "^8.4.2" "@types/scheduler@^0.16.1": version "0.16.1" resolved "http://registry.npm.chengfayun.net/@types/scheduler/download/@types/scheduler-0.16.1.tgz#18845205e86ff0038517aab7a18a62a6b9f71275" integrity sha1-GIRSBehv8AOFF6q3oYpiprn3EnU= "@types/unist@^2.0.0", "@types/unist@^2.0.2": version "2.0.3" resolved "http://registry.npm.chengfayun.net/@types/unist/download/@types/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" integrity sha1-nAiGeYdvN061mD8VDUeHqm+zLX4= accepts@^1.3.5: version "1.3.7" resolved "http://registry.npm.chengfayun.net/accepts/download/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" integrity sha1-UxvHJlF6OytB+FACHGzBXqq1B80= dependencies: mime-types "~2.1.24" negotiator "0.6.2" any-promise@^1.1.0: version "1.3.0" resolved "http://registry.npm.chengfayun.net/any-promise/download/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= arg@^4.1.0: version "4.1.3" resolved "http://registry.npm.chengfayun.net/arg/download/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha1-Jp/HrVuOQstjyJbVZmAXJhwUQIk= arrify@^2.0.1: version "2.0.1" resolved "http://registry.npm.chengfayun.net/arrify/download/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha1-yWVekzHgq81YjSp8rX6ZVvZnAfo= bail@^1.0.0: version "1.0.5" resolved "http://registry.npm.chengfayun.net/bail/download/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" integrity sha1-tvoTNASjksvB+MS/Y/WVM1Hnp3Y= buffer-from@^1.0.0, buffer-from@^1.1.1: version "1.1.1" resolved "http://registry.npm.chengfayun.net/buffer-from/download/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha1-MnE7wCj3XAL9txDXx7zsHyxgcO8= cache-content-type@^1.0.0: version "1.0.1" resolved "http://registry.npm.chengfayun.net/cache-content-type/download/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c" integrity sha1-A1zeKwjuISn0qDFeqPAKANuhRTw= dependencies: mime-types "^2.1.18" ylru "^1.2.0" character-entities-legacy@^1.0.0: version "1.1.4" resolved "http://registry.npm.chengfayun.net/character-entities-legacy/download/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" integrity sha1-lLwYRdznClu50uzHSHJWYSk9j8E= character-entities@^1.0.0: version "1.2.4" resolved "http://registry.npm.chengfayun.net/character-entities/download/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" integrity sha1-4Sw5Obfq9OWxXnrUxeKOHUjFsWs= character-reference-invalid@^1.0.0: version "1.1.4" resolved "http://registry.npm.chengfayun.net/character-reference-invalid/download/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" integrity sha1-CDMpzaDq4nKrPbvzfpo4LBOvFWA= co@^4.6.0: version "4.6.0" resolved "http://registry.npm.chengfayun.net/co/download/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= collapse-white-space@^1.0.2: version "1.0.6" resolved "http://registry.npm.chengfayun.net/collapse-white-space/download/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" integrity sha1-5jYpwAFmZXkgYNu+t5xCI50sUoc= content-disposition@~0.5.2: version "0.5.3" resolved "http://registry.npm.chengfayun.net/content-disposition/download/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" integrity sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70= dependencies: safe-buffer "5.1.2" content-type@^1.0.4: version "1.0.4" resolved "http://registry.npm.chengfayun.net/content-type/download/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha1-4TjMdeBAxyexlm/l5fjJruJW/js= cookies@~0.8.0: version "0.8.0" resolved "http://registry.npm.chengfayun.net/cookies/download/cookies-0.8.0.tgz#1293ce4b391740a8406e3c9870e828c4b54f3f90" integrity sha1-EpPOSzkXQKhAbjyYcOgoxLVPP5A= dependencies: depd "~2.0.0" keygrip "~1.1.0" debug@~3.1.0: version "3.1.0" resolved "http://registry.npm.chengfayun.net/debug/download/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" integrity sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE= dependencies: ms "2.0.0" deep-equal@~1.0.1: version "1.0.1" resolved "http://registry.npm.chengfayun.net/deep-equal/download/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= delegates@^1.0.0: version "1.0.0" resolved "http://registry.npm.chengfayun.net/delegates/download/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= depd@^1.1.2, depd@~1.1.2: version "1.1.2" resolved "http://registry.npm.chengfayun.net/depd/download/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= depd@~2.0.0: version "2.0.0" resolved "http://registry.npm.chengfayun.net/depd/download/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha1-tpYWPMdXVg0JzyLMj60Vcbeedt8= destroy@^1.0.4: version "1.0.4" resolved "http://registry.npm.chengfayun.net/destroy/download/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= diff@^3.1.0: version "3.5.0" resolved "http://registry.npm.chengfayun.net/diff/download/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI= ee-first@1.1.1: version "1.1.1" resolved "http://registry.npm.chengfayun.net/ee-first/download/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= encodeurl@^1.0.2: version "1.0.2" resolved "http://registry.npm.chengfayun.net/encodeurl/download/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= escape-html@^1.0.3: version "1.0.3" resolved "http://registry.npm.chengfayun.net/escape-html/download/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= extend@^3.0.0: version "3.0.2" resolved "http://registry.npm.chengfayun.net/extend/download/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo= formidable@^1.2.2: version "1.2.2" resolved "http://registry.npm.chengfayun.net/formidable/download/formidable-1.2.2.tgz#bf69aea2972982675f00865342b982986f6b8dd9" integrity sha1-v2muopcpgmdfAIZTQrmCmG9rjdk= fresh@~0.5.2: version "0.5.2" resolved "http://registry.npm.chengfayun.net/fresh/download/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= http-assert@^1.3.0: version "1.4.1" resolved "http://registry.npm.chengfayun.net/http-assert/download/http-assert-1.4.1.tgz#c5f725d677aa7e873ef736199b89686cceb37878" integrity sha1-xfcl1neqfoc+9zYZm4lobM6zeHg= dependencies: deep-equal "~1.0.1" http-errors "~1.7.2" http-errors@^1.6.3, http-errors@~1.7.2: version "1.7.3" resolved "http://registry.npm.chengfayun.net/http-errors/download/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" integrity sha1-bGGeT5xgMIw4UZSYwU+7EKrOuwY= dependencies: depd "~1.1.2" inherits "2.0.4" setprototypeof "1.1.1" statuses ">= 1.5.0 < 2" toidentifier "1.0.0" inherits@2.0.4, inherits@^2.0.0: version "2.0.4" resolved "http://registry.npm.chengfayun.net/inherits/download/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w= is-alphabetical@^1.0.0: version "1.0.4" resolved "http://registry.npm.chengfayun.net/is-alphabetical/download/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" integrity sha1-nn1rlJFr4iFTdF0YTCmMv5hqaG0= is-alphanumerical@^1.0.0: version "1.0.4" resolved "http://registry.npm.chengfayun.net/is-alphanumerical/download/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" integrity sha1-frmiQx+FX2se8aeOMm31FWlsTb8= dependencies: is-alphabetical "^1.0.0" is-decimal "^1.0.0" is-buffer@^2.0.0: version "2.0.4" resolved "http://registry.npm.chengfayun.net/is-buffer/download/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" integrity sha1-PlcvI8hBGlz9lVfISeNmXgspBiM= is-decimal@^1.0.0: version "1.0.4" resolved "http://registry.npm.chengfayun.net/is-decimal/download/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" integrity sha1-ZaOllYocW2OnBuGzM9fNn2MNP6U= is-generator-function@^1.0.7: version "1.0.7" resolved "http://registry.npm.chengfayun.net/is-generator-function/download/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" integrity sha1-0hMuUpuwAAp/gHlNS99c1eWBNSI= is-hexadecimal@^1.0.0: version "1.0.4" resolved "http://registry.npm.chengfayun.net/is-hexadecimal/download/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" integrity sha1-zDXJdYjaS9Saju3WvECC1E3LI6c= is-plain-obj@^2.0.0: version "2.1.0" resolved "http://registry.npm.chengfayun.net/is-plain-obj/download/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha1-ReQuN/zPH0Dajl927iFRWEDAkoc= is-whitespace-character@^1.0.0: version "1.0.4" resolved "http://registry.npm.chengfayun.net/is-whitespace-character/download/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" integrity sha1-CFjt2UqVWUx8ndC1wXTsbkXuSqc= is-word-character@^1.0.0: version "1.0.4" resolved "http://registry.npm.chengfayun.net/is-word-character/download/is-word-character-1.0.4.tgz#ce0e73216f98599060592f62ff31354ddbeb0230" integrity sha1-zg5zIW+YWZBgWS9i/zE1TdvrAjA= "js-tokens@^3.0.0 || ^4.0.0": version "4.0.0" resolved "http://registry.npm.chengfayun.net/js-tokens/download/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha1-GSA/tZmR35jjoocFDUZHzerzJJk= keygrip@~1.1.0: version "1.1.0" resolved "http://registry.npm.chengfayun.net/keygrip/download/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226" integrity sha1-hxsWgdXhWcYqRFsMdLYV4JF+ciY= dependencies: tsscmp "1.0.6" koa-compose@^3.0.0: version "3.2.1" resolved "http://registry.npm.chengfayun.net/koa-compose/download/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" integrity sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec= dependencies: any-promise "^1.1.0" koa-compose@^4.1.0: version "4.1.0" resolved "http://registry.npm.chengfayun.net/koa-compose/download/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" integrity sha1-UHMGuTcZAdtBEhyBLpI9DWfT6Hc= koa-convert@^1.2.0: version "1.2.0" resolved "http://registry.npm.chengfayun.net/koa-convert/download/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" integrity sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA= dependencies: co "^4.6.0" koa-compose "^3.0.0" koa@^2.12.0: version "2.12.0" resolved "http://registry.npm.chengfayun.net/koa/download/koa-2.12.0.tgz#c92bfb42defd86f365c31bf63fe918db11fc5c74" integrity sha1-ySv7Qt79hvNlwxv2P+kY2xH8XHQ= dependencies: accepts "^1.3.5" cache-content-type "^1.0.0" content-disposition "~0.5.2" content-type "^1.0.4" cookies "~0.8.0" debug "~3.1.0" delegates "^1.0.0" depd "^1.1.2" destroy "^1.0.4" encodeurl "^1.0.2" escape-html "^1.0.3" fresh "~0.5.2" http-assert "^1.3.0" http-errors "^1.6.3" is-generator-function "^1.0.7" koa-compose "^4.1.0" koa-convert "^1.2.0" on-finished "^2.3.0" only "~0.0.2" parseurl "^1.3.2" statuses "^1.5.0" type-is "^1.6.16" vary "^1.1.2" loose-envify@^1.1.0: version "1.4.0" resolved "http://registry.npm.chengfayun.net/loose-envify/download/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8= dependencies: js-tokens "^3.0.0 || ^4.0.0" make-error@^1.1.1: version "1.3.6" resolved "http://registry.npm.chengfayun.net/make-error/download/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha1-LrLjfqm2fEiR9oShOUeZr0hM96I= markdown-escapes@^1.0.0: version "1.0.4" resolved "http://registry.npm.chengfayun.net/markdown-escapes/download/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" integrity sha1-yVQV70UUmddgK5EJXzyOiXX3hTU= media-typer@0.3.0: version "0.3.0" resolved "http://registry.npm.chengfayun.net/media-typer/download/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= mime-db@1.44.0: version "1.44.0" resolved "http://registry.npm.chengfayun.net/mime-db/download/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" integrity sha1-+hHF6wrKEzS0Izy01S8QxaYnL5I= mime-types@^2.1.18, mime-types@~2.1.24: version "2.1.27" resolved "http://registry.npm.chengfayun.net/mime-types/download/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" integrity sha1-R5SfmOJ56lMRn1ci4PNOUpvsAJ8= dependencies: mime-db "1.44.0" minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "http://registry.npm.chengfayun.net/minimist/download/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI= mkdirp@^0.5.1: version "0.5.5" resolved "http://registry.npm.chengfayun.net/mkdirp/download/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha1-2Rzv1i0UNsoPQWIOJRKI1CAJne8= dependencies: minimist "^1.2.5" ms@2.0.0: version "2.0.0" resolved "http://registry.npm.chengfayun.net/ms/download/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= negotiator@0.6.2: version "0.6.2" resolved "http://registry.npm.chengfayun.net/negotiator/download/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs= object-assign@^4.1.1: version "4.1.1" resolved "http://registry.npm.chengfayun.net/object-assign/download/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= on-finished@^2.3.0: version "2.3.0" resolved "http://registry.npm.chengfayun.net/on-finished/download/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= dependencies: ee-first "1.1.1" only@~0.0.2: version "0.0.2" resolved "http://registry.npm.chengfayun.net/only/download/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q= parse-entities@^1.1.0: version "1.2.2" resolved "http://registry.npm.chengfayun.net/parse-entities/download/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" integrity sha1-wxvw9lO2ZhNU+Jc1WcuG3R1e31A= dependencies: character-entities "^1.0.0" character-entities-legacy "^1.0.0" character-reference-invalid "^1.0.0" is-alphanumerical "^1.0.0" is-decimal "^1.0.0" is-hexadecimal "^1.0.0" parseurl@^1.3.2: version "1.3.3" resolved "http://registry.npm.chengfayun.net/parseurl/download/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ= remark-parse@^6.0.3: version "6.0.3" resolved "http://registry.npm.chengfayun.net/remark-parse/download/remark-parse-6.0.3.tgz#c99131052809da482108413f87b0ee7f52180a3a" integrity sha1-yZExBSgJ2kghCEE/h7Duf1IYCjo= dependencies: collapse-white-space "^1.0.2" is-alphabetical "^1.0.0" is-decimal "^1.0.0" is-whitespace-character "^1.0.0" is-word-character "^1.0.0" markdown-escapes "^1.0.0" parse-entities "^1.1.0" repeat-string "^1.5.4" state-toggle "^1.0.0" trim "0.0.1" trim-trailing-lines "^1.0.0" unherit "^1.0.4" unist-util-remove-position "^1.0.0" vfile-location "^2.0.0" xtend "^4.0.1" repeat-string@^1.5.4: version "1.6.1" resolved "http://registry.npm.chengfayun.net/repeat-string/download/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= replace-ext@1.0.0: version "1.0.0" resolved "http://registry.npm.chengfayun.net/replace-ext/download/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= safe-buffer@5.1.2: version "5.1.2" resolved "http://registry.npm.chengfayun.net/safe-buffer/download/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha1-mR7GnSluAxN0fVm9/St0XDX4go0= scheduler@^0.19.1: version "0.19.1" resolved "http://registry.npm.chengfayun.net/scheduler/download/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" integrity sha1-Tz4u0sGn1laB9MhU+oxaHMtA8ZY= dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" setprototypeof@1.1.1: version "1.1.1" resolved "http://registry.npm.chengfayun.net/setprototypeof/download/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" integrity sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM= source-map-support@^0.5.6: version "0.5.19" resolved "http://registry.npm.chengfayun.net/source-map-support/download/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha1-qYti+G3K9PZzmWSMCFKRq56P7WE= dependencies: buffer-from "^1.0.0" source-map "^0.6.0" source-map@^0.6.0: version "0.6.1" resolved "http://registry.npm.chengfayun.net/source-map/download/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha1-dHIq8y6WFOnCh6jQu95IteLxomM= state-toggle@^1.0.0: version "1.0.3" resolved "http://registry.npm.chengfayun.net/state-toggle/download/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe" integrity sha1-4SOxaojhQxObCcaFIiG8mBWRff4= "statuses@>= 1.5.0 < 2", statuses@^1.5.0: version "1.5.0" resolved "http://registry.npm.chengfayun.net/statuses/download/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= toidentifier@1.0.0: version "1.0.0" resolved "http://registry.npm.chengfayun.net/toidentifier/download/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM= trim-trailing-lines@^1.0.0: version "1.1.3" resolved "http://registry.npm.chengfayun.net/trim-trailing-lines/download/trim-trailing-lines-1.1.3.tgz#7f0739881ff76657b7776e10874128004b625a94" integrity sha1-fwc5iB/3Zle3d24Qh0EoAEtiWpQ= trim@0.0.1: version "0.0.1" resolved "http://registry.npm.chengfayun.net/trim/download/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= trough@^1.0.0: version "1.0.5" resolved "http://registry.npm.chengfayun.net/trough/download/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha1-uLY5zvrX0LsqvTfUM/+Ck++l9AY= ts-node@^8.9.1: version "7.0.1" resolved "http://registry.npm.chengfayun.net/ts-node/download/ts-node-7.0.1.tgz#75242659bb27cdbec59d893d233b8595c397faea" integrity sha1-dSQmWbsnzb7FnYk9IzuFlcOX+uo= dependencies: arg "^4.1.0" arrify "^2.0.1" buffer-from "^1.1.1" diff "^3.1.0" make-error "^1.1.1" minimist "^1.2.0" mkdirp "^0.5.1" source-map-support "^0.5.6" yn "^3.0.0" tsscmp@1.0.6: version "1.0.6" resolved "http://registry.npm.chengfayun.net/tsscmp/download/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" integrity sha1-hbmVg6w1iexL/vgltQAKqRHWBes= type-is@^1.6.16: version "1.6.18" resolved "http://registry.npm.chengfayun.net/type-is/download/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha1-TlUs0F3wlGfcvE73Od6J8s83wTE= dependencies: media-typer "0.3.0" mime-types "~2.1.24" typescript@^3.8.3: version "3.8.3" resolved "http://registry.npm.chengfayun.net/typescript/download/typescript-3.8.3.tgz#8c2f59df15365e2eea9949840dd148d33381fd17" integrity sha1-jC9Z3xU2Xi7qmUmEDdFI0zOB/Rc= dependencies: "@triones/biz-compiler" ">=0.0.0" unherit@^1.0.4: version "1.1.3" resolved "http://registry.npm.chengfayun.net/unherit/download/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" integrity sha1-bJtQPytBsmIzDIDpHIYUq9qmnCI= dependencies: inherits "^2.0.0" xtend "^4.0.0" unified@^8.4.2: version "8.4.2" resolved "http://registry.npm.chengfayun.net/unified/download/unified-8.4.2.tgz#13ad58b4a437faa2751a4a4c6a16f680c500fff1" integrity sha1-E61YtKQ3+qJ1GkpMahb2gMUA//E= dependencies: bail "^1.0.0" extend "^3.0.0" is-plain-obj "^2.0.0" trough "^1.0.0" vfile "^4.0.0" unist-util-is@^3.0.0: version "3.0.0" resolved "http://registry.npm.chengfayun.net/unist-util-is/download/unist-util-is-3.0.0.tgz#d9e84381c2468e82629e4a5be9d7d05a2dd324cd" integrity sha1-2ehDgcJGjoJinkpb6dfQWi3TJM0= unist-util-remove-position@^1.0.0: version "1.1.4" resolved "http://registry.npm.chengfayun.net/unist-util-remove-position/download/unist-util-remove-position-1.1.4.tgz#ec037348b6102c897703eee6d0294ca4755a2020" integrity sha1-7ANzSLYQLIl3A+7m0ClMpHVaICA= dependencies: unist-util-visit "^1.1.0" unist-util-stringify-position@^2.0.0: version "2.0.3" resolved "http://registry.npm.chengfayun.net/unist-util-stringify-position/download/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" integrity sha1-zOO/oc34W6c3XR1bF73Eytqb2do= dependencies: "@types/unist" "^2.0.2" unist-util-visit-parents@^2.0.0: version "2.1.2" resolved "http://registry.npm.chengfayun.net/unist-util-visit-parents/download/unist-util-visit-parents-2.1.2.tgz#25e43e55312166f3348cae6743588781d112c1e9" integrity sha1-JeQ+VTEhZvM0jK5nQ1iHgdESwek= dependencies: unist-util-is "^3.0.0" unist-util-visit@^1.1.0: version "1.4.1" resolved "http://registry.npm.chengfayun.net/unist-util-visit/download/unist-util-visit-1.4.1.tgz#4724aaa8486e6ee6e26d7ff3c8685960d560b1e3" integrity sha1-RySqqEhububibX/zyGhZYNVgseM= dependencies: unist-util-visit-parents "^2.0.0" vary@^1.1.2: version "1.1.2" resolved "http://registry.npm.chengfayun.net/vary/download/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= vfile-location@^2.0.0: version "2.0.6" resolved "http://registry.npm.chengfayun.net/vfile-location/download/vfile-location-2.0.6.tgz#8a274f39411b8719ea5728802e10d9e0dff1519e" integrity sha1-iidPOUEbhxnqVyiALhDZ4N/xUZ4= vfile-message@^2.0.0: version "2.0.4" resolved "http://registry.npm.chengfayun.net/vfile-message/download/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" integrity sha1-W0O4gXHUCerlhHfRPyPdQdUsNxo= dependencies: "@types/unist" "^2.0.0" unist-util-stringify-position "^2.0.0" vfile@^4.0.0: version "4.1.1" resolved "http://registry.npm.chengfayun.net/vfile/download/vfile-4.1.1.tgz#282d28cebb609183ac51703001bc18b3e3f17de9" integrity sha1-KC0ozrtgkYOsUXAwAbwYs+Pxfek= dependencies: "@types/unist" "^2.0.0" is-buffer "^2.0.0" replace-ext "1.0.0" unist-util-stringify-position "^2.0.0" vfile-message "^2.0.0" xtend@^4.0.0, xtend@^4.0.1: version "4.0.2" resolved "http://registry.npm.chengfayun.net/xtend/download/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q= ylru@^1.2.0: version "1.2.1" resolved "http://registry.npm.chengfayun.net/ylru/download/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f" integrity sha1-9Xa2M0FUeYnB3nuiiHYJI7J/6E8= yn@^3.0.0: version "3.1.1" resolved "http://registry.npm.chengfayun.net/yn/download/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha1-HodAGgnXZ8HV6rJqbkwYUYLS61A=