llm_learn/蒸馏/数据集/问题/segmentfault_questions.json
2025-10-16 08:46:13 +08:00

2750 lines
793 KiB
JSON
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[
{
"id": "segmentfault_0",
"question": "http和https的区别\n我知道https更加安全问题是怎么个安全法\n比如我现在有一个纯的静态页面就是做信息展示就是我们说的marketing site,这里面也没有什么ajax请求啥的是不是就http/https从安全角度就没有区别了\n但是浏览器还是标记Http not secure呢哪里不安全了",
"answer": "小明要给小红写信,但小明小红之间离的太远了,没法直接交换信件,只能是小明先给小强、小强再给小刚、小刚再给小红,小红收到了以后回信给小刚、小刚再给小强、小强才能给到小明。小强和小刚在这个过程中都可以拆开信看到内容、甚至模仿小明小红的字迹去篡改这封信。本来可能小明写的是情书,被小刚改成了战书,小红收到了不得气炸了。\n你现在用浏览器访问了思否网站但你的电脑跟思否网站服务器显然并不是一根网线直连的中间会经过层层设备转发有路由器、交换机、中继器、代理、网关等等等等。而 HTTP 是明文的,也就是这中间的每一个设备都可以监听、甚至篡改 HTTP 报文。即便你是纯静态的网站,但你怎么确保浏览器收到的一定就是你的服务器返回的那个 HTTP 报文、中间没经过其他设备的监听和篡改呢?本来你服务器返回的是一个企业宣传网站,结果被篡改成了一个黄赌毒网站。\n这种监听和篡改在计算机中被称之为“中间人攻击” —— 顾名思义,就是因为通信两端中间的某些节点发生的攻击。而 HTTPS 要解决的就是这个问题。具体还可以细分为单向认证和双向认证。单向认证只能确保客户端收到的一定是服务器返回的内容,但无法保证服务器收到的一定是客户端发出的内容;双向认证则两端都可以确保不被篡改。\n扩展思考前面说因为客户端和服务器离得太远所以不得不需要很多“中间人”来转发那么假如客户端和服务器用网线直接连接、去掉这些“中间人”用 HTTP 就会安全吗?答案是依然不安全,至于为什么,您可以先自己思考一下。",
"type": "technical_qa"
},
{
"id": "segmentfault_1",
"question": "为什么感觉redis队列不如mysql稳定容易丢数据原因何在\n目前的开发环境php7.2 | thinkphp\n1.用mysql实现的架构\n生产者大量数据先存入mysql中间表mysql中间表用唯一索引约束唯一性\n多个消费者循环从mysql中间表中取数据进行计算后存入mysql结果表\n2.用redis实现的架构\n生产者大量数据先进入redis集合为了保证重复数据不入队列确定能进入集合的数据再塞入redis队列\n多个生产者循环从redis队列中取数据每取一条数据后将该数据从redis集合中删除对数据进行计算计算后的数据存入mysql结果表\n两种架构在实际使用中发现用纯mysql的方式实现结果数据很稳定没有出现丢失的情况。\n而用redis的方式实现会发现存在数据丢失的情况即结果表里缺少数据而且还找不到数据丢失的原因trycatch和redis日志均无问题。用redis集合加redis队列作为中间过度的方式为什么会不稳定原因在哪里",
"answer": "首先Redis什么时候会出现`丢数据`\nRedis持久化有两种方式`RDB`和`AOF`,它只会在重启时可能丢失数据。正常运行的情况下,是不会丢失数据的。\n找不到丢失的原因为什么不稳定\nMySQL有ACID强一致性事务支持。而Redis分步操作每步都可能出问题。\n`而且还找不到数据丢失的原因`\n分步骤来看\n- 大量数据先进入redis集合 是否正常\n- 再塞入redis队列 是否正常\n\n`循环从redis队列中取数据每取一条数据后将该数据从redis集合中删除对数据进行计算计算后的数据存入mysql结果表`\n这是一个很大的步骤。最简答的方法加日志看看是哪里丢的数据。比如取了数据从Redis删除了计算时出现问题没有写MySQL。\n你抛出的问题别人很难处理。没有代码不请求具体实现而且你没有耐心的去找原因。每个步骤都加详细的日志不可能存在找不到原因这种问题。",
"type": "technical_qa"
},
{
"id": "segmentfault_2",
"question": "JS 中通过apply实现数组中查找最大值的方法原理是什么\nJS数组中无法直接通过`Math.max`查找数组中元素的最大值,但可以通过`apply`方法实现,底层实现逻辑及原理是什么样的呢?\n```\nMath.max.apply(null, [1,2,3]);\n```",
"answer": "我们这样来理解,\n首先\n```\nMath.max(value0, value1, /* … ,*/ valueN) \n```\n这个函数的参数并不是数组比如你有N个数字比大小哪它就要输入N个参数\n对于在数组中的数字你把整个数组当参数给它Math.max就认为只有一个参数了。所以比不了\n也就是说你要把数组中每一位数字都转成它的参数\n```\nconst arr=[1,2,3]\n//最笨的办法是\nMath.max(arr[0],arr[1],arr[2])\n//最新的办法\nMath.max(...arr)\n```\n上面都是把数组的每一位变成参数传个Math.max\n哪为什么Function.prototype.apply() 就可以呢因为apply(thisArg, argsArray),第二个参数,就是接受一个数组对像,把它变成调用者的所有参数,",
"type": "technical_qa"
},
{
"id": "segmentfault_3",
"question": "为什么mysql的依赖scope是runtime\n如题runtime意味着打包时不包含mysql依赖没有mysql驱动发布后的项目如何正常连接数据库呢",
"answer": "因为JDBC通常你在编码的时候依赖的只是JDBC接口而不直接依赖mysql JDBC对吧\n想想你在连接mysql的时候是不是用的类似于这样的代码?\n```\nClass.forName(\"com.mysql.jdbc.Driver\");\nConnection conn = DriverManager.getConnection(url, username, password);\n// ...\n```\n我们会发现我们会使用反射方法`Class.forName`在运行的时候从ClassPath中加载Mysql JDBC,后续调用的时候均没有使用任何MySQL JDBC的专有方法而是用的JDBC接口对吧\n所以JDBC Driver不是编译依赖(Compile Scope)因为我们的代码中没有直接使用JDBC Driver的专有方法所以编译的时候不需要JDBC Driver存在。JDBC接口才是编译依赖JDBC Driver属于运行依赖(Runtime Scope)。\n你声明Runtime依赖的时候在编译中是不会将依赖引入ClassPath的但是打包的时候会所以无需担心JDBC Driver就应该是Runtime Scope依赖。\nCompile Scope指的是编译的时候需要该依赖通常编译依赖也是Runtime依赖而Maven/Gradle对于compile依赖通常都是编译之后同时也包含在fat jar中的相当于Compile就隐含Runtime。某些依赖也可能是CompileOnly依赖比如注解处理器就是典型的CompileOnly依赖只有编译的时候需要编译过后在运行中是不需要的",
"type": "technical_qa"
},
{
"id": "segmentfault_4",
"question": "chrome控制台调试f9 和 f11 有何区别?\nf10(跳过下一个函数调用)、f11(进入下一个函数调用)用的很熟但f9(单步调试)没用过经过测试感觉和f11一样遇到函数就进入函数里边执行。那么f9 和 f11 有何区别?",
"answer": "stackoverflow\nYou can spot the difference while running async code or multi-threaded code.\nStep into: DevTools assumes that you want to pause in the asynchronous code that eventually runs\nStep: DevTools pause in code as it chronologically ran\nConsider this example:\n```\nsetTimeout(() => {\n console.log('inside')\n}, 3000);\nconsole.log('outside')\n```\nAfter stopping on the breakpoint on the first line (`setTimeout(() => {`).\nStep into: it waits 3 seconds and stops on the 2nd line (`console.log('inside')`)\nStep: it pauses on the 4th line (`console.log('outside')`)\nLink to the docs: https://developers.google.com...",
"type": "technical_qa"
},
{
"id": "segmentfault_5",
"question": "函数传入的值,作为对象的 key 返回TS 应该如何写?\n返回的 `ts` 一定有 `a` 这个 `key`\n```\nfunction test(a:string, b:object){\n return {\n [a]:b[a]\n }\n}\n```",
"answer": "```\nfunction test<T extends Record<string, any>, K extends keyof T>(a:K, b:T){\n return {\n [a]:b[a]\n } as Pick<T, K>\n}\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_6",
"question": "如果一次网页操作本身就只会触发一次回流/重绘,那么虚拟 dom 还有优势吗?\n按照我目前的理解,虚拟dom的优势在于把当前的变化打包给浏览器,让浏览器一次性更新,而不是来一个更新一个,减少页面的回流和重绘.\n但是如果只有一个按钮, 点一下文字变色或者改变某个元素的显隐性,那么这种操作浏览器应该本身就是只回流/重绘一次,这个时候虚拟dom还有优势吗?\n#### 还有个小问题: 默认浏览器是怎么更新元素的?\n如果我一次 display:none 了页面中的9个元素,那么在没有虚拟dom的情况下,浏览器会回流/重绘9次吗",
"answer": "Q1\n> 但是如果只有一个按钮, 点一下文字变色或者改变某个元素的显隐性,那么这种操作浏览器应该本身就是只回流/重绘一次,这个时候虚拟 DOM 还有优势吗?那肯定是原生直接操作 DOM 更快。\n但问题是这种简单页面的场景为啥你要用 MVVM 框架?\nQ2\n> 如果我一次 display:none 了页面中的 9 个元素,那么在没有虚拟 DOM 的情况下,浏览器会回流/重绘 9 次吗。\n这里的“一次”我理解为是一段代码里连续控制 9 个元素隐藏,类似:\n```\nel1.style.display = 'none';\nel2.style.display = 'none';\nel3.style.display = 'none';\n// 略...\n```\n那么答案是不一定。\n老浏览器的话是回流 9 次(没错,就说你呢,明天就要退休的 IE。现代浏览器会有渲染队列来对这种场景做优化一段时间内的重复回流操作会被合并但要注意这里的队列可能会被另一些操作打断并清空比如 `getBoundingClientRect`、`getComputedStyle` 等等,这也很好理解,这些操作是要获取当前 DOM 状态的,自然要必须强制触发一次回流才可以拿到实时状态)。\n而回流必然会重绘重绘不一定回流。所以次数这里两者是一样的。",
"type": "technical_qa"
},
{
"id": "segmentfault_7",
"question": "来个 js 算法大牛看看这个题,有没有优雅点的代码?\n`源数据`\n```\nconst data = [\n {\n city:'浙江',\n children:[\n {\n city:'宁波',\n children:[{\n city:'鄞州区',\n children:[]\n },{\n city:'江北区',\n children:[]\n }]\n },\n {\n city:'杭州',\n children:[{\n city:'富阳',\n children:[]\n },{\n city:'上城区',\n children:[]\n }]\n }\n ]\n },\n {\n city:'上海',\n children:[\n {\n city:'黄浦区',\n children:[]\n }\n ]\n }\n]\n```\n`目标结构`\n```\n[\n \"浙江,宁波,鄞州区\",\n \"浙江,宁波,江北区\",\n \"浙江,杭州,富阳\",\n \"浙江,杭州,上城区\",\n \"上海,黄浦区\"\n]\n```",
"answer": "## solution 1\n```\nfunction flatTree(nodes, parents = []) {\n const pathes = nodes\n .filter(({ children }) => !children?.length)\n .map(({ city }) => [...parents, city]);\n const subPathes = nodes.filter(({ children }) => children?.length)\n .flatMap(({ city, children }) => flatTree(children, [...parents, city]));\n return pathes.concat(subPathes);\n}\n```\n## solution 2\n```\nfunction flatTree(nodes, parents = []) {\n return nodes.flatMap(({ city, children }) => {\n return children?.length\n ? flatTree(children, [...parents, city])\n : [[...parents, city]];\n });\n}\n```\n## using\n```\nconsole.log(flatTree(data).map(path => path.join(\",\")));\n// ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_8",
"question": "怎么让 a == 1 && a==2 && a==3 的结果为 true\n让 a == 1 && a==2 && a==3 的结果为 true",
"answer": "```\nfunction A() {\n this.value = 0;\n this.toString = function() {\n return ++this.value\n }\n}\nconst a = new A();\n\na == 1 && a == 2 && a == 3\n```\n相等运算符 `==` 和 `!=` 使用 抽象相等比较算法 比较两个操作数。可以大致概括如下:\n- 如果两个操作数都是对象,则仅当两个操作数都引用同一个对象时才返回 `true` 。\n- 如果一个操作数是 `null`,另一个操作数是 `undefined`,则返回`true` 。\n- 如果两个操作数是不同类型的,就会尝试在比较之前将它们转换为相同类型:当数字与字符串进行比较时,会尝试将字符串转换为数字值。如果操作数之一是 `Boolean`则将布尔操作数转换为1或0。如果是 `true`,则转换为 `1`。如果是 `false`,则转换为 `0`。如果操作数之一是对象,另一个是数字或字符串,会尝试使用对象的 `valueOf()` 和 `toString()` 方法将对象转换为原始值。\n- 如果操作数具有相同的类型,则将它们进行如下比较:`String``true` 仅当两个操作数具有相同顺序的相同字符时才返回。`Number``true` 仅当两个操作数具有相同的值时才返回。`+0` 并被 `-0` 视为相同的值。如果任一操作数为 `NaN`,则返回 `false`。`Boolean` `true` 仅当操作数为两个 `true` 或两个 `false` 时才返回 `true`。\n\n如果两个操作数是不同类型的就会尝试在比较之前将它们转换为相同类型\n- 当数字与字符串进行比较时,会尝试将字符串转换为数字值。\n- 如果操作数之一是 `Boolean`则将布尔操作数转换为1或0。如果是 `true`,则转换为 `1`。如果是 `false`,则转换为 `0`。\n- 如果操作数之一是对象,另一个是数字或字符串,会尝试使用对象的 `valueOf()` 和 `toString()` 方法将对象转换为原始值。\n\n如果操作数之一是 `Boolean`则将布尔操作数转换为1或0。\n- 如果是 `true`,则转换为 `1`。\n- 如果是 `false`,则转换为 `0`。\n\n如果操作数具有相同的类型则将它们进行如下比较\n- `String``true` 仅当两个操作数具有相同顺序的相同字符时才返回。\n- `Number``true` 仅当两个操作数具有相同的值时才返回。`+0` 并被 `-0` 视为相同的值。如果任一操作数为 `NaN`,则返回 `false`。\n- `Boolean` `true` 仅当操作数为两个 `true` 或两个 `false` 时才返回 `true`。\n\n来自 https://developer.mozilla.org...",
"type": "technical_qa"
},
{
"id": "segmentfault_9",
"question": "js 函数 return false 跳出外部函数,怎么写?\n```\nfunction a(){\n iftrue\n return false;\n}\n```\n这是没有任何问题的如果我改成这种\n```\nfunction Test(){\n a();\n b();\n c();\n}\n```\njs 函数a() return false 跳出外部函数Test(),怎么写?",
"answer": "`return` 只能退出当前函数,不具备跨函数的功能。但是 `throw` 具有不限层次中断的功能,所以这个需要可能需要使用 throw 来完成。\n一般情况下 `throw` 应该抛出一个 `Error` 对象。但是 JavaScript 并未对 `throw` 的对象有所有限制,所以也可以抛出其它东西,在确实不需要抛出错误的情况下,抛出一个状态对象,甚至值都是可以的。但不管抛出什么,要想外面的程序能正常运行,都是需要 `try ... catch` 的。\n举例\n```\nfunction a() {\n console.log(\"[Trace] a()\");\n if (true) {\n throw \"true-as-false\";\n }\n}\n\nfunction b() {\n console.log(\"[Trace] b()\");\n}\n\nfunction c() {\n console.log(\"[Trace] c()\");\n}\n\nfunction test() {\n try {\n a();\n b();\n c();\n } catch (stat) {\n if (stat === \"true-as-false\") {\n return;\n }\n\n // TODO 其他情况正常处理可能发生的错误\n }\n}\n\ntest();\n```\n只会输出 `[Trace] a()`,因为被 throw 给中断掉了。\n如果是有一堆判断函数只要有一个 flase 就退出,那就可以用数组来处理,比如\n```\nconst fns = [\n () => { console.log(true); return true; },\n () => { console.log(true); return true; },\n () => { console.log(false); return false; },\n () => { console.log(true); return true; },\n];\n\nfns.every(fn => fn());\n// true\n// true\n// false\n```\n只要遇到一个返回 `false` 的就结束了(注意,返回 `undefined`,也就是无返回值 …… 也表示 `false`)",
"type": "technical_qa"
},
{
"id": "segmentfault_10",
"question": "判断一个字符串A-Z对应输出0-25a-z对应输出26-51有什么简洁的写法吗\n比如'AZaz' => '0 25 26 51' \n我目前的做法\n```\nfunction Words(words){\n let strArray = []\n for (let s of words){\n if(/[A-Z]/.test(s)) strArray.push(s.charCodeAt(0)-65)\n else if(/[a-z]/.test(s)) strArray.push(s.charCodeAt(0)-71)\n }\n return(strArray.join(' ')) \n}\n\nWords('AZaz')\n```",
"answer": "```\nvar Words=(s,a='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')=>s.split('').map(v=>a.indexOf(v)).join('');\n\nWords('AZaz'); \n```",
"type": "technical_qa"
},
{
"id": "segmentfault_11",
"question": "来个 js 大牛,如何简洁的处理这种数组转换成对象?\n有这样一个 Array,\n`[{key:xxx},{value:xxx}]`\n`key` `value`是固定的属性\n```\n[\n {key:'alan',value:12},\n {key:'mike',value:18}\n]\n```\n期望值\n```\n{alan:12,mike:18}\n```\n希望不借助新的变量,简洁优雅一些~",
"answer": "其实所谓简洁,无非就是找现成的功能函数替换掉一堆逻辑代码……所以,自己封个工具函数,一句调用是最简洁的!\n```\nconst data = [\n { key: \"alan\", value: 12 },\n { key: \"mike\", value: 18 }\n];\n\n// 就这句话,换行主要是为了看清楚,可以不换\nconst result = Object.fromEntries(\n data.map(({ key, value }) => [key, value])\n);\n\nconsole.log(result);\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_12",
"question": "Vue如何动态修改template?\n先上代码\n```\n<template>\n <div v-html=\"marked(content)\"></div>\n</template>\n<script>\n....\n....\nmethods:{\n markdown (content) {\n var renderer = new marked.Renderer()\n renderer.image = (href, title, text) => {\n return '<a @click=\"showFullImage\">' + text + '</a>'\n }\n marked.setOptions({\n renderer: renderer,\n gfm: true,\n tables: true,\n breaks: true,\n pedantic: false,\n sanitize: false,\n smartLists: true,\n smartypants: false,\n highlight: (code) => {\n return hljs.highlightAuto(code).value\n }\n })\n return marked(content)\n }\n}\n</script>\n```\n我在使用vue做一个工具需要输入框中的markdown代码转为html然后展示出来。\n其中我想做的一个功能是当用户输入\n```\n![pic](www.example.com/img.jpg \"title\")\n```\n使用marked的自定义渲染函数转换成html已经实现:\n```\n<a @click=\"showFullImage\">title</a>'\n```\n现在的问题是在展示的时候使用v-html无法完成函数绑定。有没有好的方法\n简洁的说法是我需要自己生成一段vue格式的html字符串然后将这个字符串渲染出来里面有各种vue指令需要绑定该怎么做呢",
"answer": "我是在一个子组件中实现的,你可以动态的添加该子组件:\n下面的`content`是markdown格式的数据\n`../common/markdown`文件是自己写好的基于marked的解析函数它会将`Markdown`格式析为`Vue`格式的字符串:\n```\n![图片文字](url)\n// 上面会解析为:\n<img src=\"url\" @click=\"showInfo('图片文字')\">\n```\n用下面的方法即可以实现点击图片时会输出信息。当然其他的vue处理方法同样支持。\n```\n<template >\n <div ref=\"markedContent\"></div>\n</template>\n\n<script>\nimport Vue from 'vue'\nimport markdown from '../common/markdown'\nexport default {\n name: 'wf-marked-content',\n props: ['content'],\n mounted () {\n\n // 调用compile方法。你也可以将写在这里。\n // 但是代码太多,我个人不喜欢\n this.compile()\n },\n methods: {\n compile () {\n // 变量html是生成好的vue格式的HTML模板字符串\n // 这个模板里面可以包含各种vue的指令数据绑定等操作\n // 比如 v-if, :bind, @click 等。\n const html = markdown(this.content)\n \n // Vue.extend是vue的组件构造器专门用来构建自定义组件的\n // 但是不会注册类似于js中的createElement\n // 创建但是不会添加。\n // 在这里创建出一个子组件对象构造器。\n const Component = Vue.extend({\n \n // 模板文件。由于Markdown解析之后可能会有多个根节点\n // 因此需要包裹起来。\n // 实际的内容是:\n // `<div><img src=\"url\" @click=\"showInfo(`图片文字')\"></div>`\n template: `<div> ${html} </div>`,\n \n // 这里面写的就是这个动态生成的新组件中的方法了,\n // 当然你也可加上data、mounted、updated、watch、computed等等。\n methods: {\n \n // 上面模板中将点击事件绑定到了这里,因此点击了之后就会调用这个函数。\n // 你可以写多个函数在这里,但是这里的函数的作用域只限在这个子组件中。\n showInfo (title) {\n console.log(title)\n }\n }\n })\n \n // new Component()是将上面构建的组件对象给实例化,\n // $mount()是将实例化的组件进行手动挂载,\n // 将虚拟dom生成出实际渲染的dom\n // 这里的markedComponent是完成挂载以后的子组件\n const markedComponent = new Component().$mount()\n \n // 将挂载以后的子组件dom插入到父组件中\n // markedComponent.$el就是挂载后生成的渲染dom\n this.$refs['markedContent'].appendChild(markedComponent.$el)\n }\n }\n // 本质上来讲,这个子组件不是任何组件的子组件,\n // 它是由vue直接在全局动态生成的一个匿名组件然后将它插入到当前位置的。\n // 也正是因此,它才能够完成动态的生成和添加。\n}\n</script>\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_13",
"question": "怎么判断一个数组里是否嵌套子数组\n我怎么判断一个数组是不是双层呢判断后返回true和false,比如[1,1,1,1]就是false[1,[2,2,2],1,1,1]就是true,有啥方法么,如果是三层,怎么判断呢",
"answer": "`isDeepThen()` 用来判断最大深度是否超出指定 level`getMaxDeep()` 用来获取最大深度。都是递归实现。两个函数没有直接关系,只是用来干不同的事情。\n```\nconst cases = [\n [1, [2, [3, [4], [5]]]],\n [1, [2, [3]]],\n [2, [2, 3]],\n [1, 2, 4],\n 1\n];\n\n// 检查最大深度是否超过指定 level如果 level 传 0 表示只要是数组就行\n// 可以通过 getMaxDeep() 来判断,但是 getMaxDeep() 会遍历所有项,效率较低\n// isDeepThen() 有快递中断机制\nfunction isDeeperThen(arr, level = 0) {\n // 不是数数组,肯定是 false\n if (!Array.isArray(arr)) { return false; }\n // 如果是数组,层次肯定大于 0\n if (level === 0) { return true; }\n\n // 找到所有数组元素进行递归检查\n return arr.filter(el => Array.isArray(el)).some(el => isDeeperThen(el, level - 1));\n}\n\n// 获取最大深度(与上面那个 isDeepThen() 没关系)\nfunction getMaxDeep(arr) {\n // 不是数组,深度为 0\n if (!Array.isArray(arr)) {\n return 0;\n }\n\n // 是数组,深度 + 1具体是多深还要递归判断元素中的数组\n return 1 + Math.max(...arr.map(el => getMaxDeep(el)));\n}\n\ncases.forEach(data => {\n console.log(\n isDeeperThen(data, 2).toString().padEnd(6, \" \"),\n getMaxDeep(data),\n JSON.stringify(data)\n );\n});\n```\n```\ntrue 4 [1,[2,[3,[4],[5]]]]\ntrue 3 [1,[2,[3]]]\nfalse 2 [2,[2,3]]\nfalse 1 [1,2,4]\nfalse 0 1\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_14",
"question": "Mysql 为什么要有最左前缀的要求,优化器不能自己优化调整顺序吗\n比如一个联合索引 `index('user_id', 'created_at')` ,我写了下面的 `SQL` 语句\n```\nselect\n *\nfrom\n tweet\nwhere\n created_at < '2021-11-11'\n and user_id = 1\n```\n优化器会把上面的语句优化为下面的语句吗\n```\nselect\n *\nfrom\n tweet\nwhere\n user_id = 1\n and created_at < '2021-11-11'\n```",
"answer": "你对左前缀理解错了。\n你这种情况是可以用到索引的。\n左前缀是指这种情况走不了索引\n```\nselect\n *\nfrom\n tweet\nwhere\n created_at < '2021-11-11'\n```\n而这种情况可以\n```\nselect\n *\nfrom\n tweet\nwhere\n user_id = 1\n```\n因为 `user_id` 在联合索引的左边。\n如果有索引 (a, b, c) 那么 `where a, b, c`、`where a, b`、`where a` where 后的顺序无关,可以随意组合,但是跟出现的字段有关)都是可以走到索引的。但是 `where b, c` 就不走索引了,因为按照左前缀原则,这里必须要出现 `a` 才行。\n使用如下。\n上表中第二行`a, c` 虽然是联合索引`(a, b, c)` 中有两个字段,但是因为这里没有出现 `b`,按照做前缀原则就断开了,所以只能使用到 `a`\n注意上文中 where 顺序可以随意组装,比如 `a, b, c` 你可以写成 `a, c, b`、 `c, a, b` 等,这些都不影响,但是出现的字段必须是上面写到的。\n除了 where 外,还有 order。\n`where a order c` 这个就只会用到 (a, b, c) 中的 `(a)` ,而如果是 `where a order b` 则能用到 `(a, b)`",
"type": "technical_qa"
},
{
"id": "segmentfault_15",
"question": "请问大家,这个小算法问题,怎么改?\n[\n```\n{\n \"categoryId\": \"373\",\n \"parentId\": \"3\",\n \"categoryName\": \"张三\",\n \"sunCategorys\": [\n {\n \"categoryId\": \"374\",\n \"parentId\": \"373\",\n \"categoryName\": \"张三一\",\n },\n {\n \"categoryId\": \"375\",\n \"parentId\": \"373\",\n \"categoryName\": \"张三二\",\n }\n ]\n},\n{\n \"categoryId\": \"374\",\n \"parentId\": \"3\",\n \"categoryName\": \"李四\",\n \"sunCategorys\": [\n {\n \"categoryId\": \"375\",\n \"parentId\": \"374\",\n \"categoryName\": \"李四一\",\n },\n {\n \"categoryId\": \"376\",\n \"parentId\": \"374\",\n \"categoryName\": \"李四二\",\n }\n ]\n}\n```\n]\n我想把上面数据的categoryName 和 sunCategorys里面的categoryNamecategoryId的id的值取出来组合成这样的形式请问应该如何去写\n[\n```\n{\n \"text\": \"张三\",\n \"children\": [\n {\n \"text\": \"张三一\",\n \"id\": 374\n },\n {\n \"text\": \"张三二\",\n \"id\": 375\n }\n ]\n},\n{\n \"text\": \"李四\",\n \"children\": [\n {\n \"text\": \"李四一\",\n \"id\": 375\n },\n {\n \"text\": \"李四二\",\n \"id\": 376\n }\n ]\n}\n```\n]",
"answer": "```\nconst result = data.map((item) => ({\n text: item.categoryName,\n children: item.sunCategorys.map((category) => ({\n text: category.categoryName,\n id: category.categoryId,\n })),\n}));\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_16",
"question": "vue的nextTick为什么一定会比promise更先执行\nnextTick内部打比按照promise进行那么是怎么做到比逻辑中的promise更早执行的看源码写的是Promise.resolve().then(callback)执行回调代码callback\n```\nif (typeof Promise !== 'undefined' && isNative(Promise)) {\n const p = Promise.resolve()\n timerFunc = () => {\n p.then(flushCallbacks)\n // In problematic UIWebViews, Promise.then doesn't completely break, but\n // it can get stuck in a weird state where callbacks are pushed into the\n // microtask queue but the queue isn't being flushed, until the browser\n // needs to do some other work, e.g. handle a timer. Therefore we can\n // \"force\" the microtask queue to be flushed by adding an empty timer.\n if (isIOS) setTimeout(noop)\n }\n isUsingMicroTask = true\n} \n```",
"answer": "首先我不知道您是怎么得出一定这个结果的nextTick并不一定比Promise快它本来就是Promise就得遵循Promise的规范和顺序但是nextTick是对Promise的封装所以\n```\nnextTick(fn1) // Promise\nnextTick(fn2)\nnextTick(fn3)\n```\n实际上就初始化了一个Promise就在第一个nextTick执行的时候\n后面调用的fn2,fn3可以理解为都是往第一个fn1函数里push的所以下面的执行顺序就是fn1 fn2 fn3 fn4因为fn1 fn2 fn3合并为了一个函数就造成了 fn2 和fn3比fn4快\n```\nnextTick(fn1) // Promise1\nPromise.resolve().then(fn4) // Promise2\nnextTick(fn2)\nnextTick(fn3)\n```\n自始至终只有2个Promise 第一次执行nextTick的fn1和fn4因为fn1声明在fn4之前所以fn1比fn4快\n这只限于同一个事件循环在下一次事件循环第一次执行nextTick依然会有一个新的Promise",
"type": "technical_qa"
},
{
"id": "segmentfault_17",
"question": "在 JavaScript 中,如何实现 const a = [...5] 就可以创建一个 [1, 2, 3, 4, 5] 数组\n如何实现在编写 JavaScript 项目时,可以以下面这样的方式,创建一个新的数组:\n```\nconst a = [...5];\n\n// a = [1, 2, 3, 4, 5];\n```",
"answer": "```\nNumber.prototype[Symbol.iterator] = function () {\n const i = +this;\n let value = 0;\n return {\n next() {\n value += 1;\n return {done: value > i, value};\n }\n };\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_18",
"question": "请问 prettier 与 EditorConfig 功能是不是重复了?\nprettier 与 EditorConfig 都是代码格式化工具,他们到底有什么区别?我只知道他们的配置文件不同,一个是.prettierrc文件而另外一个是.editorconfig文件但感觉他们功能一样在网上看别人教程为何都是两个一起使用的不是功能重复了吗求解答",
"answer": "EditorConfig 格式化的是比较基础的东西基本上你用“Editor”编辑器本身能干的操作就可以用它来干。比如 Tab 变几个空格啊、换行符是 CR 还是 CRLF 啊、文件编码是不是 UTF-8 啊这种的。\n而且它不只局限于格式化名字也能看出来是“Config”配置而不是“Formatter”格式化器。你也可以用它来配置诸如让 IDE 忽略特定的编译警告错误之类的。\n所以你会发现它跟编程语言本身没什么关系各个语言的项目都能看到 `.editorconfig` 的身影,它更多地干的是当你用特定 IDE 时能配置的那些东西,好让那些不用这个 IDE 的、或者它 IDE 配置跟你不一样的开发者也能使用相同的编辑器方案。当然了它确实可以通过插件的形式去支持一些其他语言特有的格式化方案,不过并不常用。\n而 Prettier 是 JS 特有的格式化工具,里面很多配置项是 JS 这门语言特有的规范。\n总体来说二者有重叠的部分但大部分并不相同。所以前端项目往往两者都有非要只选一个的话选 Prettier 而不是 EditorConfig。",
"type": "technical_qa"
},
{
"id": "segmentfault_19",
"question": "请求返回的是 字符串 格式的 js代码我要怎么 import 到内部的 模块呢\n手动@大佬回答 @边城 \n如题 后端接口返回给我的是\n字符串格式的\n```\nvar a = 1\nfunction setA(v){\n a = v\n}\nexport function getA(){\n return a\n}\n```\n我要怎么 `import` 到内部的 `getA` 模块呢\n使用的 `vue`",
"answer": "https://stackoverflow.com/que...\n```\n<script type=\"module\">\nconst code = `\nvar a = 1\nfunction setA(v){\n a = v\n}\nexport function getA(){\n return a\n}\n`;\nconst objectURL = URL.createObjectURL(new Blob([code], { type: 'text/javascript' }));\nconst module = await import(objectURL);\nconsole.log(module.getA());\n</script>\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_20",
"question": "vue怎么监听数组项\n如下数组其中ccc属性值根据bbb属性和ddd属性计算得到的我需要监听数据项的变化动态计算ccc属性值\n```\n export default {\n data() {\n return {\n aaa: [{\n bbb: \"xxx\",\n ddd: \"xxx\",\n ccc: \"\"\n }, {\n bbb: \"yyy\",\n ddd: \"yyy\",\n ccc: \"\"\n }]\n }\n }\n \n }\n\n```\n于是我使用了watch监听\n```\n watch: {\n aaa: {\n deep: true,\n handler(newValue, oldValue) {\n for (let i = 0; i < newValue.length; i++) {\n newValue[i].ccc = newValue[i].bbb + newValue[i].ddd;\n }\n }\n }\n }\n```\n这种方法会导致每个数据项的变动需要所有数据项都计算一次有没有什么好的方式\n而且还有个问题监听数组并没法获取到旧值也就是newValue和oldValue是一模一样的都是新的值。\n这个问题主要是讨论性能问题比如每个数组有100个属性项又或者ccc是通过耗性能的计算得到的那么每次数据项的变动都导致所有数据项重新计算一次这耗费的性能不可想象所以大家可以想一下看有没有好的实现方案?? 实现目标是只对变动的数据项进行计算",
"answer": "```\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <title>JS Bin</title>\n</head>\n<body>\n <div id=\"app\">\n <div v-for=\"v of list\">\n <input type=\"number\" v-model=\"v.a\">\n <input type=\"number\" v-model=\"v.b\">\n <span>sum: {{v|sum}}</span>\n <span>和:{{v.c}}</span>\n </div>\n </div>\n<script src=\"https://cdn.staticfile.org/vue/2.6.13/vue.min.js\"></script>\n <script>\n new Vue({\n el: '#app',\n filters: {\n sum: item => +item.a + (+item.b)\n },\n data: {\n list: [{\n a: 1,\n b: 2,\n get c() {\n return +this.a + (+this.b)\n }\n }, {\n a: 3,\n b: 4,\n get c() {\n return +this.a + (+this.b)\n }\n }]\n }\n })\n </script>\n</body>\n</html>\n```\n比较简单的方式——过滤器或者直接定义一个getter\n还有一个方式就是将动态计算显示的那个属性抽成组件传入props通过vue的computed去计算和直接在数据上定义getter原理上是一样的",
"type": "technical_qa"
},
{
"id": "segmentfault_21",
"question": "JS的onclick在Chrome和Safari中均不能被触发\n写了一段很简单的源码就是最基本的使用 <button> 触发事件:\nHTML 源码如下:\n```\n<body>\n <button>Click this button to trigger an event</button>\n</body>\n\n<script src=\"Event.js\"></script>\n```\nJS 源码如下:\n```\nvar btn = document.getElementsByTagName(\"button\")\nbtn.onclick = function () {\n alert(\"Successfully Triggered an Event !\");\n console.log(\"Good\");\n}\n```\n在浏览器中解析后调试时发现 btn 中选择到了 <button> 元素,而且也被赋值了。但是点击 <button> 按钮却没有反应,即没有出现 alert 对话框,控制台也没有显示 “Good”。这是为什么啊 ",
"answer": "因为getElementsByTagName获取的是元素集合不是元素本身所以你需要先从这个集合中取到元素再进行绑定\n```\nvar btns = document.getElementsByTagName(\"button\")\n// 或者使用遍历,需要注意它是一个为数组,不能直接当数组进行遍历 \nbtns[0].onclick = function () {\n alert(\"Successfully Triggered an Event !\");\n console.log(\"Good\");\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_22",
"question": "JS排序问题(凑满减)\n```\nconst list =[\n {title:'苹果',price:1},\n {title:'香蕉',price:4},\n {title:'鸭梨',price:3},\n {title:'西瓜',price:5},\n {title:'山竹',price:2}];\n```\n我想排序, 按照price大于3的正序, 然后再把小于3的倒序, 排在大于的数据后面, 求最优算法.\n期望如下:\n```\nconst list =[\n {title:'香蕉',price:4},\n {title:'西瓜',price:5},\n {title:'鸭梨',price:3},\n {title:'山竹',price:2},\n {title:'苹果',price:1}];\n```",
"answer": "```\nlist.sort((a, b) => {\n if(a.price > 3 && b.price > 3){\n return a.price - b.price\n }\n return b.price - a.price\n})\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_23",
"question": "if判断是否有值但是这个值为0它也判了不过请问怎么写呢\n```\n // row保存\n saveRow (record) {\n const { num, id } = record \n if (!num) { // 这里为0也走了怎么判断单纯有没有值\n this.tableLoading = false\n this.$message.error('请填写完整信息。')\n return\n }\n },\n```",
"answer": "这里先要搞明白 `num` 允许是哪些值。如果只能是数字的话,可以这样\n```\nif (typeof num === \"number\") { ... }\n```\n不过这样的话`num` 还有可能是 `NaN`,一般 `NaN` 也需要过滤掉(要不要过滤看业务),所以\n```\nif (typeof num === \"number\" && !isNaN(num)) { ... }\n```\n接下来如果逻辑可以保证 `num` 只会是数字,或者空(含 `undefined`),那么可以这样判断\n```\nif (!(num === undefined || num === null || isNaN(num))) { ... }\n```\n如果用新语法 Nullish Coalescing会简单一些\n```\nif (!isNaN(num ?? NaN)) { ... }\n```\n如果 `NaN` 算是合法的,那就得找个不应该出现的值(只能是一个非数字值了,幸好 JS 不绑定类型)\n```\n// if (num ?? false !== false) { ... }\n// 修改一下,用 null 语义上更舒服一些\nif (num ?? null !== null) { ... }\n```\n更复杂的情况如果 `\"1234\"` (表示数的字符串)这种也算合法,还是老实的用 `typeof` 吧\n```\n// 代码没测试,小心使用\n// 假设 NaN 不合法\nfunction isValudNum(num) {\n switch (typeof num) {\n case \"string\":\n num = parseInt(num, 10);\n // 如果可能是浮点数用 parseFloat\n // 这里不加 break需要穿透下去判断 isNaN\n case \"number\":\n return !isNaN(num);\n default:\n return false;\n }\n}\n```\n如果 `NaN` 也合法,处理 `\"string\"` 类型的时候会更伤心,因为需要先判断是否数字,用正则表达式判断\n```\ncase \"string\":\n return /^\\d+$/.test(num);\n // 如果要判断浮点数\n // return /^\\d+(?:\\.\\d+)?$/.test(num);\n```\n当然如果只是做数字判断的话`NaN` 不合法的情况下,用下面这个 `case \"string\"` 代替上面那个也是没问题的。",
"type": "technical_qa"
},
{
"id": "segmentfault_24",
"question": "定义一个数组,调用方法报错\n通过不同方式定义一个数组直接调用方法报错\n感觉可能和js自动装包有点关系\n但是每种情况报错文案还不太一样\n为什么借用一个变量就ok了 \n它们内部机制是什么求大佬详细讲解下\n```\nconst a = 1\nconst b = 2\n[a,b].forEach(e => {\n console.log(e);\n});\n\n//VM409:3 Uncaught ReferenceError: Cannot access 'b' before initialization\n```\n```\nlet a = 1\nlet b = 2\n[a,b].forEach(e => {\n console.log(e);\n});\n\n//ReferenceError: b is not defined\n```\n```\nvar a = 1\nvar b = 2\n[a,b].forEach(e => {\n console.log(e);\n});\n\n//VM409:3 VM480:3 Uncaught TypeError: Cannot read property 'forEach' of undefined\n```\n```\nconst a = 1\nconst b = 2\nconst arr = [a,b]\narr.forEach(e => {\n console.log(e);\n});\n\n//1,2 执行成功\n```\n```\nconst a = 1\nconst b = 2\nconst fn = (e)=>{\n console.log(e);\n}\n[a,b].forEach(fn);\n\n//1,2 执行成功\n```",
"answer": "少写了分号\n每一行最后都加上分号\nconst a = 1;\nconst b = 2;\n分号会和下一行的 [ 连在一起\n相当于\n```\nconst b = 2[a,b].forEach(e => {\n console.log(e);\n});\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_25",
"question": "问个java很白痴的问题\n为什么`String`类型是大写的 别的类型都是小写的?",
"answer": "小写的应该是基本类型。Java 基本类型只有 8 种,这 8 种类型不是类类型,但有对应的类类型\n- `byte` ⇔ `java.lang.Byte`\n- `short` ⇔ `java.lang.Short`\n- `int` ⇔ `java.lang.Integer`\n- `long` ⇔ `java.lang.Long`\n- `float` ⇔ `java.lang.Float`\n- `double` ⇔ `java.lang.Double`\n- `boolean` ⇔ `java.lang.Boolean`\n- `char` ⇔ `java.lang.Character`\n\n基本类型不是类也不会在任何包里。其他类型都是类或接口类型。\n`String` 全名 `java.lang.String`,是一个类。\n按 Java 的开发规范,类名是按 Pascal 风格命名,也就是组成类名的每个单词首字母大写,其他字符小写的命名风格。",
"type": "technical_qa"
},
{
"id": "segmentfault_26",
"question": "for...of 循环含有辅助平面字符的字符串,输出让我感到困惑\n## 代码\n```\nlet count = 0,\n s = \"𠮷a\";\nfor(let i of s){\n count ++;\n console.log(i);\n}\nfor...of 输出:𠮷 a\nconsole.log(count);//2\nconsole.log(s.length);//3\n```\n## 疑惑的地方\n1、字符串s的length为3循环次数是2次我用for循环测试循环次数是3\n次。\n2、for...of在循环中做了那些事情导致循环次数少了一次",
"answer": "Javascript 采用 Unicode字符集在 UTF-16 之前使用的是 UCS-2 编码该编码方法使用2个字节表示字符基本平面字符。\nUTF-16 编码发布后UCS-2 被整合进 UTF-16基本平面字符仍用2个字节辅助平面字符使用4个字节表示。\n因此Javascript 的字符操作函数在处理4个字节的字符时会当成两个双字节的字符处理从而无法返回正确的结果。\n```\ns.slice(0, 1) // <20>\ns.substr(0, 1) // <20>\ns.charAt(0) // \\uD842\n```\n\"𠮷\" 的 UTF-16 编码是4个字节的 `0xD842 DFB7`而4个字节的字符不属于 UCS-2编码javascript 会将其识别为`U+D842`和`U+DFB7` 两个字符(在基本平面内,`U+D800` 到 `U+DFFF` 是一个空段,不对应任何字符)\nES6 增强了 Unicode 支持可以识别4字节的字符。除了`for...of`,还有以下方法\n```\ns.codePointAt(0).toString(16) // 20bb7\ns.at(0) // 𠮷\nString.fromCodePoint(\"0x20BB7\") // 𠮷\n```\n`length` 属性返回字符串中字符编码单元的数量,所以也可能与实际的字符数量不相同。\n想要返回字符串的正确长度可以使用 `Array.from(string).length`",
"type": "technical_qa"
},
{
"id": "segmentfault_27",
"question": "CSRF攻击者是如何向网站注入欺诈链接的\n我明白CSRF的运作过程但想不出来攻击者是如何在目标网站注入欺诈链接来骗用户点击的",
"answer": "比如这个 看似人畜无害的链接,就可以把人从思否诱导到一条不归之路[手动狗头],这里利用的原理是只要构造出合适的 URL 就可以发起百度搜索,仅此而已,但是你跳过去之后,浏览器会把本地的 `Cookie` 给你带上,百度后台就会认为是你本人在搜这种奇怪的东西,换成字节搜索的话,没准明天你的抖音就会刷到震撼的短视频了。\n这个例子只是一个不怀好意的诱导还算不上攻击因为百度搜索的这个特点不算什么漏洞。但是如果某个银行的转账接口也是在 URL 里拼参数的话,那可就危险了:如果用户恰好登过这个银行的网页,`Cookie` 还在,那么只要构造一条转账的 `URL`,找机会让用户去点,就能神不知鬼不觉地把用户的钱拿到手。\n那么我有没有在百度的网站注入任何东西没有。所以对于要攻击的目标网站我们是不需要注入任何东西的只要找到他的 CSRF 漏洞就行。\n- 我们真正需要“注入”的,是这条链接,我这里写回答其实就已经成功“注入”了,因此,假如你发现了某个网站有这种明显的 CSRF 漏洞的话,你只需要在这里提个问题,夹带私货,然后静候猎物上钩。\n- 有些时候我们需要使用更高档的手段,比如构造表单,那么这里的跳转链接显然是不够用的,这时候如果思否有 XSS 漏洞可以注入长的 html 片段的话,那么可以在这个 html 片段里构造表单,由于 XSS 的存在,我们已经不需要用户点击来发起攻击了。(思否在几个月前貌似真的有 XSS ,参见这个问题,这里我说的是“貌似”,因为当我打算验证的时候已经无法复现了,不知道他们是不是恶搞)\n- 除此之外,我们还可以给用户发带链接的钓鱼短信,或者在钓鱼邮件里放一个名为“船新艳照门.avi.html”的静态文件……",
"type": "technical_qa"
},
{
"id": "segmentfault_28",
"question": "js简写能不能用一行写出来\n看注释希望能用一句写出来有没有这种简便写法\n```\nconst t = [\n {name: 'John', value: 111},\n {name: 'Mary', value: 222}\n];\n\nconst param = t.reduce((p, n) => {\n // 这儿能不能用一行写出来,类似于这样 t.map(k => k.child);\n p[n.name] = n.value;\n return p;\n}, {})\n```",
"answer": "```\nconst t = [\n {name: 'John', value: 111},\n {name: 'Mary', value: 222}\n];\nconst param = t.reduce((p, n) => (p[n.name] = n.value,p), {})\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_29",
"question": "TypeScript怎么实现接口的重载入\n### 题目描述\nTS中是怎么实现接口的重载入\n### 相关代码\n```\ntype ItemProps = {\n a: string;\n b?: boolean;\n c?: string; \n}\n\nconst arr: ItemProps[] = [\n {\n a: 'demo',\n b: true,\n c: 'test'\n },\n {\n a: 'demo2'\n }\n]\n```\n在上面定义中怎么定义`ItemProps`类型才能达到: 如果`b`属性存在,则`c`属性必需存在 的效果\n### 期待结果\n```\nconst arr: ItemProps[] = [\n {\n a: 'demo',\n b: true,\n c: 'test'\n },\n {\n a: 'demo2',\n b: true, // 类型报错因为存在b属性但是缺少c\n } \n]; \n```",
"answer": "```\ntype ExcludeKeys<T> = { [P in keyof T]: never; }\n\ntype RequireOrExcludeKeys<T, Keys extends keyof T = keyof T> =\n Pick<T, Exclude<keyof T, Keys>>\n & (Required<Pick<T, Keys>> | ExcludeKeys<Pick<T, Keys>>)\n\ntype ItemProps = RequireOrExcludeKeys<{\n a: string;\n b?: boolean;\n c?: string;\n}, 'b' | 'c'>\n```\nPlayground\n把条件改成`如果b属性存在则c必须存在但是c属性存在b可以不存在。`\n总结一下就是 c 必须存在b 可选存在。\n只要修改下`RequireOrExcludeKeys`的参数,以及`Required<Pick<T, Keys>>`。\n```\ntype RequireOrExcludeKeys<T, RequireKeys extends keyof T = keyof T, PartialKeys extends keyof T = keyof T> =\n Pick<T, Exclude<keyof T, RequireKeys>>\n & ((Required<Pick<T, RequireKeys>> & Partial<Pick<T, PartialKeys>>)\n | ExcludeKeys<Pick<T, RequireKeys | PartialKeys>>)\n\ntype ItemProps = RequireOrExcludeKeys<{\n a: string;\n b?: boolean;\n c?: string;\n}, 'c', 'b'>\n```\nPlayground",
"type": "technical_qa"
},
{
"id": "segmentfault_30",
"question": "请问如何将监听事件改为promise的形式\n现在的代码结构是这样\n```\nfunction receiver(type, callback) {\n document.addEventListener(type, (ev) => {\n callback(ev);\n });\n}\n```\n然后通过回调函数来执行\n```\nreceiver('click', (ev) => {\n console.log(ev)\n})\n```\n现在想改为promise的形式\n```\nreceiver('click').then(ev => {\n console.log(ev)\n})\n```\n请问需要怎么修改",
"answer": "Promise就像一个状态机而且是一个状态不可逆的状态机这就意味它只会在到达Fullfiled或者Rejected状态时会执行你注册的函数所以用Promise实现是不合适的\n但是可以写成这样以达成相似效果\n```\nfunction receiver(type) {\n const listeners = [];\n\n const listen = {\n then(callback) {\n listeners.push(callback);\n\n return listen;\n }\n };\n document.addEventListener(type, async (ev) => {\n let acc = ev;\n for (let i = 0; i < listeners.length; ++i) {\n acc = await listeners[i](acc);\n }\n });\n\n return listen;\n}\n\nreceiver(\"click\")\n .then((e) => {\n console.log(e);\n\n return 1;\n })\n .then((v) => {\n console.log(v);\n });\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_31",
"question": "$nextTick和setTimeout有什么区别\n①$nextTick和setTimeout有什么区别\n②在实际项目中使用两者哪个会好点没有优缺点之类的需要注意什么\n在实际项目中遇到元素还没渲染出来就执行了事件甚至是有些接口先调用了\n除了这种延时调用的方法还有更好的解决方案嘛\n大神们求解",
"answer": "`nextTick`:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。\n`setTimeout`:只是延迟执行,在延迟执行的方法里,`DOM`有可能会更新也有可能没有更新。\n常规做法就是延迟500ms或者1s\n建议使用`nextTick`在有涉及`DOM`更新的场景",
"type": "technical_qa"
},
{
"id": "segmentfault_32",
"question": "在js中执行顺序\n在js中假设执行五万条log(1)需要5秒钟在这个js中的第一行写个setTimeout一秒后执行log(2)这个log(2)是一秒后执行还是log(1)执行完以后再执行?",
"answer": "- log(1)执行完以后再执行。这里涉及到浏览器端的js事件循环机制。js代码由上到下执行在调用栈里面执行。\n- 执行到setTimeout函数是宏任务放到回调队列里面。\n- 然后继续执行调用栈里面的代码五万条log(1),是同步任务,在调用栈里面执行,一条一条先进先出。\n- 等到过了1秒后setTimeout函数执行完。但是此时的调用栈还没有空继续等待等到5秒后调用栈空了就会执行回调队列里面的任务。此时打印log(2)\n- 附上js事件循环的链接https://segmentfault.com/a/11...",
"type": "technical_qa"
},
{
"id": "segmentfault_33",
"question": "网站如何检测到是否开启开发者工具?\nhttp://211.149.185.229:8080/l...\n上面这个网站打开开发者工具就会跳转到错误页面请问如何做到的",
"answer": "```\n! function(e) {\n var im = new Image();\n Object.defineProperty(im, 'id', {\n get: function() {\n window.location.href = \"http://106.53.103.200:8082/error.html\"\n blast();\n }\n });\n console.log(im); //谷歌最新版失效\n\n\n let num = 0; //谷歌最新版有效\n var devtools = new Date();\n devtools.toString = function() {\n num++;\n if (num > 1) {\n window.location.href = \"http://106.53.103.200:8082/error.html\"\n blast();\n }\n }\n console.log('', devtools);\n\n function blast() {\n var t = \"\";\n for (var i = 0; i < 1000000; i++) {\n t = t + i.toString();\n history.pushState(0, 0, t);\n }\n }\n\n //Edge浏览器 上面的代码会失效 强制使用谷歌浏览器\n function detectIE() {\n var ua = window.navigator.userAgent;\n\n var msie = ua.indexOf('MSIE ');\n if (msie > 0) {\n return true;\n }\n\n var trident = ua.indexOf('Trident/');\n if (trident > 0) {\n return true;\n }\n\n var edge = ua.indexOf('Edge/');\n if (edge > 0) {\n return true\n }\n\n edge = ua.indexOf('Edg/');\n if (edge > 0) {\n return true;\n }\n return false;\n }\n\n if (detectIE()) {\n window.location.href = \"http://106.53.103.200:8082/error.html\"\n setTimeout(() => {\n blast();\n }, 10);\n }\n\n //检测是否为谷歌浏览器\n if (navigator.userAgent.toLowerCase().indexOf(\"chrome\") == -1) {       \n window.location.href = \"http://106.53.103.200:8082/error.html\"\n setTimeout(() => {\n blast();\n }, 10); \n } else {  }\n var c = window.webpackJsonp;\n window.webpackJsonp = function(d, b, n) {\n for (var t, r, o, i = 0, u = []; i < d.length; i++) r = d[i], f[r] && u.push(f[r][0]), f[r] = 0;\n for (t in b) Object.prototype.hasOwnProperty.call(b, t) && (e[t] = b[t]);\n for (c && c(d, b, n); u.length;) u.shift()();\n if (n)\n for (i = 0; i < n.length; i++) o = a(a.s = n[i]);\n return o\n };\n var d = {},\n f = { 175: 0 };\n\n function a(c) { if (d[c]) return d[c].exports; var f = d[c] = { i: c, l: !1, exports: {} }; return e[c].call(f.exports, f, f.exports, a), f.l = !0, f.exports }\n a.e = function(e) {\n var c = f[e];\n if (0 === c) return new Promise(function(e) { e() });\n if (c) return c[2];\n var d = new Promise(function(d, a) { c = f[e] = [d, a] });\n c[2] = d;\n var b = document.getElementsByTagName(\"head\")[0],\n n = document.createElement(\"script\");\n n.type = \"text/javascript\", n.charset = \"utf-8\", n.async = !0, n.timeout = 12e4, a.nc && n.setAttribute(\"nonce\", a.nc), n.src = a.p + \"static/js/\" + e + \".\" + { 0: \"58343593b3d635f094d3\", 1: \"170c868fc04dc19762d3\", 2: \"6322f0e8edf9be188074\", 3: \"a1765a9449d25d8ddb73\", 4: \"ed0444d9d4f4d8149166\", 5: \"7048b6cbe04f821a7a57\", 6: \"495809735f0567a06ca1\", 7: \"738518b8623f4daf2074\", 8: \"79e3d52c44ffa6e8db72\", 9: \"a42e342b0c6f4725d697\", 10: \"bd8fd2f85a336d87353a\", 11: \"c8a67a0677f81467ec03\", 12: \"54de84073c1d84cd86cc\", 13: \"894d2b586f4095d2951b\", 14: \"397a9e269db52d1023f4\", 15: \"ef0c5bfb2fe0d8e27596\", 16: \"990f7536c4c670812e94\", 17: \"f61d23aa6811e2b6c2b2\", 18: \"d8e024c526c32d89746c\", 19: \"469e1ee9b2b29738d202\", 20: \"72235ed53624d56e9dde\", 21: \"6df2e36e5339091e31e3\", 22: \"f162799068649251188b\", 23: \"5b8b8ff7e684c0cb5d79\", 24: \"64be717ceb6afba77309\", 25: \"088fa84830e259e9b699\", 26: \"aed0acc26d0fd6e92ad5\", 27: \"58b1890f11318d66a663\", 28: \"6d32344a9d8ba9283e6a\", 29: \"010b33fb0451752cff2f\", 30: \"91edfc7808d4638d1bd1\", 31: \"c6918881d2dbed3eed07\", 32: \"8a8ccafada824bbde814\", 33: \"6f53001b1477280a0ec6\", 34: \"ec05d3ad70f32aa7289f\", 35: \"caac8c518ca14e0cb874\", 36: \"11061379750eb66c4f59\", 37: \"77295ebca55081d2ec2f\", 38: \"5456a10cd94755b27aae\", 39: \"5689270ec30af56ad400\", 40: \"6de5db58505e1dab0223\", 41: \"b16cfbea9e7e02d080e3\", 42: \"43a27e8106b175fd53ad\", 43: \"9df557d28c6c29f51c0b\", 44: \"01838c136f2d6d55ac31\", 45: \"8c7b2c7d30cbf29b643e\", 46: \"78913abc65343ebf4994\", 47: \"7700b7dc766b55ffbc16\", 48: \"8e8a6d1339721da8b366\", 49: \"8e373f9d1e9dae1a6fe7\", 50: \"5afc9202d9c115b2c40b\", 51: \"bc0f76028a37185daefe\", 52: \"103168ac49d236a36b29\", 53: \"347171c80257cafe1b33\", 54: \"6678a67dda9322ae2936\", 55: \"49850b7ce833695528f7\", 56: \"efc9c891bfc8ae2fad9e\", 57: \"743d15b6904c27d77207\", 58: \"f2a1e5ae299ef04c8cd5\", 59: \"21aea718b2f9ca1db661\", 60: \"cef6df04114296b9974d\", 61: \"0296b1428d8c122359df\", 62: \"45d3c1468e5117fcf4fe\", 63: \"458399e2b989c5f149f5\", 64: \"36b5e68c12bc3ace7d90\", 65: \"5e9bab27de8bb58e707f\", 66: \"9912d8c2a8dc47f32775\", 67: \"e281bd6382c275178ce7\", 68: \"ffb3ec8139adb33f53e6\", 69: \"26f47842b920dd4983b7\", 70: \"662d83087db196bd5e3f\", 71: \"01a19190c8aea8990055\", 72: \"30307fa4279c5e560958\", 73: \"27127048e6f66da6d933\", 74: \"73150b35cf3b34648ed2\", 75: \"fff965257715c93c8573\", 76: \"180088d1dc722196c0a9\", 77: \"4207a6c03d7eb6426fce\", 78: \"6ed6e5b5e96c9682ea6b\", 79: \"5ba6d6e0660806f434fe\", 80: \"bb50103d7dbda5be716e\", 81: \"3564f0e2ddfa1370aac8\", 82: \"74736b83a6e4371d3f1e\", 83: \"161367c1bf7e27ce069b\", 84: \"0deb5f3a187b095fc40d\", 85: \"6f96c6dcd9b446bcc759\", 86: \"f50b8f40838f9d73d905\", 87: \"7a6f3b17c7ef2ee130d5\", 88: \"f46a8c81a9e598513ae3\", 89: \"a7298ec9951747867ea6\", 90: \"48923a48caf18819b6ec\", 91: \"da17aed35f252405dd00\", 92: \"4b1e57c0a70fa8bfdcac\", 93: \"bca78005f6cece4f1cd5\", 94: \"781326c90af1a0bfd8dd\", 95: \"a6c2a4c1399295f27ace\", 96: \"7c52a8be6d4adf2f2146\", 97: \"59a8a8be872520f18af7\", 98: \"aba4cd370bc1e3991be9\", 99: \"1a731fc2affe5749156f\", 100: \"c8aba78e75829c835a09\", 101: \"b6636cc981e819992644\", 102: \"a353a3afc73cde1a7130\", 103: \"0520f0d8f51ef368fa50\", 104: \"6891df789725d0327f7f\", 105: \"c1e429cb8be856847d26\", 106: \"1cf371af6b468076022d\", 107: \"467df05ae843f8668592\", 108: \"5790d6c8bffc4b03a1d0\", 109: \"79fc8184a7e35bde4219\", 110: \"398ba5ef8f1ffdc0d0cb\", 111: \"de3d07dbd9b31d4ed847\", 112: \"80e07142240fbb715434\", 113: \"73a8e8366c945be961a9\", 114: \"93925e229ab81ccb3e5b\", 115: \"2e293441a83ffe86bcb8\", 116: \"83107df1d930f497b98f\", 117: \"7762e2b0f0ae9a48dad9\", 118: \"75f91257356724b157ff\", 119: \"0b0883d29d32bd25c35a\", 120: \"2f32fa353d50a6cff06b\", 121: \"7b913bf843227d7a1385\", 122: \"3c4af8e79020b010985e\", 123: \"9b4be4993b7555f84777\", 124: \"5e54a3067200daf6df5f\", 125: \"f9d33ca889203a552021\", 126: \"6c3b7c7964b9d5ef01e8\", 127: \"5bed6c71750a494b5c8b\", 128: \"bfeb4143e9f823905e36\", 129: \"b0ef2fe8b570bed9e5a0\", 130: \"3387bd2baf111c88964f\", 131: \"409e1085f1dd22cd8cbc\", 132: \"87f68ef5e57346c2b975\", 133: \"ad3a1b8578bcf2a8f006\", 134: \"2cfd3557b778ebd98dda\", 135: \"e3abc3058f0ece43053f\", 136: \"9b350e70bda4fb870968\", 137: \"211fc449b8c9738c5c82\", 138: \"3d67cbb44e14672aca7d\", 139: \"8e6e6aecb40dc49ae68d\", 140: \"46f0da74cc22a6458932\", 141: \"0fe415cd7c0faaf37e69\", 142: \"4b1a9cd9051c11f5f5bd\", 143: \"a48dd7b05bf223f138ba\", 144: \"dd74194529a7dc01dc4b\", 145: \"1990bb83c72a69561bbe\", 146: \"7d2558f5f0f7e40c2334\", 147: \"d861da20e7121ebe7aab\", 148: \"5aad3befabda3a5c4964\", 149: \"196d5cc4e9b49d585146\", 150: \"b4c61be25d3eddb47129\", 151: \"9731a688a82462e0215b\", 152: \"69816786cdd282fc13e0\", 153: \"cf9e6f9c6a25cc4832fc\", 154: \"2118d9d0efff6879de56\", 155: \"4d6d3b7d615ace032558\", 156: \"47456d9dba64b4f28c33\", 157: \"ecff122d7bda8b03d8d5\", 158: \"b9fc20085a7592ea4ea9\", 159: \"ca444bbed61d53994c61\", 160: \"7b589bcf555ef5accd7f\", 161: \"133d5edbd54c87cc72e9\", 162: \"5255d1ac3955cf58b4b2\", 163: \"c6ae074fbbc68484b1e8\", 164: \"1540f755b68e060dcba3\", 165: \"6cb8f7a152e0a1bc552c\", 166: \"59563bc6615227e1d782\", 167: \"94a6298f099b6d62b3ca\", 168: \"311a767b2fe403f5279f\", 169: \"5c7869bce985f0c638f0\", 170: \"5afe2a69d3ff35faa2da\", 171: \"80651bd9df0e4b930cc1\", 172: \"4a46e51c63e2626300f7\" }[e] + \".js\";\n var t = setTimeout(r, 12e4);\n\n function r() {\n n.onerror = n.onload = null, clearTimeout(t);\n var c = f[e];\n 0 !== c && (c && c[1](new Error(\"Loading chunk \" + e + \" failed.\")), f[e] = void 0)\n }\n return n.onerror = n.onload = r, b.appendChild(n), d\n }, a.m = e, a.c = d, a.d = function(e, c, d) { a.o(e, c) || Object.defineProperty(e, c, { configurable: !1, enumerable: !0, get: d }) }, a.n = function(e) { var c = e && e.__esModule ? function() { return e.default } : function() { return e }; return a.d(c, \"a\", c), c }, a.o = function(e, c) { return Object.prototype.hasOwnProperty.call(e, c) }, a.p = \"/\", a.oe = function(e) { throw e }\n}([]);\n```\n直接右键保存本地down了一下。核心代码在这。",
"type": "technical_qa"
},
{
"id": "segmentfault_34",
"question": "js for循环以逗号拆分为新数组\n原数据格式↓\n```\nconst data = [{ name: 'apple', cut: 'a,b,c' }, { name: 'trigger', cut: 'a,g' }]\n```\n期望数据格式↓\n```\nconst data1 = [{ name: 'apple', final: 'a' },\n { name: 'apple', final: 'b' },\n { name: 'apple', final: 'c' },\n { name: 'trigger', final: 'a' },\n { name: 'trigger', final: 'g' }]\n```\n在原数据格式data中的cut字段用逗号来拆分为新字段finalname不变\n请教该如何操作",
"answer": "基本思路:把 `cut` 拆分之后进行一次映射,可以拿到每个原始对象对应的一个数组,组合起来就是一个二维数据;再把这个二维数据展开,就是你要的答案。\n`flatMap` 就是先映射再展开\n```\nconst data = [{ name: 'apple', cut: 'a,b,c' }, { name: 'trigger', cut: 'a,g' }];\n\nconst data1 = data.flatMap(it =>\n it.cut.split(\",\")\n .map(s => ({ name: it.name, final: s }))\n);\n\nconsole.log(data1);\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_35",
"question": "每日百万数据量的订单表如何导出到excel\n需求是这样的系统每日会产生上百万的成交订单客户需要每天导出一份给他们因此需要每天生成一份大数据量的excel。\n首先想到的就是在定时任务中通过for循环分页访问数据库然后分批导出到excel。但是for循环中访问数据库如果测试不充分或者程序有bug会导致频繁访问数据库会严重影响数据库的性能。其实在循环中访问数据库本来就是一种不好的习惯。\n有什么好的方案或者建议吗",
"answer": "我貌似get到了您的想法\n总得来说就是觉得数据已经存进去了但由于导出`excel`,需要再循环查询数据读出来,感觉有点\"多此一举\",这个多此一举导致了循环访问数据库,对此感到不安\n那我提供一种思路不一定能解决你的问题但是或多或少是一种思路叭\n即能不能在插入订单数据的同时也能发个通知也就是做个消息中间件这样消费者就是`execl`导出服务,读取消息直接此时就写入到`excel`中\n当然那肯定要准备一个消息中间件了看你百万的数据量肯定`kafka`没跑了,至于如何往`kafka`里扔消息,这里面有两种方案可以提供给你\n\n1. 在插入订单的代码中新增一个消息发布\n2. 做数据库的CDCChange data capture处理也就是数据库的数据变更捕捉处理\n\n方案1 那就是很简单啦,直接加代码,但是呢由于要在之前的逻辑里加东西,那就不好说了,毕竟开闭原则嘛,修改以前的逻辑势必会带来一些风险\n方案2 这就基本不用改以前的代码了,毕竟做的是`CDC`,当然不知道你们用的什么数据库,那`CDC`的具体方案就不一样了,如果以`mysql`举例,当然是基于它的`binlog`来做处理咯,随便搜一搜一大堆,你可以自己造轮子,也可以用别人早已经造好的,当然造好的确实需要花一些代价去学习啦。不过呢不用硬生生修改之前的逻辑,主要就是去解析增量的数据库日志就可以了\n当然也许你会问主动去解析日志文件跟去循环查询数据库不是还是差不太多么\nno no no有些数据库是支持响应式的操作的就是你主动查和数据库主动推送给你的区别比如解析`mysql binlog`的工具`Maxwell`,好家伙,它就是伪装成`Slave`,这不就可以从`Master`节点获取到`binlog`了嘛,从而再发出来,如果发给`kafka`,你再做一个消费者服务,不就可以了么\n总之`CDC`是一种数据集成方法吧,不同数据库实现`CDC`的方法并不相同,当然其实早已经有一个库整合了不少主流数据库,然后集成了自己一套`CDC`的接口你可以去看看debezium不过这玩意儿我自己装起来很头大后面公司最终的方案也没有用`debezium`,还是找到了我们自己使用的数据库的官方响应`API`完成的\n仅做参考希望对您有帮助不过最后说一下您提到\"频繁访问数据库,会严重影响数据库的性能\"\n影响性能根本原因就是读写操作是一个库嘛所以你也可以考虑分库啊读写分离啊是吧就是导出专门是一个只读从库就可以了嘛和主库分开部署这样即使你现在这样做频繁访问数据库其实影响也不大如果还有很大影响说明你从库的机器配置太低了。。。叭",
"type": "technical_qa"
},
{
"id": "segmentfault_36",
"question": "请问现在那个使用那个跨前端技术会比较好。\nReact Native / Weex / Flutter / uni-app 如何选择好呢",
"answer": "ReactNative 适合有一定 React 前端基础的人。不过性能瓶颈是天坑,稍微复杂一点儿的组件还是得写原生配合。胜在出生较早,生态相对完善,社区活跃。\nFlutter 是用得 Dart 基本就是重学一门语言了,但性能要比 RN 强很多。出生虽比 RN 晚,但后发制人,社区也很活跃。\nuni-app 严格意义上来说不是跨端 App只是 Web 浏览器套壳。你写 Web 有啥瓶颈,它就有啥瓶颈。(别说它也封装了一些 Native API性能还不如 RN 呢)。\nWeex 还活着?",
"type": "technical_qa"
},
{
"id": "segmentfault_37",
"question": "美团前端二面,读代码题求解\n```\nvar a = 0;\nif (true) {\n a = 1;\n function a() {}\n a = 21;\n console.log(a);\n}\nconsole.log(a);\n```\n求两次 console 出来的值。\n答案是21 1。\n本菜鸡想了很久也没想明白第二个为啥是1。。\n求大佬解惑 ?",
"answer": "21 1 的输出结果不完全正确,在不同的浏览器下结果不同\n在safari下结果为21 21\n在chrome下结果为21 1\n同时ECMAScript规范中说函数声明可以嵌套在条件语句块内但是其运行的结果依赖于JS解析器的实现其结果具有不确定性,不推荐在生产环境下使用",
"type": "technical_qa"
},
{
"id": "segmentfault_38",
"question": "JavaScript 两个对象大小比较的机制?\n偶然见看到的一个关于类型转换的题目\n对象 ab 是两个字面量函数,在进行比较的时候,可以发现大小和相等的比较结果都是 `false`\n```\nvar a = {b: 42};\nvar b = {b: 43};\n```\n```\na < b; //false\na == b; //false \na > b; //false\n\na <= b; //true \na >= b; //true \n```\n在这个过程之a 和 b 比较的时候,到底比较的是什么?为什么 <=> 三个运算符都是 false。\n为什么 `a<=b` 是 true\n`a<=b == true` 是因为 JS 计算的是 `!(a>b)` 吗?",
"answer": "ES 规定如此。\n`==`、`!=` 不说了,基础问题了;说下 `>`、`<` 这种吧,最后都会转换为数值形式做比较。\n首先尝试调用对象的 `Symbol.toPrimitive` 方法得到原始值。\n如果没有这个方法就再尝试调用 `valueOf`。\n经过以上转换后如果两边都是 `string`,则按 Unicode 逐位比较;否则,都强转成 `number` 比较。\n`Object` 强转后就变成了 `NaN`。`NaN` 是个特殊的 `number`,它跟任意数(包括它自己)做任何比较运算,恒为 `false`。\n至于 `>=`、`<=` 你说的对,确实是取反。\nP.S. 完整讲述可以自己搜索一下 ECMA-262 文档中关于 Abstract Relational Comparison 的相关定义https://tc39.es/ecma262/#sec-abstract-relational-comparison",
"type": "technical_qa"
},
{
"id": "segmentfault_39",
"question": "关于实际代码中如何用策略模式处理频繁的 if else 的问题\n直接上代码吧 都在代码里写清楚了\n问题就是\n如何把函数中 tabs.filter.forEach 这些几乎相同的逻辑 独立出来 之前学习了策略模式 但是想不到好的方案 请大佬指点一二\n```\nlet tabs = [{index:0,name:'angelaBaby'},{index:1,'陈冠西'},{index:2,'李bingbing'},{index:3,'范特西'}]\nlet COMMAND_TYPE_LIST = {\n OTHER:'other',\n RIGHT:'right',\n SELF:'self',\n}\n\n/**\n * @desc 抽中的成员逻辑\n * @param {*} type:string - 抽中的类型 \n * @param {*} randomIndex:number - 抽中的数组 index\n * @example \n * 比如 type==='other' randomIndex=1 那么抽中的成员就是 0,2,3\n * 比如 type==='right' randomIndex=1 那么抽中的成员就是 2,3\n * 比如 type==='self' randomIndex=1 那么抽中的成员就是 1\n * @todo\n * 如何把 tabs.filter.forEach 这些几乎相同的逻辑 独立出来 之前学习了策略模式 但是想不到好的方案 请大佬指点一二\n */\nfunction checkedPerson(type,randomIndex){\n if (type === COMMAND_TYPE_LIST.OTHER) {\n //抽中其他\n tabs\n .filter((item, index) => index !== randomIndex)\n .forEach((tab) => {\n //循环处理逻辑\n })\n } else if (type === COMMAND_TYPE_LIST.RIGHT) {\n //抽中右侧\n tabs\n .filter((item, index) => index > randomIndex)\n .forEach((tab) => {\n //循环处理逻辑\n })\n } else if (type === COMMAND_TYPE_LIST.SELF) {\n //抽中自身\n tabs\n .filter((item, index) => index === randomIndex)\n .forEach((tab) => {\n //循环处理逻辑\n })\n }\n}\ncheckedPerson(COMMAND_TYPE_LIST.OTHER,2)//抽中的成员就是 0,1,3\n\n\n```",
"answer": "解耦最终操作放在外面,可用性更高点\n```\nfunction checkedPerson1(type,randomIndex) {\n const other = (randomIndex, index) => index !== randomIndex;\n const right = (randomIndex, index) => index > randomIndex;\n const self = (randomIndex, index) => index === randomIndex;\n const dict = {\n other,\n right,\n self\n }\n return tabs.filter((item, index) => dict[type](randomIndex, index));\n}\ncheckedPerson1('other', 1).forEach(item => {\n console.log(item);\n});\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_40",
"question": ".ts文件识别不了.vue 文件?\nmain.ts\n```\nimport Vue from \"vue\";\nimport Component from \"vue-class-component\";\nimport App from \"./App.vue\";\n```\n报这个错误\nCannot find module './App.vue' or its corresponding type declarations.\ntsconfig.json\n```\n{ // 编译选项\n \"compilerOptions\": {\n // 编译输出目标 ES 版本\n \"target\": \"esnext\",\n // 采用的模块系统\n \"module\": \"esnext\",\n // 以严格模式解析\n \"strict\": false,\n \"jsx\": \"preserve\",\n // 从 tslib 导入外部帮助库: 比如__extends__rest等\n \"importHelpers\": true,\n // 如何处理模块\n \"moduleResolution\": \"node\",\n // 启用装饰器\n \"experimentalDecorators\": true,\n \"esModuleInterop\": true,\n // 允许从没有设置默认导出的模块中默认导入\n \"allowSyntheticDefaultImports\": true,\n // 定义一个变量就必须给它一个初始值\n \"strictPropertyInitialization\" : false,\n // 允许编译javascript文件\n \"allowJs\": true,\n // 是否包含可以用于 debug 的 sourceMap\n \"sourceMap\": true,\n // 忽略 this 的类型检查, Raise error on this expressions with an implied any type.\n \"noImplicitThis\": false,\n // 解析非相对模块名的基准目录 \n \"baseUrl\": \".\",\n // 给错误和消息设置样式,使用颜色和上下文。\n \"pretty\": true,\n // 设置引入的定义文件\n \"types\": [\"webpack-env\", \"mocha\", \"chai\"],\n // 指定特殊模块的路径\n \"paths\": {\n \"@/*\": [\"src/*\"]\n },\n // 编译过程中需要引入的库文件的列表\n \"lib\": [\"esnext\", \"dom\", \"dom.iterable\", \"scripthost\"],\n \"typeRoots\": [\n \"./types\",\n \"./node_modules/vue/types\",\n \"./src\"\n ],\n },\n // ts 管理的文件\n \"include\": [\n \"src/**/*.ts\",\n \"src/**/*.tsx\",\n \"src/**/*.vue\",\n \"tests/**/*.ts\",\n \"tests/**/*.tsx\"\n ],\n // ts 排除的文件\n \"exclude\": [\"node_modules\"]\n}\n```\nshims-vue.d.ts\n```\nimport Vue from \"vue\";\nimport VueRouter, { Route } from \"vue-router\";\n\ndeclare module '*.vue' {\n export default Vue\n}\n\n\ndeclare module \"vue/types/vue\" {\n interface Vue {\n $router: VueRouter; // 这表示this下有这个东西\n $route: Route;\n $http: any;\n $Message: any;\n $Modal: any;\n }\n}\n```\n第一次用ts写vue不知道为什么报这个错误\n.vue文件里能识别.vue文件,.ts文件里就识别不了但是页面能正常打开\npackage.json\n```\n{\n \"name\": \"scgx\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"scripts\": {\n \"start\": \"vue-cli-service serve\",\n \"serve\": \"vue-cli-service serve\",\n \"build\": \"vue-cli-service build\",\n \"lint\": \"vue-cli-service lint\",\n \"test:unit\": \"vue-cli-service test:unit\"\n },\n \"dependencies\": {\n \"axios\": \"^0.18.0\",\n \"element-ui\": \"^2.13.2\",\n \"vue\": \"^2.6.6\",\n \"vue-class-component\": \"^6.0.0\",\n \"vue-property-decorator\": \"^7.0.0\",\n \"vue-router\": \"^3.0.1\",\n \"vuex\": \"^3.0.1\"\n },\n \"devDependencies\": {\n \"@types/chai\": \"^4.1.0\",\n \"@types/mocha\": \"^5.2.4\",\n \"@vue/cli-plugin-babel\": \"^3.5.0\",\n \"@vue/cli-plugin-eslint\": \"^3.5.0\",\n \"@vue/cli-plugin-typescript\": \"^3.5.0\",\n \"@vue/cli-plugin-unit-mocha\": \"^3.5.0\",\n \"@vue/cli-service\": \"^3.5.0\",\n \"@vue/eslint-config-prettier\": \"^4.0.1\",\n \"@vue/eslint-config-typescript\": \"^4.0.0\",\n \"@vue/test-utils\": \"1.0.0-beta.29\",\n \"babel-eslint\": \"^10.0.1\",\n \"babel-plugin-component\": \"^1.1.1\",\n \"chai\": \"^4.1.2\",\n \"eslint\": \"^5.8.0\",\n \"eslint-plugin-vue\": \"^5.0.0\",\n \"less\": \"^3.0.4\",\n \"less-loader\": \"^4.1.0\",\n \"typescript\": \"^3.2.1\",\n \"vue-template-compiler\": \"^2.5.21\",\n \"vuex-class\": \"^0.3.2\"\n }\n}\n```\nvue.config.js\n```\nconst path = require(\"path\");\nconst sourceMap = process.env.NODE_ENV === \"development\";\n\nmodule.exports = {\n // 基本路径\n publicPath: \"./\",\n // 输出文件目录\n outputDir: \"dist\",\n // eslint-loader 是否在保存的时候检查\n lintOnSave: false,\n // webpack配置\n // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md\n chainWebpack: () => {},\n configureWebpack: config => {\n if (process.env.NODE_ENV === \"production\") {\n // 为生产环境修改配置...\n config.mode = \"production\";\n } else {\n // 为开发环境修改配置...\n config.mode = \"development\";\n }\n\n Object.assign(config, {\n // 开发生产共同配置\n resolve: {\n extensions: [\".js\", \".vue\", \".json\", \".ts\", \".tsx\"],\n alias: {\n vue$: \"vue/dist/vue.js\",\n \"@\": path.resolve(__dirname, \"./src\"),\n \"@c\": path.resolve(__dirname, \"./src/components\"),\n utils: path.resolve(__dirname, \"./src/utils\"),\n views: path.resolve(__dirname, \"./src/views\"),\n assets: path.resolve(__dirname, \"./src/assets\"),\n com: path.resolve(__dirname, \"./src/components\")\n }\n }\n });\n },\n // 生产环境是否生成 sourceMap 文件\n productionSourceMap: sourceMap,\n // css相关配置\n css: {\n // 是否使用css分离插件 ExtractTextPlugin\n extract: true,\n // 开启 CSS source maps?\n sourceMap: false,\n // css预设器配置项\n loaderOptions: {},\n // 启用 CSS modules for all css / pre-processor files.\n modules: false\n },\n // use thread-loader for babel & TS in production build\n // enabled by default if the machine has more than 1 cores\n parallel: require(\"os\").cpus().length > 1,\n // PWA 插件相关配置\n // see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa\n pwa: {},\n // webpack-dev-server 相关配置\n devServer: {\n open: process.platform === \"darwin\",\n host: \"localhost\",\n port: 3001, //8080,\n https: false,\n hotOnly: false,\n proxy: {\n // 设置代理\n // proxy all requests starting with /api to jsonplaceholder\n \"/api\": {\n target: \"http://localhost:8989/\",\n changeOrigin: true,\n ws: true,\n pathRewrite: {\n \"^/api\": \"\"\n }\n }\n },\n before: app => {}\n },\n // 第三方插件配置\n pluginOptions: {\n // ...\n }\n};\n\n```",
"answer": "不要再shims-vue.d.ts中最外层使用import使用这种写法\n```\ndeclare module '*.vue' {\n import Vue from 'vue';\n export default Vue;\n}\n\ndeclare module \"vue/types/vue\" {\n import VueRouter, { Route } from 'vue-router';\n interface Vue {\n $router: VueRouter; // 这表示this下有这个东西\n $route: Route;\n $http: any;\n $Message: any;\n $Modal: any;\n }\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_41",
"question": "webpack使用CopyWebpackPlugin插件一直报错麻烦大佬看看\n```\nconst CopyWebpackPlugin = require(\"copy-webpack-plugin\");\nconst path = require(\"path\");\n\nmodule.exports = {\n entry: \"./src/index.js\",\n output: {\n filename: \"bundle.js\",\n path: path.resolve(__dirname, \"dist\"),\n },\n module: {\n rules: [],\n },\n plugins: [\n new CopyWebpackPlugin([\n // {output}/file.txt\n { from: path.resolve(__dirname, './src/assets/'), },\n ]),\n ],\n};\n```\n一直给我提示这个错误我想知道到底错在哪按照文档上配的百度、google都没这个错误的。大致意思是缺少`{ from: path.resolve(__dirname, './src/assets/'), }`配置,我现在实在找不到错误在哪,麻烦大佬指明一下\n```\nInvalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.\n - options[0] misses the property 'patterns'. Should be:\n [non-empty string | object { from, to?, context?, globOptions?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)\nValidationError: Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.\n at validate (D:\\vscode-workspace\\brower-manager\\node_modules\\copy-webpack-plugin\\node_modules\\schema-utils\\dist\\validate.js:88:11)\n at new CopyPlugin (D:\\vscode-workspace\\brower-manager\\node_modules\\copy-webpack-plugin\\dist\\index.js:24:30)\n at Object.<anonymous> (D:\\vscode-workspace\\brower-manager\\webpack.common.js:14:5)\n at Module._compile (D:\\vscode-workspace\\brower-manager\\node_modules\\v8-compile-cache\\v8-compile-cache.js:192:30)\n at Object.Module._extensions..js (internal/modules/cjs/loader.js:1153:10)\n at Module.load (internal/modules/cjs/loader.js:977:32)\n at Function.Module._load (internal/modules/cjs/loader.js:877:14)\n at Module.require (internal/modules/cjs/loader.js:1019:19)\n at require (D:\\vscode-workspace\\brower-manager\\node_modules\\v8-compile-cache\\v8-compile-cache.js:161:20)\n at Object.<anonymous> (D:\\vscode-workspace\\brower-manager\\webpack.dev.js:2:16)\n at Module._compile (D:\\vscode-workspace\\brower-manager\\node_modules\\v8-compile-cache\\v8-compile-cache.js:192:30)\n at Object.Module._extensions..js (internal/modules/cjs/loader.js:1153:10)\n at Module.load (internal/modules/cjs/loader.js:977:32)\n at Function.Module._load (internal/modules/cjs/loader.js:877:14)\n at Module.require (internal/modules/cjs/loader.js:1019:19)\n at require (D:\\vscode-workspace\\brower-manager\\node_modules\\v8-compile-cache\\v8-compile-cache.js:161:20)\nnpm ERR! code ELIFECYCLE\nnpm ERR! errno 1\nnpm ERR! brower-manager@1.0.0 dev: `webpack --config webpack.dev.js`\nnpm ERR! Exit status 1\nnpm ERR!\nnpm ERR! Failed at the brower-manager@1.0.0 dev script.\nnpm ERR! This is probably not a problem with npm. There is likely additional logging output above.\n\n```",
"answer": "仔细看错误信息,缺少了 `patterns` 字段。实际上 copy-webpack-plugin 从 6.0 以后,把配置改成了\n```\nnew CopyWebpackPlugin(\n patterns:\n [\n { from: path.resolve(__dirname, './src/assets/'), },\n ]\n ),\n) \n```",
"type": "technical_qa"
},
{
"id": "segmentfault_42",
"question": "前端路由是全部都由后端返回,还是后端返回对应角色下的权限,然后前端通过遍历的方式来修改当前路由呢?\n在看vue-element-admin中有个权限验证现在不知道这2者有啥区别请大佬说说有什么好的方式来处理这个动态路由\nhttps://panjiachen.github.io/...",
"answer": "第一种后台返回路由,第二种后台返回权限。\n共同点\n- 两种方法都可以实现需求\n- 前端都要维护一份路由地址与模块文件地址的映射\n- 后段返回的数据一般都要再遍历做二次处理\n- 有关页面内元素(按钮)的权限都要另做处理\n- 技术点都会涉及路由守卫和路由鉴权\n\n差异点\n- 默认路由列表方法一只维护home、login等无权限需求路由其他路由需要后续通过接口和路由api`addRoutes`动态添加方法二需要维护一个全量的路由列表不需要额外添加路由通过配置每个路由的access数组来做鉴权。\n- 路由跳转:因为方法一返回的就是该用户权限下的路由,所以不需要再做权限鉴权;方法二需要。\n- 路由的自定义程度:方法一可以通过修改数据库的路由数据来自定义前端的菜单结构,因此也需要做一个实现路由重组的递归函数,拓展性更好;方法二针对的是菜单结构相对稳定的项目,一般不支持结构变动。\n- 返回报文:一般来说,返回报文大小 方法一比方法二要大",
"type": "technical_qa"
},
{
"id": "segmentfault_43",
"question": "promise then 的回调函数是在什么时候进入微任务队列的?\npromise then 的回调函数是在遇到 resolve 语句的时候就被加入微任务队列,还是在遇到 then 语句的时候被加入到微任务队列?\n在网上查了一些资料发现有不同的说法\n1. 比如在《深入理解ES6》中文版 244 页里是这么说的:“调用 resolve( ) 后会触发一个异步操作, 传入 then( ) 和 catch( ) 方法的函数会被添加到任务队列中并异步执行”,所以 then 方法的回调应该是在调用 resolve 后就被加入到队列中的?\n2. 对应的英文版原文是这么说的“Calling resolve() triggers an asynchronous operation. Functions passed to then() and catch() are executed asynchronously, because these are also added to the job queue”\n这个是知乎的回答https://www.zhihu.com/question/62305365\n这个是 StackOverflow 类似问题的回答https://stackoverflow.com/questions/59846764/how-job-queue-works-with-promise ,答主在分析 event loop 的时候有这么一句“The first then hooks up the first fulfillment handler, queuing a PromiseJobs job because the promise is already fulfilled”\n1、2 都认为 then 的回调函数是在遇到 resolve 语句的时候就被加入微任务队列3、4 都认为是在遇到 then 语句的时候被加入到微任务队列的。到底哪一种说法是正确的呢?",
"answer": "都没问题。\n关键在于`then` 是在 `resolve` 之前被调用的,还是 `resolve` 之后呢?\n`then` 在 `resolve` 之前,`then` 不会加微任务,而是缓存起来,`resolve` 看到缓存里又 `then` 的回调,于是加微任务。\n`resolve` 在 `then` 之前,`resolve` 的时候还没有任何回调要执行,自然不会加微任务。`then` 的时候发现已经 fullfilled ,于是直接加微任务。\n也就是说他们都有可能加也都有可能不加就看调用时的 promise 的状态了。\n你的引用有些只说明了其一但是说明里条件写得还是很清楚的比如 4 里 \"because the promise is already fulfilled\"",
"type": "technical_qa"
},
{
"id": "segmentfault_44",
"question": "JS怎么获取变量名称反射\nJS中怎么在程序执行的时候获取变量名称。\n比如通过一个函数返回指定参数的参数名。\n```\njsvar paramName = 'asdf' // 不管等于什么。\nvar paramName2 = new Object(); // 不管等于什么。\n\nfunction getParamName(p) {\n // ...实现过程\n var result = ...; // 这里只是模拟\n return result;\n}\n\ngetParamName(paramName);\ngetParamName(paramName2);\n\n```\n最终参数的返回结果应该为\n```\noutput Output:\n paramName\n paramName2\n\n```\n请问类似的需求怎么实现有没有变通的方法\n看了一下感觉 http://segmentfault.com/q/1010000002761696#a-1020000002765874 说的比较合理。",
"answer": "2017.1.5 答案已重写\n每一个上下文都有一个与之对应的变量对象任何声明的变量都是这个变量对象的属性。全局上下文的变量对象是全局对象因而在全局声明的变量就变成了全局对象的属性。相应地函数上下文的变量对象是活化对象在函数上下文声明的变量是活化对象的属性。然而活化对象是引擎内部的一个对象不可被外部访问因而不可在 JS 中获取函数上下文变量的名称。\n此外基本类型的函数实参是以传值的方式传入函数的对象类型的实参是以引用的方式传入函数的无论哪种方式函数都只能得到传入的值或者引用而无法访问调用函数的上下文的变量对象因而不能在函数内部获得传入函数的变量的名称。\n既然没有函数能够返回调用这个函数的上下文中变量的名称JS 也没有提供能做到这件事的操作符,那么在执行上下文内部获取该执行上下文内部变量的名称也就是不可能的。\n当然啦对于函数代码的执行上下文如果我们能获得这个函数的代码就可以解析这段代码得到这段代码当中变量的名称。\n示例代码\n```\nfunction getParamName() {}\n\nfunction fn() {\n var param1 = 0\n var a = 2\n\n console.log(getParamName(param1))\n console.log(getParamName(a))\n}\n\nfunction callWithVariableName(fn) {\n eval('(' + fn.toString().replace(/\\bgetParamName\\s*\\(([a-zA-Z_$][\\w_$]*)\\)/g, function(u, v) {\n return \"'\" + v + \"'\"\n }) + '())')\n}\n\ncallWithVariableName(fn)\n\n```\n控制台输出\n```\nparam1\na\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_45",
"question": "在DolphinDB中如何对连续的相同值分组 \n比如有表如下\n```\nt = table(1 1 1 1 2 2 2 2 1 1 1 1 3 3 3 as bs_flag) \n```\n希望根据 bs_flag 进行分组,连续相同的 bs_flag 的行group 为一组 \n 即希望分组后是 \n1 \n2 \n1 \n3 \n如何写sql语句",
"answer": "可以用\n```\nselect first(bs_flag)  from t group by segmentby(first, bs_flag.rowNo(), bs_flag)\n```\n或\n```\nselect first(bs_flag), first(bs_flag.rowNo()) from t group by eachPre(ne, bs_flag).cumsum()\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_46",
"question": "DolphinDB的流数据表怎么查询\n我有一个流数据表然后\n```\nenableTableShareAndPersistence(table, tableName, [asynWrite=true], [compress=true], [cacheSize=-1], [retentionMinutes=1440], [flushMode=0]) \n```\n我把cacheSize 设为100,000.\n现在假设流进来的数据已经超过了100,000行, 也就是部分数据已经存入persisenceDir。如果用select * from tableName会不会返回所有的行\n问的原因是因为我在考虑要不要单独建一个实时数据仓来query所有已经流进来的数据。",
"answer": "用select * from tableName不会返回所有的行。默认情况下流计算的表把所有数据保存在内存中。如果流数据表太大系统可能会出现内存不足的情况。为了避免内存不足的问题我们可以设置缓存大小的界限。如果流数据表的行数达到这个界限前面一半的记录行会从内存中清理。 \n可以用getPersistenceMeta(table)观察一下。",
"type": "technical_qa"
},
{
"id": "segmentfault_47",
"question": "在DolphinDB中怎么拼接Matrix\n如果我有一个结果是一个ANY 向量,他的每一个元素是shape相同的Matrix,我怎么样可以把他合并成一个大的Matrix? 最好是纵向拼接,列数不变增加行数。",
"answer": "横向拼接两个矩阵: \na = 1..4$2:2\nb = 1..4$2:2\na.join(b) \n纵向拼接用 a.transpose().join(b.transpose()).transpose() \n假设ANY vector c如下\n```\nc = [a, b]\ndef transposeJoin(a, b) {\n  return a.transpose().join(b.transpose()).transpose()\n}\nreduce(transposeJoin, c)\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_48",
"question": "提问关于 mysql得联合主键和复合主键的问题\n如下sql\nCREATE TABLE `film_actor` (\n`actor_id` smallint(5) unsigned NOT NULL,\n`film_id` smallint(5) unsigned NOT NULL,\n`name` varchar(50) NOT NULL,\n`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n PRIMARY KEY (`actor_id`,`film_id`) USING BTREE,\n KEY `idx_fk_film_id` (`film_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n`primary key` 是联合主键还是复合主键,我个人理解的是联合主键,毕竟`actor_id`不是自增的?但是针对`actor_id`和`film_id`设值时只能1-1的for primary key。\n但是如果`actor_id`设有自增`auto_increment`,然后`primary key`是 `primary key(actor_id,film_id)`这种是联合还是复合?\n又或者设有自增的`actor_id``primary key(actor_id,name)`是复合还是联合?求大神解答一下疑惑,谢谢",
"answer": "这个问题要是问外国开发者TA们能一脸懵逼。\n在英文语境中只有 `Composite Primary Key`(也有叫 `Compound Primary Key` 的),就是一个表中如果是多个字段组成一个主键,那么这个主键就被称为这玩意儿。\n至于这玩意儿你翻译成“联合主键”、“组合主键”、“混合主键”还是“复合主键”都特么是一回事儿。\n结果到了中文编程界不知道是哪位神仙起的头儿非得编个“联合主键”和“复合主键”的区别出来。再加上中文编程界有一大特点就是博客或者问答习惯性东抄西搬结果错的知识也能流传广泛甚至成为“主流”。\n搬一个“流传最广”的对于“联合主键”和“复合主键”区别的文章\n“联合主键”还是单一主键只不过往往用在关联表里一个关联表里会涉及到多个其他表的主键组合形成一条数据你既可以为它们设置一个“复合主键”、也可以再新加一个自增列设为“联合主键”。\n举例\n```\n--- 学生表\nCREATE TABLE `student` (\n `student_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n `name` varchar(20) NOT NULL,\n PRIMARY KEY (`student_id`) USING BTREE\n);\n\n--- 科目表\nCREATE TABLE `subject` (\n `subject_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n `name` varchar(20) NOT NULL,\n PRIMARY KEY (`subject_id`) USING BTREE\n);\n\n--- 分数表,用所谓的“复合主键”\nCREATE TABLE `score` (\n `student_id` int(10) unsigned NOT NULL,\n `subject_id` int(10) unsigned NOT NULL,\n `value` int(10) unsigned NOT NULL,\n PRIMARY KEY (`student_id`, `subject_id`) USING BTREE\n);\n\n--- 分数表,用所谓的“联合主键”\nCREATE TABLE `score` (\n `id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n `student_id` int(10) unsigned NOT NULL,\n `subject_id` int(10) unsigned NOT NULL,\n `value` int(10) unsigned NOT NULL,\n PRIMARY KEY (`id`) USING BTREE,\n UNIQUE INDEX `un`(`student_id`, `subject_id`) USING BTREE\n);\n```\n写在最后\n再次重申这种概念是中文编程界或者说是中文编程博客界人为造出的。\n上面的例子看看就得了根本就是胡编一个 `联合主键` 的定义出来,你会发现它其实就是一个最简单的自增主键,只不过表的逻辑上 `student_id` + `subject_id` 是唯一的,`id` 就成了所谓的二者的 `联合主键`。",
"type": "technical_qa"
},
{
"id": "segmentfault_49",
"question": "new Promise((resolve)=>{resolve()}) 与 Promise.resolve() 等价吗\n### 处理以下类型的时候这个两个方法感觉差不多\n参数是一个 Promise 实例\n参数是一个thenable对象\n参数不是具有then方法的对象或根本就不是对象\n但我看有人说`promise.resolve(v)`不等于`new Promise(r => r(v))`,因为如果 v 是一个 Promise 对象,前者会直接返回 v而后者需要经过一系列的处理主要是 PromiseResolveThenableJob",
"answer": "## 我自己做了一个详细的测试\n先说结论在v是一个promise实例的时候`promise.resolve(v)`与`new Promise(r => r(v))`有明显的差异\n区别表现new Promise(r => r(v))的.then()回调会被推迟两个时序(事件循环)\n原因new Promise(r => r(v))里浏览器会创建一个 PromiseResolveThenableJob 去处理这个 Promise 实例,这是一个微任务。具体分析如下\n```\n // v是一个实例化的promise且状态为fulfilled\n let v = new Promise(resolve => {\n console.log(\"begin\");\n resolve(\"then\");\n });\n\n // 在promise里面resolve一个状态为fulfilled的promise\n\n // 模式一 new Promise里的resolve()\n // begin->1->2->3->then->4 可以发现then推迟了两个时序\n // 推迟原因:浏览器会创建一个 PromiseResolveThenableJob 去处理这个 Promise 实例,这是一个微任务。\n // 等到下次循环到来这个微任务会执行也就是PromiseResolveThenableJob 执行中的时候因为这个Promise 实例是fulfilled状态所以又会注册一个它的.then()回调\n // 又等一次循环到这个Promise 实例它的.then()回调执行后,才会注册下面的这个.then(),于是就被推迟了两个时序\n new Promise(resolve => {\n resolve(v);\n }).then((v)=>{\n console.log(v)\n });\n\n // 模式二 Promise.resolve(v)直接创建\n // begin->1->then->2->3->4 可以发现then的执行时间正常了第一个执行的微任务就是下面这个.then\n // 原因Promise.resolve()API如果参数是promise会直接返回这个promise实例不会做任何处理\n/* Promise.resolve(v).then((v)=>{\n console.log(v)\n }); */\n\n new Promise(resolve => {\n console.log(1);\n resolve();\n })\n .then(() => {\n console.log(2);\n })\n .then(() => {\n console.log(3);\n })\n .then(() => {\n console.log(4);\n });\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_50",
"question": "上海字节跳动一道关于http缓存的面试题\n首先这个问题是http的缓存我答了强缓存和协商缓存。\n我说道协商缓存是会请求到后端服务器然后对比响应头last-modified或者etag来决定时候使用缓存。\n此时面试官问我已经请求到后端了为什么还要再去取缓存而不是直接使用response我就没答出来。\n网上搜了很多主要还是都是介绍2种缓存的并没有提到这个问题望解答",
"answer": "我猜你说的 response 指的是 response body\n协商缓存如果命中返回的是 304 啊……只有 header 没有 body。\n虽然还是请求了一次服务器但只需要传输 header 部分就可以了,节省了传输文件本身的开销。",
"type": "technical_qa"
},
{
"id": "segmentfault_51",
"question": "如何高效的监控多台服务器,该做哪些方面的监控?\n系统的服务器多了独立运行的服务进程多了服务进程间的通讯多了该做那些监控该怎么监控有没有什么成熟的思想想法\n\n监控是不是可以分为2个方面1系统级别的监控(cpu,memory,io,disk,net),服务是否存活\n\n2)应用级别(各子系统业务相关异常监控)\n\n具体的怎么来实现这个监控做到一个可灵活配置、扩展的插件式监控平台感觉还是比较棘手\n查阅了资料后我打算先这么做\n\n1Nagios作为CPU、内存、硬盘等各个基本非业务的监控\n\n2各个业务模块做自己相关的监控服务异常监控、服务统计信息等\n\n1服务异常信息通过mq异步的发送给监控主服务器由监控主服务器统一处理\n\n2服务统计信息先在本地模块内存汇总然后定时间隔的发送给监控主服务器进行持久化等相关处理",
"answer": "`以下都是自己想到什么写什么\n\n监控从方向来分为 系统级别监控和业务逻辑层监控。一般的开源软件都是面向系统软件级别的监控 不可能会有业务逻辑的监控 业务逻辑的监控因为不同的应用而不同 这个需要程序员预留接口可以进行监控 运维是可以提需求的。\n\n监控从功能上分为 报警监控和性能监控。 报警监控就像大家说的nagios是非常好的开源软件 其实nagios提供的也是一种监控的框架 所以他比较的灵活 性能监控 主要是用来查看变化趋势, 可以更好的找到问题, 或者提早发现问题, 有时候因为报警的阀值是需要不断的调整才能到最佳状态,像cacti和ganglia\n\n监控的选择 一般要看你的服务器分布:\n\n如果是分布式的机房, 机房很多, 那么对集中监控和处理要求比较高, ganglia本身就有分布式特性, 是第一选择; nagios需要再做些插件的优化和结构调整才能更好的支持分布式的需求. 因为分布式面临的问题是集中管理和可靠性, 可靠性: 网络传输可能出现的问题都要避免监控,才能让监控准确; 集中管理: 才可以减少工作量\n\n如果是集中的, 在量很大的情况下还是建议使用ganglia, 如果小其它的很多监控都可以选择, 报警监控还是用nagios, 好像很少有他这样灵活的工具, 但一定要将配置改成最适合自己环境的, 并且最简单和快速的配置 需要自己制定一些规则会比较好。\n\n如果说要监控配合的外围工具: 像短信报警 邮件 都需要自己做些工具会比较好 ,都是为了保证报警的可靠性 监控前期一定要多关注是否跟上了需求 要做很多的调整 不是说搭建了就万事大吉了.\n评下你的做法\n\n查阅了资料后我打算先这么做\n\n1Nagios作为CPU、内存、硬盘等各个基本非业务的监控\n\n其实nagios也可以监控业务逻辑 主要是首先要知道要监控哪些业务逻辑 再程序方面是否有相应的接口 如果没有是否可以做 再自己写一些相应的脚本 nagios和ganglia都可以很方便的写脚本。最关键的还是监控需求和程序的支持情况\n\n2各个业务模块做自己相关的监控服务异常监控、服务统计信息等\n\n1服务异常信息通过mq异步的发送给监控主服务器由监控主服务器统一处理\n\n你应该说的是自己写监控再通过队列发送给主服务,如果是同机房当然还是写nagios的插件会比较好,这样是统一管理,而只需要写插件; 如果是机房是分布的,可以考虑nagios之间的消息传递写一些脚本完成,自己写的话是时间问题和管理上不统一的麻烦。\n\n2服务统计信息先在本地模块内存汇总然后定时间隔的发送给监控主服务器进行持久化等相关处理\n\n这一部分我建议是分成两部分: 第一部分是服务器基本信息, 像cpu 内存 硬盘 这些不会变化的可以间隔很长时间, 其实ganglia默认就有系统硬件的所有信息 只是如果想放到表格里面对比就差些了 反而对于系统用户 磁盘容量 各种配置文件 如计划任务 打开的服务 自启动的内容可以定时的执行和收集, 这个应该属于备份了, 但如果所有的配置集中处理之后,像使用puppet或者其它配置工作,这些都不需要做了。",
"type": "technical_qa"
},
{
"id": "segmentfault_52",
"question": "java 如何通过反射修改类的私有方法\n网上能找到的都是修改私有变量, 访问私有方法, 我想要修改私有方法, 请问如何操作?",
"answer": "反射是不能修改方法的,但是可以使用修改字节码的方式来实现修改。\n使用javassist工具在类加载器加载这个类之前修改他的字节码。 \n比如修改这个方法的字节码 \norg.jboss.resteasy.core.InjectorFactoryImpl.createMethodInjector()\n```\nClassPool pool = new ClassPool(true);\nCtClass ct = pool.getCtClass(\"org.jboss.resteasy.core.InjectorFactoryImpl\");// 加载这个类\n// 获取被修改的方法\nCtMethod m = ct.getDeclaredMethod(\"createMethodInjector\");\nm.setBody(\"return \\\"已经被修改!\\\"\"); // 直接修改方法体\n// 转为class\nct.toClass();\n// 释放对象\nct.detach();\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_53",
"question": "JS树结构的遍历、创建\n这样树结构的数组\n```\n \nlet tree =[\n {id: '1',\n title: '节点1',\n children: [\n {\n id: '1-1',\n title: '节点1-1',\n children: [\n {\n id: '1-1-1',\n title: '节点1-1-1'\n },]\n },\n {\n id: '1-2',\n title: '节点1-2'\n }\n ]\n },\n {\n id: '2',\n title: '节点2',\n children: [\n {\n id: '2-1',\n title: '节点2-1'\n }\n ]\n }\n ]\n \n```\n我想把其中的某项取出创建新的数组结构不变例如这样\n```\n getTree =[\n {\n title: '节点1',\n children: [\n {\n title: '节点1-1',\n children: [\n {\n title: '节点1-1-1'\n },]\n },\n {\n title: '节点1-2'\n }\n ]\n },\n {\n title: '节点2',\n children: [\n {\n title: '节点2-1'\n }\n ]\n }\n ]\n \n```\n不知道怎么写不知道描述清楚没我是新手不耻下问啊...",
"answer": "你可以先了解一下什么是 递归\n这个需求通过递归可以很轻易实现\n```\nfunction getTree(ary) {\n return ary.map(v => {\n const item = {\n title: v.title, //这是创建的新对象 根据需要的键随意更改\n };\n if (v.children) item.children = getTree(v.children);\n return item;\n });\n}\n```\n```\nconst newTree = getTree(tree);\nconsole.log(newTree)\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_54",
"question": "如何让一个元素hover时让指定区域的产生背景色在线等\n### 问题描述\n现在一个div高为50px宽为200px我想让它hover时只让这个div的高为40px宽为200px的区域产生背景色切要居中\n### 相关代码\ncss\n```\ndiv{\n height: 50px; \n width: 200px; \n background: slategrey;\n}\ndiv:hover{\n /*background: red;*/\n}\n```\nhtml结构\n```\n<div>\n TEST\n</div>\n```\n### 有什么解决方法吗?",
"answer": "```\ndiv:hover {\n background: linear-gradient(to bottom,slategrey 5px,red 0,red 45px,slategrey 0);\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_55",
"question": "请问vue或者uniapp如何实现背景色自动根据图片的主色进行渲染\n请问如何实现背景色自动根据图片的主色进行渲染",
"answer": "把图片绘制到一个与图片大小相等的 canvas 上,然后在图片上取样,确定图片的主色,把这个色值作为背景色即可。\n```\nconst picUrl = __YOUR_PIC_URL__;\nconst canvas = document.getElementById('yourCanvasId');\nconst ctx = canvas.getContext('2d');\nconst image = new Image();\nimage.setAttribute('crossOrigin', 'anonymous');\ncanvas.setAttribute('crossOrigin', 'anonymous');\n\nimage.addEventListener('load', e => {\n // image.removeEventListener('load', function(){});\n console.log('image.width:', image.width);\n const WIDTH = image.width;\n const HEIGHT = image.height;\n canvas.height = HEIGHT;\n canvas.width = WIDTH;\n ctx.drawImage(image, 0, 0, WIDTH, HEIGHT);\n const imageData = ctx.getImageData(0, 0, WIDTH, HEIGHT).data;\n \n // 这里为了简便,采用数组缓存颜色平均值\n // 如果需要进一步提高性能的话,可以使用 ArrayBuffer\n let colorArray = [\n imageData[0], // red 通道\n imageData[1], // green 通道\n imageData[2], // blue 通道\n imageData[3] // alpha 通道\n ];\n \n // 开启透明度时imageData 的每四个值代表一个点的 RGBA值\n for(let cnt = 4; undefined !== imageData[cnt + 3]; cnt += 16){\n colorArray[0] = ((colorArray[0] + imageData[cnt]) >> 1);\n colorArray[1] = ((colorArray[1] + imageData[cnt + 1]) >> 1);\n colorArray[2] = ((colorArray[2] + imageData[cnt + 2]) >> 1);\n colorArray[3] = ((colorArray[3] + imageData[cnt + 3]) >> 1);\n }\n document.getElementById('mainWrap').style.backgroundColor = \n [\n 'rgba(', \n ~~colorArray[0], \n ',', \n ~~colorArray[1], \n ',', \n ~~colorArray[2], \n ',', \n colorArray[3] / 255, \n ')'\n ].join('');\n});\nimage.src = picUrl;\n```\n当然如果图片不是特别花哨、要求不是特别高的话可以将背景设为 transparent ,然后将图片设为伪元素的背景,再进行高斯模糊即可:\n```\n<div class=\"main-wrap\">\n</div>\n\n<style>\n .main-wrap{\n background: transparent;\n position: relative;\n z-index: 1\n }\n .main-wrap::before{\n position: absolute;\n top: -100px;\n left: -100px;\n right: -100px;\n bottom: -100px;\n background: center no-repeat;\n background-size: cover;\n background-image: url(__YOUR_PIC_URL__);\n filter: blur(100px);\n }\n</style>\n```\n代码没测试过但是思路应该还算清晰我怀疑 JS 不太可能跑得起来需要多改进DOM 操作最好改成 ref 引用。\n时隔一天回来更新下JS 代码经简单测试可用了,用例在 codepen。",
"type": "technical_qa"
},
{
"id": "segmentfault_56",
"question": "使用axios发送请求的时候 什么时候算请求出错,什么情况算响应出错\n在设置请求拦截器与响应拦截器的时候失败状态下的情况遇到的一些疑问\n```\nAxios.interceptors.request.useconfig={\n //这里会最先拿到你的请求配置\n},err=>{\n//这里什么情况下会进来?并且进来之后对你接下来的程序执行有什么影响\n}\n\nAxios.interceptors.response.useres ={\n //这里会最先拿到你的response\n},err=>{\n//这里什么情况下会进来? 并且进来之后对你接下来的程序执行有什么影响\n}\n```",
"answer": "```\nAxios.interceptors.request.useconfig={\n //这里会最先拿到你的请求配置\n},err=>{\n // 这里极少情况会进来,暂时没有找到主动触发的方法,估计只有浏览器不兼容时才会触发,欢迎后面同学补充\n // 看了几个GitHub的issue有人甚至提出了这个方法是不必要的因为没有触发的场景不过还是建议大家按照官方的写法避免不必要的错误\n // 进来之后没法发起请求\n}\n\nAxios.interceptors.response.useres ={\n //这里会最先拿到你的response\n // 只有返回的状态码是2xx都会进来这里\n},err=>{\n // 目前发现三种情况会进入这里:\n// 1. http状态码非2开头的都会进来这里如404,500等\n// 2. 取消请求也会进入这里CancelToken可以用axios.isCancel(err)来判断是取消的请求\n// 3. 请求运行有异常也会进入这里如故意将headers写错axios.defaults.headers = '123',或者在request中有语法或解析错误也会进入这里\n// 进入这里意味着请求失败axios会进入catch分支\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_57",
"question": "一个面试题关于函数的优先级\n```\nfunction Foo(){\n getName = function() { \n alert(1)\n }; \n return this \n};\nFoo.getName = function () {\n alert(2)\n};\nFoo.prototype.getName = function () {\n alert(3) \n};\nvar getName = function () { \n alert(4) \n}\nfunction getName() {\n alert(5)\n}\nFoo.getName();\ngetName();\nFoo().getName();\ngetName();\nnew Foo.getName();\nnew Foo().getName();\nnew new Foo().getName()\n```\n打印出来的结果是2411233\n 但是我想的是 2514211.\n 有疑惑的地方",
"answer": "挺有意思的一道题。\n第一个 2 不用多解释,直接用的是 `Foo.getName` 静态方法。\n第二个为啥是 4 呢?你会注意到最后有一个 `var getName = funtion() {}` 和一个 `function getName`,后声明的 `function` 咋没覆盖前面的 `var` 呢?因为 `function` 有函数提升,虽然是后声明的,反而会被提到当前作用域最前面去执行。(你可能会说 `var` 不也有变量提升吗?因为 JS 里函数是一等公民,函数提升比变量提升更优先!)\n第三个和第四个为啥都是 1 呢?因为没 `new` 所以 `Foo()` 里的返回值 `this` 实际是 `window`,而 `window.getName` 上一步说了因为函数提升的原因,在执行 `Foo()` 之前其实是那个 `var getName`;但 `Foo()` 方法里给这个变量重新赋值了!\n第五个是 2 也没啥讲的,虽然有 `new` 了,但 `Foo` 是引用而非调用,所以还是静态方法。\n第六个第七个因为有 `new` 了、且调用了 `Foo()`,所以此时实际相当于实例化了一个 `Foo` 类型对象出来,那么后面的 `.getName()` 就是原型链方法了。\nP.S. 最后两个连着的 `new` 可能容易迷惑,实际上的执行顺序是:\n```\nlet a = new Foo();\nlet b = a.getName();\nlet c = new b;\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_58",
"question": "原生js如何获取json字符串中某个对象的内容\n有如下json字符串\n```\nconst str = `\n input: {\n label: \"输入框input\",\n name: \"input\",\n option: {\n rules: [{ required: true, message: \"Please select your country!\" }]\n },\n on: {\n change: e => {\n const { value } = e.target;\n console.log(\"change\", value);\n }\n }\n },\n number: {\n label: \"数字输入框\",\n name: \"input\",\n type: \"number\",\n props: {\n min: 3,\n max: 500\n },\n option: {\n rules: [{ required: true, message: \"Please select your country!\" }]\n },\n on: {\n change: value => {\n console.log(\"change\", value);\n }\n }\n }\n `;\n```\n怎样获取其中对象input或者number为字符串的内容要得到的结果如下\n获取input的结果\n```\n{\n label: \"输入框input\",\n name: \"input\",\n option: {\n rules: [{ required: true, message: \"Please select your country!\" }]\n },\n on: {\n change: e => {\n const { value } = e.target;\n console.log(\"change\", value);\n }\n }\n }\n```\n获取number的结果\n```\n{\n label: \"数字输入框\",\n name: \"input\",\n type: \"number\",\n props: {\n min: 3,\n max: 500\n },\n option: {\n rules: [{ required: true, message: \"Please select your country!\" }]\n },\n on: {\n change: value => {\n console.log(\"change\", value);\n }\n }\n }\n```\n原来使用 const json = JSON.parse(str); 转成json再通过 json.input 获取需要的对象内容然后通过JSON.stringify(json.input);转回需要的字符串;但这种方法会导致里面的 change为方法的内容获取不到。",
"answer": "这是一段`js`脚本。`eval`函数不安全,可以模拟实现类似功能。如下:\n```\nfunction equalEval(str){\n return new Function('return ' + str)();\n}\nlet obj = equalEval(str);\nconsole.log(obj.input);\nconsole.log(obj.number);\n\n```\n这样相对安全一些。",
"type": "technical_qa"
},
{
"id": "segmentfault_59",
"question": "为什么linux 创建文件是touch 而不是create\n好奇~ 为什么linux 创建文件是touch 而不是create",
"answer": "touch 的作用本来不是创建文件,而是将指定文件的修改时间设置为当前时间。\n就是假装“碰”touch了一下这个文件假装文件被“修改”了于是文件的修改时间就是被设置为当前时间。\n这带来了一个副作用就是当 touch 一个不存在的文件的时候,它会创建这个文件。\n然后由于 touch 已经可以完成创建文件的功能了,就不再需要一个单独的 create 了。",
"type": "technical_qa"
},
{
"id": "segmentfault_60",
"question": "网站大量无用图片如何处理?\n比如富文本这样的功能或者一些存储图片的字段。\n当执行编辑操作的时候有时候数据库中新图片会替代旧图片旧图片链接名称在数据库中不存在了但旧图片的文件还存在在硬盘中。\n这种已经没用的图片一般如何处理\n我想到的方案\n方案1在编辑的时候就把没用的图片一同处理掉但这样会增加很多代码量因为很多图片的存储结构不同需要在各个功能代码处写专门的处理函数。\n方案2定期处理。扫描图片在各个表中是否用到没有用到就删除。但这样做的话如果增加了新的功能还要去添加\"要扫描的表和字段\",遗漏的话会造成误删。\n方案3不处理。冗余图片不会对网站产生大的影响猜测。\n求解答。",
"answer": "建一个图片文件表:\n```\ncreate table pic(\nid int,\npath varchar(256),\nmd5 varchar(32),\nsize int,\nrefer_count int,\n)\n```\nrefer_count 为引用计数,多少文章里用到了,就是多少,文章修改时,先减少再增加,少到为零就可以删了。\n用md5做摘要可以把重复上传的图版合二为一。size和可以与用户结合进行配额限制防止被恶意使用。",
"type": "technical_qa"
},
{
"id": "segmentfault_61",
"question": "关于 useEffect 重复调用以及依赖数组的问题?\n关于`useEffect`有有一些疑惑疑惑, 如下, 代码已经放入codesandbox 的 CounterHook.js 文件中\n代码简化如下:\n```\nconst CounterHook = props => {\n const [count, setCount] = useState(0)\n const [loading, setLoading] = useState(false)\n\n useEffect(() => {\n setLoading(true)\n console.log(loading) // false, true, false, ture...\n // 模拟发送数据\n setTimeout(() => {\n setLoading(false)\n setCount(1)\n }, 2000)\n })\n \n return ...\n}\n```\n这里如果没有添加`useEffect`的依赖数组, 会造成无限循环. 不是特别理解为什么会造成无限循环. 个人打印了一下 loading, 发现一直不断重复输出 false, true, false, true....\n### 第一个问题\n个人对造成无限循环的理解:\n- 在调用`useEffect`之前, loading 是 false\n- \n第一次调用`useEffect`:\n\n类似`componentDidMount`, 此时 loading 被设置成了 true, 同时发出了一个异步请求\n请求结束, loading 又被设置成了 false, 组件的 state 被更新了, 由于 `useEffect` 在组件更新更新时也会触发, 因此触发第二次`useEffect`:\n\n\n- 第二次调用`useEffect`: 和第一次一样, 首先`componentDidMount`, 设置 loading 为 true...循环继续\n第一次调用`useEffect`:\n- 类似`componentDidMount`, 此时 loading 被设置成了 true, 同时发出了一个异步请求\n- 请求结束, loading 又被设置成了 false, 组件的 state 被更新了, 由于 `useEffect` 在组件更新更新时也会触发, 因此触发第二次`useEffect`:\n所以第一个问题是, 不知道这样理解造成无限循环对不对?\n### 第二个问题:\n如果将请求数据部分抽成一个函数, 如下;\n```\nconst CounterHook = props => {\n const [count, setCount] = useState(0)\n const [loading, setLoading] = useState(false)\n\n useEffect(() => {\n fetchApi()\n }, [fetchApi])\n\n const fetchApi = () => {\n setLoading(true)\n // 模拟发送数据\n setTimeout(() => {\n setLoading(false)\n setCount(1)\n }, 2000)\n }\n\n return ...\n}\n```\n`useEffect`的依赖数组变成了一个函数, 而且此时似乎仍旧会造成无限循环. 同时有提示:\n所以第二个问题为: 如果`useEffect`的依赖数组存在函数, 该如何理解这个函数是否\"变化\"? 例如上面例子里面, 为什么会造成无限循环, 函数到底是哪里\"变化\"了导致`useEffect`不断的被重新调用?\n### 第三个问题\n和第二个问题有关联, 按照提示修改, 使用`useCallback`包装了一下`fetchApi`这个函数, 代码如下:\n```\nconst CounterHook = props => {\n const [count, setCount] = useState(0)\n const [loading, setLoading] = useState(false)\n\n useEffect(() => {\n fetchApiCallback()\n }, [fetchApiCallback])\n\n const fetchApiCallback = useCallback(() => {\n setLoading(true)\n // 模拟发送数据\n setTimeout(() => {\n setLoading(false)\n setCount(1)\n }, 2000)\n }, [])\n\n return ...\n```\n问题: `useCallback`依赖添加了一个依赖数组, 里面为空, 似乎代码没有出现无限循环的情况, 请问该如何解释? `useCallback`到底使得函数的\"变化发生了怎样的改变\"?",
"answer": "第一个问题:\n对。\n第二个问题\n函数组件的每次渲染都是执行一遍这个函数在你的例子中也就是 `CounterHook` 函数。那么两次执行中创建的局部函数,还会是同一个引用吗?不会的。所以本次执行中的 `fetchApi` 和上次执行中的 `fetchApi` 是两个不同的函数,因此 `useEffect` 的依赖被更新了,触发执行。\n第三个问题\n`useCallback` 的返回值即为它接收的第一个参数,直到依赖更新。因此使用 `useCallback` 包裹的 `fetchApi` ,在依赖更新之前,总是同一个函数。也就不会触发 `useEffect`。",
"type": "technical_qa"
},
{
"id": "segmentfault_62",
"question": "为什么需要申请SSL证书\n最近在研究把现有网站换成https看了下SSL原理介绍有一点不明白既然https的本质是为了在通讯过程中讯息对称加密的方式传输为什么浏览器不直接支持服务端自己生产的加密证书加密证书只需要提供RSA的公钥不就好了为什么需要花很多钱申请这个证书呢",
"answer": "如果抛开安全只看加密,那确实,只要像你说的那样提供个公钥就行了。\n但这样做的问题是虽然确保了传输过程中的数据是被加密的但没办法确保最后解密的那台服务器是你真的想要发送给它的那台。\n举个例子在不使用证书加密之前我想给你服务器传纸条中间需要经过N个人传话如路由器等各级中间节点那么在你收到消息的时候很可能在中间某个传话的就给它篡改了或者说没篡改、但是被传话的偷看了小秘密。\n那么现在咱俩之间约定一个非对称加密的方式你先给我个公钥我用公钥把要给你的纸条加密了你收到后再用私钥解密这样中间传话的看不懂密码就没法偷看内容、即使瞎改的话你那解密不出来你就知道纸条内容被篡改了。\n到此为止就像你所说的那样但这样还有个问题那就是我怎么确认“你”是“你”我现在喊「`Boniu`,我要给你传纸条了,给我个公钥」,结果一个实际叫 `niuBo` 的人站出来了说「来来来,我就是 `Boniu`,我给你公钥,你传纸条吧」,结果咱俩的小秘密最后发给这个不相干的人了。这就是中间人攻击(上面这个例子里其实就是 DNS 劫持)。\n那怎么解决呢现实中好办传纸条前先看一下身份证“你”确实是“你”行了可以发了。\n这是因为你信任身份证这个由国家颁发的凭证。那网络上的凭证谁来颁发这就是证书签发机构的事儿了它们作为“权威”给每个域颁发证书就像国家给每个人颁发身份证一样你信任这些机构也就信任它们发的证从而也就信任有证书这些网站了。这里还有信任链的问题不展开讲了\n现实中你办个护照还需要交个工本费呢。想让证书颁发机构给你发证那就要给它们钱。而且这个证还分三六九等越权威的越值钱。\n不想花钱怎么办自己给自己签发呗然后你让所有使用证书的人都去信任你这个签发人早期 12306 就是这么干的,自己给自己签证书,你访问的时候还得先下载它们的证书导入到系统的信任链里去)。",
"type": "technical_qa"
},
{
"id": "segmentfault_63",
"question": "通过docker命令行报错Fatal error, can't open config file在容器内执行没问题\n首先我的dockerfile如下\n```\nFROM redis:latest\nCOPY $PWD/redis.conf /root/\nRUN [\"chmod\", \"777\", \"/root/redis.conf\"]\nCMD [\"redis-server\", \"/root/redis.conf\"]\n```\nredis.conf文件的内容是从这里复制的https://raw.githubusercontent...\n使用`docker build .`之后,使用`docker run -it --rm 7141cd2da206`运行,\n报以下错误\n```\n1:C 03 Sep 2019 12:59:48.539 # Fatal error, can't open config file '/root/redis.conf'\n```\n但是我通过bash进入容器`docker run -it --rm 7141cd2da206 bash`\n执行redis-server没有任何问题可以启动成功\n```\nroot@7d50439a05df:/data# ls -l /root/redis.conf \n-rwxrwxrwx 1 root root 58765 Sep 3 12:59 /root/redis.conf\n```\n```\nroot@7d50439a05df:/data# redis-server /root/redis.conf \n8:C 03 Sep 2019 13:05:46.070 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo\n8:C 03 Sep 2019 13:05:46.070 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=8, just started\n8:C 03 Sep 2019 13:05:46.070 # Configuration loaded\n _._ \n _.-``__ ''-._ \n _.-`` `. `_. ''-._ Redis 5.0.5 (00000000/0) 64 bit\n .-`` .-```. ```\\/ _.,_ ''-._ \n ( ' , .-` | `, ) Running in standalone mode\n |`-._`-...-` __...-.``-._|'` _.-'| Port: 6379\n | `-._ `._ / _.-' | PID: 8\n `-._ `-._ `-./ _.-' _.-' \n |`-._`-._ `-.__.-' _.-'_.-'| \n | `-._`-._ _.-'_.-' | http://redis.io \n `-._ `-._`-.__.-'_.-' _.-' \n |`-._`-._ `-.__.-' _.-'_.-'| \n | `-._`-._ _.-'_.-' | \n `-._ `-._`-.__.-'_.-' _.-' \n `-._ `-.__.-' _.-' \n `-._ _.-' \n `-.__.-' \n\n8:M 03 Sep 2019 13:05:46.072 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.\n8:M 03 Sep 2019 13:05:46.073 # Server initialized\n8:M 03 Sep 2019 13:05:46.073 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.\n8:M 03 Sep 2019 13:05:46.073 * Ready to accept connections\n\n```\n很困惑啊。。。\n-----更新------\n把dockerfile里redis-server替换成绝对路径又可以了\n```\nFROM redis:latest\nCOPY $PWD/redis.conf /root/\nCMD [\"/usr/local/bin/redis-server\", \"/root/redis.conf\"]\n```\n???",
"answer": "用 docker inspect 可以看到redis 的 docker 镜像的默认的 Entrypoint 是 `docker-entrypoint.sh` 。也就是说CMD 定义的命令是由这个脚本执行的。\n这个脚本的内容如下可能不同的版本会有所不同\n```\n#!/bin/sh\nset -e\n\n# first arg is `-f` or `--some-option`\n# or first arg is `something.conf`\nif [ \"${1#-}\" != \"$1\" ] || [ \"${1%.conf}\" != \"$1\" ]; then\n set -- redis-server \"$@\"\nfi\n\n# allow the container to be started with `--user`\nif [ \"$1\" = 'redis-server' -a \"$(id -u)\" = '0' ]; then\n find . \\! -user redis -exec chown redis '{}' +\n exec gosu redis \"$0\" \"$@\"\nfi\n\nexec \"$@\"\n```\n可以看到当 CMD 的第一个元素为 `redis-server` 的时候它将当前目录WorkingDir通过 docker inspect 可以看到是 `/data` 的所有文件的所有者改为了 `redis` ,然后以 `redis` 用户运行命令。\nDockerfile 里,虽然将 `/root/redis.conf` 的权限改成了 777 ,但是 `/root` 目录的权限是 700 redis 用户不可读,于是出错。将 `/root` 的权限也改成 777 就可以解决。\n========================\n由于脚本在进行精确匹配命令改为绝对路径后将不能匹配会进入最后一行的 exec 。此时是用 root 用户跑的,所以有读权限,可以启动。\n或者说只要 CMD 的第一个元素不是 `redis-server` ,那么用户就是 root 。所以用 bash 进容器里再跑也是没有问题的。\n最后如果 CMD 改成: `CMD redis-server /root/redis.conf` ,这个 CMD 会被改写成:`CMD [\"/bin/sh\", \"-c\", \"redis-server /root/redis.conf\"]` 。参考 Dockerfile / CMD 文档 ,并且可以通过 docker inspect 看到实际的 Cmd 。这时,运行的用户也是 root ,也是有读权限的,可以运行。\n在命令行指定 CMD 也会使用同样的规则,参考 docerker run / COMMAND 文档 可以解释相对路径会找不到文件,而改成绝对路径就可以的问题。\n======================\n如果 CMD 的第一个参数以 `-` 开始,或者以 `.conf` 结束,那么 `docker-entrypoint.sh` 会在前面加一个 `redis-server` 。这是其中第一个 `if` 干的事情。此时,由于第一个参数是(新插入的)`redis-server` ,所以也会以 redis 用户运行。\n也就是说启动 redis 镜像时,`redis-server` 命令其实可以不写,只写参数。比如:`CMD [\"/root/redis.conf\"]` 。或者,`docker run -it --rm a7f182f6c6dd /root/redis.conf` 。",
"type": "technical_qa"
},
{
"id": "segmentfault_64",
"question": "refresh token安全问题\n如果`access_token`有效期一个小时,`refresh_token`有效期7天\n- 那么在这7内天我都可以通过`refresh_token`获得`access_token`那不是等价于`access_token`有效期为7天了吗\n- 7天的有效期也会让安全风险增加那为什么还要用`refresh_token`呢?",
"answer": "这是一个有关暴露风险大小和有效期时长的问题,如果我们只有一个 token ,每次请求中都要携带这个,那么它暴露的风险会很高,如果这个 token 的有效期还比较长,那么它一旦暴露,损失会很高,所以 access_token 的有效期需要比较短。\n但是我们又不希望用户的登录有效期只能这么短那么怎么办呢refresh_token 的存在价值正在这里refresh_token 只需要在刷新 access_token 的请求里面携带,相对于 access_token 而言,它暴露的风险小很多,所以即便它的有效期比较长,相对来说造成损失的可能性也没那么高。\n更详细的看看这个Why Does OAuth v2 Have Both Access and Refresh Tokens?",
"type": "technical_qa"
},
{
"id": "segmentfault_65",
"question": "js:关于遍历数组中对象封装数据问题\n有个数组如下结构\n```\n let a = [\n {0: '内容11', 1: '内容12', 2: '内容13', 3: '内容14', head: '头部1'} ,\n {0: '内容21', 1: '内容22', 2: '内容23', 3: '内容24', head: '头部2'} ,\n {0: '内容31', 1: '内容32', 2: '内容33', 3: '内容34', head: '头部3'} ,\n ]\n```\n怎么变成下面的结构\n```\n let b = [\n {头部1: '内容11', 头部2: '内容21', 头部3: '内容31'}, \n {头部1: '内容11', 头部2: '内容21', 头部3: '内容31'}, \n {头部1: '内容11', 头部2: '内容21', 头部3: '内容31'}, \n {头部1: '内容14', 头部2: '内容24', 头部3: '内容34'}, \n ]\n```\n写了好久总有问题希望能解决。谢谢",
"answer": "```\n// 你这期望值给的我也是看不懂 大致猜测是行变列\n\nlet a = [\n { 0: '内容11', 1: '内容12', 2: '内容13', 3: '内容14', head: '头部1' },\n { 0: '内容21', 1: '内容22', 2: '内容23', 3: '内容24', head: '头部2' },\n { 0: '内容31', 1: '内容32', 2: '内容33', 3: '内容34', head: '头部3' }\n]\n\nfunction transformList(arr) {\n if (!Array.isArray(arr)) return\n\n return arr.reduce((temp, item, i) => {\n Object.keys(item).forEach((key, j) => {\n if (key === 'head') return\n if (!temp[j]) temp[j] = {}\n\n temp[j][item.head] = item[key]\n })\n return temp\n }, [])\n}\n\nconsole.log(transformList(a))\n// 打印\n[ { '头部1': '内容11', '头部2': '内容21', '头部3': '内容31' },\n { '头部1': '内容12', '头部2': '内容22', '头部3': '内容32' },\n { '头部1': '内容13', '头部2': '内容23', '头部3': '内容33' },\n { '头部1': '内容14', '头部2': '内容24', '头部3': '内容34' } ]\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_66",
"question": "为什么MySQL8.0直接把查询缓存的功能删除了呢?\n一种说法是不建议使用查询缓存因为查询缓存往往弊大于利。\n查询缓存的失效非常频繁只要有对一个表的更新这个表上的所有的查询缓存都会被清空。\n因此很可能你费劲地把结果存起来还没使用呢就被一个更新全清空了。对于更新压力大的数据库来说查询缓存的命中率会非常低。除非你的业务有一张静态表很长时间更新一次比如系统配置表那么这张表的查询才适合做查询缓存。\n在我看来大多数应用都把缓存做到了应用逻辑层简单的如一个map的mybatis复杂的可以用redis或者memcache直接操作内存远远比走网络访问快所以mysql直接抛弃了查询缓存",
"answer": "MySQL服务器团队有一篇关于此的详细博客其中Matt Lord说\n我们考虑了可以对查询缓存进行哪些改进以及我们可以进行的优化这些优化可以改善所有工作负载。\n虽然这些选择本身是正交的但工程资源是有限的。也就是说我们正在转变战略投资于更普遍适用于所有工作负载的改进。\n建议把缓存放到客户端",
"type": "technical_qa"
},
{
"id": "segmentfault_67",
"question": "js 树形结构数据 已知某一子节点 一次向上获取所有父节点\n```\nvar res = [{\n code: 1,\n name: \"湖北省\",\n children: [{\n code: 1,\n name: \"武汉市\",\n children: [{\n code: 1,\n name: \"汉阳区\",\n children: [{\n code: 1,\n name: \"水上分局1\"\n }]\n }, {\n code: 1,\n name: \"武昌区\",\n children: [{\n code: 1,\n name: \"水上分局2\"\n }]\n }, {\n code: 1,\n name: \"汉口区\",\n children: [{\n code: 1,\n name: \"水上分局3\"\n }]\n }]\n }, {\n code: 1,\n name: \"十堰市\",\n children: [{\n code: 1,\n name: \"郧阳区\",\n children: [{\n code: 1,\n name: \"安阳镇\"\n }]\n }, {\n code: 1,\n name: \"茅箭区\",\n children: [{\n code: 1,\n name: \"小川乡\"\n }]\n }]\n }]\n}]\n```\n已知树形结构 res。现在有一个对象是{code: 1,name: \"水上分局\"},想向上依次获取取得父级,比如说水上分局 父节点是汉阳区 汉阳区父节点是武汉市 武汉市父节点是湖北省 最后将 汉阳区 武汉市 湖北省 存起来 求指点",
"answer": "```\nfunction treeFindPath (tree, func, path = []) {\n if (!tree) return []\n for (const data of tree) {\n // 这里按照你的需求来存放最后返回的内容吧\n path.push(data.name)\n if (func(data)) return path\n if (data.children) {\n const findChildren = treeFindPath(data.children, func, path)\n if (findChildren.length) return findChildren\n }\n path.pop()\n }\n return []\n}\n\n```\n调用\n```\ntreeFindPath(res, data=> data.name==='水上分局')\n```\n打印调用结果\n```\n[\"湖北省\",\"武汉市\",\"汉阳区\",\"水上分局\"]\n```\n随手给你写一个函数吧这个确实比一般递归复杂那么一点点就是要记录一下你遍历过的节点。",
"type": "technical_qa"
},
{
"id": "segmentfault_68",
"question": "为什么要用vue-cli3\n其实这个问您要是想了解vue-cli3与vue-cli2相比是否存在一些不得不升级的好处和优点\n产生这个问题的原因是在试用完vue-cli3之后并没有觉得好用反而觉得束手束脚我cli2时webpack想怎么配怎么配为什么到了cli3我要在vue.config.js中配置\n众所周知vue-cli的通用配置并不适合每种情况,而在vue.config.js只能做增添和覆盖所以一直没有用vue-cli3构建项目\n所以想请教下 这个版本有没有值得升级的优点",
"answer": "好问题vue-cli3相对vue-cli有很多重要的更新。\n首先说一些vue-cli这些工具的初衷吧: 这些工具就是为了让开发者能够开箱即用快速地进行应用开发而开发的,它们秉承的是“约定大于配置”思想,简单说就是\"能不配置的就不配置,你就按照我的方式来,也不要去争论这个好不好,快速进行业务开发才是正经事\". 它们不建议你去配置,但也不会拦着你去配置。\n另外Webpack对初学者并不是十分友好又长又臭的配置普通开发者很难写入定义良好性能优化的配置。不然就不会各种cli工具冒出来了比如parcelcreate-react-app。这些工具都宣称零配置目的就是让开发者能够愉快的进行代码开发。\n现在来看看Vue-cli v3的改进以及思考这些有什么意义呢\n\n\n1. 抽离cli service层\nCreate-React-App是第一个做这种事情的。vue-cli3库现在包含以下两个模块\n- CLI: 即vue全局命令主要用于项目创建和管理包含了`vue create`、`vue ui`这些命令。CLI命令的做的事情比较少所以更新不会太频繁(开发者也很少会去更新这些命令)\n- Service层: 负责项目的实际构建也就是webpack项目构建。这一块是频繁更新的一般作为项目的局部依赖。\n\n\n\nOK这么做有什么意义呢考虑这样一个场景这也是一个痛点\nvue-cli3之前不算是一个构建CLI, 它顶多就是一个模板拷贝器, 所有webpack配置和构建命令都是耦合在具体的项目里面package.json会包含一大堆开发依赖。\n如果去跟进webpack或相关工具更新的朋友会有这种体会升级不是一件容易的事情。比如你升级了babel-loader, 可能要连带webpack都升级webpack升级后可能其他工具又不兼容了。\n升级方面的痛点是其一。如果你的团队需要维护很多项目你怎么对这些项目进行维护升级每个项目都拷贝一下如果某个项目做了特殊配置呢\n对于团队而言项目构建这一块是应该尽量做到的统一和傻瓜化的没有必要在这方面投入太多的精力应该把事情外包给擅长这种事情的人去做。\n另外不要排斥更新更新可以获得更好的开发体验和构建速度、运行性能, 别人在这方面比你了解的更多。\n分离了vue-cli-service之后项目构建更新只是一个命令的事情除非做了很多特殊化操作。特殊化操作应该封装到vue-cli的插件中。这就引出了vue-cli3的另外一个特色插件\n\n\n2. 插件化\n相比create-react-app, vue-cli是在太仁慈了。vue-cli的插件机制很灵活通过`webpack-chain`和`webpack-merge`可以实现webpack完全定制化。\n可以对比一下市面上流行的cli工具的可扩展性\n对于vue-cli的插件实现机制可以看这篇文章。\n因为vue-cli灵活的扩展性所以它不仅限于vue本身可以扩展支持react、anything...\n按照上文说的如果你要做深度的vue-cli定制化不建议直接写在vue.config.js中而是封装在插件中独立的维护这个插件然后项目再依赖这个插件。这样就可以简化升级的成本和复杂度。\n\n\n3. GUI界面\n虽然大部分人都觉得作用不大因为确实对开发效率并实际的提升效果。就是看着舒服直观这就够了。\n\n\n4. 快速原型开发\nvue-cli3也支持直接将一个vue文件跑起来快速原型开发或验证某些想法时挺不错。\n\n\n5. 现代模式\n给先进的浏览器配合先进的代码(ES6之后),同时兼容旧版本的浏览器,先进的代码不管从文件体积还是脚本解析效率都有较高的提升。\n体积对比:\n解析效率:\n总结一下\n- 如果我们喜欢折腾肯定会觉得vue-cli3束手束脚这时候我们不是vue-cli3的目标用户就比如我们团队就自己搞了一一个CLI构建工具: jm-cli, 根据自己的团队需求进行深度定制,不过我们这个工具是强约定的,包括目录结构、编码规范等等. 因为我们不推荐团队成员去搞特殊化定制,而且为了方便进行更新,所以干脆就不让扩展了,统一和规范对团队来说才是最重要的.\n如果你有类似的开发经验你会觉得vue-cli可能是所有构建CLI的最终归宿或者典范。\n\n- 如果不想折腾,只想写代码,那就直接拿来用吧;\n- 如果想折腾又要考虑团队协作和构建工具链的维护成本vue-cli是很适合的。当然你也可以造轮子\n- 如果想学webpack的构建项目也不推荐你使用vue-cli\n\n就比如我们团队就自己搞了一一个CLI构建工具: jm-cli, 根据自己的团队需求进行深度定制,不过我们这个工具是强约定的,包括目录结构、编码规范等等. 因为我们不推荐团队成员去搞特殊化定制,而且为了方便进行更新,所以干脆就不让扩展了,统一和规范对团队来说才是最重要的.\n如果你有类似的开发经验你会觉得vue-cli可能是所有构建CLI的最终归宿或者典范。\n\n\n最后给vue团队点个赞?\n欢迎关注我和我交流",
"type": "technical_qa"
},
{
"id": "segmentfault_69",
"question": "Typescript内置类型中的Exclude实现原理\n#### lib.es5.d.ts\n```\n/**\n * Exclude from T those types that are assignable to U\n */\ntype Exclude<T, U> = T extends U ? never : T;\n```\n#### 问题\n```\ntype AB = 'a' | 'b'\ntype BC = 'b' | 'c'\ntype Demo = Exclude<AB, BC> // => type Demo = 'a'\n```\n从结果上看`T extends U`判断了 truthy 和 falsy同时进行逻辑运算并把结果赋值给T`extends`的这个功能官网有介绍吗?",
"answer": "`T extends U ? never : T` 表示如果 `T`是 `U`的子类返回`never`类型,如果不是返回`T`类型。\n当`T`为联合类型的时候,它会自动分发条件。\nTS 一些工具泛型的使用及其实现",
"type": "technical_qa"
},
{
"id": "segmentfault_70",
"question": "计算一个整数数组中最大差值的元素?\n#### 我用php实现的代码比较暴力类似于冒泡排序.\n```\n$arr = [4,2,7,5,11,13,9,1];\n$a = 0;\n$b = 0;\nfor ($i = count($arr) - 1; $i >= 0; $i--) {\n for ($j = 0; $j <= $i - 1; $j++) {\n $tmp = $arr[$i] - $arr[$j];\n\n if ($tmp > $a) {\n $a = $tmp;\n $b = $arr[$i];\n }\n }\n}\n\necho $b;\n```\n求一个更优的算法语言不限。",
"answer": "@Reming 的算法有一个小漏洞, 如果数据是这样的话, 算出来的实际上是有问题的.\n```\n[4, 2, 7, 5, 11, 13, 9, 0, 12]\n```\n个人认为, 这个问题有两个关注点:\n- 最小值\n- 最大差值\n\n但和最大值无关, 我们需要关注的是最大差值, 可能最大值出现的时候, 最小值还没有出现, 而后面出现的数值减去最小值可能反而比较大. 上面的用例就是基于这种逻辑设计出来的.\n修改后逻辑为: 向后循环遍历, 记录下到目前为止的最小值 以及 最大差值, 然后计算当前元素-目前为止最小值, 判断大小. 记录最大的差值即可.\n基于 @Reming 的代码稍微修改了下:\n```\nvar arr = [4, 2, 7, 5, 11, 13, 9, 0, 12];\nvar min = arr[0], maxDValue = 0;\n\narr.forEach((el, index) => {\n if (min > el) min = el;\n\n var diff = el - min;\n if (diff > maxDValue) {\n maxDValue = diff;\n };\n});\n\nconsole.log(maxDValue);\n```\n再补充一句, 实际上这个问题可以这样想:\n- 假设有一个数组[a1, a2, a3, ..., an]\n- \n那么我们可以分两步计算出来最大差值\n\n计算a1与左边元素的最大差值, a2与左边元素最大的差值, a3与左边元素的最大差值....an与左边元素的最大差值.\n计算所有最大差值里的最大值.\n\n\n- 其中第一步实际上就是就算am(m=1, 2, 3...)与其左边最小值的差值, 所以我们只需要记录当前最小值以及最大的差值即可.\n\n那么我们可以分两步计算出来最大差值\n- 计算a1与左边元素的最大差值, a2与左边元素最大的差值, a3与左边元素的最大差值....an与左边元素的最大差值.\n- 计算所有最大差值里的最大值.",
"type": "technical_qa"
},
{
"id": "segmentfault_71",
"question": "flutter进入首页的时候判断是否登录没登录则跳到登录页这个怎么实现\n进入首页的时候判断是否登录没登录则跳到登录页这个怎么实现",
"answer": "链接描述\n这是我写的一个demo实现了你要的功能\n```\nclass _StartAppState extends State<StartApp>{\n\n var loginState;\n\n void initState(){\n super.initState();\n _validateLogin();\n }\n \n @override\n Widget build(BuildContext context){\n ScreenUtil.instance = ScreenUtil(width: 750,height: 1334)..init(context);\n\n final router = Router();\n Routes.configureRoutes(router);\n Application.router = router;\n\n print(loginState);\n if(loginState == 0){\n return LoginPage();\n }else{\n return HomePage();\n }\n }\n\n Future _validateLogin() async{\n Future<dynamic> future = Future(()async{\n SharedPreferences prefs =await SharedPreferences.getInstance();\n return prefs.getString(\"loginToken\");\n });\n future.then((val){\n if(val == null){\n setState(() {\n loginState = 0;\n });\n }else{\n setState(() {\n loginState = 1;\n });\n }\n }).catchError((_){\n print(\"catchError\");\n });\n \n }\n\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_72",
"question": "面试遇到的问题,面试之后,感觉十分好奇\n考官问我做的前端页面是组件切换还是跳转的页面。举个例子比如一个 类似淘宝“个人中心” 页面上可以选择不同的订单状态的tab点击就会进入订单列表页面这样的页面是直接用一个页面然后切换状态显示还是直接两个不同的页面呢\n我回答是两个页面因为我觉得两个页面的内容都不一样也符合跳转的逻辑。但是面试官明显的失望了所以我后来琢磨是不是写成一个页面然后切换状态体验比较好而且不用传递订单的状态参数过去呢具体有什么原因呢我想起来京东也是做成切换的他的商品分类页面的搜索框点击搜索框会切换到搜索页面实际上是一个页面在切换状态显示不同的内容这么做的意义是什么呢\n如果说做成一个页面切换显示那么就是单纯的v-if切换吗我使用的是vue",
"answer": "单独从京东的搜索界面来说。\n大部分情况下搜索界面的内容不是很复杂基本就是一个input一些搜索记录和热搜的 item ,为页面加载不会带来太大的鸭梨,而且,一般搜索记录是本地存储,可以优先读入,提升用户体验,搜索记录是 ajax 后端读取,即使预读也不会有太多的鸭梨,这些都是可以用 Redis 做到缓冲,而且 搜索相对于用户体验体验来说,也应该是点击就能出现的,所以做成一个 `图层` 我觉得没什么问题,是一个比较好的设计。即使在 wap 2.0 时代,搜索只是嵌入在页面亦是如此,点击即可输入进行操作。\n至于题干中的 个人中心 > 订单列表,无论从项目设计还是实践来说,都应该采用分页面的方式,当然现在的单页用了 router 后,只要后端不拖后腿(你可以提前预读),页面载入也是很快的,对用户体验基本造成不了太大的影响,但是如果这两个页面混合在一起,那么对于相对来说,页面层级混乱,不容易管理。\n如果单从开发来说如果你对组件分割能够游刃有余那也不是问题直接做进去也是完全可以的但是违背开发原则。\n从面试的角度来讲或许对方更想考察你对不同业务环境下该采用什么样的方式方法来处理问题是关键的其次因为这些不成定性的东西大家基本都是按照自己第一感去处理如果你能说服他或者达成某些共识在一定程度上还可以为自己加分。",
"type": "technical_qa"
},
{
"id": "segmentfault_73",
"question": "npm 的 --unsafe-perm 参数是有何作用呢?\nnpm 的 --unsafe-perm 参数是有何作用呢?",
"answer": "这玩意儿看官方文档啊https://docs.npmjs.com/misc/c...\n就是说 npm 出于安全考虑不支持以 root 用户运行,即使你用 root 用户身份运行了npm 会自动转成一个叫 nobody 的用户来运行,而这个用户几乎没有任何权限。这样的话如果你脚本里有一些需要权限的操作,比如写文件(尤其是写 /root/.node-gyp就会崩掉了。\n为了避免这种情况要么按照 npm 的规矩来,专门建一个用于运行 npm 的高权限用户;要么加 --unsafe-perm 参数,这样就不会切换到 nobody 上,运行时是哪个用户就是哪个用户,即使是 root。",
"type": "technical_qa"
},
{
"id": "segmentfault_74",
"question": "Java集合 modCount为什么不用volatile修饰\n2个线程 访问一个list 其中一个remove操作了 另一个在迭代 假如不用vol修饰 那么在迭代的那个线程可能感知不到modcount的变化啊\n甚至于说官方认为有volatile是一个BUGhttps://bugs.java.com/bugdata...",
"answer": "我觉得你是理解有误首先Java集合中有`modCount`属性未加`volatile`的都是线程不安全的集合类,都是单线程集合类`single thread collections`,讲单线程集合类放到多线程中去讨论,是很不合适的。\n所以你的假设在多线程情况下的可见行问题根本就不应该出现这个问题!因为你的思路就有问题。\n要保证有这个属性的集合类的正确使用至少不会出现在多线程的编程中这是前提条件为什么呢\n`fail-fast`机制是确保集合类遍历过程中集合类不会出现结构性修改(增、删元素)\n一般认为在遍历时出现结构性修改那么遍历将无法保证所有元素均能被遍历到新增时也无法顺利完成遍历删除时\n要在遍历是进行结构性修改必须配合`Iterator`提供的`remove()`方法\n我觉得你应该考虑的问题是为什么会出现`fail-fast`机制这个东西,这个东西的出现是为了解决什么样子的问题。\n你要记住`modCount`本身就不是为多线程准备的,再多线程情况下诸如`ArrayList`之类的集合类连本身线程安全都保证不了,又有什么必要去设计一个线程安全的`modCount`呢?\n你要一个先天就不具备线程安全的类去实现线程安全的问题干嘛呢这根本不是它考虑的问题这完全没有必要。如果真这么做了就不仅仅是设计过度的问题了。",
"type": "technical_qa"
},
{
"id": "segmentfault_75",
"question": "JS正则中的$1的一个问题\n```\nvar str = 'this is a test'\nconsole.log(str.replace(/\\b(\\w)/g, ('$1'+'a').toUpperCase()))\n// tAhis iAs aA tAest\n```\n为什么输出的不是TAhis IAs AA TAest\nstr.replace(/b(w)/g, ('$1').toUpperCase())为什么调用的toUpperCase这个方法无效。",
"answer": "你对于toUpperCase的作用范围理解错了\n```\nstr.replace(/\\b(\\w)/g, ('$1'+'a').toUpperCase())\n\n```\n相当于\n```\nstr.replace(/\\b(\\w)/g, '$1A')\n\n```\n$1的大写还是$1,你只是把替换规则的字符串大写了,并没有把替换的结果大写\n如果需要大写的话用以下方法就可以了\nstr.replace(/b(w)/g, v => `${v}a`.toUpperCase())",
"type": "technical_qa"
},
{
"id": "segmentfault_76",
"question": "echarts地图能不能通过加减按钮控制缩放\n### 项目中用到了echarts的地图在geo里有roam参数不过是通过滚轮控制缩放的这样用户体验不太好能不能通过加减按钮或者地图比例尺的形式来控制缩放",
"answer": "可以试试我写的这个\n```\n<button onclick=\"roamMap(0)\" style=\"position: absolute; z-index: 999\">+</button>\n<button onclick=\"roamMap(1)\" style=\"position: absolute; left: 5%; z-index: 999\">-</button>\n```\n```\n // 地图缩放 flag: 0->放大 1->缩小\n function roamMap(flag) {\n let currentZoom = nationalChart.getOption().geo[0].zoom; // 当前的缩放比例\n \n let increaseAmplitude = 1.2; // 点击按钮每次 放大/缩小 比例\n if (flag == 1) {\n increaseAmplitude = 0.8\n }\n\n nationalChart.setOption({\n geo: {\n zoom: currentZoom*increaseAmplitude\n }\n })\n }\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_77",
"question": "如何让img里的图片自适应div并填充不变形\n```\n<div>\n <img src=\"...\" alt=\"image\">\n<div>\n\nimg如何随父元素div改变尺寸填充整个img并且不变形\n就是background-size: cover;的感觉。\n\n或者保持不变形只显示图片的一部分也可以\n\n谢谢大家。\n```",
"answer": "img标签在固定高宽的div里的显示除了JS以及背景图片可以试一下使用css属性object-fit属性。\n它的几个属性\n```\nfill不保持纵横比缩放图片使图片完全适应\ncontain保持纵横比缩放图片使图片的长边能完全显示出来\ncover保持纵横比缩放图片只保证图片的短边能完全显示出来\nnone保持图片宽高不变\nscale-down当图片实际宽高小于所设置的图片宽高时显示效果与none一致否则显示效果与contain一致\ninherit\ninitial\nunset\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_78",
"question": "vscode怎么快速重启?\n## 如题:\n## 当 \n## 可是我在菜单没有找到\n## 因为可能经常会用到",
"answer": "打开:“命令面板”\nCTRL + SHITF + P\n输入\n```\n> Reload Window\n```\n也可以绑定`快捷键`\n```\n{\n \"key\": \"ctrl+f5\",\n \"command\": \"workbench.action.reloadWindow\",\n \"when\": \"editorTextFocus\"\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_79",
"question": "vue中v-for写成render的形式key怎么解决\n项目中有部分代码写层render的形式比template会更好...\n但是遇到了一个问题我们都知道v-for的时候是必须要设置key的当我用render去遍历一个数组的时候key怎么设置呢我将key放在单个组件的props或是domProps都不起作用。一下是render代码\n这里Goup和Cell都是vue对象...也就是components\n```\nrender(h): any {\n const mapNode = (h): any =>{\n const conArray = [];\n let hVnode = ( vNodeName, part ): any =>{\n return h(vNodeName, {\n props: {\n part: part,\n key: part.partId\n },\n domProps: {\n key: part.partId\n },\n });\n } \n for(let item of this.partList) {\n if(item.partType === 'group') {\n conArray.push( hVnode(Group, item) );\n } else {\n conArray.push( hVnode(Cell, item) );\n }\n }\n return conArray;\n }\n return h( 'div', {\n attrs: {\n class: 'group-list',\n id: \"group-list\"\n }\n },\n mapNode(h)\n );\n },\n```\n可行的方案是template一下是代码\n```\n<template>\n <div class='group-list' id=\"group-list\">\n <div v-for=\"item of partList\" :key=\"item.partId\">\n <template v-if=\"item.partType === 'group'\">\n <Group :part=\"item\"></Group>\n </template>\n <template v-else-if=\"item.partType === ''\">\n <Cell :part=\"item\"></Cell>\n </template>\n </div>\n </div>\n</template>\n```\n以上render的形式key值不起作用表现在删除数组的时候一定会删除最后一个即使我删除的是第一个数组对象...",
"answer": "```\nreturn h(vNodeName, {\n key: part.partId,\n});\n```\n教个小诀窍如果对`render`不是很熟,可以先写好`template`,然后借助`Vue.compile`来生成`render`\n```\nimport Vue from 'vue';\n\nconst res = Vue.compile(`\n<div class='group-list' id=\"group-list\">\n <div v-for=\"item of partList\" :key=\"item.partId\">\n <template v-if=\"item.partType === 'group'\">\n <Group :part=\"item\"></Group>\n </template>\n <template v-else-if=\"item.partType === ''\">\n <Cell :part=\"item\"></Cell>\n </template>\n </div>\n</div>\n`);\n\nconsole.log(res.render);\n```\n这样控制台会打印出来生成好的`render`函数,不明白可以参见内部细节",
"type": "technical_qa"
},
{
"id": "segmentfault_80",
"question": "webpack 打包库时出现 window is not defined\n按照官网的步骤进行库的打包 创建library\nwebpack.config.js\n```\nvar path = require('path');\n\nmodule.exports = {\n entry: './src/index.js',\n mode: 'production',\n output: {\n path: path.resolve(__dirname, 'dist'),\n filename: 'webpack-numbers.js',\n library: 'webpackNumbers', // 支持多种模式的导出\n libraryTarget: 'umd'\n },\n externals: { \n lodash: {\n commonjs: 'lodash',\n commonjs2: 'lodash',\n amd: 'lodash',\n root: '_'\n }\n },\n```\nindex.js\n```\nimport _ from 'lodash';\nimport numRef from './ref.json';\n\nexport function numToWord(num) {\n return _.reduce(numRef, (accum, ref) => {\n return ref.num === num ? ref.word : accum;\n }, '');\n}\n\nexport function wordToNum(word) {\n return _.reduce(numRef, (accum, ref) => {\n return (ref.word.toLowerCase() === word.toLowerCase()) ? ref.num : accum;\n }, -1);\n}\n```\n使用 test.js 测试导出的包在 node 环境能否使用\n```\nconst _ = require('lodash') \n\nconst webpackNmuners = require('../dist/webpack-numbers')\n\nconsole.log(webpackNmuners.numToWord(4))\n\nconsole.log(webpackNmuners.wordToNum('four'))\n```\n运行时报错\n```\nReferenceError: window is not defined\n \n```\n查看打包出来的模块,发现确实存在 window 对象\n如果存在 window 对象,那么这个模块就不能在 node 环境中使用\n但是我现在的配置和官网都是一致的,不应该出现这种情况啊\n现在要使库生效,我得手动进入打包后的文件把 window 改为 this\n请问一下这是哪里出了问题,webpack 版本是 webpack 4.29.6",
"answer": "你需要在`output`里面设置`globalObject`\n```\n// webpack.config.js\nmodule.exports = {\n ...\n output: {\n path: path.resolve(__dirname, 'dist'),\n filename: 'webpack-numbers.js',\n library: 'webpackNumbers', \n globalObject: 'this', // 添加这个选项\n libraryTarget: 'umd'\n }\n ...\n}\n```\noutput.globalObject",
"type": "technical_qa"
},
{
"id": "segmentfault_81",
"question": "【编程进阶】js实现一个map函数\n实现一个myOwnMap函数:\n输入\n```\n[1,2,3].myOwnMap((item, index) => {\n return item *2\n})\n\n```\n输出 `[2,4,6]`",
"answer": "首先要搞清楚`map()`函数的用法,传入一个函数,函数允许传三个参数(数组每一项,数组索引,数组本身),并且`map()`函数有返回值,如此一来也就有思路了:\n```\n Array.prototype.newMap = function(fn,context){\n if(typeof fn !== 'function')return;\n var newArr = [];\n for(var i = 0;i < this.length;i++){\n newArr.push(fn.call(context,this[i],i,this,context));\n }\n return newArr;\n }\n //调用\n [1,2,3].newMap(function(item){\n return item * 2;\n });//[2,4,6]\n\n\n\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_82",
"question": "typescript声明联合类型元组后加入新元素\n刚刚看ts的文档看到元组越界的时候尝试了下\n```\nlet x: [string, number];\nx = ['hello', 10];\n当访问一个越界的元素会使用联合类型替代\nx[3] = 'world'; // OK, 字符串可以赋值给(string | number)类型\nconsole.log(x[5].toString()); // OK, 'string' 和 'number' 都有 toString\n\nx[6] = true; // Error, 布尔不是(string | number)类型\n```\n写到这里就会报错了表示不能直接更改一个长度为2的数组的第三个索引值试了下另一个教程的push方法发现可以插入成功但是依旧不能通过索引访问也不能改变元组length属性\n感到有些疑惑ts是js超集这里感觉不能直接改变数组元素呢push之后元素已经插入了但是却访问不了该元素又是怎么回事呢 求教",
"answer": "官方文档关于这一点上没有更新。\n事实上在 Typescript 2.7Fixed Length Tuples 一节中) 之后, Tuple 的定义已经变成了有限制长度的数组了。\n```\ninterface NumStrTuple extends Array<number | string> {\n 0: number;\n 1: string;\n length: 2; // using the numeric literal type '2'\n}\n```\n所以你不能再越界访问了。",
"type": "technical_qa"
},
{
"id": "segmentfault_83",
"question": "闭包js这样写有什么好处\n很多地方都可以看到js代码用\n```\n(function($){\n //代码\n var demo = function(){\n \n };\n \n var demo2 = function(){\n \n }; \n})(jQuery)\n```\n这样包起来这是js闭包吧。把js代码写到这个里面有什么好处呢\n```\n<script type=\"text/javascript\">\n (function($){\n var hehe = funcion(){\n alert('hehe');\n };\n })(jQuery);\n</script>\n```",
"answer": "这是一个立即执行匿名函数,同时也是一个闭包。\n闭包的作用主要有两个减少全局变量保护变量\n举两个例子请您揣摩\n```\n// 第一例:\nvar a = function(){\n alert('global');\n};\n(function(){\n var a = function(){\n alert('closure');\n }\n a();\n})();\na();\n\n\n// 第二例:\nvar setter = function(){\n var privateVar;\n return {\n set: function(v){\n privateVar = v;\n },\n get: function(){\n return privateVar;\n }\n };\n}();\n\nsetter.set('hello world');\nsetter.get();\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_84",
"question": "python爬虫程序的原理是什么PHP不能写爬虫吗\npython爬虫程序的原理是什么PHP不能写爬虫吗",
"answer": "爬虫的原理是从一个起始`种子链接`开始,发`http请求`这个链接,得到该链接中的内容,然后大多使用`正则匹配`出页面里面的`有效链接`,然后将这些链接保存到待访问队列中,等待`爬取线程`取这个待访队列,一旦链接访问过了,为了有效的减少不必要的网络请求,我们应该把访问过的链接放到一个`已访问map`中,已防止重复抓取及死循环。我以上提到的过程可能是一个比较简单的爬虫实现,复杂的可能不会这么简单,但这里面有几个概念,一个是发`http请求`,一个是`正则匹配`你感兴趣的链接,一个是`多线程`,另外还有`两个队列`,理论上,任何能实现这么些概念的编程语言去写爬虫都是可以的,期间取舍还是看自己对熟练成都。",
"type": "technical_qa"
},
{
"id": "segmentfault_85",
"question": "关于递归问题 js\n原数据格式\n```\nlet obj =[\n {1:'20190805',2:'1',3:'success'},\n {1:'20191120',2:'1.1',3:'success'},\n {1:'20190212',2:'1.1.1',3:'success'},\n {1:'20190212',2:'1.1.2',3:'success'},\n {1:'20190212',2:'1.1.3',3:'success'},\n {1:'20190212',2:'1.2',3:'success'},\n {1:'20190212',2:'1.2.1',3:'success'},\n {1:'20190212',2:'2',3:'success'},\n {1:'20190212',2:'2.1',3:'success'},\n {1:'20190212',2:'2.2.1',3:'success'},\n {1:'20190212',2:'2.2',3:'success'},\n {1:'20190212',2:'2.3',3:'success'},\n {1:'20190212',2:'2.3.1',3:'success'},\n ...\n ]\n```\n最后想要下面这种结果格式请问该怎么实现呢\n```\nlet data = [\n {1: '20190805', 2: '1', 3: 'success', children: [\n {1: '20191120', 2: '1.1', 3: 'success', children: [\n {1: '20190212', 2: '1.1.1', 3: 'success'},\n {1: '20190212', 2: '1.1.2', 3: 'success'},\n {1: '20190212', 2: '1.1.3', 3: 'success'},\n ]}, {1: '20191120', 2: '1.2', 3: 'success', children: [\n {1: '20190212', 2: '1.2.1', 3: 'success'},\n ]\n }]\n },\n {1: '20190212', 2: '2', 3: 'success', children: [\n {1: '20190212', 2: '2.1', 3: 'success', children: [\n {1: '20190212', 2: '2.2.1', 3: 'success'},\n ]},\n {1: '20190212', 2: '2.2', 3: 'success'},\n {1: '20190212', 2: '2.3', 3: 'success', children: [\n {1: '20190212', 2: '2.3.1', 3: 'success'}]\n }]\n },\n ...\n ]\n```",
"answer": "```\n/**\n *\n * @param {Array} source\n * @returns {Array} 分类好的数据\n */\nfunction mark(source) {\n var temp = {};\n source.forEach(item => {\n temp[item[\"2\"]] = item;\n });\n source.forEach(item => {\n var key = item[\"2\"],\n parent;\n //子级\n if (key.length > 1) {\n //子级的父 id\n key = key.slice(0, -2);\n parent = temp[key];\n if (parent) {\n parent.children = parent.children || [];\n parent.children.push(item);\n }\n }\n });\n return Object.keys(temp).reduce((ret, key) => ret.concat(key.length === 1 ? temp[key] : []), []);\n}\n\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_86",
"question": "关于js 递归方法\n### 题目描述\n有2个数组\n### 相关代码\n```\nvar a = ['customer','supplier','materal','purchaseOrder','rolesMenge']\nvar b = [\n {\n name:'maindata',\n children:[\n {\n name:'customer',\n meta:{\n title:'customer' \n }\n },\n {\n name:'supplier',\n meta:{\n title:'supplier' \n }\n },\n {\n name:'materal',\n meta:{\n title:'materal' \n }\n },\n ]\n },\n {\n name:'purchase',\n children:[\n {\n name:'purchaseOrder',\n meta:{\n title:'purchaseOrder' \n }\n },\n {\n name:'purchaseGood',\n meta:{\n title:'purchaseGood' \n }\n },\n ]\n },\n {\n name:'stock',\n children:[\n {\n name:'stockOrder',\n meta:{\n title:'stockOrder' \n }\n }\n ]\n },\n {\n name:'config',\n children:[\n {\n name:'userConfig',\n children:[\n {\n name:'rolesMenge',\n meta:{\n title:'rolesMenge' \n }\n }\n ]\n },\n ]\n }\n]\n\n```\n### 我的代码\n```\nfunction getarr(a,b){\n return b.reduce((k,m) => {\n if(m.children){\n let obj = {\n name:m.name,\n children:[]\n }\n for(let j of m.children){\n if(j.children){\n getarr(a,m.children)\n } else {\n if(a.includes(j.meta.title)){\n obj.children.push(j)\n }\n }\n \n }\n if(obj.children.length){\n k.push(obj)\n }\n\n }\n return k\n },[])\n}\n```\n### 你期待的结果是什么?实际看到的错误信息又是什么?\n希望得到\n```\n[\n {\n name: \"maindata\",\n children:[\n {\n name:'customer',\n meta:{\n title:'customer' \n }\n },\n {\n name:'supplier',\n meta:{\n title:'supplier' \n }\n },\n {\n name:'materal',\n meta:{\n title:'materal' \n }\n }\n ]\n }, \n {\n name:'purchase',\n children:[\n {\n name:'purchaseOrder',\n meta:{\n title:'purchaseOrder' \n }\n }\n ]\n },\n {\n name:'config',\n children:[\n {\n name:'userConfig',\n children:[\n {\n name:'rolesMenge',\n meta:{\n title:'rolesMenge' \n }\n }\n ]\n },\n ]\n }\n]\n```",
"answer": "前不久刚回答了另一个类似的问题,本来以为是一样的,仔细分析之后发现这两个问题有一点重大差异:\n- 这个问题要求结果保留原树结构,也就是说,符合条件节点的父路径上所有节点都要保留\n\n新的 `deal()` 修改如下(含注释),顺便处理了之前那个问题结果中含大量空 `children` 的问题\n```\n/**\n * 递归过滤节点,但保留原树结构,即符合条件节点的父路径上所有节点不管是否符合条件都保留\n * @param {Node[]} nodes 要过滤的节点\n * @param {node => boolean} predicate 过滤条件,符合条件的节点保留\n * @return 过滤后的根节点数组\n */\nfunction deal(nodes, predicate) {\n // 如果已经没有节点了,结束递归\n if (!(nodes && nodes.length)) {\n return;\n }\n\n const newChildren = [];\n for (const node of nodes) {\n if (predicate(node)) {\n // 如果自己(节点)符合条件,直接加入到新的节点集\n newChildren.push(node);\n // 并接着处理其 children\n node.children = deal(node.children, predicate);\n } else {\n // 如果自己不符合条件,需要根据子集来判断它是否将其加入新节点集\n // 根据递归调用 deal() 的返回值来判断\n const subs = deal(node.children, predicate);\n if (subs && subs.length) {\n // 1. 如果子孙集中有符合要求的节点(返回 [...]),加入\n node.children = subs;\n newChildren.push(node);\n }\n // 2. 否则,不加入(因为整个子集都没有符合条件的)\n }\n }\n return newChildren.length ? newChildren : void 0;\n}\n```\n不过这不是最终答案因为代码还可以进行优化。`if` 的两个分支中都需要递归,根据递归的结果来,结合对当前节点的检查来判断是否需要加入当前节点,所以循环内部可以修改一下\n```\n for (const node of nodes) {\n const subs = deal(node.children, predicate);\n\n // 以下两个条件任何一个成立,当前节点都应该加入到新子节点集中\n // 1. 子孙节点中存在符合条件的,即 subs 数组中有值\n // 2. 自己本身符合条件\n if ((subs && subs.length) || predicate(node)) {\n node.children = subs;\n newChildren.push(node);\n }\n }\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_87",
"question": "微信浏览器H5页面软键盘关闭导致页面空缺的问题\n1. 微信6.7.4 H5页面里的select,input软键盘弹起的时候页面会上移软键盘关闭页面不会下移。导致页面空缺了一部分。\n2. 微信6.7.3及其它版本不会有这个问题!页面会随着软键盘关闭而下移恢复正常!",
"answer": "您可以尝试以下代码\n```\n $('textarea').on('blur',function(){\n setTimeout(function(){\n window.scrollTo(0, 0)\n },100)\n })\n```\n\n如果出现同页面有两个以上输入框当输入完第一个未关闭软键盘就去点第二个输入框的时候页面回滚到顶部导致输入框被软键盘盖住的问题也可以将以上代码改写一下```\n'$(\"input,textarea\").on(\"blur\",function(){\n setTimeout(function(){\n window.scrollTo(0,0);\n },100)\n}).on('focus',function(){\n var clientHeight = document.documentElement.clientHeight || document.body.clientHeight;\n var offsetTop = $(this).offset().top - (clientHeight / 4);\n setTimeout(function(){\n window.scrollTo(0,offsetTop);\n },100)\n})\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_88",
"question": "Java8 unordered() 无序化无效\n### Java8 unordered()无序化无效, 多次运行结果还是与流中元素顺序一致\n// 多次运行结果: 5, 1, 2, 6, 3, 7, 4 没有达到无序的效果\nStream.of(5, 1, 2, 6, 3, 7, 4).unordered().forEach(System.out::println);\n求大神指教\n### 相关代码\n```\n\n /**\n * S unordered(); 产生一个与当前流中元素相同的无序流, 当流本身就是无序或流已经无序, 会返回流本身\n */\n @Test\n public void unorderedTest() {\n Stream.of(5, 1, 2, 6, 3, 7, 4).forEach(System.out::println);\n \n // 多次运行结果: 5, 1, 2, 6, 3, 7, 4 没有达到无序的效果 TODO\n Stream.of(5, 1, 2, 6, 3, 7, 4).unordered().forEach(System.out::println);\n }\n\n\n```",
"answer": "`unordered()`操作不会执行任何操作来显式地对流进行排序。它的作用是消除了流必须保持有序的约束,从而允许后续操作使用不必考虑排序的优化。\n您可以在Java 8文档中阅读此内容\n在流有序时, 但用户不特别关心该顺序的情况下,使用 unordered 明确地对流进行去除有序约束可以改善某些有状态或终端操作的并行性能。\n可以比较下面的结果\n```\n Stream.of(5, 1, 2, 6, 3, 7, 4).unordered().forEach(System.out::println);\n Stream.of(5, 1, 2, 6, 3, 7, 4).unordered().parallel().forEach(System.out::println);\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_89",
"question": "vuedraggable中如何设置部分元素不可拖拽\ndraggable渲染成了ul但是想让ul中部分li元素可拖拽部分li元素不可拖拽。\n文档只给出了在option中设置disabled;sort等属性可以让整个标签不能拖拽但是没有给出让子元素不可拖拽的实现方法。\n如果要实现部分子元素可拖拽部分子元素不可拖拽的话除了把一个ul拆分成两个ul还有其他方法吗",
"answer": "handle: selector 格式为简单css选择器的字符串使列表单元中符合选择器的元素成为拖动的手柄只有按住拖动手柄才能使列表单元进行拖动\n根据上述进行配置可拖动手柄handle'.header'",
"type": "technical_qa"
},
{
"id": "segmentfault_90",
"question": "关于 js 函数默认值的问题\n下面这两种写法为什么会产生两种不同的结果求大佬详细解答.... 个人觉得是跟函数参数的块级作用域有关.....但是理解起来还是怪怪的,而且用 chrome debugger 来查看也觉得怪怪的,为啥最后那个输入 x是根据 Block 来输出的?万分感谢~\n```\nfunction test (x, y = function t () { x = 2 }) {\n var x\n y()\n console.log(x) // undefined\n}\ntest()\n```\n```\nfunction test (x, y = function t () { x = 2 }) {\n // var x\n y()\n console.log(x) // 2\n}\ndebugger\ntest()\n```",
"answer": "9.2.12 FunctionDeclarationInstantiation\n如果存在函数默认值那么会为函数体部分创建第二个环境记录这个第二个环境是在函数默认值之下的。\n类似于\n```\n// ES6\nfunction foo(x, y = function() { x = 2; }) {\n var x = 3;\n y(); // is `x` shared?\n console.log(x); // no, still 3, not 2\n}\n \n// Compiled to ES5\nfunction foo(x, y) {\n // Setup defaults.\n if (typeof y == 'undefined') {\n y = function() { x = 2; }; // now clearly see that it updates `x` from params\n }\n \n return function() {\n var x = 3; // now clearly see that this `x` is from inner scope\n y();\n console.log(x);\n }.apply(this, arguments);\n}\n```\n代码来自 es6-notes-default-values-of-parameters",
"type": "technical_qa"
},
{
"id": "segmentfault_91",
"question": "java反射使用setAccessible(true)调用private方法问题\n如题定义了一个Person类有一个private方法\n```\npublic Person {\n private void test();//private方法\n}\n```\n使用反射来调用\n先说有问题的方法\n```\nConstructor con= Person.class.getConstructor();//构造方法\nObject object = con.newInstance();//生成对象\n//有问题\nPerson.class.getDeclareMethod(\"test\").setAccessible(true);\nPerson.class.getDeclareMethod(\"test\").invoke(object);//报错不能访问\n/*Person.class.getDeclareMethod(\"test\").isAccessible()还是等于false*/\n```\n而使用下面的写法却可以\n```\nMethod = Person.class.getDeclareMethod(\"test\")\nmethod.setAccessible(true);\nmethod.invoke(object);//不报错,正常执行\n/*method.isAccessible()是true\n而Person.class.getDeclareMethod(\"test\").isAccessible()还是等于false\n*/\n```\n这是Person.class.getDeclareMethod(\"test\")方法的问题吗,这个问题在反射调用构造函数时也会出现,他们都有一个@CallerSensitive注解是这个原因吗望解答。",
"answer": "每次获取方法得到不是同一个`Method`对象 \n`setAccessable`仅作用于得到的方法对象,也不是全局的 \n所以第一种写法会报错 \n另外`setAccessable`的属性并没有被包含在`Method`的`equals` 和`hashCode`中",
"type": "technical_qa"
},
{
"id": "segmentfault_92",
"question": "一道关于js类型转换的面试题\nif([] == false){console.log('a')}\nif({} == false){console.log('b')}\nif([] == {}){console.log('c')}\nif([]){console.log('d')}\n这几道题的隐式转换的方式大神帮忙解答下吧",
"answer": "对象和非对象之间的相等比较\nES5 规范 11.9.3.8-9 做如下规定:\n`ToPrimitive`就是尝试返回它的原始值,也就是`string`或者`number`。\n因此\n1. [] == false`{[]}`会先通过`{valueOf}`,得到`{[]}`,不是原始值,再通过`{toString}`,得到`{\"\"}`\n2. ({}) == false同上面步骤最终的到`{\"[object Object]\"}`\n3. 同上,`{''!=\"[object Object]\"}`\n4. 没有`{==}`[]默认为true",
"type": "technical_qa"
},
{
"id": "segmentfault_93",
"question": "合并数组用 concat 还是 扩展运算符比较好?\n```\nlet arr1 = [1, 2];\nlet arr2 = [3, 4];\n// concat\narr1 = arr1.concat(arr2);\n// 扩展运算符\narr1 = [...arr1, ...arr2];\n// 或者\narr1.push(...arr2);\n```\n哪种更好为什么性能",
"answer": "究竟用哪种还是得根据你实际需求来的\n`concat`是`es5`时就有的,优点是`兼容性`高,不需要转译\n`...`是`es6`新出的语法,`简化`了写法,代码看上去更简洁直观,但实际只是做了`封装`底层还是用的原来的方法如下为babel转译的结果\n#### 第二种写法\n```\narr1 = [...arr1, ...arr2];\n ↓ 相当于\nfunction _toConsumableArray(arr) {\n if (Array.isArray(arr)) { \n for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; \n } else { return Array.from(arr); }\n}\narr1 = [].concat(_toConsumableArray(arr1), arr2);\n```\n#### 第三种写法\n```\narr1.push(...arr2);\n ↓ 相当于\narr1.push.apply(arr1, arr2);\n```\n再来看三种写法处理不同数据量的时间(数据分别为1,10,100) 单位:万\n```\nnum:10000\n s1: 0.01813671875ms\n s2: 0.1808984375ms\n s3: 0.078857421875ms\n\nnum:100000\n s1: 0.8310546875ms\n s2: 10.428955078125ms\n s3: 8.025146484375ms\n\nnum:1000000\ns1: 11.42724609375ms\ns2: 83.867919921875ms\ns3: Maximum call stack size exceeded\n```\n总结:\n`concat`性能最优\n在数据量极小时三者差异并不大\n在数据有一定量时`concat`性能遥遥领先于 `arr1 = [...arr1, ...arr2]` 和 `arr1.push(...arr2)`\n在数据过大时第三种方法会因为`apply`的特点由于数据量过大导致堆栈溢出",
"type": "technical_qa"
},
{
"id": "segmentfault_94",
"question": "GET查询加.keyword与不加.keyword的区别是什么为什么没有结果\n```\nGET production-index-info/index_info/_search\n{\n \"query\": {\n \"bool\": {\n \"minimum_should_match\": 0,\n \"must\": [\n {\n \"term\": {\n \"is_resolved.keyword\": \"解决\"\n }\n }\n ],\n \"should\": []\n }\n }\n}\n```\n使用这种方式查询就可以得到数据。数据如下格式\n```\n{\n \"took\": 51,\n \"timed_out\": false,\n \"_shards\": {\n \"total\": 5,\n \"successful\": 5,\n \"skipped\": 0,\n \"failed\": 0\n },\n \"hits\": {\n \"total\": 2914867,\n \"max_score\": 0.26003557,\n \"hits\": [\n {\n \"_index\": \"production-index-info\",\n \"_type\": \"index_info\",\n \"_id\": \"5a5d4fcdc42fbc2bcefae14a\",\n \"_score\": 0.26003557,\n \"_source\": {\n \"created_time\": \"2020-01-21T22:44:50+08:00\",\n \"tickets\": [],\n \"is_resolved\": \"解决\",\n \"note\": \"\",\n }\n },\n {\n \"_index\": \"production-index-info\",\n \"_type\": \"index_info\",\n \"_id\": \"5a64a762cd1cb23dbb294bfa\",\n \"_score\": 0.26003557,\n \"_source\": {\n \"created_time\": \"2018-01-21T22:44:50+08:00\",\n \"tickets\": [],\n \"is_resolved\": \"解决\",\n \"note\": \"\",\n }\n },\n {\n \"_index\": \"production-index-info\",\n \"_type\": \"index_info\",\n \"_id\": \"5a5d88136817b27825831ac2\",\n \"_score\": 0.26003557,\n \"_source\": {\n \"created_time\": \"2018-01-16T13:05:23+08:00\",\n \"tickets\": [],\n \"is_resolved\": \"解决\",\n \"note\": \"11111\",\n }\n },\n {\n \"_index\": \"production-index-info\",\n \"_type\": \"index_info\",\n \"_id\": \"5a5dbc30c42fbc2ef1307ba9\",\n \"_score\": 0.26003557,\n \"_source\": {\n \"created_time\": \"2018-01-16T16:47:44+08:00\",\n \"tickets\": [],\n \"is_resolved\": \"未解决\",\n \"note\": \"222\",\n }\n },\n ......\n ]\n }\n}\n```\n但是如果使用这种方式删除了`.keywprd`\n```\nGET production-index-info/index_info/_search\n{\n \"query\": {\n \"bool\": {\n \"minimum_should_match\": 0,\n \"must\": [\n {\n \"term\": {\n \"is_resolved\": \"解决\"\n }\n }\n ],\n \"should\": []\n }\n }\n}\n```\n那么结果就是这样的\n```\n{\n \"took\": 0,\n \"timed_out\": false,\n \"_shards\": {\n \"total\": 5,\n \"successful\": 5,\n \"skipped\": 0,\n \"failed\": 0\n },\n \"hits\": {\n \"total\": 0,\n \"max_score\": null,\n \"hits\": []\n }\n}\n```\n我知道这个`.keyword`和分词有关,但是对于这个例子,没有搞懂为什么,加了`.keyword`才可以查询出来结果不加就不行了。另外is_resolved的值只有解决和未解决两个。",
"answer": "1.ES5.0及以后的版本取消了`string`类型,将原先的`string`类型拆分为`text`和`keyword`两种类型。它们的区别在于`text`会对字段进行分词处理而`keyword`则不会。\n2.当你没有以IndexTemplate等形式为你的索引字段预先指定mapping的话ES就会使用Dynamic Mapping通过推断你传入的文档中字段的值对字段进行动态映射。例如传入的文档中字段price的值为12那么price将被映射为`long`类型字段addr的值为\"192.168.0.1\"那么addr将被映射为`ip`类型。然而对于不满足ip和date格式的普通字符串来说情况有些不同ES会将它们映射为text类型但为了保留对这些字段做精确查询以及聚合的能力又同时对它们做了keyword类型的映射作为该字段的fields属性写到_mapping中。例如当ES遇到一个新的字段\"foobar\": \"some string\"时会对它做如下的Dynamic Mapping\n```\n{\n \"foobar\": {\n \"type\" \"text\",\n \"fields\": {\n \"keyword\": {\n \"type\": \"keyword\",\n \"ignore_above\": 256\n }\n }\n }\n}\n```\n在之后的查询中使用foobar是将foobar作为text类型查询而使用foobar.keyword则是将foobar作为keyword类型查询。前者会对查询内容做分词处理之后再匹配而后者则是直接对查询结果做精确匹配。\n3.ES的term query做的是精确匹配而不是分词查询因此对text类型的字段做term查询将是查不到结果的除非字段本身经过分词器处理后不变未被转换或分词。此时必须使用foobar.keyword来对foobar字段以keyword类型进行精确匹配。",
"type": "technical_qa"
},
{
"id": "segmentfault_95",
"question": "bind和call的笔试题为什么用call和没用call执行的结果一样\n面试题是这样的\n```\nvar s = {\n s: 'student',\n getS:function(){\n console.log(this.s);\n }\n};\nvar t = {\n s: 'teacher chen'\n}\nvar getS = s.getS;\nvar getS1 = getS.bind(s);\n```\n正确的运行结果是\n```\ngetS1(); // student\ngetS1.call(t); //student\n```\nvar getS1 = getS.bind(s) 这一句的是说创建一个新函数并且通过bind将新函数的this绑定到对象s。输出student没错。但是getS1.call(t)不是通过call方法将this绑定到对象t了吗为嘛输出的仍然是student而不是teacher chen 呢?",
"answer": "对这个问题很感兴趣,查了一些资料\n以下是 MDN 里 bind 的 Polyfill , 可以看出来 bind 返回的函数只有用 new 方法当做构造函数调用时才会改变 this, 其他情况下的 this 一直是绑定的那个\n```\nif (!Function.prototype.bind) {\n Function.prototype.bind = function(oThis) {\n if (typeof this !== 'function') {\n // closest thing possible to the ECMAScript 5\n // internal IsCallable function\n throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');\n }\n\n var aArgs = Array.prototype.slice.call(arguments, 1),\n fToBind = this,\n fNOP = function() {},\n fBound = function() {\n // this instanceof fNOP === true时,说明返回的fBound被当做new的构造函数调用\n return fToBind.apply(this instanceof fNOP\n ? this\n : oThis,\n // 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的\n aArgs.concat(Array.prototype.slice.call(arguments)));\n };\n\n // 维护原型关系\n if (this.prototype) {\n // Function.prototype doesn't have a prototype property\n fNOP.prototype = this.prototype; \n }\n // 下行的代码使fBound.prototype是fNOP的实例,因此\n // 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例\n fBound.prototype = new fNOP();\n\n return fBound;\n };\n}\n```\n另外还有 https://blog.csdn.net/learnin... 这位作者做了一些实验,结论是对哪个函数使用bind()方法即改变这个函数的this值和内置其参数或者说像克里化一样理解先预置好参数",
"type": "technical_qa"
},
{
"id": "segmentfault_96",
"question": "React组件方法全部用箭头函数这样好吗\nReact的组件中不用bind(this),全部用箭头函数,这样会有什么缺点吗?",
"answer": "箭头函数的优点就是可以自动绑定上下文中的`this`箭头函数的优点是不会创建自己的`this`,它只会从自己的作用域链的上一层继承`this`.当然这也有可能是缺点,比如在你需要改变`this`的时候,这个时候就需要改成普通函数了.\n我遇到的另外一种情况是需要使用装饰器的情况,普通的函数使用装饰器直接覆盖`descriptor.value`就好了.但是如果装饰在箭头函数上面的话`descriptor.value`为空,需要通过别的方法来操作,有点麻烦,最后我直接改成普通函数,在最外面加了层绑定`this`的装饰器解决的.\n其实也没多少好纠结的,只要你明白什么情况下不能用,其他情况下就大胆用.当你什么时候遇到问题了,就在心中记一笔,这种情况不能用就好了.跟结束加不加分号一个道理.用多了之后能遇到的情况基本上都遇到了,至于没遇到的情况,等遇到在说呗.\n箭头函数表达式",
"type": "technical_qa"
},
{
"id": "segmentfault_97",
"question": "vue中v-if影响同级audio标签播放\n### 问题描述\n#### 以下是部分代码\n```\n <audio class=\"basic-audio\" :src=\"audio\" autoplay=\"autoplay\" @ended=\"ended\"></audio>\n\n <div class=\"content-region\" v-if=\"chooseCard\">\n <el-row type=\"flex\" v-for=\"(item,index) in contentList\" :key=\"index\" >\n <el-col class=\"content-lattice\" v-for=\"(item,index1) in item\" :key=\"index1\">{{item.name}}</el-col>\n </el-row>\n </div>\n```",
"answer": "可以了解一下`vue`中`diff`算法相关的实现。比如这篇文章。\n这种情况应该会出现于`audio`前后(不仅限于相邻)的兄弟节点中都存在`v-if`的情况。\n因为`vue`中`diff`是基于同层级比较的,并且`updateChildren`方法中的`VNode`比较是从节点左右两侧向中间靠拢的,所以当`audio`前后都存在`v-if`时,`virtual dom`重新渲染时,会将`audio`这个`dom`进行移动,所以实际上`audio`是会被从父节点移除然后再重新加入(可以通过给`audio`绑定`DOMNodeRemoved`来验证)。\n由于`audio`被移除过,所以播放会被停止。至于`v-show`没有此问题,是因为`v-show`前后`dom`结构未发生改变。",
"type": "technical_qa"
},
{
"id": "segmentfault_98",
"question": "vuex中存储的数据在页面刷新之后都是失去我想让vuex中的数据在刷新之后不会丢失怎么办。\n1.vuex中存储的数据在刷新页面(F5)之后会丢失全部的数据\n2.我想刷新页面之后不丢失。同时我还不想存储在window中的session和local中\nvuex中有没有相应的数据存储方法或者设置可以做到这样的效果",
"answer": "你的这个业务场景跟vuex没有关系吧\nvuex就是一个“提升变量”的一个工具它是将state当做全局变量存储。F5刷新页面之后自然随着页面的刷新重新初始化state。\n目前想让浏览器记住数据一般都会采用cookie或者localStorage等方法如果有什么其它方法欢迎分享。",
"type": "technical_qa"
},
{
"id": "segmentfault_99",
"question": "java nio 与 nio 的关系\n## 以前遇到问题总是可以在网上找到绝对正确的答案现在遇到的很多问题博客上会有很多种不同的答案比如说关于java nio有人说是同步非阻塞还有人说是异步阻塞我只知道java nio是采用的reactor模式也可以说是io多路复用netty也是这种方式。希望大鸟们可以给我一个详细的解释关于java nio与linux nio在此谢过大家",
"answer": "首先我想说下我对 同步异步 阻塞非阻塞的理解:\n`同步异步 指的是线程在处理一件事的时候,能不能去处理另外一件事,然后过一会再给上一件事结果`\n`阻塞非阻塞 指的是线程在处理一件事的时候,会不会被阻塞住 linux 里的NIO 意思就是no block io`\n这在java 等编程语言里 ,应该是一种编程模型,\n而在linux 的IO模型里 ,这种表述就不成立 因为不管什么IO模型在从内核复制到用户态的过程 中都是阻塞的,即使是 同步非阻塞模型,\n在linux 模型中,阻塞非阻塞指的是 使用系统调用看用户态准备好没有这个过程 而对于linux多路复用系统调用select也阻塞也没有办法去做别的任务看起来他应该是同步阻塞但他却比linux的同步阻塞要好得多\n因为同步阻塞模型是对一个IO 而多路复用是对多个IO\n我之前也纠结过同步非阻塞和异步非阻塞的事情但是后来想了想这个东西要从不同的层面看就拿netty来说从整体来看是属于异步非阻塞accept的线程处理完请求交给后面的reactor\n那accept的线程不就去处理别的请求了这不就达到了异步非阻塞但他内部reactor 使用的是多路复用模型 而不是 真正的 异步非阻塞模型,\n所以说了这么多其实还是想表达 同步异步,阻塞非阻塞 只是一种编程思路不用去纠结也不要被linux的IO模型搞混了\n还有就是java的NIO 是 new IO 的意思不是noblock io ,因为他除了提供selector之外还有其他的io特性提供比如大文件的处理",
"type": "technical_qa"
},
{
"id": "segmentfault_100",
"question": "关于Promise中this的指向问题\n## 代码\n```\nclass Dog {\n constructor() {\n this.name = 'adong';\n }\n\n start() {\n this.p().then(this.say);\n }\n\n p() {\n return new Promise((resolve, reject)=>{\n resolve('good');\n })\n }\n \n say(str) {\n console.log(this);\n console.log(this.name + str);\n }\n}\n\nlet dog = new Dog();\ndog.start();\n```\n## 题目描述\n`say`方法单独调用时没有问题的,但是在`Promise`的`then`里面再调用`this`就变为`undefined`了,哪个大神帮忙分析一下,谢谢!\n### 错误显示\n```\nundefined\n(node:5784) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'name' of undefined\n at say (D:\\NodeJS\\Test\\test2.js:18:22)\n```",
"answer": "```\nclass Dog {\n constructor() {\n this.name = 'adong';\n }\n\n start() {\n this.p().then(this.say.bind(this));\n }\n\n p() {\n return new Promise((resolve, reject)=>{\n resolve('good');\n })\n }\n \n say(str) {\n console.log(this);\n console.log(this.name + str);\n }\n}\n\nlet dog = new Dog();\ndog.start();\n\n```\n你上面的调用写法其本质就是\n```\nclass Dog {\n constructor() {\n this.name = 'adong';\n }\n\n start() {\n // this.p().then(this.say) 本质如下\n this.p().then(function(str){\n console.log(str); // good\n console.log(this); //undefined\n //console.log(this.name + str); //this.name会报错注释掉\n });\n }\n\n p() {\n return new Promise((resolve, reject)=>{\n resolve('good');\n })\n }\n \n say(str) {\n console.log(this);\n console.log(this.name + str); \n }\n}\n\nlet dog = new Dog();\ndog.start();\n```\npromise的then方法传入的是一个回调函数参数所以 then(this.say)实质只是将this.say作为一个参数使用所以不存在this\n1>. 回调函数为匿名函数时回调函数的this会指向window需要对回调函数bind(this)。\n2>. 回调函数为箭头函数时回调函数的this会指向他的直接上层本例中指向dog。",
"type": "technical_qa"
},
{
"id": "segmentfault_101",
"question": "TOKEN加在HEADER里使用HTTPS通信有安全隐患吗\n在写一个WEB API我现在是把TOKEN放在网页请求头HEADER里使用HTTPS跟服务器进行通信。\n请问这样会不会被人劫持到TOKEN呢有点担心伪造请求。 求指点~谢谢!",
"answer": "`token`的作用是保证数据来源的可信,至于`token`本身的安全不在它的职责范围内.\n比如用 jwt 生成的,里面存储的信息都是不加密的,他只保证里面信息的正确,比如`{id:12345}`我用这个数据生成一个`token`,这个`token`分为三段信息,第一段是头部`Header`,第二部分就是我们的数据`Payload`,通过`base64`加密,第三部分是加密的签名,通过`Header`和`Payload`以及我们的私钥生成.\n当客户端带着这个`token`访问服务器的时候,我会通过我们的私钥来验证整个数据的完整性,如果通过验证,就说明这个信息是可信的.当信息被篡改时,比如有人拿到`token`,并把数据改成`{id:56789}`,但是他没有私钥,所以没法生成正确的签名,当服务端验证`token`的时候通不过,我们就知道这个数据经过了篡改,然后执行相应的处理.\n这是`token`的作用,用来保证数据可信.保证这个`token`在其所在的权限范围内,而不会超出其权限范围之外,比如别的用户的信息.\n当然你可以根据需求,在加上别的措施,比如就不想别人知道`token`里面的数据,那就可以在给这个数据加一下密.\n或者当心这个`token`会被别人获取,照成这个用户的损失,那就需要在加别的手段来保证,比如通过验证来访的 ip ,比如设置更短的过期时间,比如你用的`HTTPS`,或者添加更多的验证等等.通过增加第三方的窃取成本,来降低被窃取的几率.\n你可以把`token`想象为银行的验钞机,验钞机的职责是验证假钞保证收进来的钱都是真钱,至于这个钱是偷的抢的,还是正常交易所得,那就不是验钞机管的了,那是警察叔叔管的.",
"type": "technical_qa"
},
{
"id": "segmentfault_102",
"question": "接口被恶意调用,如何解决\n有个短信接口给用户注册时发送验证码的然后现在发现有人每次用不同ip 不同号码进行恶意调用,现在接口被调爆,如何解决这个问题呢。\n补充一下目前APP已经发布出去了能不能再服务器做相关的限制呢因为在接口做限制它不停的调的话还是导致了该接口出现卡的现象",
"answer": "本质上就是客户端一个请求发给服务器请求的所有参数都是来自客户端所有在客户端做防护的措施都是浮云。有1000种方式防就有1001种方式破。有时间不如先在服务端检查一下HTTP请求的合法性举个例子一个由Firefox浏览器对你APP服务器发起的短信请求`User-Agent: Firefox`,你要给它发吗?一个请求的`Refer`是`www.duanxingongzhaji.com`,你应不应该拦截呢?\n最经济有效的其实是`加验证码`,因为攻击者即使是对接打码平台,也是有固定经济成本的。有大把的裸接口跑在外面,短信轰炸机这种工具是不会盯上你的,除非是有人故意要搞你。但加验证码随之而来的就是用户体验的下降。\n`APP已经发版了没办法加怎么办 凉拌呗! 要么强升要么就继续忍受攻击吧`。\n回答对IP和手机号做次数限制的亲们你们认真审题了吗\n每次用不同ip 不同号码 不同ip 不同号码 不同ip 不同号码\nIP可以考虑对代理和机房IP的识别自己识别成本太高可以对接第三方的saas服务但也没有谁能100%识别代理70%~80%是差不多的。另外有一些攻击行为是众包的由中了木马的肉鸡发起机器本身是在正常不过的个人PC这种方式基本不要想怎么防了。\n手机号只能考虑空号检测了这个也不要试图自己做了找供应商吧同样的没有100%的准确率,并且不是实时的。技术上讲可以有一些帮助,但是产品层面可能不太优雅。\n从攻击者攻击方式考虑\n- 对于短信轰炸机这种无攻击目的性的情况来说一般手机号都是存在的并且IP都是分散的正常IP除了验证码真的没什么手段可以防。`除非你能事先知道这个号码正在被攻击`\n- 对于恶意的黑客攻击行为一般会伴随大量空号和代理IP一定要防的话需要一定成本否则只能认栽。\n\n对于短信轰炸机这种无攻击目的性的情况来说一般手机号都是存在的并且IP都是分散的正常IP除了验证码真的没什么手段可以防。`除非你能事先知道这个号码正在被攻击`\n对于恶意的黑客攻击行为一般会伴随大量空号和代理IP一定要防的话需要一定成本否则只能认栽。",
"type": "technical_qa"
},
{
"id": "segmentfault_103",
"question": "问个跨域问题http://www.baidu.com请求https://www.baidu.com要跨域吗\n就是http的域名请求https的域名这个要跨域吗为什么",
"answer": "跨域。\n不同源域名协议端口。\n协议http,https。\n会触发跨域的条件还有\n域名\nhttps://www.baidu1.com\nhttps://www.baidu2.com\n端口\nhttps://www.baidu.com:3000\nhttps://www.baidu.com:3001",
"type": "technical_qa"
},
{
"id": "segmentfault_104",
"question": "数组中选取最小值的问题\n在选取数组中最小值的时候发现如果是下面这样子的代码直接运行在<script> </script>中会有问题。\n代码1\n```\n<script> \nvar name=[12,3,65,8,2,12];\nvar min = name[0];\nfor (var i = 1; i <= 1; i++) {\n if (name[i]<min) \n {\n min = name[i];\n } \n}\n console.log(min);\n}\n</script>\n\n\n```\n代码2\n```\n<script> \nfunction test(){\nvar name=[12,3,65,8,2,12];\nvar min = name[0];\nfor (var i = 1; i <= 1; i++) {\n if (name[i]<min) \n {\n min = name[i];\n } \n}\n console.log(min);\n}\n}\n\ntest();\n</script>\n\n```\n2段代码的结果不一样想知道是为什么呀",
"answer": "这是全局变量导致的我们知道window在<script></script>标签里可以直接使用,其实还有很多这样的全局变量,比如:\nname(默认为空)\nlength(默认为0)\n你可能还会纳闷 那第一种写法为什么得到的是1呢接下来我们分析下你的代码\n```\n<script>\n var name=[12,3,65,8,2,12]; // 全局变量\n var min = name[0];\n for (var i = 1; i <= 1; i++) {\n if (name[i]<min){\n min = name[i];\n } \n }\n console.log(min);\n</script>\n\n// name是在全局里定义的而name本身就是一个全局变量而且作为全局变量时只能是字符串无论赋值什么内容都会调用 name.toString()方法\n// 所以在for循环之前name的值是 \"12,3,65,8,2,12\", 因为循环只进行了一次所以结果是1\n```\n我们来看第二段代码\n```\nfunction test(){\n var name=[12,3,65,8,2,12]; // 局部变量\n var min = name[0];\n for (var i = 1; i <= 1; i++) {\n if (name[i]<min) \n {\n min = name[i];\n } \n }\n console.log(min);\n}\ntest();\n\n// 在函数内部name就变成了局部变量此时可以正常赋值即for循环之前的值是[12,3,65,8,2,12],因为循环执行了一次, 12 < 3所以得到的结果是3\n```\n总结在定义变量时最好不要使用name因为全局下name会被转化为字符串。length是可以使用记得还有其他的全局变量感兴趣的话自己搜一下吧",
"type": "technical_qa"
},
{
"id": "segmentfault_105",
"question": "请问下大家这种代码还能优化吗\n```\n if (resState == 8) {//下\n li_one.appendTo(\"#haved .ul-list\");\n li_one.find(\".status\").html(\"完场\");\n } else if (resState == 9) {\n li_one.appendTo(\"#haved .ul-list\");\n li_one.find(\".status\").html(\"推迟\");\n } else if (resState == 10) {\n li_one.appendTo(\"#haved .ul-list\");\n li_one.find(\".status\").html(\"中断\");\n } else if (resState == 11) {\n li_one.appendTo(\"#haved .ul-list\");\n li_one.find(\".status\").html(\"腰斩\");\n } else if (resState == 12) {\n li_one.appendTo(\"#haved .ul-list\");\n li_one.find(\".status\").html(\"取消\");\n } else if (resState == 13) {\n li_one.appendTo(\"#haved .ul-list\");\n li_one.find(\".status\").html(\"待定\");\n }\n```\n如上,这种代码执行效率怎么样?萌新求指教蟹蟹",
"answer": "执行效率没什么问题,就是代码简化些吧\n```\nvar textObj = { 8: \"完场\", 9: \"推迟\", 10: \"中断\", 11: \"腰斩\", 12: \"取消\", 13: \"待定\" }\nif (textObj[resState]) {\n li_one.appendTo(\"#haved .ul-list\")\n li_one.find(\".status\").html(textObj[resState])\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_106",
"question": "js if多重判断如何优化到最简?\n经常碰到循环数组之后需要把某个值转换\n```\nlet arr = res.data.orderinformation;\nfor (let i = 0; i < arr.length; i++) {\n if (arr[i].ctype == \"11001\") {\n arr[i].ctype = \"微信支付购买\";\n } else if (arr[i].ctype == \"11008\") {\n arr[i].ctype = \"余额购买\";\n } else if (arr[i].ctype == \"11011\") {\n arr[i].ctype = \"退款到余额\";\n } else if (arr[i].ctype == \"11012\") {\n arr[i].ctype = \"优惠卷兑换\";\n } else if (arr[i].ctype == \"11013\") {\n arr[i].ctype = \"积分兑换\";\n } else if (arr[i].ctype == \"11014\") {\n arr[i].ctype = \"赠送课程\";\n }\n\n // switch优化, 但是这样写不对, 哪里出了问题?\n // switch (arr[i].ctype) {\n // case \"11001\":\n // arr[i].ctype = \"微信支付购买\";\n // break;\n // case \"11008\":\n // arr[i].ctype = \"余额购买\";\n // break;\n // case \"11011\":\n // arr[i].ctype = \"退款到余额\";\n // break;\n // case \"11012\":\n // arr[i].ctype = \"优惠卷兑换\";\n // break;\n // case \"11013\":\n // arr[i].ctype = \"积分兑换\";\n // break;\n // case \"11014\":\n // arr[i].ctype = \"赠送课程\";\n // break;\n // default:\n // break;\n // } \n\n // 用时间戳转成日期\n arr[i].ctime = new Date(arr[i].ctime);\n arr[i].ctime =\n arr[i].ctime.toLocaleDateString().replace(/\\//g, \"-\") +\n \" \" +\n arr[i].ctime.toTimeString().substr(0, 8);\n}\n```",
"answer": "```\nconst d = {\n '11001': '微信支付购买',\n '11008': '余额购买',\n '11011': '退款到余额',\n '11012': '优惠卷兑换',\n '11013': '积分兑换',\n '11014': '赠送课程',\n};\nfor (let i = 0; i < arr.length; i++) {\n if (d[arr[i].ctype]) arr[i].ctype = d[arr[i].ctype];\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_107",
"question": "JavaScript 为什么页面会先显示alert()框,而不是先显示页面元素?\n显示顺序\n1.显示提示框(此时页面一片空白)\n2.点确定后正常显示HelloWorld\n```\n<body>\n <script>\n document.write(\"<h1>HelloWorld</h1>\");\n document.write(\"<h1>HelloWorld</h1>\");\n alert(\"你好\");\n </script>\n</body>\n```\n为什么页面会先显示alert()框,而不是先显示HelloWorld,我的代码明明是HelloWorld写在上面?",
"answer": "栗子:比如你有一天去饭店, 告诉老板要吃火锅了,他再给你上火锅的路上, 你出去接了个电话 他已经把火锅端上来了(但是你没看到,你走进去才会看到) (`阻塞了`)\n```\n document.write(\"<h1>HelloWorld</h1>\");\n document.write(\"<h1>HelloWorld</h1>\");\n setTimeout(function(){alert(\"你好\")},1000) //定时线程走,就可以看到效果\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_108",
"question": "vue 中 axios要如何做同步机制\naxios 好像不能想jquery那样设置async来实现同步请求这导致我实现一些逻辑带来的困难。\n```\nmethods: {\n funcA() {\n axios.post(\n // 在请求成功后把属性a赋值\n )\n return a\n }\n}\n```\n如果我有类似上面的需求我要在请求完成后对数据进行赋值然后在后面的语句中要操作数据比如返回它。如果是同步机制那么最后我可以成功返回a的值但是axios是异步的。 \n把需求写在请求的回调里面是不行的如果我要返回这个值只是这个请求调用返回对于整个函数来说没有返回这真的很难受有没有什么解决方案回调真的不行。",
"answer": "```\nmethods: {\n async funA(){\n var res = await axios.post('')//这里的res就是你axios请求回来的结果了\n }\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_109",
"question": "一个php的面试题大家看看\n```\n$listData = [\n '111' => ['a', 'b', 'c', 'a'],\n '222' => ['d', 'e', 'f', 'f', 'b'],\n '333' => ['g', 'h'],\n '444' => ['i', 'j'],\n ...\n];\n```\n定义一个函数传入$listData\n如果`111`里面的元素,和 222/333/444... 里面的元素有重复返回false \n如果`222`里面的元素,和 111/333/444... 里面的元素有重复返回false \n如果`333`里面的元素,和 111/222/444... 里面的元素有重复返回false \n如果 ... \n允许 111/222/333/444 自己里面的元素重复返回true \n其他情况返回true\n已知:\n$listData长度未知\n111/222/333/444... 的长度未知\n111/222/333/444... 里的元素为字符串和数字\n我自己实现了一下感觉算法很糟请问有没有其他方法\n```\nfunction test ($array) {\n\n $tempValueList = [];\n foreach ($array as $key => $valueList) {\n \n foreach ($valueList as $value) {\n \n $tempValueList[] = $key . '~' . $value;\n }\n }\n $result = true;\n foreach ($array as $key => $valueList) {\n \n foreach ($valueList as $value) {\n \n foreach ($tempValueList as $_value) {\n \n $pos = strpos($_value, '~');\n $_key = substr($_value, 0, $pos);\n $_val = substr($_value, $pos + 1);\n\n if ($key == $_key) {\n\n continue;\n }\n if ($_val == $value) {\n\n $result = false;\n break 3;\n }\n }\n }\n }\n\n return $result;\n}\n```",
"answer": "我对子数组的定义是像 ['a', 'b', 'c', 'a'] 这样的单个数组。\n我的答案\n```\n$result = array();\nforeach ($listData as $line) {\n //子数组内部去重,再组装回原来的格式\n $result[] = array_unique($line);\n}\n\n//子数组先去重再合并的结果数量 和 先合并子数组再去重的结果数量 做比较。\n//如果是相同的,意味着不存在跨子数组的重复,只存在子数组内部重复,所以`True`\nvar_dump(count(array_merge(...$result)) === count(array_unique(array_merge(...$listData))));\n```\n我这个答案调用系统函数次数比较多看起来简洁一些但是PHP array_xxx 这类函数很大一部分性能是不具备优势的,如果不用这些函数,能相对程度提高运行效率。\n另外想要在各种情形下都能保持最高效率可以参考以下代码。\n```function check($arr)\n{\n $chk = [];\n foreach ($arr as $k => $v)\n foreach ($v as $i)\n {\n if (isset($chk[$i] && $chk[$i] != $k))\n return false;\n $chk[$i] = $k;\n }\n return true;\n}```\n方便理解的辅助参考信息\n原始数据\n```\n$listData = [\n '111' => ['a', 'b', 'c', 'a'],\n '222' => ['d', 'e', 'f', 'f', 'b'],\n '333' => ['g', 'h'],\n '444' => ['i', 'j']\n];\n\n```\n然后 $result 最终是这样的:\n```\n$listData = [\n '111' => ['a', 'b', 'c'],\n '222' => ['d', 'e', 'f', 'b'],\n '333' => ['g', 'h'],\n '444' => ['i', 'j']\n];\n\n```\n子数组先去重再合并的结果\n```\nArray\n(\n [0] => a\n [1] => b\n [2] => c\n [3] => d\n [4] => e\n [5] => f\n [6] => b\n [7] => g\n [8] => h\n [9] => i\n [10] => j\n)\n\n```\n用于和上面进行数量数组元素数量比较的所谓的“先合并子数组再去重的结果”\n```\nArray\n(\n [0] => a\n [1] => b\n [2] => c\n [4] => d\n [5] => e\n [6] => f\n [9] => g\n [10] => h\n [11] => i\n [12] => j\n)\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_110",
"question": "求助道面试题在前端项目中如何进行seo优化你在哪些项目里有过seo优化效果如何\n参加面试被问到这个在网上查阅资料但是找不到很好的回答\n在实际项目里是如何做好seo优化的优化后的效果是什么样的",
"answer": "您英文水品怎么样,如果还可以的话,试试读读这个系列的文章,也许会有所帮助:\nhttps://moz.com/beginners-guide-to-seo/how-search-engines-operate。\n如果是单纯应付面试的话简单说说就可以了毕竟这个东西要细聊聊一天也聊不完比如\n- 做 SPA 项目时,为解决 SEO 问题,引入了 SSR 渲染引擎\n- 在首页加入 meta 标签提供一些元数据\n- 使用简单、具有表意性的 title 以及使用 h5 提供的具有语义化的标签(不要一堆 div\n- 生成对 search engine 友好的 sitemap\n- 使用合理的 html 结构(比如按标题、内容、页脚这样的顺序、或者将重要的内容放在 html 前,其他放在后)\n\n现在让我想就大概能想这么多当然还有其他方式但是我觉的面试回答这些应该足够了吧毕竟也就是考察一下知识点而已。\n另外也可以通过打开 devtool 的方式,看看一些流量比较大的网站的 html 以及头标签是怎么写的,比如 segmentfault.com我觉的 SF 这个 SEO 优化的真的是很好了,搜索关键字比较明了的话,一般前 5 个搜索结果必有一个是 SF 的。",
"type": "technical_qa"
},
{
"id": "segmentfault_111",
"question": "vue-cli 在写css的时候无法自动刷新浏览器是什么原因\n1修改css的时候切换到浏览器无法自动刷新需要手动刷新才能看到效果有人遇到过这样的情况吗\n修改其他到是没事 只是css 会有这个问题\n我用的是vue-cli 3.0\n附上解决后的配置\n```\n// vue.config.js\nmodule.exports = {\n lintOnSave:false,\n devServer:{\n host:'0.0.0.0'\n }\n}\n```",
"answer": "我也遇到这个问题不过查明原因后发现是我的vue.config.js配置了extract:true,把style提取至独立的css文件了而不是动态注入javascipt中。把这个参数去掉就可以了。以下是官方文档原文\ncss.extract\nType: boolean | Object\nDefault: 生产环境下是 true开发环境下是 false\n是否将组件中的 CSS 提取至一个独立的 CSS 文件中 (而不是动态注入到 JavaScript 中的 inline 代码)。\n同样当构建 Web Components 组件时它总是会被禁用 (样式是 inline 的并注入到了 shadowRoot 中)。\n当作为一个库构建时你也可以将其设置为 false 免得用户自己导入 CSS。\n提取 CSS 在开发环境模式下是默认不开启的,因为它和 CSS 热重载不兼容。然而,你仍然可以将这个值显性地设置为 true 在所有情况下都强制提取。",
"type": "technical_qa"
},
{
"id": "segmentfault_112",
"question": "vue-awesome-swiper中loop设置true无效\n### vue-awesome-swiper中loop设置true无效\n数据是动态加载的在网上查不到和我相关的问题答案\n是放在子组件中首页直接引入此swiper子组件的\n### 相关代码\n```\n<div class=\"wrapper\" :class=\"cname\">\n <swiper :options=\"options\">\n <swiper-slide v-for=\"(item, index) in items\" :key=\"index\">\n <slot :src=\"item\"></slot>\n </swiper-slide>\n <div class=\"swiper-pagination\" v-if=\"options.pagination\" slot=\"pagination\"></div>\n </swiper>\n</div>\n\nname: \"sliderComponent\",\nprops: {\n cname: {\n type: String,\n default: \"\"\n },\n options: {\n type: Object,\n default () {\n return {\n autoplay: {\n delay: 3000,\n disableOnInteraction: false,\n //stopOnLastSlide: false\n },\n loop: true,\n pagination: {\n el: '.swiper-pagination'\n },\n observeParents:true,\n observer:true \n }\n }\n },\n\n\n\n```\n不循环了轮播到最后一个图就不动了",
"answer": "试了好多次,终极答案是这样:\n```\n<swiper\n :options=\"swiperOption\"\n ref=\"mySwiper\"\n>\n <!-- slides -->\n <swiper-slide\n v-for=\"(item,index) in topBanner\"\n :key=\"item.id\"\n >\n <img\n :src=\"item.image_url\"\n :alt=\"index\"\n class=\"banner-img\"\n >\n </swiper-slide>\n</swiper>\n```\n```\ndata() {\n return {\n swiperOption: {\n init:false,\n loop: true,\n autoplay: {\n delay: 2000,\n disableOnInteraction: false\n },\n },\n }\n}\n```\n当然在computed()时要获取$refs:\n```\ncomputed: {\n swiper() {\n return this.$refs.mySwiper.swiper;\n }\n},\n```\n然后在vue生命周期的updated()时初始化swiper\n```\nupdated() {\n console.log(this.topBanner);\n if (this.topBanner.length>1) {\n console.log(this.swiper);\n this.swiper.init();\n }\n},\n```\n不用v-if获取到了this.swiper问题完美解决",
"type": "technical_qa"
},
{
"id": "segmentfault_113",
"question": "关于js柯里化做笔试题时遇到一个问题\n请实现test2函数满足以下四个条件使其通过测试以最简洁的方式完成并保证代码质量\nmodule.exports.test2 = (input) => {\n}\n(1)test2() === 0\n(2)test2(1)() === 1\n(3)test2(1)(2)(3)(4)() === 10\n(4)const t2 = test2(1)(2); t2(3)() === 6; t2(4)() === 7\n我写了一个函数但是只能满足前三个条件求大神赐教怎么同时满足这四个条件不知道咋写。",
"answer": "题目已经给出了函数的签名,那么答案是不应该擅自改动的。\n```\nmodule.exports.test2 = (input) => {\n const fn = a => b => b == null ? a : fn(a + b)\n return input == null ? 0 : fn(input)\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_114",
"question": "如何使用filter方法递归过滤Tree数组对象\n```\nconst treeData = [{\n title: \"1\",\n key: \"1\",\n children: [{\n title: \"1-1\",\n key: \"1-1\",\n children:[{\n title:\"1-1-1\",\n key:\"1-1-1\",\n },{\n title:\"1-1-2\",\n key:\"1-1-2\",\n }]\n }, {\n title: \"1-2\",\n key: \"1-2\",\n },{\n title: \"1-3\",\n key: \"1-3\",\n },{\n title: \"1-4\",\n key: \"1-4\",\n }],\n}];\n\n```\n想要实现通过传入的key过滤树如果父级被过滤掉该父级下面所有子级也全部被过滤。\n我通过递归map,还有递归filter都没有实现过滤的效果。代码如下\n```\ndeleteTreeData = (data,selectedKey) => {\n const newTreeData = data.filter((item) => {\n if(item.children){\n this.deleteTreeData(item.children,selectedKey);\n }\n\n return item.key !== selectedKey;\n\n });\n\n this.setState({\n treeData : newTreeData,\n },function(){\n console.log(\"=====newTreeData\"+JSON.stringify(newTreeData));\n });\n }\n\n```\n这样写只能删除顶级菜单请问正确的思路是什么谢谢~",
"answer": "```\nconst treeData = [{\n title: \"1\",\n key: \"1\",\n children: [{\n title: \"1-1\",\n key: \"1-1\",\n children:[{\n title:\"1-1-1\",\n key:\"1-1-1\",\n },{\n title:\"1-1-2\",\n key:\"1-1-2\",\n }]\n }, {\n title: \"1-2\",\n key: \"1-2\",\n },{\n title: \"1-3\",\n key: \"1-3\",\n },{\n title: \"1-4\",\n key: \"1-4\",\n }],\n}];\n\nfunction f(arr, selectedKey) {\n return arr.filter(item => item.key !== selectedKey).map(item => {\n item = Object.assign({}, item)\n if (item.children) {\n item.children = f(item.children, selectedKey)\n }\n return item\n })\n}\n\nconsole.log(f(treeData, '1-2'))\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_115",
"question": "求助关于java8 Collectors的groupingBy和mapping\n### 问题描述\n- 小弟尝试将一段如下json读到一个Map<String, List<String>>中map\n的key为condNamemap的value为condValue\n- 现在用stream结合Collectors的groupingBy和toList方法将List<Condition>转成了Map<String, List<Condition>>\n- 然后尝试通过mapping方法将List<Condition>映射为List<String>时发现无从下手。。。几次尝试后得到了一个Map<String, List<List<String>>>多了一层List\n- 想去掉这一层List如果再遍历一遍又感觉不太优雅\n- 有什么思路吗最好是通过mapping一次得到想要的结果\n- 不胜感激!\n### 问题出现的环境背景及自己尝试过哪些方法\n### 相关代码\n```\n{\n \"condition\": [\n {\n \"condName\": \"name1\",\n \"condValue\": [\n \"val11\",\n \"val12\"\n ]\n },\n {\n \"condName\": \"name2\",\n \"condValue\": [\n \"val21\"\n ]\n },\n {\n \"condName\": \"name3\",\n \"condValue\": [\n \"val31\",\n \"val32\",\n \"val33\"\n ]\n }\n ],\n \"total\": 3\n}\n```\n```\n@Data\npublic class Request {\n private List<Condition> condition;\n private Long total;\n}\n```\n```\n@Data\npublic class Condition {\n private String condName;\n private List<String> condValue;\n}\n```\n转换方法读取json和转成Request对象的代码省略。。。\n```\nString json = getContent();\ntry {\n List<Condition> conditions = deseriliaze(json).getCondition();\n Map<String, List<Condition>> map1 = conditions.stream().collect(Collectors.groupingBy(Condition::getCondName));\n Map<String, List<List<String>>> map2 = conditions.stream().collect(Collectors.groupingBy(Condition::getCondName, Collectors.mapping(Condition::getCondValue, Collectors.toList())));\n} catch (Exception e) {\n e.printStackTrace();\n}\n```\n### 你期待的结果是什么?实际看到的错误信息又是什么?\n- map1:\n```\n{name3=[Condition(condName=name3, condValue=[val31, val32, val33])], name2=[Condition(condName=name2, condValue=[val21])], name1=[Condition(condName=name1, condValue=[val11, val12])]}\n```\n- map2:\n```\n{name3=[[val31, val32, val33]], name2=[[val21]], name1=[[val11, val12]]}\n```",
"answer": "回答这个问题的话,我们可以先来看看为啥会出现`Map<String, List<List<String>>>`的结果,这要从`Collectors.groupingBy`的设计语义来说了,它代表把流的数据按照一定规则进行归类分组,并要求提供同一组的数据怎么进行收集的方法,所以这就是`Collectors.groupingBy`两个参数的含义\n那您第一个参数写的是`Condition::getCondName`,代表流的`Condition`按照其`condName`属性进行分组,分组之后,同一组的`Condition`如何处理,这里用的`Collectors.mapping(Condition::getCondValue, Collectors.toList()))``mapping`代表映射转换,这里有点类似分组,`Collectors.mapping`第一个参数把流的`Condition`转化为`List<String>`,此时流里就是`List<String>`,再经过第二个参数`Collectors.toList()`,哦豁,当然最后结果就是`List<List<String>>`\n这里您得不到答案的原因就是`Collectors.mapping`的第二个参数没有写对,我这里想到三种方式\n第一种还是用`Collectors.mapping`,类似您提到的再遍历一遍,哈哈\n```\nMap<String, List<String>> collect = conditions.stream()\n .collect(Collectors.groupingBy(Condition::getCondName,\n Collectors.mapping(Condition::getCondValue,\n Collectors.collectingAndThen(Collectors.toList(), lists -> lists.stream().flatMap(List::stream).collect(Collectors.toList())))));\n```\n这里`Collectors.mapping`的第二个参数用了`Collectors.collectingAndThen`,从名字就看得出来,收集好了之后再做什么事...第一个参数当然还是按照`Collectors.toList()`,收集到之后,第二个参数再把`List`遍历一次,压平后再组成`List`\nemmm我也不太喜欢这种不过只是引出了哈`collectingAndThen`,说不定以后您可以用到\n第二种也还是用`Collectors.mapping`,不过这次第二个参数用`Collectors.reducing`\n```\nMap<String, List<String>> collect2 = conditions.stream()\n .collect(Collectors.groupingBy(Condition::getCondName, \n Collectors.mapping(Condition::getCondValue, \n Collectors.reducing(new ArrayList<>(), (l1, l2) -> Stream.concat(l1.stream(), l2.stream()).collect(Collectors.toList())))));\n```\n这里的`Collectors.reducing`就是数据的聚合,正好也符合当前的场景,当流里的数据由`Condition`转化为`List<String>`时,我们就是要找到一种合并不同`List<String>`的方法,所以这里用到这个聚合方法`Collectors.reducing`,第一个参数是起始值,第二个参数代表怎么合并两个`list`\n第二个方法要好一点不过这里我还想到第三个方法\n第三种不用`Collectors.groupingBy`,而采用`Collectors.toMap`\n```\nMap<String, List<String>> collect1 = conditions.stream().collect(\n Collectors.toMap(Condition::getCondName, Condition::getCondValue, (c1, c2) -> Stream.concat(c1.stream(), c2.stream()).collect(Collectors.toList())));\n```\n第三种方式感觉要比前两种简单点但是这是巧用了哈`toMap`方法,`toMap`方法一般使用在数据能够有一种一对一的关系时才用,大多数的时候我们一般也只使用两个参数的方法,即传入怎么获取`map`的`key`和怎么获取`map`的`value`的两个`Function`,因为一般情况下,业务上可以保证数据是具有一对一的关系的,如果只是调用两参方法,但是实际使用过程中,确实出现了一对多的情况,那么这时候调用`toMap`两参方法是会报错的,因此就有了`toMap`这个三参方法,第三个参数代表怎么合并同一个`key`的`value`值,所以到了这里就跟第二种方法的思路差不多了,合并两个集合即可\n以上就是我的回答仅供参考\n对了再加一点我一般是不太喜欢在流里写过长的lambda表达式的因为流里是要体现当前流程的不是什么都往里塞所以第三种方式最后的集合合并最好还是写成一个`BinaryOperator`,毕竟现在方法也可以是一种参数或者属性了嘛\n```\npublic static final BinaryOperator<List<String>> listMergeMethod = (l1, l2) -> Stream.concat(l1.stream(), l2.stream()).collect(Collectors.toList());\n```\n```\nMap<String, List<String>> collect1 = conditions.stream().collect(\n Collectors.toMap(Condition::getCondName, Condition::getCondValue, listMergeMethod));\n```\n这样我感觉要顺点。",
"type": "technical_qa"
},
{
"id": "segmentfault_116",
"question": "关于mogodb缓存\n```\nWith WiredTiger, MongoDB utilizes both the WiredTiger internal cache and the filesystem cache.\n\nStarting in 3.4, the WiredTiger internal cache, by default, will use the larger of either:\n\n 50% of (RAM - 1 GB), or\n 256 MB.\n\n```\nmongodb4.0文档,大概意思是mongodb使用internal cache and the filesystem cache,\n(1))请问一下如果机子内存2g,那么按照上面的计算,internal catche将占用512m,如果数据增加,内存占用超过512m,是不是就开始启用filesystem cache,把此时数据缓存放在空闲内存上,两者有没有先后顺序?\n(2)既然两者都是放在内存中,为什么还要分两类缓存,是不是internal cache占据内存是不能被释放的,filesystem cache占据的是会被其他服务挤掉的,是这样吗?\n(3)这些缓存是不是也是压缩过的?",
"answer": "internal cache 你可以理解为程序使用的内存。filesystem cache 理解为操作系统的文件系统缓存机制。\n\n在mongo 的 WiredTiger 缓存机制中。如果不做配置的话他会默认使用你的50% 的系统内存做索引和数据的缓存。\n如果你的机器内存比较小小于 512M 它就使用 256M 内存做缓存。\n\n文件系统的缓存是在内核层面的。你打开一个文件读了读。关闭了它。系统会根据你的使用程度做一些缓存。你关闭这个文件的时候操作系统可能并没有把数据从物理内存释放。你再次打开读取这个文件就要比首次打开要快。\n\nfilesystem cache是操作系统行为不受应用控制的。必要的时候这部分缓存会被分给其他进程。因为filesystem cache是对磁盘文件的忠实映射而MongoDB在磁盘上存储的文件是压缩过的所以这就代表着在filesystem cache中的内容是压缩过的。\ninternal cache则是MongoDB控制的部分其中存储的是最近用到过的数据索引等并且是解压过的。\n1) 这实际上是操作系统原理方面的知识。MongoDB要把数据加载到内存中首先要从磁盘上读取原始的文件那么文件内容就会进入filesystem cache. 然后要把文件内容转换为WiredTiger可以直接使用的格式即解压解密之后的内容才会进到internal cache。所以一定要说先后顺序的话internal cache中的内容肯定来自filesystem cache后者先加载。\n2) internal cache是进程内存filesystem cache是操作系统缓存。后者在一定时候会被LRU算法驱逐出内存。如果再次被读取又会从磁盘加载。不过前者同样有可能会被驱逐出内存因为数据容量可能比缓存大那么就是保留需要的内容释放掉暂时不用的部分。这里同样的是LRU。\n3internal cache未压缩filesystem cache压缩。\n额外一些需要注意的问题\n\n1. 索引无论在internal cache还是filesystem cache都是压缩的压缩的是索引的键。\n2. filesystem cache对性能的影响同样至关重要不要忽略它的作用。",
"type": "technical_qa"
},
{
"id": "segmentfault_117",
"question": "vue父组件的created和子组件的mounted的执行先后\n父组件的created和子组件的mounted的执行先后\n如果父组件的created里有.then那么子组件的created会在子组件mounted前执行吗",
"answer": "执行顺序如下:\n\n1. 父组件 created\n2. 子组件 created\n3. 子组件 mounted\n4. 父组件 mounted\n\n如果有多个子组件\n\n1. 父组件created钩子结束后依次执行子组件的created钩子\n2. 多个子组件的created执行顺序为父组件内子组件DOM顺序\n3. 多个子组件的mounted顺序无法保证跟子组件本身复杂程度有关\n4. 父组件一定在所有子组件结束mounted钩子之后才会进入mounted钩子",
"type": "technical_qa"
},
{
"id": "segmentfault_118",
"question": "vue input每次输入一个字符后自动失去焦点\n代码如下遇到的问题就是我在输入框输入的时候每输入一次输入框就自动失去焦点了。\nps实现的功能是每点击一次添加按钮然后就会为list对象的name数组添加一个对象这个时候就会生成一个新的input在这个input输入就会遇到如上问题\n```\n <div class=\"addTags\" v-for=\"(item,index) in list.name\" :key=\"item.data\">\n <input type=\"text\" v-model=\"item.data\">\n </div>\n <span class=\"add\" @click=\"addData()\">+请添加</span>\n\n\n data() {\n return: {\n list: {\n name: []\n }\n }\n },\n methods: {\n addData() {\n this.list.name.push({data:''})\n }\n }\n```",
"answer": "问题在于:key=item.data'input数据绑定后进行模型更新后div的属性要刷新进行渲染后就重新刷新的input。如果你是要在代码中找div建议你直接找input的父节点的方式而不要用子节点绑定的数据给父节点的属性赋值。",
"type": "technical_qa"
},
{
"id": "segmentfault_119",
"question": "js怎么监听元素属性变化\n原生js监听dom元素的属性值的变化如果监测的目标属性发生变化。执行特定语句。\n监听Dom元素的Style内部的某个特定的属性例如display默认为none修改为inline时触发事件\n思路\n```\n1.Object.defineProperty\n set,get\n2.Mutation Observer API\n \n \n \n```\n发生的问题\n1.defineProperty监测的目标是对象Dom元素的属性集合[dom.attributes]也为对象{}。attributes对象是所有的属性集合的对象style是属性集合里下属的集合因为style的参数多。\n问题把dom.attributes当做对象监测集合下的style当style发生改变的时候触发Set方法内的语句。但是测试的时候当图片的display的值发生改变时set无触发经测试Object.defineProperty无反应。\n```\n var m=document.getElementById(\"m\").attributes; //对象{}\n Object.defineProperty(m,'style',{\n get:function () {\n console.log('get:'+m.style);\n return m.style.display;\n },\n set:function (v) {\n console.log('set:修改后的值'+v);\n m.alt='图片';\n }\n })\n```\n2.Mutation Observer API它等待所有脚本任务完成后才会运行即异步触发方式不知道能不能实时触发修改。",
"answer": "我觉得MutationObserver可以用啊正常情况下这个等待DOM操作结束再执行的异步回调没什么问题吧。什么业务实时性要那么高啊 一般一个事件里面同步的不会有同个属性改来改去的情况(有这种情况优化代码更好)如果是异步的那MutationObserver也会异步调用倒没什么问题\n```\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"UTF-8\">\n <title></title>\n</head>\n<body>\n<div id=\"test\" style=\"position: relative;\" onclick=\"clickMe()\">test</div>\n<script type=\"text/javascript\">\n var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;\n var element = document.querySelector('#test');\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(mutation) {\n if (mutation.type == \"attributes\") {\n console.log('mm', new Date().getTime()) \n console.log(\"attributes changed\", mutation.attributeName)\n }\n });\n });\n\n observer.observe(element, {\n attributes: true //configure it to listen to attribute changes\n });\n \n function clickMe(){\n console.log('111', new Date().getTime())\n element.style.left = Math.random()* 10 + 'px';\n console.log('222', new Date().getTime())\n element.style.left = Math.random()* 10 + 'px';\n setTimeout(function(){\n console.log('333-timeout', new Date().getTime())\n element.style.left = Math.random()* 10 + 'px';\n }, 2000)\n\n console.log('click-end')\n }\n</script>\n</body>\n</html>\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_120",
"question": "js如果两个数组中有相同对象 给对象添加属性\n[{id:'11'},{id:'22'},{id:'33'}] [{id:'11'},{id:'33'}]\n想要下面结果 \n[\n{id:'11',follwed:true},\n{id:'22',follwed:false},\n{id:'33',follwed:true}\n]",
"answer": "```\n let arr1 = [{id:'11'},{id:'22'},{id:'33'}];\n let arr2 = [{id:'11'},{id:'33'}];\n let arr = [...arr1, ...arr2];\n let obj = {};\n arr.forEach(item=>{\n if(obj[item.id]){\n obj[item.id].follwed = true\n }else{\n obj[item.id] = item\n obj[item.id].follwed = false\n }\n });\n let result = Object.values(obj);\n console.log(result)\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_121",
"question": "伪元素中content属性为什么不能设置图片尺寸\ndiv::before{\n content: url('a.png');\n display: block;\n width: 100px;\n height: 100px;\n object-fit: fill;\n}\n伪元素的content属性引入的图片之所以不能设置尺寸表现为固有尺寸是不是因为它的默认属性是boject-fit: none\n如果不是那是为什么不能设置呢\n如果是的话那么我已经设置了object-fit: fill为什么依然不能设置呢",
"answer": "`object-fit`是图片`img`的样式,伪元素虽然可以设置图片,但毕竟不是`img`\n你可以用背景图片然后用`background-size:cover`\n```\ndiv::before{\ncontent: '';\ndisplay: block;\nwidth: 100px;\nheight: 100px;\nbackground:url('a.png')\nbackground-size:cover;\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_122",
"question": "el-scrollbar怎么滚动到锚点\nel-scrollbar用的目的是为了好看滚动条被隐藏掉了\n但是现在有个问题是正因为用了它不能滚动到锚点window.scrollTo也不行\nel-scrollbar必须设定高度才可以使用scrollTop的。内容区就是固定高度了很丑啊。\n我要的是`<a href=\"#id\">` 点击直接#id到达锚点的效果",
"answer": "<template>\n <div class=\"test\">\n```\n<a href=\"javascript:void(0)\" @click=\"AnchorLinkTo('id')\">我是锚点</a>\n<el-scrollbar ref=\"myScrollbar\" style=\"height: 300px; width: 500px;\">\n <div>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p ref=\"id\">哈哈哈哈哈哈哈哈哈</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n <p>sdfsdfsd</p>\n </div>\n</el-scrollbar>\n```\n</div>\n</template>\n<script>\nexport default {\n name: 'test',\n data () {\n```\nreturn {}\n```\n},\n methods: {\n```\nAnchorLinkTo (ref) {\n this.$refs['myScrollbar'].wrap.scrollTop = this.$refs['' + ref].offsetTop\n}\n```\n}\n}\n</script>",
"type": "technical_qa"
},
{
"id": "segmentfault_123",
"question": "webpck是不是不能编译这个属性-webkit-box-orient: vertical\n```\n // -webkit-box-orient: vertical!important;\noverflow: hidden;\n-webkit-line-clamp: 2;\nheight: .72rem;\nline-height: .36rem;\ndisplay: -webkit-box;\n```\n这几个属性是用来处理多行文本溢出的但是现在webpack编译以后\n`-webkit-box-orient: vertical`检查元素样式并没有这个属性,\n其他的几个属性都有现在只有把这个属性放入内联样式才行我用的是scss\n希望直接给出解决方案。",
"answer": "解决方案如下\n```\n /* autoprefixer: off */\n -webkit-box-orient: vertical;\n /* autoprefixer: on */\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_124",
"question": "php数组引用的小疑问\n```\n$a=[1,2,3]; \nforeach($a as &$v){} \nforeach($a as $v){}\n\nvar_dump($a);\n\n//结果\n0 => int 1\n1 => int 2\n2 => int 2\n\n```\n为什么最后一个元素变成了2",
"answer": "这个挺有意思的,很简单,我们来分析一下执行流程即可。\n首先第一次是\n```\nforeach($a as $v) {}\n```\n第一次是引用遍历形式而在PHP中foreach里的变量不是只在foreach这个范围内有效而是在整个下文程序中都是有效的。\n所以第一次遍历此时`$v`得到的是`$a`数组最后的一个引用,也就是 `$v == $a[2] == 3`,当前$v是$a[2]的引用。\n然后来看第二次\n```\nforeach($a as $v) {}\n```\n我们来看这里的执行情况这里执行3次我们从第一次到第三次的执行分析。\n首先第一次`foreach`后,`$v = $a[0] == 1`,也就是$v被赋值为`$a[0]`,而从上文我们知道$v是$a[2]的引用,所以,此时相当于`$a[2] = $v = $a[0] == 1`,也就是说,此时`$a = [1,2,1]`\n同理来看第二次`foreach`,此时从第一次循环所看到的`$a = [1,2,1]`可知`$v = $a[1] == 2`,已知$v是$a[2]的引用,所以此时相当于`$a[2] = $v = $a[1] == 2`,也就是说,此时`$a = [1,2,2]`;\n由此可见第三次循环那么`$v = $a[2]`,而从第二次循环可知`$a = [1,2,2]`,所以此时`$v == 2`,已知$v是$a[2]的引用,所以此时相当于`$a[2] = $v = $a[2] == 2`,也就是说,此时`$a = [1,2,2]`\n如果是多次循环可以依此道理进行计算。",
"type": "technical_qa"
},
{
"id": "segmentfault_125",
"question": "react antd table滚动条事件如何实现\n### react antd table滚动条事件如何实现\n### 项目开发中有一个table表格需要做懒加载效果\n### 滚动条事件就是当table的竖向滚动条到底时就触发ajax事件再拿一定条数的数据。",
"answer": "可以试试 onScrollCapture 监听\n类似这样\n```\n<div className={styles.center} onScrollCapture={() => this.onScrollEvent()} ref={c => (this.container = c)}>\n...\n</div>\n```\n```\nconstructor(props) {\n super(props);\n this.onScrollEvent = this.onScrollEvent.bind(this);\n }\n\n onScrollEvent() {\n if (this.container.scrollTop + this.container.clientHeight === \n this.container.scrollHeight) {\n // todo\n }\n }\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_126",
"question": "typescript 泛型内的 `=` 赋值操作是什么意思?\n### 描述\n举个 `jQuery` 声明文件 的 栗子\n```\ninterface JQueryStatic {\n // ...\n <TElement extends Element = HTMLElement>(selector: JQuery.Selector, context?: Element | Document | JQuery): JQuery<TElement>;\n}\n```\n如果是 `<TElement extends Element>(selector: JQuery.Selector, context?: Element | Document | JQuery): JQuery<TElement>` , 我理解大概是说:“可以传入一个泛型参数 TElement且 TElement 需要满足 Element类型的约束条件” \n### 问题\n这里的`=`赋值像是函数参数默认值,代表泛型的默认值么? 但是,由官方栗子可知,类型推论会自动确定确认 T 的类型,应该是不需要泛型的默认值的吧?\n```\n`function identity<T>(arg: T): T {\n return arg;\n}\n\nlet output = identity<string>(\"myString\"); // type of output will be 'string'\n\n// 利用了类型推论 -- 即编译器会根据传入的参数自动地帮助我们确定T的类型\nlet output2 = identity(\"myString\"); // type of output will be 'string'`\n```",
"answer": "就是泛型的默认值。\n阁下引用的例子里写到\n而在`JQueryStatic`里,传入的参数与`TElement`一毛钱关系都没有,换言之,是无法自动推断的。在这种时候,就可以指定一个默认值。\n您引用的例子里写的是“传入的参数”所以我也就沿用了这个不严谨的表达但是看起来导致困惑了……\n这里的“传入的参数”指的是圆括号里的东西即函数的形参。如果圆括号里面没有出现过`TElement`,那么就不可能根据调用时的实参去自动推断泛型。至于泛型的约束条件,可以与默认值同时出现,也可以不同时出现,两者没有必然的联系。\n严格来说“传入”这个词和“泛型参数”这个词是不能搭配的。泛型是定义时使用的运行时会被去掉。\n再补上例子吧\n```\nfunction bare<TElement>(): TElement {\n return null as any as TElement;\n}\n\nconst a = bare(); // typeof a === {}\n\nfunction ext<TElement extends Element>(): TElement {\n return null as any as TElement;\n}\n\nconst b = ext(); // typeof b === Element\n\nfunction dft<TElement extends Element = HTMLElement>(): TElement {\n return null as any as TElement;\n}\n\nconst c = dft(); // typeof c === HTMLElement\n```\n以上圆括号里面都没有出现过`TElement`。",
"type": "technical_qa"
},
{
"id": "segmentfault_127",
"question": "有人说\"如果是手机开发, static 会构成内存负担memory leak 隐患,尽量少用吧。但不用实例话可以直接调用有时又更方便,相对节省内存,这个就拿捏吧。。\"\njava的static方法会不会造成内存负担",
"answer": "这样的说法真是胡说八道。首先所有的方法本质上(底层)都是静态的,非静态方法只是多传了一个隐藏的 this 参数。所以任何方法不论是否静态都会占用内存空间。其次优化内存不应该关心方法,而是应该专注于对象的生存周期。",
"type": "technical_qa"
},
{
"id": "segmentfault_128",
"question": "假如数据库连接数只有1000怎么处理100万的并发量呢不能用负载均衡有别的办法吗\n求大佬们给个思路这是我上午的面试题。。。",
"answer": "1、用redis将高频查询数据存储。提高查询速度\n2、mysql做主从\n3、增删改加队列\n4、切表分库\n5、swoole解决并发\n6、有必要时用grpc做服务治理\n7、微服务\n8、代码分割\n。。。。等等等等\n又是一个面试造核弹上班拧螺丝的过程",
"type": "technical_qa"
},
{
"id": "segmentfault_129",
"question": "js中!!有存在的必要么?为什么?\n### 业务背景\n- 浏览`lodash源码\n- 发现了`!!`这个用法\n- 查了一下,是两次取反的意思\n- 但是没搞懂他存在的必要\n### 示例代码\n```\nfunction isObjectLike(value) {\n return !!value && typeof value == 'object';\n}\n```\n```\nfunction isObjectLike(value) {\n return value && typeof value == 'object';\n}\n```\n### 我的困惑\n- \n官方代码的含义\n - 就是取反之后再取反,最后来判断这个变量是否为真\n- \n我的代码\n - `js`会根据数据类型以及变量值,自动判断他为真为假\n\n比如传一个0进去\n- \n官方的步骤:\n1. !0 => true\n2. !true => false\n- \n我的步骤\n1. 0 => false\n\n### 问题\n- 既然结果都一样,那很多大佬写的代码为什么都要这样用呢?肯定不是多此一举吧",
"answer": "作用是为了类型转换, 强制转换成布尔值.\n至于为什么需要. 我来详细说说:\n```\nfunction isObjectLike(value) {}\n```\n我们期望 isObjectLike 的返回值是个 boolean. 但 && 操作的返回值是参与操作的操作数.\n```\nconsole.log(1 && 2) // 打印 2\nconsole.log(0 && 2) // 打印 0\n```\n所以如果我们传递给 && 的操作数不是布尔类型的, 那么我么得到的返回值就不是布尔值. 我们看看去掉 !! 会造成怎样的不一致性和bug.\n```\nfunction isObjectLike(value) {\n return value && typeof value == 'object'; // 去掉 !!\n}\n\nisObjectLike(0) === false // false 什么? 居然不相等?\n\nconsole.log(isObjectLike(0)) // 打印 0\n```\n你能想象一个叫 `isObjectLike` 的函数返回值类型却不是 boolean 值吗?",
"type": "technical_qa"
},
{
"id": "segmentfault_130",
"question": "vscode 如何配置路径别名?配合webpack使用\n```\nimport { queryString } from '@/utils'\n```\n如果使用相对路径, 如:\n```\nimport { queryString } from '../../utils'\n```\n点击 queryString 就能直接索引到对应的文件\n但是用webpack alias 后 就失去这种便捷的功能了, \nvscode有没有这种路径别名的配置?",
"answer": "放一个jsconfig.json到项目根目录下。\n```\n{\n \"compilerOptions\": {\n \"baseUrl\": \".\",\n \"paths\": {\n \"@/*\": [\"./*\"]\n }\n }\n}\n```\n文档jsconfig#_using-webpack-aliases",
"type": "technical_qa"
},
{
"id": "segmentfault_131",
"question": "js中!!有存在的必要么?为什么?\n### 业务背景\n- 浏览`lodash源码\n- 发现了`!!`这个用法\n- 查了一下,是两次取反的意思\n- 但是没搞懂他存在的必要\n### 示例代码\n```\nfunction isObjectLike(value) {\n return !!value && typeof value == 'object';\n}\n```\n```\nfunction isObjectLike(value) {\n return value && typeof value == 'object';\n}\n```\n### 我的困惑\n- \n官方代码的含义\n - 就是取反之后再取反,最后来判断这个变量是否为真\n- \n我的代码\n - `js`会根据数据类型以及变量值,自动判断他为真为假\n\n比如传一个0进去\n- \n官方的步骤:\n1. !0 => true\n2. !true => false\n- \n我的步骤\n1. 0 => false\n\n### 问题\n- 既然结果都一样,那很多大佬写的代码为什么都要这样用呢?肯定不是多此一举吧",
"answer": "作用是为了类型转换, 强制转换成布尔值.\n至于为什么需要. 我来详细说说:\n```\nfunction isObjectLike(value) {}\n```\n我们期望 isObjectLike 的返回值是个 boolean. 但 && 操作的返回值是参与操作的操作数.\n```\nconsole.log(1 && 2) // 打印 2\nconsole.log(0 && 2) // 打印 0\n```\n所以如果我们传递给 && 的操作数不是布尔类型的, 那么我么得到的返回值就不是布尔值. 我们看看去掉 !! 会造成怎样的不一致性和bug.\n```\nfunction isObjectLike(value) {\n return value && typeof value == 'object'; // 去掉 !!\n}\n\nisObjectLike(0) === false // false 什么? 居然不相等?\n\nconsole.log(isObjectLike(0)) // 打印 0\n```\n你能想象一个叫 `isObjectLike` 的函数返回值类型却不是 boolean 值吗?",
"type": "technical_qa"
},
{
"id": "segmentfault_132",
"question": "说明下为什么this指向window\n能帮我解释下为什么this指向window\n```\nfunction fn(){ console.log(this)\n};\n```\n原理",
"answer": "1. 在这个上下文(执行环境)函数并没有绑定到任何一个对象中,意味着 this 指向 window\n\n2. 从作用域和调用链方面看就很好理解了,函数 fn 的上一级就是全局, 这个 this 指向全局;\n\n3. 如果是在严格模式下执行的,而严格模式下该 this 指向 undefined。",
"type": "technical_qa"
},
{
"id": "segmentfault_133",
"question": "typescript 往window上挂在属性报错如何解决\n编译直接报错如何解决\n```\nwindow.isWeixin = os.weixin ? os.weixin : false;\n```\n就想往window上挂在 有什么好的方法能解决此问题",
"answer": "1. 整个项目都能用的方法,适用于自定义属性\n```\ndeclare global {\n interface Window {\n isWeixin: boolean\n }\n}\n```\n\n2. 单文件的方法适用于简易Polyfill或者不希望泄漏。\n```\ndeclare var window: Window & { isWeixin: boolean }\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_134",
"question": "正则 exec方法 返回数组中 groups是用来存储什么值的\nvar reg = /d+/;\nvar str = 'ac123abc456abc';\nvar result = reg.exec(str);\nconsole.log(result);\n//=> result: [\"123\", index: 2, input: \"ac123abc456abc\", groups: undefined]\n//=> groups 作用是什么?",
"answer": "`groups`是一个新的`field`,用来存储命名捕获组的信息:\n```\nlet reg1 = /(\\d)(\\d)/\nlet str1 = '123'\n\nconsole.log(reg1.exec(str1)) // => [12, 1, 2] 除去第一个以外的其他数据就是分组捕获到的数据,但是因为是一个数组,所以会存在一个记忆成本\n\n// 命名捕获组的获取\nlet reg1 = /(?<first>\\d)(?<second>\\d)/\nlet str2 = '123'\n\nconsole.log(reg2.exec(str2).groups) // => { first: 1, second: 2 } 而新的语法支持对这些捕获组进行命名,更方便地获取某个捕获组的数据\n```\n语法为`(?<捕获组的名字>捕获组对应的规则)`",
"type": "technical_qa"
},
{
"id": "segmentfault_135",
"question": "js算法问题\n```\nlet arr1 = [\n {\n label:'张三'\n value:'1'\n },\n {\n label:'李四',\n value:'2'\n },\n {\n label:'王五',\n value:'3'\n }\n ]\n\nlet arry2 = ['1','2']\n\nlet resArry = ?\n\nconsole.log(resArry) //输出 张三、李四\n```\narry2中的值能对应到arry1中的value 则放入resArry中 最终打印出张三、李四\n这个怎么实现呢",
"answer": "```\nlet resArry = arr1.filter(o=>arry2.indexOf(o.value)>-1).map(o=>o.label);\nconsole.log(resArry);\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_136",
"question": "引入vuxv-chart 报错\n引入vuxv-chart 报错,错误信息如下:\n```\nERROR Failed to compile with 1 errors 18:17:42\n\nerror in ./node_modules/_vux@2.9.1@vux/src/components/v-chart/mixin.js\n\nModule parse failed: Unexpected token (18:6)\nYou may need an appropriate loader to handle this file type.\n| this.$parent.set(this.chartName, {\n| shape: defaultShapeMap[this.chartName] || '',\n| ...this.$props,\n| ...camelAttrs(this.$attrs)\n| })\n```",
"answer": "vux2必须配合vux-loader使用, 请在build/webpack.base.conf.js里参照如下代码进行配置\n```\nconst vuxLoader = require('vux-loader')\nconst webpackConfig = originalConfig // 原来的 module.exports 代码赋值给变量 webpackConfig\n\nmodule.exports = vuxLoader.merge(webpackConfig, {\n plugins: ['vux-ui']\n})\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_137",
"question": "vue路由跳转不刷新\n在'game-detail'页面执行this.$router.push()方法,跳转到'game-detail',页面不刷新。\n因为路由主体没变变的只是传递的参数id\n所以从'game-detail?id=1'到'game-detail?id=2',并没有跳转。\n但是可以在watch里监听$route,监听到id的变化。\n后来我就在watch里边监听路由点击后……重新调用了获取页面数据的methods函数。\n想通过刷新页面数据再加上把滚动条归零来模拟页面的刷新。\n然后……点击后……数据刷新了页面没变化……\n父组件是通过props传递给子组件的请问我应该在子组件里怎么做呢\n刚才百度了发现有的人说是在子组件里watch并且deep监听\n然后我监听到数据变化了以后在子组件里进行赋值也还是不行。\n父组件部分内容\n```\n<child :data=\"dataList\"/>\ndata里边dataList: []\nthis.$http.get().then((res)=>{\n this.dataList.splice(0, this.dataList.length, ...res)\n})\n\n```\nwatch部分\n```\nwatch: {\n $route(to, from) {\n this.$http.get().then((res)=>{\n this.dataList.splice(0, this.dataList.length, ...res)\n })\n }\n}\n\n```\n子组件部分内容\n```\n<div>{{ getData.name }}</div>\nprops: ['data']\ndata里边getData: this.data[0]\n\n```",
"answer": "受邀来答。\n路由参数变化但是页面没有刷新这是Vue的组件复用的默认处理方式\n文档里面写了\n不想复用的话就在父组件的router-view上加个key\n`<router-view :key=\"$route.fullPath\"></router-view>`",
"type": "technical_qa"
},
{
"id": "segmentfault_138",
"question": "怎么判数组中的值相等\nlet arr1 = ['你好','我很好'];\nlet arr2 = [\n```\n { name: '我不知道',value: 0},\n { name: '我不好',value: 1}, \n { name: '你好',value: 2},\n { name: '我特别布好',value: 3}, \n { name: '我很好',value: 4},\n ];\n```\n请问该怎么判断这里面的值相等啊最后输出value",
"answer": "```\narr2.filter(function(el) {\n return ~arr1.indexOf(el.name)\n}).map(function(item) { return item.value })\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_139",
"question": "optimization.runtimeChunk 具体作用是什么?\nwebpack 的optimization.runtimeChunk这个配置项的具体作用是什么看了文档还是不懂",
"answer": "优化持久化缓存的, runtime 指的是 webpack 的运行环境(具体作用就是模块解析, 加载) 和 模块信息清单, 模块信息清单在每次有模块变更(hash 变更)时都会变更, 所以我们想把这部分代码单独打包出来, 配合后端缓存策略, 这样就不会因为某个模块的变更导致包含模块信息的模块(通常会被包含在最后一个 bundle 中)缓存失效. optimization.runtimeChunk 就是告诉 webpack 是否要把这部分单独打包出来.",
"type": "technical_qa"
},
{
"id": "segmentfault_140",
"question": "vue-property-decorator 和 vue-class-component 有什么区别?\n```\n@Component({})\n```\n貌似都可以用以上方式来使用久而久之有点混乱请问他们之间有什么区别或者什么场景下应该使用哪一个",
"answer": "vue class component 是vue 官方出的\nvue property decorator 是社区出的\n其中vue class component 提供了 vue component 等等\nvue property decorator 深度依赖了 vue class component 拓展出了很多操作符 @Prop @Emit @Inject 等等 可以说是 vue class component 的一个超集\n正常开发的时候 你只需要使用 vue property decorator 中提供的操作符即可 不用再从vue class componen 引入vue component",
"type": "technical_qa"
},
{
"id": "segmentfault_141",
"question": "js一道题目大家进来瞅一瞅\n函数add可以实现连续的加法运算\n函数add语法如下\nadd(num1)(num2)(num3)...;//注意这里是省略号哟,无限\n使用举例如下\nadd(10)(10)=20;\nadd(10)(20)(50)=80;\nadd(10)(20)(50)(100)=180;\n请用js代码实现函数add。\n```\nfunction add(num){\n var sum=num,\n \n tmp=function(v){\n sum+=v;\n return tmp\n };\n \n tmp.toString=function(){\n return sum\n };\n \n return tmp\n}\n\n\nconsole.log( add(10)(20)(50) ) //80\n\n```\n这个tmp又返回tmp是什么操作这就是传说中的偏函数吗还有toString的调用",
"answer": "```\nconsole.log( add(10)(20)(50) )\n```\n之后代码运行的过程是\n1.首先执行add(10),初始化add函数内部sum为10,\n```\nreturn tmp=function(v){\n 10+=v;\n return tmp\n };\n```\n2.其后执行tmp(20)即:\n```\nreturn tmp=function(20){\n 10+=20;\n return tmp\n };\n```\n3.其后执行tmp(50)\n```\nreturn tmp=function(50){\n 30+=50;\n return tmp\n };\n```\n4.其后输出时会执行一个类型转换函数即被重写的:\n```\ntmp.toString=function(){\n return sum\n };\n```\n5.输出tmp函数以及即内容即此时的sum80",
"type": "technical_qa"
},
{
"id": "segmentfault_142",
"question": "无缝轮播滚动js代码异步出了点小问题\n要轮播5张图 ,布置 5->1->2->3->4->5->1 7张图 要实现无缝\n实际思路上就是最后一张滚到第一张实际是顺着滚动画结束再取消transition切回第一张再附加transition\n现在我遇到这个个问题\n```\n/...5->1执行的代码有滚动动画.../\n if (newLeft === -3600) { //滚到第7张图时的left,执行回滚\n setTimeout(function () {\n list.style.transition = 'none'; //取消动画\n list.style.left = -600 + 'px'; //瞬间回滚\n list.style.transition = 'left 2s linear';//恢复动画 //但是这句话回滚的时候会生效是为什么\n },2000)\n }\n\n```\n这么写回滚的时候动画会生效\n必须要用下面的写法第二个计时器必须大于2000几个毫秒才满足需求,\n为什么会发生这种事情计时器里面回调函数应该是同步的呀 list.style.left = -600 + 'px';不执行完后面应该是不会设置动画的呀?\n```\nif (newLeft === -3600) {\n setTimeout(function () {\n list.style.transition = 'none';\n list.style.left = -600 + 'px';\n },2000)\n setTimeout(function () {\n list.style.transition = 'left 2s linear';\n },2020)\n}\n\n```\n这里我发现间隔时间1-4秒基本没用给间隔10ms偶尔会出现回滚动画设置20ms基本没问题\n实际上还是刚刚的问题js是单线程会阻塞2000ms执行的代码如果不执行完2010ms是不会把异步代码拿来执行的如果执行完了那么我这个回滚应该是没有动画的。求大神解释一下",
"answer": "浏览器会在一个特定的点去执行渲染,在那之前的操作是没有中间态的!\n```\nlist.style.left = 0 + 'px';\n\n// 某一时刻 浏览器渲染\n\n// 浏览器执行js\nlist.style.left = 1 + 'px';\nlist.style.left = 2 + 'px';\nlist.style.left = 3 + 'px';\nlist.style.left = 4 + 'px';\n\n// 某一时刻 浏览器渲染\n```\n在两次渲染间,浏览器只知道 `list.style.left` 从 0 变为 4px 这个事实, 他不知道也不关心你到 4 中间发生了什么, 你可以是1个px 累加,或先到100再到4. 浏览器看到就是上一次渲染是0,这次是4.\n所以\n```\nlist.style.transition = 'none'; \nlist.style.left = -600 + 'px';\nlist.style.transition = 'left 2s linear';\n```\n在浏览器看来就是:\n```\nlist.style.left = -600 + 'px';\nlist.style.transition = 'left 2s linear';\n```\n解决办法是在需要被感知状态的地方让浏览器进行一次渲染, setTimeout 就可以达到这个效果,还有常见的访问 `offsetWidth` 等属性触发一次 reflow.\n方案一:\n```\nlist.style.transition = 'none'; \nlist.style.left = -600 + 'px';\n\n// 触发 reflow\nlist.offsetWidth;\n\nlist.style.transition = 'left 2s linear';\n```\n方案二:\n```\n\nsetTimeout(function () {\n list.style.transition = 'none';\n list.style.left = -600 + 'px';\n\n // 延迟这部分脚本执行, 让浏览器先渲染当前帧\n setTimeout(() => {\n list.style.transition = 'left 2s linear';\n })\n},2000)\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_143",
"question": "vue failed to convert exception to string\n使用了vue的导航守卫之后就报错\n```\nfailed to convert exception to string\n```\n```\nrouter.beforeEach(function(to, from, next){\n /* 路由发生变化修改页面title */\n if (to.meta.title) {\n document.title = to.meta.title\n }\n if(!localStorage.getItem('token')){\n // router.push({name:'login'})\n // router.push({name: 'login'});\n next({ path: '/user/login' });\n }\n next();\n});\nexport default router;\n```",
"answer": "你这样写会陷入无限循环的,给你个参考下\n```\nlet login = localStorage.getItem('token')\nlet path = to.path\nif (path === '/user/login') {\n next()\n return\n}\nif (login) {\n if (path === '/') {\n next({\n path: '/index'\n })\n } else {\n next()\n }\n} else {\n next({\n path: '/user/login'\n })\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_144",
"question": "js如何修改对象的key值\n原数据\n```\nvar array = [\n {\n id:1,\n name:\"小明\"\n },\n {\n id:2,\n name:\"小红\"\n }\n];\n\n```\n我要改为的数据\n```\nvar array = [\n {\n value:1,\n label:\"小明\"\n },\n {\n value:2,\n label:\"小红\"\n }\n];\n\n```\n对应的值不变只是改key的名称用js如何实现呢",
"answer": "```\nvar array = [\n {\n id:1,\n name:\"小明\"\n },\n {\n id:2,\n name:\"小红\"\n }\n];\n//旧key到新key的映射\nvar keyMap = {\n \"id\" : \"value\",\n \"name\" : \"label\"\n};\n\nfor(var i = 0;i < array.length;i++){\n var obj = array[i];\n for(var key in obj){\n var newKey = keyMap[key];\n if(newKey){\n obj[newKey] = obj[key];\n delete obj[key];\n }\n }\n}\nconsole.log(array);\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_145",
"question": "go gorm select 了字段后 结果集还是所有的struct都被返回只是其他字段为空\n### go gorm select 了字段后 结果集还是所有的struct都被返回只是其他字段为空\n### 问题出现的环境背景及自己尝试过哪些方法\n### 相关代码\ndb.Debug().Where(s).Select([]string{\"id\",\"username\",\"phone\"}).Find(&user)\ntype User struct {\n```\ngorm.Model\nUsername string `json:\"username\"`\nPhone string `json:\"phone\"`\nType int8 `json:\"type\"`\nOrder []Order `gorm:\"ForeignKey:UId\"` // hasMany 设置对应的外键\nCreditCard *CreditCard `gorm:\"foreignkey:CardID\"`\nCardID uint\n```\n}\n### 实际结果\n```\n[\n{\n\"id\": 3,\n\"created_at\": \"0001-01-01T00:00:00Z\",\n\"updated_at\": \"0001-01-01T00:00:00Z\",\n\"deleted_at\": null,\n\"username\": \"hello\",\n\"phone\": \"18672858778\",\n\"type\": 0,\n\"Order\": null,\n\"CreditCard\": null,\n\"CardID\": 0\n},\n{\n\"id\": 6,\n\"created_at\": \"0001-01-01T00:00:00Z\",\n\"updated_at\": \"0001-01-01T00:00:00Z\",\n\"deleted_at\": null,\n\"username\": \"hello\",\n\"phone\": \"18672858778\",\n\"type\": 0,\n\"Order\": null,\n\"CreditCard\": null,\n\"CardID\": 0\n},\n{\n\"id\": 9,\n\"created_at\": \"0001-01-01T00:00:00Z\",\n\"updated_at\": \"0001-01-01T00:00:00Z\",\n\"deleted_at\": null,\n\"username\": \"hello\",\n\"phone\": \"18672858779\",\n\"type\": 0,\n\"Order\": null,\n\"CreditCard\": null,\n\"CardID\": 0\n},\n{\n\"id\": 12,\n\"created_at\": \"0001-01-01T00:00:00Z\",\n\"updated_at\": \"0001-01-01T00:00:00Z\",\n\"deleted_at\": null,\n\"username\": \"hello\",\n\"phone\": \"18672858779\",\n\"type\": 0,\n\"Order\": null,\n\"CreditCard\": null,\n\"CardID\": 0\n}\n]\n```\n期望结果\n```\n[{\n\"id\":6,\n\"username\":\"hello\",\n\"phone\":\"18672858779\"\n},\n{\n\"id\":9,\n\"username\":\"hello\",\n\"phone\":\"18672858779\"\n}\n]\n```",
"answer": "因为你使用是的:\n```\nFind(&user)\n```\n其中&user 是一个 stuct ,肯定是一个完整的结构,没有值的字段会有默认值\n如果不想显示那些的话可以使用 Scan\n```\ntype Result struct {\n Name string\n Age int\n}\n\nvar result Result\ndb.Table(\"users\").Select(\"name, age\").Where(\"name = ?\", 3).Scan(&result)\n\n// Raw SQL\ndb.Raw(\"SELECT name, age FROM users WHERE name = ?\", 3).Scan(&result)\n\n```\n文档见这里",
"type": "technical_qa"
},
{
"id": "segmentfault_146",
"question": "vue中 钩子函数如何使用async\n```\n async created () {\n await setTimeout(()=>{\n console.log(1)\n },5000);\n },\n async mounted () {\n console.log(2)\n }\n```\n在vue中给created使用async await还是会先输出2而不是等1输出完",
"answer": "可以变相达到这个目的\n```\n async created () {\n this.create_promise = new Promise(resolve=>this.create_promise_resolve=resolve);\n setTimeout(()=>{\n console.log(1);\n this.create_promise_resolve();\n },1000)\n },\n async mounted () {\n await this.create_promise;\n console.log(2)\n }\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_147",
"question": "axios的withCredentials问题\n### 问题描述\n我想要跨域带上`cookies`,为什么`withCredentials: true`不起作用?\n### 问题出现的环境背景及自己尝试过哪些方法\n我尝试过`axios.defaults.withCredentials = true`可以起作用。 \n但是为什么单独配置没有作用\n### 相关代码\n```\naxios.post('http://101.132.138.141:8888/service/pageUsers', objectToForm({\n 'currentPage': '1',\n 'pageSize': '10',\n 'token': '7e987daa-6c84-46d2-be26-f345dfaed8a7',\n }), {\n // 单独配置\n withCredentials: true\n })\n .then(function(res) {\n console.log(res.data);\n })\n .catch(function(err) {\n console.error(err);\n });\n```\n### 实际看到的错误信息又是什么?\n后端已经设置了`CORS`头,但是因为没有附带上`cookies`,所以被拦截器拦截了。",
"answer": "withCredentials的情况下后端要设置Access-Control-Allow-Origin为你的源地址例如http://localhost:8080不能是*而且还要设置header('Access-Control-Allow-Credentials: true');",
"type": "technical_qa"
},
{
"id": "segmentfault_148",
"question": "Nodejs里运行npm run dev shell脚本无效果\n### 问题描述\nNodejs里如何运行npm run dev shell脚本\n### 问题出现的环境背景及自己尝试过哪些方法\n1、在webpack构建的模块里npm run script一个node脚本文件但是我想在这个脚本文件里运行其它的npm run尝试了require('child_process').exec但是无效执行到这里什么反应都没。\n### 相关代码\nvar exec = require('child_process').execSync\nexec('npm run dev')\n### 你期待的结果是什么?实际看到的错误信息又是什么?\n或者在node脚本js文件里如何才能正确执行package.json里的script呢\n### 补充贴上\n```\n{\n \"name\": \"vue\",\n \"version\": \"1.0.0\",\n \"description\": \"A Vue.js project\",\n \"author\": \"author@gmail.com\",\n \"private\": true,\n \"scripts\": {\n \"dev\": \"webpack-dev-server --inline --progress --config build/webpack.dev.conf.js\",\n \"modify\": \"node script/modify-path.js\",\n \"build:prod\": \"npm run modify && npm run build --no-cache\",\n \"start\": \"npm run dev\",\n \"lint\": \"eslint --ext .js,.vue src\",\n \"build\": \"node build/build.js\"\n },\n \"dependencies\": {\n \"fg-loadcss\": \"^2.0.1\",\n \"vue-router\": \"^3.0.1\"\n },\n \"devDependencies\": {\n \"autoprefixer\": \"^7.1.2\",\n \"babel-core\": \"^6.22.1\",\n \"babel-eslint\": \"^8.2.1\",\n \"babel-helper-vue-jsx-merge-props\": \"^2.0.3\",\n \"babel-loader\": \"^7.1.1\",\n \"babel-plugin-syntax-jsx\": \"^6.18.0\",\n \"babel-plugin-transform-runtime\": \"^6.22.0\",\n \"babel-plugin-transform-vue-jsx\": \"^3.5.0\",\n \"babel-preset-env\": \"^1.3.2\",\n \"babel-preset-stage-2\": \"^6.22.0\",\n \"chalk\": \"^2.0.1\",\n \"commander\": \"^2.16.0\",\n \"copy-webpack-plugin\": \"^4.0.1\",\n \"cross-env\": \"^5.2.0\",\n \"css-loader\": \"^0.28.0\",\n \"eslint\": \"^4.19.1\",\n \"eslint-config-standard\": \"^11.0.0\",\n \"eslint-friendly-formatter\": \"^4.0.1\",\n \"eslint-loader\": \"^2.0.0\",\n \"eslint-plugin-import\": \"^2.13.0\",\n \"eslint-plugin-node\": \"^6.0.1\",\n \"eslint-plugin-promise\": \"^3.8.0\",\n \"eslint-plugin-standard\": \"^3.1.0\",\n \"eslint-plugin-vue\": \"^4.7.0\",\n \"execa\": \"^0.10.0\",\n \"file-loader\": \"^1.1.11\",\n \"fontfaceobserver\": \"^2.0.13\",\n \"fontmin\": \"^0.9.7-beta\",\n \"fontmin-webpack\": \"^2.0.1\",\n \"friendly-errors-webpack-plugin\": \"^1.6.1\",\n \"html-webpack-plugin\": \"^3.2.0\",\n \"inquirer\": \"^6.0.0\",\n \"js-yaml\": \"^3.12.0\",\n \"mini-css-extract-plugin\": \"^0.4.1\",\n \"node-notifier\": \"^5.1.2\",\n \"node-sass\": \"^4.9.2\",\n \"optimize-css-assets-webpack-plugin\": \"^5.0.0\",\n \"ora\": \"^1.2.0\",\n \"portfinder\": \"^1.0.13\",\n \"postcss-import\": \"^11.0.0\",\n \"postcss-loader\": \"^2.0.8\",\n \"postcss-url\": \"^7.2.1\",\n \"rimraf\": \"^2.6.0\",\n \"sass-loader\": \"^7.0.3\",\n \"semver\": \"^5.3.0\",\n \"shelljs\": \"^0.7.6\",\n \"uglifyjs-webpack-plugin\": \"^1.1.1\",\n \"url-loader\": \"^1.0.1\",\n \"vue\": \"^2.5.16\",\n \"vue-loader\": \"^15.2.4\",\n \"vue-style-loader\": \"^3.0.1\",\n \"vue-template-compiler\": \"^2.5.2\",\n \"webfont-webpack-plugin\": \"^0.2.2\",\n \"webpack\": \"^4.16.0\",\n \"webpack-bundle-analyzer\": \"^2.9.0\",\n \"webpack-cli\": \"^3.0.8\",\n \"webpack-dev-server\": \"^3.1.4\",\n \"webpack-merge\": \"^4.1.0\"\n },\n \"engines\": {\n \"node\": \">= 6.0.0\",\n \"npm\": \">= 3.0.0\"\n },\n \"browserslist\": [\n \"> 1%\",\n \"last 2 versions\",\n \"not ie <= 8\"\n ]\n}\n\n```",
"answer": "这就是你想要的\n```\nvar spawn = require('child_process').spawn;\n\nspawn('npm', ['run','dev'], {\n stdio: 'inherit'\n});\n```\n或\n```\nvar exec = require('child_process').execSync;\nexec('npm run dev', {stdio: 'inherit'});\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_149",
"question": "菜鸟问题axios到底是装在devDependencies中还是装在dependencies中\n之前只是用一直没有注意这个问题在github上axios的官方安装是\n```\n$ npm install axios\n```\n那就等于是安装在dependencies中了但是我现在的项目中是安装在devDependencies中的关键是打包后仍然可以正常使用所以我有点没明白",
"answer": "除了字面的含义的区别,\n`dependencies`和`devDependencies`的区别还在于:\n如果你的项目是发布到`npm`的一个包,\n那么这个包的`package.json`中的`dependencies`中的依赖是会被下载下来到这个包的`node_modules`文件夹中的(如果你的项目本身没有这个依赖),而`devDependencies`不会。\n举个例子\n我发布了一个组件`A`,它有`dependencieslodash`和`devDependenciesmoment`。\n那么如果你的项目`npm install` 了组件`A`。\n除非你的项目也依赖了`lodash`并且版本一致,那么项目的`node_modules/A`下会有一个`node_modules`,里面会有`lodash`。\n而 `moment`,则无论如何也不会出现在你的项目中。\n至于一般的项目不管你是安装在dev还是dependencies中安装的时候都会安装打包的时候都会被打进去的区分依赖只是为了让项目看起来更加清晰。",
"type": "technical_qa"
},
{
"id": "segmentfault_150",
"question": "为什么webpack可以通过require('path')直接使用node.js的内置模块\n这个问题可能看起来很搞笑我也经常用webpack用到node.js的模块时因为之前跟着教程学习的缘故所以也没觉得有什么奇怪。\n可是现在想想为什么webpack可以通过require('path')直接使用node.js的内置模块呢\n感觉webpack在打包时通过node起了一个服务吧。或者说用webpack时项目本身已经是一个node项目了",
"answer": "- js是一种解释型语言不能直接运行需要运行环境。\n- 常见的运行环境有web浏览器后端服务器(nodejs环境)等。\n- webpack里的js不是在浏览器中运行的而是在后端环境中运行的这里就是nodejs环境。\n- 相当于在nodejs环境中跑webpack当然可以使用node内置模块。",
"type": "technical_qa"
},
{
"id": "segmentfault_151",
"question": "js 数组赋值问题 :值传递还是引用?\n### 题目描述\n```\nvar a = [1,2,3];\nvar b = a;\na = [4,5,6];\nalert(b); //[1,2,3]\n\n\nvar a = [1,2,3];\nvar b = a;\na.pop();\nalert(b); //[1,2]\n//第一个我懂 第二个我不懂\n```\n### 题目来源\n知乎\n```\n这是一个人回答的\na = [4,5,6];//改变的是a引用本身没有改变数组对象\na.pop();//改变的是数组对象a引用没有改变。\nb = a;//该操作后b直接指向数组对象不是b指向aa再指向数组。\n//所以改变a引用并不会对b引用造成影响改变数组对象可以\n\n```\n但是我觉得说不通啊 我觉得应该是 这个执行顺序啊 但是从结果看 我是错的~~\n```\na = [4,5,6];//改变的是a引用本身没有改变数组对象\nb = a; // 这边还是指向引用\na.pop();\n\n```\n早上在知乎翻到的 看了他们的答案还是有点蒙蔽 有点蒙蔽 大佬能不能简明扼要的解答下 \n我有点菜 望不吝赐教",
"answer": "[1,2,3]是一幢楼,\n[4,5,6]也是一幢楼,\na和b是两块门牌号铁皮。\n```\nvar a = [1,2,3]; //把a牌号挂到 123楼门口\nvar b = a; //把b牌号挂到 a牌号所在的楼门口即123楼\na = [4,5,6]; //把a牌号摘下来挂到了456楼的门口\nalert(b); //[1,2,3] //此时b牌号依旧挂在123楼门口b即代表着123楼\n\n\nvar a = [1,2,3]; //把a牌号挂到 123楼门口\nvar b = a; //把b牌号挂到 a牌号所在的楼门口即123楼\na.pop(); //把a牌号所在的楼拆掉顶层,此时a牌号仍旧挂在123楼门口那就拆3层\nalert(b); //[1,2] //b牌号仍旧挂在 原123楼门口但此时只剩12两层\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_152",
"question": "typescript 往window上挂在属性报错如何解决\n编译直接报错如何解决\n```\nwindow.isWeixin = os.weixin ? os.weixin : false;\n\n\n```\n### 就想往window上挂在 有什么好的方法能解决此问题",
"answer": "上面的any大法当然是可以解决所有问题我补充两个漂亮点的方法吧。\n整个项目都能用的方法适用于自定义属性\n```\n`declare global {\n interface Window {\n isWeixin: boolean\n }\n}`\n```\n单文件的方法适用于简易Polyfill或者不希望泄漏\n```\n`declare var window: Window & { isWeixin: boolean }`\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_153",
"question": "es6中对象属性双方括号是什么意思\n### es6中对象属性双方括号是什么意思?\n在react表单输入输入框的change事件中\n```\nhandleChange = (e) => {\n console.log(e);\n this.setState({\n value: e.target.value\n });\n}\n```\n这里的event对象是一个proxy对象将其打印到控制台输出如下\n```\n[[Handler]] : Object\n set : ƒ (target, prop, value)\n __proto__ : Object\n[[Target]] : SyntheticEvent\n bubbles : (...)\n cancelable : (...)\n currentTarget : (...)\n defaultPrevented : (...)\n dispatchConfig : null\n eventPhase : (...)\n isDefaultPrevented : null\n isPropagationStopped : null\n isTrusted : (...)\n nativeEvent : (...)\n target : (...)\n timeStamp : (...)\n type : (...)\n _dispatchInstances : null\n _dispatchListeners : null\n _targetInst : null\n preventDefault : (...)\n stopPropagation : (...)\n get bubbles : ƒ ()\n set bubbles : ƒ (val)\n get cancelable : ƒ ()\n set cancelable : ƒ (val)\n get currentTarget : ƒ ()\n set currentTarget : ƒ (val)\n get defaultPrevented : ƒ ()\n set defaultPrevented : ƒ (val)\n get eventPhase : ƒ ()\n set eventPhase : ƒ (val)\n get isTrusted : ƒ ()\n set isTrusted : ƒ (val)\n get nativeEvent : ƒ ()\n set nativeEvent : ƒ (val)\n get target : ƒ ()\n set target : ƒ (val)\n get timeStamp : ƒ ()\n set timeStamp : ƒ (val)\n get type : ƒ ()\n set type : ƒ (val)\n get preventDefault : ƒ ()\n set preventDefault : ƒ (val)\n get stopPropagation : ƒ ()\n set stopPropagation : ƒ (val)\n __proto__ : Object\n[[IsRevoked]] : false\n\n\n```\n如果是函数对象又会有这样的结构\n```\narguments : (...)\ncaller : (...)\nlength : 0\nname : \"\"\nprototype : {constructor: ƒ}\n__proto__ : ƒ ()\n[[FunctionLocation]] : emptyFunction.js:13\n[[Scopes]] : Scopes[2]\n```\n那这个对象里的[[]](双方括号)属性命名是有什么意义?",
"answer": "双方括号代表这是JavaScript引擎内部使用的属性/方法可以帮助debug点一下`[[FunctionLocation]]`就能跳到定义,点一下`[[Scopes]]`就能查看闭包但是正常JavaScript代码是取不到这些属性的。\n引擎看心情决定要显示哪些内部属性显示的格式也没有规定但在控制台里大家一般都约定俗成用双方括号保持和规范的格式一致。\nECMA 标准: Object Internal Methods and Internal Slots",
"type": "technical_qa"
},
{
"id": "segmentfault_154",
"question": "面试题http和https的区别是什么跟TCP/IP四层模型有什么关系\n在面试中被问到http和https的具体区别是什么\n与tcp/ip有什么关系了跟三次握手有关系吗\n能不能好好讲解下",
"answer": "## 区别\nHTTP协议传输的数据都是未加密的也就是明文的可以用抓包工具直接抓下来而HTTPS则是利用了网景公司设计的SSLSecure Sockets Layer协议对HTTP协议传输的数据进行加密抓包工具抓下来的是密文大幅增加了中间人攻击的成本。简单来说HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议要比http协议安全。\n## 跟TCP/IP的区别\nTPC/IP协议是传输层和网络层协议主要解决数据如何在网络中传输而HTTP是应用层协议主要解决如何包装数据。WEB使用HTTP协议作应用层协议以封装HTTP 文本信息然后使用TCP/IP做传输层协议将它发到网络上。\n## 三次握手过程中的区别\n太长不看版\n```\nHTTP:使用三次TCP握手确认建立一个HTTP连接。\nHTTPS:HTTPS在HTTP的基础上加入了SSL协议SSL依靠证书来验证服务器的身份并为浏览器和服务器之间的通信加密。\n```\n详细贼长版\nHTTP三次握手\n```\n第一次握手客户端发送syn包(syn=j)到服务器并进入SYN_SEND状态等待服务器确认\n\n第二次握手服务器收到syn包必须确认客户的SYNack=j+1同时自己也发送一个SYN包syn=k即SYN+ACK包此时服务器进入SYN_RECV状态\n\n第三次握手客户端收到服务器的SYNACK包向服务器发送确认包ACK(ack=k+1)此包发送完毕客户端和服务器进入ESTABLISHED状态完成三次握手。\n```\nHTTPS复杂的三次握手\n```\n1. 客户端发起HTTPS请求\n\n2. 服务端的配置\n\n采用HTTPS协议的服务器必须要有一套数字证书可以是自己制作或者CA证书。区别就是自己颁发的证书需要客户端验证通过才可以继续访问而使用CA证书则不会弹出提示页面。这套证书其实就是一对公钥和私钥。公钥给别人加密使用私钥给自己解密使用。\n\n3. 传送证书\n\n这个证书其实就是公钥只是包含了很多信息如证书的颁发机构过期时间等。\n\n4. 客户端解析证书\n\n这部分工作是有客户端的TLS来完成的首先会验证公钥是否有效比如颁发机构过期时间等如果发现异常则会弹出一个警告框提示证书存在问题。如果证书没有问题那么就生成一个随即值然后用证书对该随机值进行加密。\n\n5. 传送加密信息\n\n这部分传送的是用证书加密后的随机值目的就是让服务端得到这个随机值以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。\n\n6. 服务段解密信息\n\n服务端用私钥解密后得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对称加密。所谓对称加密就是,将信息和私钥通过某种算法混合在一起,这样除非知道私钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全。\n\n7. 传输加密后的信息\n\n这部分信息是服务段用私钥加密后的信息可以在客户端被还原。\n\n8. 客户端解密信息\n\n客户端用之前生成的私钥解密服务段传过来的信息于是获取了解密后的内容。\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_155",
"question": "var a=5a=6a的地址变了没有啊\nvar a=5a=6a的地址变了没有啊",
"answer": "答案是“不知道”。\n如果这两段代码如你所写\n```\nvar a=5;a=6;\n```\n那么没变因为目前任何 js 引擎都会把这段代码直接优化编译为 `var a=6;`。\n如果 `a` 先初始化为 5在后面的程序中一直使用这个 `5`。然后在某一步又被重新赋值为 `6`。 那么 `a` 的地址变了吗?\n这也得分情况如果是在一个短小的函数中也许 `a` 根本就没有内存地址,而是直接在寄存器里面进行运算。\n即使 `a` 在内存中分配,也不能保证 `a` 的地址是不变的,因为在 GC 阶段要进行新生代内存区域交换和老生代内存碎片整理。\n至于通常用来对比 `var` 和 `const` 的说法,“`const` 只是保证了内存地址不变,而不能保证引用的数据不变”,这个只是民间的说法,规范里面从来没有这么说。之所以这么说,是使用了 C++ 的概念来说明 `const` 的常量性质。\n如果从 JavaScript 使用者的角度将,我们可以认为 `const` 定义的变量(常量)地址指向是不变的,但是如果从引擎和底层的角度讲,我们不能想当然的认为常量的地址是不变的。",
"type": "technical_qa"
},
{
"id": "segmentfault_156",
"question": "微信小程序里自定义组件canvas组件没有效果\n微信小程序里自定义组件canvas组件没有效果请问有没有人遇到过这个问题\n```\n ready(){\n const ctx = wx.createCanvasContext('back-canvas')\n ctx.setFillStyle('red')\n ctx.fillRect(10, 10, 150, 75)\n ctx.draw();\n },\n```\n```\n<canvas class='ca' canvas-id=\"back-canvas\" style=\"width:200px;height:200px;\"></canvas>\n```",
"answer": "createCanvasContext这个是有两个参数的在page页面默认传了一个This,组件里面 需要传this\nconst ctx = wx.createCanvasContext('myCanvas',this);",
"type": "technical_qa"
},
{
"id": "segmentfault_157",
"question": "vue获取后端数据应该在created还是mounted方法\nvue获取后端数据应该在created还是mounted方法",
"answer": "看情况了一般放到created里面就可以了这样可以及早发请求获取数据如果有依赖dom必须存在的情况就放到`mounted(){this.$nextTick(() => { /* code */ })}`里面",
"type": "technical_qa"
},
{
"id": "segmentfault_158",
"question": "async函数块之间如何同步执行\n请问多个async函数块之间如何同步的进行执行\n例子以下两个async函数块如何顺序进行\n```\nclass Example {\n first;\n second;\n constructor(){\n }\n \n async getFirstVal(){\n this.first = await [一个promise]\n }\n \n async getSecondVal(){\n this.second = await[一个依赖于first的promise]\n }\n \n async getOtherVal(){\n this.other = await[一个promise]\n }\n \n doSomeWork(){\n this.getFirstVal(); \n this.getSecondVal();\n this.getOtherVal();\n ........\n }\n}\n\n```\n请问怎么做才能保证doSomeWork里面的first和second这两个异步块顺序执行\n我不想将second这一部分的逻辑写入getFirstVal方法中虽然这样能获得正确的执行顺序因为getFirstVal可能在很多地方都会异步调用到我想将他封装成一个单独的函数。请问有什么好的方法帮助我实现这种async块之间的顺序执行吗",
"answer": "```\nasync doSomeWork() {\n await this.getFirstVal(); \n this.getSecondVal();\n this.getOtherVal();\n}\n```\n这样可以吗优雅的方案也没太研究过但是你可以 看看 Rxjs 或者 async 这些库,能得到比较好的思路",
"type": "technical_qa"
},
{
"id": "segmentfault_159",
"question": "只用了el-dropdown怎么控制el-dropdown的显示和隐藏\n我只引用了el-dropdown没有引用el-dropdown-menu和el-dropdown-item。\ndropdown里面的内容都自己写的请问要怎么控制dropdown的显示和隐藏呢",
"answer": "解决了看dropdown的源码封装有hiden()和show()方法直接给el-dropdown加个ref再通过ref运行组件内的方法即可\n```\n<el-dropdown trigger=\"click\" ref=\"messageDrop\"></el-dropdown>\n\nthis.$refs.messageDrop.hide();\nthis.$refs.messageDrop.show();\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_160",
"question": "bind,call,apply在实际项目中什么地方会用到 ? \n经常看到介绍call或者apply的文章,然后会以下面这种代码来举例说明 .\n```\nfunction identify() {\n console.log(\"Hello,I'm \" + this.name);\n}\nlet me = {\n name: \"Kyle\"\n};\nlet you = {\n name: \"Reader\"\n};\nidentify.call(me); // Hello,I'm Kyle\nidentify.call(you); // Hello,I'm Reader\n```\n我有点不理解的是,实际开发的时候以参数的形式传给 `indentify(obj)` 方法不是更好吗,\n```\n// 传参形式\nfunction identify(obj) {\n console.log(\"Hello,I'm \" + obj.name);\n}\nlet me = {\n name: \"Kyle\"\n};\nlet you = {\n name: \"Reader\"\n};\nidentify(me); // Hello,I'm Kyle\nidentify(you); // Hello,I'm Reader\n```\n那么bind,call,apply一般在实际项目中什么地方会用到 ?",
"answer": "我也同意第二种方法更好。实际上我觉得JavaScript没给`this`一个正式的形参地位就是设计失误,其他函数式/面向对象混合的语言都显式给出了以至于被Python点名嘲讽新语言都不敢用`this`这个关键字了TypeScript如果在`class`之外引用`this`也是要求作为第一个形参显式声明的。编译器知道`this`是隐藏参数,程序员也知道,但大家都闷声大发财,这是最糟糕的。\n## \n\n`bind`可以拿来做偏函数应用,试试往后面继续填参数,这些参数会被“记住”,以便之后使用。\n在现代语境下`call`/`apply`的唯一作用就是把本来是隐藏参数的`this`提成正式参数,允许程序员显式指定。上面举的例子`Math.max.apply(null, [1, 2, 3, 4])`,推荐的做法应该是`Math.max(...[1, 2, 3, 4])`,清晰明了,而且在现代浏览器里性能会略有提升。除非是引用了别人的代码,恕我直言,自愿去搅和`call`/`apply`的,都是文明用语行为。\n## 封装起来给别人使用/别人写的代码\n个人观察现在的大趋势也是不做文明用语行为不在`class`以外乱搞`this`,所以可以期待别人写的代码里需要`call`/`apply`的也会越来越少。koa 1用`this`传上下文被喷了koa 2马上改成显式形参。lodash这种工具库全是第二种方式传参的如果想链式调用都需要手动包装。\nvue一大堆`this`,其实一小撮人是有意见的,考虑到一般来说组件的函数都不通用,不存在需要`call`/`apply`的场合我也就接受了。但vuex的mutations很有可能是通用的所以也是用的第二种方式传参要不然真的是超级文明用语。如果是自己写的代码需要别人提供`this`,建议反思一下。\n## unbound\n上面有回答提到“反柯里化的实现”实际上我觉得应该叫debound更多是历史遗留问题的妥协方案。被设计为通用的函数本身就不应该被绑在特定的类里面只不过此事已经发生ES标准又不能大改只能将就着。像Python这种兼容性喂狗的语言早就彻底消除了“反柯里化”这种行为的必要性全是直接用第二种方式传参。不是因为`this`的话,没有必要自找麻烦。\n## 总结\n- \n`call`/`apply`是历史遗留问题的解决方案\n- \n`bind`的用处更广泛些,偏函数应用还是相当好使的\n- 为了用那些老库,学习`call`/`apply`还是有必要的\n- 自己写的代码不要牵扯`call`/`apply`",
"type": "technical_qa"
},
{
"id": "segmentfault_161",
"question": "JAVA为什么要有多个类加载器1个不行吗",
"answer": "思考以下情景:\n\n1. 首先,是为了区分同名的类:假定存在一个应用服务器,上面部署着许多独立的应用,同时他们拥有许多同名却不同版本的类库。试想,这时候 jvm 该怎么加载这些类同时能尽可能的避免掉类加载时对同名类的差异检测呢?当然是不同的应用都拥有自己独立的类加载器了。\n2. 其次,是为了更方便的加强类的能力:类加载器可以在 load class 时对 class 进行重写和覆盖,在此期间就可以对类进行功能性的增强。比如添加面向切面编程时用到的动态代理,以及 debug 等原理。怎么样达到仅修改一个类库而不对其他类库产生影响的效果呢?一个比较方便的模式就是每个类库都可以使用独立的类加载器\n\n小结\njvm 需要有不同的类加载器,因为它一方面允许你在一个 jvm 里运行不同的应用程序,另一方面方便你独立的对不同类库进行运行时增强。",
"type": "technical_qa"
},
{
"id": "segmentfault_162",
"question": "npm start 和 npm run start的关系\nnpm start 和 npm run start有什么关系吗\n要是在package.json的\"scripts\"里有 start 项\n执行 npm run start 和 npm start 好像是一样的效果\n但是如果是别的命令项\n执行 npm run \"别的命令\" 和npm \"别的命令\" 效果就会不一样\n向大佬求解",
"answer": "`npm start`和 `npm run start`是等效关系在一个npm管理项目中一般默认有`start`的定义,且会经常使用,所以就在`npm`执行中简化输入目的设置了`npm run start`的简写,类似的还有`npm stop`、`npm test`等等。而其他的一些不太通用的命令项则只能通过`npm run <命令项>`的形式执行啦。",
"type": "technical_qa"
},
{
"id": "segmentfault_163",
"question": "Javascript的生成器函数要多加一个星号Python却不需要额外标识为什么这样设计\n一个Javascript的生成器函数是这样的\n```\nfunction *gen(n) {\n for (let i = 0; i < n; i++) {\n yield i;\n }\n}\n[...gen(10)]\n// <- (10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n```\nJavascript在声明的时候要多加一个星号。如果不加星号会报`SyntaxError`。\n一个python的生成器函数是这样的\n```\ndef gen(n):\n for i in range(n):\n yield i\n\n>>> list(gen(10))\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n```\npython在声明的时候不需要额外标识。直接用`yield`就行了。\n两个语言都用了`yield`关键词工作原理也几乎相同甚至可以说Javascript就是抄的python。那为什么Javascript反而要多加一个星号呢这个星号有什么意义为什么要这样设计是Javascipt太特殊还是python太特殊\n我相信这应该是有原因的毕竟ES2015的制定过程相当和谐字面意义上的",
"answer": "ES 一直以来在坚持的一个原则便是完全避免 breaking changes毕竟用户的浏览器版本不是编程人员所能干涉的。如果用户的升级导致某些网站的旧代码失效了组委会肯定会被喷死。这点和其他语言很不一样。因此 Compatibility 是首要原因,新版 ES 必须完全兼容旧版 ES。\nReadability 和 Generality 其实都是产生的附加效果。Generality 其实是个伪需求,空 Generator 都可以被有 0 条或 1 条 yield 语句的 Generator 替代而且后者可读性比前者更好。Readability 这点 ES 的确实比 Python 的要优秀,至少只阅读函数头我便可以知道这是个 Generator 还是 Normal Function但优势只有在读长代码时才明显。仅凭这些不足以 diss Python 的设计。\n而至于 Python 当年为什么沿用了 `def`,其实没有过多什么“意义”,仅仅是出于 Guido 的直觉而已:-)。",
"type": "technical_qa"
},
{
"id": "segmentfault_164",
"question": "typescript 结合 vue 中 :! 是什么意思\n最近在学习结合typescript开发vue在github中看到这样地问题一直无法理解\n```\n private today!: {\n active: string[] | never[] | number[];\n finishedDate: string[] | never[];\n isReceived: boolean;\n };\n\n private title?: string;\n private num!: number;\n private isDone!: boolean;\n private isReceived!: boolean;\n```\n请指点迷津",
"answer": "分开看就好了\n`!`是和`?`相对的是typescript的语法表示强制解析也就是告诉typescript编译器我这里一定有值。你写`?`的时候再调用typescript会提示`可能为undefined`\n`:`是类型声明",
"type": "technical_qa"
},
{
"id": "segmentfault_165",
"question": "js 判断一个数是否为正整数?\nif ( ( ( number - 0 ) | 0 ) !== number - 0 ){ // 输入购买数量是否为正整数\n```\nnextBtn.disabled = true;\nnextBtn.innerHTML = '请输入正确的购买数量';\nreturn;\n```\n}\n书上看到这样的代码 ( number - 0 ) | 0 ) !== number - 0 \n负数 或 0 还不是负数吗?\n是不是写错了\n如果写错了 按这本书的写法可以怎么写呢?\n请大佬帮忙谢谢了",
"answer": "你这个判断的关键在那个按位或操作符上如果number是整数的话比如 10, 那么 `10 | 0 == 10`, 但是 如果是小数的话,或出来的结果也是整数 `10.1 | 0 == 10`。同时有number - 0 操作那么如果number == 'abc'这样的字符串 `number - 0 == NaN` 这时候再按位与为 `NaN | 0 == 0` 就避免了报错。\n回到你的条件如果number是整数那么条件不成立也就不用提示用户再输入正确的数量如果number是小数那么条件成立提示用户输入正确的数量。这个条件不会判断正负只关心是不是整数。如果number 是 '123'这样的字符串,条件不成立, 如果是 'abc' 这样的字符串,条件成立。\n结论 书上没写错。这个条件会在用户输入小数,非数字的字符串时成立。\n如果非要判断>0的话可以这样写\n```\nif ((( number - 0 ) | 0 ) !== (number - 0) && (( number - 0 ) | 0 ) <= 0)\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_166",
"question": "js switch奇怪的问题\n```\nvar result_time = 45852221;\nvar simple_text;\n\nswitch (result_time) {\n\n case result_time < 60:\n\n simple_text = '刚刚';\n\n break;\n\n\n case result_time > 60 && result_time < 3600 : //分钟前\n\n simple_text = Math.round(result_time/60)+'分钟前';\n\n\n break;\n\n\n case result_time > 3600 && result_time < 86400 : //小时前\n\n simple_text = Math.round(result_time/60/24)+'小时前';\n\n break;\n\n case result_time > 86400 && result_time < 2592000 : //天前\n\n simple_text = Math.round(result_time/60/60/24)+'天前';\n\n\n break;\n\n case result_time > 2592000 && result_time < 31104000 : //月前\n\n simple_text = Math.round(result_time/60/60/24/30)+'月前';\n\n\n break;\n\n\n case result_time > 31104000: //年前\n\n simple_text = Math.round(result_time/60/60/24/30/12)+'年前';\n\n\n break;\n}\ndocument.write(simple_text)\n```\n如上图所示这是一个简化时间的判断语句为什么它判断不出任何case",
"answer": "把`switch (result_time)`改为`switch (true)`就行\n`switch`的用法:\n```\nswitch (expression)\n case value:\n statement;\n break;\n case value:\n statement;\n break;\n```\n`expression`和`value`可以是值,也可以是表达式(表达式其实也是值,`1 < 2` 等价于 `true`)\n只要`expression`等于`value`就会执行相关语句\n比如:\n```\nswitch (1 < 2)\n{\n case true:\n console.log('true');\n break;\n case false :\n console.log('false');\n break;\n}\n```\n```\nswitch (true)\n{\n case 1 < 2:\n console.log('true');\n break;\n case 1 > 2 :\n console.log('false');\n break;\n}\n```\n上面两个代码其实是一样的",
"type": "technical_qa"
},
{
"id": "segmentfault_167",
"question": "Jsdoc 函数有解构参数时如何注释呢\n```\n/**\n * 这个函数用来示范一般函数参数注释方式!\n * @param {String} unit\n * @param {Number} item\n */\nfunction foo(name,age) {\n return {name, age}\n}\n\nfoo(\"Luke\",18)\n\n/**\n * 这个函数的注释写法是什么呢?\n * @param {String} ??? 此时应该如何注释呢\n * @param {Number} ??? 此时应该如何注释呢\n */\nfunction bar({name,age}) {\n return {name, age}\n}\n\nbar({\n age: 18\n name: \"Luke\"\n})\n```\n第二个函数这样写可以不用刻意安排参数的输入顺序但是如果我想用JsDoc注释时应该怎么写呢",
"answer": "```\n/**\n * @param {Object} option - foo\n * @param {String} option.name - bar\n * @param {Number} option.age - baz\n */\nfunction bar({name,age}) {\n return {name, age}\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_168",
"question": "js中forEach跳出循环问题\n去重的时候用for循环是没什么问题的\n```\nvar arr=[2,3,2,2,2,4,5],\n arr2=[];\n function find(arr2,ele){\n for(var i= 0,len=arr2.length;i<len;i++){\n if(arr2[i]==ele) return true;\n }\n return false;\n }\n\n for(var i= 0,len=arr.length;i<len;i++){\n if(!find(arr2,arr[i])){\n arr2.push(arr[i]);\n }\n }\n```\n改用forEach的时候\n```\n function find(arr2,ele){\n arr2.forEach(function(item,i){\n if(item==ele) return true;\n });\n return false;\n }\n\n arr.forEach(function(item,i,array){\n if(!find(arr2,arr[i])){\n arr2.push(arr[i]);\n }\n })\n```\n发现结果不对forEach貌似没有在return的时候跳出循环求教应该如何写呢。。。。",
"answer": "`forEach`函数不支持`break`,可以用`every`函数替代:\n```\nfunction find(arr2, ele) {\n arr2.every(function (item, i) {\n if (item === ele) {\n return false\n }\n return true\n })\n}\n```\n`return false`跳出循环,`return true`继续循环,详见 https://developer.mozilla.org...",
"type": "technical_qa"
},
{
"id": "segmentfault_169",
"question": "vscode怎么设置打开新文件的时候不关闭没有修改过的旧文件\n经常需要对比两个文件vscode自动给我关闭了这个有点蛋疼",
"answer": "// 控制是否将打开的编辑器显示为预览。预览编辑器将会重用至其被保留(例如,通过双击或编辑),且其字体样式将为斜体。\n```\n\"workbench.editor.enablePreview\": true,\n```\n这个设置改为false就好了",
"type": "technical_qa"
},
{
"id": "segmentfault_170",
"question": "Vue刷新当前路由有什么好的解决方式么\n```\nthis.$router.go(0);\nlocation.reload() \n//这两种方式都相当于f5刷新页面会有卡顿的情况\n```\n```\nthis.$router.push({ path: '/kong', query: {} });\n// 这种方式是进入一个空白页,在空白页里面跳转回原来的页面,这种方式页面刷新相对流畅,\n// 但是我发现,使用这种方式的话,在用户点击浏览器的后退键的时候,会再次进入/kong 这个空白页然后马上回来\n// 导致页面无法后退\n```\n请问有其他好的方式实现页面刷新吗",
"answer": "如果你希望能从`breforeCreate`开始重走整个生命周期的话\n其实在你的这个方法上略作修改就可以\n```\nthis.$router.push({ path: '/kong', query: {} });\n```\n把`push`换成`replace`\n同样的`kong`这个页面里`beforeRouteEnter`时也用`replace`\n就不会有那个后退的问题了\n附上我用的代码吧\n```\n// 使用页面\nrefresh () {\n this.$router.replace({\n path: '/refresh',\n query: {\n t: Date.now()\n }\n })\n}\n\n// refresh.vue\n<script>\nexport default {\n beforeRouteEnter(to, from, next) {\n next(vm => {\n vm.$router.replace(from.path)\n })\n }\n}\n</script>\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_171",
"question": "安装好php为什么要复制一份php.ini 到/usr/local/php/lib/php.ini\n安装好php为什么要复制一份php.ini 到/usr/local/php/lib/php.ini\n\n我试过了 如果不复制一份 php也能正常运行 为什么要从安装包里复制一份php.ini 到 /usr/local/php/lib/php.ini 目录下呢",
"answer": "对于您的问题,为什么要拷贝到那个目录,那时因为 PHP 编译时指定了配置文件目录,而指定的目录是 /usr/local/php/lib 因此 PHP 启动时会去那个目录下读取 php.ini 的配置文件,不拷贝不影响 PHP 正常运行,只不过无法添加配置项罢了。要查看当前 PHP 会去哪个目录下找配置文件,可以在 phpinfo() 中看到,(命令行下运行 php -i 也可以),看到 'Configuration File (php.ini) Path' 和 'Scan this dir for additional .ini files' 两项,这里面记录了 PHP 加载 .ini 配置文件的路径。\n建议下载一份 PHP 的 source code 自己尝试着去编译运行一遍。",
"type": "technical_qa"
},
{
"id": "segmentfault_172",
"question": "npm run dev和npm start的区别\n这是vue脚手架的官方Webpack模版请问一下其中的\"start\": \"npm run dev\"有什么意义\nnpm run dev和npm start的区别是什么呢\n为什么直接输入npm dev就不能执行scripts配置下的dev命令而npm start就可以呢\n```\n \"scripts\": {\n \"dev\": \"webpack-dev-server --inline --progress --config build/webpack.dev.conf.js\",\n \"start\": \"npm run dev\",\n \"lint\": \"eslint --ext .js,.vue src\",\n \"build\": \"node build/build.js\"\n },\n```",
"answer": "执行`scripts`里的命令要`npm run 命令名`。\n`npm start`可以运行是为了方便开发者使用npm-start。\n`npm start`会执行`scripts`里的`start`字段。 如果没有`start`字段则执行`node server.js`。",
"type": "technical_qa"
},
{
"id": "segmentfault_173",
"question": "try/catch无法捕获promise.reject的问题\n```\nfunction f2() {\n try {\n Promise.reject('出错了');\n } catch(e) {\n console.log(e)\n }\n}\n\n```\n- 执行`f2()`无法通过try/catch捕获promise.reject控制台抛出`Uncaught (in promise)`\n\n```\nasync function f() {\n try {\n await Promise.reject('出错了')\n } catch(e) {\n console.log(e)\n }\n}\n```\n- 为什么改成await/async后执行`f()`就能在catch中捕获到错误了并不会抛出`Uncaught (in promise)`",
"answer": "这样应该就理解了吧,拒绝发生在未来回调只会在未来的事件循环中执行。\n```\nfunction f2() {\n try {\n Promise.reject('出错了').catch(err => {\n console.log('2', err)\n });\n console.log('1')\n } catch (e) {\n console.log(e)\n }\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_174",
"question": "js数组中对象怎么合并\nvar list=[{id:1,number:2,title:2},{id:1,number:3,title:2}]\n如果数组中id和title的值相同,数组中两个对象合并,number值相加,怎么实现\n最终得到[{id:1,number:5,title:2}]",
"answer": "```\nvar list=[{id:1,number:2,title:2},{id:1,number:3,title:2}]\nfunction merge (list) {\n let result = []\n let cache = {}\n list.forEach(item => {\n let key = `id:${item.id},title${item.title`\n let index = cache[key]\n if (index !== undefined) {\n result[index].number += item.number\n } else {\n result.push(Object.assign({}, item))\n cache[key] = result.length - 1\n }\n })\n return result\n}\n\nmerge(list)\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_175",
"question": "rpc服务器是不是一般是服务器内部交互用的这样有什么好处\n最近在学习rpc框架因为我看有些rpc框架还没跨语言,序列化只有自己语言认识而那些语言我看很少在客户端开发用到我这里说的客户端指移动端浏览器这种。比如golang,python。 那意味着是不是rpc框架主要是用于服务器内网交互的一种架构 这样做有什么好处啊我看貌似好处就是分散流量压力啊因为用rpc做分布式计算工作还不全都交到那台server的服务器去做了吗\n我原来还以为rpc架构是客户端软件和服务器交互用的。。。",
"answer": "RPC从概念上讲不是一种协议也不属于通信的范畴\n而是一种编程技术一种代码封装方式目的是提高代码构建和维护效率。\nRPCRemote Procedure Call把进程间包括跨服务器的通信过程封装成函数调用方式隐藏复杂的通信处理细节方便使用、简化代码使得调用者可以像调用本地函数那样调用其他进程提供的处理过程。\n一旦我们把RPC理解为一种代码封装技术就很容易理解为啥看上去“内网用的多”“客户端用的少”。\n内网并不是关键。\n关键是RPC在简化代码的同时增加了耦合。\n如果我们定义两个实体之间通过HTTP通信或其他任何协议只要双方遵循HTTP协议就没有问题和双方的语言实现没有任何关系。\n而如果是RPC那么我们对外部呈现的是函数接口这就和语言以及平台相关需要给调用者提供函数声明文件和链接库。\n当我们的场景耦合成本比较高时例如我们构建的服务是提供给团队之外甚至是公司之外的用户使用用RPC就比直接用HTTP麻烦多了——\n我们需要提供各种版本以支持用户的各种平台和语言。\n即使采用支持多语言的RPC框架那么这个框架本质是一个代码库也要双方都引用和依赖这和直接采用协议比起来耦合要重的多。\n显然您所看到的“服务器内网交互用的多“并不是本质本质是\n同一个系统内部交互因为可以采用相同的基础平台或框架所以可以考虑使用RPC封装通信过程以提高代码构建和维护效率而恰恰系统内部交互大都是走内网。。。",
"type": "technical_qa"
},
{
"id": "segmentfault_176",
"question": "es6方法过滤掉两个数组中对象id值相等的项\n```\nconst arr1=[{id:1,name:'网'},{id:2,name:'二位'}]\nconst arr2=[{id:1,name:'老二'},{id:3,name:'老三'}]\n```\nes6方法过滤掉arr2中id和arr1 id相同的项",
"answer": "我自己来分享个\n```\n let arr1=[{id:1,name:'网'},{id:2,name:'二位'}]\n let arr2=[{id:1,name:'问问'},{id:3,name:'多少'},{id:44,name:'多少'},{id:45,name:'多少'},]\n\n let add=arr2.filter(item=>!arr1.some(ele=>ele.id===item.id))\n console.log(add)\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_177",
"question": "go, python做WEB哪个最合适?\n目前处于迷茫状态, 到底该专注一种语言还是同时使用多种语言?\n使用golang开发web连续一年了, 频繁的写err!=nil, 频繁的循环断言,reflect,unsafe....感觉大部分时间都在写轮子, 或者考虑轮子的性能. 开发效率来看,是PHP50%吧; 最大的问题的是代码不优雅, 别的语言1行代码, 我用轮子的情况下, 至少要多写两三行.\npython,只是看过手册, 很讨厌缩进; 但的确是理想语言, 动态类型更适合快速开发, 库多! 想深入学习, 但又怕go会慢慢淡忘. \n我最开始学c#, 后来用php, c#忘了. 再后来学go, php也几乎忘了. 更别提以前就没学好的C++, 现在连复杂的指针都看不懂了. 但js没忘, 因为几乎天天用啊.\n很纠结! 求老鸟指点.",
"answer": "我个人主要是PHP和Golang方向我谈谈个人的看法吧。\n对于开发项目语言技术栈方案的选择不能仅仅从开发语言本身来进行考虑还要考虑对应的生态环境包括软件生态、社区情况和人力资源。\n目前整个行业来看的话PHP拿来做页面级的开发非常适合也很高效也就是很多大型互联网公司所谓的“应用层”。Java通过几十年的发展它的生态环境已经非常繁荣这也是很多企业选择Java的原因并且也稳定。Golang相对来说比较新其实仅仅从开发语言上来讲的话它更加高级(这根设计思想有很大关系)也是Google踩了几十年的坑产出的结果之一它并不是为了替代谁而是给了大家更多的选择。",
"type": "technical_qa"
},
{
"id": "segmentfault_178",
"question": "vue递归组件如何传递事件给父组件\n如题根据数据遍历递归不明确具体会遍历几次形式大概如下\n```\n<parent>\n <children>\n <children>\n <children>\n ...\n </children>\n </children>\n </children>\n</parent>\n\n```\n我现在要在最后一层children传出数据到parent接收但是emit只能向上传递一层有什么好的解决方案吗除了用vuex我没好的想法了",
"answer": "用eventBus 策略。\n定义\n```\n// bus.js\nimport Vue from 'vue'\nexport default new Vue()\n```\n使用\nparent\n```\n// parent.vue\nimport bus from './bus'\n\nexport default {\n mounted(){\n bus.$on('post-message',(msg)=>{\n console.log(msg)\n })\n }\n}\n```\nchildren\n```\n// children.vue\nimport bus from './bus'\n\nexport default {\n mounted(){\n bus.$emit('post-message','发送')\n }\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_179",
"question": "为什么JS用分号结尾和没用分号结尾执行的结果不一致\n代码1\nvar a = 'Aaa';\nvar b = 'Bbb';\n[a, b] = [b, a];\nconsole.log(a);\nconsole.log(b);\n结果\nBbb\nAaa\n代码2\nvar a = 'Aaa'\nvar b = 'Bbb'\n[a, b] = [b, a]\nconsole.log(a);\nconsole.log(b);\n结果\nAaa\n[ undefined, 'Aaa' ]\n如果说JS并不强行要求每行语句末尾必须要用分号结尾的话上面两段代码按道理来说结果不是应该一致的吗\n测试环境node v6.10.2",
"answer": "不强行要求分号不代表不写分号是正确的。解释器会自动加分号,不保证完全能按你的意思加分号也许就加错分号了,结果就错了。变成了\n```\nvar a = 'Aaa';\nvar b = 'Bbb'[a, b] = [b, a];\nconsole.log(a);\nconsole.log(b);\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_180",
"question": "PHP怎么实现数组键名不变值互换\n```\n$arr = array('a'=>'aaa','b'=>'bbb');\n转变为\n$arr = array('a'=>'bbb','b'=>'aaa');\n```",
"answer": "```\n$arr = array('a'=>'aaa','b'=>'bbb');\n$arr_new = array_combine(array_keys($arr),array_reverse(array_values($arr)));\nvar_dump($arr_new);\n```\n=============\n哎迟了一步@熊猫桑 握爪",
"type": "technical_qa"
},
{
"id": "segmentfault_181",
"question": "vim怎么粘贴其他地方复制的代码\n我在网页上复制了一段代码想粘贴到vim中。\n第一次粘贴的时候总会丢失复制内容的起始几个字符紧接着第二次粘贴则正常是什么原因\n下面是`<title>Hello, world!</title>`为粘贴内容的测试结果,共粘贴两次,可以看到,第一次(前面两行)很奇怪,第二次(第三行)正常。\n```\n 1\n 2 , world!</title>\n 3 <title>Hello, world!</title>\n```\n左侧的1 2 3为行号",
"answer": "简单原因: 你没有进入编辑模式就试图编辑文件, 所以产生了你意想不到的结果.\n具体原因:\n1. 你打开了 vim, 此时 vim 处于 `正常模式`.\n2. 你粘贴了 `<title>Hello, world!</title>`, 相当于向 vim 申请执行 该指令, vim 会顺次执行. 在正常模式下, `<` 和 `>` 表示缩进, 但因为你没有选中文本, 因此什么也没有发生, 两个中括号中间的 `title` 是无效的. `Hell` 也不会有具体效果. 但执行到 `o` 时, `o` 表示在光标所在行的下一行进入 `插入模式`, 剩下的内容被当做 插入文本处理. 因此你文件中的第一行是空白行, 第二行是 `o` 后面的内容, 即 `, world!</title>`\n\n3. 因为上面的操作已经使 vim 进入 `插入模式`, 且你并未点击 `ESC` 退出该模式, 因此在你继续进行第二次粘贴的时候, 就会直接执行插入操作, 这行被完整的插入进去了。\n\n疑问:\n如果两次粘贴中间没有其他操作, 那么第二次粘贴时不应该会另起一行. 我猜测你应该敲了一个回车符后进行的粘贴.\n建议:\n了解下 vi 操作基础.",
"type": "technical_qa"
},
{
"id": "segmentfault_182",
"question": "关于前后端分离数据接口的问题?\n公司有一个小项目自己采用了前后端分离的方式就是我在js中采用ajax请求后端提供的数据接口主要是一些文字内容。有的同事对这种做法提出了自己的疑问就是数据接口都是写在js中的那么上线后就有可能被其他人通过查看js的数据接口地址恶意破坏比如多次循环访问这个接口造成服务器负荷比较大。\n疑问前后端分离会造成诸如以上的安全问题吗如何有效避免呢",
"answer": "你那个同事水平有限,不要跟他做朋友。\najax请求也可以加各种权限校验啊。如果能破解了校验那就算通过页面返回数据不是一样能模拟发页面请求么\n再说多次调接口对服务器有压力那多次请求页面不也有压力么",
"type": "technical_qa"
},
{
"id": "segmentfault_183",
"question": "前端进行兼容性测试的标准流程是什么?\n现在业界是怎么进行兼容性测试的不仅包括IE低版本还有Chrome、Firefox等的低版本还是说现在默认不测现代浏览器低版本的兼容性了那这个低版本有没有一个具体的分界点",
"answer": "看项目需求吧,一般看项目的兼容性需求;\n- 一般来说PC端兼容性测试指IE的兼容性Chrome、Firefox的兼容性一般来说很少人测基本上IE的兼容性测试通过了就OK\n- IE兼容性又大概分两个阶段IE10和IE8目前一般甚少需要兼容到IE8或以下的了除非是政府项目有些还需要兼容到IE6所以如果项目不特别说明兼容性一般兼容到IE10就可以了。\n- 兼容性测试没有什么标准流程一般来说都是测试人员手动测试的听说目前有云测不过了解了下基本是针对APP的\n- 至于测试平台,可以安装浏览器插件进行基本测试,不过兼容性没有真机测试准确,会有偏差;严格点的测试应该在真机或者虚拟机上测试。",
"type": "technical_qa"
},
{
"id": "segmentfault_184",
"question": "为什么Webpack生成JavaScript代码要引入eval模式\n最近在看Webpack的生成的JavaScript有一个疑问想不明白为什么Webpack要提供`eval`的模式将模块的generated code用`eval`来包裹?\n这里的讨论不仅限于`devtool`是`eval`,还包括`eval-source-map`, `cheap-eval-source-map`等各种包含了`eval`的衍生组合。如果说`eval`的好处是build速度快因为它不生成source map那类似于`eval-source-map`这样的呢?\n所以我的疑问并不在于source map而是`eval`本身。既然它如此被诟病为什么Webpack还是要引入这样一种代码生成机制它究竟有什么好处",
"answer": "goto也被诟病但你仍然可以在C/C++中使用goto。\n真正被诟病的不是eval而且eval的滥用。如果你确认拿到的代码是你自己的或任何你信任的用eval是完全可以接受的而且可以享受到速度快的好处。",
"type": "technical_qa"
},
{
"id": "segmentfault_185",
"question": "css如何让某个元素不继承父元素的宽度而让子元素撑开他\n这里这个例子\nhttps://jsfiddle.net/93bh7vpz/\n如何让inner这一层和里面所有层的宽度都等于最最最里面的",
"answer": "html元素宽度不具有继承特性块级元素(block)的宽度会占据一整行,所以看似继承了,实则不是。\n让一个元素的宽度根据内容撑开只要设置其display不为块级元素不设置宽度就可以了\n比如float,inline,position为absolute,fixed等等等等(真的很多,不是块元素,不要设置宽度)",
"type": "technical_qa"
},
{
"id": "segmentfault_186",
"question": "Js怎么做这题目\n4444\n 333\n 22\n 1\n 22\n 333\n4444\n用JS怎么做。我只会做1以上那半求大神\n4444\n 333\n 22\n 1\n 22\n 333\n4444\n我只会做1上面那半",
"answer": "```\nfunction f(n) {\n for (let i = -n; i <= n; i++) {\n if (i === 0 || i === 1) {\n continue\n }\n let k = Math.abs(i)\n console.log(k.toString().repeat(k))\n }\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_187",
"question": "将一个对象填入window.localStorage后访问不到其中的属性\n```\nwindow.localStorage.setItem('obj', {name: 'hhh', age: 100});\n\n\n```\nlocalStorage.obj 是存在的,但 localStorage.obj.name 是undefined.\n请问如何访问到name的value",
"answer": "`localStorage注意事项`\n一般我们会将JSON存入localStorage中但是在localStorage会自动将localStorage转换成为字符串形式\n这个时候我们可以使用JSON.stringify()这个方法来将JSON转换成为JSON字符串\n示例\n```\nif(!window.localStorage){\n alert(\"浏览器不支持localstorage\");\n}else{\n var storage=window.localStorage;\n var data={\n name:'luozz',\n sex:'man',\n hobby:'program'\n };\n var d=JSON.stringify(data);\n storage.setItem(\"data\",d);\n console.log(storage.data);\n}\n \n```\n读取之后要将JSON字符串转换成为JSON对象使用JSON.parse()方法\n```\nvar storage=window.localStorage;\nvar data={\n name:'luozz',\n sex:'man',\n hobby:'program'\n};\nvar d=JSON.stringify(data);\nstorage.setItem(\"data\",d);\n//将JSON字符串转换成为JSON对象输出\nvar json=storage.getItem(\"data\");\nvar jsonObj=JSON.parse(json);\nconsole.log(typeof jsonObj);\n```\n另外还有一点要注意的是其他类型读取出来也要进行转换",
"type": "technical_qa"
},
{
"id": "segmentfault_188",
"question": "如何在学习在工作中用不到的技术?\n在工作中一些技术并没有实践机会比如一些公司项目并没有用到vue、webpack等等在这种情况下如何去学习用不上的技术",
"answer": "这个问题我应该很有发言权\n1 首先找个早八晚五的公司不要相信996能提高技术提高的只是1+1=2这种问题的熟练度而且你回家以后很累并不能坚持学习\n2 满足1的前提下学自己想学的知识。强迫自己回家之后写代码不需要太多一百多行就行",
"type": "technical_qa"
},
{
"id": "segmentfault_189",
"question": "前后端分离koa2的作用是什么\n如前后端分离项目 vue + axios + koa2 + javaspringboot 使用restful风格api\n问题\n1. koa2到底扮演什么角色具体点就是什么代码应该写在koa2中呢\n2. vue+koa2 前端组合下路由应该写在哪里呢vue-router koa koa-router如果vue和koa2中写两次路由意义在哪里\n3. 有人说的一个场景后台一般不会把数据根据前端展示字段包装而是一坨扔过来然后用koa2进行拆解整合在给vue显示这算koa2存在的一个理由么\n4. 用 vue-cli 生成一个项目, 其实就都可以实现前端要求了包括node服务器、webpack等那么极端点说在加上axios就都可以啦koa2没用啊......",
"answer": "1.你用vue-cli生成的项目里的koa只是在开发环境里有用模拟server在生产环境里是不需要koa的\n2.一般的前后端分离的项目也很少需要在前端后后端java之间加一层node也就是koa除非是像淘宝这种需要首屏优化或者有强烈的seo需求的需要浏览器请求到的就是可以直接展示的静态页面的或者是后端java提供的api不能直接给前端展示的需要经过转换的才会需要node中间层\n3.vue-router是前端路由是在浏览器里执行的url改变切换不同的页面而 koa-router主要是针对服务端的对于api的路由",
"type": "technical_qa"
},
{
"id": "segmentfault_190",
"question": "webpack4不再支持extract-text-webpack-plugin\n今天体验了一下webpack4.1.0,发现不再支持 extract-text-webpack-plugin。\n那应该用什么方法去单独提取css文件呢\n还有一个问题是我在看别人用webpack打包的一个开源项目的时候发现它的html中是这样引入css的\n```\n<link type=\"text/css\" rel=\"stylesheet\" href=\"blob:null/e83446f1-423b-40a8-a91a-d885bde94722\">\n```\n那个 href 中的内容是什么意思啊,是用什么插件完成的?\n而且我在文件内也没找到它生成的css文件只有源码中的scss文件。\n实在的搜索不到答案。请大神指教一下先谢过了。",
"answer": "原因:`extract-text-webpack-plugin` 最新版本为 `3.0.2`,这个版本还没有适应 `webpack 4` 的版本\n解决办法使用 `4.0 beta` 版,`npm install --save-dev extract-text-webpack-plugin@next`",
"type": "technical_qa"
},
{
"id": "segmentfault_191",
"question": "关于token不理解的地方\n目前在写api接口是为移动端提供的接口那么我们为用户设定了用户名密码的同时为何还要加一个token而且文档还说以token的方式来验证那每次直接确认用户的密码不行吗这个token作用是啥百度说的不清楚啊",
"answer": "例如:\n云冲印应用要访问你的百度网盘读取网盘图片然后打印给你。但是它需要你的账号和密码才能登录访问你的网盘。你会放心把账号密码给它用吗但是你可以授权网盘给云冲印一个令牌这个令牌有效期10天。云冲印有了这个token就相当于有了你的账号和密码。就可以拿着token去访问你的网盘数据了。这样你的密码不会泄露。你可以随时取消这个授权这样可以禁止别人去读取你的数据。如果你给了账号和密码那么以后想取消授权就只能改密码了。\n用户密码存储在本地是不安全了别人有机会可以看到你的明文密码。API是无状态的难道每次请求都要把用户名和密码带上吗这样会不安全。\n本质上 token = 用户名 + 密码",
"type": "technical_qa"
},
{
"id": "segmentfault_192",
"question": "node中跨域代理 proxyTable的原理是什么\n1.node中跨域代理 proxyTable的原理是什么\n2.我在浏览器和服务端都没有设置CORS的情况下只要设置proxytable就可以跨域了这样是不是就违背了同源策略的初衷\nps: 希望见到比较有水准的解释",
"answer": "跨域是浏览器禁止的,服务端并不禁止跨域 \n所以浏览器可以发给自己的服务端然后由自己的服务端再转发给要跨域的服务端做一层代理\n`vue-cli`的`proxyTable`用的是`http-proxy-middleware`中间件\n`create-react-app`用的是`webpack-dev-server`内部也是用的`http-proxy-middleware`\n`http-proxy-middleware`内部用的`http-proxy`",
"type": "technical_qa"
},
{
"id": "segmentfault_193",
"question": "关于promise中reject和catch的问题\nreject和catch是否都会执行或者只执行其中一个分别在什么情况下执行",
"answer": "### 一、reject后的东西一定会进入then中的第二个回调如果then中没有写第二个回调则进入catch\n```\n\n var p1=new Promise((resolve,rej) => {\n console.log('没有resolve')\n //throw new Error('手动返回错误')\n rej('失败了')\n\n })\n\n p1.then(data =>{\n console.log('data::',data);\n },err=> {\n console.log('err::',err)\n }).catch(\n res => {\n console.log('catch data::', res)\n })\n\n VM367054:2 没有resolve\n VM367054:11 err:: 失败了\n\n```\n- then中没有第二个回调的情况\n\n```\n\n var p1=new Promise((resolve,rej) => {\n console.log('没有resolve')\n //throw new Error('手动返回错误')\n rej('失败了')\n\n })\n\n p1.then(data =>{\n console.log('data::',data);\n }).catch(\n res => {\n console.log('catch data::', res)\n })\n\n VM367054:2 没有resolve\n VM367054:11 catch data:: 失败了\n\n```\n- 如果没有then 也可以直接进入catch\n\n```\n var p1=new Promise((resolve,rej) => {\n console.log('没有 resolve')\n //throw new Error('手动返回错误')\n rej('失败了')\n\n })\n\n p1.catch(\n res => {\n console.log('catch data::', res)\n })\nVM367087:2 没有resolve\nVM367087:9 catch data:: 失败了\n\n```\n### 二、resolve的东西一定会进入then的第一个回调肯定不会进入catch\n```\n var p1=new Promise((resolve,rej) => {\n console.log('resolve')\n //throw new Error('手动返回错误')\n resolve('成功了')\n\n })\n\n p1.then(data =>{\n console.log('data::',data);\n }).catch(\n res => {\n console.log('catch data::', res)\n })\nVM367087:2 resolve\nVM367087:9 data:: 成功了\n\n```\n- 不会进入catch的情况\n\n```\n var p1=new Promise((resolve,rej) => {\n console.log('resolve')\n //throw new Error('手动返回错误')\n resolve('成功了')\n\n })\n\n p1.catch(\n res => {\n console.log('catch data::', res)\n })\nVM367087:2 resolve\n\n```\n throw new Error 的情况和rej一样但是他俩只会有一个发生 \n 另外网络异常比如断网会直接进入catch而不会进入then的第二个回调 ",
"type": "technical_qa"
},
{
"id": "segmentfault_194",
"question": "Js在数组中添加元素\n如何提取数组中的字段然后添加新的字段获取数据如下\n```\nvar data = [\n{\"id\":\"1\",\"name\":\"华为\",\"data\":\"25u6s8f545d3\"},\n{\"id\":\"2\",\"name\":\"小米\",\"data\":\"cd58de9d3c5d\"},\n];\n```\n我想获得的数据格式如下\n```\nvar data = [\n{\"id\":\"1\",\"name\":\"华为\",\"data\":\"25u6s8f545d3\",\"mac\":\"25:u6:s8:f5:45:d3\"},\n{\"id\":\"2\",\"name\":\"小米\",\"data\":\"cd58de9d3c5d\",\"mac\":\"cd:58:de:9d:3c:5d\"},\n];\n```\n我现在方法如下\n```\nfor (var i = 0; i < data.length; i++) {\n var mac = data[i].data.toUpperCase();\n mac1 = mac.substring(0, 2);\n mac2 = mac.substring(2, 4);\n mac3 = mac.substring(4, 6);\n mac4 = mac.substring(6, 8);\n mac5 = mac.substring(8, 10);\n mac6 = mac.substring(10, 12);\n var mac = mac1 + ':' + mac2 + ':' + mac3 + ':' + mac4 + ':' + mac5 + ':' + mac6;\n data[i].mac = mac;\n };\n```\n请教下有没有更好的方法我觉得自己方法有点烂。",
"answer": "```\nvar data = [\n { \"id\": \"1\", \"name\": \"华为\", \"data\": \"25u6s8f545d3\" },\n { \"id\": \"2\", \"name\": \"小米\", \"data\": \"cd58de9d3c5d\" },\n];\ndata.forEach(item => {\n item.mac = item.data.replace(/\\w{2}\\B/g, '$&:')\n})\nconsole.log(data)\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_195",
"question": "web框架中的controller、service层、dao层、logic层的联系与作用啊\n### 一直不太理解controller、service层、dao层、logic层这几个概念以及具体如何用、为何这样用",
"answer": "说下个人目前在用的分布\nController:接受Web请求,分发调用不同的逻辑或服务完成一项事情,返回数据\n service:做些服务Api接口相关的代码\n dao:和数据库打交道(对表进行增删改查)\n logic:自己的业务逻辑相关\n```\n现在有个PC注册账号的功能\n 1:初始阶段,controller收到请求,直接在controler里面写数据库连接进行增删改查,没毛病,可以运行。\n 2:慢慢发展,功能多了Controller多起来了contoller到处都是sql和数据库打交道的代码,虽然不影响运行,但是有时候发现,如果我要修改一个数据表的字段或其他东西,得到好几个Controller里面去找相同的一个代码并修改,太麻烦了,干脆都放到一个里面,全部对增删改查从同一个地方多好,这时候出现了dao层。\n 3:继续发展,进军移动端,有了手机注册的功能,简单,写呗,写着写着发现,我去怎么和PC注册功能这么像都要校验用户信息->判断数据库有无重复->插入数据库(重复的业务功能在几个控制器都要被重复使用),有了第二步的经验,把这些相同的业务操作抽离放到一起呗出现了logic层(logic层负责做些处理并调用dao层完成数据的入库等和数据库打交道的事情),RegisterLogic规定所有的注册功能都走这一个逻辑了,维护更加方便了,以后即使增加一百种注册方式,只要 new RegisterLogic()->register();就行了。\n 4:继续发展下去,公司有声有色的,老板说,网站太无聊了,加点天气预报,随机推送笑话的附属功能吧,这行功能不属于自己的系统的业务逻辑,更具第二步和第三步的经验,应该单独放一个地方,没准以后其他的地方会用到,这时候service层就出现了。\n \n```",
"type": "technical_qa"
},
{
"id": "segmentfault_196",
"question": "jwt前端加密后端解密\n最近在学习jwt但是遇到一个问题。\n用户输入用户名和密码之后发送给服务器服务器将其加密后返回token每次前端请求都带上这个token。\n于是我产生一个问题用户输入账号和密码如果这个请求被拦截了就能拿到了账号密码但是有一种叫openssl的东西就是要求域名用https。但是这种方式也不是十分安全。\n既然jwt有JavaScript版那为啥不在前端就加密了之后后端解密去验证呢\n问题jwt前端加密账号密码后端解密如何实现\n现在做的项目也有token的做法实现方式\n1.页面加载前端发送一个16位后端就会返回一个publick_key。\n2.前端收到这个public_key将用户名密码还有一个16位的随机数用md5加密。\n3.登陆的时候将上面的加密发送给后端后端使用private_key解密后得到加密的数据。\n我想上面的实现方式就跟jwt类似。",
"answer": "先不管JWT和SESSION机制我来讨论下网络安全问题可能说的不对欢迎指正。\n假定现在你的电脑不安全电脑中被安装了木马监听同时网关里有也中间人\n1. 无论你的网页中是否加密,你在键盘中输入的任何数据都会被木马监听到,这是操作系统层的监听;\n2. 你在网页中键入的请求以及接收到的响应,通过网关都会被中间人拦截,这是路由层的监听;\n\n所以加密密码必须采用哈希算法而不是对称加密不然中间人既然可以拦截所有的请求和响应而js又是明文你如何保证对称加密的秘钥不被中间人看到呢\n> 你可能会问加密的密码也会被看到,中间人也可以绕开网页,直接发包模拟请求。是的,确实如此;加密密码解决的是不让你的密码被明文泄露,这样中间人无法用你的账户密码去其他应用中撞库。\n\n但是传输的主体内容是不能采用哈希算法因为双方必须知道具体的内容这导致了中间人会看到明文的内容(简单的JS对称加密是无用的因为HTML是明文的中间人也可以看到对称加密的秘钥)\nHTTPS解决的就是对称加密的问题将证书提前准备好并通过浏览器预先安装的根证书来避免中间人伪造证书这从根本上解决对称加密的秘钥问题。\n而JWT我觉得从根本上并不是为了解决网页安全问题而是想通过一种分布式无状态的方式来解决服务端的SESSION问题。",
"type": "technical_qa"
},
{
"id": "segmentfault_197",
"question": "mongoose 的Virtual是什么\nVirtual properties are document properties that you can get and set but that do not get persisted to MongoDB. \n这句话看不是很懂。请不要翻译希望能用自己的话解释有例子更好。谢谢",
"answer": "大致意思就是你可以用mongoose添加和设置虚拟属性但是这虚拟属性的值不会保存到数据库中。\n比如前台传到后台一个参数name代表用户的名称但是数据库保存的是两个字段姓和名这就可以用虚拟属性\n```\n// 数据库中缓存的格式\nvar schema = new Schema({\n name: {\n first: { 'type': String }, \n last: { 'type': String },\n }\n});\n\n// 当获取该 schema 的fullname属性时,将 schema 中的 name.first 和 name.last 拼接起来返回\nvar virtual = schema.virtual('fullname');\nvirtual.get(function () {\n return this.name.first + ' ' + this.name.last;\n});\n// 当设置该schema的 fullname 属性时,将设置的字以空格分开,分别赋值给 schema 中的 name.first 和 name.last 属性\nvar virtual = schema.virtual('fullname');\nvirtual.set(function (v) {\n var parts = v.split(' ');\n this.name.first = parts[0];\n this.name.last = parts[1];\n});\n\n// 将该 schema 保存到数据库中时,只会保存 name.first 和 name.last\n// fullname属性的值不会保存到数据库中,这就是virtual\n\n```\nhttp://mongoosejs.com/docs/ap...\nset 中的 function 的参数 v,是设置虚拟属性时的值.不保存到数据库中,但是它也是有存在的意义的,比如,就像例子中的,在用户看来,它只有一个名字,但是在数据库中,是要保存姓和名,因为分为姓和名,我们后续可以对用户做统计,姓张的多少人.(这也只是举个例子).\n再比如,订单的状态,数据库中保存的是0,1,2,3,4,5,6,7.但是在页面上,显示的是未支付,已付款,待发货,已发货,待收货,已完成,待评价等.我们就可以设置一个虚拟属性\n```\nvar virtual = schema.virtual('statusName');\nvirtual.get(function () {\n switch(this.status){\n case 0: return '待发货';\n case 1: return '待收获';\n case 2: return '已完成';\n default: return '待支付';\n }\n return this.name.first + ' ' + this.name.last;\n});\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_198",
"question": "angular4项目中使用ng server启动 别人在局域网里访问无效\nangular4项目中使用ng server启动后本地用localhost:4200可以打开在局域网里别人用我的局域网地址无法访问我的项目",
"answer": "运行ng serve --host xxx.xxx.x.xxx自己的ip地址,然后别就可以通过你的ip地址访问了。\n好像在项目里面也可以配置的配置了的话可以直接运行ng serve就行具体怎么弄我也忘了",
"type": "technical_qa"
},
{
"id": "segmentfault_199",
"question": "CSS3 Transform 引起的 z-index \"失效\"\n两个页面使用的css3 Transform动画之后页面下子元素的z-index就失效了就算设置的再大的值也不会起作用但是一个页面的时候是没有问题的",
"answer": "这里涉及到一个`stacking context`(有人翻译为`层叠上下文`)的概念。\n给元素设置`transform`属性会创建一个新的`stacking context`。\n请看下面的具体讲解\n注以下两个例子最好先想象一下预览效果再查看结果预览页面。\n先上一个小例子你可以在https://jsfiddle.net/运行):\n```html\n'<div class=\"test test-1\">\n</div>\n<div class=\"test test-2\">\n</div>\n```\n```css\n.test {\n width: 100px;\n height: 100px;\n}\n\n.test-1 {\n -webkit-transform: scale(.9);\n transform: scale(.9);\n /*opacity: 0.9*/\n background: #f20;\n}\n\n.test-2 {\n margin-top: -50px;\n background: #000;\n}\n```\n上面这个例子中两个div都没有设置任何`position`,如果没有给`test-1`添加`transform`属性的话第二个div将会覆盖第一个div。但是如果设置了`transform`的话呢?由于`transform`会创建一个新的`stacking context`。在层级关系上就要比`test-2`高一级,因此,显示在上面。\n再来一个例子\n```html\n'<div class=\"test test-1\">\n</div>\n<div class=\"test test-2\">\n</div>\n```\n```css\n.test {\n width: 100px;\n height: 100px;\n}\n\n.test-1 {\n position: relative;\n background: #f20;\n}\n\n.test-2 {\n -webkit-transform: scale(.9);\n transform: scale(.9);\n margin-top: -50px;\n background: #000;\n}\n```\n这个例子了是对上面那个例子作了个简单的修改。我们给`test-1`添加了一个`position: relative``test-2`没有任何`position`属性,只是添加了一个`transform`的属性。如果不看预览页面的话,可能会以为`test-1`会显示在`test-2`上方,其实不然。由于`transform`会创建新的`stacking context`,同时`test-2`在文档中又处于`test-1`的后面,所以最终的效果是`test-2`显示在`test-1`的上方。\n那么问题来了哪些情况下会创建新的`stacking context`呢?\nMDN上有相关的介绍\n- the root element (HTML),\n- positioned (absolutely or relatively) with a z-index value other than \"auto\",\n- a flex item with a z-index value other than \"auto\",\n- elements with an opacity value less than 1,\n- elements with a transform value other than \"none\",\n- elements with a mix-blend-mode value other than \"normal\",\n- elements with isolation set to \"isolate\", on mobile WebKit and Chrome 22+, position: fixed always creates a new stacking context, even when z-index is \"auto\",\n- specifing any attribute above in will-change even you don't write themselves directly\n\n其中第二条是我们平时最常见的另外几条加粗的会随着CSS3的普及越来越常见。令我感到惊奇是`opacity`竟然也会创建新的`stacking context`,你可以试着将上面两个例子中的`transform`换成`opacity`,会得到同样的效果。\n值得注意的是介绍`stacking context`的文章显然不像介绍CSS中另外一个“上下文”——`Block formatting context`(块级格式上下文)的文章多,原因可能是,我们在平常很少遇到`stacking context`相关的问题但是随着CSS3的普及这方面的问题可能会多起来的。\n这也算是CSS中一个比较有趣而且有用的知识点之前在工作中遇到过一次正好此处有人问到特整理了一下供参考。\n### 补充\n说了这么多回到你这个具体的问题上来由于你没有提供具体的代码不好说出具体的问题所在但可以推测出你的代码中可能有类似下面这个例子中的结构。你给`.child`设置再大的`z-index`都没有用。但是如果将`.inner`的`transform`去掉就不一样了。试试看。\n```html\n<div class=\"test test-1\">\n <div class=\"inner\">\n <div class=\"child\">\n Child\n </div>\n </div>\n</div>\n<div class=\"test test-2\">\n</div>\n```\n```css\n.test {\n width: 100px;\n height: 100px;\n}\n\n.test-1 {\n position: relative;\n background: #f20;\n}\n\n.inner {\n width: 80px;\n height: 80px;\n transform: scale(1); /*此处会产生新的stacking context*/\n background: green;\n}\n\n.child {\n position: absolute;\n bottom: 15px;\n color: #fff;\n font-size: 30px;\n z-index: 1000;\n}\n\n.test-2 {\n position: relative;\n margin-top: -50px;\n background: #000;\n}\n```\n### 参考链接\n- [The stacking context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context)",
"type": "technical_qa"
},
{
"id": "segmentfault_200",
"question": "前端面试时被问到JS异步执行的问题有A、B、C三个任务要求A和B异步执行二者都完成后执行C\n前端面试时被问到JS异步执行的问题有A、B、C三个任务要求A和B异步执行二者都完成后执行C",
"answer": "方案一,`Promise.all`形式:\n```\nvar promise1 = new Promise((resolve, reject) => {\n setTimeout(() => {\n console.log(1);\n resolve()\n }, 0);\n \n});\nvar promise2 = new Promise((resolve, reject) => {\n setTimeout(() => {\n console.log(2);\n resolve()\n }, 0);\n});\nPromise.all([promise1, promise2]).then(function(res) {\n console.log(3)\n});\n```\n方案二`callback`形式:\n```\nvar index = 0\n\nfunction C(){\n console.log(3);\n}\n\nsetTimeout(() => {\n console.log(1);\n index++;\n if(index === 2){\n C()\n }\n}, 0);\n\nsetTimeout(() => {\n console.log(2);\n index++;\n if(index === 2){\n C()\n }\n}, 0);\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_201",
"question": "数组中对象去重的方法\n如下一个数组怎么去除其中的重复对象求大神给个方法谢谢啊\n```\narr = [\n{orgId:\"100\",orgName:\"信息组\"},\n{orgId:\"100\",orgName:\"信息组\"},\n{orgId:\"100\",orgName:\"信息组\"},\n{orgId:\"81\",orgName:\"安全组\"},\n{orgId:\"11\",orgName:\"秘书组\"},\n{orgId:\"81\",orgName:\"安全组\"}\n]\n```",
"answer": "```\nvar arr = [\n { orgId: '100', orgName: '信息组' },\n { orgId: '100', orgName: '信息组' },\n { orgId: '100', orgName: '信息组' },\n { orgId: '81', orgName: '安全组' },\n { orgId: '11', orgName: '秘书组' },\n { orgId: '81', orgName: '安全组' },\n];\n\nObject.values(\n arr.reduce((obj, next) => {\n var key = JSON.stringify(next);\n return (obj[key] = next), obj;\n }, {}),\n);\n\n```\n我来个最简单的but 有个缺点arr里面的对象必须能被 JSON.stringify 处理",
"type": "technical_qa"
},
{
"id": "segmentfault_202",
"question": "python二维列表每个子列表元素个数不同取一个元素进行组合列出所有可能的情况\n比如已知二维列表[[a,b,c],[d,e],[f]],要求从每个子列表中选出一个元素进行相加列出所有的组合情况本题输出为adf,aef,bdf,bef,cdf,cef这6种可能。有很多这样的列表子列表个数不一定相同请教怎么用python进行处理",
"answer": "```\n>>> import itertools\n>>> s = [['a','b','c'],['d','e'],['f']]\n>>> [''.join(i) for i in itertools.product(*s)]\n['adf', 'aef', 'bdf', 'bef', 'cdf', 'cef']\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_203",
"question": "看一个题谁能帮忙解释一下这是一个关于reduce递归\n看以下题目\n```\nvar f = (function() {\n let r = 1;\n return function(...args){\n r *= args.reduce((p, n) => p + n);\n f.valueOf = () => r; // 主要是这句代码完全懵B\n return f;\n }\n}());\n+f(1,2,3)(2,3)(3,4,5)(6,7)\n// 输出值为(1+2+3)*(2+3)*(3+4+5)*(6+7)的计算结果\n```\n考虑到用到的知识点\n\n1. reduce\n2. valueOf\n3. 递归\n4. ...(涉及的没提到的)",
"answer": "1 `reduce` 配合 `args` 解构用来求每一个圆括号里面的和\n```\nconst sum = (...args) => args.reduce((i, j) => i + j)\n```\n2 每次圆括号执行`f`都会再返回这个`f`,保证了这个`f`后面可以跟上无限多个圆括号\n```\nvar j = (function() {\n return function () {\n console.log('yo')\n return j\n }\n}())\n\nj()()()() // yo yo yo yo\n```\n3 立即执行函数保证了每有一个圆括号都立即、顺序执行\n```\nvar f = function() {\n let r = 1\n return function f(...args){\n r *= args.reduce((p, n) => p + n)\n console.log(args) // 第一个圆括号就不执行了\n f.valueOf = () => r\n return f\n }\n}\n```\n4 如果你只想得到返回的 `f` 函数,或者是只想让这个 `r` 存在于各个层级 `f` 的上下文中的话,`valueOf` 都没有出现的意义,但是如果你想从 `f()()()` 中把 `r` 取出来,就需要 `valueOf` 了。最后的加号会用到他,这里就返回当前上下文中的 `r`。\n```\nvar f = (function() {\n let r = 1\n return function f(...args){\n r *= args.reduce((p, n) => p + n)\n if (args.length == 2) return r // 如果你能找另外一个方式把 r 输出也是可以的\n return f\n }\n}())\nconsole.log(f(1,2,3)(2,3,5)(3,4,5)(6,7))\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_204",
"question": "下载了别人的github上的代码然后创建自己的分支如何把自己的代码贡献给他",
"answer": "1. 在对方仓库的首页上点 fork分叉一份到自己名下\n2. 创建分支,分支名尽量清晰,尊重对方的规范,比如 `bugfix-some-thing-should-be-right`\n\n3. 开发,测试,编写测试用例,写清楚文档\n4. 推到自己的仓库\n5. 在这个分支上会看到一个“Create Pull Request”的按钮按下创建 PR\n6. 对方会审查你的 PR如果的确有用他就会合并\n\n整个过程都需要遵守对方的要求比如代码规范、分支 PR 的命名规范、文档、测试用例的规范等。\n\n祝你做个好的 contributor。",
"type": "technical_qa"
},
{
"id": "segmentfault_205",
"question": "一道js的数组算法题\n有一个数组:\n```\nconst arr = [[1,2],3,[4,5,6]];\n```\n定义一个函数传入arr后返回值为一个二维数组\n```\n[[1,3,4],[2,3,4],[1,3,5],[2,3,5],[1,3,6],[2,3,6]]\n```",
"answer": "```\nfunction f(arr) {\n var ret = []\n\n function fi(result, i) {\n if (i === -1) {\n ret.push(result)\n } else {\n let items = arr[i]\n if (!Array.isArray(items)) {\n items = [items]\n }\n items.forEach(item => {\n fi([item,...result], i - 1)\n });\n }\n }\n fi([], arr.length - 1)\n return ret\n}\nconst arr = [[1,2],3,[4,5,6]];\nconsole.log(f(arr))\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_206",
"question": "路径中`@/`代表什么意思,与`./`有何区别呢?\n我在一个项目代码中看到\n```\nimport store from '@/vuex/store'\n\n```\n请问它与\n```\nimport store from './vuex/store'\n\n```\n有什么区别",
"answer": "`import store from './vuex/store'`是相对路径代表当前路径同级下vuex下的store\n`import store from '@/vuex/store'`也是相对路径和上面意思差不多但是具体代表什么路径要看你webpack里面对于`@`是如何配置的,比如我的:\n```\nalias: {\n 'vue$': 'vue/dist/vue.esm.js',\n '@': resolve('src'),\n 'Axios': 'axios' \n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_207",
"question": "vue 项目ios上audio音频 无法自动播放\nspa页面初次进入音乐播放界面的时候在ios上无法自动播放通过play()方法还是无法实现播放。有什么方法可以解决的",
"answer": "我是这样做的:\n```\n//--创建页面监听,页面加载完毕--触发音频播放\ndocument.addEventListener('DOMContentLoaded', function () {\n function audioAutoPlay() {\n var musicEle0 = document.getElementById('music_mp3_0');\n musicEle0.play();\n }\n audioAutoPlay();\n});\n//--创建触摸监听,当浏览器打开页面时,触摸屏幕触发事件,进行音频播放\ndocument.addEventListener('touchstart', function () {\n function audioAutoPlay() {\n var musicEle0 = document.getElementById('music_mp3_0');\n musicEle0.play();\n }\n audioAutoPlay();\n});\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_208",
"question": "分享一道面试题请指点结果为何是undefined\n```\nif(!(\"a\" in window)){\n var a = 10;\n}\nconsole.log(a); // undefined\n\n\n```",
"answer": "```\n因为变量提升到作用域顶部\n\n//变量提升\nvar a ;\n\n//此时 a 为全局变量 a in window 为 true\n\nif(!(\"a\" in window)){\n var a = 10;\n}\nconsole.log(a); // undefined\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_209",
"question": "redux中间件对于异步action的意义是什么\n不太理解类似于redux-thunk这样的中间件对于发送异步action有什么意义\n不可以在异步回调之后直接手动dispatch一个action吗",
"answer": "首先,我不知道你入和对意义的定义?性能变好?代码可读性增加?扩展性变强?\nIf youre not sure whether you need it, you probably dont.\n如果你处于这个阶段你可以选择不用官方描述。\n你觉的你当前代码写的很舒服那么为什么需要额外的引入你不了解的东西呢当然不需要\n想要知道thunk有没有意义?可以先从文档上了解\n这是thunk的motivation\nRedux Thunk middleware allows you to write action creators that return a function instead of an action\n就是你可以dispatch(function)。\n下来谈谈你的问题不可以在异步回调之后直接手动dispatch一个action吗\n当然可以。你在异步回调之后直接dispatch这可以啊我觉的没什么不好。\n这里主要看你对action的定义就以网络请求为例列个简单比较。\n```\nxxxAction(xxxData) {\n return {\n type: xxxType,\n data: xxxData\n }\n}\n\n// 直接放在你需要使用的地方\nfetchXxxData().then((res) => {\n dispatch(xxxAction(xxx))\n})\n\n```\n这种情况下你将你xxxAction定义为一个通过数据来修改store数据的action\n```\ngetXxxDataAction() {\n return (dispatch) => {\n fetchXxxxData().then((res) = > {\n dispatch(xxxAction(res))\n })\n }\n}\n\n使用方式\nstore.dispatch(getXxxDataAction())\n```\n这种情况下你将这个getXxxDataAction定义为一个从后台获取数据变修改store库中的Action\n其实你会发现这两个写法基本是一致的上面那种方法是没有问题的。上面的方法可以看做是下面方法的解耦。解除了请求和修改store之间的关系。所以根本没有什么非得用谁只是你当前的场景适合用谁。\n下面方法的好处是什么就是比如我在这个系统中我的请求和修改数据的关系是恒定不变的那么我不解耦的用法可能会更加的舒服。比如\nA 需要获取xxx数据并存入store中。\nB 也需要获取xxx数据并存入store中。\n下面这种只需要在两个组件中去添加这句store.dispatch(getXxxDataAction())\n而上面那种就必须把请求以及回调来重复写一遍同样的代码两个路口一旦涉及到需要修改的时候就很容易会遗漏",
"type": "technical_qa"
},
{
"id": "segmentfault_210",
"question": "如何使用JS禁用F12和浏览器的开发者模式控制台\n后台管理框架想禁用用户取查看开发者模式控制台请问有什么JS方法或者插件可以禁用呢比较全面的禁用适用于多个不同浏览器的禁用。\n希望有经验的能指教一下\n例如这个demo站\nhttp://demo.larrycms.com/back...\n我觉得这个站真的比较全面的禁掉了开发者模式控制台",
"answer": "事先把 devtools 调成弹出式窗口的然后关掉,然后把 javascript:console.log=function(){}; 加入书签,点一下他这个你所谓的“完全禁掉了”就破功了。他是利用 console.log 打印一个对象然后覆盖这个对象的 toString 方法一旦开发者工具存在toString 方法就会被调用。所以破功方式就是毁掉 console.log. \n不让打开 devtools 以及不让右键查看源代码,这些都是徒劳的,我自己的电脑我在中间加个 http 代理你肯定管不着http 代理要怎么看怎么看,把你页面上的禁用开发者工具的那段代码删掉都行。",
"type": "technical_qa"
},
{
"id": "segmentfault_211",
"question": "一个中高阶难度的 JavaScript 正则场景\n## 问题描述\n这是一个字符串正则替换的问题我自己想了一晚上也想不出用纯正则就能搞定这个问题。但这个问题看起确实不复杂所以来思否求大佬解答。\n大概的特征是这样的我需要在一个字符串文件中查找类似 `start template template ... end` 的字符串。其中 `start` 和 `end` 是固定形式的字符串,`template` 是一个正则模式,我需要将位于 `start` 和 `end` 之间的满足 `template` 模式的字符串前面加一个前缀 `prefix`,最后我希望文件中的满足条件的字符串被修改为 `start prefix-template prefix-template ... end` 。\n## 问题实例\n下面是一个例子\n```\nvar str = \"lajishuju..Ejhohaodf98 a.length+b.length+10+:rowspan=a.length + b.length+ c.length20:rowspan=a.length+b.length lajishujudsjalfj)Ufaojd\";\n```\n我希望能把 `:rowspan=` 和 `\\d+` 之间的 `x.length` 形式的字符串修改为 `sub.x.length`。替换后的字符串应如下:\n```\n\"lajishuju..Ejhohaodf98 a.length+b.length+10+:rowspan=sub.a.length + sub.b.length+ sub.c.length20:rowspan=a.length+b.length lajishujudsjalfj)Ufaojd\"\n```\n明细字符串中加入了干扰字符串如有 `:rowspan=` 开头却没有 `\\d+` 结尾的字符串,和有结尾却没开头的字符串。\n## 我的想法\n我写出的正则只能利用 `(?=)` 断言排除有开头没结尾干扰字符串的干扰,无法判断是否具有合理的 `:rowspan=` 开头。\n恳请大佬指条明路我和同学商量一下他说不可能用一个正则一次解决这个问题。但我觉的这个模式特征这么明显看起了也很简单如此强大的正则不应该做不到请大佬传道解惑\n## 另外\n题目中的“中高阶难度”是我大言不惭毕竟我是个没怎么写过正则的菜鸡?,如有不当,请见谅!",
"answer": "```\nvar str = \"lajishuju..Ejhohaodf98 a.length+b.length+10+:rowspan=a.length + b.length+ c.length20:rowspan=a.length+b.length lajishujudsjalfj)Ufaojd\";\n\nvar r = str.replace(/(:rowspan=)(.+?)(?=\\d*:rowspan)/g, function (...m)\n{\n m[2] = m[2].replace(/\\b([a-z]\\w*\\.length)/g, 'sub.$1');\n\n return m[1] + m[2];\n});\n\nconsole.log(r);\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_212",
"question": "树形结构已知子节点找父节点\n已知 子节点 求父节点 \n例如 已知 AAA\n希望 得到 A-AA-AAA的格式\ndata3: [{\n```\n id: 1,\n label: '一级 2',\n children: [{\n id: 3,\n label: '二级 2-1',\n children: [{\n id: 4,\n label: '三级 3-1-1'\n }, {\n id: 5,\n label: '三级 3-1-2',\n disabled: true\n }]\n }, {\n id: 2,\n label: '二级 2-2',\n disabled: true,\n children: [{\n id: 6,\n label: '三级 3-2-1'\n }, {\n id: 7,\n label: '三级 3-2-2',\n disabled: true\n }]\n }]\n }],\n```",
"answer": "```\nlet find = (array, label) =>{\n let stack = [];\n let going = true;\n \n let walker = (array, label) => {\n array.forEach(item => {\n if (!going) return;\n stack.push(item['label']);\n if (item['label'] === label) {\n going = false;\n } else if (item['children']) {\n walker(item['children'], label);\n } else {\n stack.pop();\n }\n });\n if (going) stack.pop();\n }\n\n walker(array, label);\n\n return stack.join('-');\n}\n\nconsole.log(find(data, '三级 3-2-2'))\n// 一级 2-二级 2-2-三级 3-2-2\n```\n应该是 `DFS`",
"type": "technical_qa"
},
{
"id": "segmentfault_213",
"question": "怎么判断JSON对象中value存在重复值次数多少\n怎么判断JSON对象中value存在重复值次数多少\n假设是等待处理判断这个相同值总共多少个然后新建 JSON如下\n原数据\n```\n[\n {name: \"fcf294131\", key: \"处理进度\", value: \"等待处理\"},\n {name: \"fcf294131\", key: \"处理进度\", value: \"正在处理\"},\n {name: \"fcf294131\", key: \"处理进度\", value: \"等待处理\"},\n {name: \"fcf294131\", key: \"处理进度\", value: \"完成\"},\n {name: \"fcf294131\", key: \"处理进度\", value: \"等待处理\"}\n]\n```\n处理\n```\n[\n {key:\"等待处理\",len:3},\n {key:\"正在处理\",len:1},\n {key:\"完成\",len:1}\n]\n```\n这个方法怎么写",
"answer": "```\nlet arr = [], // 初始数据集\n res = {}; // 结果\narr.forEach(item => {\n if(!res[item.value]) {\n res[item.value] = {\n key: item.value,\n len: 1\n }\n } else {\n res[item.value].len++;\n }\n})\n\nres = Object.values(res);\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_214",
"question": "vue-cli 更新过后手机访问不显示页面内容\n今天把之前学习的demo拿出来重新写发现vue-cli 更新后不能输入ip 进行访问了比如我的ip 是192.168.5.212 只能是默认的127.0.0.18080 问了群里的大神改成host0.0.0.0 电脑输入Ip 是可以访问了192.168.5.212:8080但是手机访问电脑的Ip 只显示页面的标题不显示内容。(在一个局域网下)是什么原因?",
"answer": "需要把 config/index.js里的devtool: '#eval-source-map'改为devtool:'inline-source-map',就可以访问到了。\n原有答案已失效更新下\npackage.json中找到 scripts.dev在后面加上host参数 `--host 0.0.0.0`\n```\n\"dev\": \"webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --host 0.0.0.0\",\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_215",
"question": "vue-router.js里如何使用饿了么组件的弹框等的方法\nmethods: {\n```\n open5() {\n this.$notify.info({\n title: '消息',\n message: '这是一条消息的提示消息'\n });\n }\n}\n\n这是饿了么UI的弹框方法也是放到了单独的一个pop.vue组件\n\nimport pop from '@/components/pop'\n\nrouter.beforeEach((to, from, next) => {\nif (to.path === '/login' || to.path === '/') {\n next()\n} else {\n if (Cookies.get('uName')) {\n next()\n } else {\n next({path: '/login'})\n alert('请重新登录')\n pop.methods.open5() //就是这里,使用报错\n }\n}\n```\n})\n这是router.js的守卫 我想在 重新登录 这使用open5这个方法但是报错this不对",
"answer": "可以参考我的:\n```\n\nimport ElementUI from 'element-ui'\nimport 'element-ui/lib/theme-chalk/index.css'\nVue.use(ElementUI)\nimport { Notification } from 'element-ui'\n\n// 钩子函数路由判断\nrouter.beforeEach((to, from, next) => {\n if (to.meta.requireAuth) {\n if (localStorage.token) {\n // console.log(\"已有个人信息!\");\n next();\n } else {\n Notification.error({message: '请先登录!', duration: 1000, position: 'bottom-right', showClose: false})\n next({\n path: '/login',\n // 跳转到登录页\n })\n }\n }\n else {\n next();\n }\n})\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_216",
"question": "java如何获取实时cpu使用情况\n问题java如何获取实时cpu使用情况\n我是一个java新手我想知道如何实时获得cpu使用情况也就是动态的随着cpu情况返回不同的cpu使用信息我猜这个程序需要一直运行。非常抱歉我不知道这么做也没有相关的代码但是我非常想知道能提供一个案例吗\n我在搜索引擎上查找了很多信息都没有相关的代码\n这是我搜索到的但这一个不是实时的我需要一个能实时观察的提前感谢\n我搜索到的地址https://www.cnblogs.com/Rozdy...",
"answer": "首先编写一个MonitorInfoBean类用来装载监控的一些信息包括物理内存、剩余的物理内存、已使用的物理内存、内存使用率等字段该类的代码如下\n```\npackage com.amgkaka.performance; \n \n/** *//** \n * 监视信息的JavaBean类. \n * @author amg \n * @version 1.0 \n * Creation date: 2008-4-25 - 上午10:37:00 \n */ \npublic class MonitorInfoBean { \n /** *//** 可使用内存. */ \n private long totalMemory; \n \n /** *//** 剩余内存. */ \n private long freeMemory; \n \n /** *//** 最大可使用内存. */ \n private long maxMemory; \n \n /** *//** 操作系统. */ \n private String osName; \n \n /** *//** 总的物理内存. */ \n private long totalMemorySize; \n \n /** *//** 剩余的物理内存. */ \n private long freePhysicalMemorySize; \n \n /** *//** 已使用的物理内存. */ \n private long usedMemory; \n \n /** *//** 线程总数. */ \n private int totalThread; \n \n /** *//** cpu使用率. */ \n private double cpuRatio; \n \n public long getFreeMemory() { \n return freeMemory; \n } \n \n public void setFreeMemory(long freeMemory) { \n this.freeMemory = freeMemory; \n } \n \n public long getFreePhysicalMemorySize() { \n return freePhysicalMemorySize; \n } \n \n public void setFreePhysicalMemorySize(long freePhysicalMemorySize) { \n this.freePhysicalMemorySize = freePhysicalMemorySize; \n } \n \n public long getMaxMemory() { \n return maxMemory; \n } \n \n public void setMaxMemory(long maxMemory) { \n this.maxMemory = maxMemory; \n } \n \n public String getOsName() { \n return osName; \n } \n \n public void setOsName(String osName) { \n this.osName = osName; \n } \n \n public long getTotalMemory() { \n return totalMemory; \n } \n \n public void setTotalMemory(long totalMemory) { \n this.totalMemory = totalMemory; \n } \n \n public long getTotalMemorySize() { \n return totalMemorySize; \n } \n \n public void setTotalMemorySize(long totalMemorySize) { \n this.totalMemorySize = totalMemorySize; \n } \n \n public int getTotalThread() { \n return totalThread; \n } \n \n public void setTotalThread(int totalThread) { \n this.totalThread = totalThread; \n } \n \n public long getUsedMemory() { \n return usedMemory; \n } \n \n public void setUsedMemory(long usedMemory) { \n this.usedMemory = usedMemory; \n } \n \n public double getCpuRatio() { \n return cpuRatio; \n } \n \n public void setCpuRatio(double cpuRatio) { \n this.cpuRatio = cpuRatio; \n } \n} \n\n\npackage com.amgkaka.performance; \n \n/** *//** \n * 监视信息的JavaBean类. \n * @author amg \n * @version 1.0 \n * Creation date: 2008-4-25 - 上午10:37:00 \n */ \npublic class MonitorInfoBean { \n /** *//** 可使用内存. */ \n private long totalMemory; \n \n /** *//** 剩余内存. */ \n private long freeMemory; \n \n /** *//** 最大可使用内存. */ \n private long maxMemory; \n \n /** *//** 操作系统. */ \n private String osName; \n \n /** *//** 总的物理内存. */ \n private long totalMemorySize; \n \n /** *//** 剩余的物理内存. */ \n private long freePhysicalMemorySize; \n \n /** *//** 已使用的物理内存. */ \n private long usedMemory; \n \n /** *//** 线程总数. */ \n private int totalThread; \n \n /** *//** cpu使用率. */ \n private double cpuRatio; \n \n public long getFreeMemory() { \n return freeMemory; \n } \n \n public void setFreeMemory(long freeMemory) { \n this.freeMemory = freeMemory; \n } \n \n public long getFreePhysicalMemorySize() { \n return freePhysicalMemorySize; \n } \n \n public void setFreePhysicalMemorySize(long freePhysicalMemorySize) { \n this.freePhysicalMemorySize = freePhysicalMemorySize; \n } \n \n public long getMaxMemory() { \n return maxMemory; \n } \n \n public void setMaxMemory(long maxMemory) { \n this.maxMemory = maxMemory; \n } \n \n public String getOsName() { \n return osName; \n } \n \n public void setOsName(String osName) { \n this.osName = osName; \n } \n \n public long getTotalMemory() { \n return totalMemory; \n } \n \n public void setTotalMemory(long totalMemory) { \n this.totalMemory = totalMemory; \n } \n \n public long getTotalMemorySize() { \n return totalMemorySize; \n } \n \n public void setTotalMemorySize(long totalMemorySize) { \n this.totalMemorySize = totalMemorySize; \n } \n \n public int getTotalThread() { \n return totalThread; \n } \n \n public void setTotalThread(int totalThread) { \n this.totalThread = totalThread; \n } \n \n public long getUsedMemory() { \n return usedMemory; \n } \n \n public void setUsedMemory(long usedMemory) { \n this.usedMemory = usedMemory; \n } \n \n public double getCpuRatio() { \n return cpuRatio; \n } \n \n public void setCpuRatio(double cpuRatio) { \n this.cpuRatio = cpuRatio; \n } \n} \n\n\n\n```\n接着编写一个获得当前的监控信息的接口该类的代码如下所示\n```\npackage com.amgkaka.performance; \n \n/** *//** \n * 获取系统信息的业务逻辑类接口. \n * @author amg * @version 1.0 \n * Creation date: 2008-3-11 - 上午10:06:06 \n */ \npublic interface IMonitorService { \n /** *//** \n * 获得当前的监控对象. \n * @return 返回构造好的监控对象 \n * @throws Exception \n * @author amgkaka \n * Creation date: 2008-4-25 - 上午10:45:08 \n */ \n public MonitorInfoBean getMonitorInfoBean() throws Exception; \n \n} \n\n\npackage com.amgkaka.performance; \n \n/** *//** \n * 获取系统信息的业务逻辑类接口. \n * @author amg * @version 1.0 \n * Creation date: 2008-3-11 - 上午10:06:06 \n */ \npublic interface IMonitorService { \n /** *//** \n * 获得当前的监控对象. \n * @return 返回构造好的监控对象 \n * @throws Exception \n * @author amgkaka \n * Creation date: 2008-4-25 - 上午10:45:08 \n */ \n public MonitorInfoBean getMonitorInfoBean() throws Exception; \n \n} \n\n```\n该类的实现类MonitorServiceImpl如下所示\n```\npackage com.amgkaka.performance; \n \nimport java.io.InputStreamReader; \nimport java.io.LineNumberReader; \n \nimport sun.management.ManagementFactory; \n \nimport com.sun.management.OperatingSystemMXBean; \n \n/** *//** \n * 获取系统信息的业务逻辑实现类. \n * @author amg * @version 1.0 Creation date: 2008-3-11 - 上午10:06:06 \n */ \npublic class MonitorServiceImpl implements IMonitorService { \n //可以设置长些防止读到运行此次系统检查时的cpu占用率就不准了 \n private static final int CPUTIME = 5000; \n \n private static final int PERCENT = 100; \n \n private static final int FAULTLENGTH = 10; \n \n /** *//** \n * 获得当前的监控对象. \n * @return 返回构造好的监控对象 \n * @throws Exception \n * @author amg * Creation date: 2008-4-25 - 上午10:45:08 \n */ \n public MonitorInfoBean getMonitorInfoBean() throws Exception { \n int kb = 1024; \n \n // 可使用内存 \n long totalMemory = Runtime.getRuntime().totalMemory() / kb; \n // 剩余内存 \n long freeMemory = Runtime.getRuntime().freeMemory() / kb; \n // 最大可使用内存 \n long maxMemory = Runtime.getRuntime().maxMemory() / kb; \n \n OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory \n .getOperatingSystemMXBean(); \n \n // 操作系统 \n String osName = System.getProperty(\"os.name\"); \n // 总的物理内存 \n long totalMemorySize = osmxb.getTotalPhysicalMemorySize() / kb; \n // 剩余的物理内存 \n long freePhysicalMemorySize = osmxb.getFreePhysicalMemorySize() / kb; \n // 已使用的物理内存 \n long usedMemory = (osmxb.getTotalPhysicalMemorySize() - osmxb \n .getFreePhysicalMemorySize()) \n / kb; \n \n // 获得线程总数 \n ThreadGroup parentThread; \n for (parentThread = Thread.currentThread().getThreadGroup(); parentThread \n .getParent() != null; parentThread = parentThread.getParent()) \n ; \n int totalThread = parentThread.activeCount(); \n \n double cpuRatio = 0; \n if (osName.toLowerCase().startsWith(\"windows\")) { \n cpuRatio = this.getCpuRatioForWindows(); \n } \n \n // 构造返回对象 \n MonitorInfoBean infoBean = new MonitorInfoBean(); \n infoBean.setFreeMemory(freeMemory); \n infoBean.setFreePhysicalMemorySize(freePhysicalMemorySize); \n infoBean.setMaxMemory(maxMemory); \n infoBean.setOsName(osName); \n infoBean.setTotalMemory(totalMemory); \n infoBean.setTotalMemorySize(totalMemorySize); \n infoBean.setTotalThread(totalThread); \n infoBean.setUsedMemory(usedMemory); \n infoBean.setCpuRatio(cpuRatio); \n return infoBean; \n } \n \n /** *//** \n * 获得CPU使用率. \n * @return 返回cpu使用率 \n * @author amg * Creation date: 2008-4-25 - 下午06:05:11 \n */ \n private double getCpuRatioForWindows() { \n try { \n String procCmd = System.getenv(\"windir\") \n + \"//system32//wbem//wmic.exe process get Caption,CommandLine,\" \n + \"KernelModeTime,ReadOperationCount,ThreadCount,UserModeTime,WriteOperationCount\"; \n // 取进程信息 \n long[] c0 = readCpu(Runtime.getRuntime().exec(procCmd)); \n Thread.sleep(CPUTIME); \n long[] c1 = readCpu(Runtime.getRuntime().exec(procCmd)); \n if (c0 != null && c1 != null) { \n long idletime = c1[0] - c0[0]; \n long busytime = c1[1] - c0[1]; \n return Double.valueOf( \n PERCENT * (busytime) / (busytime + idletime)) \n .doubleValue(); \n } else { \n return 0.0; \n } \n } catch (Exception ex) { \n ex.printStackTrace(); \n return 0.0; \n } \n } \n \n /** *//** \n * 读取CPU信息. \n * @param proc \n * @return \n * @author amg * Creation date: 2008-4-25 - 下午06:10:14 \n */ \n private long[] readCpu(final Process proc) { \n long[] retn = new long[2]; \n try { \n proc.getOutputStream().close(); \n InputStreamReader ir = new InputStreamReader(proc.getInputStream()); \n LineNumberReader input = new LineNumberReader(ir); \n String line = input.readLine(); \n if (line == null || line.length() < FAULTLENGTH) { \n return null; \n } \n int capidx = line.indexOf(\"Caption\"); \n int cmdidx = line.indexOf(\"CommandLine\"); \n int rocidx = line.indexOf(\"ReadOperationCount\"); \n int umtidx = line.indexOf(\"UserModeTime\"); \n int kmtidx = line.indexOf(\"KernelModeTime\"); \n int wocidx = line.indexOf(\"WriteOperationCount\"); \n long idletime = 0; \n long kneltime = 0; \n long usertime = 0; \n while ((line = input.readLine()) != null) { \n if (line.length() < wocidx) { \n continue; \n } \n // 字段出现顺序Caption,CommandLine,KernelModeTime,ReadOperationCount, \n // ThreadCount,UserModeTime,WriteOperation \n String caption = Bytes.substring(line, capidx, cmdidx - 1) \n .trim(); \n String cmd = Bytes.substring(line, cmdidx, kmtidx - 1).trim(); \n if (cmd.indexOf(\"wmic.exe\") >= 0) { \n continue; \n } \n // log.info(\"line=\"+line); \n if (caption.equals(\"System Idle Process\") \n || caption.equals(\"System\")) { \n idletime += Long.valueOf( \n Bytes.substring(line, kmtidx, rocidx - 1).trim()) \n .longValue(); \n idletime += Long.valueOf( \n Bytes.substring(line, umtidx, wocidx - 1).trim()) \n .longValue(); \n continue; \n } \n \n kneltime += Long.valueOf( \n Bytes.substring(line, kmtidx, rocidx - 1).trim()) \n .longValue(); \n usertime += Long.valueOf( \n Bytes.substring(line, umtidx, wocidx - 1).trim()) \n .longValue(); \n } \n retn[0] = idletime; \n retn[1] = kneltime + usertime; \n return retn; \n } catch (Exception ex) { \n ex.printStackTrace(); \n } finally { \n try { \n proc.getInputStream().close(); \n } catch (Exception e) { \n e.printStackTrace(); \n } \n } \n return null; \n } \n \n /** *//** \n * 测试方法. \n * @param args \n * @throws Exception \n * @author amg * Creation date: 2008-4-30 - 下午04:47:29 \n */ \n public static void main(String[] args) throws Exception { \n IMonitorService service = new MonitorServiceImpl(); \n MonitorInfoBean monitorInfo = service.getMonitorInfoBean(); \n System.out.println(\"cpu占有率=\" + monitorInfo.getCpuRatio()); \n \n System.out.println(\"可使用内存=\" + monitorInfo.getTotalMemory()); \n System.out.println(\"剩余内存=\" + monitorInfo.getFreeMemory()); \n System.out.println(\"最大可使用内存=\" + monitorInfo.getMaxMemory()); \n \n System.out.println(\"操作系统=\" + monitorInfo.getOsName()); \n System.out.println(\"总的物理内存=\" + monitorInfo.getTotalMemorySize() + \"kb\"); \n System.out.println(\"剩余的物理内存=\" + monitorInfo.getFreeMemory() + \"kb\"); \n System.out.println(\"已使用的物理内存=\" + monitorInfo.getUsedMemory() + \"kb\"); \n System.out.println(\"线程总数=\" + monitorInfo.getTotalThread() + \"kb\"); \n } \n} \n\n\n\npackage com.amgkaka.performance; \n \nimport java.io.InputStreamReader; \nimport java.io.LineNumberReader; \n \nimport sun.management.ManagementFactory; \n \nimport com.sun.management.OperatingSystemMXBean; \n \n/** *//** \n * 获取系统信息的业务逻辑实现类. \n * @author amg * @version 1.0 Creation date: 2008-3-11 - 上午10:06:06 \n */ \npublic class MonitorServiceImpl implements IMonitorService { \n //可以设置长些防止读到运行此次系统检查时的cpu占用率就不准了 \n private static final int CPUTIME = 5000; \n \n private static final int PERCENT = 100; \n \n private static final int FAULTLENGTH = 10; \n \n /** *//** \n * 获得当前的监控对象. \n * @return 返回构造好的监控对象 \n * @throws Exception \n * @author amg * Creation date: 2008-4-25 - 上午10:45:08 \n */ \n public MonitorInfoBean getMonitorInfoBean() throws Exception { \n int kb = 1024; \n \n // 可使用内存 \n long totalMemory = Runtime.getRuntime().totalMemory() / kb; \n // 剩余内存 \n long freeMemory = Runtime.getRuntime().freeMemory() / kb; \n // 最大可使用内存 \n long maxMemory = Runtime.getRuntime().maxMemory() / kb; \n \n OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory \n .getOperatingSystemMXBean(); \n \n // 操作系统 \n String osName = System.getProperty(\"os.name\"); \n // 总的物理内存 \n long totalMemorySize = osmxb.getTotalPhysicalMemorySize() / kb; \n // 剩余的物理内存 \n long freePhysicalMemorySize = osmxb.getFreePhysicalMemorySize() / kb; \n // 已使用的物理内存 \n long usedMemory = (osmxb.getTotalPhysicalMemorySize() - osmxb \n .getFreePhysicalMemorySize()) \n / kb; \n \n // 获得线程总数 \n ThreadGroup parentThread; \n for (parentThread = Thread.currentThread().getThreadGroup(); parentThread \n .getParent() != null; parentThread = parentThread.getParent()) \n ; \n int totalThread = parentThread.activeCount(); \n \n double cpuRatio = 0; \n if (osName.toLowerCase().startsWith(\"windows\")) { \n cpuRatio = this.getCpuRatioForWindows(); \n } \n \n // 构造返回对象 \n MonitorInfoBean infoBean = new MonitorInfoBean(); \n infoBean.setFreeMemory(freeMemory); \n infoBean.setFreePhysicalMemorySize(freePhysicalMemorySize); \n infoBean.setMaxMemory(maxMemory); \n infoBean.setOsName(osName); \n infoBean.setTotalMemory(totalMemory); \n infoBean.setTotalMemorySize(totalMemorySize); \n infoBean.setTotalThread(totalThread); \n infoBean.setUsedMemory(usedMemory); \n infoBean.setCpuRatio(cpuRatio); \n return infoBean; \n } \n \n /** *//** \n * 获得CPU使用率. \n * @return 返回cpu使用率 \n * @author amg * Creation date: 2008-4-25 - 下午06:05:11 \n */ \n private double getCpuRatioForWindows() { \n try { \n String procCmd = System.getenv(\"windir\") \n + \"//system32//wbem//wmic.exe process get Caption,CommandLine,\" \n + \"KernelModeTime,ReadOperationCount,ThreadCount,UserModeTime,WriteOperationCount\"; \n // 取进程信息 \n long[] c0 = readCpu(Runtime.getRuntime().exec(procCmd)); \n Thread.sleep(CPUTIME); \n long[] c1 = readCpu(Runtime.getRuntime().exec(procCmd)); \n if (c0 != null && c1 != null) { \n long idletime = c1[0] - c0[0]; \n long busytime = c1[1] - c0[1]; \n return Double.valueOf( \n PERCENT * (busytime) / (busytime + idletime)) \n .doubleValue(); \n } else { \n return 0.0; \n } \n } catch (Exception ex) { \n ex.printStackTrace(); \n return 0.0; \n } \n } \n \n /** *//** \n * 读取CPU信息. \n * @param proc \n * @return \n * @author amg * Creation date: 2008-4-25 - 下午06:10:14 \n */ \n private long[] readCpu(final Process proc) { \n long[] retn = new long[2]; \n try { \n proc.getOutputStream().close(); \n InputStreamReader ir = new InputStreamReader(proc.getInputStream()); \n LineNumberReader input = new LineNumberReader(ir); \n String line = input.readLine(); \n if (line == null || line.length() < FAULTLENGTH) { \n return null; \n } \n int capidx = line.indexOf(\"Caption\"); \n int cmdidx = line.indexOf(\"CommandLine\"); \n int rocidx = line.indexOf(\"ReadOperationCount\"); \n int umtidx = line.indexOf(\"UserModeTime\"); \n int kmtidx = line.indexOf(\"KernelModeTime\"); \n int wocidx = line.indexOf(\"WriteOperationCount\"); \n long idletime = 0; \n long kneltime = 0; \n long usertime = 0; \n while ((line = input.readLine()) != null) { \n if (line.length() < wocidx) { \n continue; \n } \n // 字段出现顺序Caption,CommandLine,KernelModeTime,ReadOperationCount, \n // ThreadCount,UserModeTime,WriteOperation \n String caption = Bytes.substring(line, capidx, cmdidx - 1) \n .trim(); \n String cmd = Bytes.substring(line, cmdidx, kmtidx - 1).trim(); \n if (cmd.indexOf(\"wmic.exe\") >= 0) { \n continue; \n } \n // log.info(\"line=\"+line); \n if (caption.equals(\"System Idle Process\") \n || caption.equals(\"System\")) { \n idletime += Long.valueOf( \n Bytes.substring(line, kmtidx, rocidx - 1).trim()) \n .longValue(); \n idletime += Long.valueOf( \n Bytes.substring(line, umtidx, wocidx - 1).trim()) \n .longValue(); \n continue; \n } \n \n kneltime += Long.valueOf( \n Bytes.substring(line, kmtidx, rocidx - 1).trim()) \n .longValue(); \n usertime += Long.valueOf( \n Bytes.substring(line, umtidx, wocidx - 1).trim()) \n .longValue(); \n } \n retn[0] = idletime; \n retn[1] = kneltime + usertime; \n return retn; \n } catch (Exception ex) { \n ex.printStackTrace(); \n } finally { \n try { \n proc.getInputStream().close(); \n } catch (Exception e) { \n e.printStackTrace(); \n } \n } \n return null; \n } \n \n /** *//** \n * 测试方法. \n * @param args \n * @throws Exception \n * @author amg * Creation date: 2008-4-30 - 下午04:47:29 \n */ \n public static void main(String[] args) throws Exception { \n IMonitorService service = new MonitorServiceImpl(); \n MonitorInfoBean monitorInfo = service.getMonitorInfoBean(); \n System.out.println(\"cpu占有率=\" + monitorInfo.getCpuRatio()); \n \n System.out.println(\"可使用内存=\" + monitorInfo.getTotalMemory()); \n System.out.println(\"剩余内存=\" + monitorInfo.getFreeMemory()); \n System.out.println(\"最大可使用内存=\" + monitorInfo.getMaxMemory()); \n \n System.out.println(\"操作系统=\" + monitorInfo.getOsName()); \n System.out.println(\"总的物理内存=\" + monitorInfo.getTotalMemorySize() + \"kb\"); \n System.out.println(\"剩余的物理内存=\" + monitorInfo.getFreeMemory() + \"kb\"); \n System.out.println(\"已使用的物理内存=\" + monitorInfo.getUsedMemory() + \"kb\"); \n System.out.println(\"线程总数=\" + monitorInfo.getTotalThread() + \"kb\"); \n } \n} \n\n\n\n```\n该实现类中需要用到一个自己编写byte的工具类该类的代码如下所示\n```\npackage com.amgkaka.performance; \n \n/** *//** \n * byte操作类. \n * @author amg * @version 1.0 \n * Creation date: 2008-4-30 - 下午04:57:23 \n */ \npublic class Bytes { \n /** *//** \n * 由于String.subString对汉字处理存在问题把一个汉字视为一个字节),因此在 \n * 包含汉字的字符串时存在隐患,现调整如下: \n * @param src 要截取的字符串 \n * @param start_idx 开始坐标(包括该坐标) \n * @param end_idx 截止坐标(包括该坐标) \n * @return \n */ \n public static String substring(String src, int start_idx, int end_idx){ \n byte[] b = src.getBytes(); \n String tgt = \"\"; \n for(int i=start_idx; i<=end_idx; i++){ \n tgt +=(char)b[i]; \n } \n return tgt; \n } \n} \n\n\n\npackage com.amgkaka.performance; \n \n/** *//** \n * byte操作类. \n * @author amg * @version 1.0 \n * Creation date: 2008-4-30 - 下午04:57:23 \n */ \npublic class Bytes { \n /** *//** \n * 由于String.subString对汉字处理存在问题把一个汉字视为一个字节),因此在 \n * 包含汉字的字符串时存在隐患,现调整如下: \n * @param src 要截取的字符串 \n * @param start_idx 开始坐标(包括该坐标) \n * @param end_idx 截止坐标(包括该坐标) \n * @return \n */ \n public static String substring(String src, int start_idx, int end_idx){ \n byte[] b = src.getBytes(); \n String tgt = \"\"; \n for(int i=start_idx; i<=end_idx; i++){ \n tgt +=(char)b[i]; \n } \n return tgt; \n } \n} \n\n\n\n```\n运行下MonitorBeanImpl类读者将会看到当前的内存、cpu利用率等信息\nwmic很强大网上有很多wmic的命令\neg:wmic 获取物理内存\nwmic memlogical get TotalPhysicalMemory\nwmic 获取进程信息,很详细\nwmic process\nSystem.getProperty(\"os.name\"));//得到操作系统名字 \nSystem.getProperty(\"sun.os.patch.level\");//得到操作系统版本",
"type": "technical_qa"
},
{
"id": "segmentfault_217",
"question": "这个页面用到了哪些技术?\n我想知道这个如果要实现这种页面效果需要用到哪些技术图片又是如何存储并且加载到页面中的看了好像不是Flash。\nhttps://xlysauc.yunzhan365.co...",
"answer": "打开看控制台呀动画是css3做的 transform: translate3d() rotate;\n今天好像截图不好用那就不贴图片了。\n这种东西肯定是插件嘛。这还用想打开sourcenetwork看看资源然后看看特别的class类名。发现了fliphtml5这么个东西百度一下\n传送门",
"type": "technical_qa"
},
{
"id": "segmentfault_218",
"question": "我想把getData(start)中的使用多个 if 这里优化一下,请问如何处理?\n```\nasync getData(start) {\n\n const _self = this;\n var response = [];\n if(start == 0){\n try {\n // let response = await fetch('mock-data/selectData01.json').then(function(response) {\n // return response.json(); // 第1个\n // }).then(function(responseThenData) {\n // //console.log('responseThenData =',responseThenData);\n // return responseThenData // 第2个\n // }).catch(function(e) {\n // console.log(\"Oops, error\");\n // });\n response = await fetch('mock-data/selectData01.json').then(function(response) {\n return response.json();\n })\n return response; // 第3个\n } catch(e) {\n console.log(\"Oops, error\", e);\n }\n } else if (start == 1) {\n try {\n response = await fetch('mock-data/selectData02.json').then(function(response) {\n return response.json();\n })\n return response; // 第3个\n } catch(e) {\n console.log(\"Oops, error\", e);\n }\n } else if (start == 2) {\n try {\n\n response = await fetch('mock-data/selectData03.json').then(function(response) {\n return response.json();\n })\n return response; // 第3个\n } catch(e) {\n console.log(\"Oops, error\", e);\n }\n } else if (start == 3) {\n try {\n\n response = await fetch('mock-data/selectData04.json').then(function(response) {\n return response.json();\n })\n return response; // 第3个\n } catch(e) {\n console.log(\"Oops, error\", e);\n }\n } else if (start == 4) {\n try {\n\n response = await fetch('mock-data/selectData05.json').then(function(response) {\n return response.json();\n })\n return response; // 第3个\n } catch(e) {\n console.log(\"Oops, error\", e);\n }\n }\n }\n\n componentDidMount() {\n const _self = this;\n var key = true;\n\n\n let dataReadStart = 0;\n\n _self.getData(dataReadStart)\n .then(function(responseThenData) {\n //console.log('responseThenData =',responseThenData['dataChinaTelecom']['regionData']);\n _self.setState({\n tableBody: responseThenData['dataChinaTelecom']['emergencyTableData'],\n tableHead: responseThenData['dataChinaTelecom']['emergencyTableHeader']\n })\n })\n .then(function() {\n //console.log('abc')\n })\n .catch(function(e) {\n console.log(\"promise, error =\", e);\n });\n\n\n // var key = true;\n // new Promise(function(resolve, reject){\n // if(key){\n // resolve('成功了')\n // }else{\n // reject('被拒绝')\n // }\n // }).then(function(value) {\n // console.log(value); // key=true 123\n // }, function (rej) {\n // console.log('---------result reject');\n // console.log(rej);\n // })\n\n dataReadStart = dataReadStart + 1;\n setInterval(function(){\n\n let dataPromise = _self.getData(dataReadStart);\n console.log('dataPromise =',dataPromise)\n dataPromise\n .then(function(responseThenData) {\n //console.log('responseThenData =',responseThenData['dataChinaTelecom']['regionData']);\n _self.setState({\n tableBody: responseThenData['dataChinaTelecom']['emergencyTableData'],\n tableHead: responseThenData['dataChinaTelecom']['emergencyTableHeader']\n })\n })\n .then(function() {\n //console.log('abc')\n })\n .catch(function(e) {\n console.log(\"promise, error =\", e);\n });\n if(dataReadStart + 1 == 5){\n dataReadStart = 0;\n } else {\n dataReadStart = dataReadStart +1;\n }\n\n },30000)\n\n // ECMAScript 定义了 Undefined、Null、Boolean、String、Number、Object 6种类型\n // 其中 Undefined 和 Null 都是只包含一个值得特殊类型,分别为 undefined 和 null\n // 因此根据定义undefined和null分属不同类型\n // 使用===运算符返回false\n // 当声明的变量未初始化时该变量的默认值是undefined而null则用于表示尚未存在的对象\n }\n\n```\n这里if能不能缩简到一个",
"answer": "```\nexport default class a {\n async getData(start) {\n var response = [];\n const MAP = [\n { url: 'mock-data/selectData01.json' },\n { url: 'mock-data/selectData02.json' },\n { url: 'mock-data/selectData03.json' },\n { url: 'mock-data/selectData04.json' },\n { url: 'mock-data/selectData05.json' },\n ];\n try {\n response = await fetch(MAP[start].url).then(res => res.json());\n return response;\n } catch (e) {\n console.log('Oops, error', e);\n }\n }\n}\n\n```\n抛砖引玉",
"type": "technical_qa"
},
{
"id": "segmentfault_219",
"question": "请教个问题,关于项目开发的\n例如在java开发时前后端分离那数据库设计、前端、后端是怎么分配的-->数据库设计是有主要的人员设计吗?前后端分离,是前端做完再把东西和接口让后端做?",
"answer": "数据库可以由专人负责,也可以由业务告知需求,让后台的人设计。\n步骤1\n前端和后端商定可能需要用到的接口然后开发时可以用\n`http://www.example.com/api/v1/GetUserInfo`\n其中通过 `/api/v1` 来区分不同时期的版本,在约定好接口(域、参数列表、返回参考)后,就可以开始正式开发:\n步骤二\n前端通过 `mock` 来模拟数据,简单来说就是根据前边的约定自己写死一个假数据先用着,现在也有专门开个 `mock server` 来提供通信环境的模拟;\n后端则可以通过单元测试来检查接口。\n步骤三\n当开发到一定程度后可以两边开始实际对接一下找出问题进行沟通修改一开始的接口约定。\n重复步骤一到三因为长期项目维护的话就不会有尽头了。",
"type": "technical_qa"
},
{
"id": "segmentfault_220",
"question": "学了半年前端如何去理解那些框架的工作原理比如webpackvue\n最近很疑惑究竟要熟练到什么程度才能对前端的一些框架、工作流等工作原理比较熟悉。去看webpack的文档感觉太晦涩难懂了。。。\n感觉一直是在做一名搬运工只知道拿别人的东西来用但却不知道为什么不懂如何创造",
"answer": "思考当然很重要,但是中间决不能缺少代码从量变到质变的过程。\n有了这个过程之后思考的作用才能得以体现。\n你现在有这样的心态很好不能急于求成。不要让这份对代码的好奇与热爱的感觉消失\n总有一天我相信你用经验与技术写成的文章会被万人收藏!\n(送给自己,和每一个在路上的执着的人)",
"type": "technical_qa"
},
{
"id": "segmentfault_221",
"question": "laravel 5想自定义全局函数怎么弄呢\n想把\n```\n//生成友好时间形式\nfunction friendly_date( $from ){\n static $now = NULL;\n $now == NULL && $now = time();\n ! is_numeric( $from ) && $from = strtotime( $from );\n $seconds = $now - $from;\n $minutes = floor( $seconds / 60 );\n $hours = floor( $seconds / 3600 );\n $day = round( ( strtotime( date( 'Y-m-d', $now ) ) - strtotime( date( 'Y-m-d', $from ) ) ) / 86400 );\n if( $seconds == 0 ){\n return '刚刚';\n }\n if( ( $seconds >= 0 ) && ( $seconds <= 60 ) ){\n return \"{$seconds}秒前\";\n }\n if( ( $minutes >= 0 ) && ( $minutes <= 60 ) ){\n return \"{$minutes}分钟前\";\n }\n if( ( $hours >= 0 ) && ( $hours <= 24 ) ){\n return \"{$hours}小时前\";\n }\n if( ( date( 'Y' ) - date( 'Y', $from ) ) > 0 ) {\n return date( 'Y-m-d', $from );\n }\n \n switch( $day ){\n case 0:\n return date( '今天H:i', $from );\n break;\n \n case 1:\n return date( '昨天H:i', $from );\n break;\n \n default:\n //$day += 1;\n return \"{$day} 天前\";\n break;\n }\n}\n```\n放入函数库怎么放呢",
"answer": "在app/Helpers/(目录可以自己随便来) 下新建一个文件 functions.php \n在functions.php 中加入这个方法\n然后在\nbootstrap/autoload.php 中添加\n```\nrequire __DIR__.'/../app/Helpers/functions.php';\n```\n或者在\ncomposer.json 中的 autoload 下增加\n```\n\"files\": [\n \"app/Helpers/functions.php\"\n]\n```\n```\n...\n\"autoload\": {\n \"classmap\": [\n \"database\"\n ],\n \"psr-4\": {\n \"App\\\\\": \"app/\"\n },\n \"files\": [\n \"app/helpers/functions.php\"\n ]\n},\n\n...\n```\n然后执行\n```\ncomposer dump-auto\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_222",
"question": "有没有遇到过只在 Android 7.1 机型上报告的由Toast引起的BadTokenException错误\n由Bugly统计上报只发生在7.1.1和7.1.2机型上,目前没有复现,所以还没排查出是哪里出了问题。\n错误堆栈\n```\n# main(1)\nandroid.view.WindowManager$BadTokenException\n Unable to add window -- token android.os.BinderProxy@7f652b2 is not valid; is your activity running?\n android.view.ViewRootImpl.setView(ViewRootImpl.java:826)\n android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:369)\n android.view.WindowManagerImpl.addView(WindowManagerImpl.java:94)\n android.widget.Toast$TN.handleShow(Toast.java:459)\n android.widget.Toast$TN$2.handleMessage(Toast.java:342)\n android.os.Handler.dispatchMessage(Handler.java:102)\n android.os.Looper.loop(Looper.java:185)\n android.app.ActivityThread.main(ActivityThread.java:6493)\n java.lang.reflect.Method.invoke(Native Method)\n com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:916)\n com.android.internal.os.ZygoteInit.main(ZygoteInit.java:806)\n```",
"answer": "这个问题由于targetSDKVersion升到26之后在7.1.1机型上概率性出现。稳定复现的步骤是在Toast.show()之后UI线程做了耗时的操作阻塞了Handler message的处理如使用Thread.sleep(5000)然后这个崩溃就出现了。原因是7.1.1系统对TYPE_TOAST的Window类型做了超时限制绑定了Window Token最长超时时间是3.5s如果UI在这段时间内没有执行完Toast.show()内部的handler message得不到执行NotificationManageService那端会把这个Toast取消掉同时把Toast对于的window token置为无效。等App端真正需要显示Toast时因为window token已经失效ViewRootImpl就抛出了上面的异常。\nAndroid 8.0上面google意识到这个bug在Toast的内部加了try-catch保护。目前只有7.1.1上面的Toast存在这个问题崩溃在系统源码里。APP层可以通过自定义Toast类反射替换TN的内部成员变量mHandler从而添加try-catch做到workaround所有使用Toast的地方都使用这个自定义的不要直接使用系统原生的。",
"type": "technical_qa"
},
{
"id": "segmentfault_223",
"question": "如何写一个python脚本可以同时执行 python3 和 Python2\n不管是在 Python2 还是在 Python3 中,我们可以通过以下方法得到关键字列表:\n```\nimport keyword\nkeyword.kwlist\n```\n现在我们可以得到两个版本的 Python 的关键字,手工赋值:\n```\nkw2= ['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield'] # Python2 关键字列表\n\nkw3 = ['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield'] # Python3 的关键字列表\n\n```\n使用内建的 difflib 模块,我们可以比较出增减的关键字:\n```\nd = difflib.Differ()\ndiff = d.compare(kw2, kw3)\nprint '\\n'.join(diff)\n```\n得到以下内容\n```\n+ False\n+ None\n+ True\n and\n as\n assert\n break\n class\n continue\n def\n del\n elif\n else\n except\n- exec\n finally\n for\n from\n global\n if\n import\n in\n is\n lambda\n+ nonlocal\n not\n or\n pass\n- print\n raise\n return\n try\n while\n with\n yield\n```\n那么问题来了不管是使用 Python2 还是 Python3 ,我如何做,才能使用一个脚本,直接实现上面的结果???",
"answer": "直接上代码,自己体会吧。\n```\nimport os\nimport json\nimport difflib\ndef test():\n cmd2 = 'E:/Python27/python.exe -c \"import keyword;import json;print (json.dumps(keyword.kwlist))\"'\n cmd3 = 'C:/Python36/python.exe -c \"import keyword;import json;print (json.dumps(keyword.kwlist))\"'\n res2 = json.loads(os.popen(cmd2).read())\n res3 = json.loads(os.popen(cmd3).read())\n d = difflib.Differ()\n diff = d.compare(res2, res3)\n print '\\n'.join(diff)\nif __name__ == '__main__':\n test()\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_224",
"question": "对express 应用级中间件next('route') 方法实例的疑惑\n对`express`官网 的实例有点疑惑,不知道为什么这样书写.\n官网的代码是这样的\n```\n// 一个中间件栈,处理指向 /user/:id 的 GET 请求\napp.get('/user/:id', function (req, res, next) {\n // 如果 user id 为 0, 跳到下一个路由\n if (req.params.id == 0) next('route');\n // 否则将控制权交给栈中下一个中间件\n else next(); //\n}, function (req, res, next) {\n // 渲染常规页面\n res.render('regular');\n});\n\n// 处理 /user/:id 渲染一个特殊页面\napp.get('/user/:id', function (req, res, next) {\n res.render('special');\n});\n\n```\n```\napp.get('/user/:id', function (req, res, next) {\n if (req.params.id == 0) {\n res.render('special');\n } else {\n res.render('regular');\n };\n})\n```\n附上网址 (http://www.expressjs.com.cn/g...\n`应用级中间件`的第四个实例 `next('route')` 方法",
"answer": "## 先回答您的问题\n首先官方这段代码实现的效果跟您修改后代码的效果是差不多的。\n其次官网这段代码的主要目的是告诉使用者`next('route')`的用途。\n最后至于官网为什么要这样写得从Express的路由机制谈起。\n## Express路由分组机制\nExpress的路由内部实现比较复杂这里只挑跟题目有关的讲。\nExpress中路由是以组的形式添加的。什么意思呢可以看下面伪代码\n```\napp.get('/user/:id', fn1, fn2, fn3);\napp.get('/user/:id', fn4, fn5, fn6);\n```\n在内部Express把上面添加的路由分成了两个组。继续看伪代码可以看到路由在内部被分成了两个组。\n```\nvar stack = [\n {path: '/user/:id', fns: [fn1, fn2, fn3], // 路由组1\n {path: '/user/:id', fns: [fn4, fn5, fn5] // 路由组2\n];\n```\n路由匹配就是个遍历的过程略。\n## next('route')是干嘛的\n答案跳过当前路由分组中剩余的handler中间件\n如果没有`next('route')`,一路`next()`调用下去的话,调用顺序是这样的:\n```\nfn1 -> fn2 -> fn3 -> fn4 -> fn5 -> fn6\n```\n假设某些情况下在执行了`fn1`后,想要跳过`fn2`、`fn3`,怎么办?(比如您举的例子)\n答案就是在`fn1`里调用`next('route')`。\n然后就变成了\n```\nfn1 -> fn4 -> fn5 -> fn6\n```\n完。",
"type": "technical_qa"
},
{
"id": "segmentfault_225",
"question": "应该用forEach改变数组的值吗?\n由于js中的数组是引用类型所以可以利用类似指针的特性通过改变另一个变量去修改原始的值。我认为这其实是js中的缺陷所以我不喜欢利用这个\"缺陷\"去实现一些功能在最近的一次code review中同事指出了这个问题。所以我希望有更多朋友能给我一些建议。\n下面就是简单的例子。\n```\nlet arr = [{\n a:1,\n b:2,\n}, {\n a:3,\n b:4,\n}];\n```\n如果有以上数组我需要将每一项的a改为3。大概有两种写法一种是用forEach另一种是用map来返回一个新数组(暂不考虑for循环)。\nforEach:\n```\narr.forEach((item) => {\n item.a = 3; \n});\n```\nmap:\n```\narr = arr.map((item) => { // 有同事指出应该声明一个新变量来存储map的结果这个建议我认为是对的。\n item.a = 3;\n return item;\n});\n```",
"answer": "补充下,刚才没仔细看题目。题目的`map`方法不够“纯粹”,实际上还是直接修改了每个`item`的属性,要想不影响原有对象,应该这么写:\n```\narr = arr.map((item) => { // 有同事指出应该声明一个新变量来存储map的结果这个建议我认为是对的。\n return {\n ...item,\n a:3\n }\n});\n```\n==============\n`map`方法体现的是数据不可变的思想。该思想认为所有的数据都是不能改变的,只能通过生成新的数据来达到修改的目的,因此直接对数组元素或对象属性进行操作的行为都是不可取的。这种思想其实有很多好处,最直接的就是避免了数据的隐式修改。`immutable.js`是实现数据不可变的一个库可通过专属的API对引用类型进行操作每次形成一个新的对象。\n但具体到项目中还是要看团队的要求都用或者都不用。单单局部使用是没有效果的。\n如果使用了`React + Redux` 的技术栈,是比较推荐使用的\n另外有一点`forEach`和`map`还存在一个编程思想的区别,前者是命令式编程,后者是声明式编程,如果项目的风格是声明式的,比如`React`,那么后者显然更统一。",
"type": "technical_qa"
},
{
"id": "segmentfault_226",
"question": "关于和后端对接数据,空值判断的问题\n大家在拿到后端的数据要绑到页面上的时候空值判断一般是怎么处理的\n比如说前端要一个`List``Array`类型,但后端没查到,你想着会给你个`[]`,但就给你返回个`null`,这就导致前端取`length`的时候就报错了,难道每次都要写`if`判断吗?\n```\nif (res.list !== null) {\n this.list = res.list;\n}\n```\n请问有什么干净效率的办法",
"answer": "假如后端返回res对象res.body希望是个数组但是实际返回一个null\n那么在不考虑深复制浅复制问题的前提下\n```\nlet newArray = res.body || []\n\nconsole.log(newArray.length)\n```\n这样至少可以保证不会得到null",
"type": "technical_qa"
},
{
"id": "segmentfault_227",
"question": "vscode如何postcss语法并且对其支持emmet和格式化操作\n项目使用postcss嵌套的语法会被vscode报错有没有什么设置可以忽略掉报错呢……\n就像这种里层的嵌套就会被标红。\n```\n.pages {\n height: 100%;\n & > div {\n width: 100%;\n }\n}\n```\n本身在css中这样写不行虽然vsode也不知道我要用postcss编译报错确实看起来也是合情合理。不过这实在影响查找真的错误以及强迫症…………\n实在不行还是用回scss算了?",
"answer": "我是提问者,几天没人回答,终于解决后所以最后自己回答了……。\n- vscode支持postcss语法\n 安装 `postcss-sugar-language` 这个插件然后就能在右下角点击格式名称选择PostCss格式了可使用.postcss .pcss .sss以及.css后缀我选用了熟悉的css后缀。\n- \n将css文件视作postcss为了方便.css文件使用postcss语法不被报错以及让emmet支持postcss文件。\n在settings中的配置\n`\"files.associations\": {\n \"*.css\": \"postcss\"\n},\n\"emmet.includeLanguages\": {\n \"vue-html\": \"html\",\n \"javascript\": \"javascriptreact\",\n \"postcss\": \"css\"\n}`\n另外设置里面不要修改` \"emmet.showExpandedAbbreviation\": \"always\",`默认值就是是always不过alaways的出发判定机制并不如inMarkupAndStylesheetFilesOnly好从名字也能看出来:\n\n`\"inMarkupAndStylesheetFilesOnly\"`,将在 html、haml、jade、slim、xml、xsl、css、scss、sass、less 和 stylus 文件中生效。\n 若选择 `\"always\"`,将在所有适用文件 (不仅仅是标记或 CSS 文件) 的所有部分生效。\n但是在该需求要还是不要改这个值这样就能在postcss中使用emmet的简写比如dib扩展成display:inline-block这样就能愉快地在.css后缀的文件中使用postcss格式(伪装成css的postcss参看上一条并且使用emmet啦。\n\n\n将css文件视作postcss为了方便.css文件使用postcss语法不被报错以及让emmet支持postcss文件。\n在settings中的配置\n```\n`\"files.associations\": {\n \"*.css\": \"postcss\"\n},\n\"emmet.includeLanguages\": {\n \"vue-html\": \"html\",\n \"javascript\": \"javascriptreact\",\n \"postcss\": \"css\"\n}`\n```\n另外设置里面不要修改` \"emmet.showExpandedAbbreviation\": \"always\",`默认值就是是always不过alaways的出发判定机制并不如inMarkupAndStylesheetFilesOnly好从名字也能看出来:\n但是在该需求要还是不要改这个值这样就能在postcss中使用emmet的简写比如dib扩展成display:inline-block这样就能愉快地在.css后缀的文件中使用postcss格式(伪装成css的postcss参看上一条并且使用emmet啦。\n以上目的是为了不改变.css文件情况下自如地切换postcss和css想写什么前也不用改下后缀毕竟很多时候我们还是写原生css同时兼顾使用emmet这对使用习惯影响很小唯一不爽就是没法增加`inMarkupAndStylesheetFilesOnly`中的值加一个postcss多好呀?。\n- \npostcss文件不能格式化\n2019.10.10更新,现在prettier新版又没问题了直接安装就行啦。\n以下就可以不用看了真香prettier。\n——————————————————————————————————————————————————\n安装前端都喜欢安装的prettier插件prettier -code formater\n最近不能格式化了版本1.7.1)…… prettier更新后的问题,prettier插件不知从哪个版本起开始抽风不能格式化css和html不过默认vscode是可以格式化html的我们只需要禁用prettier对html格式化的接管就行了在设置中Prettier的disable Languages处修改如下\n` \"prettier.disableLanguages\": [\"vue\", \"html\"]`\n或者可以安装prettier1.6.1版这个版本html格式化没有抽风。\n不过可惜的是vscode居然自己不能格式化css这个就不吐槽了n版本前就吐槽过而prettier喵的明明介绍里面写的` format your JavaScript / TypeScript / CSS using Prettier.`现在连原生css都没法格式化了要你何用啊在真香定律作用下我决定暂时留着这货……安装beautify插件。\n机智如我不要脸发现在beautify插件配置中可塞进去postcss直接剥夺prettier对css的接管权限估计下一步就是将其打入冷宫了beautify也能格式化json和js呢在settings的`\"beautify.language\":`的css数组中添加postcss\n` \"prettier.disableLanguages\": [\"vue\", \"html\", \"css\"]\n \"beautify.language\": {\n \"css\": [\n \"css\",\n \"scss\",\n \"postcss\"\n ],\n}`\n这个方法最完美啊还简单。\n\n\npostcss文件不能格式化\n2019.10.10更新,现在prettier新版又没问题了直接安装就行啦。\n以下就可以不用看了真香prettier。\n——————————————————————————————————————————————————\n安装前端都喜欢安装的prettier插件prettier -code formater\n最近不能格式化了版本1.7.1)…… prettier更新后的问题,prettier插件不知从哪个版本起开始抽风不能格式化css和html不过默认vscode是可以格式化html的我们只需要禁用prettier对html格式化的接管就行了在设置中Prettier的disable Languages处修改如下\n```\n` \"prettier.disableLanguages\": [\"vue\", \"html\"]`\n```\n或者可以安装prettier1.6.1版这个版本html格式化没有抽风。\n不过可惜的是vscode居然自己不能格式化css这个就不吐槽了n版本前就吐槽过而prettier喵的明明介绍里面写的` format your JavaScript / TypeScript / CSS using Prettier.`现在连原生css都没法格式化了要你何用啊在真香定律作用下我决定暂时留着这货……安装beautify插件。\n机智如我不要脸发现在beautify插件配置中可塞进去postcss直接剥夺prettier对css的接管权限估计下一步就是将其打入冷宫了beautify也能格式化json和js呢在settings的`\"beautify.language\":`的css数组中添加postcss\n```\n` \"prettier.disableLanguages\": [\"vue\", \"html\", \"css\"]\n \"beautify.language\": {\n \"css\": [\n \"css\",\n \"scss\",\n \"postcss\"\n ],\n}`\n```\n这个方法最完美啊还简单。\n另提示使用`ctrl`-`shift`-`a`进行块注释(即`/* */`),询问过作者,他说后面会把`ctrl`-`/`的注释风格改成`/* */`。",
"type": "technical_qa"
},
{
"id": "segmentfault_228",
"question": "a['b']和a.b哪个性能更好\n```\nvar a = {\n b: 9\n}\n\n```\n如题a['b']和a.b哪个性能更好",
"answer": "a.b性能好一点。\n```\nvar x = {a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:1}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}};\nconsole.time();\nconsole.log(x['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']['a']);\nconsole.timeEnd();\nconsole.time();\nconsole.log(x.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a)\nconsole.timeEnd();\nVM1121:3 {a: {…}}\nVM1121:4 default: 0.43701171875ms\nVM1121:6 {a: {…}}\nVM1121:7 default: 0.22119140625ms\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_229",
"question": "在Vue.js中什么是内联处理器\n在文档中 内联处理器中的方法:\n请问下`内联处理器`是指的什么呢?",
"answer": "比较一下这两个写法有什么不同:\n## 写法一\n```\n<div id=\"example-3\">\n <button v-on:click=\"say\">Say hi</button>\n <button v-on:click=\"say\">Say what</button>\n</div>\n```\n```\nnew Vue({\n el: '#example-3',\n methods: {\n say: function () {\n alert('hello');\n }\n }\n});\n```\n## 写法二\n```\n<div id=\"example-3\">\n <button v-on:click=\"say('hi')\">Say hi</button>\n <button v-on:click=\"say('what')\">Say what</button>\n</div>\n```\n```\nnew Vue({\n el: '#example-3',\n methods: {\n say: function (message) {\n alert(message);\n }\n }\n});\n```\n## 差异\n一个有括号一个没括号对吧\n没括号的这个直接就是函数名有括号的这个实际是一条JS语句有括号的这个就叫『内联处理器』。\n## 没括号的好处\n看上去有括号的更直观更容易理解。那为什么还要搞什么无括号\n没括号的有这么一个好处\n```\n<div id=\"example-3\">\n <button v-on:click=\"say\">Say hi</button>\n <button v-on:click=\"say\">Say what</button>\n</div>\n```\n```\nnew Vue({\n el: '#example-3',\n methods: {\n say: function (event) {\n alert(event.target.tagName);\n }\n }\n});\n```\n虽然我没括号但我天生自带`event`参数呀,你在上面不用写`event`,我下面就自带`event`了,你有括号的括号里几个参数,下面就得几个参数,你不能无中生有的。\n### 有括号的逆袭\n为了让有括号的也能得到无括号娘胎里自带的event参数我们可以这样写\n```\n<div id=\"example-3\">\n <button v-on:click=\"say('hi', $event)\">Say hi</button>\n <button v-on:click=\"say('what', $event)\">Say what</button>\n</div>\n```\n```\nnew Vue({\n el: '#example-3',\n methods: {\n say: function (message, event) {\n alert(message);\n alert(event.target.tagName);\n }\n }\n});\n```\n送他一个美刀`$`,于是有括号的也可以快乐地使用天然无雕饰的`event`参数了!",
"type": "technical_qa"
},
{
"id": "segmentfault_230",
"question": "函数参数中的中括号究竟代表什么呢?\n1.这是我看某文档的时候产生的疑问如一个node中的write方法\n`buf.write(string[, offset[, length]][, encoding])`\n2.问题函数参数中的中括号代表什么了怎么有些只有半个括号比如string[ 或 offset[;而有的却是length]][这样了?\n3.还会有其他符号也有它独特代表的含义吗?\n4.这种写法的好处是什么?",
"answer": "以上三个问题作一个问题回答。\n简单的回答就是中括号表示这个参数非必须.\n接下来详细解释。\n首先这样使用中括号只是出于一种的表达形式的需要而已(这样的表达形式很常见)这与api本身是没有关系的。\n然后我们拿上面的例子来说\n```\nbuf.write(string[, offset[, length]][, encoding])\n```\n对于`buf.write`这个方法:\n第一个参数`string`是必须的,他表示你要写入的内容;往后的`offset`、`length`、`encoding`这些参数都是非必须的。这些参数你可以不传(用[]括起来表示不传),但并不表示这三个参数你想怎么传就怎么传的,这里是有规则的,规则从这里中括号的对应关系中可以看出来。我们来看他的对应关系:`[, offset[, length]]` && `[ encoding]`。这表示`offset`、`length`和`encoding`你可以传或者不传,但是你要是没有传`offset`的话那`length`是一定不能传的,这就是为什么`length`要放在`offset`的括号里面的原因。\n所以整个例子理解起来就是\n`string`必须传,`offset`、`length`、`encoding`可传可不传,但是`offset`不传的话`length`也不能传。\n至于这样写有什么好处我想这可能是当初写api那帮家伙觉得这样表达更合理吧后面写文档的觉得这种方式还不错就依葫芦画瓢了慢慢的就约定俗成了。",
"type": "technical_qa"
},
{
"id": "segmentfault_231",
"question": "当执行npm publish 时出现unauthorized 和 is not in the npm registry\n当执行npm publish发生了如下错误\n```\nappledeMacBook-Pro:nini-react apple$ npm publish\nnpm ERR! publish Failed PUT 401\nnpm ERR! code E401\nnpm ERR! 404 unauthorized Login first: nini-react\nnpm ERR! 404\nnpm ERR! 404 'nini-react' is not in the npm registry.\nnpm ERR! 404 You should bug the author to publish it (or use the name yourself!)\nnpm ERR! 404\nnpm ERR! 404 Note that you can also install from a\nnpm ERR! 404 tarball, folder, http url, or git url.\n\nnpm ERR! A complete log of this run can be found in:\nnpm ERR! /Users/apple/.npm/_logs/2018-02-04T00_32_35_475Z-debug.log\nappledeMacBook-Pro:nini-react apple$ \n```\n起先以为是账户的问题我就执行了npm adduser 和 npm login 都不行。公司的电脑都是可以的!哪位大神帮帮忙!",
"answer": "您首先执行下` npm adduser `,输入您相应的` Username `、` Password `、` Email: (this IS public) `,关键的一步来了!\n```\nLogged in as 您的Username on https://registry.npmjs.org/.\n```\n如果` on `后面不是` https://registry.npmjs.org/ `,而是其他的镜像,比如我们大家常见的淘宝镜像:\n```\nhttp://registry.npm.taobao.org/\n```\n那么您首先替换成原来的替换成原来执行如下命令\n```\nnpm config set registry https://registry.npmjs.org/\n```\n最后替换完毕再执行` npm adduser `、` npm publish `这样应该就ok了",
"type": "technical_qa"
},
{
"id": "segmentfault_232",
"question": "请教一道算法题,如下,谢谢!\n有一个数组`[1,1,1,2,3,4,5,8,10,22,24,25,26,66]`\n请写一个方法把数组变成`[1,1,[1,2,3,4,5],8,10,22,[24,25,26],66]`\n就是把里面连续递增的数字归成一个数组没思路有没有好的方案",
"answer": "两个指针 i,j\n```\nvar arr = [1,1,1,2,3,4,5,8,10,22,24,25,26,66]\nvar len = arr.length\nvar i = 1, j = 0\nvar rst = []\nfor(; i <= len; i++) {\n if(arr[i]-arr[i-1] !== 1) {\n i-j===1 ? rst.push(arr[j]) : rst.push(arr.slice(j, i))\n j = i\n }\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_233",
"question": "php 使用redis进行秒杀的思路\n问题大概是这样的,因为项目中设计一个比较简单的类似于秒杀的东西\n但几经搜索之后 都说使用redis的原子性 采用队列来处理, 然后去看了一下redis的一些命令\n又结合了别人的一些代码 大致思路是以下这样\n我有几个问题\n1.什么时候触发 左进右出 取数据这个流程呢 ,条件是什么呢\n2.还是说 把商品数量提到 检查队列长度之前??\n3.或者说我的思路 本身就有很大漏洞或者 歪了\n请不留情 斧正\n```\n \n \n \n //用户进入\n //获取用户信息\n //连接redis\n //加入队列msList\n \n //这个位置检查缓存的商品数量?? 为0就直接返回了 不用进行下面的操作?\n \n //检查队列长度 \n //--1.大于200就返回 抢购人数过多,跳转抢购结束页面,结束,终止秒杀\n //--2.小于等于就加入队列\n \n //判断等于200触发下面操作???\n\n //左进右出 取数据\n //----查询商品数量为num \n //-------1.无则 加入redis缓存 \n //-------2.有则判断是否大于0 \n //----------1.小于等于就退出 ,跳转库存不足页面,结束\n //----------2.无则判断\n //-------------进入的用户左进右出\n //-----------------事务\n //-----------------1.插入成功,num-1,返回用户消息,结束\n //-----------------1.插入失败,回滚,返回用户消息,结束\n //释放redis\n\n //订单超时,库存增加??\n```",
"answer": "您可以逆向思考这个秒杀问题由于Redis的list数据结构是不可能到达“负”长度的所以可以把需要被秒杀的商品信息和一个唯一编号预先放到指定商品类型的唯一队列中用户请求时直接lpop出结果不可能出现超量的问题很多东西都免了。",
"type": "technical_qa"
},
{
"id": "segmentfault_234",
"question": "js 怎样用正则去掉小数点后面多于的0\n想用replace替换掉小数点后面多于的0.\n```\n例如 12.000700 ——————> 12.0007\n\n```\n注意若是没有小数点的话匹配不生效不替换任何字符。\n1.不希望转为数字我的整个数值计算是字符串按位计算的所以我并不希望将他转为数字而是通过正则的方式去掉多余的0。不愿意转换也有一点是String/Number等方法对小数点后面的位数有限制。\n2.(需要考虑没有小数点的情况)/0*$/或者/0+$/这种单纯的匹配末尾是不全面的。可能有没有小数点的存在。\n```\n并不希望: 12000 ——————> 12\n\n```\n这明显改变了数值\n3.目前想到的方法目前的能想到的用了两个replace一个match。先匹配到小数点右面的字符。再将该字符去末尾0替换到小数点右面。显然不高级有没有更优雅的写法。\n```\nvar str = \"12.000700\";\nvar _tmp = str.match(/\\.\\d+0+/)[0].replace(/0+$/,'');\nconsole.log(str.replace(/\\.\\d+0+/, _tmp));\n```",
"answer": "```\nconst arr=['1200.00100','1200.00000','1200.','1200','1200.10000','0.120010000','0.000011111']\nconst regexp=/(?:\\.0*|(\\.\\d+?)0+)$/\narr.forEach((item)=>{\n console.log(item.replace(regexp,'$1'))\n})\n\n// > 1200.001\n// > 1200\n// > 1200\n// > 1200\n// > 1200.1\n// > 0.12001\n// > 0.000011111\n```\n再解释下正则的意思`(?:\\.0*|(\\.\\d+?)0+)$`\n先分解成4部分\n\n1. `(?:reg1|reg2)` - 它是一个正则分组非捕获组要么匹配reg1要么匹配reg2优先匹配reg1加上`?:`不对捕获组记录\n2. `\\\\.0*` - 表示匹配一个`.`开头后边跟着0或0个以上数量的`0`,且不进行捕获,所以在填充`$1`时,就是个空值\n3. `(\\\\.\\\\d+?)0+` - 它是一个捕获组,匹配一个`.`开头后边跟着非贪婪(懒惰)匹配任意数字,接着在末尾尽可能多的匹配`0`这个字符,匹配完成 后,生成一个捕获组内容\n4. `$` - 表示匹配结果需要以`0`作为结尾",
"type": "technical_qa"
},
{
"id": "segmentfault_235",
"question": "一道关于 对象之间 值传递的问题\n```\n var a = {\n num: 2\n };\n\n var b = a; \n\n a.num = a = {\n num: 4\n };\n console.log(a.num);// 4\n console.log(b.num);// { num: 4 }\n\n```\n这个b.num是4不是因为 'var b = a时' b指向a了吗那为什么下面那个没有指向a\n```\n var a = {\n num: 2\n };\n\n var b = a; //没有把指向给b吗\n\n a = {\n num: 4\n };\n console.log(b.num) //为什么是2 a已经是4了b的指向还是a为什么不是4\n```",
"answer": "Javascript中有5种基础数据类型分别是`Undefined、Null、Boolean、Number、StringES6中新加的Symbol暂时不考虑它`基础数据类型都是按值访问即我们可以直接操作保存在变量中得实际值。而Javascript中的引用数据类型比如ArrayObject。。。它们的值是保存在堆内存中得对象Javascript 不允许直接访问堆内存中的数据,即无法直接操作对象的堆内存空间。在操作对象时,实际上我们操作的是对象的引用,也就是我们经常提及的内存地址、内存指针等。废话不多说,咱们来看题目。\n```\nvar a = {\n num: 2\n};\n\nvar b = a;\n```\n我们通过` var b = a; `进行引用类型的赋值操作该操作会自动分配一个值保存在变量b不过这个值就是咱们经常提及的引用类型的一个内存地址或内存指针。当内存地址相同时尽管变量之间相互独立但访问的具体对象实际上是同一个即变量 a 和 b 在内存空间对应的对象是同一个在该位置您不管是修改a.num还是修改b.num它们两个都会受影响\n接下我们再分析一下最容易迷惑的一行代码\n```\na.num = a = {\n num: 4\n};\n```\n因为Javascript的成员访问优先级19比赋值优先级3运算符优先级可参考运算符优先级因此先执行成员访问a.num上面我们说了不管您是修改a.num还是修改b.num它们两个都会受影响所以这里变量b也会受到影响因此实则发生了如下赋值代码\n```\nb.num = a = {\n num: 4\n}\n```\n所以变量b对应的堆内存的对象如下\n```\nb = {\n num: {\n num: 4\n }\n}\n```\n接下来我们再看看变量a变量a起先对应的堆内存的对象为\n```\na = {\n num: 2\n};\n```\n当执行 `b.num = a = { num: 4 }`再次进行引用类型的赋值操作在这里会重新为a分配一个内存指针所以a最终变成了\n```\na = {\n num: 4\n};\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_236",
"question": "怎么在ng4中阻止触摸事件的冒泡or渗透\n我用ng4写了一个触摸滑动组件部分代码如下\n```\nlet touchstart = Observable.fromEvent(this.el.nativeElement,'touchstart')\nlet touchmove = Observable.fromEvent(this.el.nativeElement, 'touchmove')\nlet touchend = Observable.fromEvent(this.el.nativeElement, 'touchend')\n\ntouchstart.map((start:any) => {\n return new Position(start.touches[0].pageX, start.touches[0].pageY)\n}).subscribe(start => {\n this.duration = 0;\n this.touchObject.start = start\n transObject.start = new Position(this.trans.x, this.trans.y)\n});\n```\n......\n这个组件是fixed在最上层的他响应触摸滑动的时候它下面的内容也会跟着一起滑动有什么办法能够只让它自己滑动呢",
"answer": "没试过。试试`Observable`加个`filter`\n```\nlet touchstart = Observable.fromEvent(this.el.nativeElement,'touchstart').pipe(\n filter((evt:any) => evt.target == this.el.nativeElement)\n)\n```\n或者加个`tap`中阻止冒泡试试。\n```\nlet touchstart = Observable.fromEvent(this.el.nativeElement,'touchstart').pipe(\n tap((evt:any) => evt.stopPropagation())\n)\n```\n`Rxjs 5+`",
"type": "technical_qa"
},
{
"id": "segmentfault_237",
"question": "java怎么判断不是常用汉字例如这类字挹攀繊昧\njava怎么判断不是常用汉字例如这类字挹攀繊昧\n谢谢",
"answer": "把常用汉字做成一个字典存起来,用的时候查就行了\nhttp://blog.csdn.net/mingzzne...\n只收录一级汉字的话也就大约10KB左右的大小\n上面的是GB2312标准中的\n按新一点的有2013年发布的《通用规范汉字表》一级字变成了3500个但是似乎没有整理好的文字版",
"type": "technical_qa"
},
{
"id": "segmentfault_238",
"question": "请问如何修改element表头的样式浏览器页面不显示出应有的样式\n本人萌新最近在使用element中的表格时遇到了一些问题\n请问在浏览器页面修改该表格中的.el-table th,加入background#f4f4f4 样式能正常显示但是在项目的style标签中修改再到浏览器页面就不会显示出应有的样式。\n以下是代码\n样式\n```\n .el-table th{\n background:#f4f4f4 !important;\n font-size: large;\n }\n```\n表格\n```\n<el-table\n :data=\"tableData\"\n style=\"width: 100%\"\n border>\n <el-table-column\n prop=\"doc\"\n label=\"文件名称\"\n width=\"290\"\n header-align=\"center\"\n >\n </el-table-column>\n <el-table-column\n prop=\"name\"\n label=\"发起人\"\n width=\"290\"\n header-align=\"center\">\n </el-table-column>\n <el-table-column\n prop=\"situation\"\n label=\"文件状态\"\n width=\"290\"\n header-align=\"center\">\n </el-table-column>\n </el-table>\n```",
"answer": "您说的项目中,应该是指“组件内”吧?\n在组件内使用其它组件的时候有些样式的设置是无效的。\n比如你的test.vue中使用了el-table这个组件但 .el-table th 这个元素在test.vue中并不存在而是在el-table这个组件内那么你在test.vue 中设置 .el-table th的样式是无效的这应该跟vue的渲染机制有关。\n把.el-table th的样式写到全局的css文件中就好了。",
"type": "technical_qa"
},
{
"id": "segmentfault_239",
"question": "求路过前辈指导下小弟学习路线(前端)\n```\n 小弟前端菜鸟一枚,基础很不扎实,目前断断续续工作了也有半年了,感觉没学到什么东西,反而把知识搞的很乱,现在想自己重新深入学习一遍,由于自己现在东西学的特别乱,十分迷茫,求诸位前辈指点,建议个学习路线,再此写过诸位.\n 下面说下我目前会的东西css,html可以javascript会用但不够扎实css3和html5的东西也差不多可以bootstrapjqueryajax只能说可以简单使用了还有dojo公司之前也用过目前正想学习vue看了两天照着文档可以用但好多东西根本看不懂。\n 真的很是迷乱,求大神指点一条正确学习路线,小弟在此再次写过诸位大神!\n```",
"answer": "我的学习过程经历过及个阶段:主要是从断断续续看书以及实践中升级。或许你可以借鉴一下。\n- 阶段0《jQuery基础教程 (第四版)》\n- 阶段1《JavaScript高级程序设计 (第三版)》\n- 阶段3《JavaScript忍者秘籍》\n- 阶段4《Node.js 实战》《HTTP权威指南》《图解TCP IP》《图解HTTP》`不要以为前端不懂通讯协议也行`\n\n- 阶段5Vue, Webpack, React (直接在官网按照教程学习)\n- \n阶段6自己写一些教程\n\nVue + Vue-router + Element-ui 搭建一个非常简单的dashboard demo\nVue+ElementUI: 手把手教你做一个audio组件 (ps: 示例音频好好听)\n\n\n- 阶段7 开源一些小项目发布两个npm包\n\n阶段6自己写一些教程\n- Vue + Vue-router + Element-ui 搭建一个非常简单的dashboard demo\n- Vue+ElementUI: 手把手教你做一个audio组件 (ps: 示例音频好好听)\n\n我的学习并不是持续的过程而是断断续续的过程。当然也学到很多其他的东西。当我想学A的时候我会发现里面有一些有趣的B,C,D可以学习。\n总结一下\n- `不要畏惧英文文档,我觉得最好的文档就是官方文档`\n- `学习可以不求甚解,渐进式学习`\n- `保持对新技术的好奇心,尝试各种新鲜玩意`\n- `不要对某个技术特别崇拜`\n- `学习要有文档笔记的积累,有个技术博客是不错的加分项`\n- 不要认为学好前端就是学好JS, 实际上完全不是如此你还要掌握HTTP相关知识。例如: OPTIONS预检请求,这里涉及到浏览器的机制不明白的话跨域POST时可能会闹笑话。\n- 不要认为前端只是搞前端,有时候后端架构也是要了解的\n- ...\n\n另外编程不是目的。建议阅读以下`《软技能:代码之外的生存指南》``《新生--七年就是一辈子》`。\n最重要就是`终身学习,读书,给自己打补丁,升级自己的操作系统。`",
"type": "technical_qa"
},
{
"id": "segmentfault_240",
"question": "用better-scroll做的轮播图,为什么不能无缝循环?\n一.实锤:\n1.1 html:\n```\n <div class=\"slider\" ref=\"slider\">\n <div class=\"slider-group\" ref=\"sliderGroup\">\n <div v-for=\"item in recommends\">\n <a :href=\"item.linkUrl\">\n <img class=\"needsclick\" @load=\"loadImage\" :src=\"item.picUrl\">\n </a>\n </div>\n <div class=\"dots\">\n <span class=\"dot\" :class=\"{active: currentPageIndex === index }\" v-for=\"(item, index) in dots\"></span>\n </div>\n </div>\n```\n1.2 script:\n```\n\n<script>\nimport BScroll from 'better-scroll'\nimport {addClass} from 'common/js/dom'\nexport default{\n props: {\n loop: {\n type: Boolean,\n default: true\n },\n autoPlay: {\n type: Boolean,\n default: true\n },\n interval: {\n type: Number,\n default: 4000\n }\n },\n data() {\n return {\n dots: [],\n currentPageIndex: 0\n }\n },\n mounted() {\n setTimeout(() => {\n this._setSliderWidth()\n this._initSlider()\n this._initDots()\n\n if (this.autoPlay) {\n this._play()\n }\n }, 20)\n\n window.addEventListener('resize', () => {\n if (!this.slider) {\n return\n }\n this._setSliderWidth(true)\n this.slider.refresh()\n })\n },\n methods: {\n _setSliderWidth(isResize) {\n // 取轮播组的子元素\n this.children = this.$refs.sliderGroup.children\n\n let width = 0\n // 取轮播组件宽度(即屏幕宽度)\n let sliderWidth = this.$refs.slider.clientWidth\n for (var i = 0; i < this.children.length; i++) {\n let child = this.children[i]\n addClass(child, 'slider-item')\n\n // 设置轮播子图宽度为屏幕宽度\n child.style.width = sliderWidth + 'px'\n // 将轮播子图累加\n width += sliderWidth\n }\n\n // ???\n if (this.loop && !isResize) {\n width += 2 * sliderWidth\n }\n this.$refs.sliderGroup.style.width = width + 'px'\n },\n _initSlider() {\n this.slider = new BScroll(this.$refs.slider, {\n scrollX: true,\n scrollY: false,\n momentum: false,\n snap: true,\n snapLoop: this.loop, // 循环\n snapThreshold: 0.3,\n snapSpeed: 400,\n click: true\n })\n\n this.slider.on('scrollEnd', () => {\n let pageIndex = this.slider.getCurrentPage().pageX\n if (this.loop) {\n pageIndex -= 1\n }\n this.currentPageIndex = pageIndex\n\n if (this.autoPlay) {\n clearTimeout(this.timer)\n this._play()\n }\n })\n },\n _initDots() {\n this.dots = new Array(this.children.length)\n },\n _play() {\n let pageIndex = this.currentPageIndex + 1\n if (this.loop) {\n pageIndex += 1\n }\n this.timer = setTimeout(() => {\n this.slider.goToPage(pageIndex, 0, 400)\n }, this.interval)\n }\n }\n}\n</script>\n```\n二.线索:\n1. 可以轮播,但不能循环(不能从第一张往前翻,不能从最后一张往后翻)\n2. 按教程里给slider-group增加了2个slider的宽 度(是为无缝循环准备的?),但他们出现在轮播图片的末尾(2个空白)\n3. 第一张图没有对应dot,第二张图对应第一个dot,以此类推\n4. 对比了教程里的代码,几乎没有区别,数据来源也是一样,替换了代码也是这样的表现,so百思不得其解",
"answer": "新版本已经更新了,是版本的问题,在0.1.15版本这么写是没问题的,snap的各个配置项并列写,但在新版本要写在一个snap对象内\n_initSlider() {\n```\nlet slider = new BScroll(this.slider, {\n click: true,\n scrollX: true,\n scrollY: false,\n momentum: false,\n snap: {\n loop: true,\n threshold: 0.3,\n speed: 400\n },\n})\n\n这么写就可以了\n```\n\n另外还有几个小修改,请您作为参考\n`\n```\n _initDots() {\n // this.dots = new Array(this.children.length) // 原写法\n this.dots = new Array(this.children.length - 2)\n },\n```\n2.升版本,修改创建better-scroll的配置时,dot与图片不对应:\n```\n // bs对象配置方法中(配置后):\n this.slider.on('scrollEnd', () => {\n let pageIndex = this.slider.getCurrentPage().pageX\n // 老版本有,新版去掉:\n // if (this.loop) {\n // pageIndex -= 1\n // }\n this.currentPageIndex = pageIndex\n\n if (this.autoPlay) {\n clearTimeout(this.timer)\n this._play()\n }\n })\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_241",
"question": "JavaScript数组map方法的疑问[已解决]\n问题\n一个长度为4空数组\n用`map()`给数组元素赋值\n为什么新数组还是空的呢?\n下面的代码为什么不输出\n`[empty × 4]    [2,2,2,2]`\n代码\n```\nvar array = new Array(4);\nvar newArray = array.map(item=>{\n return '2'\n});\nconsole.log(array,newArray);\n// =>[empty × 4]   [empty × 4]\n```\n解决",
"answer": "什么都没有的数组元素叫做槽(slot),一般方法都会忽略,可以用 `Array.prototype.fill`、`Array.from` 或者 `[...arr]` 的方式转换。\n比如 `Array.from(new Array(4))`",
"type": "technical_qa"
},
{
"id": "segmentfault_242",
"question": "vue单页面引入cdn\nvue单页面应用中需要引入百度地图的三个cdn文件来画图\n但是网上都说在index.html加这样的话会有不必要的加载影响速度\n所以想问怎么只在单个组件里引入这三个文件",
"answer": "封装一个工具函数比如bmap.js大致代码如下\n```\nexport function MP() { \n return new Promise(function (resolve, reject) { \n window.onload = function () { \n resolve(BMap) \n } \n let script = document.createElement('script'); \n script.type = 'text/javascript'; \n script.src = 'http://api.map.baidu.com/api?v=2.0&ak=ak&callback=init'; \n script.onerror = reject; \n document.head.appendChild(script); \n }) \n} \n```\n组件中使用\n```\nimport { MP } from './bmap.js'\nexport default {\n mounted() { \n this.$nextTick(function() { \n const _this = this; \n MP().then(BMap => { \n // 其他操作 \n })\n })\n }\n} \n```",
"type": "technical_qa"
},
{
"id": "segmentfault_243",
"question": "问一个数据库乐观锁的问题\n通常我们采用引入一个version版本号来作为乐观锁提交的时候校验这个版本号那么此时有两种方式\n方式一程序中对版本加一即判断条件为数据库版本小于当前传入的版本\nupdate set name = ${name} and version = ${version} where id = ${id} and version < ${version}\n方式二通过数据库进行加一即判断条件为数据库版本等于当前传入的版本\nupdate set name = ${name} and version = version + 1 where id = ${id} and version = ${version}\n请问下这两种方式有什么不同吗因为我看几乎所有的乐观锁都是用第二种方式来实现的",
"answer": "结果是一样的,方法二比较好理解点罢了。\n很多情况下乐观锁并不需要version比如你要UPDATE的是name这一列那就可以把name当成version这样就可以写成\n```\nUPDATE ... SET name = ${newname} WHERE id = ${id} AND name = ${oldname}\n\n```\n我也不知道用方法一该怎么来写呢。",
"type": "technical_qa"
},
{
"id": "segmentfault_244",
"question": "用JS怎样才能正确的得到字符串的长度\n```\nvar s = '吉林?';\ns.length; //4\n```\n用js输出s.length的是4但是变量s的字符串的个数是3如何通过代码准确得到变量 s 的字符串个数3",
"answer": "`s.match(/[\\s\\S]/gu).length`\n主要是正则表达式`u`标志符可以匹配4字节 Unicode 编码。\n空字符串要处理一下。。。因为 match 返回 `null`。\n正则表达式`u`是ES6的特性同样的ES6的字符串迭代器也能正确处理 Unicode 编码:`[...s].length`等等写法。\n我好奇地跑去 babel 测试了一下,发现了这群大触丧病的 hack\n```\ns.match(/[\\s\\S]/gu)\n\ns.match(/(?:[\\0-\\uD7FF\\uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF])/g)\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_245",
"question": "JS如何优雅的创建连续元素的数组\nRT, 仅供娱乐,不喜勿喷。\n下边是常规的实现方式\n```\nfunction ls(count) {\n var a = [], b = 1;\n for (; b <= count; b++)\n a.push(b);\n return a;\n}\n\nls(6); // [1, 2, 3, 4, 5, 6]\n```",
"answer": "```\nArray.apply(Array, Array(20)).map((v, k) => k)\n```\n```\n[...Array(20)].map((v, k) => k)\n```\n```\n' '.repeat(20).split('').map((v, k) => k)\n```\n```\nArray.from({ length: 20 }).map((v, k) => k)\n```\n```\nArray.from(function* gen(i, l) {\n while(i < l) yield i++;\n}(0, 20));\n```\n```\nObject.keys([...Array(20)]) // 字符串\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_246",
"question": "小白提问python 在什么时候用函数,什么时候用类?\n半路自学的编程小透明刚刚接触python这门语言。现在有个疑问想请教大家。\n我想问的是大家是如何判断、以及用什么标准来决定什么时候使用函数什么时候使用类\n函数还好说一段代码需要重复使用的时候用函数会减少代码量。\n但是我遇到了这样一个实例由于目前思想上更习惯使用面向过程编程所以在编写下面这个小小爬虫程序的时候就写成了这样的形式\n```\n# 任务目标是爬取特定网页上图片列表页面的所有图片。\n# 由于是列表页面所以有一个总页数,就使用了 for 循环遍历所有页面,然后下载个页面图片的思路。\n# 大致如下\n\nbase_url = 'xxx/page=' # 网址忽略了\npages = 90 # 假设一共有 90 页\n\nfor page in range(1, pages + 1): # 首先使用 for 遍历列表的每一页,获取所有的 img 标签\n url = base_url + str(page)\n rq = requests.get(url)\n soup = BeautifulSoup(rq.text)\n all_tag_img = soup.find_all('img')\n \n for tag in all_tag_img: # 然后在通过 for 遍历所有标签获取下载地址,下载后保存\n img_url = tag.get('src')\n img = requests.get(img_url)\n # 下面就是获取图片的名称,然后保存什么的了\n \n```\n这样下来的话流程上面感觉比较接近普通浏览的顺序\n但这是这里用不到函数更用不到类但是见到过很多爬虫教程大家会把例如下载图片、获取名称、保存这些东西封装成函数。有些直接就是创建一个爬虫的类然后增加各种功能。\n所有问题就是这样一个任务你们回去用函数或类么为什么\n我觉得编程最难的是思想所有我特别想知道你们是怎么考虑的\n万分感谢",
"answer": "个人觉得其实这个跟你需要完成的任务有关。打个比方你只是自己想写一个程序方便自己工作那你就可以写函数为主反正自己知道这些函数什么意思有时候换地方使用直接copy一下修修改改就好了。\n而如果是完成某个大的项目项目要分很多块那么就必须写类了。有人说我写个函数最终实现起来还不是一样实现起来是一样那么后期维护呢你是更喜欢看一个模块这个模块有几个类还是说喜欢看几十个函数呢显而易见一般稍微有点样子的项目都是分成几个模块每个模块会分出几个类来各自实现某个特定的任务。到代码层的时候才会需要看函数的代码。\n如果一个项目是由按照某些顺序直接调用几十个函数完成的相信后期维护的人会疯吧好气啊全是函数虽然有说明也很费事的吧",
"type": "technical_qa"
},
{
"id": "segmentfault_247",
"question": "Laravel 5.5 中该怎么拦截表单校验失败重定向或者返回JSON的返回格式\n在 laravel 5.1 中 可以在 BaseController 中重写\n```\n/**\n * {@inheritdoc}\n */\n protected function buildFailedValidationResponse(Request $request, array $errors)\n {\n return new JsonResponse($errors);\n }\n```\n可以实现拦截`$this->validate($request,$rules,$messages);`方法的自动跳转\n现在在 laravel 5.5 中没有了这个方法,现在该怎么修改?",
"answer": "我自己回答这个问题吧,希望以后那些自己不能提出解决方案只会说教别人的嘴炮都闭嘴吧。\n一. 仍然使用 控制器 中的`$request->validate($rules);`进行校验,在表单输入不合法的时候,会抛出一个`throw new ValidationException();`错误,可以在`App\\Exceptions\\Handler`的 `render()`方法中去捕获它\n```\n if ($exception instanceof ValidationException) {\n return new JsonResponse($exception->getMessage());\n }\n```\n二. 我们不使用 request 对象中的 validate 方法,自己构造一个验证\n```\n $validator = Validator::make($request->all(), $rules);\n if ($validator->fails()) {\n return new JsonResponse($validator->getMessage());\n }\n```\n推荐使用第一个解决方案仍然可以达到之前的效果代码修改量也最小。",
"type": "technical_qa"
},
{
"id": "segmentfault_248",
"question": "vue element tab切换两个表格第一次点切换进来表格渲染会闪一下这是什么原因\nvue element tab切换两个表格第一次点切换进来表格渲染会闪一下\n```\n <el-tabs v-model=\"activeName\">\n <el-tab-pane label=\"实物\" name=\"first\">\n <!--实物表格-->\n <el-table :data=\"tableData1\" border style=\"width: 100%\" ref=\"multipleTable\" @selection-change=\"handleSelectionChange\">\n <el-table-column prop=\"ordergoods\" label=\"活动订单商品\" align=\"center\"></el-table-column>\n <el-table-column prop=\"consignee\" label=\"收货人信息\"></el-table-column>\n <el-table-column prop=\"buyeraccount\" label=\"下单人账号\" width=\"150\" align=\"center\"></el-table-column>\n </el-table>\n </el-tab-pane>\n <el-tab-pane label=\"虚拟\" name=\"second\">\n <!--虚拟表格-->\n <el-table :data=\"tableData2\" border style=\"width: 100%\" ref=\"multipleTable\" >\n <el-table-column prop=\"virtualOrderGoods\" label=\"活动订单商品\" align=\"center\"></el-table-column>\n <el-table-column prop=\"activationCode\" label=\"激活码\" align=\"center\"></el-table-column>\n <el-table-column prop=\"validityTerm\" label=\"有效期\" align=\"center\"></el-table-column>\n <el-table-column prop=\"buyerAccount\" label=\"下单人账号\" align=\"center\"></el-table-column>\n <el-table-column prop=\"state\" label=\"状态\" align=\"center\"></el-table-column>\n </el-table>\n </el-tab-pane>\n </el-tabs>\n```\n之后再点击切换就是正常的刷新页面第一次进来的时候会闪",
"answer": "使用`v-if`控制`el-tab-pane`里的内容是可以的,亲测有效\n例如`v-if=\"activeName === 'second'\"`\n例子详见\nhttps://jsfiddle.net/athena03...",
"type": "technical_qa"
},
{
"id": "segmentfault_249",
"question": "python写爬虫较node和PHP有什么优势\n## 问题\n- \npython 写爬虫较php有什么优势\npython和php的话都简单易学。python其实内置类型实现上更优雅都面向对象了别的有什么优势嘛\n- \npython 写爬虫较node有什么优势\nnode模拟js环境方便点python能做到多线程别的有什么优势嘛",
"answer": "都是 `图灵完备` 的语言,不存在什么这语言能做,那语言不能做这种问题,顶多就是实现其实复杂不复杂。\n你说的几种语言都有一些良好的抓取库。\nPython 爬虫的优势就是\n1、名气大大家都知道\n2、大家都是用贡献代码\n以上 2 点良性循环。\n难道爬个简单的网页PHP Node 做不到么。",
"type": "technical_qa"
},
{
"id": "segmentfault_250",
"question": "H5商城项目里关于价格运算是由前端来做还是后端来做\n公众号里的h5商城项目比如买下选择了三个糖果点立即购买跳到结算页结算页有个“合计”多少钱像这种运算都是把商品价格和数量传给后端再从后端拿到还是前端自己算出来不过js浮点运算有精度问题是都交给后端来算吧",
"answer": "其实这个问题根本就不用问,因为必须后端算 。并且过程是这样的 。\n1、后台加载订单或者商品这里订单的总价可以是前端算但是注意精度。\n2、当有代金券或者优惠券等减少金额的也可以在前端算 。但是只是提供展示。\n3、订单提交把订单中的商品信息带过去包括订单金额、优惠券之类都提交过去。\n4、后端接到信息后应该根据订单中有的商品重新查数据库得到准确的价格重新计算然后如果有代金券要校验代金券的真实性和有效性然后再计算总价。这个总价是有意义的决定着最后支付的金额多少。\n5、有人肯定会问、那前端的总金额提交后台有什么用可以做一个对比如果计算的结果和前端的总价有区别那证明这个订单有问题 。要么是页面没刷新导致商品价格、代金券之类有偏差可以直接返回到对应的提示页面告诉用户刷新重新提交订单。另外有可能信息被篡改那同样的处理如果是0.01这种,需要记录日志做对应的处理惩罚或者预防 。\n手机打字不容易有帮助请采纳和点赞。?",
"type": "technical_qa"
},
{
"id": "segmentfault_251",
"question": "前后端分离项目,你们是怎么控制权限的?\n已经做前后端分离 快一年了\n技术栈趋向成熟\n- vue\n- vue router\n- vuex\n- node\n- express\n做出来的是单页面应用但是在权限上一直都有问题。\n现在我做权限 是 后台有一套,前端又有重复的一套,麻烦就在这里,\n- 只有我对后台有请求的时候,我才知道用户到底有没有这个权限「因为前台的权限,就存在 localSorage 里面,用户可以更改」,如果请求发现没权限,还是前端 router 跳到没权限或者登录页,但是如果这个页面没有请求呢。\n- \n因为是一个管理系统权限特别细比如某些用户只有这几个目录可以看其他用户只有那几个目录可以看但我用的是前端路由问题又来了。\n\n前端路由一般都是配置好的我怎么让用户一进来就跳到他自己有权限的页面的第一页。\n如果用户直接输入 一个没有权限进入的地址 我该怎么拦截「须知我的拦截其实没有意义,因为页面都在他那里,他只需要改掉我的拦截代码就行」\n\n\n因为是一个管理系统权限特别细比如某些用户只有这几个目录可以看其他用户只有那几个目录可以看但我用的是前端路由问题又来了。\n- 前端路由一般都是配置好的,我怎么让用户一进来就跳到他自己有权限的页面的第一页。\n- 如果用户直接输入 一个没有权限进入的地址 我该怎么拦截「须知我的拦截其实没有意义,因为页面都在他那里,他只需要改掉我的拦截代码就行」\n这里 我现在的解决方案是\n- 还是后台传给我 详细的权限,用于我铺设页面,如果这个没有权限,导航上也是没有显示的,但是这样还是可以被更改。\n- \n第二个 用户登录 就会跳他能看到页面的第一个。\n\n首先 路由上 是全部都注册好的\n请求之后拿到权限然后根据权限 生成导航数组\n然后自动页面跳到导航数组的 第一个\n切换页面的时候都要去根据导航数组判断他是否有这个页面权限。\n\n\n第二个 用户登录 就会跳他能看到页面的第一个。\n- 首先 路由上 是全部都注册好的\n- 请求之后拿到权限,然后根据权限 生成导航数组\n- 然后自动页面跳到导航数组的 第一个\n- 切换页面的时候,都要去根据导航数组判断他是否有这个页面权限。\n但是我觉得自己的办法太笨拙而且还是会被篡改所以求解答疑惑谢谢了。",
"answer": "我觉得您的问题应该是不存在的。\n后端做了权限控制无权看到的内容就不会返回了即使你请求了这个接口。\n前端也控制了权限无权访问的页面导航中就不会显示了如果用户自己在前端修改了前端的数据或者跳过你给的导航直接通过url访问对应的页面也应该不会有什么大问题因为即使他能在前端访问到那个页面但每个页面都有对应的内容数据显示内容的时候是需要请求后端的后端没有权限打开页面也只能是空白。\n你只要后端做好了权限控制前端无论怎么改也应该是不能获取到自己没有权限的内容的。\n从数据安全的角度来说前端可以完全不使用权限控制如果你那里做不到这点的话那么你后端的权限控制肯定是有问题的。\n前端的权限控制只是为了给用户更好的体检并不是真的拿来控制权限的。",
"type": "technical_qa"
},
{
"id": "segmentfault_252",
"question": "报错Cannot assign to read only property 'exports' of object\n```\nexport default {\n data(){\n return {\n currentPage: 'findMusic',\n currentCut: 'discover',\n }\n },\n name: 'home',\n components: {\n headTop\n },\n mounted(){\n new Swiper('.swiper-container', {\n loop: true,\n autoplay: 3000,\n autoHeight: true,\n grabCursor: true,\n prevButton: '.swiper-button-prev',\n nextButton: '.swiper-button-next',\n pagination: '.swiper-pagination',\n });\n }\n}\n```\n```\nimport '../plugins/swiper-3.4.2.min.js'\nimport '../styles/swiper.min.css'\n```\n```\n<div class='swiper-container'>\n <div class='swiper-wrapper'>\n <div class='swiper-slide'><img src='../assets/slide/slide1.jpg'/></div>\n <div class='swiper-slide'><img src='../assets/slide/slide2.jpg'/></div>\n <div class='swiper-slide'><img src='../assets/slide/slide3.jpg'/></div>\n <div class='swiper-slide'><img src='../assets/slide/slide4.jpg'/></div>\n <div class='swiper-slide'><img src='../assets/slide/slide5.jpg'/></div>\n <div class='swiper-slide'><img src='../assets/slide/slide6.jpg'/></div>\n </div>\n <div class='swiper-pagination'></div>\n <div class='swiper-button-prev swiper-prev'></div>\n <div class='swiper-button-next swiper-next'></div>\n </div>\n```\n网上搜索说的是 import 和 module.export不能混用可是我这里没有混用啊。。。晕麻烦简单直接地回答一下就行",
"answer": "需要引入插件 babel-plugin-transform-es2015-modules-commonjs\n然后在 .babelrc中配置 { \"plugins\": [\"transform-es2015-modules-commonjs\"] }",
"type": "technical_qa"
},
{
"id": "segmentfault_253",
"question": "python的for循环同时遍历两个list?\n```\nb = [1, 2, 3]\nc = [(10, 20), (30, 40), (50, 60)]\n\nfor i, j in b, c:\n print(i, j)\n\n```\n```\nValueError: too many values to unpack (expected 2)\n```\n```\nb = [1, 2]\nc = [(10, 20), (30, 40)]\n\nfor i, j in b, c:\n print(j)\n```\n```\n2\n(30, 40)\n```\n这输出到底是怎么回事啊, 不能这么遍历吗...\n为什么我印象中有这种用法呢...\n`dict.items()` 就能用:\n```\nfor key, value in x.items()\n```\n遍历..",
"answer": "當你寫出 `b, c` 的時候, Python 會以為你要製造一個 tuple, 所以:\n```\nfor i, j in b, c:\n```\n相當於:\n```\nfor i, j in (b, c):\n```\n當 `b = [1, 2, 3]` 且 `c = [(10, 20), (30, 40), (50, 60)]` 時就相當於:\n```\nfor i, j in ([1, 2, 3], [(10, 20), (30, 40), (50, 60)]):\n```\n所以第一個迭代到的對象是 `[1, 2, 3]`, 而這個 list 有三個元素自然是無法拆解成兩個變量 `i` 和 `j` 的。\n但如果 `b = [1, 2]` 且 `c = [(10, 20), (30, 40)]`,則相當於:\n```\nfor i, j in ([1, 2], [(10, 20), (30, 40)]):\n```\n第一個迭代到的對象是 `[1, 2]`, 該 list 有兩個元素恰能 unpack 為 `i` 和 `j`,所以下面的語法是能夠順利運行的。\n回到你的需求若要平行迭代兩個 list你需要的是 `zip` 或 `zip_longest`,你可以參考 @Python爬虫分享 的範例。\n我回答過的問題: Python-QA",
"type": "technical_qa"
},
{
"id": "segmentfault_254",
"question": "gulp和webpack究竟有什么区别\n我学了这两款工具之后发现他们做的事情基本上都是一样的啊比如说整合好几个js文件模块成一个文件然后进行压缩和检查语法或者调用bable和sass编译器把他们编译成浏览器可以用的文件包括gulp的watch在webpack里面也有插件可以实现这个功能那么他们区别究竟是什么呢\n我百度了半天很多人只是从用法上说了他们的区别webpack是写好配置文件然后webpack自己按照配置文件来执行前端构建流程而gulp是直接自己写流程就像linux下写sh那样那么这只是用法上的区别从他们的执行结果和功能来看我看不出啥区别啊。。。",
"answer": "Gulp 的定位是 Task Runner, 就是用来跑一个一个任务的。\n放在以前比如我想用sass写css, coffee写js, 我必须手动的用相应的compiler去编译各自的文件然后各自minify。这时候designer给你了两张新图片好嘞接着用自己的小工具手动去压缩图片。\n后来前端人不能忍了搞出个自动化这个流程的 Grunt/Gulp, 比如你写完代码后要想发布production版本用一句 `gulp build` 就可以\n1. `rm` 掉 dist文件夹中以前的旧文件\n2. 自动把sass编译成css, coffee编译成js\n3. 压缩各自的文件压缩图片生成图片sprite\n4. 拷贝minified/uglified 文件到 dist 文件夹\n\n但是它没发解决的是 js module 的问题,是你写代码时候如何组织代码结构的问题.\n之前大家可以用 require.js, sea.js 来 require dependency, 后来出了一个 webpack 说 我们能不能把所有的文件(css, image, js) 都用 js 来 生成依赖最后生成一个bundle呢 所以webpack 也叫做file bundler. \n\n同时 webpack 为了解决可以 require 不同文件的需求引入了loader, 比如面对sass文件有\n1. sass-loader, 把sass 转换成 css\n2. css-loader, 让 webpack 能识别处理 css\n3. style-loader, 把识别后的 css 插入到 html style中\n类似的识别es6 有babel-loader\n\n本来这就是 webpack 的初衷require everything, bundle everything. 一开始 webpack 刚出来的时候大家都是把它结合着 gulp 一起用的, gulp 里面有个 gulp-webpack就是让 webpack 专门去做module dependency的事情, 生成一个bundle.js文件然后再用 gulp 去做一些其他杂七杂八minify, uglify的事情。 后来人们发现 webpack 有个plugins的选项 可以用来进一步处理经过loader 生成的bundle.js于是有人写了对应的插件 所以minify/uglify, 生成hash的工作也可以转移到webpack本身了挤掉了gulp这部分的市场份额。 再后来大家有发现 npm/package.json 里面的scripts 原来好好用啊,调用任务的时候就直接写一个简单的命令,因为 gulp 也不就是各种插件命令的组合呀,大部分情况下越来越不需要 gulp/grunt 之类的了 ref. 所以你现在看到的很多新项目都是package.json里面scripts 写了一堆外部只需要一个webpack就够了。 \n\n打个不恰当的比方webpack就像微信一样本来就是做聊天(module dependency)的,后来生生搞出一个微信小程序(processing files)大家面对简单的需求发现这个比原生app方便使用啊于是开发原生的人越来越少一样。\n\n所以 LZ 一开始就模仿其他项目用 npm scripts + webpack 就好了,当你发现有哪些任务你没法用 webpack 或者npm scripts 解决起来麻烦, 这个时候再引入task runner 也不迟",
"type": "technical_qa"
},
{
"id": "segmentfault_255",
"question": "vue项目如何引入babel-polyfill \nbabel-pollyfill 官方说的是:\n```\nWith webpack.config.js, add babel-polyfill to your entry array:\n```\n```\nWith webpack.config.js, add babel-polyfill to your entry array:\nmodule.exports = {\n entry: [\"babel-polyfill\", \"./app/js\"]\n};\n```\n但是项目没有webpack.config.js 倒是有 build/webpack.base.conf.js。 但是里面的结构为:\n```\nmodule.exports = {\n entry: {\n app: './src/main.js'\n },\n output: {\n path: config.build.assetsRoot,\n filename: '[name].js',\n publicPath: process.env.NODE_ENV === 'production'\n ? config.build.assetsPublicPath\n : config.dev.assetsPublicPath\n }\n...\n```\nentry: [\"babel-polyfill\", \"./app/js\"] 该怎么加进去呢?",
"answer": "main.js 里面引入\n```\nimport 'babel-polyfill'\n```\nwebpack.base.conf.js 替换到entry部分\n```\n entry: {\n // app: './src/main.js'\n app: [\"babel-polyfill\", \"./src/main.js\"]\n },\n```\n注意多试一下清空缓存多试试我也是捣鼓捣鼓才可以的",
"type": "technical_qa"
},
{
"id": "segmentfault_256",
"question": "vue组件created中创建的setInterval定时器离开页面之后仍然在执行怎么让它停止下来等下次进来的时候再执行\n如果离开页面还在执行那么以后每次点击进来岂不是都会重新执行setInterval创建一个定时器",
"answer": "解决办法如下:\n```\ndata: {\n return {\n timer: null\n }\n},\ncreated() {\n this.timer = setInterval(....);\n},\nbeforeDestroy() {\n if(this.timer) { //如果定时器还在运行 或者直接关闭,不用判断\n clearInterval(this.timer); //关闭\n }\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_257",
"question": "iView中Table通过render添加一个Input如何双向绑定数据\n有一个Table\n```\n<Table :columns=\"columns\" :data=\"data\" :border=\"true\"></Table>\n```\nJS代码如下\n```\n export default {\n data(){\n return {\n columns:[],\n data:[{name:11111,name2:'加工精度',value:'',key:''}]\n }\n },\n created(){\n this.init();\n },\n methods:{\n init(){\n let vm = this;\n this.columns = [\n {\n title: '序号',\n key: 'name'\n },\n {\n title: '检验项名称',\n key: 'name2'\n },\n {\n title: '检验值',\n key:'value',\n render: (h, params) => {\n return h('Input',{\n props:{\n type:'text',\n value:vm.data[params.index].value //此处如何让数据双向绑定\n },\n on:{\n 'on-change':(event) => {\n console.log(params)\n }\n }\n })\n }\n },\n {\n title: '检验结论',\n key:'key',\n render: (h, params) => {\n return h('Select',[\n h('Option', {\n props: {\n value: '1',\n }\n }, '合格'),\n h('Option', {\n props: {\n value: '2',\n }\n }, '不合格')\n ]);\n }\n },\n ]\n },\n get(){\n console.log(this.data)\n }\n }\n }\n```",
"answer": "```\nrender: (h, params) => {\n return h('Input',{\n props:{\n type:'text',\n value:vm.data[params.index].value\n },\n on:{\n 'on-blur':(event) => {\n vm.data[params.index].value = event.target.value;\n }\n },\n })\n }\n```\n通过这个方法可以解决",
"type": "technical_qa"
},
{
"id": "segmentfault_258",
"question": "vue watch怎样同时监听两个值的变化并执行方法\n```\nwatch:{\n city(cur,old){\n this.loadTop();\n },\n country(cur,old){\n// this.loadTop();\n },\n }\n```\n如上我想在城市和国家都变化的时候执行刷新的方法而不是单一执行刷新",
"answer": "用computed定义一个address对象吧然后再去watch addres\n```\ndata() {\n return {\n city: '',\n country: ''\n }\n},\ncomputed: {\n address() {\n const { city, country } = this\n return {\n city,\n country\n }\n }\n},\nwatch: {\n address: {\n handler: function(val) {\n console.log('address change: ', val)\n },\n deep: true\n }\n}\n\n```\n只的在computed里面调用也行不过要使用$nextTick不然值会是更新前的值。\n```\ndata() {\n return {\n city: '',\n country: ''\n }\n},\ncomputed: {\n address() {\n const { city, country } = this\n this.$nextTick(() => {\n console.log(this.city, this.country, 3333)\n })\n return {\n city,\n country\n }\n }\n},\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_259",
"question": "vue怎么在beforeCreate里获取data\n被问的一个面试题vue怎么在beforeCreate里获取data",
"answer": "1. 异步方式获取data。this.$nextTick或者setTimeout都行。相当于在初始化前告诉容器等全执行完了再跑里面的代码。 这种方式别说拿data了拿渲染完DOM都OK~\n2. 同步方式的话是要了解框架内部原理的。在beforeCreate前所有的options都会先存到`vm.$options`中在beforeCreate之后将`$options`里的data啦props啦methods啦等等一个个附到vm上然后再触发created钩子。所以在beforeCreate的时候通过this.message是拿不到值的在created的时候就能通过this.message拿到值了。\n\n一定要在beforeCreate的时候就同步去拿data里的值的话就是直接从`this.$options.data`里去拿。如果data中的初始值是简单的string那直接`this.$options.data()[\"message\"]`就好.涉及到复杂点的情况建议看看源码里是怎么处理的具体在core/instance/state.js中的initData(vm)里。\n但是实际情况中从来没遇到过需要在组件还没初始化就去拿data的……",
"type": "technical_qa"
},
{
"id": "segmentfault_260",
"question": "redis连接池问题\n比如就一个服务A部署在服务器1上。\nredis部署在服务器2上。\n\n为什么还会需要redis连接池这个东西我在服务A上维护一个全局变量的redis连接实例前端请求过来我都是用这个连接实例去执行redis指令不也可以吗\n\n redis连接池无非就是高并发的时候可以支持多个redis连接实例去连接redis但是redis本身就是单线程的我多个连接同时去连redis不还是得排队么然后执行指令和我单个全局连接直接去一个个执行redis指令感觉应该差不多性能吧\n\n而且如果是全局单个redis连接的话每次请求过来我还省了连接这个操作不是又省了点时间么",
"answer": "您的说法并不正确。\n\n1. redis本身是单线程的没有问题但这并不表示使用连接池不能提供效率只是不能通过多线程提高效率而已。\n2. redis连接池较单链接的效能提高很多。要了解为什么redis连接池能够这么大幅的提高性能就要了解单链接的性能瓶颈在哪。\n单线程并 不是redis性能瓶颈。对redis而言有两个性能所在一个是计算性能也就是所谓的执行命令速度另一个是网络通信性能。很显然redis较执行效率而言通信才是其瓶颈。据我所知不一定正确但也相差无几redis执行命令大概是10w/s因此对于客户端 将若干条若干条显然不会很大命令传输给redis服务命令执行时间和通信时间比等于0.(假设以1s举例几条命令传输时间为40ms, 而每秒可执行10w个命令即n/10w 秒就可执行完毕,等待下一个命令到来的时间间隙(约39ms多)redis没有任何命令执行)这就造成了redis闲置。\n综上要提高redis的性能可以降低单位时间内的通信成本。那么连接池就是一个不错的选择。\n客户端使用连接池+多线程方案使得使得redis服务闲置时间降低极大地提高了服务效率。",
"type": "technical_qa"
},
{
"id": "segmentfault_261",
"question": "return 对代码可读性的影响\n在函数中是否应该控制尽量少的 `return` 出口?\n比如 (以 `PHP` 代码举例):\n```\n<?php\n\n/**\n * 控制尽量少的退出点\n */\nfunction foo1($var)\n{\n try {\n if (empty($var)) {\n throw new \\Exception('emty var');\n }\n\n if (!is_string($var)) {\n throw new \\Exception('var must be string');\n }\n\n return sprintf(\"input-var:%s \\n\", $var);\n } catch (\\Exception $e) {\n return sprintf(\"error:%s \\n\", $e->getMessage());\n }\n}\n\n/**\n * 不控制,可以结束的时候直接 return\n */\nfunction foo2($var)\n{\n if (empty($var)) {\n return 'error:empty var' . PHP_EOL;\n }\n\n if (!is_string($var)) {\n return 'error:var must be string' . PHP_EOL;\n }\n\n return sprintf(\"input-var:%s \\n\", $var);\n}\n\n```\n### 常见观点\n#### 正面:应该控制\n- 过多的 `renturn`,增加了函数出口点,不利于代码阅读\n#### 反面:没必要\n- 多个 `return` 也没什么,类似 `try-catch` 在效率上有所损失,尽量少用\n#### 中立\n- 两种写法只是跟人风格问题,没有优略\n- 短函数多个 `return` 无伤大雅,但是长函数中,会严重降低可读性\n欢迎留下你的观点。\n我的观点\n无论是短函数还是长函数都尽量控制一下 `return` 点,因为短函数随着迭代可能会变成长函数。\n而且多个 `return` 会明显降低长函数的可读性。\n对于 `try-catch` 结构,在性能上的一丁点牺牲,换来的可读性提升,是值得的。",
"answer": "观点与你相反,函数中要尽可能多的使用 return 来控制,因为 return 从设计上来说就是这个功能,表示执行权限的移交。这样不会造成任何执行权限的问题。所谓函数,从设计之初,核心就是计算和返回。\n滥用 try catch 会导致上级 try catch 无法正确捕获异常\n语义化上来说return 也比 try catch 更加清晰明了。",
"type": "technical_qa"
},
{
"id": "segmentfault_262",
"question": "@Service是标记在接口上还是实现类上\n@Service是标记在接口上还是实现类上",
"answer": "`@Service`注解是标注在实现类上的,因为`@Service`是把`spring`容器中的`bean`进行实例化,也就是等同于`new`操作,只有`实现类`是可以进行`new`实例化的,而`接口`则不能,所以是加在`实现类`上的。",
"type": "technical_qa"
},
{
"id": "segmentfault_263",
"question": "webpack(config,function(){}) , 这个函数的第二个参数有什么作用?\n```\nvar webpack = require('webpack')\nvar webpackConfig = require('./webpack.config.js')\n\nwebpack(webpackConfig, function(err, stats) {\n process.stdout.write(stats.toString({\n colors: true,\n modules: false,\n children: false,\n chunks: false,\n chunkModules: false\n }))\n \n})\n```\n请问webpack(config,function(){}) 这个函数的第二个函数里面的内容有什么作用?",
"answer": "对打包的配置化如果打包的时候有错误我们就抛出错误我们可以在webpack()回调里拿到一个stats打包状态process.stdout.write跟console.log一个意思因为在node环境里console.log也是用process封装的就是向cli里打印输出。但是输出的时候进行了一些格式化。 colors 让打包的时候有颜色。 module : 去掉内置模块信息 children :去掉子模块 chunks : 增加包信息(设置为 false 能允许较少的冗长输出chunkModules : 去除包里内置模块的信息",
"type": "technical_qa"
},
{
"id": "segmentfault_264",
"question": "esLint里no-case-declarations的意义在哪\n官网的解释The reason is that the lexical declaration is visible in the entire switch block but it only gets initialized when it is assigned, which will only happen if the case where it is defined is reached.\n没怎么看懂",
"answer": "有中文网站 no-case-declarations\n为了保证词法声明语句只在当前 `case` 语句中有效,将你子句包裹在块中。 \n该规则旨在避免访问未经初始化的词法绑定以及跨 `case` 语句访问被提升的函数。\n```\nswitch (foo) {\n case 1:\n let x = 1;\n break;\n case 2:\n const y = 2;\n break;\n case 3:\n function f() {}\n break;\n default:\n class C {}\n}\n```\n大概是指上面`case 1`里的`x`在`case 2`里也会生效,所以要用`{}`包起来,防止`x`提升到整个`switch`语句。",
"type": "technical_qa"
},
{
"id": "segmentfault_265",
"question": "锤子科技官网banner的动效是如何实现的\n锤子科技官网banner的动效是如何实现的呢就是图片随鼠标的轨迹移动的动效。以及上方图片文字动效。是CSS3吗\n地址https://www.smartisan.com/",
"answer": "```\n<style type=\"text/css\">\n .content{\n margin:200px auto;\n width:200px;\n height:200px; \n background: #db473c; \n color:#fff; \n }\n .container {\n transform-style: preserve-3d;\n perspective: 500px;\n }\n </style>\n <div class=\"container\">\n <div class=\"content\"></div>\n </div>\n <script type=\"text/javascript\">\n (function(){\n var content=document.querySelector(\".content\")\n content.onmousemove=function(e){\n var evt=e||window.event;\n var rotateY=-(content.clientWidth/2-evt.offsetX)/10;\n var rotateX=(content.clientHeight/2-evt.offsetY)/10;\n content.style.transform=`rotateX(${rotateX}deg) rotateY(${rotateY}deg)`\n }\n }\n )()\n \n </script>\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_266",
"question": "js数组重组\n现在有一个数组类似于\nvar a=[{name:\"May\",age:12,id:1},{name:\"Jone\",age:13,id:5},{name:\"May\",age:15,id:6}];\n要把所有name相同的对象重组大概成为这样的数组\nvar b = [{\n```\nname: \"May\",\nlist: [{\n name: \"May\",\n age: 12,\n id: 1\n}, {\n name: \"May\": age: 15,\n id: 6\n}]\n```\n}, {\n```\nname: \"Jone\",\nlist: [{\n name: \"Jone\",\n age: 13,\n id: 5\n}]\n```\n}]",
"answer": "```\nconst a = [{ name: \"May\", age: 12, id: 1 }, { name: \"Jone\", age: 13, id: 5 }, { name: \"May\", age: 15, id: 6 }]\n\nlet result = Object.values(a.reduce((m, n) => {\n if (!m[n.name]) {\n m[n.name] = {name: n.name, list: []}\n }\n m[n.name].list.push(n)\n return m\n}, {}))\n\nconsole.log(result)\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_267",
"question": "CSS3如何查看获取scale缩放后的元素宽高\n代码如下\n```\n<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <title>text</title>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <!-- <link href=\"css/style.css\" rel=\"stylesheet\"> -->\n <style type=\"text/css\">\n *{\n margin:0;\n padding: 0;\n }\n html,body{\n height: 100%;\n width: 100%;\n }\n .fa{\n height: 100%;\n background-color:green;\n }\n .small{\n width: 100px;\n height: 100px;\n background-color: red;\n }\n </style>\n </head>\n <body>\n <div class=\"fa\">\n <div class=\"small\"></div>\n </div>\n <script src=\"http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js\"></script>\n <script type=\"text/javascript\">\n $(document).ready(function(){\n var faH=$(\".fa\").height();\n var faW=$(\".fa\").width();\n var smH=$(\".small\").height();\n var smW=$(\".small\").width();\n console.log(\"父盒子的高度:\"+faH);\n console.log(\"父盒子的宽度:\"+faW);\n var overviewheight=100;\n var overviewwidth=100;\n var scaleY=faH/overviewheight,\n scaleX=faW/overviewwidth;\n console.log(\"Y的比例:\"+scaleY+\" X的比例:\"+scaleX);\n $(\".small\").css(\"transform\",\"scaleY(\"+scaleY+\")\"+\"scaleX(\"+scaleX+\")\");\n console.log(\"子盒子的高度:\"+smH);\n console.log(\"子盒子的宽度:\"+smW);\n })\n </script>\n </body>\n</html>\n```\nscale属性设置后盒子还是占用原来的宽高但实际上大小已经发生了变化我试过用`getBoundingClientRect()`方法,发现获取到的数值不是这个元素的,不准确。\n请问有更好的方法吗",
"answer": "我也遇到了这样的问题,解决方法是通过getBoundingClientRect()方法.\n比如:\n-js代码如下\n```\n let Div = document.getElementsByTagName('div')\n Div.getBoundingClientRect().width;//获取div放大(缩小)后的宽度\n Div.getBoundingClientRect().height;//获取div放大(缩小)后的高度\n```\n-css代码如下\n```\ndiv {\n width: 100px;\n height: 100px;\n background: #ccc;\n text-align: center; \n line-height: 100px; \n -webkit-transform: scale(2);\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_268",
"question": "怎么通过点击事件关闭Element ui 的Notification 通知\n点击打开弹出通知点击关闭怎么关闭通知\n```\n<div>\n <el-button plain @click=\"open\">打开</el-button>\n <el-button @click=\"close\">关闭</el-button>\n</div>\n\nmethods: {\n open() {\n this.$notify({\n title: '提示',\n message: '这是一条不会自动关闭的消息',\n duration: 0\n });\n },\n close() {\n this.$notify.close()\n }\n }\n```",
"answer": "this.$notify 会返回当前 Notification 的实例\n```\nmethods: {\n open() {\n this.instance = this.$notify({\n title: '提示',\n message: '这是一条不会自动关闭的消息',\n duration: 0\n });\n },\n close() {\n this.instance.close()\n }\n }\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_269",
"question": "用script的方式引入vue的情况怎么impor其他的.vue文件作为组件使用\n因为项目需要构建项目时候使用传统的多页方式我的vue也是通过script方式来引入的没有使用构建工具但我之前写的.vue文件怎么引入到现在的项目中呢直接import也不行求解",
"answer": "目前我司项目有这种情况, 传统多页项目, 有许多公共样式我通过封装组件引用的, 比如:\n`header.js`\n```\nvar headerTemplate = '<div> header HTML 代码</div>'\nVue.component('my-header', {\n template: headerTemplate,\n data: xxx,\n methods: {}\n // ...\n})\n\n```\n通过 `script`标签引入 `header.js`, 然后在 header.html 内就可以使用了, 比如:\n```\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>Document</title>\n <script src=\"vue.min.js\"></script>\n <script src=\"header.js\"></script>\n</head>\n<body>\n <div id=\"main\">\n <my-header></my-header>\n </div>\n\n\n <script>\n new Vue({\n el: '#main'\n })\n </script>\n</body>\n</html>\n```\n希望可以帮助到你",
"type": "technical_qa"
},
{
"id": "segmentfault_270",
"question": "小程序里如何使页面自动滚动到底部?\n在更新数据后以及初次进入页面希望页面停留在最底部\n因为内容中有video不能使用scroll-view来实现看页面有监听滚动的函数但没有控制滚动的那么怎样可以实现呢",
"answer": "```\n// 获取容器高度,使页面滚动到容器底部\n pageScrollToBottom: function() {\n wx.createSelectorQuery().select('#j_page').boundingClientRect(function(rect){\n // 使页面滚动到底部\n wx.pageScrollTo({\n scrollTop: rect.bottom\n })\n }).exec()\n },\n```\n- \n`j_page`为页面容器的id\n- 使用`rect.bottom, rect.height`均能达到滚动到底部的效果\n- 在数据更新后setData回调函数使用\n\n相关api文档\nhttps://mp.weixin.qq.com/debug/wxadoc/dev/api/scroll.html\nhttps://mp.weixin.qq.com/debug/wxadoc/dev/api/wxml-nodes-info.html#nodesrefboundingclientrectcallback",
"type": "technical_qa"
},
{
"id": "segmentfault_271",
"question": "数据库SQL查询问题一道面试题查了好久也没搞定来SF求助\n数据库中有张表\n表的定义为name, address,arrive_time,\n数据为 \n张三北京1000 ; \n张三 河北12:00 。\n怎么查询显示结果为 张三, 北京 河北, 12:00",
"answer": "```\nSELECT name, GROUP_CONCAT(DISTINCT address SEPARATOR ' ') AS address, max(arrive_time) AS arrive_time\nFROM mytable\nGROUP BY name\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_272",
"question": "react设置多个className\n在一个元素上设置样式有一个固定的样式然后还有一个使用三元运算符根据条件添加的样式。\n```\n比如说有一个固定样式\"title\":\n<div className=\"title\">标题</div>\n然后还要一个点击高亮的样式:\n<div className={index === this.state.active ? \"active\" : null}>标题</div>\n不能这样写\n<div className=\"title\" className={index === this.state.active ? \"active\" : null}>标题</div>\n```\n那多个样式有字符串有表达式应该怎么写到一起",
"answer": "ES6 模板字符串 ``\n```\nclassName={`title ${index === this.state.active ? 'active' : ''`}\n```\n或\n`classnames`\n参照classnames",
"type": "technical_qa"
},
{
"id": "segmentfault_273",
"question": "vue这个三个点...mapGetters为什么要把computed转换成数组\n```\n<script>\n import { mapGetters } from 'vuex'\n export default {\n computed: {\n ...mapGetters({ //不理解为什么要把这个computed的内容转成数组\n goods_list: 'goods_list',\n userInfo:'userInfo'\n })\n }, }\n</script>\n```",
"answer": "```\nmapGetters({ \n goods_list: 'goods_list',\n userInfo:'userInfo'\n});\n```\n这种写法跟下面的写法是等价的。为了写的更简单一目了然\n当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组。\n```\nmapGetters([\n // 映射 this.goods_list 为 store.getters.goods_list\n 'goods_list',\n // 映射 this.userInfo 为 store.getters.userInfo\n 'userInfo'\n])\n\n```\n... 是es6的数组扩展运算符可以同时写多个例如\n```\ncomputed: {\n ...mapGetters([ 'goods_list','userInfo']),\n ...mapGetters({\n // 映射 `this.doneCount` 为 `store.getters.doneTodosCount`\n doneCount: 'doneTodosCount'\n })\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_274",
"question": "VSCode中使用vetur插件格式化vue文件时js代码会被添加上分号且单引号会转变为双引号\n由于vetur插件报错找不到某某组件于是卸载重装。 装回后插件不再报错但是格式化vue代码时会执行两条多余的规则与未重装之前比较\n- 自动为js代码加上分号结束符\n- 自动将单引号变换为双引号\n由于在配置setting.json中未找到相应的配置故很疑惑应如何取消掉以上两条规则\n2018/11/29 更新\n```\n//VSCODE扩展当前时间的最新版\nvscode version 1.29.1\nprettier version: 1.7.2\nvetur version: 0.14.2\n\n```\n也会出现上述问题解决办法修改 User Settings\n```\n \"vetur.format.defaultFormatterOptions\": {\n \"js-beautify-html\": {\n // force-aligned | force-expand-multiline\n \"wrap_attributes\": \"force-aligned\"\n },\n \"prettyhtml\": {\n \"printWidth\": 100,\n \"singleQuote\": false,\n \"wrapAttributes\": false,\n \"sortAttributes\": true\n },\n // --- 解决问题 ---\n \"prettier\": {\n \"semi\": false,\n \"singleQuote\": true\n }\n // --- 解决问题 ---\n },\n```",
"answer": "这是因为在VSCode`1.7.2`中替换了内置格式化插件。解决办法是在VScode设置(setting.json)中,配置如下规则\n```\n{\n \"prettier.singleQuote\": true,\n \"prettier.semi\": false,\n \"vetur.format.defaultFormatter.html\": \"js-beautify-html\",\n \"vetur.format.defaultFormatterOptions\": {\n \"wrap_attributes\": \"force-aligned\"\n }\n}\n```\n即可解决您的问题。详情见https://github.com/vuejs/vetur/issues/476",
"type": "technical_qa"
},
{
"id": "segmentfault_275",
"question": "python 列表生成式怎么理解?\n```\nz=[x if x%3==0 else x%5==0 for x in range(1,9) ]\nprint(z)\n```\n[False, False, 3, False, True, 6, False, False]\n为什么5的地方是True,而不是显示5这个语法怎么理解比较好怎样翻译成一个个具体的instruction来理解",
"answer": "你的代码等效于下面的这一段代码:\n```\nz = []\nfor x in range(1,9):\n if x%3 == 0:\n z.append(x)\n else:\n z.append(x%5 == 0)\n\nprint(z)\n\n```\n这样就应该很清楚了吧。。",
"type": "technical_qa"
},
{
"id": "segmentfault_276",
"question": "在方法内部throw异常必须要同时在方法头部声明throws吗\n下面节选自类 JSONObject:\n```\npublic String getString(String key) {\n this.verifyIsNull();\n Object o = this.get(key);\n if(o != null) {\n return o.toString();\n } else {\n throw new JSONException(\"JSONObject[\" + JSONUtils.quote(key) + \"] not found.\");\n }\n}\n```\n以上直接抛出异常而没有在方法头部声明throws。\n但是我自己写的方法中是同时有throw和throws的。去掉throws就会报错\nUnhundled Exception 。\n这是为什么",
"answer": "java异常一般分为`Checked`异常和`Runtime`异常,所有`RuntimeException`类及其子类的实例被称为`Runtime`异常,不属于该范畴的异常则被称为`CheckedException`。\nJava认为`Checked`异常都是可以被处理的异常所以Java程序必须显示处理Checked异常。如果程序没有处理`Checked`异常,该程序在编译时就会发生错误无法编译。\n而`RuntimeException`异常如果没有显示的捕获处理则由系统自动检测并将它们交给缺省的异常处理程序。\n`JSONException`应该是`RuntimeException`的子类可以不用显式的对它try...catch或者throws.如果没有对该异常的处理会交给jvm处理。\n而你自己写的异常肯定是属于Checked异常被认为是可以避免的异常必须try...catch或者显式的抛出throws不然编译报错。如果你自定义的异常想像`throw new JSONException`这样处理,则你自定义的异常需要继承`RuntimeException`即可。",
"type": "technical_qa"
},
{
"id": "segmentfault_277",
"question": "onmouseover事件为啥鼠标移动时层会闪烁\n```\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n<title>图片说明demo</title>\n <!--样式-->\n <style type=\"text/css\">\n /*主div*/\n #main\n {\n width: 960px; \n height: 600px; \n border: 1px solid #000; \n margin: auto;\n }\n .content\n {\n margin:auto;\n margin-top: 50px;\n width: 99%;\n }\n .photo\n {\n float: left;\n margin-left: 20px;\n cursor: pointer;\n }\n /*图片*/\n .pic\n {\n height: 287px;\n width: 287px; \n border: 1px solid #fc2;\n }\n\n /*文字描述*/\n .des\n {\n display: none;\n width: 289px;\n height: 289px;\n margin-top: -289px;\n border: 1px solid #ce3; \n background-color: #000;\n color: #fff;\n z-index:10px;\n position: relative;\n }\n .detail\n {\n display: none;\n width: 300px;\n height: 200px;\n background-color: #eec;\n }\n </style>\n <!--JS代码-->\n <script type=\"text/javascript\">\n function ShowDes( id ){\n document.getElementById('des'+ id ).style.display = \"block\";\n }\n function ClearDes( id ){\n document.getElementById('des'+ id ).style.display = \"none\";\n }\n function ShowDetail( id ){\n document.getElementById( 'detail'+id ).style.display = \"block\";\n document.getElementById('list_content').style.display = \"none\";\n }\n </script>\n</head>\n<body>\n <div id=\"main\">\n <div id=\"list_content\" class=\"content\">\n <div class=\"photo\">\n <img class=\"pic\" id=\"img1\" onmouseover=\"ShowDes(1)\" onmouseout=\"ClearDes(1)\" src=\"http://img0.bdstatic.com/img/image/sy1204.jpg\" />\n <span id=\"des1\" onclick=\"ShowDetail(3)\" class=\"des\">\n 图片一\n </span>\n </div>\n <div class=\"photo\">\n <img id=\"img2\" class=\"pic\" onmouseover=\"ShowDes(2)\" onmouseout=\"ClearDes(2)\" src=\"http://img0.bdstatic.com/img/image/8034a36acaf2edda3cc7a7cfd3703e93901213f9208.jpg\" />\n\n <span id=\"des2\" class=\"des\">\n 图片二\n </span>\n </div>\n <div class=\"photo\">\n <img class=\"pic\" id=\"img3\" onmouseover=\"ShowDes(3)\" onmouseout=\"ClearDes(3)\" src=\"http://img0.bdstatic.com/img/image/379b8389b504fc2d5625c364ec2e51190ef76c66ce7.jpg\" />\n\n <span id=\"des3\" class=\"des\" >\n 图片三\n </span>\n </div>\n </div>\n <div id = \"detail1\" class = \"detail\" >\n APP详情1\n </div>\n <div id = \"detail2\" class = \"detail\" >\n APP详情2\n </div>\n <div id = \"detail3\" class = \"detail\" >\n APP详情3\n </div>\n </div>\n</body>\n</html>\n\n```\n实现的效果是鼠标放到图片上会显示图片的一个说明文字但是发现鼠标放上去会不停的闪烁求知道原因",
"answer": "原因很简单:\n\n`span.des` 出现后,它遮住了 `img`。也就是说此时你的鼠标已经不在 `img` 上了,而是在 `span.des` 上。于是你稍微一动就触发了 `img` 的 `mouseout` 事件,然后由于 `ClearDes` `span.des` 也就自然而然地消失了。消失以后鼠标相当于又在 `img` 上了,于是又立刻触发 `mouseover` 事件,调用 `ShowDes`,把 `span.des` 显示出来……\n因此它就一直在闪。\n既然你只问原因我就不回答通用的解决方法了。一个在较新的浏览器的解决办法在 `.des` 的 CSS 里加上 `pointer-events: none;`",
"type": "technical_qa"
},
{
"id": "segmentfault_278",
"question": "PHP可变长参数(...)和生成器问题\n问题是关于向redis快速插入大量数据。我使用了1百万个元素数组来插入在我这里是内存溢出的所以我使用了生成器的方式\n```\nfunction xrange() {\n for ($i=0; $i<1000000; $i++) {\n yield $i;\n }\n}\n$r = xrange();\n\n$redis = new Redis();\n$redis->connect('127.0.0.1', 6379);\n\n$key = 'jimu';\n$redis->del($key);\n$begin = microtime(true);\n$redis->sadd($key, ...$r);\n\n$end = microtime(true);\necho ($end - $begin) . \"\\n\";\n```\n输出结果\n```\n[vagrant@localhost ~]$ php redis.php \n1.2786898612976\n[vagrant@localhost ~]$\n```\n然后redis-cli中确实有了一百万个元素。那么当我把代码中的一百万修改为一千万的时候又报内存溢出\n```\n[vagrant@localhost ~]$ php redis.php \nPHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 32 bytes) in /home/vagrant/redis.php on line 6\n\nFatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 32 bytes) in /home/vagrant/redis.php on line 6\n```\n根据我理解的生成器知识不应该出现内存溢出的情况。因为自始至终生成器xrange只占用一个变量`($i)`内存?\n所以我猜测是不是`$redis->sadd($key, ...$r);`这一步的时候`...$r`依然会解析成大数组。 现在不知道如何证实。\n补充\n我在`sadd`之前使用`var_dump(...$r);exit;`发现输出的都是\n```\nint(999775)\nint(999776)\nint(999777)\nint(999778)\nint(999779)\nint(999780)\nint(999781)\n```\n这样可以证明生成器确实是一个一个产出值的。那么为什么将...$r传入到sadd()的时候还报内存不足呢?不明白这个`...`的原理,还请大佬们指点。",
"answer": "a. 这个问题和redis毫无关系\nb. 上代码\n```\n<?php\n//splat.php\nfunction gen() {\n global $argv;\n $max = $argv[1];\n while($max--) {\n yield(str_repeat('x', 10000));\n }\n}\n\nfunction noop() {\n\n}\n\nfunction getargs() {\n $arg = func_get_args();\n}\n\nfunction splat(...$arg) {\n\n}\n\nfunction printmemory($msg) {\n printf(\"%s: %d/%d\\n\", $msg, memory_get_usage(), memory_get_peak_usage());\n}\n\nprintmemory(__LINE__);\n$gen = gen();\nprintmemory(__LINE__);\nforeach(gen() as $r) {\n crc32($r);\n}\nprintmemory(__LINE__);\n$argv[2](...$gen);\nprintmemory(__LINE__);\n```\n```\n~/Desktop $ php splat.php 10000 getargs\n27: 357896/394272\n29: 358504/394272\n33: 370816/394272\n35: 382912/123779064\n~/Desktop $ php splat.php 10000 noop\n27: 357896/394272\n29: 358504/394272\n33: 370816/394272\n35: 382912/123250912\n~/Desktop $ php splat.php 10000 splat\n27: 357896/394272\n29: 358504/394272\n33: 370816/394272\n35: 382912/123779064\n~/Desktop $ php splat.php 1000 splat\n27: 357896/394272\n29: 358504/394272\n33: 370816/394272\n35: 382912/12695544\n~/Desktop $ php splat.php 100 splat\n27: 357896/394272\n29: 358504/394272\n33: 370816/394272\n35: 382912/1607672\n```\nc. 解释\n\n27-29-33之间几乎没有内存占用这是所谓的\"生成器节省内存”的现象也就是各种相关文章里都会解释的在30行迭代生成器的时候每次循环都会进到生成器内部去yield一次产生一个大字符串下次循环的时候循环变量又重新被赋值之前的字符串自然会被GC回收所以无论循环多大多少次占用的内存是稳定的包括上面的`$gen=gen()`也是几乎不占内存的)\n\n33-35无论被调用的函数如何甚至noop函数都一样会占用大量内存占用内存的量明显和次数成正比也就是说生成器的内容被合并到一起而占用了一整块内存。这其实很容易解释几乎的所有语言“调用函数”的过程都是类似的\n1. 首先计算所有参数,形成参数列表\n2. 生成call frame其中包含调用被调双方、文件行号、参数列表等等信息压入call stack中\n3. 控制权移交给函数内部(当然省略了超级多的细节,比如实参形参的映射/copy啊内存管理啊等等什么的和本题无关\n`...$args`这个操作符其实影响的就是第一个阶段,计算参数的时候,看到...操作符,就需要展开其中的参数来形成参数列表,那么用生成器的场合,这个阶段内存就从原有生成器的少量占用变成了完整的占用了,所以即使是空的`noop`函数也会占用几乎一样多的内存,你的理解是正确的\n\n回到原题的那个redis问题的话因为重复调用redis方法一定会占用大量的额外网络开销而一次性批量插入又铁定逃不开内存占用其实你想redis扩展要发送这个批量的指令给redis那么这块内存肯定是要的比较好的方式就是分组了每1000个或者10000个合并成一次$redis调用mysql也好其他场景也是类似的",
"type": "technical_qa"
},
{
"id": "segmentfault_279",
"question": "一道js面试题\n```\nfor(var i=0; i<10; i++){\n setTimeout(function() {\n console.log(i);\n },0)\n}\n```\n请问输出什么\n如果要输出'0123456789',要怎么改?",
"answer": "推荐将 `var` 替换为 `let`,拥抱 es6 吧。\n```\nfor(let i=0; i<10; i++){\n setTimeout(function() {\n console.log(i);\n },0)\n}\n```\n这里简单说明一下为什么如此替换会有效。\n1. \n`var` 命令声明的变量,在全局范围内有效。例中代码,全局只有一个变量 `i`。每一次循环,`i` 的值均会改变,而 `console.log(i)` 里面的 `i` 指向的就是全局的 `i`,导致运行时输出的是最后一轮的 `i` 的值,即 `10`。\n2. \n`let` 命令声明 的变量,仅在块级作用域内有效。修改后的代码,每一次循环的 `i` 都是一个新的变量,所以最后输出 `0123456789`。\n\n另外一点如果每一轮循环的变量 `i` 均为重新声明,那它怎么知道上一轮循环的值?\n因为记得。`JavaScript` 引擎内部会记住上一轮循环的值,初始化本轮的变量 `i` 时,就在上一轮循环的基础上进行计算。",
"type": "technical_qa"
},
{
"id": "segmentfault_280",
"question": "vue.js 如何在页面渲染完后去操作dom而且只执行一次\n我想在页面渲染完执行我的代码,去操作dom。因为我把操作dom的写在加载数据的方法里面发现是选不到dom的应该是这个时候js还没执行完页面还没渲染好。\nvue的created是实例创建完执行一次但是这个时候去操作dom是选不到的。\n还有个update这个倒是可以选到dom,但是这个每次都被执行啊,我只想在执行一次。\n对于这种需求有没有什么好的解决方法",
"answer": "在接口请求成功的回调里使用\n```\nthis.$nextTick(() =>{\n // 在这里面去获取DOM\n})。\n```\n在mounted生命周期组件挂载成功但还未渲染自然获取不到相关的DOM节点。看你资料好像不是前端举个更简单的例子你在html中把 `console.log(document.querySelector('body'))`写在body标签前面代码执行时机先于页面渲染结果就是undefined。\n不推荐用updated, beforeUpdate生命周期这2个生命周期只会在数据发生变化时才触发。如果你请求接口的数据是放在created生命周期我推荐放在created里面去发起请求初次进入页面是不会触发updated, beforeUpdate里面的代码。\n如果你非要要updated并且希望第一次进入页面即可获取到DOM节点那么请在mounted生命周期请求接口数据而不是created了",
"type": "technical_qa"
},
{
"id": "segmentfault_281",
"question": "关于npm的小问题\n自从看了es6的模块引入之后对npm一直有个小问题。 \n比如在`npm install vue --save`之后为什么在页面内引入vue只需要`var Vue = require('vue');` 而不是`var Vue = require('./node_modules/vue/vue');`",
"answer": "Node引入模块一般需要经历3个步骤`路径分析`、`扩展名分析`、`编译执行`。\nNode查找模块的先后顺序`缓存模块 > 核心模块 > 路径形式文件模块 > 自定义文件模块`。\n`缓存模块`Node引入过的模块都会被缓存下来。无论是核心模块还是文件模块require对相同模块的第二次加载一律采用缓存优先的方式其中`核心模块`的缓存检查优先于`文件模块`的缓存检查。\n`核心模块:`Node提供的模块已经是编译后二进制文件。\n`路径形式文件模块:`以.、..和./开头的模块。\n`自定义文件模块:`第三方npm包查找此类模块最耗时且最慢查找先后顺序`当前目录下node_modules目录`、`父目录下node_modules目录`、`向上逐级递归直到根目录下下node_modules目录`因为node_modules文件目录一般都比较深入所以最耗时最慢。\n希望对您有所帮助\n参考资料`深入浅出NodeJS`",
"type": "technical_qa"
},
{
"id": "segmentfault_282",
"question": "js 数组合并问题\n业务描述在日历上显示一个月跑步的日期\n日历这快完全是用前端js实现的所以只需要后台给一个跑步日期的数组插进日历的数组里就行了我的思路是做两层循环但是这样计算量很大有没有更好的方法\n后台返回一个月中跑步的日期\n```\n[1,4,6,8,21]\n```\n前端某月 日历数组\n```\n[{day:1},{day:2}......{day:31}]\n\n```\n希望合并的最后的结果是\n```\n[{day:1,isrun:false},{day:2,isrun:false}...{day:4,isrun:true}...{day:6,isrun:true}....{day:31,isrun:false}]\n```",
"answer": " 首先反对推荐答案indexOf只是语法糖内部还是循环 \n如果这样做我想了很久没有想到什么好办法\n但是上面的答案也绝对不对你想下map、indexOf、include这些方法内部原理是不是还是循环\n只是被封装的很好使你的代码看起来很优雅。\n那么我们换个思路\n```\nlet days = [2, 4, 5, 7];\nlet run = [{ day: 1 }, { day: 2 }......{ day: 31 }];\nfor(let i=0;i<days.length;i++){\n run[days[i]-1].isrun=true;\n}\n```\nrun数组里的下标是可以利用起来的实际天数-1就是下标\n写之前没注意看 我赞同 @yszou 的答案,只有这样才能实现单层循环,其他的全是语法糖包装,实质运算量并没有减少",
"type": "technical_qa"
},
{
"id": "segmentfault_283",
"question": "大多数语言的switch语句不在case后默认break是出于什么考虑\n为什么会选择让编程者手动写break是出于什么考虑么",
"answer": "case是从汇编时代留下来的典型“模式”汇编时代有大量的cmp比较然后jmp跳转是一种非常常用的写法。C模仿了汇编的cmp+jmp模式设计出了switch-case模式就这样switch-case就延续下来了接下来各种模仿语言也就跟着用了。",
"type": "technical_qa"
},
{
"id": "segmentfault_284",
"question": "vue-router使用next()跳转到指定路径时会无限循环\n我在路由为 /path 的页面这样写\n```\n beforeRouteLeave (to, from, next) {\n console.log('离开路路由')\n if(to.fullPath==='/home'){\n next();\n }else{\n next('/home')\n }\n```\n这个是组件路由我想实现的效果是在这个页面点击浏览器的返回按钮后要返回 /home页面而不是上一个页面上面的代码是没问题的而我之前的写法就一直死循环\n```\n// 下面的写法会死循环\n beforeRouteLeave (to, from, next) {\n console.log('离开路路由')\n next('/home')\n}\n```\n问题\n```\n 1.我不太明白为什么会死循环我在home页面也没有写任何钩子函数来跳到result页面啊我也没有写全局的beforeEach钩子函数。\n 2.上面第一段代码是可用的,自己瞎摸索出来的,但是不是很明白为什么要加那个判断?\n```",
"answer": "自问自答下吧通过别人指点算是大致理解了当执行钩子函数时如果遇到next('/home')等时会中断当前导航,比如当前导航是去/a,那么遇到next('/home')后就会把to.path改为/home然后会重新触发这个离开的钩子注意此时会重新触发执行这个钩子而不是在这个钩子函数继续执行的之前是一直没理解这里以为是执行next('/home')后就会直接跳到home页面呢当重新触发后就会继续执行next('/home')所以会一直循环。至于解决办法就是判断下,如果已经是/home了就next()。",
"type": "technical_qa"
},
{
"id": "segmentfault_285",
"question": "请问dva中 connect()()的用法。\n这段代码是dva的基础代码\n```\nimport React from 'react';\nimport { connect } from 'dva';\n\nfunction IndexPage() {\n return (\n <div> this is a div </div>\n );\n}\n\nexport default connect()(IndexPage);\n```\n【请问】最后一行这个 connect()(IndexPage) 怎么理解? \n还要请教这两个括号的在一起的写法是es6语吗我在阮一峰的es6指南中没找到这个语法说明我要看箭头函数一章还是到哪章去了解这个`()()`\n老司机能提供一个纯js的双括号函数案例吗\np.s.\n我思考了一下之前见过 `function(){}()` 这样的最后放一个括号表示立即执行。请问和上边的这个有相通的地方吗?\n谢谢您前来科普帮助感谢老司机指路----O(∩_∩)O\n```\n//▼补充代码,\nimport React from 'react';\nimport { connect } from 'dva';\nimport { Table, Pagination, Popconfirm, Button } from 'antd';\nimport { routerRedux } from 'dva/router';\n\nfunction stuIndexPage({ dispatch, list: dataSource, loading, total, page: current }) {\n return (\n <div> index 首页 </div>\n );\n}\n\nfunction mapStateToProps({ stuIndexPage }){\n return {\n stuIndexPage\n };\n}\n//▼还有这个,两个括号都传参了,搞不太懂是什么作用\nexport default connect(mapStateToProps)(stuIndexPage);\n```",
"answer": "`connect` 函数的返回值还是一个函数 这样说你懂了没\n```\nconnect()(IndexPage)\n// =>\nconst bindToComponent = connect()\nexport default bindToComponent(IndexPage)\n```\n`export default connect(从 model 的 state 中获取数据)(要将数据绑定到哪个组件)`",
"type": "technical_qa"
},
{
"id": "segmentfault_286",
"question": " 怎么判断 iphoneX 手机?\n要兼容 iosX需判断手机类型怎么判断\nios真的会搞事情",
"answer": "看到一篇关于 解决iPhoneX适配的文章 https://mp.weixin.qq.com/s?__...\n亲测这个其实是针对 ios11系统有效。\n1.设置网页在可视窗口的布局方式。\n 首先 meta里 添加 `viewport-fit=cover`\n```\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no, viewport-fit=cover\" />\n\n```\n2.页面主体内容限定在安全区域内。\n 可以配合 @supports 这样编写样式:\n```\n@supports (bottom: constant(safe-area-inset-bottom)) {\n div {\n margin-bottom: constant(safe-area-inset-bottom);\n }\n}\n\n```\n更好的解决方式可以采用媒体查询 ,再加上面的代码 。\n```\n@media (device-width: 375px) and (device-height: 812px) and (-webkit-min-device-pixel-ratio : 3){\n //如果以后出现375*812,非ios机型可以加上下面语句\n @supports (bottom: constant(safe-area-inset-bottom)) {\n \n }\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_287",
"question": "js字符串拼接\n后台让我给他们传图片的时候给图片排序\n我现在取到的图片地址是 \n`19998321312.jpg`\n后台需要的格式是 \n`19998321312_01.jpg`\n`19998321312_02.jpg`\n`19998321312_03.jpg`\n...\n`19998321312_10.jpg`\n`19998321312_11.jpg`\n个位数在前边加 0\n请问我需要怎么拼接",
"answer": "```\n var arr = [{url: '19998321312.jpg'}];\n var result = arr.map((item,index) => {\n var strIndex = index + 1;\n if((strIndex).toString().length===1){\n strIndex = '0' + strIndex;\n }\n var urlIndex = item.url.lastIndexOf('.');\n var beforeUrl = item.url.slice(0, urlIndex);\n var afterUrl = item.url.slice(urlIndex)\n item.url = beforeUrl + '_' + strIndex + afterUrl;\n return item;\n });\n console.log(result); // [{url: \"19998321312_01.jpg\"}]\n // 多个改下数组arr即可。\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_288",
"question": "vue中keep-alive中缓存的组件可以主动销毁吗\n在项目中使用会缓存个别路由组件代码如下\n```\n `<transition name=\"fade\" mode=\"out-in\">\n <keep-alive>\n <router-view v-if=\"$route.meta.keepAlive\"></router-view>\n </keep-alive>\n </transition>\n <transition name=\"fade\" mode=\"out-in\">\n <router-view v-if=\"!$route.meta.keepAlive\"></router-view>\n </transition>`\n \n 这儿有一个问题就是如果我想主动把keep-alive中的个别组件手动销毁还没有什么方法和头绪。\n```",
"answer": "在vue@2.5.0 中 `keep-alive` 新增了一个 `max` 属性可以设置 cache instance 的个数\nadd max prop for <keep-alive> for limiting max number of instances cached\n相关issue\n所以个人认为没有太大必要手动来维护 `keep-alive`的组件,当然你想的话可以使用`include` 和 `exclude` 来实现",
"type": "technical_qa"
},
{
"id": "segmentfault_289",
"question": "如何更改<input type=\"file\" />上传文件的名字?\n在选择文件后上传文件前或者是点击提交的时候如何更改上传文件的名字\n```\n<form id=\"upload_form\" method=\"post\" enctype=\"multipart/form-data\">\n <input type=\"file\" name=\"upload_file\">\n <input type=\"submit\">\n</form>\n```\n直接改变`file.name`是无效的;\n```\nvar fileExtension = '.' + file.name.split('.').pop();\nfile.name = Math.random().toString(36).substring(7) + fileExtension;\nconsole.log(file);\n```\n应该如何更改呢",
"answer": "使用FormData进行提交修改文件名用以下方法\n```\nformData.append(name, value, filename);\n```\n参考地址https://developer.mozilla.org...\n注意如果是移动端iphone请注意旋转图片角度。\n希望对您有所帮助",
"type": "technical_qa"
},
{
"id": "segmentfault_290",
"question": "这样是不是就叫\n前后端分离开发了\n以前曾经写过一个后台是用java写的有前后台页面的网站。\n被朋友吐槽说我那个网站不是用的前后端分离很low。说没有用请求api接口而且用了jsp來改写html说前后端分离不需要这样套模版的。\n问题\n0.现在是不是差不多所有公司都用前后端分离了?没试过这种开发模式咋办…\n1.是不是前后端分离与传统的开发其实主要就是以上那些区别?\n2.工作中如果后端同事写的接口文档比较难看懂不就坑了前端?\n3.看到别人github有前后端分离项目为啥运行时前后台页面都是同一个端口号如9000不是应该前端首页localhost:3000/index 后端首页localhost:9000/index这样分开才叫前后端分离吗 都用9000端口那和我之前写网站访问前后台的方式一样阿…\n概念其实在网上了解过但怕很多地方还是理解错所以上来求指正",
"answer": "0 NO 前后端分离是趋势但是也还存在问题例如SEO搜索引擎难以识别等短时间内不可能取代不分离的\n1 主要区别是数据和表现分离只需要静态的html和动态的接口例如jsp数据在浏览器端实现动态加载\n2 理想情况是,先出文档(前后端都认可),然后后端、前端都按照文档来,一切以接口规定的为准\n3 跟端口没一毛钱关系,重点在于接口!靠 API 来分离前后端,解决前后端大团队、多版本、复杂功能协作的问题\n补充\n可以参考淘宝前端的设计在 java 接口和 html 输出之前用 NodeJS 代理一层,暂时能解决 SEO 的问题\n定义好了接口前端就可以用不用等后端直接用模拟的数据格式方便地进行前端测试了\n说重点API 相比前后端混写、模板引擎之类的东西的好处:\n方便设计、开发、测试前端不再需要依赖后端后端也不需要依赖前端就可以各干各的独立测试代码\n方便记录和统计功能使用后端相同功能的入口位置统一不同功能的位置也可以合理有序地组织\n方便修改和版本控制等后端可以提供多版本的 API不需要修改已有代码不影响已有 API 的功能)\n最重点的是\n你的Team要是分工不明确、人少、功能简单直接、代码修改不多就完全不需要分离就酱。\n最明显的\n前端代码不用被后端粘贴来粘贴去了后端的相同代码也不需要各种位置粘贴来粘贴去了。\n隐藏的好处\n到时候出了问题照着 API 设计文档一对比,就知道是前端用的不对,还是后端写的不对,分分钟找到背锅侠。\nUpdate 2017/10/13:\n其实很有一个很大的优势忘了说……\n以后网站的功能要做Windows、Mac、Android、IOS、Linux的客户端或者需要做成批量处理的脚本或者需要和别的什么系统对接什么微信公众号、小程序之类的等等等等……\n有API在就能瞬间解决问题就这个提供给前端的API一样的调用这个接口就行了",
"type": "technical_qa"
},
{
"id": "segmentfault_291",
"question": "int占4字节一数占一字符为什么int能表示5位以上的数字?\n我知道这个问题~有点无厘头和傻乎乎。还是想请人解答一下~\n----------可能目前脑子正处于抽风阶段----------\n首先我知道int占4个字节包含正负2的31次方内的数字也就是基本可以表示10位数字。\n那么根据Ascll里一个数字占用一个字节的规则来思考。\n我让int按照这种规则来储存数字是不是应该只能储存最多4位数字\n还请明白人~指出我这样思考的错误点在哪里?或者告知正确的解答方式~。",
"answer": "字符和数值的表示方法是不同的ascii码里面的数字不是数值是用编码表示的字符因此每个数字字符占7位(扩充的ascii码占8位)。比如12用ascii码表示为0110001 0110010(它表示的是一二两个数字字符组成的字符串,并没有十二的大小的涵义)而用int则表示为00000000 00000000 00000000 00001010它表示数值为十二的整数一二两个数是不可分割的。。总之数值与字符在计算机内表示的方法是不同的int不是用ascii码表示的",
"type": "technical_qa"
},
{
"id": "segmentfault_292",
"question": "用jsx写vue组件怎样监听.sync修饰符的事件\n用 `jsx` 来写 vue 的组件,需要监听 `.sync` 修饰符的事件,找不到文档,我试过下面的方法,但是并不行。\n```\n<MyComponent visible={this.visible} {...{['on-update:visible']: console.log}} />\n```\n求问正确的写法应该要怎样呢",
"answer": "在 babel-plugin-transform-vue-jsx 的 example 中找到了答案,可以这样写:\n```\n<MyComponent visible={this.visible} {...{on:{'update:visible': console.log}}} />\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_293",
"question": "vue-cli 根据不同的环境打包\n项目开发中有三个环境分别是测试环境预生产环境生产环境\n如题根据项目需要目前需要打包通过vue-cli中的npm run build 打包这个只能打包到一个环境但是项目中有三个环境每个环境的接口地址都不同根据process.env分别进行接口的调用但是如何处理打包呢\n目前的解决方案是复制了几个build下面的build.js ,感觉这样并不是最优的解决方案,\n不知是否有更完美的解决方案\n 感激不尽!",
"answer": "解决此类问题还得靠自己,大神一般都不给力\nvue-cli 中build中build.js部分代码做如下修改\n```\nrequire('./check-versions')()\n\n// process.env.NODE_ENV = 'production'\n\nvar ora = require('ora')\nvar rm = require('rimraf')\nvar path = require('path')\nvar chalk = require('chalk')\nvar webpack = require('webpack')\nvar config = require('../config')\nvar webpackConfig = require('./webpack.prod.conf')\n\nvar spinner = ora('building for ' + process.env.NODE_ENV + ' of ' + process.env.env_config+ ' mode...' )\nspinner.start()\n// var spinner = ora('building for production...')\n// spinner.start()\n。。。。\n```\nbuild中webpack.prod.conf.js做如下修改\n```\nconst env = config.build[process.env.env_config+'Env']\n// var env = process.env.NODE_ENV === 'testing' ?\n// require('../config/test.env') :\n// config.build.env\n。。。。\n```\nconfig中的index.js 部分代码修改如下\n```\nmodule.exports = {\n build: {\n prodEnv: require('./prod.env'),\n sitEnv: require('./sit.env'),\n ppeEnv: require('./ppe.env'),\n index: path.resolve(__dirname, '../dist/' + new_dateTime + '/index.html'),\n 。。。。。\n```\nconfig中 dev.env.js 修改\n开发环境用的是测试接口通过merge进行拷贝\n```\nvar merge = require('webpack-merge')\nvar sitEnv = require('./sit.env')\n\nmodule.exports = merge(sitEnv, {\n NODE_ENV: '\"development\"'\n})\n```\n在config中新建sit.env.js\n```\n//测试\nmodule.exports = {\n NODE_ENV: '\"sitEnvironment\"',\n ENV_CONFIG: '\"sit\"',\n hosturl: '\"https://sitxxx\"',\n。。。\n}\n```\n在config中新建ppe.env.js\n```\n//预生产\nmodule.exports = {\n NODE_ENV: '\"ppeEnvironment\"',\n ENV_CONFIG: '\"ppe\"',\nhosturl: '\"https://ppexxx\"'\n。。。\n}\n```\n生产环境是prod.env.js vue-cli 自带\n安装cross-env\npackage.json 修改\n```\n \"scripts\": {\n \"dev\": \"node build/dev-server.js\",\n \"build:prod\": \"cross-env NODE_ENV=production env_config=prod node build/build.js\",\n \"build:ppe\": \"cross-env NODE_ENV=ppeEnvironment env_config=ppe node build/build.js\",\n \"build:sit\": \"cross-env NODE_ENV=sitEnvironment env_config=sit node build/build.js\",\n \"e2e\": \"node test/e2e/runner.js\",\n \"test\": \"npm run e2e\"\n },\n```\nend",
"type": "technical_qa"
},
{
"id": "segmentfault_294",
"question": "element-ui的tree树形组件怎么控制全部展开和全部折叠啊\nelement-ui的tree树形组件怎么控制全部展开和全部折叠啊有一个default-expand-all 是否默认展开所有节点的属性只在第一次初始化tree的时候有效改变这个属性的值好像不能控制展开折叠请问有什么方法吗",
"answer": "```\nfor(var i=0;i<this.$refs.treeX.store._getAllNodes().length;i++){\n this.$refs.treeX.store._getAllNodes()[i].expanded=this.isexpand;\n }\n\n\n\n```\nthis.$refs.treeX是树对象通过树对象获取所有的树节点遍历树节点设置expand属性为true则全部展开设置为false则全部收起",
"type": "technical_qa"
},
{
"id": "segmentfault_295",
"question": "如何理解three.js中的buffergeometry\n如何理解three.js中的buffergeometry\nbuffergeometry与Geometry 相比优势与劣势是什么?\n最适用于什么样的场景",
"answer": "BufferGeometry 会缓存网格模型,性能要高效点。网格模型生成原理\n1、Geometry 生成的模型是这样的 (代码)-> (CUP 进行数据处理转化成虚拟3D数据) -> (GPU 进行数据组装,转化成像素点,准备渲染) -> 显示器\n第二次操作时重复走这些流程。\n2、BufferGeometry 生成模型流程 (代码) -> (CUP 进行数据处理转化成虚拟3D数据) -> (GPU 进行数据组装,转化成像素点,准备渲染) -> (丢入缓存区) -> 显示器\n第二次修改时通过API直接修改缓存区数据流程就变成了这样\n(代码) -> (CUP 进行数据处理转化成虚拟3D数据) -> (修改缓存区数据) -> 显示器\n节约了GPU性能的运算性能",
"type": "technical_qa"
},
{
"id": "segmentfault_296",
"question": "js闭包this对象\n```\nvar name = \"The Window\";\nvar getNameFunc= {\n name: \"My Object\",\n getNameFunc: function() {\n return function() {\n return this.name;\n };\n }\n};\nalert(object.getNameFunc()()); //\"The Window\"(在非严格模式下)\n\n```\n在高级程序设计的第7章7.2.2关于this对象中有几句话实在是不太明白\n以上代码先创建了一个全局变量 name又创建了一个包含 name 属性的对象。这个对象还包含一个方法——getNameFunc(),它返回一个匿名函数,而匿名函数又返回 this.name。由于 getNameFunc()返回一个函数,因此调用 object.getNameFunc()()就会立即调用它返回的函数,结果就是返回一个字符串。然而,这个例子返回的字符串是\"The Window\",即全局 name 变量的值。为什么匿名函数没有取得其包含作用域(或外部作用域)的 this 对象呢?\n前面曾经提到过每个函数在被调用时都会自动取得两个特殊变量 this 和 arguments。内部函数在搜索这两个变量时只会搜索到其活动对象为止因此永远不可能直接访问外部函数中的这两个变量。\n1.只会搜索到其活动对象??? 不是有个作用域链吗匿名活动对象在最下面在匿名对象中找不到那就去上面的活动对象去找咯getNameFunc中找不到就去object去找咯。。。不就找到了吗\n2.因此永远不可能直接访问外部函数中的这两个变量???是什么意思?外部函数是指哪个?",
"answer": "你可以通过修改尝试对 `this` 加深一下理解 .\n1) 将匿名函数独立出来给个名字.\n稍微调整如下:\n```\nvar name = \"The Window\";\nfunction getThisName(){\n return this.name\n}\nvar object = {\n name: \"My Object\",\n getNameFunc: function() {\n return getThisName\n }\n};\nvar getThisNameFunc = object.getNameFunc()\nconsole.log(getThisNameFunc()); \n```\n现在你再来看这个 `getThisName` 这个原来你代码里面的匿名函数,你是不是可以很清楚的看出它的调用方是认谁了? 很显示到最后调用这个方法时是隐式的全局变量 (window, 在浏览器环境)\n它跟上面声明的 `object` 没有任何关系. 只是 `object.getNameFunc` 这个函数将这个函数作为返回值.\n如果是返回的其他标量,自然也不会发生关系.\n另外你上面的书也提到了, `this` 和 `arguments`这两个隐式的变量是在函数调用的时候才获得的.\n所以在这个函数被调用的时候明显它的`this` 只能是全局的 `this`.\n2) 将 object 直接跟 `getThisName` 建立关系:\n```\nvar name = \"The Window\";\nfunction getThisName(){\n return this.name\n}\nvar object = {\n name: \"My Object\",\n getNameFunc:getThisName \n};\nconsole.log(object.getNameFunc()); // 输出: My Object\nvar getThisNameFunc = object.getNameFunc; \nconsole.log(getThisNameFunc()); // 输出: The Window\n```\n观察上面的输出,你再加深以下对这句话的理解:\n每个函数在被调用时都会自动取得两个特殊变量\n3) 加深对函数调用的理解, 加上 `apply` 和 `call`\n你看一下如下代码的输出:\n```\nvar name = \"The Window\";\nfunction getThisName(){\n return this.name\n}\nvar object = {\n name: \"My Object\",\n getNameFunc:getThisName \n};\nconsole.log(object.getNameFunc()); \nvar getThisNameFunc = object.getNameFunc\nconsole.log(getThisNameFunc()); \nconsole.log(getThisNameFunc.apply(object)); \nconsole.log(getThisNameFunc.call(object)); \n```\n每个函数在被调用时都会自动取得两个特殊变量\n同时你也可以通过使用 `apply`, `call` 等内置函数原型的方法来指定函数调用时所使用的 this 对象. 如上所示.\nJavaScript 的这一特点, 跟 Java 等静态语言是很不同的. Java 等静态语言,往往由于你方法(注意这里没有说函数)写的地方就决定了 `this` 对象的指向,但是 JavaScript 是动态语言这一点很不一样. 所以还需要在后面的实践中多多注意总结和理解.",
"type": "technical_qa"
},
{
"id": "segmentfault_297",
"question": "谁能用自己的话解释init和initWithFrame调用的先后顺序原因\n这是一个自定义view\n```\n@implementation MyView\n\n- (instancetype)init {\n if (self = [super init]) {\n NSLog(@\"调用了init\");\n }\n return self;\n}\n\n- (instancetype)initWithFrame:(CGRect)frame {\n if (self = [super initWithFrame:frame]) {\n NSLog(@\"调用了initWithFrame\");\n }\n return self;\n}\n\n\n@end\n\n```\n现在我调用它的init方法\n```\nMyView *myView = [[MyView alloc] init];\n```\n控制台打印信息是\n2017-10-09 11:14:35.224 block[2391:262544] 调用了initWithFrame\n2017-10-09 11:14:35.225 block[2391:262544] 调用了init\n问\n为什么先打印的是initWithFrame而不是init?",
"answer": "```\nMyView *myView = [[MyView alloc] init];\n```\n代码调用过程如下\n\n1. 动态查找到 MyView 的 init 方法\n2. 调用 super init 方法\n3. super init 方法内部执行的是 [super initWithFrame:CGRectZero]\n4. 然后 super 会发现 MyView 实现了 initWithFrame 方法\n5. 转而执行 [MyView initWithFrame:CGRectZero]\n6. 最后再执行 init 其余部分\n\n关键点OC 里面的 super 实际上是让某个类自己去调用父类的方法, 而不是父类去调用某方法。方法动态调用过程中的顺序是按照继承关系从下到上。",
"type": "technical_qa"
},
{
"id": "segmentfault_298",
"question": "关于php解决并发的一些疑惑\n首先 并发我是这样理解的:\n2 个人同时下单, 库存只有 1, 那么肯定有一个人无法抢到。也就是说, 库存只会减 1, 订单也只会生成一条。\n后来我用 Jmemter 模拟 1000 人同时操作, 发现订单确实只有一个, 而且库存也没有负数, 但是我并没有做什么锁啊或者队列这些一谈到并发就会涉及到的东西。\n`$a` 是查询到的库存\n```\n$b = $a-1;\n\nif($b>=0){\n 生成订单\n 修改库存\n}\n```\n如果没有 `if` 判断, 确实会负。但是如果加了这个 `if` 判断就库存只减少 1, 订单只有一条\n那么我的问题来了, 加个 `if` 判断就能解决并发? 还是说实际上真正要处理的是模拟测试后出现的错误率 (Jmemter, 模拟 1000 人, error:59.5%), 或者其他? \n请解答, 如果我的思路有错误, 也请毫不留情",
"answer": "你说的订单问题,其实是:高并发场景下,如何正确扣减库存的问题\n`if($b>=0)` 这样的判断,在高并发的场景下并不使用,因为这样的业务逻辑判断并不是 `原子操作`,所以存在 `脏读` 的可能。\n例如\n由两个请求同时到达 `服务端`(分别名为:`p1`, `p2``p1` 先取到了数据,走到了 `if` 判断,\n此时 `p2` 也取到了数据,但是 `p1` 还没有更新数据库,所以 `p2` 取到的数据跟 `p1` 是一样的,所以,`p1` `p2` 得到的 `$b` 值是一样的, `p2` 也可以通过 `if` 条件,但是这两个请求只扣减了一次存库。\n如何解决这个问题呢\n- 加锁;\n- 队列:改并行为串行,依次扣减;\n- 操作转换为原子操作;\n\n加锁\n队列改并行为串行依次扣减\n操作转换为原子操作\n不光是数据库操作高并发场景下还可能会面对什么问题呢\n- 单点问题(当然 非刚并发场景也会面临这个问题,但是高并发场景,此问题尤为突出)\n- 最大连接数问题eg. `web 服务器` `数据库` ...\n- 数据安全问题eg. `脏读` `重复操作`\n\n单点问题当然 非刚并发场景也会面临这个问题,但是高并发场景,此问题尤为突出)\n最大连接数问题eg. `web 服务器` `数据库` ...\n数据安全问题eg. `脏读` `重复操作`",
"type": "technical_qa"
},
{
"id": "segmentfault_299",
"question": "如何使用localStorage结合Vuex来保存用户登录信息\n我现在有一个 `headerBar` 组件,上面显示了用户名称(如果设置了昵称显示昵称,否则显示用户名称),当用户点击登录按钮时,调用`api`获取用户信息,保存到`Vuex`的`state`里面,`headerBar`通过`this.$store.getters.xxx`来获取用户登录信息但是当用户刷新时state里面的用户信息全没了所以我考虑加入 `localStorage` 来保存用户信息,但是这部分代码不知道该如何“分布”,因为要考虑`用户登录超时`,请小伙伴们指点指点,谢谢!\n代码如下\n```\nexport default new Vuex.Store({\n state: {\n loginInfo: null,//当前用户简要信息\n },\n getters: {\n GET_LOGININFO(state) {\n //先从state里面获取用户登录信息\n let loginInfo = state.loginInfo;\n //如果 state 里面获取不到那么从localStorage里面获取\n if(!loginInfo){\n loginInfo = JSON.parse(window.localStorage.getItem('loginInfo') || null)\n }\n return loginInfo;\n },\n },\n mutations: {\n SET_LOGININFO(state, data){\n state.userInfo = data.data;\n }\n },\n actions: {\n Login(context, data) {\n axios.post('/api/login', {\n userName: 'admin',\n pwd: '123456'\n })\n .then((res) => {\n //登录成功,保存当前用户信息到 state 里面,以便其他组建获取\n context.commit('SET_LOGININFO', res.data);\n //保存到localStorage里面\n window.localStorage.setItem('loginInfo', JSON.stringify(items));\n return res; \n })\n .catch(function (error) {});\n },\n }\n})\n```\n想请教几个问题\n1、这么使用 `localStorage` 正确么?或者合理么?有没有更好的方法呢?\n2、在`getters`下面的`GET_LOGININFO`方法里面,如果进入了`if(!loginInfo)`语句,该方法是否可以为 `state `属性`loginInfo`赋值呢(或者调用`mutations`方法来给`loginInfo`赋值)?\n3、这样的话如果用户点击`退出`按钮是不是意味着需要清空state的loginInfo还需要清除localStorage下面的loginInfo呢\n4、这样的话从客户端角度来看是不是客户就永远保持以登录状态了这个环节该怎么做好呢\n补充第二个问题其实就是getters里面的方法是否可以为state属性赋值直接访问state属性赋值 或者 调用mutations方法赋值",
"answer": "1. **不合理**。用户登录成功以后应该在本地保存一份用户数据,注意我说的是保存到本地不是保存到`localstorage`,因为保存本地的方法有很多种,比如`cookie`、`indexedDB`等,所以,代码中不应该直接调用`window.localStorage`,而是应该封装一个用户数据的读取类,解除代码耦合,将来要改成其他存储方式比较简单:\n```\n`const USER_INFO='USER_INFO'\nfunction getUserinfo(){}\nfunction setUserinfo(){}`\n```\n2. **不应该**。个人认为不应该,`getters`语义上就是获取数据,但是却改变了数据,导致不纯净,可能会埋下维护上的隐患。\n3. **是的**。理论上应该有一个接口用来更新用户状态,比如判断用户是否需要重新登录之类的,比如`api/refresh` 所以逻辑应该是:\n - 用户进入app判断本地是否有用户信息。\n\n\n - 有,调用`api/refresh`,判断是否需要重新登录。\n - 不需要(连续登录),将信息保存在`vuex`中,并进入首页,往后数据读取全部走`vuex`。\n - 需要(长时间未登录),删除本地用户信息并跳转到登录流程。\n - 没有, 跳转到登录流程(以下是登录流程)。\n - 调用`api/login`登录。\n - 将保存到本地,并保存到`vuex`中,往后数据读取全部走`vuex`。\n\n4. **看3**,具体还可以看看`jwt`,或者基于`token`的`api`设计相关的文章。",
"type": "technical_qa"
},
{
"id": "segmentfault_300",
"question": "js怎样确定两个异步函数的执行顺序\n```\nconst asyncFunction = function() {\n return new Promise(function(resolve, reject) {\n resolve('promise');\n });\n};\n\nasyncFunction().then(value => console.log(value));\n\nsetTimeout(() => { console.log('settimeout') }, 0);\n\n```\n输出\n```\n// promise\n// settimeout\n```\n请问两个都是异步的函数为什么`setTimeout`函数后执行?",
"answer": "Promise 是microtask 队列\n而setTimeout属于 macrotask 队列\n在一个Tasks执行之后会立刻执行microtask队列而后执行macrotask队列\nmacrotask永远在 microtask 之后执行",
"type": "technical_qa"
},
{
"id": "segmentfault_301",
"question": "vue 权限控制\n项目使用了vue + vue-router作为前端框架, 现在需要做权限控制,\n请问怎么设计前端的权限\n补充: 抱歉可能我表达不清, 意思是前端对某个角色的权限进行控制, 比如有些页面不显示, 有些按钮不能点击",
"answer": "最近搭建了公司的后台管理系统, 而且系统还比较庞大, 要实现以下几点:\n1. 菜单权限, 根据不同权限显示不同的菜单\n2. 操作权限, 比如有些账号没有新增权限, 有些没有修改或者删除权限\n3. 数据权限, 比如统计概况, 普通管理员不能看到公司营业概况,但能看到自己所属区域的概况\n4. 显示权限, 比如列表, 运营能看到那一列的签约金额,但市场不能看到签约金额这一列\n\n到目前为止还在构建中 已经解决菜单权限和操作权限。\n\n菜单权限\n最开始的时候本地先配置一套路由然后登陆成功后会从服务器返回一个菜单列表然后在beforeEach里面把返回的菜单列表和本地配置的路由进行对比 如果存在则有权限访问。 做了几天发现很难用, 本地得配置一整套路由,还得做几个页面来把这些路由信息写入到服务器,这样来进行权限分配, 当你的权限菜单比较多的时候, 像我们这个后台,光公司内部权限就有好几套, 还有代理商、商家权限等等, 不同的菜单可能会超过几百个, 这样配置太累了,还容易出错。\n最后的解决思路是完全不在本地做任何路由配置 登录页面单独弄不放到vue组件里面 登录成功后从后台抓取菜单列表, 因为现在是已经登录成功了,所以抓取的就是拥有全新的菜单。 抓取成功后在配置到路由里面然后实例化vue , 这样就避免了本地配置一套路由了,完全是服务器上面配置路由。 \n这样解决的难点只有一个那就是路由需要对应的组件所以我们将所有组件存放到一个对象里面 服务器的返回的菜单列表里面,会有一个字段配置组件名, 在抓取成功后生成路由配置的时候就使用 router[menuName]就能直接加载到这个组件,非常方便。\nmain.js代码片段\n```\n// 实例化Login类并初始化\n new Login(function (err, data) {\n if (err) {\n // 登录出错\n } else {\n // 登录成功\n init(data);\n }\n }).init();\n\nconst init = function (data) {\n // 先配置路由信息\n // componentConfigs 是本地的组件配置\n let routers = assignRouter(data.menus, componentConfigs);\n // 实例化路由\n router = new Router({routes: routers});\n // 再实例化vue\n new Vue({\n el: '#app',\n store,\n router,\n nprogress,\n ...App\n });\n};\n```\n```\ncomponentConfigs.js 代码片段:\n```\n```\nexport default {\n Common: {\n Admin: require('../../vue/pages/common/Admin'),\n Index: require('../../vue/pages/common/Index'),\n UpdatePassword: r => require.ensure([], () => r(require('../../vue/pages/users/UpdatePassword')), 'users')\n }\n}\n```\n服务器返回的菜单json:\n其中meta 字段里面是当前路由里的操作权限\n```\n[{\n \"path\": \"\\/admin\\/index\",\n \"name\": \"\\u9996\\u9875\",\n \"component\": \"Common.Index\",\n \"display\": true,\n \"icon\": \"icon-home\"\n }, {\n \"path\": \"\\/admin\\/updatePassword\",\n \"name\": \"\\u4fee\\u6539\\u5bc6\\u7801\",\n \"component\": \"Common.UpdatePassword\",\n \"display\": false\n }, {\n \"path\": \"\\/admin\\/commodity\",\n \"name\": \"\\u5546\\u54c1\\u7ba1\\u7406\",\n \"component\": \"Content\",\n \"display\": true,\n \"icon\": \"icon-class\",\n \"children\": [{\n \"path\": \"\\/admin\\/commodity\\/publicWarehouse\",\n \"name\": \"\\u516c\\u5171\\u5e93\\u7ba1\\u7406\",\n \"component\": \"Commodity.PublicWarehouse\",\n \"display\": true,\n \"meta\": {\"handleAuth\": {\"add\": true, \"edit\": false, \"del\": true}}\n }, {\n \"path\": \"\\/admin\\/commodity\\/businessesWarehouse\",\n \"name\": \"\\u5546\\u5bb6\\u5e93\\u7ba1\\u7406\",\n \"component\": \"Commodity.BusinessesWarehouse\",\n \"display\": true,\n \"meta\": {\"handleAuth\": {\"add\": true, \"edit\": false, \"del\": true}}\n }]\n }]\n```\n菜单的权限大概就是这样 至于操作权限, 思路是这样的: 写一个鉴权的vue插件 然后所有的操作独立放到methods里面; 然后所有的操作 @click里面调用鉴权函数 $auth('add', arg1, arg2, ...argN) ; $auth里面判断this.$route.meta 里是否有权限进行这个操作, 如果有则调用 this[authName].apply(null, arg);",
"type": "technical_qa"
},
{
"id": "segmentfault_302",
"question": "jquery 怎么判断一个数组的最大值并显示name\n像下面的这种怎么判断后面的数字大小并输出最大数的 a:7 这种形式。\n```\nvar arr=[{a:7},{b:2},{c:0},{d:5},{e:1}];\n```",
"answer": "```\nvar arr=[{a:7},{b:2},{c:0},{d:5},{e:1}];\narr.sort(function(item1,item2){\n return item2[Object.keys(item2)[0]]-item1[Object.keys(item1)[0]]\n})[0] //{a: 7}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_303",
"question": "C++ 字符串加字符\n```\ncout << (\"s\" + 'a');\n\n```\n这样一段代码为什么输出是一个空行呢\n难道是 `string literal + character` 没有这个运算吗?\n没有的话为什么输出是空行呢\nC++ 中, `string literal` 就是 `const char[n]` 吗?",
"answer": "表达式`\"s\"`的类型是`const char[]`,表达式 `'a'`的类型是`char`。\n数组是不能进行内置加法运算的。所以`const char []`会被转换成`const char *`,这里的运算就变成了\"指针+整型\"(`char`是一种整型)。输出空行的运行结果实际上是数组越界引起的。\nString literal\nNarrow multibyte string literal. The type of an unprefixed string literal is const char[]\nAdditive operators\naddition. For the built-in operator, lhs and rhs must be one of the following: Both have arithmetic or unscoped enumeration type. In this case, the usual arithmetic conversions are performed on both operands and determine the type of the result. One is a pointer to complete object type, the other has integral or unscoped enumeration type. In this case, the result type has the type of the pointer\nArray-to-pointer decay\nThere is an implicit conversion from lvalues and rvalues of array type to rvalues of pointer type: it constructs a pointer to the first element of an array. This conversion is used whenever arrays appear in context where arrays are not expected, but pointers are.",
"type": "technical_qa"
},
{
"id": "segmentfault_304",
"question": "process.nextTick()与promise.then()\n```\nprocess.nextTick(function(){\n console.log(7);\n});\n\nnew Promise(function(resolve){\n console.log(3);\n resolve();\n console.log(4);\n}).then(function(){\n console.log(5);\n});\n\nprocess.nextTick(function(){\n console.log(8);\n});\n```\n这段代码运行结果是34785\nprocess.nextTick和Promise都是Microtasks为什么process.nextTick会先执行",
"answer": "process.nextTick 永远大于 promise.then原因其实很简单。在Node中_tickCallback在每一次执行完TaskQueue中的一个任务后被调用而这个_tickCallback中实质上干了两件事\n1.nextTickQueue中所有任务执行掉(长度最大1e4Node版本v6.9.1)\n2.第一步执行完后执行_runMicrotasks函数执行microtask中的部分(promise.then注册的回调)\n所以很明显 process.nextTick > promise.then",
"type": "technical_qa"
},
{
"id": "segmentfault_305",
"question": "为什么js里面 0.1+0.2=0.30000000000000004\n```\nvar a =0.1;\nvar b =0.2;\nlog(a+b)//0.30000000000000004\n```\n这是什么原因",
"answer": "本质是因为浮点数的问题。\n其实不用想的太复杂你把0.1换算成二进制的形式就知道它的二进制表示是一个无限循环的数。也就说实际上保存到内存里的0.1是一个近似值。\n然后一个近似于0.1的二进制数再转回10进制就会出现这种问题。",
"type": "technical_qa"
},
{
"id": "segmentfault_306",
"question": "JavaScript中typeof原理探究\n我们都知道 `typeof(null) === 'object'`关于原因在小黄书《你不知道的JavaScript》中有这么一段解释\n原理是这样的 不同的对象在底层都表示为二进制, 在 JavaScript 中二进制前三位都为 0 的话会被判断为 object 类型, null 的二进制表示是全 0 自然前三位也是 0 所以执行 typeof 时会返回“object”。\n我就想问下不同的对象对应的二进制数是多少位的具体值又是多少比如String类型的二进制表示是多少",
"answer": "并不完全正确。\n我在知乎 有哪些明明是 bug却被说成是 feature 的例子? 有介绍过。\njavascript 中的 `null`:既是对象,又不是对象,史称「薛定谔的对象」。\n```\ntypeof null === 'object';\nnull instanceof Object === false\n```\n而\n```\nnull instanceof null\n```\n会抛出异常\n```\nUncaught TypeError: Right-hand side of 'instanceof' is not an object\n```\n这是一个历史遗留下来的 feature(or bug?)The history of “typeof null”\n在 javascript 的最初版本中,使用的 32 位系统,为了性能考虑使用低位存储了变量的类型信息:\n- 000对象\n- 1整数\n- 010浮点数\n- 100字符串\n- 110布尔\n\n有 2 个值比较特殊:\n- undefined用 - 2^30表示。\n- null对应机器码的 NULL 指针,一般是全零。\n\n在第一版的 javascript 实现中,判断类型的代码是这么写的:\n```\nif (JSVAL_IS_VOID(v)) { // (1)\n type = JSTYPE_VOID;\n} else if (JSVAL_IS_OBJECT(v)) { // (2)\n obj = JSVAL_TO_OBJECT(v);\n if (obj &&\n (ops = obj->map->ops,\n ops == &js_ObjectOps\n ? (clasp = OBJ_GET_CLASS(cx, obj),\n clasp->call || clasp == &js_FunctionClass) // (3,4)\n : ops->call != 0)) { // (3)\n type = JSTYPE_FUNCTION;\n } else {\n type = JSTYPE_OBJECT;\n }\n} else if (JSVAL_IS_NUMBER(v)) {\n type = JSTYPE_NUMBER;\n} else if (JSVAL_IS_STRING(v)) {\n type = JSTYPE_STRING;\n} else if (JSVAL_IS_BOOLEAN(v)) {\n type = JSTYPE_BOOLEAN;\n}\n```\n1判断是否为 undefined\n2如果不是 undefined判断是否为对象\n3如果不是对象判断是否为数字\n4。。。\n这样一来`null` 就出了一个 bug。根据 type tags 信息,低位是 `000`,因此 `null` 被判断成了一个对象。这就是为什么 `typeof null` 的返回值是 `object`。\n关于 `null` 的类型在 MDN 文档中也有简单的描述typeof - javascript | MDN\n在 ES6 中曾有关于修复此 bug 的提议,提议中称应该让 `typeof null === 'null'` http://wiki.ecmascript.org/do...:typeof_null 但是该提议被无情的否决了,自此 `typeof null` 终于不再是一个 bug而是一个 feature并且永远不会被修复。\n这是 JavaScript 最初实现的一个 bug目前的 JavaScript 引擎已经不这么去实现了,但是这个 bug 却一直流传了下来。\n至于对象的内部表示不同的 JavaScript 引擎实现起来都是不一样的,单说说 V8 吧。\nv8引擎是如何知道js数据类型的 (原文太长我就不贴过来了)",
"type": "technical_qa"
},
{
"id": "segmentfault_307",
"question": "怎么提高组织语言能力和表达能力?求指导下,主要在项目文档的撰写和开会对项目口语表达\n怎么提高组织语言能力和表达能力求指导下主要在项目文档的撰写和开会对项目口语表达",
"answer": "提高表达能力的核心是理清思路我用来提高自己表达能力的方法是复述具体操作是找几部自己比较喜欢的电影看15min然后暂停并且用1min复述这15min的剧情每天锻炼1h左右也就是复述4次一个月左右就能有较为明显的效果了。\n这个方法我在高中毕业的暑假中用过持续了一个多月。之后在大学四年中我参与竞选的演讲都十分成功现在工作后与领导同事的沟通、组会交流以及项目沟通都十分顺畅。\n我比较推荐这个方法您可以试一下。",
"type": "technical_qa"
},
{
"id": "segmentfault_308",
"question": "git 怎样删除远程仓库的某次错误提交?\n在网上找到一种方法\n\n在本地把远程的master分支删除再把reset后的分支内容给push上去\n本地仓库 彻底回退到某一个版本\n\ngit reset hard\n删除远程的master分支 (注意master前有个:)\n\ngit push origin :master\n重新创建远程master分支(这跟我们第1次提交本地代码库给远程仓库的命令一样吧)\n\ngit push origin master\n我的问题是除了这种比较暴力的方法还有别的方法吗",
"answer": "假设你有3个commit如下\n```\ncommit 3\ncommit 2\ncommit 1\n\n```\n其中最后一次提交`commit 3`是错误的,那么可以执行:\n```\ngit reset --hard HEAD~1\n\n```\n你会发现`HEAD is now at commit 2`。\n然后再使用`git push --force`将本次变更强行推送至服务器。这样在服务器上的最后一次错误提交也彻底消失了。\n值得注意的是这类操作比较比较危险例如在你的`commit 3`之后别人又提交了新的`commit 4`,那在你强制推送之后,那位仁兄的`commit 4`也跟着一起消失了。",
"type": "technical_qa"
},
{
"id": "segmentfault_309",
"question": "Vue动态面包屑导航怎么实现\n没有思路求大神解答\n补充一下我的思路是beforeEach获取上一个路由name和即将进入的路由name然后填加到数组最后router-link循环但是不知道从哪下手",
"answer": "```\nvar routeList = []\n\nrouter.beforeEach((to, from, next) => {\n var index = routeList.indexOf(to.name)\n if (index !== -1) {\n //如果存在路由列表,则把之后的路由都删掉\n routeList.splice(index + 1, routeList.length - index - 1)\n } else {\n routeList.push(to.name)\n }\n to.meta.routeList = routeList\n next()\n})\n```\n之后在需要用到的页面\n```\nbeforeRouteEnter(to, from, next) {\n next(vm=>{\n vm.routeList = to.meta.routeList\n })\n}\n```\n或者在watch里\n```\nthis.$route.meta.routeList\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_310",
"question": "webpack配置中devtool项加不加#有什么区别?\n用vue-cli生成的项目中webpack.dev.conf.js里有这么一段\n```\n// cheap-module-eval-source-map is faster for development\ndevtool: \"#cheap-module-eval-source-map\",\n\n```\n去webpack官网上看关于devtool的文档里面没提到说前面需要加#。实际中我去掉或者带上#也不会影响打包。那这个#到底干嘛用的呢?",
"answer": "文档里有说:\nPrefixing @, # or #@ will enforce a pragma style. (Defaults to @ in webpack@1 and # in webpack@2; using # is recommended)\n翻译成中文就是使用指定的符号来指定预处理风格",
"type": "technical_qa"
},
{
"id": "segmentfault_311",
"question": "TS中报错说style在element类型中不存在怎么办\n我用queryselectorall去获取一个dom元素集合然而在编译时却报错说property 'style' does not exist on type 'element'。在控制台里看block集合里各个元素是有style属性的但是用for循环去遍历就没了。求指教一下是不是要转类型或者是要用foreach去遍历\n用的是typescript。\n代码\n```\n var winWidth = document.body.clientWidth;\n var height = winWidth*1.23;\n let block = document.querySelectorAll(\".block\");\n for(var i=0;i<block.length;i++){\n block.item(i).style.height = height + \"px\";\n }\n \n \n```",
"answer": "这是typescript的类型检查导致的需要在你的querySelectorAll方法前面加个类型断言就好了如下\n```\nlet block = document.querySelectorAll(\".block\") as NodeListOf<HTMLElement>;\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_312",
"question": "js 指定删除数组(树结构数据)\n查找相同ID删除对象,ID相同则删除该对象\nvar data =[{id:1,name:'一级', children:[{id:2,name:'二级', children:[{id:3,name:'一级', children:[{id:31,name:'二级'},{id:32,name:'二级'},{id:33,name:'二级'}],company_id:7}],company_id:8}], company_id:9}]\n比如ID==31得到以下数组\n[{id:1,name:'一级', children:[{id:2,name:'二级', children:[{id:3,name:'一级', children:[{id:32,name:'二级'},{id:33,name:'二级'}],company_id:7}],company_id:8}], company_id:9}]",
"answer": "```\nfunction filter (data, id) {\n var newData = data.filter(x => x.id !== id)\n newData.forEach(x => x.children && (x.children = filter(x.children, id)))\n return newData\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_313",
"question": "一个电商系统中,消息中间件可以用来做什么呢?\n当然不仅仅限于电商 \n最近在了解消息中间件但是一直不太清楚消息中间件到底是干嘛的到底在一个系统中用来做什么就好比redis内存数据库我可以在系统中缓存数据缓解db压力可以充当队列用于订单系统异步处理只是拿redis来举个例子不是和kafka来比较在网上很多人介绍都只说生产者消费者模式异步阿用于消息告知等等看了之后更是一头雾水有了解的能否举几个在实际项目中或工作中场景中的例子可以更直观的对消息中间件有一个理解谢谢",
"answer": "就题目和个人理解回答:消息中间件,是解决分布式系统中各个系统相互通信的工具。\n举个很常用的例子\nA系统是分布式模块化构成\n包含a子系统--比如用户模块包含b子系统--比如资产模块。\n现在接到这样的一个需求要求在用户成功注册系统用户时要赠送积分给该用户。\n那么这个流程就是\n```\n用户注册——》a子系统新增用户——》a子系统新增用户成功通知b子系统加相应积分——》b子系统接收通知——》b子系统增加用户积分\n```\n以上的通知和接收即为消息中间件中的发布和订阅概念。\n当然你可能会问为什么不在同一个事物里注册完用户加相应用户积分\n答案是是可以的只是这样系统就不能达到模块之间业务解耦的目的。\n所以消息中间件又可以用来解决分布式系统各个模块耦合的功效。",
"type": "technical_qa"
},
{
"id": "segmentfault_314",
"question": "webpack打包生成的文件名问题\nwebpack入口为多页每个页面中有懒加载的组件打包出来懒加载的组件会打成不同id的文件名但是没有模快名分辨不出当前这个id属于哪个模块下如果能让懒加载的文件带上模块名\n如\n```\n` a.html \n a.js\n b.html\n b.js`\n```\n//懒加载模块分别对应a,b模块\n```\n` 1.js\n 2.js\n 3.js\n 4.js\n`\n```\n```\n //webpack配置\noutput: {\n path: config.build.assetsRoot,\n filename: utils.assetsPath('js/[name].[chunkhash].js'),\n chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')\n },\n```",
"answer": "代码里的`[name]`默认是`id`覆盖,如果你要给`chunkFilename`重新起名字,要使用`webpack1`的`require.ensure()`或`webpack2`以上的`import()`方法。\nwebpack1:\n```\nrequire.ensure(dependencies: String[], callback: function(require), chunkName: String)\n```\n上面的`chunkName`对应的就是`webpack`里的`chunkFilename`里的`[name]`\nwebpack2-3:\n```\nconst Foo = asyncComponent(() => import(/* webpackChunkName: \"foo\" */ \"./foo\"))\n\n<Route path=\"/xx\" component={Foo} />\n\n```\n上面的`import()`是`webpack2`以上版本的写法,注意`/* webpackChunkName: \"foo\" */`,这里对应的就是`webpack`里的`chunkFilename`里的`[name]`",
"type": "technical_qa"
},
{
"id": "segmentfault_315",
"question": "mysql数据检索过多导致索引没有生效的问题\n查询的时候在数据量过多时出现索引失效的情况请问是什么原因\n```\n具体情况mysql版本5.7.7,ad_stat_day表总数据在250W左右day_time字段上有建立索引\n```\n```\n-- 25号至30号总数据\nmysql> select count(*) from ad_stat_day where dayTime BETWEEN '2017-10-25' and '2017-10-30';\n+----------+\n| count(*) |\n+----------+\n| 107063 |\n+----------+\n1 row in set\n```\n```\n-- 只查id的情况下会走索引\nmysql> EXPLAIN select id from ad_stat_day where dayTime BETWEEN '2017-10-25' and '2017-10-30';\n+----+-------------+-------------+------------+-------+---------------+-------------+---------+------+--------+----------+--------------------------+\n| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |\n+----+-------------+-------------+------------+-------+---------------+-------------+---------+------+--------+----------+--------------------------+\n| 1 | SIMPLE | ad_stat_day | NULL | range | nk_day_time | nk_day_time | 4 | NULL | 189566 | 100 | Using where; Using index |\n+----+-------------+-------------+------------+-------+---------------+-------------+---------+------+--------+----------+--------------------------+\n1 row in set\n```\n```\n-- 查id,fee就不走索引了\nmysql> EXPLAIN select id,fee from ad_stat_day where dayTime BETWEEN '2017-10-25' and '2017-10-30';\n+----+-------------+-------------+------------+------+---------------+------+---------+------+--------+----------+-------------+\n| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |\n+----+-------------+-------------+------------+------+---------------+------+---------+------+--------+----------+-------------+\n| 1 | SIMPLE | ad_stat_day | NULL | ALL | nk_day_time | NULL | NULL | NULL | 646016 | 27.18 | Using where |\n+----+-------------+-------------+------------+------+---------------+------+---------+------+--------+----------+-------------+\n1 row in set\n```\n```\n--缩小条件范围查询id,fee也会走索引\nmysql> EXPLAIN select id,fee from ad_stat_day where dayTime BETWEEN '2017-10-27' and '2017-10-30';\n+----+-------------+-------------+------------+-------+---------------+-------------+---------+------+--------+----------+----------------------------------+\n| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |\n+----+-------------+-------------+------------+-------+---------------+-------------+---------+------+--------+----------+----------------------------------+\n| 1 | SIMPLE | ad_stat_day | NULL | range | nk_day_time | nk_day_time | 4 | NULL | 124092 | 100 | Using index condition; Using MRR |\n+----+-------------+-------------+------------+-------+---------------+-------------+---------+------+--------+----------+----------------------------------+\n1 row in set\n```\n求大佬告知下mysql是根据什么情况来选择使用索引和不使用索引的\n```\n这次范围扫描数据(189566行)不到表总数的10%,而加上一个字段就成了(646016行)占到表总数的25%来了这个646016行数据mysql是怎么算出来的还有mysql有明确的配置来说明超过某个阀值(百分比)就不使用索引了吗?\n```",
"answer": "索引:hiMySQL这次我给你带来了一个很大范围的索引片哦并且我的索引结构上面还有一个只在表结构里面存在的数据你看看怎么查询起来快吧...\nMySQL:我擦,你的数据量太大了,我还不如直接去表里面查快呢...\n索引:hiMySQL我为上次的事情道歉这次虽然给你带来的范围还是比较大但是呢我需要的字段都在我的索引结构上面你帮我处理一下吧...\nMySQL:嗯,这次你不需要通过表结构,我就直接在你自己身上给你处理吧...\n上文中的`MySQL`就是我们知道的`MySQL`的优化器在处理,《数据库索引结构和设计》这本书中有讲一个三星索引的概念,像你遇到的这种情况,你可以考虑一下是否需要建立一个`<day_time , fee>`的联合索引,不知道我是否有阐述清楚。",
"type": "technical_qa"
},
{
"id": "segmentfault_316",
"question": "关于vuex的作用。\n刚学过vuex,现在自己做了个电商小项目准备用下vuex,于是我就想说到把购物车的商品放vuex里边方便不同组件调用到购物车里边的数据但是实际项目中我想了下又感觉vuex没什么用原因如下\n当我们点击加入购物车的时候肯定要把需要加入购物车的商品传给后台呀。那我们进入到购物车组件里边直接从后台调取数据不就直接可以看到购物车的商品根本没必要把需要加入购物车的商品传给vuex呀。当然有一种可能就是传给vuex可以直接读取不用再调用后台数据。\n是我vuex用在购物车上本来就是错的那我可以用在什么地方举几个例子",
"answer": "在使用库或框架时,需要注意一个「适用性」的问题。\nVuex 或者说实现了 Flux 思想的库,解决了几个问题:\n1. 组件之间的数据通信\n2. 使用单向数据流的方式进行数据的中心化管理\n\n为什么要解决这样的问题呢其实是因为当程序逻辑过于复杂的时候非中心化的数据管理会让整个 app 的逻辑非常混乱。\n举一个不使用中心化的数据管理机制的具体例子\n一个 app ,有四个 tab每个 tab 都需要读取用户的资料。如果数据在每个 tab 的控制器里(或者说组件里)都存了一份,那么在用户手动更新了用户资料之后,就需要在每一个 tab 里都更新一遍用户资料,才能保证用户看到的永远是最新的资料。\n如你问题里所说我每进一个 tab 的时候重新请求一下不就好了吗?\n这样的解决方案不是不可以但弊端也非常明显\n1. 对于服务器端来说,频繁的请求是非常占用资源的,如果你的 app 用户足够多,那么每多出一个请求,对公司来说,都是一大笔钱。如果数据存在了 store 中,并且所有的 tab 都读取同一份数据,在用户更新资料时,在前端更新了 store 中的数据,是不是在切换 tab 时就减少了四个请求呢?\n2. 对于前端开发者来说,如果你的项目足够复杂,团队的规模也不仅是一个人,那么前端代码就会因为数据分散管理而产生非常严重的性能和稳定性的隐患(比如你的同事觉得进入模块就刷新用户资料太慢了,手贱把刷新的代码删了,你又没发现)。\n\n另外单向数据流的好处也很明显\n1. 视图组件变得很薄,只包含了渲染逻辑和触发 action 这两个职责,即所谓 \"dumb components\"。\n2. 要理解一个 store 可能发生的状态变化,只需要看它所注册的 actions 回调就可以。\n3. 任何状态的变化都必须通过 action 触发,而 action 又必须通过 dispatcher 走,所以整个应用的每一次状态变化都会从同一个地方流过。其实 Flux 和传统 MVC 最不一样的就在这里了。React 在宣传的时候一直强调的一点就是 “理解你的应用的状态变化是很困难的 (managing state changing over time is hard)”Flux 的意义就在于强制让所有的状态变化都必须留下一笔记录,这样就可以利用这个来做各种 debug 工具、历史回滚等等。\n你问题中的场景业务过于简单确实是没有必要使用 vuex 的,但这不代表其他大型应用不应该使用这个框架。",
"type": "technical_qa"
},
{
"id": "segmentfault_317",
"question": "es6如何快速的删除数组元素\n有这么一个数组\n```\nlet arr = [\n {id:1,value:2},\n {id:2,value:3},\n .......\n ]\n```\n想删除数组里id=8的元素\n使用es6如何方便快捷的实现",
"answer": "`ES6 findIndex` MDN :Array.prototype.findIndex()\n`findIndex()`方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。\n```\narr.splice(arr.findIndex(item => item.id === 8), 1)\n```\n推荐文章【深度长文】JavaScript数组所有API全解密 | louis blog",
"type": "technical_qa"
},
{
"id": "segmentfault_318",
"question": "懂远程调用Rpc框架的同学来解答一下\n看了一下rpc框架的作用是可以实现远程调用可以基于http协议也可以用别的协议。\n这里的远程调用指的应该是后端服务A和后端服务B互调吧虽然有些地方会把调用方称作客户端但其实还是服务端和服务端互调。\n那如果前端就比如浏览器端想通过post或者get方式去调后端的接口也能称之为RPC方式吗应该不是吧充其量就是基于http的restful接口调用吧。而且前端浏览器端想去调后端接口只能通过http协议如果那些实现了别的协议的rpc框架根本没法处理http请求吧\n不知道我的理解对不对",
"answer": "HTTP是通信协议RPC是一种开发方式他可以基于HTTP协议比如gRPC)也可以基于其他协议比如更基础的TCP\n通信协议的选择只是RPC实现中的一小部分更重要的一部分是编码协议。比如json/xml属于文本编码还有二进制字节编码比如protofulthrift。http对比tcp最诟病的就是多余的头信息而且还是使用的文本编码造成整个数据包体积过大。不过据说http2改进很多修改为二进制编码了还支持多路复用gRPC就是基于http2实现的。\n至于restful其实他本身是一套将资源对象化的设计标准不过目前都作为技术实现再用本身又分为严格的和非严格的。从目前上来说restful接口可以认为是一种基于http使用json编码的RPC实现但还是本身restful是设计规范更多的是约束资源的访问获取手段不应当用于复杂的函数调用。\n最后前后端目前javascript也有json-RPCajax-RPC一类的更专注于函数调用的RPC实现可以基于HTTP也可以基于websocket如果目的是函数调用你可以试用一下会比使用restful舒服很多。",
"type": "technical_qa"
},
{
"id": "segmentfault_319",
"question": "vue项目报错如下(Emitted value instead of an instance of Error) \n`(Emitted value instead of an instance of Error) the \"scope\" attribute for scoped slots have been deprecated and replaced by \"slot-scope\" since 2.5. The n\not-scope\" attribute can also be used on plain elements in addition to <template> to denote scoped slots.`",
"answer": "你检查下你的列表组件里slot 里的 <template> 上面有个 scope 属性,你改成 slot-scope\n```\n<template scope=\"xxx\">yyyyyyyy</template> \n```\n改成\n```\n<template slot-scope=\"xxx\">yyyyyyyy</template> \n```\nscope 属性在2.5以后的版本中已经废弃, 被 slot-scope 替代\nslot-scope 不光可以用在 template 元素上,也可以用在其它元素",
"type": "technical_qa"
},
{
"id": "segmentfault_320",
"question": "为什么element ui el-input @click事件无效\n```\n <el-form-item label=\"审批人\">\n <el-input v-model=\"formInline.user\" placeholder=\"审批人\" @click=\"alert(1)\"></el-input>\n </el-form-item>\n```\n如何给el-input添加点击事件",
"answer": "vue.js文档 给组件绑定原生事件\n#### 给组件绑定原生事件\n有时候你可能想在某个组件的根元素上监听一个原生事件。可以使用 v-on 的修饰符 .native。例如\n```\n<my-component v-on:click.native=\"doTheThing\"></my-component>\n```\n```\n// 使用`navite`修饰符\n@click.native=\"handleClick\"\nhandleClick(){\n alert(1);\n}\n// 你的写法会报错。会认为alert不是一个函数。好奇是什么场景要绑定点击事件到el-input呢\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_321",
"question": "问一个react更新State的问题\n读react官网\n状态更新可能是动态的\n```\n// Wrong\nthis.setState({\n counter: this.state.counter + this.props.increment,\n});\n```\n官网说这种写法是错误的\n```\n// Correct\nthis.setState((prevState, props) => ({\n counter: prevState.counter + props.increment\n}));\n```\n这种写法是正确的\n我实在搞不懂为什么第一个是错误的第二种写法是正确的哪位大神能帮忙解释一下在哪种需求场景下会出现上述的情况最好能写点代码解释下多谢大神们指导。",
"answer": "因为 this.props 和 this.state 可能是异步更新的你不能依赖他们的值计算下一个state(状态)。\nsetState 方法“或许”是异步的。也许你觉得,看上去更新 state 是如此轻而易举的操作,这并没有什么可异步处理的。但是要意识到,因为 state 的更新会触发 re-rendering而 re-rendering 代价昂贵短时间内反复进行渲染在性能上肯定是不可取的。所以React 采用 batching 思想,它会 batches 一系列连续的 state 更新,而只触发一次 re-render。\nsetState的机制其实跟浏览器的dom更新类似等到一定数量或者一定时间间隔才一起更新一次它们都是异步更新的所以这样做在一定几率是有问题的。\n或者直接看下面的一个小例子。\n比如最简单的一个场景是\n```\nfunction incrementMultiple() {\n this.setState({count: this.state.count + 1});\n this.setState({count: this.state.count + 1});\n this.setState({count: this.state.count + 1});\n}\n```\n直观上来看当上面的 incrementMultiple 函数被调用时,组件状态的\ncount 值被增加了3次每次增加1那最后 count 被增加了3。但是实际上的结果只给 state 增加了1。不信你自己试试\n## 让 setState 连续更新的几个 hack\n如果想让 count 一次性加3应该如何优雅地处理潜在的异步操作规避上述问题呢\n以下提供几种解决方案\n方法一常见的一种做法便是将一个回调函数传入 setState 方法中。即 setState 著名的函数式用法。这样能保证即便在更新被 batched 时,也能访问到预期的 state 或 props。后面会解释这么做的原理\n方法二另外一个常见的做法是需要在 setState 更新之后进行的逻辑(比如上述的连续第二次 count + 1封装到一个函数中并作为第二个参数传给 setState。这段函数逻辑将会在更新后由 React 代理执行。即:\nsetState(updater, [callback])\n方法三把需要在 setState 更新之后进行的逻辑放在一个合适的生命周期 hook 函数中,比如 componentDidMount 或者 componentDidUpdate 也当然可以解决问题。也就是说 count 第一次 +1 之后,出发 componentDidUpdate 生命周期 hook第二次 count +1 操作直接放在 componentDidUpdate 函数里面就好啦。\n更多详细内容:从 setState promise 化的探讨 体会 React 团队设计思想",
"type": "technical_qa"
},
{
"id": "segmentfault_322",
"question": "Vue 中 keep-alive 是怎么实现的\nvue中keep-alive的实现原理是什么?有什么限制?",
"answer": "首先你要知道Vue.js内部将DOM节点抽象成了一个个的VNode节点这个我之前写过相关文章可以参考VNode节点。\n所以keep-alive的缓存也是基于VNode节点的而不是直接存储DOM结构。\n看一下keep-alive这个组件的代码。\n```\ntype VNodeCache = { [key: string]: ?VNode };\n\nconst patternTypes: Array<Function> = [String, RegExp]\n\n/* 获取组件名称 */\nfunction getComponentName (opts: ?VNodeComponentOptions): ?string {\n return opts && (opts.Ctor.options.name || opts.tag)\n}\n\n/* 检测name是否匹配 */\nfunction matches (pattern: string | RegExp, name: string): boolean {\n if (typeof pattern === 'string') {\n /* 字符串情况如a,b,c */\n return pattern.split(',').indexOf(name) > -1\n } else if (isRegExp(pattern)) {\n /* 正则 */\n return pattern.test(name)\n }\n /* istanbul ignore next */\n return false\n}\n\n/* 修正cache */\nfunction pruneCache (cache: VNodeCache, current: VNode, filter: Function) {\n for (const key in cache) {\n /* 取出cache中的vnode */\n const cachedNode: ?VNode = cache[key]\n if (cachedNode) {\n const name: ?string = getComponentName(cachedNode.componentOptions)\n /* name不符合filter条件的同时不是目前渲染的vnode时销毁vnode对应的组件实例Vue实例并从cache中移除 */\n if (name && !filter(name)) {\n if (cachedNode !== current) {\n pruneCacheEntry(cachedNode)\n }\n cache[key] = null\n }\n }\n }\n}\n\n/* 销毁vnode对应的组件实例Vue实例 */\nfunction pruneCacheEntry (vnode: ?VNode) {\n if (vnode) {\n vnode.componentInstance.$destroy()\n }\n}\n\n/* keep-alive组件 */\nexport default {\n name: 'keep-alive',\n /* 抽象组件 */\n abstract: true,\n\n props: {\n include: patternTypes,\n exclude: patternTypes\n },\n\n created () {\n /* 缓存对象 */\n this.cache = Object.create(null)\n },\n\n /* destroyed钩子中销毁所有cache中的组件实例 */\n destroyed () {\n for (const key in this.cache) {\n pruneCacheEntry(this.cache[key])\n }\n },\n\n watch: {\n /* 监视include以及exclude在被修改的时候对cache进行修正 */\n include (val: string | RegExp) {\n pruneCache(this.cache, this._vnode, name => matches(val, name))\n },\n exclude (val: string | RegExp) {\n pruneCache(this.cache, this._vnode, name => !matches(val, name))\n }\n },\n\n render () {\n /* 得到slot插槽中的第一个组件 */\n const vnode: VNode = getFirstComponentChild(this.$slots.default)\n\n const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions\n if (componentOptions) {\n // check pattern\n /* 获取组件名称优先获取组件的name字段否则是组件的tag */\n const name: ?string = getComponentName(componentOptions)\n /* name不在inlcude中或者在exlude中则直接返回vnode没有取缓存 */\n if (name && (\n (this.include && !matches(this.include, name)) ||\n (this.exclude && matches(this.exclude, name))\n )) {\n return vnode\n }\n const key: ?string = vnode.key == null\n // same constructor may get registered as different local components\n // so cid alone is not enough (#3269)\n ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag` : '')\n : vnode.key\n /* 如果已经做过缓存了则直接从缓存中获取组件实例给vnode还未缓存过则进行缓存 */\n if (this.cache[key]) {\n vnode.componentInstance = this.cache[key].componentInstance\n } else {\n this.cache[key] = vnode\n }\n /* keepAlive标记位 */\n vnode.data.keepAlive = true\n }\n return vnode\n }\n}\n```\n其实就是将需要缓存的VNode节点保存在this.cache中在render时,如果VNode的name符合在缓存条件可以用include以及exclude控制则会从this.cache中取出之前缓存的VNode实例进行渲染。",
"type": "technical_qa"
},
{
"id": "segmentfault_323",
"question": "maven mybatis-generator:generate失败 Exception getting JDBC Driver\n生成配置文件如下:\n```\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE generatorConfiguration\n PUBLIC \"-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN\"\n \"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd\">\n\n<generatorConfiguration>\n <context id=\"MySQLTables\" targetRuntime=\"MyBatis3\">\n <!-- 配置数据库链接信息 -->\n <jdbcConnection driverClass=\"com.mysql.jdbc.Driver\"\n connectionURL=\"jdbc:mysql://localhost:3306/ssm_crud?useSSL=false\"\n userId=\"root\"\n password=\"ABCabc123#\">\n </jdbcConnection>\n\n <javaTypeResolver>\n <property name=\"forceBigDecimals\" value=\"false\"/>\n </javaTypeResolver>\n\n <!-- 指定javaBean生成的位置 -->\n <javaModelGenerator targetPackage=\"io.ride.domain\" targetProject=\".\\src\\main\\java\">\n <property name=\"enableSubPackages\" value=\"true\"/>\n <property name=\"trimStrings\" value=\"true\"/>\n </javaModelGenerator>\n\n <!-- 制定sql映射文件的生成位置 -->\n <sqlMapGenerator targetPackage=\"io.ride.mapper\" targetProject=\".\\src\\main\\java\">\n <property name=\"enableSubPackages\" value=\"true\"/>\n </sqlMapGenerator>\n\n <!-- 指定dao接口生成位置 -->\n <javaClientGenerator type=\"XMLMAPPER\" targetPackage=\"io.ride.dao\" targetProject=\".\\src\\main\\java\">\n <property name=\"enableSubPackages\" value=\"true\"/>\n </javaClientGenerator>\n\n <!-- 制定每个表的生成策略 -->\n <table tableName=\"t_emp\" domainObjectName=\"Employee\"></table>\n <table tableName=\"t_dpt\" domainObjectName=\"Department\"></table>\n <!--<table schema=\"DB2ADMIN\" tableName=\"ALLTYPES\" domainObjectName=\"Customer\">-->\n <!--<property name=\"useActualColumnNames\" value=\"true\"/>-->\n <!--<generatedKey column=\"ID\" sqlStatement=\"DB2\" identity=\"true\"/>-->\n <!--<columnOverride column=\"DATE_FIELD\" property=\"startDate\"/>-->\n <!--<ignoreColumn column=\"FRED\"/>-->\n <!--<columnOverride column=\"LONG_VARCHAR_FIELD\" jdbcType=\"VARCHAR\"/>-->\n <!--</table>-->\n\n </context>\n</generatorConfiguration>\n```\nmaven配置\n```\n <plugins>\n <plugin>\n <groupId>org.mybatis.generator</groupId>\n <artifactId>mybatis-generator-maven-plugin</artifactId>\n <version>1.3.3</version>\n <configuration>\n <!-- 指定配置文件 -->\n <configurationFile>mybatis-generator.xml</configurationFile>\n <verbose>true</verbose>\n <overwrite>true</overwrite>\n </configuration>\n <executions>\n <execution>\n <id>Generate MyBatis Artifacts</id>\n <goals>\n <goal>generate</goal>\n </goals>\n </execution>\n </executions>\n <dependencies>\n <dependency>\n <groupId>org.mybatis.generator</groupId>\n <artifactId>mybatis-generator-core</artifactId>\n <version>1.3.3</version>\n </dependency>\n </dependencies>\n </plugin>\n </plugins>\n```\n异常报错:\norg.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.mybatis.generator:mybatis-generator-maven-plugin:1.3.3:generate (default-cli) on project SSM_CRUD: Execution default-cli of goal org.mybatis.generator:mybatis-generator-maven-plugin:1.3.3:generate failed: Exception getting JDBC Driver\n```\n[ERROR] Failed to execute goal org.mybatis.generator:mybatis-generator-maven-plugin:1.3.3:generate (default-cli) on project SSM_CRUD: Execution default-cli of goal org.mybatis.generator:mybatis-generator-maven-plugin:1.3.3:generate failed: Exception getting JDBC Driver: com.mysql.jdbc.Driver -> [Help 1]\norg.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.mybatis.generator:mybatis-generator-maven-plugin:1.3.3:generate (default-cli) on project SSM_CRUD: Execution default-cli of goal org.mybatis.generator:mybatis-generator-maven-plugin:1.3.3:generate failed: Exception getting JDBC Driver\n at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212)\n at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)\n at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)\n at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)\n at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)\n at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)\n at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)\n at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:307)\n at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:193)\n at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:106)\n at org.apache.maven.cli.MavenCli.execute(MavenCli.java:863)\n at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288)\n at org.apache.maven.cli.MavenCli.main(MavenCli.java:199)\n at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n at java.lang.reflect.Method.invoke(Method.java:498)\n at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)\n at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)\n at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)\n at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)\n at org.codehaus.classworlds.Launcher.main(Launcher.java:47)\nCaused by: org.apache.maven.plugin.PluginExecutionException: Execution default-cli of goal org.mybatis.generator:mybatis-generator-maven-plugin:1.3.3:generate failed: Exception getting JDBC Driver\n at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:145)\n at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:207)\n ... 21 more\nCaused by: java.lang.RuntimeException: Exception getting JDBC Driver\n at org.mybatis.generator.internal.db.ConnectionFactory.getDriver(ConnectionFactory.java:85)\n at org.mybatis.generator.internal.db.ConnectionFactory.getConnection(ConnectionFactory.java:54)\n at org.mybatis.generator.config.Context.getConnection(Context.java:733)\n at org.mybatis.generator.config.Context.introspectTables(Context.java:618)\n at org.mybatis.generator.api.MyBatisGenerator.generate(MyBatisGenerator.java:254)\n at org.mybatis.generator.api.MyBatisGenerator.generate(MyBatisGenerator.java:188)\n at org.mybatis.generator.maven.MyBatisGeneratorMojo.execute(MyBatisGeneratorMojo.java:199)\n at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)\n ... 22 more\nCaused by: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver\n at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:50)\n at org.codehaus.plexus.classworlds.realm.ClassRealm.unsynchronizedLoadClass(ClassRealm.java:271)\n at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:247)\n at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:239)\n at java.lang.Class.forName0(Native Method)\n at java.lang.Class.forName(Class.java:348)\n at org.mybatis.generator.internal.ObjectFactory.internalClassForName(ObjectFactory.java:167)\n at org.mybatis.generator.internal.ObjectFactory.externalClassForName(ObjectFactory.java:122)\n at org.mybatis.generator.internal.db.ConnectionFactory.getDriver(ConnectionFactory.java:82)\n ... 29 more\n[ERROR] \n[ERROR] Re-run Maven using the -X switch to enable full debug logging.\n[ERROR] \n[ERROR] For more information about the errors and possible solutions, please read the following articles:\n[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException\n\n```",
"answer": "```\n<plugin>\n <groupId>org.mybatis.generator</groupId>\n <artifactId>mybatis-generator-maven-plugin</artifactId>\n <version>1.3.2</version>\n <configuration>\n <configurationFile>${basedir}/src/main/resources/generatorConfig.xml</configurationFile>\n <overwrite>false</overwrite>\n <verbose>true</verbose>\n </configuration>\n <dependencies>\n <dependency>\n <groupId>mysql</groupId>\n <artifactId>mysql-connector-java</artifactId>\n <version>${mysql.version}</version>\n </dependency>\n </dependencies>\n</plugin>\n```\n在plugin中单独依赖Mysql驱动包",
"type": "technical_qa"
},
{
"id": "segmentfault_324",
"question": "vue-cli构建的项目eslint一直报CRLF/LF的linebreak错误\n如题vue在构建项目的时候选择了airbnb规则同时项目构建后被windows的unix bash工具pull并且push过这之后在windows上进行开发就开始一直报\n```\nExpected linebreaks to be 'CRLF' but found 'LF'\n```\n这样的错误后经查是一种强制统一方式并且解决方法是\n```\nlinebreak-style: [\"error\", \"windows\"]\n```\n强制使用windows方式我将之添加到了项目根目录下的 .eslintrc.js 文件中的rule字段下\n```\n// add your custom rules here\n 'rules': {\n // don't require .vue extension when importing\n 'import/extensions': ['error', 'always', {\n 'js': 'never',\n 'vue': 'never'\n }],\n // allow optionalDependencies\n 'import/no-extraneous-dependencies': ['error', {\n 'optionalDependencies': ['test/unit/index.js']\n }],\n // try to fix the line break problem\n 'linebreak-style': [\"error\", \"windows\"],\n // allow debugger during development\n 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0\n }\n```\n结果无效现有问题二个'1. 是否是因为系统环境不同而造成了某种强制转换才会引发如上的错误?\n2. 如何选择性的关闭eslint某个功能linebreak检查",
"answer": "#### 问题1\n不同的操作系统下甚至是不同编辑器不同工具处理过的文件可能都会导致换行符的改变。\n#### 问题2\n项目根目录下有`.eslintrc.js`文件在配置文件中修改rule配置项如下\n```\n// 统一换行符,\"\\n\" unix(for LF) and \"\\r\\n\" for windows(CRLF)默认unix\n// off或0: 禁用规则\n'linebreak-style': 'off'\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_325",
"question": "关于javascript es6 class中static方法的使用场景\n我们知道在class中定义的static方法在使用时可以直接调用不用实例化我的疑惑是\n1. 在定义类的方法的时候什么方法适宜定义成static什么方法不用\n2. 我可不可以把类中的方法都定义为static,这 样做有什么弊端没有?\n还请详细介绍下class的适用场景以及static的适用场景不胜感激",
"answer": "在OOP中带方法的类即非数据类一般有两个作用\n- 封装方法和属性(通常意义的 OOP 类)\n- 封装临时变量(和来处理复杂事务的类)\n\n不管哪个作用方法通常都是会操作成员变量的这种情况下肯定只能写实例方法因为要操作成员\n除此之外不需要访问类属性的方法都可以写成静态的这类方法一般都是 Helper 方法,即对输入进行处理再得到一个输出,与对象的成员无关。这类方法也可以直接写为公共函数(非方法函数)。不过在 C#、Java、TypeScript 等有权限限制的语言中,静态方法可以访问对象的私有成员,比如 `Foo` 类的 `Foo.bla(f: Foo)` 静态方法内部可以直接访问 `f.somePrivateMethod()`,当然目前 JavaScript 中不存在这种情况,以后引入私有成员之后会不会存在这种情况也还要观望\n顺便说一下多数静态类型语言中成员方法都是可以直接调用同一个类的静态方法的但 JavaScript 由于实现机制不能,做不到。\n### 回看有惊喜2020-02-27 更新\nJavaScript 的私有字段提议已经到了 stage-3 (实验) 阶段TypeScript 3.8 和 Chrome 7.4 已经支持私有字段,那么前面提到的疑惑其实是可以实验来验证的\n实验环境\n- Microsoft Edge Version 80.0.361.62 (Official build) (64-bit)\n- TypeScript Playground\n\n实验代码TypeScript\n```\nclass MyClass {\n static create(name: string, age: number = 10) {\n var obj = new MyClass();\n obj.#name = name;\n obj.#age = age;\n }\n\n #name: string;\n #age: number;\n\n constructor() {\n this.#name = \"Default Name\";\n this.#age = 0;\n }\n\n toString(): string {\n return `${this.#name}: ${this.#age`;\n }\n}\n\nconst inst = MyClass.create(\"James\", 10);\n// inst.#name = \"Hello\";\n\nconsole.log(inst.toString());\n```\n结论\n- 静态方法(`static create()`) 中可以访问对象的私有成员 `#name` 和 `#age`\n- 外部不能访问对象的私有成员(`inst.#name = \"Hello\"` 会报错)",
"type": "technical_qa"
},
{
"id": "segmentfault_326",
"question": "react ant design 中如何在表头中加个Icon,悬浮icon又触发Tooltip?\n如题表头的某一列是\n```\n<Table.Column title='目的地' dataIndex='destination' key='destination'></Table.Column>\n```\n显示效果就是目的地。\n我想在后面加个问号的Iconquestion-circle,鼠标悬停上去的时候显示提示文字:‘这是提示’。\n这里面用到了TableIcon.Tooltip三个组件但是不知道该怎么写出来。写法一直报错。",
"answer": "`Table.Column` 的 `title` 传值可以传入一个 `ReactNode `。\n所以可以写成这样\n```\nconst title = (\n <span>\n 目的地\n <Tooltip title=\"这是提示\">\n <Icon style={{ marginLeft: '0.25em' }} type=\"question-circle\" />\n </Tooltip>\n </span>\n);\n\n<Table.Column title={title} dataIndex='destination' key='destination'></Table.Column>\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_327",
"question": "js promise中如何取到[[PromiseValue]] ?\n```\nPromise {[[PromiseStatus]]: \"resolved\", \n [[PromiseValue]]: \"http://dl.stream.qqmusic.qq.com/M8000046HRBd0FvKLm…C380C8F140044403EDC0124&guid=489780640&fromtag=30\"\n }\n```\n有一个promise现在取到的值为上述所示 能不能直接从中取到 promisevalue的url\n该promise由 `QQMusic.getSong(1561).then(song => song.url)` 获得\n这个程序是别人写的再加上不太了解promise所以请问下可否直接取到",
"answer": "```\nvar a = Promise.resolve('xx')\n// Promise {[[PromiseStatus]]: \"resolved\", [[PromiseValue]]: \"xx\"}\na.then(function (result) { console.log(result) })\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_328",
"question": "vue的CDN有几种文件结尾分别是什么意思\nCDN地址\nhttp://www.bootcdn.cn/vue/\n下面几种文件结尾分别是什么意思\n```\nvue.js\nvue.common.js\nvue.esm.js\nvue.runtime.js\nvue.runtime.esm.js\nvue.runtime.common.js\n```",
"answer": "common和esm分别是2种现代模块化规范CommonJS和EcmaScript Module的缩写。\n现在主流的webpack2采用esm也就是es6及以上的模块化编程说白了就是\nimport ... from ...\nvue.runtime.js则是运行时的意思纯粹全是javascript适用于生产环境需要经过预编译。\n官方说法是用来创建 Vue 实例,渲染并处理 virtual DOM 等行为的代码。基本上就是除去编译器的其他一切。\nvue.esm.js预编译+运行时,也就是模板字符串和现在最常用的单文件组件.vue文件需要经过它预编译转化成纯javascrit然后再运行适用于开发环境。\n官方说法叫用来将模板字符串编译成为 JavaScript 渲染函数的代码。\nvue.js则是直接用在<script>标签中的。\n1.若是自己写个小demo测试一下\n```\n用vue.js即可方便阅读源码\n\n```\n2.若你是用vue2+webpack2开发项目vue-cli采用的方式\n```\n开发环境用vue.esm.js\n生产环境用vue.runtime.esm.js比完整版小30%左右,前端性能更优\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_329",
"question": "怎么让类数组使用forEach?\n```\n<div>1</div>\n<div>2</div>\n\n```\n```\nlet div = document.getElementsByTagName('div');\n\ndiv.forEach = Array.prototype.forEach;\ndiv.forEach(item=>{\n console.log(item);\n});\n这样是一种方法如何使用call、apply或bind 使用forEach方法\n\n```",
"answer": "```\n[].forEach.call(document.getElementsByTagName(\"div\"), (item) => console.log(item))\n```\n```\n[].forEach.apply(document.getElementsByTagName(\"div\"), [(item) => console.log(item)])\n```\n```\nvar getDivs = [].forEach.bind(document.getElementsByTagName(\"div\"))\ngetDivs(item => console.log(item))\n```\n```\ndocument.querySelectorAll('div').forEach(item => console.log(item))\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_330",
"question": "正则表达式3-10位必须包含至少1个数字和1个字母为何我这样写不对\n```\n(?=[a-zA-Z]+)(?=[0-9]+)[a-zA-Z0-9]{3,10}\n```\n上面是我写的但不正确不知道原因。我理解的是第一个正向预查找出至少一个字母和第二个正向预查找出至少一个字母。然后最后是[a-zA-Z0-9]{3,10},这大家都懂。不知道哪里错了,是不是我对正向预查的理解不正确?",
"answer": "`?=`不同的人叫法不一样,你称之为`预查`,我更倾向于叫`零宽断言`,也就是说`?=`只是匹配一个位置,并不匹配具体的字符,所以是`零宽`也就是宽度是0。\n所以`(?=[a-zA-Z]+)`匹配一个位置,这个位置后面`紧跟`至少一个字母,注意此时位置并没有后移;\n`(?=[0-9]+)`也是匹配一个位置,这个位置后面后面`紧跟`至少一个数字;\n因为`(?=[a-zA-Z]+)`和`(?=[0-9]+)`都只匹配位置,而不匹配具体的字符,这两个又直接写在了一起,也就是说`(?=[a-zA-Z]+)(?=[0-9]+)`意味着这个位置后面`紧跟`至少一个字母,`同时紧跟`至少一个数字,也就是说这个位置后面的字符既是字母又是数字,显然这样的位置不存在。\nUpdate:\n你试试这个`/^(?=[a-zA-Z]*[0-9])(?=[0-9]*[a-zA-Z])[a-zA-Z0-9]{3,10}$/`。",
"type": "technical_qa"
},
{
"id": "segmentfault_331",
"question": "JS 中 new Date 默认为1或0的问题\n最近看到了一个获取天数的写法之前一直没用过直接上代码\n```\nlet dayLength = new Date(2017,2,0); //28\n```\n有哪位大佬知道上面为什么能得到2017年2月的总天数吗\n看了 MDN 没找到答案MDN_Date",
"answer": "虽然 `new Date(2017,2,0)` 并不是输出 28 但是它却包含 28 这个信息,确实是一个获取某月天数的好方法。\n下面来说下为什么Date 作为构造函数,有一种用法是这样的,就是您说的这种:\n`new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);`\n重点\nmonth 参数,是指月份,从 0 开始也就是说0 表示 1月2表示 3月。\nday 参数,是指月份中的某一天,从 1 开始,也就是说 1 就是月份中的第一天2就是第二天0 是不在取值范围内的\n然后看一下 ES 规范http://es5.github.io/#x15.9.1.12,这一节的第七和第八条:\n7.Find a value t such that YearFromTime(t) == ym and MonthFromTime(t) == mn) and DateFromTime(t) == 1; but if this is not possible (because some argument is out of range), return NaN. \n8.Return Day(t) + dt 1.\n简单解释下就是传入 year, month, day 来获取一个新的日期实例时,会先获取指定年、月的 1 号,例如 year=2017, month=4会先获取 2017-5-1 这个日期,这是上面第七步完成的。\n然后第八步上面这个日期会加上 day 参数的整数值,然后减去 1。\n看见了没有要减去 1。你上面的例子\n```\nnew Date(2017, 2, 0)\n```\n先获取 `2017-3-1` 然后 加上 0 ,再减去 1就是 `2017-2-28`\n明白了吧。\n综上咱们可以这样来获取某年某月有多少天\n```\nfunction getMonthLength(year, month) {\n return new Date(year, month, 0).getDate();\n}\n\ngetMonthLength(2017, 2); //28\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_332",
"question": "后台管理系统有必要允许多端登录么?\nphp在写后台管理系统的时候有必要开启多设备登录么请发表观点并说明原因吧谢谢",
"answer": "允许还不允许,取决于你的需求。比如早期 QQ 就不允许多端登录,但是随着智能手机的发展,越来越多人 PC、手机同时登录QQ也就允许多端了。\n到底需要不需要应该从你的应用的使用场景去考虑比如是否有两地同时办公(比如办公室、家里)的场景有没有PC、手机同时访问的需求有没有 Web、客户端同时访问的需求……",
"type": "technical_qa"
},
{
"id": "segmentfault_333",
"question": "如何在 Spring容器 service层获取当前登录用户信息\n用户信息绑定会话怎样才可以在服务层注入",
"answer": "谢谢邀请回答。\n如果不想在controller拿到用户信息传到service层直接在service层也是可以拿到的。\nspring mvc在处理请求的时候会把请求对象放到RequestContextHolder持有的ThreadLocal对象中,你可以去看看DispatcherServlet类的源代码。\n在service层可以按照如下代码获取\n```\n//获取到当前线程绑定的请求对象\nHttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();\n//已经拿到session,就可以拿到session中保存的用户信息了。\n System.out.println(request.getSession().getAttribute(\"userInfo\"));\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_334",
"question": "拼团活动 的 业务逻辑\n有人做过拼团活动么做过的讲一下业务逻辑吧。看看和我自己想的一样不。",
"answer": "可以参照人人商城的拼团活动网上有源码或者是有赞的只能看规则什么的或者是拼多多同样是展示这里有0元参团的正好可以用来查看各界面展示他们三个逻辑也各不相同但大体思路是一样的。\n相关的表差不多是\n- 拼团商品表(包含商品信息,是否单独购买,开团人数,开团期限等)\n- 开团信息表(关联拼团商品,团开始时间,团结束时间,总人数,当前参团人数,开团人,参与人等)\n- 开团会员的购买订单表(也可在普通商品订单表基础上增加字段区分)\n\n需要注意的基本就是\n- 超时未成团的自动退款(可能需要支付宝、微信等退款接口)\n- 未成团前不能发起退款,只有成团后才能发起退款\n- 未支付成功不算参团,需要注意超卖的情况\n\n大体是这样的吧。",
"type": "technical_qa"
},
{
"id": "segmentfault_335",
"question": "vue-router两种模式到底什么情况下用hash,什么情况下用history模式呢\nvue-router两种模式hashhistory看了官方文档也不怎么明白到底什么情况下用hash,什么情况下用history模式呢",
"answer": "#### None\n对于 Vue 这类渐进式前端开发框架,为了构建 SPA单页面应用需要引入前端路由系统这也就是 Vue-Router 存在的意义。前端路由的核心,就在于 —— 改变视图的同时不会向后端发出请求。\n为了达到这一目的浏览器当前提供了以下两种支持\n1. \nhash —— 即地址栏 URL 中的 `#` 符号(此 hash 不是密码学里的散列运算)。\n比如这个 URL`http://www.abc.com/#/hello`hash 的值为 `#/hello`。它的特点在于hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。\n2. \nhistory —— 利用了 HTML5 History Interface 中新增的 `pushState()` 和 `replaceState()` 方法。(需要特定浏览器支持)\n这两个方法应用于浏览器的历史记录栈在当前已有的 `back`、`forward`、`go` 的基础之上, 它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL但浏览器不会立即向后端发送请求。\n\n因此可以说hash 模式和 history 模式都属于浏览器自身的特性Vue-Router 只是利用了这两个特性(通过调用浏览器提供的接口)来实现前端路由。\n#### None\n一般场景下hash 和 history 都可以,除非你更在意颜值,`#` 符号夹杂在 URL 里看起来确实有些不太美丽。\n> 如果不想要很丑的 hash我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成\nURL 跳转而无须重新加载页面。—— Vue-router 官网。\n另外根据 Mozilla Develop Network 的介绍,调用 `history.pushState()` 相比于直接修改 `hash`,存在以下优势:\n- \n`pushState()` 设置的新 URL 可以是与当前 URL 同源的任意 URL而 `hash` 只可修改 `#` 后面的部分,因此只能设置与当前 URL 同文档的 URL\n- \n`pushState()` 设置的新 URL 可以与当前 URL 一模一样,这样也会把记录添加到栈中;而 `hash` 设置的新值必须与原来不一样才会触发动作将记录添加到栈中;\n- \n`pushState()` 通过 `stateObject` 参数可以添加任意类型的数据到记录中;而 `hash` 只可添加短字符串;\n- \n`pushState()` 可额外设置 `title` 属性供后续使用。\n\n当然啦`history` 也不是样样都好。SPA 虽然在浏览器里游刃有余,但真要通过 URL 向后端发起 HTTP 请求时,两者的差异就来了。尤其在用户手动输入 URL 后回车,或者刷新(重启)浏览器的时候。\n1. \n`hash` 模式下,仅 `hash` 符号之前的内容会被包含在请求中,如 `http://www.abc.com`,因此对于后端来说,即使 没有做到对路由的全覆盖,也不会返回 404 错误。\n2. \n`history` 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 `http://www.abc.com/book/id`。如果后端缺少对 `/book/id` 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则 应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”\n\n#### 小节\n对于一般的 Vue + Vue-Router + Webpack + XXX 形式的 Web 开发场景,用 `history` 模式即可只需在后端Apache 或 Nginx进行简单的路由配置同时搭配前端路由的 404 页面支持。",
"type": "technical_qa"
},
{
"id": "segmentfault_336",
"question": "vscode 怎么双击选中连字符\n我的css类名习惯用 - 横线连字符可是在vscode每次双击只能选中其中一个单词不能选中整个连字符请问有办法解决吗谢谢了",
"answer": "在设置里\n```\n // 执行文字相关的导航或操作时将用作文字分隔符的字符\n \"editor.wordSeparators\": \"`~!@#$%^&*()-=+[{]}\\\\|;:'\\\",.<>/?\",\n```\n去掉 - 就好了。",
"type": "technical_qa"
},
{
"id": "segmentfault_337",
"question": "JS 构造函数原型对象设为 null为什么其实例依旧存在原型链\n```\n function Dog(){}\n Dog.prototype = null;\n var dog = new Dog();\n console.log(dog.__proto__==Object.prototype)//为什么这里dog.__proto_不是null不是dog.__proto应该指向 Dog.prototype的么\n```",
"answer": "可以查看es5的说明\n> If Type(proto) is not Object, set the [[Prototype]] internal property of obj to the standard built-in Object prototype object as described in 15.2.4.\n就是说在通过 new 关键字来创建一个对象的时候,会查看 Dog.prototype 是不是一个对象,如果不是的话,就设置为 `Object.prototype`\n如果你想让 dog 没有原型链,可以 `var dog = Object.create(null)`\n`Object.create`的执行步骤可以看这里:\n> Set the [[Prototype]] internal property of obj to O.\n`Object.create(null)`\n等价于\n```\nvar obj = new Object();\nobj.__proto__ = null;\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_338",
"question": "PHP命名空间中define和const的区别\n比如在a.php用define定义一个常量在b.php中声明一个命名空间 && 引入a.php\n此时在b.php中无法再次定义同名的常量然而用const却可以求解谢谢诸位\n```\na.php代码\ndefine('ROOT','123');\n\nb.php代码\nnamespace web360;\nrequire 'c.php';\ndefine('ROOT','123');\n```\n此时会报错常量已经定义\n而如果用const定义的话则不会出现此问题",
"answer": "这是因为 define 不会考虑命名空间,而 const 会。\n简单的说使用 define 定义时,不会考虑当前的命名空间,所以你两次定义的常量名称重复,会报重复定义。\n而使用 const 定义时,会带上命名空间,你两次定义的常量实际是 `ROOT` 和 `web360\\ROOT` 。名称不重复,不会报重复定义的错误。",
"type": "technical_qa"
},
{
"id": "segmentfault_339",
"question": "Python中list+dict的一个小问题求大家帮忙解答\nl1 = [\n{\"name\": \"aaa\",\"value\": 1},\n{\"name\": \"aaa\",\"value\": 1},\n{\"name\": \"bbb\",\"value\": 2},\n{\"name\": \"bbb\",\"value\": 1}\n]\nl2 = [\n{\"name\": \"aaa\", \"value\": 2},\n{\"name\": \"bbb\", \"value\": 3}\n]\nl1--->l2?\n请教一个小问题如何将列表l1中所有dict中name相同的value加起来生成类似于l2的列表",
"answer": "```\ndata = [\n {\"name\": \"aaa\", \"value\": 1},\n {\"name\": \"aaa\", \"value\": 1},\n {\"name\": \"bbb\", \"value\": 2},\n {\"name\": \"bbb\", \"value\": 1}\n]\n\n#第一种pandas\nimport pandas as pd\n\ndf = pd.DataFrame(data)\nprint df.groupby('name', as_index=False).sum().to_dict(orient='records')\n\n\n#第二种groupby\nfrom itertools import groupby\nlst = []\nfor k, g in groupby(sorted(data), key=lambda x: x['name']):\n lst.append(dict(name=k, value=sum([_['value'] for _ in list(g)])))\nprint lst\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_340",
"question": "对于<router-view></router-view>的用法\n在APP.vue主组件中内容上就只有<router-view></router-view>,然后在其他页面也有<router-view></router-view>,它是怎么传递的。原理是什么",
"answer": "可以这样理解,正常写法中,一层路径(`/xxx`)对应一个`router-view`。\n比如url: /a/b/c (假设a、b、c都为正常路径不会作为参数)\n- 那`/a`对应的就是App.vue中的router-view`/a`进入`a.vue`中\n- 那`/a/b`对应的就是a.vue中的router-view `/a/b`进入`b.vue`中\n\n以此类推。",
"type": "technical_qa"
},
{
"id": "segmentfault_341",
"question": "ES6中如何判断Set和Map等类型\n怎么判断这些数据类型?",
"answer": "Chai 有过讨论,这个应该可以满足了\n```\nfunction getType(obj) {\n var type = Object.prototype.toString.call(obj).match(/^\\[object (.*)\\]$/)[1].toLowerCase();\n if(type === 'string' && typeof obj === 'object') return 'object'; // Let \"new String('')\" return 'object'\n if (obj === null) return 'null'; // PhantomJS has type \"DOMWindow\" for null\n if (obj === undefined) return 'undefined'; // PhantomJS has type \"DOMWindow\" for undefined\n return type;\n }\n```\n```\ngetType(new Map()) // \"map\"\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_342",
"question": "如何通过onclick添加多个事件\n那天面试官问我一个问题如何用`onclick`给一个元素添加多个事件。\n前提是这个元素已经有一个其它人绑定的事件在无法修改那个绑定代码的情况下现在你需要再绑定一个如何做\n```\nelement.onclick = function(){\n alert(1);\n}\n```\n这个是未知的只知道已经绑定了一个事件现在需要添加一个绑定\n```\nelement.onclick = function(){\n alert(2); \n}\n```\n请赐教。",
"answer": "面试官估计是想考你给onclick重新包裹一个函数后上下文的切换与参数的传递\n```\nfunction addClickEvent(el,fn){\n if(el.onclick){\n var _bak = el.onclick;\n el.onclick = function(e){\n _bak.call(this,e)\n fn.call(this,e)\n }\n }else{\n el.onclick = fn\n }\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_343",
"question": "【mongoose】连接警告`open()` is deprecated in mongoose >= 4.11.0\nmongoose 连接成功,但是发出警告,好像是新版本要修改哪?错误信息如下\n```\nDeprecationWarning: `open()` is deprecated in mongoose >= 4.11.0use `openUri()` instead, or set the `useMongoClient` option if using `connect()` or `createConnection()`\n```\n网上找了半天没有结果求答案附上连接代码\n```\nvar mongoose = require('mongoose')\nmongoose.connect('mongodb://localhost/test');\nvar db = mongoose.connection\n\ndb.on('error', console.error.bind(console, '连接错误:'));\ndb.once('open', function() {\n console.log('连接成功');\n})\n```",
"answer": "加个{useMongoClient:true}\n比如\nmongoose.connect('mongodb://localhost/test',{useMongoClient:true})\n就可以了\n我是查看\nhttp://mongoosejs.com/docs/co...\n拉下来最后页的The `useMongoClient` Option才知道的",
"type": "technical_qa"
},
{
"id": "segmentfault_344",
"question": "如何 “意外地” 打印 “hello world”\n一道简单的题目如何“出人意料”地打印hello world比如说用更机器native的方式。语言无所谓也无所谓代码长短。\n我自己想到的一种\n```\n# Python\nls = [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]\ns = ''.join(map(lambda x: chr(x), ls))\nprint(s)\n```",
"answer": "javascript: \n方案一\n```\nconsole.log([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100].map(x=>String.fromCharCode(x)).join(''));\n```\n方案二\n```\nconsole.log(\"\\x68\\x65\\x6C\\x6C\\x6F\\x20\\x77\\x6F\\x72\\x6C\\x64\");\n```\n方案三\n```\nconsole.log((+(+!+[]+[+[]]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(+![]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(+![]+[![]]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]](!+[]+!+[]+[+!+[]])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(+[![]]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+!+[]]]+(+(!+[]+!+[]+!+[]+[!+[]+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(+![]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(+![]+[![]]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]](!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]])+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+([][[]]+[])[!+[]+!+[]]);\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_345",
"question": "es6中export无法向外输出对象变量?\ncomment.js中定义了一对象\n```\nconst comment = {\n text: 'This is text',\n author: {\n name: 'Sara',\n avatarUrl: 'http://images.ichewbubble.com/01.jpg'\n }\n}\n```\n为什么我用export comment会出错但是用export default comment就不会出错\n还有请问一个js文件中当中只能使用一次export default 吗",
"answer": "需要特别注意的是export命令规定的是对外的接口必须与模块内部的变量建立一一对应关系。\n```\n// 报错 \nexport 1;\n\n// 报错 \nvar m = 1; export m;\n\n```\n上面两种写法都会报错因为没有提供对外的接口。第一种写法直接输出1第二种写法通过变量m还是直接输出1。1只是一个值不是接口。正确的写法是下面这样。\n```\n// 写法一 \nexport var m = 1;\n\n// 写法二 \nvar m = 1; export {m};\n\n// 写法三 \nvar n = 1; export {n as m};\n\n```\n上面三种写法都是正确的规定了对外的接口m。其他脚本可以通过这个接口取到值1。它们的实质是在接口名与模块内部变量之间建立了一一对应的关系。",
"type": "technical_qa"
},
{
"id": "segmentfault_346",
"question": "python循环获取json数组中某个值\n我想使用Python来获取这组Json数据中的name及short字段的值请问该怎样循环获取呢\n```\n{\n \"apps_count\": 6,\n \"page_size\": 20,\n \"items\": [\n {\n \"id\": \"59bf8e26959d69523e000177\",\n \"user_id\": \"XXXXXX\",\n \"org_id\": \"59bba986548b7a1688812a7c\",\n \"type\": \"android\",\n \"name\": \"yljk\",\n \"short\": \"yx9a\",\n \"bundle_id\": \"XXXXXX\",\n \"genre_id\": 0,\n \"is_opened\": false,\n \"web_template\": \"default\",\n \"custom_market_url\": \"\",\n \"has_combo\": false,\n \"created_at\": 1505725990,\n \"updated_at\": 1505726002,\n \"expired_at\": 1505898802,\n \"icon_url\": \"https://XXXXXX.com\",\n \"master_release\": {\n \"version\": \"1.0.0\",\n \"build\": \"1\",\n \"release_type\": \"inhouse\",\n \"distribution_name\": \"\",\n \"supported_platform\": null,\n \"created_at\": XXXXXX\n }\n },\n {\n \"id\": \"XXXXXX\",\n \"user_id\": \"XXXXXX\",\n \"org_id\": \"XXXXXX\",\n \"type\": \"android\",\n \"name\": \"wld\",\n \"short\": \"bpdb\",\n \"bundle_id\": \"XXXXXX\",\n \"genre_id\": 0,\n \"is_opened\": false,\n \"web_template\": \"default\",\n \"custom_market_url\": \"\",\n \"has_combo\": false,\n \"created_at\": XXXXXX,\n \"updated_at\": XXXXXX,\n \"expired_at\": XXXXXX,\n \"icon_url\": \"https://XXXXXX.com\",\n \"master_release\": {\n \"version\": \"1.0.0\",\n \"build\": \"1\",\n \"release_type\": \"inhouse\",\n \"distribution_name\": \"\",\n \"supported_platform\": null,\n \"created_at\": XXXXXX\n }\n },\n {\n \"id\": \"XXXXXX\",\n \"user_id\": \"XXXXXX\",\n \"org_id\": \"XXXXXX\",\n \"type\": \"android\",\n \"name\": \"wzlj\",\n \"short\": \"1tdc\",\n \"bundle_id\": \"XXXXXX\",\n \"genre_id\": 0,\n \"is_opened\": false,\n \"web_template\": \"default\",\n \"custom_market_url\": \"\",\n \"has_combo\": false,\n \"created_at\": XXXXXX,\n \"updated_at\": XXXXXX,\n \"expired_at\": XXXXXX,\n \"icon_url\": \"https://XXXXXX.com\",\n \"master_release\": {\n \"version\": \"1.0.0\",\n \"build\": \"1\",\n \"release_type\": \"inhouse\",\n \"distribution_name\": \"\",\n \"supported_platform\": null,\n \"created_at\": XXXXXX\n }\n },\n {\n \"id\": \"XXXXXX\",\n \"user_id\": \"XXXXXX\",\n \"org_id\": \"XXXXXX\",\n \"type\": \"android\",\n \"name\": \"maib\",\n \"short\": \"y6td\",\n \"bundle_id\": \"XXXXXX\",\n \"genre_id\": 0,\n \"is_opened\": false,\n \"web_template\": \"default\",\n \"custom_market_url\": \"\",\n \"has_combo\": false,\n \"created_at\": XXXXXX,\n \"updated_at\": XXXXXX,\n \"expired_at\": XXXXXX,\n \"icon_url\": \"https://XXXXXX.com\",\n \"master_release\": {\n \"version\": \"1.0.0\",\n \"build\": \"1\",\n \"release_type\": \"inhouse\",\n \"distribution_name\": \"\",\n \"supported_platform\": null,\n \"created_at\": XXXXXX\n }\n },\n {\n \"id\": \"XXXXXX\",\n \"user_id\": \"XXXXXX\",\n \"org_id\": \"XXXXXX\",\n \"type\": \"android\",\n \"name\": \"jieb\",\n \"short\": \"jg3e\",\n \"bundle_id\": \"XXXXXX\",\n \"genre_id\": 0,\n \"is_opened\": false,\n \"web_template\": \"default\",\n \"custom_market_url\": \"\",\n \"has_combo\": false,\n \"created_at\": XXXXXX,\n \"updated_at\": XXXXXX,\n \"expired_at\": XXXXXX,\n \"icon_url\": \"https://XXXXXX.com\",\n \"master_release\": {\n \"version\": \"1.0.0\",\n \"build\": \"1\",\n \"release_type\": \"inhouse\",\n \"distribution_name\": \"\",\n \"supported_platform\": null,\n \"created_at\": XXXXXX\n }\n },\n {\n \"id\": \"XXXXXX\",\n \"user_id\": \"XXXXXX\",\n \"org_id\": \"XXXXXX\",\n \"type\": \"android\",\n \"name\": \"xxdk\",\n \"short\": \"5ewf\",\n \"bundle_id\": \"XXXXXX\",\n \"genre_id\": 0,\n \"is_opened\": false,\n \"web_template\": \"default\",\n \"custom_market_url\": \"\",\n \"has_combo\": false,\n \"created_at\": XXXXXX,\n \"updated_at\": XXXXXX,\n \"expired_at\": XXXXXX,\n \"icon_url\": \"https://XXXXXX.com\",\n \"master_release\": {\n \"version\": \"1.0.0\",\n \"build\": \"1\",\n \"release_type\": \"inhouse\",\n \"distribution_name\": \"\",\n \"supported_platform\": null,\n \"created_at\": XXXXXX\n }\n }\n ]\n}\n```",
"answer": "用`get`方法更安全:\n```\nimport json\ndata = json.load(file)\nresult = [(item.get('name', 'NA'), item.get('short', 'NA')) for item in data['items']]\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_347",
"question": "怎样入门“人工智能-深度学习”领域,包含哪些关键技术?\n请已经在此坑中人事给指个方向例如该学习什么语言、或框架。整天被“人工智能”这几个字熏陶感觉在不去了解下就、、、真晚了求大神指教。",
"answer": "这个问题不是一个糟糕的问题,只是有很多装神弄鬼的大神把人工智能吹到了天上去,就像以前说要想学计算机编程必须要数学好英语好一样,其实不见得。人工智能也是类似,很多人说要想搞人工智能必须会高等代数(甚至装逼到说连高等代数这个名词都不好,必须叫线性代数才牛逼)一样,其实没必要。\n实际上学人工智能分为三个层次\n### 第一层\n对于绝大多数人来说你只要会调用API接口就会人工智能。现在各种开放云全部提供各种人工智能接口包括百度、阿里等等。需要语音识别吗调接口就行了需要图像识别吗调接口就行了。相信我你们公司的应用还没有牛逼到必须自己写算法的地步市面上的各种开放接口所能做到的效果绝对比你自己写的强一百倍。当然你只到这个层次没有人会给你百万年薪如果想要高薪接着往下看。\n### 第二层\n对于剩下的人里的绝大多数来说你还是不需要什么线性代数如果你想稍微学得深入一些不想直接使用阿里云的语音识别而想了解得更深入一些这时候你需要学习Python语言或者R语言对R语言我了解得不多就以Python为例这时候有2个框架是你需要知道的`scikit-learn`, `matplotlib`。光知道了框架也没有用你得知道你想干什么。就像师傅给你一把斧子和一把锯子然后呢接下来你需要了解一下工具的用法可以从最简单的泰坦尼克幸存者分类或者鸢尾花分类开始做起。没有什么神秘的原理很简单给了你2000个人的姓名、年龄、舱位号你来预测一下另外1000个人是死还是活问题够简单吧这就是“机器学习”scikit-learn里有几百种不同的算法你可以一个一个拿来试直到找到一个预测准确度最高的算法为止。而且scikit-learn已经把所有算法完全包装甭管多复杂的算法上来就是三板斧创建、学习、预测\n```\nmodel = RandomForestClassifier() # 这里你可以随意选择任意算法\nmodel.fit(X_train, y_train)\nmodel.score(X_test, y_test)\n```\n你觉得这需要多么复杂高深的线性代数吗你学不会算我输。当然这时候算法的精度不够高大概80%多不到90%的样子如果你对预测结果的准确率不满意恭喜你你又上了一个层次这时候你可以开始逐渐尝试一些神经网络的库比如tensorflow的cnn等等稍微需要一些技巧不过还是不需要什么线性代数之类的鬼东西准确度已经可以提升到95%以上了。因为神经网络是分层的一开始层次不能太多最多也就是七八层的样子现在的一些神经网络已经可以提升到100多层所以就叫深度神经网络相应的机器学习也就得到了一个牛逼的名字——深度学习。\n接下来是你该思考的问题我能用这些库解决什么实际问题假设你们公司是开饭馆的那么能不能预测一下哪个饭点来的客人花钱多诸如此类的问题需要你去开动脑筋想一想然后试着用这些库预测一下看你的预测准不准。够简单吧能做这事大概你到外面能骗到三四十万年薪。\n### 第三层\n你实在是不爽别人开发的框架你还是想要获得百万年薪这时候你可以开发你自己的框架做出一个比Tensorflow还要牛逼的框架这个时候你需要用到高等代数了一般你应该是大学里的一个研究生或者教授到这个层面我就帮不上你什么忙了因为我也还没有修炼到那个程度。不过说真的你搞这个东西能为公司挣回来百万吗基本也是不可能的所以这种算法的虚火要不了多长时间就会灭火用不着羡慕别人。做这个基本就是觉得好玩去做而已工程师在任何商业文化里都是被人利用然后唾弃最后资本赚钱的喜欢就好。\n### 附录\n最后英语好的话可以经常上Kaggle寻摸寻摸看看别人又在玩什么新花样了增长眼界的同时也可以练练手。入门教程方面Cousera上吴恩达教授的机器学习入门还是一门不错的课程不过需要较好的英语。交朋友方面可以看看我这篇被众多Java爱好者喷的体无完肤的小文。Python就是牛在机器学习领域无敌手哈哈哈",
"type": "technical_qa"
},
{
"id": "segmentfault_348",
"question": "vue组件注册为什么有时候要在require后面加上default?\n手边有两个项目都是通过vue-cli生成的项目。\n其中一个项目可以直接用这样的代码注册组件\n```\nVue.component('HeaderBar',require(\"./components/common/HeaderBar.vue\"));\n```\n可是另外一个项目却需要这样注册组件\n```\nVue.component('HeaderBar',require(\"./components/common/HeaderBar.vue\").default);\n```\n否则的话就会报错说\n```\nFailed to mount component: template or render function not defined\n```\n请问这是怎么一回事呢",
"answer": "webpack 打包时支持 CommonJS、AMD 和 ES6 的模块化系统。\n\n我们通常写 .vue 单文件组件时,在 script 语言块中使用的是 ES6 的语法,使用 export default 进行默认导出。\n\nrequire 是 CommonJS和 AMD想不到吧的模块导入方式不支持模块的默认导出因此导入的结果其实是一个含 default 属性的对象,因此需要使用 .default 来获取实际的组件选项。或者使用 ES6 的 import 语句ES6 的模块化导入导出语法参见 http://es6-features.org/#Valu...import 时需要给定一个变量名,所有 import 语句必须统一放在模块的开头。\n\n如果 .vue 文件中使用的本来就是 CommonJS 或者 AMD 的模块化系统语法,导出的是 module.exports 对象作为组件选项,那么使用 require 导入时就不需要使用 .default 来获取。\n\n以上就是这个问题出现的原因下面我说说用`webpack`打包`esm`成可直接引入的配置吧。\n之前打包`export default`导出的包都会成为\n```\n{\n default: {\n // 内容\n }\n}\n```\nwebpack3多了一个配置\n```\nlibraryExport: 'default'\n```\n会将`default`中内容打包\n```\n{\n \\\\ 内容\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_349",
"question": "Java使用消息队列还是直接使用线程池ExecutorService异步处理\n说说这两种的区别各自适合什么场景\n用线程池ExecutorService异步处理我理解`ExecutorService`其实也是内部使用了队列(如`LinkedBlockingQueue`),所以从设计上,其实和使用中间价的消息队列是差不多一致的。只是这里应用服务器既充当生产者又充当消费者,也是消息队列中间价的实现者。这种应该适合非分布式的架构,比如简单的只有一台服务器。\n使用消息队列消息队列指activeMQrabbitMQkafaKaRedis等因为一般都是中间件部署在其他机器需要一定的网络消耗。\n本着解耦的目的使用后者更合理因为应用服务器一般内存也不会太多队列长度不易太长。让应用服务器只处理逻辑比较合理。适合分布式架构。\n1.使用`JDK`提供的异步框架`ExecutorService`。\n```\nthreadPool.execute(new Runnable() {\n @Override\n public void run() {\n // 这里是异步处理的,比较耗时的逻辑,比如数据库操作\n userService.setDefaultAddressId(user.getUserId(), bookingForm.getAddressId());\n }\n});\n```\n2.将消息发送到消息队列,如使用`redis`的`List`简单实现,然后后台线程消费消息。\n```\n// 生产消息\nredisTemplate.opsForList().leftPush(LOG_MQ_KEY, JsonUtil.beanToJson(httpRequestLog));\n\n// 后台线程异步消费消息\nString popValue = redisTemplate.opsForList().rightPopAndLeftPush(LOG_MQ_KEY, TEMP_LOG_MQ_KEY);\n```",
"answer": "MQ可以更加有扩展性, 支持的场景更多, 而且支持消息自动的持久化, 建议你看看 RabbitMQ 和 AMQP 协议, JMS 可以学但是没 AMQP 更加通用, redis的MQ还是不要用了, 那只是一个附带的功能, kafka 是大数据领域的不适合做核心业务功能, 只适合数据统计类应用的发送数据, 因为他不确保消息100%不丢失, 如此大的数据量丢一条无所谓的, 不会对统计结果造成影响, 但速度和吞吐量高很多\n线程池就不一样了, 目前执行状态你无法知道, msg的消费率是多少都不知道, 消息转发啊, 消息拒绝啊, 都的自己实现, 而且是单机版的, 我目前用他来做一级转发, 就是用他来将 event 异步发送出去, 而不是让他异步做一些很繁重的工作, 举例: \n注册用户service方法, 当事务结束后, 发送 RegisterUserEvent, 这个发送就是用java线程池(如spring的), 然后 RegisterUserListener 监听到了这个 event 就发送 msg 到 Rabbit MQ, 之后对注册用户这个Topic感兴趣的应用都可以订阅, 比如送积分的服务, 送优惠券的服务, 开辟云盘空间的服务等等\njava领域有很多这种类比, ehcache 和 redis对比做缓存啊, java并发库 和redis锁对比并发啊等等, 都可以提出你这类型的问题",
"type": "technical_qa"
},
{
"id": "segmentfault_350",
"question": "vue中自定义按钮组件为什么要加.native\n一直不明白为什么要@click.native = \"goback\" 我引用过muse-ui里面的自定义组件很多事件都加了.native 但是我去掉也没关系,只是一直不理解加这个意义是什么。",
"answer": "因为在自定义组件上注册的事件触发的是组件自定义的事件\n额 有点绕 举个例子你就明白了\n自定义 Button.vue 组件\n```\n<template>\n <button type=\"button\" @click=\"clickHandler\"><slot /></button>\n</template>\n```\n```\nexport default {\n name: 'button',\n methods: {\n clickHandler () {\n this.$emit('vclick') // 触发 `vclick` 事件\n }\n }\n}\n```\n引用 Button.vue 组件\n```\n<vButton @click=\"clickHandler\" @vclick=\"vClickHandler\">按钮</vButton>\n```\n```\nimport vButton from '@/components/Button'\nexport default {\n components: { vButton },\n methods: {\n clickHandler () {\n alert('onclick') // 此处不会执行 因为组件中未定义 `click` 事件\n },\n vClickHandler () {\n alert('onvclick') // 触发 `vclick` 自定义事件\n }\n }\n}\n```\n如果将上面模版改成\n```\n<vButton @click.native=\"clickHandler\" @vclick=\"vClickHandler\">按钮</vButton>\n```\n那么两个事件都会执行 `.native` 修饰符就是用来注册元素的原生事件而不是组件自定义事件的\n至于你说的 `muse-ui` 中的自定义组件去掉 `.native` 也可以执行 想必是为了方便做了兼容处理\n```\n<template>\n <!-- 此处自定义事件名也叫 `click` 所以在使用组件时加不加 `.native` 修饰符都可以 -->\n <button type=\"button\" @click=\"$emit('click')\"><slot /></button>\n</template>\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_351",
"question": "求解一道promise笔试题\n```\nsetTimeout(function () {\n console.log(1);\n}, 0);\n\nPromise.resolve(function () {\n console.log(2);\n})\n\nnew Promise(function (resolve) {\n console.log(3);\n});\n\nconsole.log(4);\n\n```\n输出3 4 undefined 1",
"answer": "js中的事件执行主要分为两个任务类型 macro task以及micro task 也就是宏仁务和微任务\n宏仁务script全局任务setTimeout setInterval setImmediate I/O UI rendering\n微任务process.nextTickpromise,Object.observer,MutationObserver\n执行顺序为 script先进入函数调用栈然后执行遇到任何其他宏仁务比如遇到了setTimeout就把setTimeout放进宏仁务队列中遇到了微任务就放入微任务队列中等到函数调用栈的所有内容出栈后 然后执行微任务队列,然后再回头执行宏仁务队列再进入函数调用栈再执行微任务队列,知道宏仁务队列执行完毕\n在看上面的例子\n```\n//遇到setTimeout放入宏仁务队列\nsetTimeout(function () {\n console.log(1);\n}, 0);\n//遇到promise放入微任务队列\nPromise.resolve(function () {\n console.log(2);\n})\n//这里虽然遇到了promise但是是用new声明的也就是立即执行所以会先输出3\nnew Promise(function (resolve) {\n console.log(3);\n});\n//第二输出4\nconsole.log(4);\n\n//需要注意的是那个undefined并不是微任务输出的而是console.log(4)输出的,具体可以控制台测试\n----然后执行微任务这个微任务并没有调用所以也不会执行然后执行宏仁务队列中的setTimeout输出1\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_352",
"question": "centos7上安装php7php -v查看php版本提示命令不存在\n在centos7上安装了php7。查看当前运行的进程有php-fpm。\n查找php文件找到以下这些\n```\n[root@demo /]# find . -name php\n./var/opt/remi/php71/lib/php\n./opt/remi/php71/root/usr/lib64/php\n./opt/remi/php71/root/usr/share/php\n./opt/remi/php71/root/usr/bin/php\n```\n运行`which php`,显示没有php\n```\n[root@demo /]# which php\n/usr/bin/which: no php in (/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin)\n\n```\nphp -v查看当前php版本提示命令不存在要怎么才可以",
"answer": "1.建立php程序的软连接 sudo ln -s /opt/remi/php71/root/usr/bin/php /usr/bin/php\n2.修改rc文件\n 1.当前用户的环境变量\n```\n#如果是使用bash作为shell\nvim ~/.bashrc\n#增加一行环境变量\nexport PATH=/opt/remi/php71/root/usr/bin:$PATH\n#刷新一下环境变量\nsource ~/.bashrc\n```\n2.修改全局环境变量\n```\n vim /etc/profile\n export PATH=/opt/remi/php71/root/usr/bin:$PATH\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_353",
"question": "js对象方法里面为什么不能用箭头函数\n先上个代码例子再说我不理解的地方求指点谢谢\n```\nvar name=\"window\";\nvar obj={\n name:'netease',\n print1:()=>{\n console.log(this.name);\n \n }\n}\nobj.print1();//window\n\n```\n`es6`中的`this`是定义时绑定,跟运行时无关,我很纳闷就是这个例子中,定义时 `print1`方法里面的`this`不是应该最先查找到的就是`obj`里面的`name`吗,为什么输出是`window`,还是绑定到全局变量上去了?不是明明`print1`里面没有`this`,再查找外围`this`,先找到的应该是`obj`中的`this`吗?",
"answer": "谢邀。\n下面这句话引自《深入理解ES6》\n箭头函数没有 this/super/arguments/new.target 的绑定,这些值是由外围最近一层非箭头函数决定。\n箭头函数的`this`和普通函数的`this`可以看成完全两个概念的东西不用传统的this去理解。\n我对`外围`的理解是,这个外围指的是`()=>{}`整体的外围比如你的代码中name属性的外围是什么print1的外围是什么。所以 `()=>{console.log(this.name);}`的外围已经出了obj从而进入window\n可以借助我下面的代码来理解\n```\n var name = \"window\";\n var obj = {\n name: 'netease',\n print1: () => {\n console.log(this.name);\n },\n print3: function () {\n return ()=>{\n console.log(this.name);\n }\n }\n }\n obj.print1();// window\n obj.print3()();// netease 注意是返回闭包函数\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_354",
"question": "如何获取vue input的值\n```\n<template>\n <div class=\"hello\">\n <div class=\"login\">\n <div class=\"input-wrapper\">\n <input class=\"input\" type=\"text\" placeholder=\"手机号\" value=\"\"/>\n </div>\n <div class=\"input-wrapper\">\n <input class=\"input\" type=\"password\" placeholder=\"密码\" value=\"\"/>\n </div>\n\n\n <div class=\"button\" @click=\"login\">\n <text class=\"text\">登陆</text>\n </div>\n\n </div>\n <!-- <toast id=\"toast\"></toast>-->\n </div>\n</template>\n\n\n<script>\n //var modal = weex.requireModule('modal');\n var modal = weex.requireModule('modal');\nvar stream = weex.requireModule('stream');\n export default {\n methods: {\n login (event) {\n //alert('66');\n stream.fetch({\n method: 'GET',\n type: 'json',\n url: 'http://xxxxxx.com/xxx/xxx?username=ggjz&password=123'\n }, function(ret) {\n if(!ret.ok){\n modal.toast({\n 'message': '登陆失败',\n 'duration': 2.0\n })\n }else{\n modal.toast({\n message: '登陆成功',\n duration: 2.0\n })\n }\n })\n },\n }\n }\n</script>\n\n<style scoped>\n .input-wrapper{\n margin-left: auto;\n margin-right: auto;\n }\n .input {\n font-size: 60px;\n height: 80px;\n width: 750px;\n }\n .text{\n color: #666666;\n font-size: 60px;\n }\n .button {\n width: 200px;\n height: 80px;\n text-align: center;\n border-width: 2px;\n border-style: solid;\n border-color: rgb(162, 217, 192);\n background-color: rgba(162, 217, 192, 0.2);\n margin-top: 20px;\n margin-left: auto;\n margin-right: auto;\n }\n</style>\n\n\n\n```",
"answer": "```\n<input v-model=\"value\"/>\n```\n```\ndata() {\n return {\n value: ''\n }\n}\n```\n```\nthis.value //获取\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_355",
"question": "php中静态成员方法和静态成员变量是不是不支持多态\n我实现了一个日志工具基类并派生了两个子类一个是运维日志类一个是业务日志类并在基类中设置了一个静态变量希望能用以区分两个子类但在调用静态方法时实际上完全不是想象中的情况代码如下\n```\n// 日志工具基类\nclass LogTool\n{\n protected static $type;\n \n public static function debug($msg) {\n switch (self::$type) {\n case 'biz':\n echo '把日志写入数据库表1';\n break;\n case 'opt':\n echo '把日志写入数据库表2';\n break;\n default:\n echo 'error';\n }\n }\n \n // 其他代码省略\n}\n\n// 运维日志类\nclass OptTool extends LogTool\n{\n protected static $type = 'opt';\n}\n\n// 业务日志类\nclass BizTool extends LogTool\n{\n protected static $type = 'biz';\n}\n\n// 调用代码\nBizTool::debug('王小虎已登录');\n\n```\n代码如上实际上函数 dosomething 的运行情况是每次都输出 'error'因为在执行静态方法debug时静态成员 $type 是空值;\n但是如果我把 debug 函数在子类中再实现一次,则运行时 $type 变量就是有值的。\n可是这样做就完全没意义了抽象父类出来就是为了减少重复代码的现在两个子类除了写入日志的表不同其他完全相同结果这样的结果弄得我欲哭无泪。\n非常简要地回答就行",
"answer": "基类中采用static::的方式,可以覆盖当前基类中定义的静态变量/方法,而去使用子类中定义的静态变量/方法。",
"type": "technical_qa"
},
{
"id": "segmentfault_356",
"question": "redis 失效的key造成的问题\n是这样得\n```\n//这里面执行判断是否存在缓存\n$res = redis -> get(\"xxx\");\nif($res != null){\n //返回缓存结果\n return $res;//缓存返回\n}\n\n$res = db -> query(\"select * ...\")//假设这句要3秒\n\nredis -> setex(\"xxx\",3600,$res)//保存到缓存3600时间\n//返回查询结果\nreturn $res;\n\n```\n大概意思是这样的,就是我先从缓存取,没有就从数据库取,且存到缓存中,方便下次再去取。\n但是问题就来了假设我有千万并发xxx 这个key存在3600,3600时间后自动销毁必须得重新从数据库获取而这句sql要3秒3秒钟并发了几千万就是查了几千万次数据库必须得第一条成功缓存下来,后续的才不会跳过缓存返回那句但这期间3秒却足以使服务器垮了我想问的是怎样才能只访问一次数据库其他那几千万访问都是从缓存取。",
"answer": "可以看看这篇博文:缓存更新的套路\n补充\n缓存被“击穿”问题以前看过一篇文章的做法你可以借鉴一下\n业界比较常用的做法是使用mutex。简单地来说就是在缓存失效的时候判断拿出来的值为空不是立即去load db而是先使用缓存工具的某些带成功操作返回值的操作比如Redis的SETNX或者Memcache的ADD去set一个mutex key当操作返回成功时再进行load db的操作并回设缓存否则就重试整个get缓存的方法。类似下面的代码\n```\n public String get(key) {\n String value = redis.get(key);\n if (value == null) { //代表缓存值过期\n //设置3min的超时防止del操作失败的时候下次缓存过期一直不能load db\n if (redis.setnx(key_mutex, 1, 3 * 60) == 1) { //代表设置成功\n value = db.get(key);\n redis.set(key, value, expire_secs);\n redis.del(key_mutex);\n } else { //这个时候代表同时候的其他线程已经load db并回设到缓存了这时候重试获取缓存值即可\n sleep(50);\n get(key); //重试\n }\n } else {\n return value; \n }\n }\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_357",
"question": "求解一道关于js的百度笔试题\n```\nvar name = \"World\";\n(function () {\n if (typeof name === 'undefined') {\n var name = 'Jack';\n console.log('Goodbye' + name);\n } else {\n console.log('hello ' + name);\n }\n})()\n\n```\n输出GoodbyeJack",
"answer": "变量声明提升: 变量的声明会提升到当前作用域的顶部\n你的代码等于\n```\nvar name = \"World\";\n(function () {\n var name //声明提升\n if (typeof name === 'undefined') {\n name = 'Jack';\n console.log('Goodbye' + name);\n } else {\n console.log('hello ' + name);\n }\n})()\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_358",
"question": "react不能给组件绑定点击事件吗\n这是我的点击事件\n```\nuseCoupon=()=>{\n console.log(444444)\n};\n\n```\n这是我的DOM结构\n```\n<div className=\"select-wrapper-inner\">\n {\n this.state.availableCouponList.map((item,index)=>{\n return (\n <SingleCoupon key={index} onClick={this.useCoupon} price={item.price} condition={item.condition} deadline={item.deadline}/>\n )\n })\n }\n</div>\n\n```\n我现在绑定的这个点击事件不会被触发什么意思SingleCoupon是我自定义的一个组件",
"answer": "SingleCoupon是你定义的组件并不是一个真实的DOM元素它不存在点击事件因为它不是最终渲染的页面的元素。\n你应该这样用\n```\nclass SingleCoupon extends Component {\n render() {\n return (\n <div onClick={this.props.onClick}/>\n )\n }\n}\n\n```\n所有的事件处理函数都必须要绑定到真实的DOM上。传给组件组件只会认为它是个prop",
"type": "technical_qa"
},
{
"id": "segmentfault_359",
"question": "js对象为什么不能直接操作\n发现一个小问题在控制台输入{a:1}.toString()会报错,必须要先把{a:1}赋值给一个变量然后在进行操作才行,这是什么情况",
"answer": "因为语法规定。\n因为语法规定导致 js 解释器没有正确理解你的意图。解决办法, 加括号消歧义。\n```\n({a:1}).toString() // or\n({a:1}.toString())\n```\n## 引申\n开始以为是 console 的锅,后来发现 node CLI 里一样存在这个问题,于是发现里蹊跷:\n花括号 `{}` 除了可以用来定义对象字面量,还可以用来定义代码块。\n冒号`:` 除了可以用来定义对象字面量中的 key-value 对外,还可以用来定义 `label`\nlabel的概念\n如果你听说过 C 语言js就是C系的语法你听说过有个语句叫 `goto`,那你应该对 `label` 有印象。js 里没有 `goto`,但是有 `break` 和 `continue`, 这俩货可以和 `label` 连用。\n`{a:1}.toString()` 之所以报错 `unexpected token .` ,是因为它被解析成了:\n```\n{\n// code block\na: // 定义一个label名字叫a\n\n1 // 这是一条语句,就一个数值 1\n \n}\n// block 结束了\n.toString() // 报错,非法字符`.`\n```\n所以你可以这样玩\n```\n{\n a:console.log(1);console.log(2);\n}\n```\n这代码语法正确能执行",
"type": "technical_qa"
},
{
"id": "segmentfault_360",
"question": "从mysql查出200万数据有什么好的办法\n查询的时候老是崩溃",
"answer": "不要用分页,查到后面越查越慢。\n因为\n```\nlimit 10000,100\n```\n这种那个10000是会查询然后丢弃的。\n正确的做法是用游标。\n假设你的游标字段为`id`\n```\n$cursor = 0;\n$size = 1000;\ndo {\n$sql = 'SELECT * FROM user WHERE id > :id ORDER BY id DESC limit :size';\n$data = 执行查询得到的数组。\n$count = count($data);\nforeach($data as $row){\n $id = $row['id'];\n//处理数据\n}\n// 当前条数不大于size证明下面没数据了。\nif($count<$size){\n break;\n}\n}while(true);\n```\n这种是利用mysql查询筛选【一部分你要的数据不存在数据丢弃】。所以速度一直都很快",
"type": "technical_qa"
},
{
"id": "segmentfault_361",
"question": "请问大家某些大牛常说不要做“api程序员”这里的api一般是哪些api呢 像 环信 融云 这样的算api吗 \n请问大家某些大牛常说不要做“api程序员”这里的api一般是哪些api呢 像 环信 融云 这样的算api吗 本人是做php开发的",
"answer": "APIApplication Programming Interface,应用程序编程接口是一些预先定义的函数目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力。我们在写程序时无疑会调用各种第三方库的API来实现功能。\n从描述看问题中的API指的是Web API这里的API并不是特指某个服务的API。\n对于Web API而言仅仅调用别人的API来实现业务功能或者说自己仅仅是从数据库中取数据写简单的增删查改的API这类工作的技术含量是很低的所以不要做“API程序员”\n一个好的Web开发者应当是需要具备比较深厚的编程功底的。比如数据结构、算法等做web开发需要知道restful规范HTTP协议负载均衡分布存储等知识。这些要求就会高得多了。\n简而言之你需要去做一些技术含量高的东西简单的API调用很基本刚学了几天web开发的程序员就会调用这不能构成任何的竞争力。大量轮子已经造好完全从零开始不实际的需要关注的是你的代码中算法和模型这些核心占比多少纯粹的API调用占比多少调用的API内部实现的机制了解多少不要只是简单调用。",
"type": "technical_qa"
},
{
"id": "segmentfault_362",
"question": "golang time.Now() 格式化的问题。\ngolang中使用time.Now().Format(\"2006/1/2 15:04:05\") 格式化时间输出时Format的参数必须是\"2006/1/2 15:04:05\",这个时间为例的时间格式吗?\n```\nfunc main() {\n now := time.Now()\n\n fmt.Println(now)\n \n // 必须使用这个时间才能返回正确的格式化后的时间,其他的都不行\n fmt.Println(now.Format(\"2006/1/2 15:04:05\"))\n fmt.Println(now.Format(\"2006/01/02 15:04:05\"))\n fmt.Println(now.Format(\"15:04:05 2006/1/2\"))\n fmt.Println(now.Format(\"2006/1/2\"))\n}\n\n```\n请问\"2006/1/2 15:04:05\"这个时间有什么历史典故吗?",
"answer": "这个是我以前收藏的笔记\ngo 的time package 提供了time.Format函数用来对时间进行格式化输出。\n类似的还有time.Parse用来解析字符串类型的时间到time.Time。这是两个互逆的函数。\n问题是go 采用的格式化 layout 和我们以往所用的任何经验都不同。以至于初次接触总是一头雾 水。\n其实 go 提供的这个 layout 对算法的实现非常科学高效,而且很规律。下面我们详细分解下。 直接上个对应表\n前面是含义后面是 go 的表示值,多种表示,逗号\",\"分割\n```\n月份 1,01,Jan,January\n日  2,02,_2\n时  3,03,15,PM,pm,AM,am\n分  4,04\n秒  5,05\n年  06,2006\n时区 -07,-0700,Z0700,Z07:00,-07:00,MST\n周几 Mon,Monday\n\n```\n您看出规律了么哦是的你发现了这里面没有一个是重复的所有的值表示都唯一对应一个时间部分。并且涵盖了很多格式组合。\n比如小时的表示(原定义是下午3时也就是15时)\n```\n3 用12小时制表示去掉前导0\n03 用12小时制表示保留前导0\n15 用24小时制表示保留前导0\n03pm 用24小时制am/pm表示上下午表示保留前导0\n3pm 用24小时制am/pm表示上下午表示去掉前导0\n\n```\n又比如月份\n```\n1 数字表示月份去掉前导0\n01 数字表示月份保留前导0\nJan 缩写单词表示月份\nJanuary 全单词表示月份\n\n```\n实例对应\n真实时间我的UTC时间是 2013年12月5日我的本地时区是Asia\n字符表示  2013 12 5 Asia\nGo Layout 2006 01 2 MST\n真实时间我的UTC时间是 2013年12月22点我的本地时区是Asia\n字符表示  2013 12 22 Asia\nGo Layout 2006 01 15 MST\n是滴上面这个时间是合法的虽然没有说是那一天但是说了小时\n而所有这些数字的顺序正好是1,2,4,5,6,7和一个时区MST\n其实还有一个秒的 repeated digits for fractional seconds 表示法\n用的是 0和9 ,很少用,源代码里面是这样写的\nstdFracSecond0 // \".0\", \".00\", ... , trailing\nzeros included stdFracSecond9 // \".9\", \".99\",\n..., trailing zeros omitted\n那些分界符\n除了那些值之外的都是分界符号自然匹配了直接举例子吧\n字符表示  2013-12 21 Asia\nGo Layout 2006-01 15 MST\n字符表示  2013年12月21时 时区Asia\nGo Layout 2006年01月15时 时区MST\n好了您是否感觉这个表示方法兼容度更好适应性更强呢更容易记忆呢。",
"type": "technical_qa"
},
{
"id": "segmentfault_363",
"question": "javascript把json对象转为数组\n转换前是这样的\n```\n\nvar articles = [{\n title: 'hello',\n content: 'hello world',\n created_at:'2017-08-30 13:45:15'\n},{\n title: 'foo',\n content: 'foo bar',\n created_at:'2017-08-30 13:45:15'\n}];\n```\n我想把它转成这样\n```\nvar articles2 = [\n [ 'hello', 'hello world', '2017-08-30 13:45:15' ],\n [ 'foo', 'foo bar','2017-08-30 13:46:06' ]\n];\n```\n用js应该怎么做呢",
"answer": "```\nvar articles = [{\n title: 'hello',\n content: 'hello world',\n created_at:'2017-08-30 13:45:15'\n},{\n title: 'foo',\n content: 'foo bar',\n created_at:'2017-08-30 13:45:15'\n}]\nvar result = articles.map(item => {\n return Object.values(item)\n})\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_364",
"question": "如何用Laravel 做Api接口\n我想用laravel做个api接口但是作为接口应该对请求做校验我能想到将校验的数据放到header中在laravel的中间件对header做校验但是我现在不知道拿到header怎么去用。\n还有就是做api对请求校验的作用重要性",
"answer": "API接口的校验有很多种看你的API是用在哪方面APP还是web。\n也不一定非要放在header中使用基础的signature方案也能完成对接口的校验。\nsignature方案客户端和API使用同一套加密规则提供一个APPkey和secret然后经过secret加密或者其他处理过程生成signature传输的时候将signature和appkey作为参数传递。这是目前用的比较多的一种API接口调用权限校验只是用来校验客户端是否有权限调用API。\nJWT: JSON WEB TOKEN 也是一种可选的,只不过他更复杂, 更多的是用来校验用户的登录状态和权限用在APP、无状态的web系统关于JWT有相对应的 composer 包可选择。核心思想就是API加密一个uid或者其他标识生成一个token这个token是有时限的比如两个小时放在header的Authorization中通过获取进行校验涉及用户的操作一般会传递uid或者其他类似标识字段通过JWT进行权限校验即可。\n至于拿到 header 怎么用如果是JWT 取出 Authorization字段以及标识字段如UID然后进行JWT校验即可加密和校验可以自己实现不过建议使用成熟的composer包吧比如我用过的https://github.com/lcobucci/jwt。\n看你到底需求什么校验 是 `用户鉴权` 还是 `API接口调用权限校验`,个人认为这两者是不同的。\n另外API请求校验的作用很明显别人即使知道你的API也无法调用。这个无法调用是相对的如果你的signature校验写的很死尤其是可以多次应用的signature就存在重放攻击。\n用户鉴权这个就更不用说了不同的用户只能操作自己权限的东西不鉴权的API是存在各种问题的。",
"type": "technical_qa"
},
{
"id": "segmentfault_365",
"question": "angular 对象?.语法的具体含义\n在angular项目的html中比如a是个对象a.b这句语法是什么意思是angular中特有的吗还是问号运算符本身就有的功能如\n```\n<div>\n {{ foo?.bar }}\n</div>\n```",
"answer": "`?.`是angular模板中的安全属性操作符语法属于angular模板特有语法\n`a?.b`表示当a存在时(不为null或undefined),取`a.b`的值否则置空以避免出现a未赋值时直接报错\n详见官方文档The safe navigation operator ( ?. ) and null property paths",
"type": "technical_qa"
},
{
"id": "segmentfault_366",
"question": "vue-router的beforeEach导航钩子next('/')出现死循环问题\n为什么next()指定路径会出现死循环\n```\nrouter.beforeEach((to, from, next) => {\n console.log('beforeEach');\n if(true){\n next('/');\n }else{\n next();\n }\n});\n```",
"answer": "next()直接跳转到to.path路径没有再执行一遍beforeEach导航钩子next('/')或者next('/login')自己指定路径的路由跳转的时候还执行一遍beforeEach导航钩子所以上面出现死循环\n栗子如我们登录页'/login')面进入首页('/'),可以这么写:\n```\nrouter.beforeEach((to, from, next) => {\n var userInfo= JSON.parse(sessionStorage.getItem('userInfoStorage'));//获取浏览器缓存的用户信息\n if(userInfo){//如果有就直接到首页咯\n next();\n }else{\n if(to.path=='/login'){//如果是登录页面路径就直接next()\n next();\n }else{//不然就跳转到登录;\n next('/login');\n }\n\n }\n});\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_367",
"question": "短信验证码是前端做还是后端?\n1.短信验证码接口是前端做的吗? 我们后台是php\n2.前端需要做什么工作啊?\n我以前没有做过这种事求大神指导",
"answer": "初步实现步骤:\n```\n1、 用户:填写手机号码\n2、 用户:点击发送短信\n3、 js :调用后端接口,提交手机号码-告知后端发送短信\n4、 后端:生成随机码,作为验证码\n5、 后端:保存随机码-\n6、 后端:调用短信接口-将随机码发送给用户\n7、 用户:接收到短信,填写验证码\n8、 用户:点击提交按钮\n9、 js :调用后端接口,提交手机号码、验证码\n10、后端根据手机号码获取保存的验证码与接收到的验证码对比是不是一样的\n11、js 判断后端返回的结果Y/N\n12、js :反馈用户\n\n```\n可以另外再做些优化\n```\na、限制用户多次提交\nb、后端保存的随机码加个时间限制\n。。。\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_368",
"question": "什么是跳板机?\n什么是跳板机",
"answer": "跳板机,就是可以给你远程连接的机器,然后通过这个机器再去访问别的机器,这个跳板机可以是`windows`下也可以是`Linux`下,跟操作系统无关,下面是其中比较常见的一种场景:\n很多客户方的服务器外网是连接不了的一般只能通过`VPN`然后才能连接,然而一些客户方觉得做`VPN`的代价太大,但是开发方不方便经常去现场或者其他原因需要访问客户方的服务器并且服务器外网不能连接时,没有`VPN`时,只能通过远程连接,比如`teamview`,`QQ`远程,还有`windows`自带的远程连接工具,连接到远端的一台电脑上,这台电脑就是跳板机,作为一个桥梁,然后再通过这个机器在内网中访问其服务器",
"type": "technical_qa"
},
{
"id": "segmentfault_369",
"question": "相对于前端来说SDK指的是什么\n请问 相对于前端开发来说 SDK指的是什么\n- 是API接口\n- 是一段注入JS\n求大大给解惑解惑",
"answer": "假设我开发了一个博客后台管理系统开放了一系列功能操作的HTTP或其他协议的接口用于创建博客、发布文章、文章列表、发布评论、对文章以及评论点赞等操作那么这个叫API用于其他程序方便通过接口实现博客功能。\n一般情况下有可能到这一步我的博客系统就打完收工了。\n但是某一天有一个合作伙伴说你们这一堆API我熟悉起来要半天能不能更加方便我来接入那我问他你用什么语言他说我就会javascript那么我就用js写了一堆类和方法把我的API接口封装起来用户不需要关心接口地址等只需要引入我封装的js的url就可以通过类和方法就可以发布文章、创建博客、文章列表等这个就叫SDK当然这个SDK很简单可能就是一个或几个js文件以及简陋的不能再简陋的文档。\n复杂的SDK其实是一整套完整的解决方案比如IOS APP开发苹果提供的SDK其实包含了开发工具Xcode、ios各种版本的sdk、帮助文档、命令行工具等等一些列东西",
"type": "technical_qa"
},
{
"id": "segmentfault_370",
"question": "laravel 路由冲突\n跟着网上视频学习laravel5.4,写了下面两行代码。\nRoute::get('/posts/{post}','AppHttpControllersPostController@show');\nRoute::get('/posts/create','AppHttpControllersPostController@create');\n然后视频中访问localhost/laravel/public/posts/create 结果是成功的而我访问却跳转到了show中求解",
"answer": "加一个正则表达式限制就好了,默认情况下,`laravel` 的路由匹是从上往下的,匹配到符合的第一条后,就不会往下匹配了:\n```\n\n//假设post为int\nRoute::get('/posts/{post}','AppHttpControllersPostController@show')->where('post', '[0-9]+');\nRoute::get('/posts/create','AppHttpControllersPostController@create');\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_371",
"question": "php 的yield叫协程go的goroutine也叫协程它这两种完全不一样吧\nphp那个我是没搞懂而且是会暂停的。\ngo那个呢并不需要暂停我就是类似另开一个线程做完了事返回数据就闪人这个还更好理解。PHP那个有点搞不懂。",
"answer": "在`php`等语言里的`yield`,不是`协程`语法,而是`迭代器`语法。 \n而包括`php`在内的大多数语言实现`迭代器`的方式,是通过一个可中断的函数完成的。 \n而`协程`的一个特点就是执行中断,切换上下文。 \n所以就有了通过`迭代器`函数去`实现`协程的方案。这种方案充分利用了`迭代器`可中断的特点来模拟`协程`中断,而利用闭包函数的上下文独立性,实现`协程`的上下文切换。 \n总结起来什么是协程协程是通过切换运行方法和上下文来在同一个空间中完成不同的处理任务注意不是另外开线程。 \n那么协程怎么实现`goroutine`就是协程的一种实现方式。 \n而通过`迭代器`实现协程,就又是另外一种方式。 \n两者的区别在于`goroutine`是已经存在的实现。相当于已经成品的车,你理解起来会相当容易。 \n而`迭代器`只是提供者实现`协程`的方法,具体要实现协程,还需要自己去写代码完成。这就好像是汽车的零件,你需要自己组装,所以还需要深入学习你才能理解它的原理",
"type": "technical_qa"
},
{
"id": "segmentfault_372",
"question": "php如何打包下载远程图片\n现在页面上有多张图片来自 OSS,如何根据这些图片的 url 来一次性将图片全部下载到本地?",
"answer": "如果你想在 浏览器端做这个功能就需要借助 js 实现\n如果你想在 服务端实现这个功能,可以一张一张获取,然后打包。\nFrom : https://stackoverflow.com/que...\n```\n$image1 = \"http://cdn.screenrant.com/wp-content/uploads/Darth-Vader-voiced-by-Arnold-Schwarzenegger.jpg\";\n$image2 = \"http://cdn.screenrant.com/wp-content/uploads/Star-Wars-Logo-Art.jpg\";\n\n$files = array($image1, $image2);\n\n$tmpFile = tempnam('/tmp', '');\n\n$zip = new ZipArchive;\n$zip->open($tmpFile, ZipArchive::CREATE);\nforeach ($files as $file) {\n // download file\n $fileContent = file_get_contents($file);\n\n $zip->addFromString(basename($file), $fileContent);\n}\n$zip->close();\n\nheader('Content-Type: application/zip');\nheader('Content-disposition: attachment; filename=file.zip');\nheader('Content-Length: ' . filesize($tmpFile));\nreadfile($tmpFile);\n\nunlink($tmpFile);\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_373",
"question": "为什么.vue文件需要使用export default\n```\n因为项目要使用vue开发。学习了一段时间之后有几个问题一直困惑着我\n1首先就是.vue结尾的文件为何需要export default就像下面的代码一样\n2为什么data需要return我不用return直接 data(){\n menu:MENU.data,\n poi:POILIST.data\n}不行吗?\n这两个问题问了几个人都不能给我合理的解释求懂的兄弟们给个帮助谢谢了。\n\n```\n```\n<script>\n import { POILIST, MENU } from '../config/vuex.js';\n export default {\n data() {\n return {\n menu: MENU.data,\n poi: POILIST.data\n }\n },\n methods: {\n set() {\n MENU.list.push('首页');\n POILIST.list.push({\n lng: 124.1,\n lat: 42.3\n });\n }\n }\n }\n</script>\n```",
"answer": "export default是ES6的语法意思是将这个东西导出你要import 引入东西导出了才能引用data是一个函数是因为data是被很多组件共享的如果 data 是一个的对象的话,每次实例化会造成所有的实例共享引用同一个数据对象,如下\n```\nvar fnc= function() {}\nfnc.prototype.data = {\n a: 1,\n b: 2,\n}\n\nvar fnc1 = new fnc()\nvar fnc2 = new fnc()\n\nfnc1.data.a === fnc2.data.a // true\nfnc2.data.b = 1;\nfnc2.data.b // ==1\n```\ndata 是函数的话,每次创建一个新实例后,调用 data 函数用return返回初始数据的一个全新副本数据对象就避免了所有实例共享引用同一个数据对象。",
"type": "technical_qa"
},
{
"id": "segmentfault_374",
"question": "npm install -g 和npm install --save-dev的关系\nnpm install --save-dev xxx是自动把模块和版本号添加到devdependencies部分\nnpm install -g xxx是将模块安装在全局\n但是执行了npm install --save-devpackage.json中devDependencies会加入安装的模块但是在命令行中执行命令时还是出现command not found还是必须要npm install -g安装在全局才行。\nnpm install --save-dev的作用仅仅是自动把模块和版本号添加到devdependencies部分么我们还是需要先安装么还是说我们没配对环境变量 为什么很多教程在Installation这流程都是npm install --save-dev xxx就OK了呢",
"answer": "1.`npm install`本地安装\n1将安装包放在 ./node_modules 下(运行 npm 命令时所在的目录),如果没有 node_modules 目录,会在当前执行 npm 命令的目录下生成 node_modules 目录。\n2可以通过 require() 来引入本地安装的包。\n2.`npm install` -g全局安装\n(1) 将安装包放在 /usr/local 下或者你 node 的安装目录。\n(2)可以直接在命令行里使用。\n3.`npm install --save`\n(1)会把msbuild包安装到node_modules目录中\n(2)会在package.json的dependencies属性下添加msbuild\n(3)之后运行npm install命令时会自动安装msbuild到node_modules目录中\n(4)之后运行npm install --production或者注明NODE_ENV变量值为production时会自动安装msbuild到node_modules目录中\n4.`npm install --save-dev`\n(1)会把msbuild包安装到node_modules目录中\n(2)会在package.json的devDependencies属性下添加msbuild\n(3)之后运行npm install命令时会自动安装msbuild到node_modules目录中\n(4)之后运行npm install --production或者注明NODE_ENV变量值为production时不会自动安装msbuild到node_modules目录中",
"type": "technical_qa"
},
{
"id": "segmentfault_375",
"question": "React-Router V4+ 打包后刷新网页404错误\n开发使用的构建工具是 create-react-app\n我在使用 React-Router V4+ 版本的时候,\n```\nnpm run build\n```\n编译成功后放在我本地的 Tomcat9 上,运行后可以正常访问首页,跳转其它页面 URL 都正常显示, 但是再刷新当前页面404错误。\n按照官方提示\nThere is also a similar approach for Apache servers. Create an .htaccess file in your folder's root:\n```\nRewriteBase /\nRewriteRule ^index\\.html$ - [L]\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteRule . /index.html [L]\n```\n问题1 \n创建了 .htaccess 文件后该文件是放在我编译好的包的根目录index.html所在目录还是在 其它位置。如果需要修改其它东西如 Apache 配置文件,要怎么修改。\n问题2 \n在网上看到这种情况都是将 URl 重定向到 index.html请问还有其它不修改服务器配置文件的解决办法没有。\n跪求解答谢谢",
"answer": "我没看过文档,建议你要理解内部的机制。\n之所以你在浏览器内可以由首页跳转到其他路由地址是因为这是由前端自行渲染的你在React Router定义了对应的路由脚本并没有刷新网页访问后台是JS动态更改了location。\n当你刷新时你首先是访问的后台地址然后返回的页面内加载了React代码最后在浏览器内执行也就是说如果这个时候报404是因为你后台并没有针对这个路由给出返回HTML内容也谈不上执行React Router了。\n解决办法就一条如果你期望所有的路由都由React Router来定义只有你的后台无论任何路径都返回index.html就好了。剩下的事情交给React Router。那么你要做的就是修改后台服务器可以放在apache也可以放在你的java路由内做一个通配路径处理。",
"type": "technical_qa"
},
{
"id": "segmentfault_376",
"question": "如何用 javascript 实现多字段模糊查询\n数组如下\n```\nvar arr = [\n {id: \"1\", en: \"Afghanistan\", cn: \"阿富汗\", code: \"93\"},\n {id: \"2\", en: \"Iraq\", cn: \"伊拉克\", code: \"964\"}, \n {id: \"3\", en: \"Qatar\", cn: \"卡塔尔\", code: \"974\"}\n ]\n```\nen,cn,code都能查询\n比如输入`aq`,查询返回第二条\n比如输入`卡`,查询返回第三条\n比如输入`97`,查询返回第三条",
"answer": "```\nfunction query(arr, q) {\n return arr.filter(v => Object.values(v).some(v => new RegExp(q + '').test(v))\n )\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_377",
"question": "在命名规范的情况 你还会写注释么?\n比如一些方法\n```\n// 封装链路信息数据\nformatLinksInfo() {}\n\n// 获取节点坐标数据\ngetNodesPosition() {}\n\n// ip转数字\nipToNum() {}\n\n// 判断元素是否全部选中\nisAllElemsActive() {}\n\n// 右键菜单选项\nitemContextMenu() {}\n\nif(target.classed('topo')){} // 拓扑图情况\nif(target.classed('node')){} // 节点\nif(target.classed('link')){} // 链路\n```\n比如像这种命名 不写注释感觉也能通过方法名或者类名 也能看懂,\n但自己还是都写了 现在code review看来觉得很冗余\n问一下你们关于代码注释编写原则是啥呢能通过命名读懂的都不写么",
"answer": "- 你不应该在每次调用方法的时候写注释,而是应该在声明函数的地方写注释\n- \n建议每个函数都写相应的注释\n\n你自己写代码存在主观性你觉得规范其实不一定规范或许可以说不一定全面;\n每个人理解方法是不一样的你觉得命名规范了那也许是真的很规范但是并不是所有人都能一下子看懂如果要整个遍历一下方法实现过程这是非常浪费时间的别人看到一个函数应该立刻能从注释和方法名知道这个函数是干什么的;\n函数名写的再好我也只能大概猜到这个函数是干什么的但是我对函数的参数和返回值类型等信息一无所知\n总而言之空间换时间一次时间换以后的`N`次时间是非常值得的\n\n\n- 建议写英文注释,这样`review`起来更加简洁,不显得那么格格不入,不要觉得什么自己或者其他人英文底子不好,网上各种英汉词典,多写英文注释遇到不知道的还能多学几个英文单词\n\n建议每个函数都写相应的注释\n- 你自己写代码存在主观性,你觉得规范,其实不一定规范,或许可以说不一定全面;\n- 每个人理解方法是不一样的,你觉得命名规范了,那也许是真的很规范,但是并不是所有人都能一下子看懂,如果要整个遍历一下方法实现过程这是非常浪费时间的,别人看到一个函数应该立刻能从注释和方法名知道这个函数是干什么的;\n- 函数名写的再好,我也只能大概猜到这个函数是干什么的,但是我对函数的参数和返回值类型等信息一无所知\n- 总而言之,空间换时间,一次时间换以后的`N`次时间是非常值得的",
"type": "technical_qa"
},
{
"id": "segmentfault_378",
"question": "Vue路由的$router.back(-1)回退时如何判断有没有上一个路由\n现在每个页面的左上角有一个返回按钮<\n点击时的代码是this.$router.back(-1),返回上一个路由\n但是我们现在有这样一个需求把其中某一页分享出去用户打开时并没有上一条路由的历史记录所以点击<按钮时没有反应。\n所以应该怎么判断有没有上一条路由的历史记录。\n代码\nrouterback: function () {\n this.$router.back(-1)\n},",
"answer": "在页面一开始加上一个全局的函数:\n```\nactivated: function () {\n this.$setgoindex()\n}\n```\n这个函数是这样的判断当前页面的历史记录是不是小于等于1如果小于等于1说明这个页面没有可以返回的上一页如果没有可以返回的上一页就给地址栏加上一个goindex=true的参数这样你从这个页面在往下一个页面跳转在返回这个参数就一直加上的\n```\nVue.prototype.$setgoindex = function () {\n if (window.history.length <= 1) {\n if (location.href.indexOf('?') === -1) {\n window.location.href = location.href + '?goindex=true'\n } else if (location.href.indexOf('?') !== -1 && location.href.indexOf('goindex') === -1) {\n window.location.href = location.href + '&goindex=true'\n }\n }\n}\n```\n然后在左上角返回按钮加上这个逻辑\n```\nif (this.$route.query.goindex === 'true') {\n this.$router.push('/')\n} else {\n this.$router.back(-1)\n}\n```\n这样就可以了",
"type": "technical_qa"
},
{
"id": "segmentfault_379",
"question": "axios 可以挂在Vue原型上 为啥还有个vue-axios?\n如题这个vue-axios有什么其他用途还是多余的\n因为\n```\nVue.prototype.$http = axios\n和\nimport Vueaxios from vue-axios\nVue.use(VueAxios,axios)\n\n```\n这二者效果都是一致这样我就感觉vue-axios显得多余。希望知道多一点的朋友能告诉我vue-axios存在的必要非常感谢",
"answer": "何不看看vue-axios的源码就一个文件\nindex.js\n```\n(function () {\n\n/**\n * Install plugin\n * @param Vue\n * @param axios\n */\n\nfunction plugin(Vue, axios) {\n\n if (plugin.installed) {\n return\n }\n plugin.installed = true\n\n if (!axios) {\n console.error('You have to install axios')\n return\n }\n\n Vue.axios = axios\n\n Object.defineProperties(Vue.prototype, {\n\n axios: {\n get() {\n return axios\n }\n },\n\n $http: {\n get() {\n return axios\n }\n }\n\n })\n}\n\nif (typeof exports == \"object\") {\n module.exports = plugin\n} else if (typeof define == \"function\" && define.amd) {\n define([], function(){ return plugin })\n} else if (window.Vue && window.axios) {\n Vue.use(plugin, window.axios)\n}\n\n})();\n```\n首先是按照`Vue`的插件文档来写的,直接绑在原型链上不是不可以,如果像您这样注册一个$http和项目其他成员协作的时候就必须注明你注册的变量名称而使用vue-axios大家就没有歧义了。\n说白了使用vue-axios更多是为了符合规范并且方便协作吧。",
"type": "technical_qa"
},
{
"id": "segmentfault_380",
"question": "react native使用 react-navigation登录后如何清空 react-navigetion 内的返回记录?\n如题所说使用navigation 导航登录后清空记录navigation有相应的方法吗???????",
"answer": "跳转并清空路由记录\n```\n import { NavigationActions } from 'react-navigation'\n resetAction = NavigationActions.reset({\n index: 0,\n actions: [\n NavigationActions.navigate({routeName:'xxx'})//要跳转到的页面名字\n ]\n });\nthis.props.navigation.dispatch(resetAction);\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_381",
"question": "移动端页面使用background-attachment:fixed;固定背景图片\n在某些机型中微信中打开不起作用大家遇到过没怎么解决的呢",
"answer": "移动端对`background-attachment: fixed`支持的不好但可以hack一下。\n```\ncssbody:before {\n content: ' ';\n position: fixed;\n z-index: -1;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n background: url(path/to/image) center 0 no-repeat;\n background-size: cover;\n}\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_382",
"question": "怎么用js通过文件的url下载文件到本地\n目前拿到的是文件的url不是下载地址只是文件的存放地址。前端怎样用js通过这个url实现文件的下载呢",
"answer": "```\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <title></title>\n</head>\n<body>\n <a href=\"/download/papers/abc.doc\">点击链接下载</a>\n <button onclick=\"download1()\">点击按钮下载</button>\n <button onclick=\"download2\">点击按钮下载</button>\n\n <script>\n // 会打开一个空白页下载,然后空白页消失,用户体验不好\n function download1() {\n window.open('/download/papers/1');\n }\n \n // 直接下载,用户体验好\n function download2() {\n var $form = $('<form method=\"GET\"></form>');\n $form.attr('action', '/download/papers/1');\n $form.appendTo($('body'));\n $form.submit();\n }\n </script>\n</body>\n</html>\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_383",
"question": "请问 React 中的 registerServiceWorker是干什么的\ncreate-react-app生成的项目中多了一个registerServiceWorker.js并且在 index.js 中引用请问这个registerServiceWorker是什么东西融合进 react 的目的是什么?",
"answer": "看下注释你就知道了,主要是用于在生产环境中为用户在本地创建一个`service worker` 来缓存资源到本地,提升应用的访问速度,具体看下面这段注释。\n```\n// In production, we register a service worker to serve assets from local cache.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on the \"N+1\" visit to a page, since previously\n// cached resources are updated in the background.\n\n// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.\n// This link also includes instructions on opting out of this behavior.\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_384",
"question": "jQuery修改input的val能否触发v-model的更新\n现在有需求希望能通过jQuery修改input的值并且能触发相关数据的更新能不能办到。比如\n```\n$(\"input\").val(2333);\n```\n我的需求比较奇葩啊页面上有循环出来的大量input框而这些input框需要通过一个自定义的键盘来输入。用jQuery的话只要在需要修改的input上打标记然后再改它的值就行。只用vue的话目前没想到有啥简单的方法来实现。\n现在的想法是实在不行就在每个input上打上数组的维度标记然后用jQuery根据维度去data中修改对应的值。这么一来就有点麻烦了",
"answer": "可以的,需要在设置完之后触发一下事件:\n```\n$(\"input\").val(2333)\n//触发一下该input的input事件\n$(\"input\")[0].dispatchEvent(new Event('input'))\n```\n`v-model` 只不过是个语法糖底层还是监听的input事件",
"type": "technical_qa"
},
{
"id": "segmentfault_385",
"question": "css 当a的父节点是p 的话,该怎么表达呢?\n```\n<p><a></a><p>\n```\n这种该怎么表达呢?主要是给p加一个样式……",
"answer": "原来用纯 CSS是表达不了CSS3没有父元素选择器\n不过 CSS4更新了功能可以参考 CSS4选择器文档CSS Selectors from CSS4 till CSS1\n还有这篇文档新增伪类 :has()\n语法是\n```\n!li > p { border:1px solid #CCC; } /* 为 p 的父元素 li 设置一个边框 */\n```\n注意的是这样的父级选择器当时一直都没有被各大浏览器支持但是可以试试。",
"type": "technical_qa"
},
{
"id": "segmentfault_386",
"question": "微信小程序的背景图要怎么显示?\n开发小程序的时候设置页面的背景我用到css代码\n```\n.page__bd{\n width: 100%;\n height: 220px;\n background: url('../../assets/img/images.jpg') no-repeat;\n background-size: 100% 100%;\n}\n```\n在调试工具上是显示的但是扫面上传到手机上却显示不出来谁遇到过这样的问题",
"answer": "可以用行内来实现\n```\n<view class=\"warp\" style=\"background-image: url('../../images/welcome.png')\">\n\n</view>\n```\n上面这个在“开发工具”中能显示但是用手机预览的时候就不出图所以下面\n以欢迎页面来说\nwxml:\n```\n<!-- welcome.wxml -->\n<view bindtap=\"goHome\" class=\"warp\">\n <image src=\"../../images/welcome.png\"></image>\n <text>{{ countDownNumber }}</text> <!-- 倒计时 -->\n</view>\n```\ncss:\n```\npage {\n height: 100%;\n}\n.warp {\n height: 100%;\n position: relative;\n}\n\n.warp image {\n width: 100%;\n height: 100%;\n}\n\n.warp text {\n width: 20px;\n height: 20px;\n line-height: 20px;\n text-align: center;\n color: #fff;\n position: absolute;\n top: 46%;\n left: 50%;\n margin-top: -10px;\n margin-left: -10px;\n border-radius: 50%;\n background-color: rgba(0,0,0,.5)\n}\n```\njs:\n```\n//welcome.js\n//获取应用实例\nconst app = getApp();\n\nPage({\n\n /**\n * 页面的初始数据\n */\n data: {\n countDownNumber: 5,\n timerId: 0\n },\n\n /**\n * 生命周期函数--监听页面加载\n */\n onLoad: function (options) {\n var page = this;\n\n //倒计时关闭当前页,重定向到首页\n var timer = setInterval(function(){\n page.setData({\n countDownNumber: page.data.countDownNumber - 1\n });\n if (page.data.countDownNumber == 1) {\n clearInterval(timer);\n wx.switchTab({\n url: '../index/index'\n }) \n } \n },1000);\n page.setData({\n timerId: timer\n })\n },\n\n /**\n * 触击“欢迎页面”直接重定向到首页\n */\n goHome: function(e){\n //清空计时器\n clearInterval(this.data.timerId);\n //关闭当前页,重定向到首页\n wx.switchTab({\n url: '../index/index'\n })\n }\n\n})\n```\n这么着“开发工具”与预览都没问题线上没试过它这css里好像只能放网络地址...,我也是头一次摸....",
"type": "technical_qa"
},
{
"id": "segmentfault_387",
"question": "vue2 如何去除带__ob__这样的数据\n```\ndata: function () {\n return {\n cityData: cityData,\n selectedOptions:this.source[this.schema_key]\n }\n}\n```\nconsole上面的this.source[this.schema_key]如下\n```\n[24, 81, __ob__: Observer]\n```\n有么有一种方式可以直接这样获取这样数据\n```\n[24, 81]\n```",
"answer": "`__ob__: Observer`这些数据是vue这个框架对数据设置的监控器一般都是不可枚举的。\n`console.log`这样的打印函数,被打印的变量会执行自身的`toString()`,这样,即便内部属性是不可枚举,实际上也能看到。举个例子:\n```\nconst obj = {\n a: 0,\n b: 1\n};\nObject.defineProperty(obj, 'b', {\n writable: false,\n enumerable: false,\n configurable: false\n});\n\nconsole.log(obj); // Object {a: 0, b: 1}\n```\n因为你已经将数据绑定在了vue之中vue就肯定要为数据添加监控器的如果你强制删掉了这些监控器那么这些数据也就失去了监控那么你使用vue的意义何在……\n如果仅仅是去掉这些监控器而不考虑后果的话把对象复制一份就行了因为复制的对象是不包含不可枚举属性的。\n```\nconst obj1 = {\n a: 0,\n b: 1\n};\nObject.defineProperty(obj1, 'b', {\n writable: false,\n enumerable: false,\n configurable: false\n});\nconst obj2 = Object.assign({}, obj1);\n\nconsole.log(obj2); // Object {a: 0}\n```\njs这类动态语言复制对象是个很头疼的事情。我写了个简单的你可以参考一下\n```\n//对象深复制,不考虑循环引用的情况\nfunction cloneObj(from) {\n return Object.keys(from)\n .reduce((obj, key) => (obj[key] = clone(from[key]), obj), {});\n}\n//数组深复制,不考虑循环引用的情况\nfunction cloneArr(from) {\n return from.map((n) => clone(n));\n}\n// 复制输入值\nfunction clone(from) {\n if (from instanceof Array) {\n return cloneArr(from);\n } else if (from instanceof Object) {\n return cloneObj(from);\n } else {\n return (from);\n }\n}\n\nconst obj = [\n {\n name: '1'\n },\n {\n name: '2'\n }\n];\nconst obj2 = clone(obj);\nconsole.log(obj2);\n```\n在外面直接用`clone()`方法就行了。",
"type": "technical_qa"
},
{
"id": "segmentfault_388",
"question": "php new 一个类 比如$a = new Cat(); Cat后面为什么写()而不是{}\n<?php\n```\nclass Cat{\n public $name;\n public $age;\n function __construct($name,$age){\n $this->name = $name;\n $this->age = $age;\n }\n}\n$a = new Cat('小白',2);\n为什么new Cat('小白',2) Cat后面是()而不是{},看起来很像是函数调用啊,虽然new一个\n对象,构造函数会自动调用\n因为js里面没有类,只有构造函数,所以new方式调用函数很好理解!\n```\n?>",
"answer": "首先`new xxx()`这是规定的声明类的写法,至于你说像函数调用,其实你也可以理解成在`new Cat('小白', 2)`的时候调用了`class Cat`中的构造函数`__construct()`,并且传递了两个参数",
"type": "technical_qa"
},
{
"id": "segmentfault_389",
"question": "提高InnoDB导入数据的速度\n向mysql中导入维基百科的数据数据源中sql的部分,总数据20g单条sql 100MB--5GB导入速度太慢1个晚上才导入不到1GB如何提高导入速度。主键唯一性检验和自动提交都已经关了。",
"answer": "之前回答过一个类似的问题,思路如下:\n对于insert方式写入优化点\n1、insert批量执行禁止单条insert value注意单条sql长度限制可临时调整max_allowed_packet\n2、开启事务处理批量提交。原理类似上1(条件允许可适当增大innodb_log_buffer_size增加单事务提交日志量该参数read only)\n3、主键顺序插入效率更高\n4、业务允许暂时disable keys\n其他录入方式比如load data是比较快的可以试试\n另外如果业务允许暂时禁用binlog并将redolog文件采用软连接的方式放入内存减少磁盘io同样也可以把你的表数据文件放入内存目录/dev/shm要求内存足够要记得导入完成重新放入磁盘以上两种方式导入均可采用此方式减少磁盘io",
"type": "technical_qa"
},
{
"id": "segmentfault_390",
"question": ".vue文件中 使用@import 来导入样式的路径问题\n```\n <style lang=\"stylus\">\n //使用 ../来匹配路径可以正确导入\n @import '../assets/css/main.styl'; //正确\n //使用 alias 中 配的 @ 就不能用了\n @import '@/assets/css/main.styl'; //错误\n </style>\n```\n怎么解决这个 @import 导入css文件的路径问题的 \n总不能一直 ../ 吧、\nwebpack 配置的 alias 好像不能作用在css里面里面\n大佬们有什么解决办法吗",
"answer": "eg: \n@import '~@/assets/scss/helpers/_mixin';\n使用 ~\n原理\nCSS loader 会把把非根路径的url解释为相对路径 加~前缀才会解释成模块路径。",
"type": "technical_qa"
},
{
"id": "segmentfault_391",
"question": "PHP二维数组根据键值对获取一组数组 (不使用foreach)\n```\n$user = array( \n 0 => array( \n 'id' => 1, \n 'name' => '张三', \n 'email' => 'zhangsan@sina.com', \n ), \n 1 => array( \n 'id' => 2, \n 'name' => '李四', \n 'email' => 'lisi@163.com', \n ), \n 2 => array( \n 'id' => 5, \n 'name' => '王五', \n 'email' => '10000@qq.com', \n ), \n ...... \n); \n```\n比如我想获取当id=2时,该数组的全部内容,不使用foreach,在PHP 5.3版本下",
"answer": "```\n$user = array( \n 0 => array( \n 'id' => 1, \n 'name' => '张三', \n 'email' => 'zhangsan@sina.com', \n ), \n 1 => array( \n 'id' => 2, \n 'name' => '李四', \n 'email' => 'lisi@163.com', \n ), \n 2 => array( \n 'id' => 5, \n 'name' => '王五', \n 'email' => '10000@qq.com', \n )\n);\n$ids = array_column($user, 'id');\n$new_user = array_combine($ids, $user);\nvar_dump($new_user[2]);\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_392",
"question": "vue for循环内点击只显示当前的\n拿到了后台给的数据在循环的时候添加的click想在点击当前td的时候改变当前下面的show而不是所有\n```\n<tr v-for='(i,index) in data'>\n <td @click=\"changeData\">\n <div v-if=\"show\">{{i.mobileNumber}}</div>\n </td>\n <td></td>\n <td></td>\n <td></td>\n</tr>\n\n\n```\n我想过在拿到后台数据以后自己给每条数据加个show:false,但有没有更好的方法",
"answer": "再添加一个数据项\n```\ncurrentActive: -1\n```\ntd设置\n```\n@click=\"currentActive = index\"\n```\n然后div设置\n```\nv-if=\"currentActive == index\"\n\n```\n相当于一个游标指向当前激活数据。",
"type": "technical_qa"
},
{
"id": "segmentfault_393",
"question": "js = ==赋值判断问题\n1.无意间发现的一个问题 知道语法错误 但不知道原理是为什么.为什么bool打印出来是false\n2.var bool,bool_;\nif(bool=true && bool_==false){}\nconsole.log(bool,bool_);//false undefined",
"answer": "很简单, js 运算符优先级的问题, && 的优先级比 = 的要高,所以你这样写等于\n```\nvar bool,bool_;\nif(bool=(true && bool_==false)){}\nconsole.log(bool,bool_);//false undefined\n```\n这样写即可得到想要的结果\n```\nvar bool,bool_;\nif((bool=true) && bool_==false){}\nconsole.log(bool,bool_);\n```\n望采纳",
"type": "technical_qa"
},
{
"id": "segmentfault_394",
"question": "小程序标记点markers怎么保持在地图中间?\n组件https://mp.weixin.qq.com/debu...\nAPI:https://mp.weixin.qq.com/debu...\n效果就像滴滴出行的地图可以进行选点让标记markers一直居中用户滑动放手后获取地图中心点坐标",
"answer": "标记marker可以用control来做将这个control定位在地图中间就行\n放手后获取地图中心坐标需要用regionchange他可以判断当前对地图的操作状态当e.type为end时用mapContext 获取到地图中心的位置;\n相关文档https://mp.weixin.qq.com/debu...\nhttps://mp.weixin.qq.com/debu...",
"type": "technical_qa"
},
{
"id": "segmentfault_395",
"question": "Python requests.get 爬虫 设置代理 IP地址未改变\n工作需要爬取亚马逊上面的信息但是亚马逊反爬虫太厉害同一个IP地址会被封。\nPython版本3.6 IDEPycharm 2017.1\n在网上查了很多资料requests库的手册也读过但是都是同一个方法代码如下\n```\nimport requests\n'''代理IP地址高匿'''\nproxy = {'HTTPS': '117.85.105.170:808'}\n'''head 信息'''\nhead = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36', \n 'Connection': 'keep-alive'}\n'''http://icanhazip.com会返回当前的IP地址'''\np = requests.get('http://icanhazip.com', headers=head, proxies=proxy)\nprint(p.text)\n```\n根据我看过的许多教程的理论如果代理设置成功最后显示的IP应该是代理的IP地址但是最终还是我真实的IP地址这样一来不就等于没有设置代理么",
"answer": "proxies在你访问http时用http的设置访问https时用https的设置\n所以你的proxy需要同时包含http及https的配置这样才能生效\n```\nproxy = {\n 'http': 'http://117.85.105.170:808',\n 'https': 'https://117.85.105.170:808'\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_396",
"question": "express app和router的区别\nvar app = express(); \nvar router = express.Router();\n以上二者的区别是什么什么时候用哪个最合适",
"answer": "区别看下面的例子:\napp.js\n```\nvar express = require('express'),\n dogs = require('./routes/dogs'),\n cats = require('./routes/cats'),\n birds = require('./routes/birds');\n\nvar app = express();\n\napp.use('/dogs', dogs);\napp.use('/cats', cats);\napp.use('/birds', birds);\n\napp.listen(3000);\n```\ndogs.js\n```\nvar express = require('express');\n\nvar router = express.Router();\n\nrouter.get('/', function(req, res) {\n res.send('GET handler for /dogs route.');\n});\n\nrouter.post('/', function(req, res) {\n res.send('POST handler for /dogs route.');\n});\n\nmodule.exports = router;\n```\n在 `app.js` 中调用 `express()` 时,返回一个 `app` 对象。\n`app` 对象可以看作创建了一个 `Express` 应用程序。\n而当 `express.Router()` 被调用时,返回稍微不同的“迷你应用”。\n“迷你应用程序”背后的想法是应用程序中的不同路线可能变得相当复杂你可以从将该逻辑移动到单独的文件中获益。\n在上面这个简单的例子中`/dogs` 路由的逻辑已经被移动到自己的文件中,所以它的 `GET` 和 `POST` 处理程序不会混乱 `app.js`。\n现在你可以独立地处理对 `/dog` 的任何请求的逻辑,而不用担心它将如何影响猫 `/birds`。\n如果你具有与所有三条路由相关的逻辑`Express` 中称为中间件),则可以将其放在 `app.use(...)` 调用上方的 `app.js` 中。\n如果你有逻辑仅与其中一条路线`/dog`)相关,那么你只将它放在该路由的文件中。\n以上回答来源于Differences between express.Router and app.get?\n共同学习给赞更好\n至于什么时候使用其实上面的例子已经解释了。\n如果代码非常简单完全可以 `app.get('/',....)`,如果路由比较复杂,使用 `express.Router()` 更合适。",
"type": "technical_qa"
},
{
"id": "segmentfault_397",
"question": "vue webpack [HMR] 警告\n[HMR] bundle has 2 warnings\nclient.js?ede2:161 ./src/components/Banner.vue\nThere are multiple modules with names that only differ in casing.\nThis can lead to unexpected behavior when compiling on a filesystem with other case-semantic.\nUse equal casing. Compare these module identifiers:\n- \nD:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangnode_modules.11.3.4@vue-loaderindex.js??ref--0!D:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangsrccomponentsBanner.vue\n`Used by 6 module(s), i. e.\nD:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\node_modules\\.6.4.1@babel-loader\\lib\\index.js!D:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\node_modules\\.11.3.4@vue-loader\\lib\\selector.js?type=script&index=0!D:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\src\\page\\bbs\\index.vue`\n\n- \nD:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangnode_modules.11.3.4@vue-loaderindex.js??ref--0!D:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangsrccomponentsbanner.vue\n`Used by 1 module(s), i. e.\nD:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\node_modules\\.6.4.1@babel-loader\\lib\\index.js!D:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\node_modules\\.11.3.4@vue-loader\\lib\\selector.js?type=script&index=0!D:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\src\\page\\service\\serviceDetails.vue`\n./~/.6.4.1@babel-loader/lib!./~/.11.3.4@vue-loader/lib/selector.js?type=script&index=0!./src/components/Banner.vue\n\nD:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangnode_modules.11.3.4@vue-loaderindex.js??ref--0!D:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangsrccomponentsBanner.vue\n```\n`Used by 6 module(s), i. e.\nD:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\node_modules\\.6.4.1@babel-loader\\lib\\index.js!D:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\node_modules\\.11.3.4@vue-loader\\lib\\selector.js?type=script&index=0!D:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\src\\page\\bbs\\index.vue`\n```\nD:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangnode_modules.11.3.4@vue-loaderindex.js??ref--0!D:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangsrccomponentsbanner.vue\n```\n`Used by 1 module(s), i. e.\nD:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\node_modules\\.6.4.1@babel-loader\\lib\\index.js!D:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\node_modules\\.11.3.4@vue-loader\\lib\\selector.js?type=script&index=0!D:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\src\\page\\service\\serviceDetails.vue`\n```\n./~/.6.4.1@babel-loader/lib!./~/.11.3.4@vue-loader/lib/selector.js?type=script&index=0!./src/components/Banner.vue\nThere are multiple modules with names that only differ in casing.\nThis can lead to unexpected behavior when compiling on a filesystem with other case-semantic.\nUse equal casing. Compare these module identifiers:\n- \nD:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangnode_modules.6.4.1@babel-loaderlibindex.js!D:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangnode_modules.11.3.4@vue-loaderlibselector.js?type=script&index=0!D:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangsrccomponentsBanner.vue\n`Used by 1 module(s), i. e.\nD:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\node_modules\\.11.3.4@vue-loader\\index.js??ref--0!D:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\src\\components\\Banner.vue`\n\n- \nD:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangnode_modules.6.4.1@babel-loaderlibindex.js!D:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangnode_modules.11.3.4@vue-loaderlibselector.js?type=script&index=0!D:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangsrccomponentsbanner.vue\n`Used by 1 module(s), i. e.\nD:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\node_modules\\.11.3.4@vue-loader\\index.js??ref--0!D:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\src\\components\\banner.vue`\n\nD:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangnode_modules.6.4.1@babel-loaderlibindex.js!D:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangnode_modules.11.3.4@vue-loaderlibselector.js?type=script&index=0!D:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangsrccomponentsBanner.vue\n```\n`Used by 1 module(s), i. e.\nD:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\node_modules\\.11.3.4@vue-loader\\index.js??ref--0!D:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\src\\components\\Banner.vue`\n```\nD:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangnode_modules.6.4.1@babel-loaderlibindex.js!D:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangnode_modules.11.3.4@vue-loaderlibselector.js?type=script&index=0!D:用户目录我的文档HBuilderProjectvue-bulingwangpulingwangsrccomponentsbanner.vue\n```\n`Used by 1 module(s), i. e.\nD:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\node_modules\\.11.3.4@vue-loader\\index.js??ref--0!D:\\用户目录\\我的文档\\HBuilderProject\\vue-bulingwang\\pulingwang\\src\\components\\banner.vue`\n```",
"answer": "有可能是因为是路径或者文件名大小写的问题,例如原本组件是得这么引的\n```\nimport SueChooseCity from '@souche-vue/sue-pc/src/components/choosecity';\n```\n然而在单页应用的另外一个页面的一不小心把choosecity写成了chooseCity\n```\nimport SueChooseCity from '@souche-vue/sue-pc/src/components/chooseCity';\n```\n然后就出了这个错。\n```\nThere are multiple modules with names that only differ in casing.\nThis can lead to unexpected behavior when compiling on a filesystem with other case-semantic.```\n\n我看到你的报错信息里有bulingwangpulingwangsrccomponentsbanner和bulingwangpulingwangsrccomponentsBanner。大小写的B的区别所以问题就出在这里。",
"type": "technical_qa"
},
{
"id": "segmentfault_398",
"question": "为什么JAVA很多类都放弃了安全而要速度呢\n比如hashmap和hashtablearrylist和vector这种的我学的时候都说是xxx不用了区别是一个安全一个不安全当然hashtable那个还有个null的区别为啥要用不安全的呢",
"answer": "什么叫`放弃安全而要速度`。\n这认识错的太远了需要线程安全的情况下当然是`必须`要使用线程安全的类型了,不需要自然是可以不用使用了。\n如下代码\n```\npublic void m() {\n int i = 0;\n String s = \"string\" + i;\n System.out.println(s);\n}\n```\n`JDK`会将字节码编译成如下\n```\n public void m();\n descriptor: ()V\n flags: ACC_PUBLIC\n Code:\n stack=2, locals=3, args_size=1\n 0: iconst_0\n 1: istore_1\n 2: new #2 // class java/lang/StringBuilder\n 5: dup\n 6: invokespecial #3 // Method java/lang/StringBuilder.\"<init>\":()V\n 9: ldc #4 // String string\n 11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;\n 14: iload_1\n 15: invokevirtual #6 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;\n 18: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;\n 21: astore_2\n 22: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;\n 25: aload_2\n 26: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V\n 29: return\n```\n可以很清楚的看到字节码中将字符串连接编译成`StringBuilder`的方式,我们知道`JDK`还提供了一个`StringBuffer`线程安全的字符串操作类。那`JDK`编译时为什么不选择`StringBuffer`来做呢,答案很显然是`不需要`,因为这是在一个方法的内部,一个`局部变量`是不可能会遇到`线程安全`问题的。\n而`HashMap`与`HashTable`也是同理,如果你是`局部变量`那只需要选择`HashMap`就可以了。如果是`全局变量`且会有多个线程同时操作该变量的情况当然是不能选择`HashMap`,而是要选择`HashTable`这种线程安全的类型,但是现在`HashTable`被选择的也会很少是因为有了更好的选择如`ConcurrentHashMap`来代替。",
"type": "technical_qa"
},
{
"id": "segmentfault_399",
"question": "如何让不带www的网站访问时跳转到带www的网站\n我用的是nginx,我按照网上说的301配置但是没有效果有没有懂的麻烦给讲解一下",
"answer": "基于域名的虚拟主机的虚拟主机可以轻松做到这一点。\n```\nserver {\n server_name example.com;\n return 301 $scheme://www.example.com$request_uri;\n}\n\nserver {\n server_name www.example.com;\n #... SNIP ...#\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_400",
"question": "PHP有办法在闭包外部得到闭包内部的变量吗\n```\n<?php\n\n\n $arr = [\n ['2','3'],\n ['6,7']\n ];\n \n\n $s= array_walk($arr, function($_value,$_key){\n\n $a = 10;\n\n return true;\n });\n\n var_dump($a);//$a 打印的时候报错了,如何得到$a呢\n```",
"answer": "```\n<?php\n\n$arr = [\n ['2','3'],\n ['6,7']\n];\n$a = 0;\n$s = array_walk($arr, function($_value,$_key) use (&$a) {\n $a = 10;\n\n return true;\n});\n\nvar_dump($a);\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_401",
"question": "三个函数调用之后分别输出什么?\n下面的三个函数调用之后分别输出什么\n```\nfunction f1(x, y, a) {\n arguments[2] = 10;\n console.log(a);\n}\nf1(1, 2, 3);\n\nfunction f2(x, y, a) {\n arguments[2] = 10;\n console.log(a);\n}\nf2(1, 2);\n\nfunction f3(x, y, a) {\n arguments[2] = 10;\n console.log(arguments[2]);\n}\nf3(1,2);\n```\n求分析:\n输出结果第一次10第二次undefined第三次10",
"answer": "- arguments是伪值它是传入函数参数的值组成的数组它的顺序和参数列表一致且可以在函数内被重写\n- arguments中每一个值都是指向参数本身的内存而并非是副本\n- 函数内`arguments`,其实就是取到了`[x, y, a]`\n- 其中,`arguments[2]`对应的是`a`,且直接指向`a`的内存\n- 因此第一个函数输出10因为修改`arguments[2]`也就是修改`a`的内存,也就是对`a`赋值10\n- 第二次,由于没有传`a`,所以`arguments[2]`没有指向任何内存,且`a`也没有指定内存,因此是`undefined`\n- 第三次,由于`arguments[2]`没有指向任何内存,`a`也没有指定内存,所以,`arguments[2]`实质是给`arguments[2]`开辟了一块内存并初始化值为10但是这块内存并不是`a`的内存\n\narguments是伪值它是传入函数参数的值组成的数组它的顺序和参数列表一致且可以在函数内被重写\narguments中每一个值都是指向参数本身的内存而并非是副本\n函数内`arguments`,其实就是取到了`[x, y, a]`\n其中`arguments[2]`对应的是`a`,且直接指向`a`的内存\n因此第一个函数输出10因为修改`arguments[2]`也就是修改`a`的内存,也就是对`a`赋值10\n第二次由于没有传`a`,所以`arguments[2]`没有指向任何内存,且`a`也没有指定内存,因此是`undefined`\n第三次由于`arguments[2]`没有指向任何内存,`a`也没有指定内存,所以,`arguments[2]`实质是给`arguments[2]`开辟了一块内存并初始化值为10但是这块内存并不是`a`的内存",
"type": "technical_qa"
},
{
"id": "segmentfault_402",
"question": "js产生1-20之间的数要求数越小出现的概率越高要怎么写\n需要随机产生1-20之间的数数字越小出现的概率越高。\n请教大家该怎么写",
"answer": "`1 + Math.floor(Math.random() * Math.random() * 20)`\n`Math.random()`的几率是相等的结果在0到1之间落在0到0.5和0.5到1之间的概率都是0.5\n两个`Math.random()`相乘落在0到0.5之间的概率是`3 / 4`落在0.5到1之间的概率是`1/4`,因为只有当两次`Math.random()`的结果都在0.5以上时结果才会在0.5到1之间。\n所以多个`Math.random()`相乘会使数越小出现的概率越高。\nUpdate:\n上面所说的\n落在0到0.5之间的概率是`3 / 4`落在0.5到1之间的概率是`1/4`,应该是`不对`的。因为即使两次`Math.random()`的结果都在0.5以上时结果也不一定会在0.5到1之间比如`0.6 * 0.6 = 0.36; 0.7 * 0.7 = 0.49`,所以上面的描述更正如下:\n感谢@manggo指正",
"type": "technical_qa"
},
{
"id": "segmentfault_403",
"question": "js扁平化树形结构的json对象 转换json数据结构\n有这样的一个`json`数据\n```\n[\n {\n 'Id': '1',\n 'Name': '教学素材管理',\n 'Pid': '0',\n 'id': '659354849B9A44AA9E2477223DF68C96',\n 'children': [\n {\n 'Id': '4DDA93E00CD34E4D812EC1A9E10AA883',\n 'Name': '教学素材',\n 'Pid': '659354849B9A44AA9E2477223DF68C96',\n 'id': '4DDA93E00CD34E4D812EC1A9E10AA883',\n 'children': [\n {\n 'Id': '6CD3A04CFBC1419F81E1A66BDC81F177',\n 'Name': '修改',\n 'Pid': '4DDA93E00CD34E4D812EC1A9E10AA883',\n 'id': '6CD3A04CFBC1419F81E1A66BDC81F177'\n },\n {\n 'Id': 'B93352644544420782337BC41C0534A9',\n 'Name': '添加',\n 'Pid': '4DDA93E00CD34E4D812EC1A9E10AA883',\n 'id': 'B93352644544420782337BC41C0534A9'\n }\n ]\n },\n {\n 'Id': '68F89C4E368048E699F3D7EDD69A86A7',\n 'Name': '测试试题',\n 'Pid': '659354849B9A44AA9E2477223DF68C96',\n 'id': '68F89C4E368048E699F3D7EDD69A86A7'\n },\n {\n 'Id': 'CF31D0CA5BC34765A61909B296E470C6',\n 'Name': '问题任务',\n 'Pid': '659354849B9A44AA9E2477223DF68C96',\n 'id': 'CF31D0CA5BC34765A61909B296E470C6'\n }\n ]\n },\n {\n 'Id': 'B85EAE5FAAC64790AC62FA288E87AEAC',\n 'Name': '基础数据管理',\n 'Pid': '0',\n 'id': 'B85EAE5FAAC64790AC62FA288E87AEAC',\n 'children': [\n {\n 'Id': '134D7E54B9D041539940D29E24592DF4',\n 'Name': '专业设置',\n 'Pid': 'B85EAE5FAAC64790AC62FA288E87AEAC',\n 'id': '134D7E54B9D041539940D29E24592DF4'\n },\n {\n 'Id': '2314DE1399484596A7440326E07590DB',\n 'Name': '专业管理',\n 'Pid': 'B85EAE5FAAC64790AC62FA288E87AEAC',\n 'id': '2314DE1399484596A7440326E07590DB'\n }\n ]\n }\n]\n\n```\n怎么转换成扁平化如下格式\n```\n[\n {\n 'Id': '1',\n 'Name': '教学素材管理',\n 'Pid': '0',\n 'id': '659354849B9A44AA9E2477223DF68C96'\n },\n {\n 'Id': '4DDA93E00CD34E4D812EC1A9E10AA883',\n 'Name': '教学素材',\n 'Pid': '659354849B9A44AA9E2477223DF68C96',\n 'id': '4DDA93E00CD34E4D812EC1A9E10AA883'\n },\n {\n 'Id': '6CD3A04CFBC1419F81E1A66BDC81F177',\n 'Name': '修改',\n 'Pid': '4DDA93E00CD34E4D812EC1A9E10AA883',\n 'id': '6CD3A04CFBC1419F81E1A66BDC81F177'\n },\n {\n 'Id': 'B93352644544420782337BC41C0534A9',\n 'Name': '添加',\n 'Pid': '4DDA93E00CD34E4D812EC1A9E10AA883',\n 'id': 'B93352644544420782337BC41C0534A9'\n },\n {\n 'Id': '68F89C4E368048E699F3D7EDD69A86A7',\n 'Name': '测试试题',\n 'Pid': '659354849B9A44AA9E2477223DF68C96',\n 'id': '68F89C4E368048E699F3D7EDD69A86A7'\n },\n {\n 'Id': 'CF31D0CA5BC34765A61909B296E470C6',\n 'Name': '问题任务',\n 'Pid': '659354849B9A44AA9E2477223DF68C96',\n 'id': 'CF31D0CA5BC34765A61909B296E470C6'\n },\n {\n 'Id': 'B85EAE5FAAC64790AC62FA288E87AEAC',\n 'Name': '基础数据管理',\n 'Pid': '0',\n 'id': 'B85EAE5FAAC64790AC62FA288E87AEAC'\n },\n {\n 'Id': '134D7E54B9D041539940D29E24592DF4',\n 'Name': '专业设置',\n 'Pid': 'B85EAE5FAAC64790AC62FA288E87AEAC',\n 'id': '134D7E54B9D041539940D29E24592DF4'\n },\n {\n 'Id': '2314DE1399484596A7440326E07590DB',\n 'Name': '专业管理',\n 'Pid': 'B85EAE5FAAC64790AC62FA288E87AEAC',\n 'id': '2314DE1399484596A7440326E07590DB'\n }\n]\n\n```",
"answer": "供参考\n```\nfunction flatten (data) {\n return data.reduce((arr, {Id, Name, Pid, id, children = []}) =>\n arr.concat([{Id, Name, Pid, id}], flatten(children)), [])\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_404",
"question": "正则表达式中 (?:)到底是什么意思\n例子\n1.(w)((?=111)(1))+ 为什么=重复4次以上的字母数字则匹配其剩下最后2位之前的部分\n2.\"abcabc\".match(/(?:a)(b).*1/g); 结果为 [\"abcab\"]",
"answer": "先回答问题题目的`(?:)`意思\n这个代表不捕获分组\n比较`(X)`和`(?:X)`,前者是捕获分组,后者不捕获,区别在于正则表达式匹配输入字符串之后所获得的匹配的(数)组当中没有`(?:X)`匹配的部分;\n比如\n```\nvar m = \"abcabc\".match(/(?:a)(b)(c)/)\n//结果 [\"abc\", \"b\", \"c\"]\n// m[0] 是/(?:a)(b)(c)/匹配到的整个字符串这里包括了a\n// m[1] 是捕获组1即(b)匹配的子字符串substring or sub sequence\n// m[2] 是捕获组2即(c)匹配到的\n```\n如果这样\n```\nvar m = \"abcabc\".match(/(a)(b)(c)/)\n//结果 [\"abc\", \"a\", \"b\", \"c\"]\n```\n第一小题应该是这样的正则表达式\n```\n/(\\w)((?=111)(1))+/\n```\n这里有一个知识点`zero-width positive lookahead`,零宽断言,正向前瞻(反正我记不住\n意思是`(?=X)`匹配某个位置右边正向是X它不真正匹配捕获子串。\n看几个匹配的测试例子\n```\n/(\\w)((?=111)(1))+/.test(\"1111\") // true\n/(\\w)((?=111)(1))+/.test(\"2222\") // false\n```\n匹配重复4次以上的字母或数字可以这么写\n```\n/(\\w)(?=\\1{3,})/.test(\"AAAAAAAA\") //true\n/(\\w)(?=\\1{3,})/.test(\"AAAB\") //false\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_405",
"question": "mysql like 模糊搜索\n问题一 name like '%联想%' 是全表搜索,如何使用索引来优化查询?\n```\n 有推荐用mysql 函数 locate/instr\n\n explain SELECT * FROM product where name like '%联想%';\n explain SELECT * FROM product where LOCATE('联想',name)>0 ;\n explain SELECT * FROM product where instr(name, '联想')>0 ;\n\n 看着解释没什么区别啊,都是用了全表搜索\n \n \n\n```\n问题二 name like '%联想%' 是匹配的 XX联想XX。如何匹配 XX联XX XX想XX现在是把搜索内容拆分了name like '%联%' or name like '%想%'",
"answer": "第一个问题: 如果左边有通配符`%`的话,是无法走索引的,只能走全表扫描,最好的结果是`select`中只查询索引覆盖的列,比如假设只有`name`s列带索引,`select name from product where name like '%联想%'`,走的是扫描整个索引,比全表扫描要快一点,但是应用很局限,一般不会只查被索引覆盖的列啊.\n第二个问题: 这种分词查询简单点就用全文索引, 如果表超级大,性能差的话, 上搜索引擎,比如`solr`,`Lucene`、`Sphinx`.",
"type": "technical_qa"
},
{
"id": "segmentfault_406",
"question": "webpack 生产环境打包出的 map 文件有什么用\n发现打包出的map文件体积比较大想知道这个文件有什么用处还有是否可以不打包生成这些文件",
"answer": "打包后产生后缀名为.map的文件是由于配置了sourcemap选项生成的打包后的文件不容易找到出bug对应的源代码的位置sourcemap就是来帮我们解决这个问题的具体配置可以查看官网devtool配置\n或者其它的webpack sourcemap 选项多种模式的一些解释",
"type": "technical_qa"
},
{
"id": "segmentfault_407",
"question": "Vue 点击切换颜色\n第一次点击span 字体变颜色,再次点击恢复原来颜色,做成选中的效果\n代码\n```\n<li><span>健康医疗</span><span>生活服务</span><span>旅游</span><span>金融</span></li>\n<li><span>信息安全</span><span>广告营销</span><span>数据服务</span><span>智能硬化</span></li>\n<li><span>文化娱乐</span><span>网络招聘</span><span>分类信息</span><span>电子商务</span></li>\n<li><span>移动互联网</span><span>企业服务</span><span>社交网络</span></li>\n\n```\n我是小白>_< 大神们,这个怎么弄???\n。。。有木有选择span标签进行判断的方法>_<。。。",
"answer": "修改后:\n <ul v-for=\"(item,index) in lidata\">\n```\n <li><span :class=\"{active:index==isActive}\" @click=\"changeClass(index)\"> {{item.name}}\n</span></li> \n```\n</ul>\ndata(){\n```\n return{\n isActive:-1\n lidata:[\n {index:0,name:'健康医疗'},\n {index:1,name:'生活服务'},\n {index:2,name:'旅游'},\n {index:3,name:'金融'},\n {index:4,name:'信息安全'},\n {index:5,name:'广告营销'},\n {index:6,name:'数据服务'},\n {index:7,name:'智能硬化'},\n {index:8,name:'文化娱乐'},\n {index:9,name:'网络招聘'},\n {index:10,name:'分类信息'},\n {index:11,name:'电子商务'},\n {index:12,name:'移动互联网'},\n {index:13,name:'企业服务'},\n {index:14,name:'社交网络'}\n ]\n }\n }\n \nchangeClass(index){\n this.isActive=index;\n},\n\n\n实现多选\n\n <ul v-for=\"(item,index) in lidata\">\n<li><span :class=\"{active:item.checked}\" @click=\"changeClass(item)\"> {{item.name}}</span>\n </li> \n```\n</ul>\nchangeClass(item){\n```\n if(typeof item.checked=='undefined'){\n this.$set(item,\"checked\",true)\n }else{\n item.checked=!item.checked\n }\n},\n\n\n限制三次\n changeClass(item){\n let a=document.getElementsByClassName('active'); \n if(typeof item.checked=='undefined'){\n if(a.length<=3){\n this.$set(item,\"checked\",true); \n }else{\n alert(2222222222)\n } \n }else{\n item.checked=!item.checked; \n }\n},\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_408",
"question": "如何部署nodejs应用到服务器\n事情是这样的我是做前端开发的最近学习nodejs并做了些练手项目。想把他们部署到服务器上对linux和服务器部署相关知识了解较少。通过google得到大致思路如下购买一台vps安装linux系统安装nodejs和mongodb,用Nginx做端口映射用pm2做进程监控管理。发现这些操作全是命令行而且感觉好复杂有好多不了解的知识。我只是单纯的想把项目部署到服务器之前用php开发的程序的时候就购买一个虚拟主机然后ftp上传一下程序就好了大家部署nodejs应用都是如何操作的有没有啥简单的方法",
"answer": "nodejs服务器部署教程一\nnodejs服务器部署教程二把vue项目部署到线上\nnodejs服务器部署教程三部署基于node+vue+mongodb的项目\nnodejs服务器部署教程四部署ssl证书升级为https",
"type": "technical_qa"
},
{
"id": "segmentfault_409",
"question": "antd Table 如何根据某一行的数据控制行tr的样式\n如果\n```\n[{nmae:xx,repeat:1},{nmae:xx,repeat:-1},{nmae:xx,repeat:1},{nmae:xx,repeat:-1},{nmae:xx,repeat:1}]\n```\n数据结构类似与上面现在通过antd Tabel组件中的columns如何只能改变某一个单元格的式样。请问一下如何设置当repeat为1的时候改变整行tr背景",
"answer": "以下代码供参考\n```\n<Table columns={configColumns} rowClassName={(record, index) => index % 2 === 0 ? styles.classname : ''} dataSource={data}/>\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_410",
"question": "java8 stream根据下标分组\n我有个list想要按照奇偶下标生成两组list只利用java8的stream可以做到吗\n比如[1,3,5,7,9],按照奇偶下标分成[1,5,9]和[3,7],但是stream似乎无法获取下标所以试了半天也不行。\n另外java8的stream以后可以完全取代for循环吗我感觉有些复杂的逻辑拿stream折腾不是一个好的选择",
"answer": "这个要从为什么`java8`会弄出`stream`这种循环方式说起了\n以前的`for`循环是属于外部循环,由调用者自己显式的取出每个元素加以处理,尤其是并行处理时,非常痛苦\n而stream是属于内部循环你可以无需关心它是如何循环的要是并行的时候如何优化这些你都可以不管你只需要简简单单告诉他需要做什么处理即可\n举个简单的例子\n地上有很多乒乓球爸爸要让你儿子捡起来放到盒子里\n如果是外部循环可能这种模式\n爸爸地上还有球么\n儿子有\n爸爸那把它捡起来放到盒子里还有么\n儿子有\n爸爸继续捡起来放到盒子里还有么\n儿子有\n爸爸接着捡起来放到盒子里还有么\n儿子没有了\n爸爸ok收拾好了\n如果是内部循环\n爸爸把地上的球捡起来全部放到盒子里\n儿子完成\n例子可能很牵强但是我们作为开发者就是爸爸只需要告诉儿子`JDK`)把球放进盒子这个动作就好,具体儿子怎么放,一次一个手拿一个,还是一次每个手拿一个,由它自己来思考,不需要我们去指挥,我们只关注具体需要做的事就好\n所以说stream是一种内部循环你不需要去关注下标...关注下标的话,从某种意义上来说,还是外部循环的思想在处理了,当然您的问题中,明确就是要求是关注下标了,貌似好像`stream`是没法写似的\n其实不然写肯定能写的只是说换一种方式而已不把下标当成循环用的元素而是把它与具体需要循环的数字绑定起来写出来差不多是这个样子\n```\npublic static void main(String[] args) {\n List<Integer> list = Arrays.asList(1,3,5,7,9);\n\n Map<Boolean, List<Integer>> collect = IntStream.rangeClosed(1, list.size())\n .boxed()\n // 把数字和下标绑定起来\n .map(i -> mapToEntry(i, list.get(i-1)))\n // 按照下标是否能被2整除进行分组\n .collect(Collectors.partitioningBy(simpleEntry -> Integer.parseInt(simpleEntry.getKey().toString()) % 2 == 0,\n Collectors.mapping(Map.Entry::getValue, Collectors.toList())));\n // 偶数列表 3,9\n List<Integer> evenList = collect.get(Boolean.TRUE);\n // 奇数列表 1,5,7\n List<Integer> oddList = collect.get(Boolean.FALSE);\n }\n\n private static AbstractMap.SimpleEntry<Integer, Integer> mapToEntry(Integer i, Integer integer) {\n return new AbstractMap.SimpleEntry(i, integer);\n }\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_411",
"question": "如何实现PHP版本共存?\n## 描述\n由于一个服务器多至多个项目. 有些项目对php版本有不一样的需求 如何实现每个项目对应指定的PHP版本?\n## 服务器环境\n- ubuntu\n- Nginx\n- MySQL\n- php.x (N个)\nubuntu\nNginx\nMySQL\nphp.x (N个)\n## 实现效果\nwww.demo.com -> 对应PHP7.x\na.demo.com -> 对应PHP5.x\nb.demo.com -> 对应PHP4.x",
"answer": "配置下让Nginx监听不同的端口或文件就可以实现了。大体思路如下\n因为Nginx是通过PHP-FastCGI与PHP交互的然后PHP-FastCGI运行后会通过文件、或本地端口两种方式进行监听在Nginx中配置相应的FastCGI监听端口或文件即实现Nginx请求对PHP的解释。因此Nginx中根据需求配置调用不同的PHP-FastCGI端口或文件便实现不同版本PHP共存了。\n修改php-fpm.conf监听端口\n```\n<value name=\"listen_address\">127.0.0.1:8001</value>\n```\n或者\n```\n<value name=\"listen_address\">/path/to/unix/socket</value>\n```\n修改好后配置好php.ini相关的参数后重启一下\n然后再修改Nginx\n```\nlocation ~ .*.(php|php5)?$\n {\n fastcgi_pass 127.0.0.1:8001;\n fastcgi_index index.php;\n include fcgi.conf;\n }\n```\n就可以通过监听不同端口来实现不同版本的php-fpm调用了。",
"type": "technical_qa"
},
{
"id": "segmentfault_412",
"question": "一道原生JS的问题\n```\n <div>\n <input/>\n <span></span>\n </div>\n \n \n function nodeToFragme(node){\n var flag = document.createDocumentFragment();\n var child;\n\n while(child = node.firstChild ){\n flag.appendChild(child); //请问为什么能够每次插入不同的节点?\n }\n\n return flag ;\n }\n```\n为什么每次appendChild都能够插入不同的节点不应该每次都是第一个节点么",
"answer": "appendChild 成功后,会把节点从原来的节点位置移除;\n当进入 while 循环的下次执行 (child=node.firstChild) 时, 这里面运算的 firstChild 已经变成了原先移除的下一个节点;\n直到 node 中再也没有节点时,(child=node.firstChild) 的返回值会为「false」,这时循环就结束了appendChild 也完成了。\n附注\nhttps://developer.mozilla.org...",
"type": "technical_qa"
},
{
"id": "segmentfault_413",
"question": "laravel中如何区分get数据和post数据\n可能有时候会碰到这样的场景\n有一个post提交请求请求地址为:xxx?id=10提交的post数据为:id=20\n而在控制器中我要同时得到get和post中数据\nget中的id为10而post中的id为20\n这两个id分别要如何取出来",
"answer": "```\n// 路由\nroute::any('input', 'YourController@input')\n\n// 测试方法\npublic function input(Request $request)\n{\n // get方法\n echo $request->get('id');\n // get方法\n echo $request->query('id');\n // get方法\n echo $request->query->get('id');\n // 有post会覆盖get improve by amu(您)\n echo $request->id;\n // 有post会覆盖get\n echo $request->input('id');\n}\n```\n通过测试一般情况下如果postget键名一样post过来的数据$request->xxx和$request->input('xxx')会覆盖掉get的取值。",
"type": "technical_qa"
},
{
"id": "segmentfault_414",
"question": "www.baidu.com为什么属于二级域名\nbaidu.com属于一级域名\nwww.baidu.com属于二级域名\nwww.google.com.hk属于三级域名他的顶级域名是.hk还是.com呀\ntieba.baidu.com前面为什么没有www\nwww.zhaopin.longfor.com前面为啥加了www也是属于三级域名",
"answer": ".com —— 根域(.com.cn .net.cn 等也属于根域)\nbaidu.com —— 顶级域名、一级域名\nxxx.baidu.com —— 二级域名\nwwwWorld Wide Web俗称万维网只是大家“默认”的域名前缀但它并不是必须的。",
"type": "technical_qa"
},
{
"id": "segmentfault_415",
"question": "javascript字符串提取数字\n需求要把一串字符拆分成有用的信息字符串的格式有两种情形\n1、abc10\n2、123abc100\n字符与数字长度不固定提取后的结果应为:\n1、['abc','10']\n2、['123','abc','100']\n补充需求\n输出结果\n1、['abc','10']\n2、['abc','123','100']\n这样使用的时候更方便。\n当abc为某个特定的字符时字符前面的数字与本身合并一起。如1ab23=>['1ab','23']",
"answer": "```\n/**\n * @param {string} str\n * @param {string|string[]} [keywords]\n * @returns {string}\n */\nfunction match (str, keywords) {\n str = String(str)\n var ks = ''\n if (Array.isArray(keywords)) {\n ks = keywords.map(k => '\\\\d+' + k).join('|') + '|'\n } else if (typeof keywords === 'string') {\n ks = `\\\\d+${keywords}|`\n }\n var checker = new RegExp(`${ks}\\\\d+|\\\\D+`, 'g')\n return str.match(checker).sort((a, b) => !isNaN(a * 1) && isNaN(b * 1) ? 1 : -1)\n}\n\nconsole.log(match('123abc100')) // [ 'abc', '123', '100' ]\nconsole.log(match('1ab23', 'ab')) // [ '1ab', '23' ]\nconsole.log(match('ab23', 'ab')) // [ 'ab', '23' ]\nconsole.log(match('1ab23cd244gh3', ['ab', 'cd'])) // [ '1ab', '23cd', 'gh', '244', '3' ]\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_416",
"question": "与php相比python在采集方面有哪些优势\n最新需要做采集功能据说用python来做会比php直接用curl来写方便很多请问主要是有哪些优势\n如果是有特定的类库的话PHP有类似的类库可以代替么\npython大概看过hello word之类感觉上手也算简单如果为了采集单开一个项目用python来写值不值",
"answer": "会啥用啥,\n- python 和 php 数据采集方面的各自特点\n- PHP或者python进行数据采集和分析有什么比较成熟的框架\n\npython 和 php 数据采集方面的各自特点\nPHP或者python进行数据采集和分析有什么比较成熟的框架\n不过你有空可以深入了解了解`python`,毕竟人生苦短,不玩`python`可惜了",
"type": "technical_qa"
},
{
"id": "segmentfault_417",
"question": "python set中的对象如何去重\n定义Person对象\nclass Person():\n```\ndef __init__(self,name,number):\n self.name=name\n self.number=number\n \n```\nperson1=Person('yms',('123456','123'))\nperson2=Person('yms',('123456','123'))\n将两个对象都放到set里面\nset([person1,person2])\n我得出的结果set里面含有2个对象但是明显这俩个对象一样的请问怎么去重呢?注意一下('123456','123')是个元组不是普通字符串",
"answer": "你需要为这个类定义`__eq__`、`__ne__`、`__hash__`这三个函数,缺一不可:\n```\nclass Person(object):\n def __init__(self, name, number):\n self.name = name\n self.number = number\n \n def __eq__(self, other):\n if isinstance(other, Person):\n return ((self.name == other.name) and (self.number == other.number))\n else:\n return False\n \n def __ne__(self, other):\n return (not self.__eq__(other))\n \n def __hash__(self):\n return hash(self.name) + hash(self.number)\n \np1 = Person('yms', ('123456','123'))\np2 = Person('yms', ('123456','123'))\nprint(set([p1, p2]))\n\n```\n由于你说`number`是元组,所以我就直接对其使用`hash`函数了。这个`hash`函数是随便写的,你自己根据实际情况调整。",
"type": "technical_qa"
},
{
"id": "segmentfault_418",
"question": "Vue img使用@路径报错import中使用正常\n1.webpack.base代码\n```\n extensions: ['.js', '.vue', '.json'],\n alias: {\n 'vue$': 'vue/dist/vue.esm.js',\n '@': resolve('src')\n }\n```\n2.img报错代码\n```\n <div class=\"m-icon-head\">\n <img src=\"@/assets/head.png\" alt=\"\">\n </div>\n```\n3.import正常代码\nindex.js\nimport manageJob from '@/pages/jobhunter/Job/manage-job';\nimport loginSelect from '@/components/index/login_select';\nimport phoneLogin from '@/components/index/phone_login';\nimport passwordLogin from '@/components/index/password_login';\n组件\n```\nimport mHeader from '@/components/header/header';\nimport mContent from './mine-content';\n\n```\n错误提示GET http://localhost:8880/@/asset... 404 (Not Found)\n为啥会这样",
"answer": "- 因为`@`是webpack中定义的别名在JS中可以使用此别名代替`resolve('src')`指向的路径\n- `import xxxxxx`是JS语法所以可以使用`@`别名\n- 而`<img src=\"@/assets/head.png\" alt=\"\">`标签中src作为一个属性值其值是字符串并非是JS所以不能用`@`别名\n- 参见https://github.com/vuejs/vue-...\n- 这个方法我还没试验过不过据上面的Issue所说`url`地址前加`~`标记可以让解析器将地址中的别名解析出来\n- Issue中提出的方案是`<img src=\"~@/assets/head.png\" alt=\"\">`\n\n因为`@`是webpack中定义的别名在JS中可以使用此别名代替`resolve('src')`指向的路径\n`import xxxxxx`是JS语法所以可以使用`@`别名\n而`<img src=\"@/assets/head.png\" alt=\"\">`标签中src作为一个属性值其值是字符串并非是JS所以不能用`@`别名\n参见https://github.com/vuejs/vue-...\n这个方法我还没试验过不过据上面的Issue所说`url`地址前加`~`标记可以让解析器将地址中的别名解析出来\nIssue中提出的方案是`<img src=\"~@/assets/head.png\" alt=\"\">`",
"type": "technical_qa"
},
{
"id": "segmentfault_419",
"question": "Vue 怎么做scrolltop 的滚动动画\n做个了需求是点击右侧的item 左边滚动到队员的位置。。\n请问怎么可以在滚的时候加一些过度效果。。下面是我的代码\n```\nscrollToEl(name){\n let scrollPosition=0\n this.playerlist.forEach((item,index)=>{\n if(item.players_name==name){\n scrollPosition=index\n }\n })\n // this.$refs.index[scrollPosition].scrollIntoView()\n let jump=document.querySelectorAll('.pick-right-item')\n let total=jump[scrollPosition].offsetTop\n console.log(total);\n // Chrome\n document.body.scrollTop = total\n }\n```\n这样可以直接滚动到制定位置但是在vue中怎么做scroll的滚动动画。。",
"answer": "非常遗憾的告诉你, scrollTop是js属性, 不是css属性, 所以无法使用transition或者animate去加动画。只能借助一些动画类库, 或者自己编写一个scroll滚动的效果.",
"type": "technical_qa"
},
{
"id": "segmentfault_420",
"question": "AJAX发送POST请求请求提交后Method从POST变成GET\n代码如下\n```\n$.ajax({\n type: \"post\",\n dataType: \"json\",\n url: \"http://xxx\",\n data: {'xxx':'xxx'},\n success: function(returnData) {}\n})\n```\nurl 是经过 nginx 重定向的 http 地址,原地址为 https 地址\nAJAX 发送的是 POST 请求,请求提交后 chrome 调试工具中看到的请求 Method 从 POST 变成 GET",
"answer": "服务器如果返回`301`或者`302`状态码,所有请求方法都会切换成`GET`头部的`location`\n如果要保证重定向后的请求方法需要在服务端返回`307`(临时)或者`308`(永久)状态码,这两个状态码不会更改原请求方法(需要客户端支持)",
"type": "technical_qa"
},
{
"id": "segmentfault_421",
"question": "怎么使用java8的stream合并HashMap的所有value为一个Listvalue的类型为Stack\n怎么使用java8的stream合并HashMap的所有value为一个Listvalue的类型为Stack\n`map = new HashMap<String, Stack<String>>;`\n要求把map的value合并成`List<String>`并使用java8的stream方法操作\nStack是java自带的容器在这里完全可以看成是ArrayList",
"answer": "在写`stream`的时候,一定要心里非常清楚当前`stream`中到底是什么元素,这样你才能结合`map`,`filter`,`peek`等方法来转化你的数据\n首先开始的时候还没有`stream`,数据源是一个`map`,把`map`转化为`stream`,我还是建议使用`entryset`的方式\n```\n// 此时stream里的元素是Map.Entry<String, Stack<String>>\nmap.entrySet().stream()\n```\n您是想要`Entry`里面的`value`,也就是`Stack<String>`,那就要把`Map.Entry<String, Stack<String>>`转化为`Stack<String>`,那这里肯定要用`map`操作啦\n```\n// 此时stream里的元素是Stack<String>\nmap.entrySet().stream().map(Map.Entry::getValue)\n```\n拿到了`Stack<String>`的`stream`还不够,看您的意思,是想取出`Stack`中的一个`String`的属性或者一个计算出来的值,那就是要把`Stack`转化为`String`,根据您的信息,这个`Stack`其实就是`java.util.Stack`,那这个也相当于是一个集合了,集合都会有都可以变成`stream`的,由于需要集合里的`string`对象,那就相当于要把这个`Stack`集合压平,压平的话,那就肯定要用`flatmap`啦\n```\nList<String> collect = map.entrySet().stream()\n .map(Map.Entry::getValue)\n .flatmap(Stack::stream)\n .collect(Collectors.toList());\n```\n这样就完整啦当然`map`中我用的是方法引用,觉得这么写更直观一点,可以看得到当前`stream`里到底是啥类型元素,你也可以写成`lamdba`的形式啦",
"type": "technical_qa"
},
{
"id": "segmentfault_422",
"question": "javascript中forEach,map,for of的应用场景与效率\n这裡讨论的是lodash版本的_.forEach和_.map原生ES6 javascript的for of这三种方法。\n目前我的使用思路是如果是要遍历并改变Array并回传一个新的Array那我就选择_.map。\n至于for of 和_.forEach我用了以下的方式测试效能:\nforEach\n```\nlet arr = [];\nfor(var i = 0 ; i<50000000 ; i++){\n arr.push(i);\n}\nvar start = Date.now();\nlet sum = 0;\n_.forEach(arr,(a)=>{\n sum += a;\n});\nvar end = Date.now();\nconsole.log('总数:'+sum,'毫秒数:'+(end-start));\n//总数:1249999975000000 毫秒数:1530\n\n```\nfor of\n```\nlet arr = [];\nfor(var i = 0 ; i<50000000 ; i++){\n arr.push(i);\n}\nvar start = Date.now();\nlet sum = 0;\nfor(let a of arr){\n sum += a;\n}\nvar end = Date.now();\nconsole.log('总数:'+sum,'毫秒数:'+(end-start));\n//总数:1249999975000000 毫秒数:575\n```\nfor of速度大胜_.forEach所以在遍历Array时我现在会使用for of而不是_.forEach。\n我想问的是这样的思路有问题吗\n_.forEach要在什麽时候使用呢\n我自己想到的_.forEach使用时机是遍历Object时javascript原生的话应该是和for in比较。",
"answer": "有问题。\nJS中不存在传统意义上的数组静态语言中数组是一段连续的内存每一个元素都是固定字节长度的所以通过下标可以取地址快速找到引用值。\n但是JS中的数组是对象这导致你遍历数组时其实是在遍历对象的key(静态语言中的HashMap)而JS中对数组类型的遍历做了特殊处理所以foreach遍历不到非数值类型的键这也解释了为什么foreach比forin慢因为多了一层判断。\n但是如果你使用forin遍历数组会带出非数字键\n```\nvar x = [1, 2, 3];\nx.a = 'a';\nx.b = 'b';\nx.c = 'c';\nfor (let k in x)\n console.log(k)\n\n```\n即使你不会这么干谁知道你的同伴们呢第三方框架中呢自定义原型链呢\n结论ES5中遍历数组还是老老实实的foreach或者for循环.\n你的例子中使用的是ES6由于Array类型实现了Iterator接口所以forof是安全的但是如果通过babel编译成es5我猜想由于需要引入Iterator的pollyfill效率不可能比foreach高。",
"type": "technical_qa"
},
{
"id": "segmentfault_423",
"question": "这种switch语句块中default放前面的情况怎么走\n```\nint c,i;\nfor (int i = 1; i < 3; ++i)\n{\n switch (i)\n {\n default: c+=i;\n case 2: c++;break;\n case 4: c+=2;break;\n }\n}\nprintf(\"%d\\n\", c);\n\n```\n这个代码为什么会等于3啊这里面不是default第一次i为1的时候走default: c+=i;第二次i等于2就走case 2: c++;break;然后就结束最后输出c=2吗为什么是3呢",
"answer": "首先明确一下switch中的一些注意点\n## 1.\n`switch` 语句体由一系列 `case` 标签和一个可选 `default` 标签组成。 `case` 语句中的两个常量表达式的计算结果不能为同一个值。 `default` 标签只能出现一次。 标记语句不是语法要求,但如果它们不存在,`switch` 语句是无意义的。默认语句(即`default`标签)无需显示在末尾;它可以显示在 switch 语句体的任何位置。 `case` 或 `default` 标签只能显示在 `switch` 语句内。 \n摘自Microsoft Visual Studio 2015 c++ Switch语句官方文档\n## 2.\n上述所说的`case`和`default`本身就是标签,就是告诉编译器从满足这个标签开始向后执行,之后不会再判断其他标签的正确性,直到`break`语句或者`switch`语句的作用域结束。\n## For this problem\nSTEP 1 :当`i=1`时,由于`i!=2&&i!=4`故从`default`标签后开始执行,此时执行语句`c+=i;`(我们现在就假设编译器帮你把c初始化为0要知道并不是所有的编译器都这么友好)执行后c的值为1 \nSTEP 2综合上述12可知由于此时没有碰到任何`break`语句也没有到`switch`语句的作用域结束(因为这个`default`语句是放在第一个的)所以它接着向后执行`case 2`后的语句(此时编译器已经不看满不满足`case`标签了)此时执行语句`c++`;执行后c的值为2遇到`break`语句跳出`switch`语句。 \nSTEP 3:当`i=2`时由于i满足`case 2`的情况,所以直接从`case 2`便签后的语句开始执行,此时执行语句`c++`,执行后c的值为3遇到`break`语句跳出`switch`语句。 \nSTEP 4:当i=3时跳出`for`循环输出c=3 \n上述过程为本人用 Visual Studio 2015单步调试并结合资料得出的结论",
"type": "technical_qa"
},
{
"id": "segmentfault_424",
"question": "if语句如何判断中文\n```\n<?php if (96 < ($this->category_info['id']) && 108 > ($this->category_info['id'])) { ?>\n标题1\n<?php } else { ?>\n标题2\n<?php } ?>\n```\n通过以上代码可以定位如果id范围在97-107之间就显示标题1的内容否则返回2\n怎么修改可以当搜索词$this->search这个变量 包含\"价格\"这个词的时候显示标题1\n否则返回标题2",
"answer": "使用 strpos\n```\nint strpos ( string $haystack , string $needle [, int $offset = 0 ] )\n```\n```\nstrpos($this->search, '价格') === false //说明不包含价格\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_425",
"question": "webpack中配置文件的module中的rules和use什么关系\nmodule有没有rulesrules中为什么还有loaderuse不是也是加载loader的吗",
"answer": "rules是一个数组指定多个RuleRule当中的loader是use中loader的简写\n官方的文档的话语能很清楚的说明此疑问(建议看看官方documentation链接: https://webpack.js.org/config... )\n```\nRule.loader is a shortcut to Rule.use: [ { loader } ]\n\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_426",
"question": "git 分支的作用\n如果有A和B两个人同时在开发通常一个feature或者bugfix会建一个新分支再合并进develop分支那如果A和B直接在develop上pull下代码再push有冲突再解决不也可以开发吗如果考虑回滚在develop上不也可以reset或者revert吗\n感觉同一个分支反而更简单忽然不知道建新的feature或bugfix分支到底有什么好处",
"answer": "如果你在开发新功能的时候,急需修改一个 bug 怎么办?那你要把你新功能不稳定的代码也部署了?显然不可能。所以要有 feature 分支来保证新功能开发的差不多的时候才能进入主分支的代码。那你的 bug 可以随时修改。\n那么如果你有两个 bug 是先后发现的,但是一个 bug 改好了需要上线,另一个还在改,怎么办?你把改到一般的 bug 部署上线么?显然不可能。所以你需要一个 bugfix 分支,来确保 bug 改好了代码才能回到主分支。\n最后你在开发一个新功能到一半。突然产品经理跟你说我这有个新功能明天上线怎么办你要把产品暴打一顿辞职还是明天上线新功能那你第一个一半的新功能代码怎么办扔了还是半成品部署上线所以你需要多个 feature 分支来开发不同的新功能。\n怎么样主分支健壮了吧随时随地可以部署了吧",
"type": "technical_qa"
},
{
"id": "segmentfault_427",
"question": "npm run dev 启动项目后报三个警告,百度查了一下也看不明白,求指点。\nwarning in ./~/vue-style-loader/lib/addStylesClient.js\nThere are multiple modules with names that only differ in casing.\nThis can lead to unexpected behavior when compiling on a filesystem with other case-semantic.\nUse equal casing. Compare these module identifiers:\n- \nE:WebProjectUFAPPDYJJnode_modulesvue-style-loaderlibaddStylesClient.js\n`Used by 4 module(s), i. e.\nE:\\WebProject\\UFAPP\\DYJJ\\node_modules\\vue-style-loader\\index.js!E:\\WebProject\\UFAPP\\DYJJ\\node_modules\\css-loader\\index.js?{\"minimize\":false,\"sourceMap\":false}!E:\\WebProject\\UFAPP\\DYJJ\\node_modules\\vue-loader\\lib\\style-compiler\\index.js?{\"vue\":true,\"id\":\"data-v-f7c02f2c\",\"scoped\":false,\"hasInlineConfig\":false}!E:\\WebProject\\UFAPP\\DYJJ\\node_modules\\vue-loader\\lib\\selector.js?type=styles&index=0!E:\\WebProject\\UFAPP\\DYJJ\\src\\App.vue`\n\n- \nE:WebProjectufappDYJJnode_modulesvue-style-loaderlibaddStylesClient.js\n`Used by 1 module(s), i. e.\nE:\\WebProject\\UFAPP\\DYJJ\\node_modules\\vue-style-loader\\index.js!E:\\WebProject\\UFAPP\\DYJJ\\node_modules\\css-loader\\index.js??ref--4-1!E:\\WebProject\\ufapp\\DYJJ\\node_modules\\.7.0.0@normalize.css\\normalize.css\n`\n\nE:WebProjectUFAPPDYJJnode_modulesvue-style-loaderlibaddStylesClient.js\n```\n`Used by 4 module(s), i. e.\nE:\\WebProject\\UFAPP\\DYJJ\\node_modules\\vue-style-loader\\index.js!E:\\WebProject\\UFAPP\\DYJJ\\node_modules\\css-loader\\index.js?{\"minimize\":false,\"sourceMap\":false}!E:\\WebProject\\UFAPP\\DYJJ\\node_modules\\vue-loader\\lib\\style-compiler\\index.js?{\"vue\":true,\"id\":\"data-v-f7c02f2c\",\"scoped\":false,\"hasInlineConfig\":false}!E:\\WebProject\\UFAPP\\DYJJ\\node_modules\\vue-loader\\lib\\selector.js?type=styles&index=0!E:\\WebProject\\UFAPP\\DYJJ\\src\\App.vue`\n```\nE:WebProjectufappDYJJnode_modulesvue-style-loaderlibaddStylesClient.js\n```\n`Used by 1 module(s), i. e.\nE:\\WebProject\\UFAPP\\DYJJ\\node_modules\\vue-style-loader\\index.js!E:\\WebProject\\UFAPP\\DYJJ\\node_modules\\css-loader\\index.js??ref--4-1!E:\\WebProject\\ufapp\\DYJJ\\node_modules\\.7.0.0@normalize.css\\normalize.css\n`\n```\nwarning in ./~/css-loader/lib/css-base.js\nThere are multiple modules with names that only differ in casing.\nThis can lead to unexpected behavior when compiling on a filesystem with other case-semantic.\nUse equal casing. Compare these module identifiers:\n- \nE:WebProjectUFAPPDYJJnode_modulescss-loaderlibcss-base.js\n`Used by 4 module(s), i. e.\nE:\\WebProject\\UFAPP\\DYJJ\\node_modules\\css-loader\\index.js?{\"minimize\":false,\"sourceMap\":false}!E:\\WebProject\\UFAPP\\DYJJ\\node_modules\\.2.0.0-rc.17@iview\\dist\\styles\\iview.css`\n\n- \nE:WebProjectufappDYJJnode_modulescss-loaderlibcss-base.js\n`Used by 1 module(s), i. e.\nE:\\WebProject\\ufapp\\DYJJ\\node_modules\\css-loader\\index.js?{\"minimize\":false,\"sourceMap\":false}!E:\\WebProject\\ufapp\\DYJJ\\node_modules\\.7.0.0@normalize.css\\normalize.css\n`\n\nE:WebProjectUFAPPDYJJnode_modulescss-loaderlibcss-base.js\n```\n`Used by 4 module(s), i. e.\nE:\\WebProject\\UFAPP\\DYJJ\\node_modules\\css-loader\\index.js?{\"minimize\":false,\"sourceMap\":false}!E:\\WebProject\\UFAPP\\DYJJ\\node_modules\\.2.0.0-rc.17@iview\\dist\\styles\\iview.css`\n```\nE:WebProjectufappDYJJnode_modulescss-loaderlibcss-base.js\n```\n`Used by 1 module(s), i. e.\nE:\\WebProject\\ufapp\\DYJJ\\node_modules\\css-loader\\index.js?{\"minimize\":false,\"sourceMap\":false}!E:\\WebProject\\ufapp\\DYJJ\\node_modules\\.7.0.0@normalize.css\\normalize.css\n`\n```\nwarning in ./~/vue-style-loader/lib/listToStyles.js\nThere are multiple modules with names that only differ in casing.\nThis can lead to unexpected behavior when compiling on a filesystem with other case-semantic.\nUse equal casing. Compare these module identifiers:\n- \nE:WebProjectUFAPPDYJJnode_modulesvue-style-loaderliblistToStyles.js\n`Used by 1 module(s), i. e.\nE:\\WebProject\\UFAPP\\DYJJ\\node_modules\\vue-style-loader\\lib\\addStylesClient.js`\n\n- \nE:WebProjectufappDYJJnode_modulesvue-style-loaderliblistToStyles.js\n`Used by 1 module(s), i. e.\nE:\\WebProject\\ufapp\\DYJJ\\node_modules\\vue-style-loader\\lib\\addStylesClient.js`\n\nE:WebProjectUFAPPDYJJnode_modulesvue-style-loaderliblistToStyles.js\n```\n`Used by 1 module(s), i. e.\nE:\\WebProject\\UFAPP\\DYJJ\\node_modules\\vue-style-loader\\lib\\addStylesClient.js`\n```\nE:WebProjectufappDYJJnode_modulesvue-style-loaderliblistToStyles.js\n```\n`Used by 1 module(s), i. e.\nE:\\WebProject\\ufapp\\DYJJ\\node_modules\\vue-style-loader\\lib\\addStylesClient.js`\n```",
"answer": "There are multiple modules with names that only differ in casing.\n有多个模块同名仅大小写不同\nThis can lead to unexpected behavior when compiling on a filesystem with other case-semantic.\n这可能导致在一些文件系统中产生不是预期的行为\nUse equal casing. \n使用唯一的写法\n猜测是因为你的文件名和引用不一致举个例文件名是App.js但是你引用的时候是写的app.js",
"type": "technical_qa"
},
{
"id": "segmentfault_428",
"question": "React 如何监听路由变化重新渲染组件\n```\n// route.js\n<Router>\n <Switch>\n <Route path=\"/\" component={NewsList} />\n <Route path=\"/new\" component={NewsList} />\n <Route path=\"/show\" component={NewsList} />\n <Route path=\"/ask\" component={NewsList} />\n <Route path=\"/jobs\" component={NewsList} />\n </Switch>\n</Router>\n```\n```\nclass NewsList extends Component {\n componentWillMount () {\n const type = this.props.location.pathname.replace('/', '') || 'top'\n this.props.dispatch(fetchListData(type))\n }\n \n render () {\n ...\n }\n}\n```\nreact: v15.6.1 \nreact-router: v4.1.1\n部分代码如上现在的问题是切换路由时组件并不会重新渲染。请问如何解决",
"answer": "为什么需要重新渲染组件?实质上,你想要的只是当路由变化,请求对应路由的数据而已。\n那么考虑一下React组件的生命周期钩子。第一次加载时:\n```\n\"constructor\"\n\"componentWillMount\"\n\"render\"\n\"componentDidMount\"\n```\n当组件的props发生改变时组件更新会调用如下的生命周期钩子\n```\n\"componentWillReceiveProps\"\n\"shouldComponentUpdate\"\n\"componentWillUpdate\"\n\"render\"\n\"componentDidUpdate\"\n```\n当路由变化时即组件的props发生了变化会调用componentWillReceiveProps等生命周期钩子\n### 那我们所需要做的只是: 当路由改变时根据路由也去请求一下数据就OK了于是乎:\n```\nclass NewsList extends Component {\n componentDidMount () {\n this.fetchData(this.props.location);\n }\n \n fetchData(location) {\n const type = location.pathname.replace('/', '') || 'top'\n this.props.dispatch(fetchListData(type))\n }\n\n componentWillReceiveProps(nextProps) {\n if (nextProps.location.pathname != this.props.location.pathname) {\n this.fetchData(nextProps.location);\n } \n }\n\n render () {\n ...\n }\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_429",
"question": "Vue.prototype的问题\n我用Vue在main.js中创建\n```\nVue.prototype.a = 1; 这个全局的变量后;\n```\n在组件a中使用\n```\nconsole.log(this.a); // => 1\nthis.a = 2;\n```\n然后从a跳到b后\n```\nconsole.log(this.a);\n```\n还是1不是2为什么 怎么修改这种全局的变量啊?还是说用其他的方法设置和修改全局的变量或对象?",
"answer": "这个不是全局变量,而是原型。\n因为每一次跳转到新的Vue页面都是一个独立的Vue实例实例中`this.a`从`Vue.prototype.a`而来所以仍然是1。\n如果需要设置全局变量在`main.js`中Vue实例化的代码里添加\n```\nnew Vue({\n ...\n data() {\n return {\n ...,\n a: 1\n ...\n };\n },\n ...\n});\n```\n其他所有组件中通过`$root.a`可访问此变量。",
"type": "technical_qa"
},
{
"id": "segmentfault_430",
"question": "数据库如何判断一条数据是否被修改?\nA ,B同时在一页面上访问一组数据, A针对其中一条数据做了修改. B的页面没有刷新,所以B看见的信息是在A修改之前的,这时候B也要修改这条数据. 我如何做才能提醒B,这条数据已经被修改过. \n看到一个办法,修改数据之前根据这条数据最后修改的时间先将这条数据查出来(select * from xxx where updatetime = xxx and id= xxx),如果查不到说明修改过,查到了说明没有修改.\n我想问问有没有更好的办法?",
"answer": "我记得hibernate中乐观锁用的是版本号字段实现的每次更新成功后时候版本号字段的值加1\n在更新前先检查数据库中的版本号和页面中保存的版本号是否相同如果版本号变大提示用户在编辑期间已有其他用户修改了数据。\n当然也可以用悲观锁进入页面的时候使用的select ... for update锁定记录这时候其他用户就不能同时编辑锁定的记录了。",
"type": "technical_qa"
},
{
"id": "segmentfault_431",
"question": "关于NumPy数组操作的问题\n```\n['000001_2017-03-17.csv', '000001_2017-03-20.csv',\n '000002_2017-03-21.csv', '000002_2017-03-22.csv',\n '000003_2017-03-23.csv', '000004_2017-03-24.csv']\n```\nnumpy数组总共有几个万个元素。现在想保留每个元素前面的编号000001之类的并且去掉重复只保留唯一的一个编号。结果应该是`['000001','000002','000003','000004']`\n除了用for语句实现外有没有更高效的办法",
"answer": "写个NumPy的吧~\npython3\n```\n>>> import numpy as np\n>>> a = np.array(['000001_2017-03-17.csv', '000001_2017-03-20.csv',\n '000002_2017-03-21.csv', '000002_2017-03-22.csv',\n '000003_2017-03-23.csv', '000004_2017-03-24.csv'])\n\n>>> b = np.unique(np.fromiter(map(lambda x:x.split('_')[0],a),'|S6'))\n>>> b\narray([b'000001', b'000002', b'000003', b'000004'], \n dtype='|S6')\n```\n还可以这样写`np.frompyfunc`\n`'|S6'`是以6个字节存储字符串\n`'<U6'`是以6个`小端序Unicode字符`存储字符串\n```\n>>> b = np.array(np.unique(np.frompyfunc(lambda x:x[:6],1,1)(a)),dtype='<U6')\n>>> b\narray(['000001', '000002', '000003', '000004'], \n dtype='<U6')\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_432",
"question": "webpack rebuild 速度太慢\n工程的开发环境使用`express`+`webpack-dev-middleware`+`webpack-hot-middleware`,热加载+网页的错误提示开发起来很爽。\n之前webpack每次启动的build速度都比较慢后来参照这篇文章做了优化\n开发工具心得如何 10 倍提高你的 Webpack 构建效率\n加上dll plugin和happypack等之后构建速度一下子由120s缩短到30s以内随着工程越来越大12万业务代码rebuild速度越来越慢现在一次rebuild速度大概得12s左右实在是不能忍受。\n哪位有这方面优化经验的还请不吝赐教。",
"answer": "There are quite a few conditions that can contribute to slowness. From personal experience, I have found that the best way about trying to solve it, is to Measure, Profile, and Diagnose the issue first. \nWhen you run webpack, instead run it with node and the following flags: \n`node --inspect --debug-brk ./node_modules/webpack/bin/webpack.js`\nThen open up Chrome Browser and goto `chrome://inspect` and click 'Open Dedicated Node Debugger'. \nThis will give you debug, breakpoint, and profiling features that you can use to measure and analyze what functions and areas of webpack are taking the longest. Once you have found that out, you can start to determine exactly what is causing the issue. Here is a great post (although a little outdated for the instructions), that shows how these steps might look like\nIf this doesn't help, then you can try other webpack build features like DllPlugin, using `devtool: 'eval-source-map'`, look for specific loaders that have caching features, as well as our new cache-loader.",
"type": "technical_qa"
},
{
"id": "segmentfault_433",
"question": "golang的slice问题\n```\ns1 := []int{1, 2, 3, 4}\ns2 := []int{-1, -2, -3}\n\nfmt.Println(append(s1[:1], s2...))\n\nfmt.Println(s1)\n```\n打印的结果\n```\n[1 -1 -2 -3]\n[1 -1 -2 -3]\n\n```\n弄不明白的是为什么s1的值也变了",
"answer": "因为append函数并不保障slice是否被修改也就是说append可能会修改slice也可能不修改所以使用append有两个原则\nappend函数调用后应该使用返回值作为结果。\n1. append函数调用后不应该再使用实参传入的slice。\n2. 所以使用append函数一般都是`s = append(s,elem1)`这种用法也就是把结果重新赋值给原来的slice。\n|append函数之所以有这个表现是因为slice的底层存储依赖于底层数组underlying array用你的例子来给你说明一下\n你的s1初始化的值是`[]int{1, 2, 3, 4}`它的len和cap都是4所以它的底层数组是一个长度为4的数组`[4]int{1,2,3,4}`。\n基于slice的特点`s1[:1]`和s1是共享底层数组的所以`s1[:1]`这个slice的改变是会影响到underlying array的。\n\n> If it has sufficient capacity, the destination is resliced to accommodate the new elements. If it does not, a new underlying array will be allocated.\n\nappend函数在填充elem1,elem2的时候会先判断slice的cap是否能容纳所有追加的值这个计算方式是从slice的尾部计算的在你的例子里slice的尾部是第一个元素后面的容量恰好可以满足3个元素所以它不会申请新的底层数组而会直接使用原有的底层数组作为存储这也就把原本的底层数组改成了[1 -1 -2 -3],由于s1的存储依赖于这个底层数组自然也就变成了`[1 -1 -2 -3]`。\n\n如果把你的例子改成`append(s1[:1],1, s2...)`,或者改成`append(s1[1:2], s2...)`,你就会发现s1没有被改变这是因为容量不能容纳所有追加元素append会申请一个新的底层数组用来存储也会返回一个新的slice这不会影响到原本的底层数组也就不会影响到原本的slice。\n\n所以使用`s = append(s,elem1)`是一个好习惯,尽量使用这个用法。",
"type": "technical_qa"
},
{
"id": "segmentfault_434",
"question": "react-router中嵌套的子组件拿location对象的问题\n比如说一个页面有个modal组件modal组件里面的内容写在子组件里面(ModalDetail),在这个组件里面拿不到this.props.location求解答除了从父组件传进去和通过window对象拿还有什么方法",
"answer": "react-router v4之前的版本有一个叫做`withRouter`的高阶组件。你在定义自己的modal组件时包一层即可。\nv4版本暂时没有用过有没有改动不清楚\n```\nimport React from 'react'\nimport PropTypes from 'prop-types'\nimport { withRouter } from 'react-router'\n\n// A simple component that shows the pathname of the current location\nclass ShowTheLocation extends React.Component {\n static propTypes = {\n match: PropTypes.object.isRequired,\n location: PropTypes.object.isRequired,\n history: PropTypes.object.isRequired\n }\n\n render() {\n const { match, location, history } = this.props\n\n return (\n <div>You are now at {location.pathname}</div>\n )\n }\n}\n\n// Create a new component that is \"connected\" (to borrow redux\n// terminology) to the router.\nexport default withRouter(ShowTheLocation)\n```\n包一层withRouter之后就可以访问到你想要的属性了你还可以进一步学习看看里面都有些什么。",
"type": "technical_qa"
},
{
"id": "segmentfault_435",
"question": "dockerfile 与 docker-compose的区别是什么?\ndocker-compose是编排镜像, 那么docker-compose是不是可以做Dockerfile的能做的事?",
"answer": "我所理解的docker-compose是编排容器的。例如你有一个php镜像一个mysql镜像一个nginx镜像。如果没有docker-compose那么每次启动的时候你需要敲各个容器的启动参数环境变量容器命名指定不同容器的链接参数等等一系列的操作相当繁琐。而用了docker-composer之后你就可以把这些命令一次性写在docker-composer.yml文件中以后每次启动这一整个环境含3个容器的时候你只要敲一个docker-composer up命令就ok了。\n而dockerfile的作用是从无到有的构建镜像。\n两个完全不是一码事",
"type": "technical_qa"
},
{
"id": "segmentfault_436",
"question": "php 的 opcache 和最近的 php jit 有什么区别?\nopcache 是用于缓存 zend 引擎编译生成的 opcode下次就无需编译。 \n最近听说了 php jit,看了一下 jit 的概念,描述是这样的:\nJIT编译just-in-time compilation即即时编译狭义指某段代码即将第一次被执行时进行编译而后则不用编译直接执行它为动态编译的一种特例。\n那 php 的 jit 和 opcache 有什么区别呢?",
"answer": "`源代码(人认识)->字节码(解释器认识)->机器码(硬件认识)`\n来看下PHP的执行流程假设有个a.php文件不启用opacache的流程如下\n`a.php->经过zend编译->opcode->PHP解释器->机器码`\n启用opacache的流程如下\n`a.php->查找opacache缓存如果没有则进行zend编译为opcode并缓存->opacode->PHP解释器->机器码`\n启用jit的流程如下\n`a.php->编译->机器码`\n以后都只执行机器码不编译效率上高了很多",
"type": "technical_qa"
},
{
"id": "segmentfault_437",
"question": "python redis 列表插入 速度太慢\n```\npool = redis.ConnectionPool(host=host, port=port)\nclient = redis.StrictRedis(connection_pool=pool)\n\nfor i in range(10000):\n for j in range(30):\n client.lpush(IDLE_TASKS, json.dumps(args))\n \n```\n这种执行效率低的可怕。\n需要等几十秒才能插入完成。\n请问有没更高效率的处理手法\nargs 只是以一个元组内容随意(1,2,\"3\")之类",
"answer": "用 Redis 的 Pipeline 先在循环内生成数据,最后一次性插入\n```\n>>> p = r.pipeline() --创建一个管道\n>>> p.set('hello','redis')\n>>> p.sadd('faz','baz')\n>>> p.incr('num')\n>>> p.execute() -- 执行管道内命令\n[True, 1, 1]\n\n>>> r.get('hello')\n'redis'\n```\n```\n\npool = redis.ConnectionPool(host=host, port=port)\nclient = redis.StrictRedis(connection_pool=pool)\n\np = client.pipeline()\nfor i in range(10000):\n for j in range(30):\n p.lpush(IDLE_TASKS, json.dumps(args))\np.execute() \n```\n使用管道Redis 会将命令暂时存储,当遇到 `execute()` 时才会执行,所以上面代码只需要和 Redis 服务器通信一次即可将数据全部插入",
"type": "technical_qa"
},
{
"id": "segmentfault_438",
"question": "如何向localStorage上的数组push数据\n我想做的一个功能是向localstorage上设置一个空数组每次点击就push当前点击的数据到localstorage的数组中但是localstorage不允许push我试过深拷贝localstorage的数组出来再push到深拷贝的数组中在设置localstorage的数组为深拷贝的数组但是也没尝试出来请大神支招",
"answer": "localStorage只能存储String要用Json对象转化下\n```\nvar arrayObject = [];\narrayObject.push('a','b','c');\nlocalStorage.setItem(\"array\",JSON.stringify(arrayObject));\nvar arrayObjectLocal = JSON.parse(localStorage.getItem(\"array\"));\narrayObjectLocal.push('d','e','f');\nfor (i = 0; i < arrayObjectLocal.length; i++) { \n console.log(arrayObjectLocal[i]);\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_439",
"question": "Vue v-for判断是否为第4列然后加个横线或者第4行才显示这一个<li>\n```\n<ul id=\"right-notice\">\n <li v-for=\"site in sites\">\n <span class='time'>{{site.ntime}}</span>\n <a title='{{site.qtitle}}'>{{site.ntitle}}</a>\n </li>\n // 思路一:<li 如果是第4行在这里加一个什么显示属性></li>\n // 思路二如果是第4行在这里插入一个`<hr>`是否可行\n</ul>\n```\n初学vue,翻了好久,没有解决问题,特来求助。望前辈们指点",
"answer": "```\n<ul id=\"right-notice\">\n <li v-for=\"(site, index) in sites\">\n <span class='time'>{{site.ntime}}</span>\n <a title='{{site.qtitle}}'>{{site.ntitle}}</a>\n <hr v-if=\"!((index + 1) % 4)\" />\n </li>\n</ul>\n```\n\n1. 其中,用`(site, index) in sites`代替`site in sites``index`为获取到的元素顺序。\n2. 这里用到了`v-if`。其中对于index值为3第四项,7第八项11第十二项... 4的倍数项需要显示`hr`,对于这些值,`(index + 1) % 4`为0所以`!((index + 1) % 4)`为`true`,显示`hr`。【这里`index`按顺序从0开始计数所以`index + 1`为表示当前site在sites数组中是第几个然后`(index + 1) % 4`每满4顺序数除以4余数都为0】\n\n添加class的方法假设class名叫`underline`\n```\n<ul id=\"right-notice\">\n <li v-for=\"(site, index) in sites\" :class=\"{underline: !((index + 1) % 4)}\">\n <span class='time'>{{site.ntime}}</span>\n <a title='{{site.qtitle}}'>{{site.ntitle}}</a>\n </li>\n</ul>\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_440",
"question": "vue-router登录成功后回到登录前页面是如何实现的\n例如复制了一个链接https://segmentfault.com/ask/...\n到浏览器粘贴回车 会进入登录页面 登录成功后想再回到https://segmentfault.com/ask/...这个页面",
"answer": "大概思路:\n1.当你想进入 `http://localhost:8080/user` (该页面需要登录授权)\n2.检查是否登录如果没有登录跳转到登录页需要将上一页的path(/user)作为query存到login页地址中`http://localhost:8080/login?redirect=%2Fuser`\n```\nif (!isLogin()) {\n this.$router.push({\n path: '/login',\n query: {redirect: 'your path'} // 如果你使用钩子函数your path 可以替换成to.fullPath\n })\n}\n```\n3.登录成功后获取query中的redirect属性然后跳转到这个地址\n```\nthis.$router.push(this.$route.query.redirect || '/')\n```\n这是一种方式你也可以用其他方式存储上一页的地址",
"type": "technical_qa"
},
{
"id": "segmentfault_441",
"question": "js中向下取整\n在js中以前向下取整都是使用Math.floor方法现在有看到这样的用法或运算\n interval = interval | 0\n为什么这样就可以向下取整了这种用法和Math.floor比较有什么好处",
"answer": "注意,`|` 不是逻辑或,而是按位或 OR。\n一些小区别。比如 `Math.floor(NaN)` 还是返回 `NaN`。但 `NaN | 0` 返回 0。\n再比如 `Math.floor(Infinity)` 返回 `Infinity`,但 `Infinity | 0` 返回 0",
"type": "technical_qa"
},
{
"id": "segmentfault_442",
"question": "vue2.0如何设置全局变量\n比如资源服务器的host后台api的host微信第三方的host。这些host不能挨个去代码里面写吧。\n其实我就是想知道vue如何设置全局变量。总感觉放到windowlocalstoragesessionstorage不太正规。",
"answer": "webpack 有global关键字\n比如在一个a.js文件中定义全局变量\n```\nglobal.COURSES = 'xxxxx'\n\n```\n在入口的main.js\n```\nimport './a'\n\n```\n就可以别的js不需要import也能用到COURSES",
"type": "technical_qa"
},
{
"id": "segmentfault_443",
"question": "为什么Github要把代码合并请求称为pull request而不是push request\nhttps://stackoverflow.com/que...\n我看了这里面的解释感觉还是不够有说服力啊\n我的理解是我做了一些修改我请求把我的修改push到你的仓库然后你review一下我的代码如果没问题就接受请求merge这样的话叫做push request岂不是更合适因为这个操作是我主动发起的。pull是仓库主向我fork的仓库发起的操作那么pull request这种操作应该是要上游仓库主来向我发起啊而不是我主动让上游仓库主来pull我仓库中的代码。",
"answer": "是这样的,这个应该分开来解释。\n这个pull指的是权限主体的操作。你提交了代码但是你没有操作上游repo的权限你需要上游repo的主人review你的代码然后把你的代码修改pull到他的repo中去这是对于pull的解释。\n而request则指的是发起主体的操作。也就是说上游repo的主人虽然有repo的控制权可以把你的代码更改pull到他自己的repo里但是他不会主动去pull。而是需要你发起主体向上游repo的主人提交申请也就是request上游repo的主人才会去响应你的request也就是执行你所说的review和pull的过程。\n所以pull request的理解方法是一个通知上游repo所有者拉取代码(pull)的请求(request)。\n在英语中request一般指的是提交一个申请需要对方对申请给予答复的。而request之前的修饰词则是答复方的动作当然中文中也是一样。比如“入团申请”你提交申请之后需要对方允许你入团你才算是团员。所以入团的动作不是你主动做的而是由审核的人把你的名字加上去才算“入团”。同理“pull request”中request是你提交的而pull则是对方做的事情。",
"type": "technical_qa"
},
{
"id": "segmentfault_444",
"question": "vuejs页面加载完成后执行函数\nmodule.exports = {\n```\ndata: function(){\n return {\n memberQrcodeState: false\n }\n},\ncomponents: {memberQrcode},\ncreated: function(){\n},\nbeforeRouteEnter: function(to, from, next) {\n // 在渲染该组件的对应路由被 confirm 前调用\n // 不!能!获取组件实例 `this`\n // 因为当钩子执行前,组件实例还没被创建\n //$e.target.src= require(\"../imgs/test/232.jpg\")\n next();\n return true;\n},\nmethods: {\n \n},\nbeforeRouteLeave: function(to, from, next) {\n // 导航离开该组件的对应路由时调用\n // 可以访问组件实例 `this`\n next();\n}\n```\n};\n在这基础上加一个页面加载完成后执行的函数我是小白第二天接触vuejs希望大神指点一二",
"answer": "```\nmounted(){\n this.init()\n},\nmethods:{\n init(){\n console.log('hello,world')\n }\n}\n```\n谨供参考~",
"type": "technical_qa"
},
{
"id": "segmentfault_445",
"question": "怎么把自己fork别人的仓库中的代码更新至最新版本\n我在Github上fork了别人一个项目然后修改之后按照正常流程提交PR并且对方merged了。\n我现在又需要对该项目进行贡献代码但是发现对方的项目仓库也有别人更新了新代码上去我怎么让我自己仓库中fork的这个项目代码也同步到和对方仓库一样的最新版本代码然后我再进行贡献",
"answer": "首先 把别人的仓库添加到你的上游远程,通常命名为 upstream。操作一次就可以了。\n```\ngit remote add upstream 原作者仓库地址\n```\n此时再用 `git remote -v` 就可以看到一个origin是你的另外一个upstream是原作者的。\n其次 更新代码\n使用`git fetch upstream` 拉去原作者的仓库更新。\n使用`git checkout master` 切换到自己的`master`\n使用 `git merge upstream/master`, merge或者rebase到你的master",
"type": "technical_qa"
},
{
"id": "segmentfault_446",
"question": "JSON.parse(JSON.stringify(data))\n问下JSON.parse(JSON.stringify(data))是什么情况下要用",
"answer": "一般用来深拷贝一个json对象吧还可以用来去除值不具有JSON 表示形式数字、字符串、逻辑值、数组、对象、null的属性也就是说像undefined和function这样的属性值。\n```\na: {\n age: 1,\n name: undefined,\n time: () => {...}\n}\n变成\nb: {\n age: 1\n}\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_447",
"question": "用户余额和收入支出mysql表设计和实现方案\n因为第一次做相关业务所以经验不足想来取点经。\n1.用户余额表除了用户id和余额还应该有哪些字段\n2.收入表和支出表是分开好还是合并?\n3.比如注册送100优惠券这种场景。注册成功后给余额字段加100给明细表添加一条记录这2个步骤放在一个事务中还是明细表用消息队列处理等其他解决方案。",
"answer": "1.用户ID余额开始时间创建时间最后交易收入支出改变时间收入总额支出总额看情况决定是否冗余冗余为了避免每次统计都要查库\n2.收入表和支出表看情况。如果收入来源和支出方式都有多种适合分开比如说收入1.打赏2充值3转账支出1购买业务2充值会员 3转赠等等\n3.放在一起直接事务也可,消息队列也行,只要涉及金钱,打好日志即可。因为送钱和明细表操作都不是耗时间操作。\n4.金钱计算尽量避开浮点数如1元应该存成100分",
"type": "technical_qa"
},
{
"id": "segmentfault_448",
"question": "如何把数组对象相同的key值合并并且把对应的id放到一个数组\n例如旧数据\nvar old = [\n```\n{\n id: 1,\n name: 'css',\n type: 'html'\n},\n{\n id: 2,\n name: 'css',\n type: 'html'\n},\n {\n id: 3,\n name: 'javacript',\n type: 'code'\n},\n{\n id: 4,\n name: 'javacript',\n type: 'code'\n}\n```\n]\n想得到的 var new = [\n```\n{\n id: [1,2],\n name: 'css',\n type: 'html'\n},\n {\n id: [3,4],\n name: 'javacript',\n type: 'code'\n},\n```\n]\n希望把相同name的对象合并并且把对应的id放到一个数组",
"answer": "```\nvar hash = {};\nvar i = 0;\nvar res = [];\nold.forEach(function(item) {\n var name = item.name;\n hash[name] ? res[hash[name] - 1].id.push(item.id) : hash[name] = ++i && res.push({\n id: [item.id],\n name: name,\n type: item.type\n })\n\n});\nconsole.log(JSON.stringify(res))\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_449",
"question": "github怎么提交回退旧版本代码并更改后的文件到主分支上\n可能说的不是很明白就是我代码写着写着发现我已经不想这么弄了用`git reset --hard <版本号>`退回到之前的某个版本重新写,这样当我当我写完之后,想在提交到远程仓库,它就会报错\n```\nTo https://github.com/zifenggao/wenda.git\n ! [rejected] master -> master (non-fast-forward)\nerror: failed to push some refs to 'https://github.com/zifenggao/wenda.git'\nhint: Updates were rejected because the tip of your current branch is behind\nhint: its remote counterpart. Integrate the remote changes (e.g.\nhint: 'git pull ...') before pushing again.\nhint: See the 'Note about fast-forwards' in 'git push --help' for details.\n```\n说我版本是之前的版本要我合并后再提交那我应该怎么弄能了几遍都没搞懂。",
"answer": "首先,根据你的描述,既然你用到了 `git reset --hard`,那就可以推断出你已经 `add` 和 `commit` 过了。\n其次根据报错可以推断出你已经 `push` 过了(这个推断基于只有你一个人拥有 master branch 的更改权限。\n那么当你执行 `git reset --hard` 之后,历史纪录是不能跟远程的记录直接合并的。因此才会有这个报错。\n举个例子远程是 `A -> B -> C -> D`,你 `git reset --hard` 之后是 `A -> B`。这时候除非远程那边抹掉 `C` 和 `D`,否则是不能合并的。\n因此这时候你应该使用 `git push origin master --force` 来强行覆盖远程记录。\n请不要根据提示使用 `git pull`。否则,你的本地又会变成 `A -> B -> C -> D`。因为 `git pull` 相当于 `git fetch` + `git merge`\n以下内容基于上面的例子远程是 `A -> B -> C -> D`,你想回滚到 B 那个状态)\n另外对于 `git revert`。其实,`git reset --hard` 和 `git revert` 都可以实现“回滚代码”。但区别在于:\n`git revert` 会把你的本地变成 `A -> B -> C -> D -> E`。其中,`E` 干的事儿是删除 `C` 和 `D`。这样做的好处在于,你 `git push origin master` 就不会有上面的报错了。但,历史线上还是会保留 `C` 和 `D` 这两个 commit。如果使用这个命令记得要 `add` 然后 `commit`。\n`git reset --hard` 会直接删掉 `C` 和 `D`,形成 `A -> B` 这样的结果。好处在于更直接更彻底。缺点在于,首先要通过 `git push origin master --force` 去强行更改。其次,一旦你后悔了,除非根据本地的 `reflog` 直接恢复 HEAD 指针,此外没有其他办法。\n用哪个都是没错的请根据自己的需要来选择。",
"type": "technical_qa"
},
{
"id": "segmentfault_450",
"question": "输入一段不减的整数如11111223333怎么快速计算重复次数最多的那个数\n输入\n一段不减整数11111223333\n输出\n出现次数最多的那个数字本例中1的出现次数最多输出1\n输入的数字具有以下规律\n1.数字为正整数不一定从1开始\n2.如果增长则increment = 1\n3.整数的总量不会超过1W但是事先无法知道总共会输入多少整数",
"answer": "这题不用对所有数字计数,那样很慢。\n如果增长则increment = 1\n把数字当作字符串来处理只要找出所有增长的点的位置就可以了然后把相邻的点的位置相减即可得到长度。\n因为不一定是从1开始所有可能的增长的点为\"12\"\"23\"\"34\",。。。\"78\"\"89\"\n例如\n将11111223333转为字符串查找增长点\n结果12-位置423-位置6\n增长点补正加112-位置523-位置7\n初始位置补0末尾补字符串长度len,得到\n[0,5,7,11]\n取相邻两点之差\n[5,2,4]\n所以出现次数最多的是第一个元素5次\n除此之外还有不需要遍历的算法\n由于increment = 1所以看开头和结尾2个数即可算出出现数字有几种\n如11111223333开头为1结尾为3则出现的数为1到3共3种\n那么考虑出现N种数的情况\nN=1就不用说了等于白送答案。\n先从简单的N=2说起吧因为有些细节在N=2的情况说了后面N>2的情况类似的细节就省略了。\n2分采样\n若len为奇数取len/2处的数这个数就是出现次数最多的数。\n若len为偶数len/2处是间隙所以取该间隙前后2个数这2个数相同的话答案就是这个数如果不同的话答案是这两个数出现次数一样并列最多。\nN分采样取0、len/N、2len/N、...、N-1len/N、len处的N+1个点由于间隙的情况太复杂这里省略请参考N=2的处理方法\n然后统计这N+1个点里面出现次数最多的数把出现次数最多的数叫做M1出现第二多的叫做M2依次类推\n若 M1的次数 - M2次数 大于等于2则答案为M1\n若 M1的次数 - M2次数 小于2那么\n2N分采样(若2N>len,则len分采样)取len/2N、3len/2N、5len/2N、。。。。、处的N个点与前面N分法时候取的N+1个点组合重新求M1M2。。。。\n若 M1的次数 - M2次数 大于等于2则答案为M1\n若 M1的次数 - M2次数 小于2\n则4N分采样(若4N>len,则len分采样)\n。。。。依次类推8N16N。。。。\n直至找到 M1的次数 - M2次数 大于等于2为止。其中若变为len分采样结束条件不需要M1的次数 - M2次数大于等于2M1就是答案。\n#### 小结\n这个算法大部分时候是比较快的最差的情况是N个数的各个次数都相差很小或者都相同那就会进入最后的len分采样等于遍历那还不如一开始就直接遍历比较快。\n但是数据的分布越是不均匀这个算法就越快。\n#### 杂谈\n写完这个算法之后我觉得有似曾相识的感觉大家了解通信原理的有没有一样的感觉 \n如果把这段不减整数映射到频域那么这就是递增阶梯的方波问题就是确定其最长一段方波如果这个方波太长数据量太大我们可以对其特征点采样来压缩数据根据奈奎斯特采样定理或者叫香农采样定理\n当采样频率fs.max大于信号中最高频率fmax的2倍时(fs.max>2fmax),采样之后的数字信号完整地保留了原始信号中的信息。\n上文的2N分采样与此正好相似是不是很有趣",
"type": "technical_qa"
},
{
"id": "segmentfault_451",
"question": "assets 和static的区别\n使用 vue-cli 搭建的项目中有 assets 和 static 文件夹,一直不懂两者的区别,看到网上的说法太模糊,希望有位大神可以举例说明两者的区别。",
"answer": "请参考 vue-cli 的 webpack 模板的文档 - Handing Static Assets作者知道会有人有这个疑惑所以作了详情的解释\nYou will notice in the project structure we have two directories for static assets: `src/assets` and `static/`. What is the difference between them?\n简单翻译一下。\n## Webpacked Assets\n为了回答这个问题我们首先需要了解Webpack如何处理静态资产。在 `*.vue` 组件中所有模板和CSS都会被 `vue-html-loader` 及 `css-loader` 解析并查找资源URL。例如在 `<img src=\"./logo.png\">`\n 和 `background: url(./logo.png)` 中,`\"./logo.png\"` 是相对的资源路径将由Webpack解析为模块依赖。\n因为 `logo.png` 不是 JavaScript当被视为模块依赖时需要使用 `url-loader` 和 `file-loader`\n 处理它。vue-cli 的 webpack 脚手架已经配置了这些 loader因此可以使用相对/模块路径。\n由于这些资源可能在构建过程中被内联/复制/重命名,所以它们基本上是源代码的一部分。这就是为什么建议将\n Webpack 处理的静态资源放在 `/src` 目录中和其它源文件放一起的原因。事实上,甚至不必把它们全部放在 `/src/assets`:可以用`模块/组件`的组织方式来使用它们。例如,可以在每个放置组件的目录中存放静态资源。\n## \"Real\" Static Assets\n相比之下`static/` 目录下的文件并不会被 Webpack 处理:它们会直接被复制到最终目录(默认是`dist/static`)下。必须使用绝对路径引用这些文件,这是通过在 `config.js` 文件中的 `build.assetsPublicPath` 和 `build.assetsSubDirectory` 连接来确定的。\n任何放在 `static/` 中文件需要以绝对路径的形式引用:`/static/[filename]`。如果更改 `assetSubDirectory` 的值为 `assets`,那么路径需改为 `/assets/[filename]`。",
"type": "technical_qa"
},
{
"id": "segmentfault_452",
"question": "请问如何在html中输出字符串中的换行符\n我在后台获取了一段字符串输出到前台的<p>标签中,但是字符串中有换行符'n',我想同样输出换行的效果。请问应该如何处理这段字符串呢?我把'n'替换成了<br/>还是不行,原样输出了。\n谢谢大家",
"answer": "有两中方式,一是设置 `white-space: pre;`,空白会被浏览器保留。或者使用\n```\n<pre>\n 我是换行字\n\n 符串\n</pre>\n\n```\npre 元素可定义预格式化的文本。被包围在 pre 元素中的文本通常会保留空格和换行符。",
"type": "technical_qa"
},
{
"id": "segmentfault_453",
"question": "python 如何将字符串转换成列表\n如何将字符串如`a = \"我是中国人\"`,转换成列表`li =[\"我\",\"是\",\"中\",\"国\",\"人\"]`\n```\na = \"我是一个中国人\"\nli = list(a)\nprint li\n```\n输出却是\n```\n['\\xe6', '\\x88', '\\x91', '\\xe6', '\\x98', '\\xaf', '\\xe4', '\\xb8', '\\x80', '\\xe4', '\\xb8', '\\xaa', '\\xe4', '\\xb8', '\\xad', '\\xe5', '\\x9b', '\\xbd', '\\xe4', '\\xba', '\\xba']\n```\n我用JavaScript很简单的就实现了\n```\nvar a = \"我是中国人\"\nli = a.split(\"\")\nconsole.log(li) // >>>[\"我\",\"是\",\"中\",\"国\",\"人\"]\n```\n不知道python应该如何实现",
"answer": "可以先将字符串解编码成`unicode`, 再用`list`\n```\n# 第一种:\n>>> a = u\"我是中国人\"\n>>> s = list(a)\n>>> print s\n[u'\\u6211', u'\\u662f', u'\\u4e2d', u'\\u56fd', u'\\u4eba']\n>>> print s[1]\n是\n\n# 第二种\n>>> a = \"我是中国人\"\n>>> s = a.decode('utf8')\n>>> s = list(a.decode('utf8'))\n>>> s\n[u'\\u6211', u'\\u662f', u'\\u4e2d', u'\\u56fd', u'\\u4eba']\n>>> print s[1]\n是\n```",
"type": "technical_qa"
},
{
"id": "segmentfault_454",
"question": "为什么说promise不能取消是一个缺点\n什么场景下我需要取消一个promise\n我不理解的地方\nhttp是无状态的那取消是不是意味着新的请求\n还是说取消仅是本地取消不处理之前请求的结果",
"answer": "Promise 的设计就是一个状态机pending 到 resolve / reject 的状态变换是单向且唯一的,没有所谓的 cancel 状态。cancel 的加入会带来更多的状态问题,并不适合 Promise 这一模式来处理这类场景下RxJS 这类 FRP 的方案应该更为适合)。\ncancel 会带来什么状态问题呢?拿电商的退款来举例子。你买了一个东西(开始一个 pending 的 promise然后东西还没收到还没 resolve你后悔了点击了退款把状态改为 cancel但这时退款流程也不能立刻生效需要审核cancel 后不能立刻 reject那这时候你发工资了又不想退款了又点了【取消退款】这时候又是一个异步的状态更改把 cancel 再 cancel 掉),而【取消退款】也是异步的,你还能取消【取消退款】的操作(把 cancel 在 cancel 掉前再 cancel 掉?)别忘了,这时候每一步状态变化还都可以对应到 resolve 和 reject 呢。好的同学们,接下来请画出流程的状态变化图,并编码实现这个支持 cancel 的 promise?\n这是一道送命题啊。",
"type": "technical_qa"
},
{
"id": "segmentfault_455",
"question": "api 使用session替代token 的利弊在哪?\n补充几种常用的验证机制\n 最近写app的api使用laravel 框架的session替代了传统的存贮到数据库的token作为校验登录用户的方法\n以下是我们目前的做法\n登录后后台生产session会往返回信息head头里写一个set_cookie\nios和安卓 会从head头里得到拿到这个cookie的东西\n然后再请求需要登录的地方的时候ios和安卓会把cookie放到head头里让框架完成自我的校验\nps:\n有人说不安全\n有人说不好管理\n有人说性能问题\n有谁具体研究过请帮我分析分析其利弊\n我个人认为的观点\n说session不安全的感觉有点牵强假如真的一点不安全的话那网站也就完全被暴露了而且laravel的session也是有自己加密的方式不是直接暴露的\n有人说不好管理放在redis里了我不太知道不好管理在哪里。\n性能问题session可以存贮的位置有很多mysql文件redis我觉得性能也不是问题。我也不知其弊端在哪里\n有谁具体研究过请帮我分析分析其利弊\n也请大家有想法的各抒己见我们一起讨论下",
"answer": "在存储过等同的情况下在只是简单运用上我只能说session与token没有本质的区别二者不都是一串被加密过的字符串拿他来做校验都一样。\n以上是因为你把token拿来当作用户是不是当事人做这么一个简单的校验的情况下。\n当然如果我们抛开一些比较极端的操作token比session也有很大的区别\n- token可以存在任何位置cookie、local storage\n- token比session更容易跨域。\n- CORS预检查时token比较更简单。\n- token有更多的控制权比如当token过期时你可以拿通过刷新token让用户一直保持有效登录。\n\ntoken可以存在任何位置cookie、local storage\ntoken比session更容易跨域。\nCORS预检查时token比较更简单。\ntoken有更多的控制权比如当token过期时你可以拿通过刷新token让用户一直保持有效登录。\n等……其实如果你只是单纯拿着token做一下自己网站内用户登录检验的话是无太多区别的。\n但假如token指的是OAuth Token提供认证和授权这类机制的话那么就可以把session甩开N条街了甚至是已经完全是两种不同的概念。\n假设有这么一个场景你们用户在你们网站产生的订单而另一家公司是专业ERP公司而你的用户希望他的订单同时授权给这家ERP公司使用的情况下难道你希望用户拿在你家网站的用户名和密码给这家ERP公司吗\n这时候OAuth Token就有意义了OAuth Token的授权大概是这样的\n- ERP需要调用我们提供的登录界面。\n- 用户输入用户名和密码后我们再向ERP发送一个TOKEN。\n- ERP拿TOKEN换数据。\n\nERP需要调用我们提供的登录界面。\n用户输入用户名和密码后我们再向ERP发送一个TOKEN。\nERP拿TOKEN换数据。\n总之如果你只是在自己网站内部上使用二者没有什么太多区别。而如果你的API是在不同终端上使用token会更方便。",
"type": "technical_qa"
},
{
"id": "segmentfault_456",
"question": "正则表达式如何匹配重复出现的字符串\n比如说`aaabccc11fdsa`这个字符串我要把aaaccc和11这种会重复两次以上的字符串匹配出来该怎么办如果正则表达式做不到的话有其他什么PHPPython内置函数可以做到吗内置函数也没有的话只能手写算法了吗",
"answer": "JS代码\n```\nvar s = 'aaabccc11fdsa';\nvar re = /(.)\\1+/g;\n\nconsole.log(s.match(re));\n```\n其中正则表达式中`.`表示任意字符,`\\1`表示第一个被匹配到的分组,`+`表示匹配前一个字符一次或一次以上。",
"type": "technical_qa"
},
{
"id": "segmentfault_457",
"question": "vuex 中的 store 和 $store 的区别\n```\n<router-link to=\"/login\">{{ $store.state.userName }}</router-link>\n<router-link to=\"/login\">{{ store.state.userName }}</router-link>\n<router-link to=\"/login\">{{ this.store.state.userName }}</router-link>\n<router-link to=\"/login\">{{ this.$store.state.userName }}</router-link>\n```\n一直搞不清楚 vuex 中 `store` 和 `$store` 的区别,也不知道什么时候前面应该加`this`,求大神告知。\n—— thanks in advance",
"answer": "`$store` 是挂载在 Vue 实例上的即Vue.prototype而组件也其实是一个Vue实例在组件中可使用 `this` 访问原型上的属性template 拥有组件实例的上下文,可直接通过 `{{ $store.state.userName }}` 访问,等价于 script 中的 `this.$store.state.userName`。\n至于 `{{ store.state.userName }}`script 中的 `data` 需声明过 `store` 才可访问。",
"type": "technical_qa"
}
]