Instruction:
http和https的区别？
我知道https更加安全，问题是怎么个安全法？
比如，我现在有一个纯的静态页面，就是做信息展示，就是我们说的marketing site,这里面也没有什么ajax请求啥的，是不是就http/https从安全角度就没有区别了？？？？
但是浏览器还是标记Http not secure呢？哪里不安全了？

Output:
小明要给小红写信，但小明小红之间离的太远了，没法直接交换信件，只能是小明先给小强、小强再给小刚、小刚再给小红，小红收到了以后回信给小刚、小刚再给小强、小强才能给到小明。小强和小刚在这个过程中都可以拆开信看到内容、甚至模仿小明小红的字迹去篡改这封信。本来可能小明写的是情书，被小刚改成了战书，小红收到了不得气炸了。
你现在用浏览器访问了思否网站，但你的电脑跟思否网站服务器显然并不是一根网线直连的，中间会经过层层设备转发，有路由器、交换机、中继器、代理、网关等等等等。而 HTTP 是明文的，也就是这中间的每一个设备都可以监听、甚至篡改 HTTP 报文。即便你是纯静态的网站，但你怎么确保浏览器收到的一定就是你的服务器返回的那个 HTTP 报文、中间没经过其他设备的监听和篡改呢？本来你服务器返回的是一个企业宣传网站，结果被篡改成了一个黄赌毒网站。
这种监听和篡改在计算机中被称之为“中间人攻击” —— 顾名思义，就是因为通信两端中间的某些节点发生的攻击。而 HTTPS 要解决的就是这个问题。具体还可以细分为单向认证和双向认证。单向认证只能确保客户端收到的一定是服务器返回的内容，但无法保证服务器收到的一定是客户端发出的内容；双向认证则两端都可以确保不被篡改。
扩展思考：前面说因为客户端和服务器离得太远所以不得不需要很多“中间人”来转发，那么假如客户端和服务器用网线直接连接、去掉这些“中间人”，用 HTTP 就会安全吗？答案是依然不安全，至于为什么，您可以先自己思考一下。


Instruction:
为什么感觉redis队列不如mysql稳定，容易丢数据，原因何在？
目前的开发环境：php7.2 | thinkphp
1.用mysql实现的架构：
生产者：大量数据先存入mysql中间表（mysql中间表用唯一索引约束唯一性）
多个消费者：循环从mysql中间表中取数据，进行计算后存入mysql结果表
2.用redis实现的架构：
生产者：大量数据先进入redis集合（为了保证重复数据不入队列），确定能进入集合的数据再塞入redis队列
多个生产者：循环从redis队列中取数据，每取一条数据后将该数据从redis集合中删除，对数据进行计算，计算后的数据存入mysql结果表
两种架构在实际使用中发现，用纯mysql的方式实现，结果数据很稳定，没有出现丢失的情况。
而用redis的方式实现，会发现存在数据丢失的情况（即结果表里缺少数据），而且还找不到数据丢失的原因，trycatch和redis日志均无问题。用redis集合加redis队列作为中间过度的方式为什么会不稳定？原因在哪里？

Output:
首先，Redis什么时候会出现`丢数据`？
Redis持久化有两种方式`RDB`和`AOF`，它只会在重启时可能丢失数据。正常运行的情况下，是不会丢失数据的。
找不到丢失的原因？，为什么不稳定？
MySQL有ACID，强一致性事务支持。而Redis分步操作，每步都可能出问题。
`而且还找不到数据丢失的原因`
分步骤来看：
- 大量数据先进入redis集合？ 是否正常
- 再塞入redis队列？ 是否正常

`循环从redis队列中取数据，每取一条数据后将该数据从redis集合中删除，对数据进行计算，计算后的数据存入mysql结果表`
这是一个很大的步骤。最简答的方法，加日志，看看是哪里丢的数据。比如取了数据从Redis删除了，计算时出现问题，没有写MySQL。
你抛出的问题，别人很难处理。没有代码不请求具体实现，而且你没有耐心的去找原因。每个步骤都加详细的日志，不可能存在找不到原因这种问题。


Instruction:
JS 中通过apply实现数组中，查找最大值的方法原理是什么？
JS数组中无法直接通过`Math.max`查找数组中元素的最大值，但可以通过`apply`方法实现，底层实现逻辑及原理是什么样的呢？
```
Math.max.apply(null, [1,2,3]);
```

Output:
我们这样来理解，
首先，
```
Math.max(value0, value1, /* … ,*/ valueN)
```
这个函数的参数并不是数组，比如你有N个数字比大小，哪它就要输入N个参数，
对于在数组中的数字，你把整个数组当参数给它，Math.max就认为只有一个参数了。所以比不了
也就是说，你要把数组中每一位数字，都转成它的参数
```
const arr=[1,2,3]
//最笨的办法是
Math.max(arr[0],arr[1],arr[2])
//最新的办法
Math.max(...arr)
```
上面都是把数组的每一位，变成参数传个Math.max
哪为什么，Function.prototype.apply() 就可以呢，因为apply(thisArg, argsArray),第二个参数，就是接受一个数组对像，把它变成调用者的所有参数，


Instruction:
为什么mysql的依赖scope是runtime？
如题，runtime意味着打包时不包含mysql依赖，没有mysql驱动发布后的项目如何正常连接数据库呢？

Output:
因为JDBC通常你在编码的时候依赖的只是JDBC接口，而不直接依赖mysql JDBC对吧？
想想你在连接mysql的时候是不是用的类似于这样的代码?
```
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(url, username, password);
// ...
```
我们会发现我们会使用反射方法`Class.forName`在运行的时候从ClassPath中加载Mysql JDBC,后续调用的时候均没有使用任何MySQL JDBC的专有方法，而是用的JDBC接口，对吧？
所以JDBC Driver不是编译依赖(Compile Scope)，因为我们的代码中没有直接使用JDBC Driver的专有方法，所以编译的时候不需要JDBC Driver存在。JDBC接口才是编译依赖，JDBC Driver属于运行依赖(Runtime Scope)。
你声明Runtime依赖的时候在编译中是不会将依赖引入ClassPath的，但是打包的时候会，所以无需担心，JDBC Driver就应该是Runtime Scope依赖。
Compile Scope指的是编译的时候需要该依赖，通常编译依赖也是Runtime依赖，而Maven/Gradle对于compile依赖通常都是编译之后同时也包含在fat jar中的，相当于Compile就隐含Runtime。某些依赖也可能是CompileOnly依赖，比如注解处理器就是典型的CompileOnly依赖，只有编译的时候需要，编译过后在运行中是不需要的


Instruction:
chrome控制台调试：f9 和 f11 有何区别?
f10(跳过下一个函数调用)、f11(进入下一个函数调用)用的很熟，但f9(单步调试)没用过，经过测试感觉和f11一样，遇到函数就进入函数里边执行。那么f9 和 f11 有何区别？

Output:
stackoverflow
You can spot the difference while running async code or multi-threaded code.
Step into: DevTools assumes that you want to pause in the asynchronous code that eventually runs
Step: DevTools pause in code as it chronologically ran
Consider this example:
```
setTimeout(() => {
    console.log('inside')
}, 3000);
console.log('outside')
```
After stopping on the breakpoint on the first line (`setTimeout(() => {`).
Step into: it waits 3 seconds and stops on the 2nd line (`console.log('inside')`)
Step: it pauses on the 4th line (`console.log('outside')`)
Link to the docs: https://developers.google.com...


Instruction:
函数传入的值，作为对象的 key 返回，TS 应该如何写？
返回的 `ts` 一定有 `a` 这个 `key`：
```
function test(a:string, b:object){
  return {
      [a]:b[a]
  }
}
```

Output:
```
function test<T extends Record<string, any>, K extends keyof T>(a:K, b:T){
  return {
    [a]:b[a]
  } as Pick<T, K>
}

```


Instruction:
如果一次网页操作本身就只会触发一次回流/重绘，那么虚拟 dom 还有优势吗?
按照我目前的理解,虚拟dom的优势在于把当前的变化打包给浏览器,让浏览器一次性更新,而不是来一个更新一个,减少页面的回流和重绘.
但是如果只有一个按钮, 点一下文字变色或者改变某个元素的显隐性,那么这种操作浏览器应该本身就是只回流/重绘一次,这个时候虚拟dom还有优势吗?
#### 还有个小问题: 默认浏览器是怎么更新元素的?
如果我一次 display:none 了页面中的9个元素,那么在没有虚拟dom的情况下,浏览器会回流/重绘9次吗

Output:
Q1：
> 但是如果只有一个按钮, 点一下文字变色或者改变某个元素的显隐性，那么这种操作浏览器应该本身就是只回流/重绘一次，这个时候虚拟 DOM 还有优势吗？那肯定是原生直接操作 DOM 更快。
但问题是这种简单页面的场景为啥你要用 MVVM 框架？
Q2：
> 如果我一次 display:none 了页面中的 9 个元素，那么在没有虚拟 DOM 的情况下，浏览器会回流/重绘 9 次吗。
这里的“一次”，我理解为是一段代码里连续控制 9 个元素隐藏，类似：
```
el1.style.display = 'none';
el2.style.display = 'none';
el3.style.display = 'none';
// 略...
```
那么答案是不一定。
老浏览器的话是回流 9 次（没错，就说你呢，明天就要退休的 IE）。现代浏览器会有渲染队列来对这种场景做优化，一段时间内的重复回流操作会被合并（但要注意这里的队列可能会被另一些操作打断并清空，比如 `getBoundingClientRect`、`getComputedStyle` 等等，这也很好理解，这些操作是要获取当前 DOM 状态的，自然要必须强制触发一次回流才可以拿到实时状态）。
而回流必然会重绘，重绘不一定回流。所以次数这里两者是一样的。


Instruction:
来个 js 算法大牛看看这个题,有没有优雅点的代码?
`源数据`
```
const data = [
  {
    city:'浙江',
    children:[
      {
        city:'宁波',
        children:[{
          city:'鄞州区',
          children:[]
        },{
          city:'江北区',
          children:[]
        }]
      },
      {
        city:'杭州',
        children:[{
          city:'富阳',
          children:[]
        },{
          city:'上城区',
          children:[]
        }]
      }
    ]
  },
  {
    city:'上海',
    children:[
      {
        city:'黄浦区',
        children:[]
      }
    ]
  }
]
```
`目标结构`
```
[
  "浙江,宁波,鄞州区",
  "浙江,宁波,江北区",
  "浙江,杭州,富阳",
  "浙江,杭州,上城区",
  "上海,黄浦区"
]
```

Output:
## solution 1
```
function flatTree(nodes, parents = []) {
    const pathes = nodes
        .filter(({ children }) => !children?.length)
        .map(({ city }) => [...parents, city]);
    const subPathes = nodes.filter(({ children }) => children?.length)
        .flatMap(({ city, children }) => flatTree(children, [...parents, city]));
    return pathes.concat(subPathes);
}
```
## solution 2
```
function flatTree(nodes, parents = []) {
    return nodes.flatMap(({ city, children }) => {
        return children?.length
            ? flatTree(children, [...parents, city])
            : [[...parents, city]];
    });
}
```
## using
```
console.log(flatTree(data).map(path => path.join(",")));
//                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
```


Instruction:
怎么让 a == 1 && a==2 && a==3  的结果为 true？
让 a == 1 && a==2 && a==3  的结果为 true

Output:
```
function A() {
    this.value = 0;
    this.toString = function() {
        return ++this.value
    }
}
const a = new A();

a == 1 && a == 2 && a == 3
```
相等运算符 `==` 和 `!=` 使用 抽象相等比较算法 比较两个操作数。可以大致概括如下：
- 如果两个操作数都是对象，则仅当两个操作数都引用同一个对象时才返回 `true` 。
- 如果一个操作数是 `null`，另一个操作数是 `undefined`，则返回`true` 。
- 如果两个操作数是不同类型的，就会尝试在比较之前将它们转换为相同类型：当数字与字符串进行比较时，会尝试将字符串转换为数字值。如果操作数之一是 `Boolean`，则将布尔操作数转换为1或0。如果是 `true`，则转换为 `1`。如果是 `false`，则转换为 `0`。如果操作数之一是对象，另一个是数字或字符串，会尝试使用对象的 `valueOf()` 和 `toString()` 方法将对象转换为原始值。
- 如果操作数具有相同的类型，则将它们进行如下比较：`String`：`true` 仅当两个操作数具有相同顺序的相同字符时才返回。`Number`：`true` 仅当两个操作数具有相同的值时才返回。`+0` 并被 `-0` 视为相同的值。如果任一操作数为 `NaN`，则返回 `false`。`Boolean`： `true` 仅当操作数为两个 `true` 或两个 `false` 时才返回 `true`。

如果两个操作数是不同类型的，就会尝试在比较之前将它们转换为相同类型：
- 当数字与字符串进行比较时，会尝试将字符串转换为数字值。
- 如果操作数之一是 `Boolean`，则将布尔操作数转换为1或0。如果是 `true`，则转换为 `1`。如果是 `false`，则转换为 `0`。
- 如果操作数之一是对象，另一个是数字或字符串，会尝试使用对象的 `valueOf()` 和 `toString()` 方法将对象转换为原始值。

如果操作数之一是 `Boolean`，则将布尔操作数转换为1或0。
- 如果是 `true`，则转换为 `1`。
- 如果是 `false`，则转换为 `0`。

如果操作数具有相同的类型，则将它们进行如下比较：
- `String`：`true` 仅当两个操作数具有相同顺序的相同字符时才返回。
- `Number`：`true` 仅当两个操作数具有相同的值时才返回。`+0` 并被 `-0` 视为相同的值。如果任一操作数为 `NaN`，则返回 `false`。
- `Boolean`： `true` 仅当操作数为两个 `true` 或两个 `false` 时才返回 `true`。

来自 https://developer.mozilla.org...


Instruction:
js 函数 return false 跳出外部函数，怎么写？
```
function a(){
   if（true）
       return false;
}
```
这是没有任何问题的，如果我改成这种
```
function Test(){
   a();
   b();
   c();
}
```
js 函数a() return false 跳出外部函数Test()，怎么写？

Output:
`return` 只能退出当前函数，不具备跨函数的功能。但是 `throw` 具有不限层次中断的功能，所以这个需要可能需要使用 throw 来完成。
一般情况下 `throw` 应该抛出一个 `Error` 对象。但是 JavaScript 并未对 `throw` 的对象有所有限制，所以也可以抛出其它东西，在确实不需要抛出错误的情况下，抛出一个状态对象，甚至值都是可以的。但不管抛出什么，要想外面的程序能正常运行，都是需要 `try ... catch` 的。
举例：
```
function a() {
    console.log("[Trace] a()");
    if (true) {
        throw "true-as-false";
    }
}

function b() {
    console.log("[Trace] b()");
}

function c() {
    console.log("[Trace] c()");
}

function test() {
    try {
        a();
        b();
        c();
    } catch (stat) {
        if (stat === "true-as-false") {
            return;
        }

        // TODO 其他情况正常处理可能发生的错误
    }
}

test();
```
只会输出 `[Trace] a()`，因为被 throw 给中断掉了。
如果是有一堆判断函数，只要有一个 flase 就退出，那就可以用数组来处理，比如
```
const fns = [
    () => { console.log(true); return true; },
    () => { console.log(true); return true; },
    () => { console.log(false); return false; },
    () => { console.log(true); return true; },
];

fns.every(fn => fn());
// true
// true
// false
```
只要遇到一个返回 `false` 的就结束了（注意，返回 `undefined`，也就是无返回值 …… 也表示 `false`)


Instruction:
判断一个字符串，A-Z对应输出0-25，a-z对应输出26-51，有什么简洁的写法吗？
比如：'AZaz' => '0 25 26 51'
我目前的做法：
```
function Words(words){
    let strArray = []
    for (let s of words){
        if(/[A-Z]/.test(s)) strArray.push(s.charCodeAt(0)-65)
        else if(/[a-z]/.test(s)) strArray.push(s.charCodeAt(0)-71)
    }
    return(strArray.join(' '))
}

Words('AZaz')
```

Output:
```
var Words=(s,a='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')=>s.split('').map(v=>a.indexOf(v)).join('');

Words('AZaz');
```


Instruction:
来个 js 大牛,如何简洁的处理这种数组转换成对象?
有这样一个 Array,
`[{key:xxx},{value:xxx}]`
`key` `value`是固定的属性
```
[
    {key:'alan',value:12},
    {key:'mike',value:18}
]
```
期望值
```
{alan:12,mike:18}
```
希望不借助新的变量,简洁优雅一些~

Output:
其实所谓简洁，无非就是找现成的功能函数替换掉一堆逻辑代码……所以，自己封个工具函数，一句调用是最简洁的！
```
const data = [
    { key: "alan", value: 12 },
    { key: "mike", value: 18 }
];

// 就这句话，换行主要是为了看清楚，可以不换
const result = Object.fromEntries(
    data.map(({ key, value }) => [key, value])
);

console.log(result);
```


Instruction:
Vue如何动态修改template?
先上代码：
```
<template>
    <div v-html="marked(content)"></div>
</template>
<script>
....
....
methods:{
   markdown (content) {
      var renderer = new marked.Renderer()
      renderer.image = (href, title, text) => {
        return '<a @click="showFullImage">' + text + '</a>'
      }
      marked.setOptions({
        renderer: renderer,
        gfm: true,
        tables: true,
        breaks: true,
        pedantic: false,
        sanitize: false,
        smartLists: true,
        smartypants: false,
        highlight: (code) => {
          return hljs.highlightAuto(code).value
        }
      })
      return marked(content)
   }
}
</script>
```
我在使用vue做一个工具，需要输入框中的markdown代码转为html，然后展示出来。
其中我想做的一个功能是，当用户输入：
```
![pic](www.example.com/img.jpg "title")
```
使用marked的自定义渲染函数，转换成html（已经实现）:
```
<a @click="showFullImage">title</a>'
```
现在的问题是，在展示的时候，使用v-html无法完成函数绑定。有没有好的方法？
简洁的说法是，我需要自己生成一段vue格式的html字符串，然后将这个字符串渲染出来，里面有各种vue指令需要绑定，该怎么做呢？

Output:
我是在一个子组件中实现的，你可以动态的添加该子组件：
下面的`content`是markdown格式的数据，
`../common/markdown`文件是自己写好的基于marked的解析函数，它会将`Markdown`格式析为`Vue`格式的字符串:
```
![图片文字](url)
// 上面会解析为：
<img src="url" @click="showInfo('图片文字')">
```
用下面的方法即可以实现点击图片时，会输出信息。当然其他的vue处理方法同样支持。
```
<template >
  <div ref="markedContent"></div>
</template>

<script>
import Vue from 'vue'
import markdown from '../common/markdown'
export default {
  name: 'wf-marked-content',
  props: ['content'],
  mounted () {

    // 调用compile方法。你也可以将写在这里。
    // 但是代码太多，我个人不喜欢
    this.compile()
  },
  methods: {
    compile () {
      // 变量html是生成好的vue格式的HTML模板字符串，
      // 这个模板里面可以包含各种vue的指令，数据绑定等操作，
      // 比如 v-if, :bind, @click 等。
      const html = markdown(this.content)

      // Vue.extend是vue的组件构造器，专门用来构建自定义组件的，
      // 但是不会注册，类似于js中的createElement，
      // 创建但是不会添加。
      // 在这里创建出一个子组件对象构造器。
      const Component = Vue.extend({

        // 模板文件。由于Markdown解析之后可能会有多个根节点，
        // 因此需要包裹起来。
        // 实际的内容是：
        // `<div><img src="url" @click="showInfo(`图片文字')"></div>`
        template: `<div> ${html} </div>`,

        // 这里面写的就是这个动态生成的新组件中的方法了，
        // 当然你也可加上data、mounted、updated、watch、computed等等。
        methods: {

          // 上面模板中将点击事件绑定到了这里，因此点击了之后就会调用这个函数。
          // 你可以写多个函数在这里，但是这里的函数的作用域只限在这个子组件中。
          showInfo (title) {
            console.log(title)
          }
        }
      })

      // new Component()是将上面构建的组件对象给实例化，
      // $mount()是将实例化的组件进行手动挂载，
      // 将虚拟dom生成出实际渲染的dom，
      // 这里的markedComponent是完成挂载以后的子组件
      const markedComponent = new Component().$mount()

      // 将挂载以后的子组件dom插入到父组件中
      // markedComponent.$el就是挂载后生成的渲染dom
      this.$refs['markedContent'].appendChild(markedComponent.$el)
    }
  }
  // 本质上来讲，这个子组件不是任何组件的子组件，
  // 它是由vue直接在全局动态生成的一个匿名组件，然后将它插入到当前位置的。
  // 也正是因此，它才能够完成动态的生成和添加。
}
</script>
```


Instruction:
怎么判断一个数组里是否嵌套子数组
我怎么判断一个数组是不是双层呢，判断后返回true和false,比如[1,1,1,1]就是false，[1,[2,2,2],1,1,1]就是true,有啥方法么，如果是三层,怎么判断呢

Output:
`isDeepThen()` 用来判断最大深度是否超出指定 level；`getMaxDeep()` 用来获取最大深度。都是递归实现。两个函数没有直接关系，只是用来干不同的事情。
```
const cases = [
    [1, [2, [3, [4], [5]]]],
    [1, [2, [3]]],
    [2, [2, 3]],
    [1, 2, 4],
    1
];

// 检查最大深度是否超过指定 level，如果 level 传 0 表示只要是数组就行
// 可以通过 getMaxDeep() 来判断，但是 getMaxDeep() 会遍历所有项，效率较低
// isDeepThen() 有快递中断机制
function isDeeperThen(arr, level = 0) {
    // 不是数数组，肯定是 false
    if (!Array.isArray(arr)) { return false; }
    // 如果是数组，层次肯定大于 0
    if (level === 0) { return true; }

    // 找到所有数组元素进行递归检查
    return arr.filter(el => Array.isArray(el)).some(el => isDeeperThen(el, level - 1));
}

// 获取最大深度（与上面那个 isDeepThen() 没关系）
function getMaxDeep(arr) {
    // 不是数组，深度为 0
    if (!Array.isArray(arr)) {
        return 0;
    }

    // 是数组，深度 + 1，具体是多深，还要递归判断元素中的数组
    return 1 + Math.max(...arr.map(el => getMaxDeep(el)));
}

cases.forEach(data => {
    console.log(
        isDeeperThen(data, 2).toString().padEnd(6, " "),
        getMaxDeep(data),
        JSON.stringify(data)
    );
});
```
```
true   4 [1,[2,[3,[4],[5]]]]
true   3 [1,[2,[3]]]
false  2 [2,[2,3]]
false  1 [1,2,4]
false  0 1
```


Instruction:
Mysql 为什么要有最左前缀的要求，优化器不能自己优化调整顺序吗
比如一个联合索引 `index('user_id', 'created_at')` ，我写了下面的 `SQL` 语句
```
select
    *
from
    tweet
where
    created_at < '2021-11-11'
    and user_id = 1
```
优化器会把上面的语句优化为下面的语句吗？
```
select
    *
from
    tweet
where
    user_id = 1
    and created_at < '2021-11-11'
```

Output:
你对左前缀理解错了。
你这种情况是可以用到索引的。
左前缀是指这种情况走不了索引
```
select
    *
from
    tweet
where
    created_at < '2021-11-11'
```
而这种情况可以
```
select
    *
from
    tweet
where
    user_id = 1
```
因为 `user_id` 在联合索引的左边。
如果有索引 (a, b, c) 那么 `where a, b, c`、`where a, b`、`where a` （where 后的顺序无关，可以随意组合，但是跟出现的字段有关）都是可以走到索引的。但是 `where b, c` 就不走索引了，因为按照左前缀原则，这里必须要出现 `a` 才行。
使用如下。
上表中，第二行，`a, c` 虽然是联合索引`(a, b, c)` 中有两个字段，但是因为这里没有出现 `b`，按照做前缀原则就断开了，所以只能使用到 `a`
注意上文中 where 顺序可以随意组装，比如 `a, b, c` 你可以写成 `a, c, b`、 `c, a, b` 等，这些都不影响，但是出现的字段必须是上面写到的。
除了 where 外，还有 order。
`where a order c` 这个就只会用到 (a, b, c) 中的 `(a)` ，而如果是 `where a order b` 则能用到 `(a, b)`


Instruction:
请问大家，这个小算法问题，怎么改？
[
```
{
    "categoryId": "373",
    "parentId": "3",
    "categoryName": "张三",
    "sunCategorys": [
        {
            "categoryId": "374",
            "parentId": "373",
            "categoryName": "张三一",
        },
        {
            "categoryId": "375",
            "parentId": "373",
            "categoryName": "张三二",
        }
    ]
},
{
    "categoryId": "374",
    "parentId": "3",
    "categoryName": "李四",
    "sunCategorys": [
        {
            "categoryId": "375",
            "parentId": "374",
            "categoryName": "李四一",
        },
        {
            "categoryId": "376",
            "parentId": "374",
            "categoryName": "李四二",
        }
    ]
}
```
]
我想把上面数据的categoryName 和 sunCategorys里面的categoryName，categoryId的id的值取出来，组合成这样的形式，请问应该如何去写
[
```
{
    "text": "张三",
    "children": [
        {
            "text": "张三一",
            "id": 374
        },
        {
            "text": "张三二",
            "id": 375
        }
    ]
},
{
    "text": "李四",
    "children": [
        {
            "text": "李四一",
            "id": 375
        },
        {
            "text": "李四二",
            "id": 376
        }
    ]
}
```
]

Output:
```
const result = data.map((item) => ({
    text: item.categoryName,
    children: item.sunCategorys.map((category) => ({
        text: category.categoryName,
        id: category.categoryId,
    })),
}));
```


Instruction:
vue的nextTick为什么一定会比promise更先执行？
nextTick内部打比按照promise进行，那么是怎么做到比逻辑中的promise更早执行的？看源码写的是Promise.resolve().then(callback)执行回调代码callback
```
if (typeof Promise !== 'undefined' && isNative(Promise)) {
  const p = Promise.resolve()
  timerFunc = () => {
    p.then(flushCallbacks)
    // In problematic UIWebViews, Promise.then doesn't completely break, but
    // it can get stuck in a weird state where callbacks are pushed into the
    // microtask queue but the queue isn't being flushed, until the browser
    // needs to do some other work, e.g. handle a timer. Therefore we can
    // "force" the microtask queue to be flushed by adding an empty timer.
    if (isIOS) setTimeout(noop)
  }
  isUsingMicroTask = true
}
```

Output:
首先我不知道您是怎么得出一定这个结果的，nextTick并不一定比Promise快，它本来就是Promise就得遵循Promise的规范和顺序，但是nextTick是对Promise的封装，所以
```
nextTick(fn1) // Promise
nextTick(fn2)
nextTick(fn3)
```
实际上就初始化了一个Promise就在第一个nextTick执行的时候
后面调用的fn2,fn3可以理解为都是往第一个fn1函数里push的，所以下面的执行顺序就是fn1 fn2 fn3 fn4因为fn1 fn2 fn3合并为了一个函数，就造成了 fn2 和fn3比fn4快
```
nextTick(fn1) // Promise1
Promise.resolve().then(fn4) // Promise2
nextTick(fn2)
nextTick(fn3)
```
自始至终只有2个Promise 第一次执行nextTick的fn1和fn4，因为fn1声明在fn4之前所以fn1比fn4快
这只限于同一个事件循环，在下一次事件循环第一次执行nextTick依然会有一个新的Promise


Instruction:
在 JavaScript 中，如何实现 const a = [...5] 就可以创建一个 [1, 2, 3, 4, 5] 数组
如何实现在编写 JavaScript 项目时，可以以下面这样的方式，创建一个新的数组：
```
const a = [...5];

// a = [1, 2, 3, 4, 5];
```

Output:
```
Number.prototype[Symbol.iterator] = function () {
  const i = +this;
  let value = 0;
  return {
    next() {
      value += 1;
      return {done: value > i, value};
    }
  };
}
```


Instruction:
请问 prettier 与 EditorConfig 功能是不是重复了？
prettier 与 EditorConfig 都是代码格式化工具，他们到底有什么区别？我只知道他们的配置文件不同，一个是.prettierrc文件，而另外一个是.editorconfig文件，但感觉他们功能一样，在网上看别人教程，为何都是两个一起使用的？不是功能重复了吗？求解答？

Output:
EditorConfig 格式化的是比较基础的东西，基本上你用“Editor”（编辑器）本身能干的操作就可以用它来干。比如 Tab 变几个空格啊、换行符是 CR 还是 CRLF 啊、文件编码是不是 UTF-8 啊这种的。
而且它不只局限于格式化，名字也能看出来是“Config”（配置）而不是“Formatter”（格式化器）。你也可以用它来配置诸如让 IDE 忽略特定的编译警告错误之类的。
所以你会发现它跟编程语言本身没什么关系，各个语言的项目都能看到 `.editorconfig` 的身影，它更多地干的是当你用特定 IDE 时能配置的那些东西，好让那些不用这个 IDE 的、或者它 IDE 配置跟你不一样的开发者也能使用相同的编辑器方案。当然了它确实可以通过插件的形式去支持一些其他语言特有的格式化方案，不过并不常用。
而 Prettier 是 JS 特有的格式化工具，里面很多配置项是 JS 这门语言特有的规范。
总体来说二者有重叠的部分，但大部分并不相同。所以前端项目往往两者都有，非要只选一个的话选 Prettier 而不是 EditorConfig。


Instruction:
请求返回的是 字符串 格式的 js代码，我要怎么 import 到内部的 模块呢
手动@大佬回答 @边城
如题 后端接口返回给我的是
字符串格式的
```
var a = 1
function setA(v){
    a = v
}
export function getA(){
    return a
}
```
我要怎么 `import` 到内部的 `getA` 模块呢
使用的 `vue`

Output:
https://stackoverflow.com/que...
```
<script type="module">
const code = `
var a = 1
function setA(v){
    a = v
}
export function getA(){
    return a
}
`;
const objectURL = URL.createObjectURL(new Blob([code], { type: 'text/javascript' }));
const module = await import(objectURL);
console.log(module.getA());
</script>
```


Instruction:
vue怎么监听数组项？
如下数组，其中ccc属性值根据bbb属性和ddd属性计算得到的，我需要监听数据项的变化，动态计算ccc属性值
```
 export default {
        data() {
            return {
                aaa: [{
                   bbb: "xxx",
                   ddd: "xxx",
                   ccc: ""
                }, {
                   bbb: "yyy",
                   ddd: "yyy",
                   ccc: ""
                }]
            }
        }

 }

```
于是我使用了watch监听
```
 watch: {
            aaa: {
                deep: true,
                handler(newValue, oldValue) {
                    for (let i = 0; i < newValue.length; i++) {
                        newValue[i].ccc = newValue[i].bbb + newValue[i].ddd;
                    }
                }
            }
        }
```
这种方法会导致每个数据项的变动，需要所有数据项都计算一次，有没有什么好的方式？
而且，还有个问题，监听数组并没法获取到旧值，也就是newValue和oldValue是一模一样的，都是新的值。
这个问题主要是讨论性能问题，比如每个数组有100个属性项，又或者ccc是通过耗性能的计算得到的，那么每次数据项的变动都导致所有数据项重新计算一次，这耗费的性能不可想象，所以大家可以想一下，看有没有好的实现方案?? 实现目标是只对变动的数据项进行计算

Output:
```
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <div id="app">
    <div v-for="v of list">
      <input type="number" v-model="v.a">
      <input type="number" v-model="v.b">
      <span>sum: {{v|sum}}</span>
      <span>和：{{v.c}}</span>
    </div>
  </div>
<script src="https://cdn.staticfile.org/vue/2.6.13/vue.min.js"></script>
  <script>
    new Vue({
      el: '#app',
      filters: {
        sum: item => +item.a + (+item.b)
      },
      data: {
        list: [{
          a: 1,
          b: 2,
          get c() {
            return +this.a + (+this.b)
          }
        }, {
          a: 3,
          b: 4,
          get c() {
            return +this.a + (+this.b)
                    }
        }]
      }
    })
  </script>
</body>
</html>
```
比较简单的方式——过滤器或者直接定义一个getter；
还有一个方式就是将动态计算显示的那个属性抽成组件，传入props通过vue的computed去计算，和直接在数据上定义getter原理上是一样的


Instruction:
JS的onclick在Chrome和Safari中均不能被触发
写了一段很简单的源码，就是最基本的使用 <button> 触发事件：
HTML 源码如下：
```
<body>
    <button>Click this button to trigger an event</button>
</body>

<script src="Event.js"></script>
```
JS 源码如下：
```
var btn = document.getElementsByTagName("button")
btn.onclick = function () {
    alert("Successfully Triggered an Event !");
    console.log("Good");
}
```
在浏览器中解析后，调试时发现 btn 中选择到了 <button> 元素，而且也被赋值了。但是点击 <button> 按钮却没有反应，即没有出现 alert 对话框，控制台也没有显示 “Good”。这是为什么啊 ？

Output:
因为getElementsByTagName获取的是元素集合，不是元素本身，所以你需要先从这个集合中取到元素，再进行绑定
```
var btns = document.getElementsByTagName("button")
// 或者使用遍历，需要注意它是一个为数组，不能直接当数组进行遍历
btns[0].onclick = function () {
    alert("Successfully Triggered an Event !");
    console.log("Good");
}
```


Instruction:
JS排序问题(凑满减)
```
const list =[
  {title:'苹果',price:1},
  {title:'香蕉',price:4},
  {title:'鸭梨',price:3},
  {title:'西瓜',price:5},
  {title:'山竹',price:2}];
```
我想排序, 按照price大于3的正序, 然后再把小于3的倒序, 排在大于的数据后面, 求最优算法.
期望如下:
```
const list =[
 {title:'香蕉',price:4},
 {title:'西瓜',price:5},
 {title:'鸭梨',price:3},
 {title:'山竹',price:2},
 {title:'苹果',price:1}];
```

Output:
```
list.sort((a, b) => {
    if(a.price > 3 && b.price > 3){
        return a.price - b.price
    }
    return b.price - a.price
})
```


Instruction:
if判断是否有值，但是这个值为0，它也判了不过请问怎么写呢
```
    // row保存
    saveRow (record) {
      const { num, id } = record
      if (!num) { // 这里为0也走了，怎么判断单纯有没有值
        this.tableLoading = false
        this.$message.error('请填写完整信息。')
        return
      }
    },
```

Output:
这里先要搞明白 `num` 允许是哪些值。如果只能是数字的话，可以这样
```
if (typeof num === "number") { ... }
```
不过这样的话，`num` 还有可能是 `NaN`，一般 `NaN` 也需要过滤掉（要不要过滤看业务），所以
```
if (typeof num === "number" && !isNaN(num)) { ... }
```
接下来，如果逻辑可以保证 `num` 只会是数字，或者空（含 `undefined`），那么可以这样判断
```
if (!(num === undefined || num === null || isNaN(num))) { ... }
```
如果用新语法 Nullish Coalescing，会简单一些
```
if (!isNaN(num ?? NaN)) { ... }
```
如果 `NaN` 算是合法的，那就得找个不应该出现的值（只能是一个非数字值了，幸好 JS 不绑定类型）
```
// if (num ?? false !== false) { ... }
// 修改一下，用 null 语义上更舒服一些
if (num ?? null !== null) { ... }
```
更复杂的情况，如果 `"1234"` （表示数的字符串）这种也算合法，还是老实的用 `typeof` 吧
```
// 代码没测试，小心使用
// 假设 NaN 不合法
function isValudNum(num) {
    switch (typeof num) {
        case "string":
            num = parseInt(num, 10);
            // 如果可能是浮点数用 parseFloat
            // 这里不加 break，需要穿透下去判断 isNaN
        case "number":
            return !isNaN(num);
        default:
            return false;
    }
}
```
如果 `NaN` 也合法，处理 `"string"` 类型的时候会更伤心，因为需要先判断是否数字，用正则表达式判断
```
case "string":
    return /^\d+$/.test(num);
    // 如果要判断浮点数
    // return /^\d+(?:\.\d+)?$/.test(num);
```
当然，如果只是做数字判断的话，`NaN` 不合法的情况下，用下面这个 `case "string"` 代替上面那个也是没问题的。


Instruction:
定义一个数组，调用方法报错
通过不同方式定义一个数组，直接调用方法报错
感觉可能和js自动装包有点关系
但是每种情况报错文案还不太一样
为什么借用一个变量就ok了
它们内部机制是什么，求大佬详细讲解下
```
const a = 1
const b = 2
[a,b].forEach(e => {
    console.log(e);
});

//VM409:3 Uncaught ReferenceError: Cannot access 'b' before initialization
```
```
let a = 1
let b = 2
[a,b].forEach(e => {
    console.log(e);
});

//ReferenceError: b is not defined
```
```
var a = 1
var b = 2
[a,b].forEach(e => {
    console.log(e);
});

//VM409:3 VM480:3 Uncaught TypeError: Cannot read property 'forEach' of undefined
```
```
const a = 1
const b = 2
const arr = [a,b]
arr.forEach(e => {
    console.log(e);
});

//1,2  执行成功
```
```
const a = 1
const b = 2
const fn = (e)=>{
     console.log(e);
}
[a,b].forEach(fn);

//1,2  执行成功
```

Output:
少写了分号
每一行最后都加上分号
const a = 1;
const b = 2;
分号会和下一行的 [ 连在一起
相当于
```
const b = 2[a,b].forEach(e => {
    console.log(e);
});
```


Instruction:
问个java很白痴的问题
为什么`String`类型是大写的 别的类型都是小写的？

Output:
小写的，应该是基本类型。Java 基本类型只有 8 种，这 8 种类型不是类类型，但有对应的类类型
- `byte` ⇔ `java.lang.Byte`
- `short` ⇔ `java.lang.Short`
- `int` ⇔ `java.lang.Integer`
- `long` ⇔ `java.lang.Long`
- `float` ⇔ `java.lang.Float`
- `double` ⇔ `java.lang.Double`
- `boolean` ⇔ `java.lang.Boolean`
- `char` ⇔ `java.lang.Character`

基本类型不是类，也不会在任何包里。其他类型，都是类或接口类型。
`String` 全名 `java.lang.String`，是一个类。
按 Java 的开发规范，类名是按 Pascal 风格命名，也就是组成类名的每个单词首字母大写，其他字符小写的命名风格。


Instruction:
for...of 循环含有辅助平面字符的字符串，输出让我感到困惑
## 代码
```
let count = 0,
    s = "𠮷a";
for(let i of s){
    count ++;
    console.log(i);
}
for...of 输出：𠮷 a
console.log(count);//2
console.log(s.length);//3
```
## 疑惑的地方
1、字符串s的length为3，循环次数是2次；我用for循环测试，循环次数是3
次。
2、for...of在循环中做了那些事情导致循环次数少了一次？

Output:
Javascript 采用 Unicode字符集，在 UTF-16 之前使用的是 UCS-2 编码，该编码方法使用2个字节表示字符（基本平面字符）。
UTF-16 编码发布后，UCS-2 被整合进 UTF-16，基本平面字符仍用2个字节，辅助平面字符使用4个字节表示。
因此，Javascript 的字符操作函数在处理4个字节的字符时，会当成两个双字节的字符处理，从而无法返回正确的结果。
```
s.slice(0, 1) // �
s.substr(0, 1) // �
s.charAt(0) // \uD842
```
"𠮷" 的 UTF-16 编码是4个字节的 `0xD842 DFB7`，而4个字节的字符不属于 UCS-2编码，javascript 会将其识别为`U+D842`和`U+DFB7` 两个字符（在基本平面内，`U+D800` 到 `U+DFFF` 是一个空段，不对应任何字符）
ES6 增强了 Unicode 支持，可以识别4字节的字符。除了`for...of`，还有以下方法
```
s.codePointAt(0).toString(16) // 20bb7
s.at(0) // 𠮷
String.fromCodePoint("0x20BB7") // 𠮷
```
`length` 属性返回字符串中字符编码单元的数量，所以也可能与实际的字符数量不相同。
想要返回字符串的正确长度，可以使用 `Array.from(string).length`


Instruction:
CSRF攻击者是如何向网站注入欺诈链接的？
我明白CSRF的运作过程，但想不出来攻击者是如何在目标网站注入欺诈链接来骗用户点击的？

Output:
比如这个 看似人畜无害的链接，就可以把人从思否诱导到一条不归之路[手动狗头]，这里利用的原理是只要构造出合适的 URL 就可以发起百度搜索，仅此而已，但是你跳过去之后，浏览器会把本地的 `Cookie` 给你带上，百度后台就会认为是你本人在搜这种奇怪的东西，换成字节搜索的话，没准明天你的抖音就会刷到震撼的短视频了。
这个例子只是一个不怀好意的诱导，还算不上攻击，因为百度搜索的这个特点不算什么漏洞。但是如果某个银行的转账接口也是在 URL 里拼参数的话，那可就危险了：如果用户恰好登过这个银行的网页，`Cookie` 还在，那么只要构造一条转账的 `URL`，找机会让用户去点，就能神不知鬼不觉地把用户的钱拿到手。
那么，我有没有在百度的网站注入任何东西？没有。所以对于要攻击的目标网站，我们是不需要注入任何东西的，只要找到他的 CSRF 漏洞就行。
- 我们真正需要“注入”的，是这条链接，我这里写回答其实就已经成功“注入”了，因此，假如你发现了某个网站有这种明显的 CSRF 漏洞的话，你只需要在这里提个问题，夹带私货，然后静候猎物上钩。
- 有些时候我们需要使用更高档的手段，比如构造表单，那么这里的跳转链接显然是不够用的，这时候如果思否有 XSS 漏洞可以注入长的 html 片段的话，那么可以在这个 html 片段里构造表单，由于 XSS 的存在，我们已经不需要用户点击来发起攻击了。（思否在几个月前貌似真的有 XSS ，参见这个问题，这里我说的是“貌似”，因为当我打算验证的时候已经无法复现了，不知道他们是不是恶搞）
- 除此之外，我们还可以给用户发带链接的钓鱼短信，或者在钓鱼邮件里放一个名为“船新艳照门.avi.html”的静态文件……


Instruction:
js简写，能不能用一行写出来
看注释，希望能用一句写出来，有没有这种简便写法？
```
const t = [
  {name: 'John', value: 111},
  {name: 'Mary', value: 222}
];

const param = t.reduce((p, n) => {
  // 这儿能不能用一行写出来，类似于这样 t.map(k => k.child);
  p[n.name] = n.value;
  return p;
}, {})
```

Output:
```
const t = [
  {name: 'John', value: 111},
  {name: 'Mary', value: 222}
];
const param = t.reduce((p, n) => (p[n.name] = n.value,p), {})
```


Instruction:
TypeScript怎么实现接口的重载入？
### 题目描述
TS中是怎么实现接口的重载入？
### 相关代码
```
type ItemProps = {
  a: string;
  b?: boolean;
  c?: string;
}

const arr: ItemProps[] = [
 {
   a: 'demo',
   b: true,
   c: 'test'
 },
 {
   a: 'demo2'
 }
]
```
在上面定义中，怎么定义`ItemProps`类型才能达到： 如果`b`属性存在，则`c`属性必需存在 的效果
### 期待结果
```
const arr: ItemProps[] = [
 {
   a: 'demo',
   b: true,
   c: 'test'
 },
 {
   a: 'demo2',
   b: true, // 类型报错，因为存在b属性，但是缺少c
 }
];
```

Output:
```
type ExcludeKeys<T> = { [P in keyof T]: never; }

type RequireOrExcludeKeys<T, Keys extends keyof T = keyof T> =
    Pick<T, Exclude<keyof T, Keys>>
    & (Required<Pick<T, Keys>> | ExcludeKeys<Pick<T, Keys>>)

type ItemProps = RequireOrExcludeKeys<{
    a: string;
    b?: boolean;
    c?: string;
}, 'b' | 'c'>
```
Playground
把条件改成：`如果b属性存在，则c必须存在，但是c属性存在，b可以不存在。`
总结一下，就是 c 必须存在，b 可选存在。
只要修改下`RequireOrExcludeKeys`的参数，以及`Required<Pick<T, Keys>>`。
```
type RequireOrExcludeKeys<T, RequireKeys extends keyof T = keyof T, PartialKeys extends keyof T = keyof T> =
    Pick<T, Exclude<keyof T, RequireKeys>>
    & ((Required<Pick<T, RequireKeys>> & Partial<Pick<T, PartialKeys>>)
        | ExcludeKeys<Pick<T, RequireKeys | PartialKeys>>)

type ItemProps = RequireOrExcludeKeys<{
    a: string;
    b?: boolean;
    c?: string;
}, 'c', 'b'>
```
Playground


Instruction:
请问如何将监听事件改为promise的形式
现在的代码结构是这样：
```
function receiver(type, callback) {
  document.addEventListener(type, (ev) => {
    callback(ev);
  });
}
```
然后通过回调函数来执行：
```
receiver('click', (ev) => {
  console.log(ev)
})
```
现在想改为promise的形式：
```
receiver('click').then(ev => {
  console.log(ev)
})
```
请问需要怎么修改？

Output:
Promise就像一个状态机，而且是一个状态不可逆的状态机，这就意味它只会在到达Fullfiled或者Rejected状态时会执行你注册的函数，所以用Promise实现是不合适的
但是可以写成这样以达成相似效果
```
function receiver(type) {
  const listeners = [];

  const listen = {
    then(callback) {
      listeners.push(callback);

      return listen;
    }
  };
  document.addEventListener(type, async (ev) => {
    let acc = ev;
    for (let i = 0; i < listeners.length; ++i) {
      acc = await listeners[i](acc);
    }
  });

  return listen;
}

receiver("click")
  .then((e) => {
    console.log(e);

    return 1;
  })
  .then((v) => {
    console.log(v);
  });

```


Instruction:
$nextTick和setTimeout有什么区别？
①$nextTick和setTimeout有什么区别？
②在实际项目中使用两者哪个会好点？没有优缺点之类的，需要注意什么
在实际项目中遇到元素还没渲染出来就执行了事件，甚至是有些接口先调用了
除了这种延时调用的方法还有更好的解决方案嘛
大神们求解

Output:
`nextTick`:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法，获取更新后的 DOM。
`setTimeout`：只是延迟执行，在延迟执行的方法里，`DOM`有可能会更新也有可能没有更新。
常规做法就是延迟500ms或者1s
建议使用`nextTick`在有涉及`DOM`更新的场景


Instruction:
在js中执行顺序？
在js中，假设执行五万条log(1)需要5秒钟，在这个js中的第一行写个setTimeout一秒后执行log(2)，这个log(2)是一秒后执行还是log(1)执行完以后再执行？

Output:
- log(1)执行完以后再执行。这里涉及到浏览器端的js事件循环机制。js代码由上到下执行，在调用栈里面执行。
- 执行到setTimeout函数，是宏任务，放到回调队列里面。
- 然后继续执行调用栈里面的代码，五万条log(1)，是同步任务，在调用栈里面执行，一条一条先进先出。
- 等到过了1秒后，setTimeout函数执行完。但是此时的调用栈还没有空，继续等待，等到5秒后，调用栈空了，就会执行回调队列里面的任务。此时打印log(2)
- 附上js事件循环的链接：https://segmentfault.com/a/11...


Instruction:
网站如何检测到是否开启开发者工具?
http://211.149.185.229:8080/l...
上面这个网站打开开发者工具就会跳转到错误页面，请问如何做到的

Output:
```
! function(e) {
    var im = new Image();
    Object.defineProperty(im, 'id', {
        get: function() {
            window.location.href = "http://106.53.103.200:8082/error.html"
            blast();
        }
    });
    console.log(im); //谷歌最新版失效

    let num = 0; //谷歌最新版有效
    var devtools = new Date();
    devtools.toString = function() {
        num++;
        if (num > 1) {
            window.location.href = "http://106.53.103.200:8082/error.html"
            blast();
        }
    }
    console.log('', devtools);

    function blast() {
        var t = "";
        for (var i = 0; i < 1000000; i++) {
            t = t + i.toString();
            history.pushState(0, 0, t);
        }
    }

    //Edge浏览器 上面的代码会失效 强制使用谷歌浏览器
    function detectIE() {
        var ua = window.navigator.userAgent;

        var msie = ua.indexOf('MSIE ');
        if (msie > 0) {
            return true;
        }

        var trident = ua.indexOf('Trident/');
        if (trident > 0) {
            return true;
        }

        var edge = ua.indexOf('Edge/');
        if (edge > 0) {
            return true
        }

        edge = ua.indexOf('Edg/');
        if (edge > 0) {
            return true;
        }
        return false;
    }

    if (detectIE()) {
        window.location.href = "http://106.53.103.200:8082/error.html"
        setTimeout(() => {
            blast();
        }, 10);
    }

    //检测是否为谷歌浏览器
    if (navigator.userAgent.toLowerCase().indexOf("chrome") == -1) {
        window.location.href = "http://106.53.103.200:8082/error.html"
        setTimeout(() => {
            blast();
        }, 10);
    } else {  }
    var c = window.webpackJsonp;
    window.webpackJsonp = function(d, b, 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;
        for (t in b) Object.prototype.hasOwnProperty.call(b, t) && (e[t] = b[t]);
        for (c && c(d, b, n); u.length;) u.shift()();
        if (n)
            for (i = 0; i < n.length; i++) o = a(a.s = n[i]);
        return o
    };
    var d = {},
        f = { 175: 0 };

    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 }
    a.e = function(e) {
        var c = f[e];
        if (0 === c) return new Promise(function(e) { e() });
        if (c) return c[2];
        var d = new Promise(function(d, a) { c = f[e] = [d, a] });
        c[2] = d;
        var b = document.getElementsByTagName("head")[0],
            n = document.createElement("script");
        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";
        var t = setTimeout(r, 12e4);

        function r() {
            n.onerror = n.onload = null, clearTimeout(t);
            var c = f[e];
            0 !== c && (c && c[1](new Error("Loading chunk " + e + " failed.")), f[e] = void 0)
        }
        return n.onerror = n.onload = r, b.appendChild(n), d
    }, 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 }
}([]);
```
直接右键保存本地，down了一下。核心代码在这。


Instruction:
js for循环以逗号拆分为新数组
原数据格式↓
```
const data = [{ name: 'apple', cut: 'a,b,c' }, { name: 'trigger', cut: 'a,g' }]
```
期望数据格式↓
```
const data1 = [{ name: 'apple', final: 'a' },
               { name: 'apple', final: 'b' },
               { name: 'apple', final: 'c' },
               { name: 'trigger', final: 'a' },
               { name: 'trigger', final: 'g' }]
```
在原数据格式data中的cut字段，用逗号来拆分为新字段final，name不变
请教该如何操作

Output:
基本思路：把 `cut` 拆分之后进行一次映射，可以拿到每个原始对象对应的一个数组，组合起来就是一个二维数据；再把这个二维数据展开，就是你要的答案。
`flatMap` 就是先映射再展开
```
const data = [{ name: 'apple', cut: 'a,b,c' }, { name: 'trigger', cut: 'a,g' }];

const data1 = data.flatMap(it =>
    it.cut.split(",")
        .map(s => ({ name: it.name, final: s }))
);

console.log(data1);
```


Instruction:
每日百万数据量的订单表如何导出到excel
需求是这样的：系统每日会产生上百万的成交订单，客户需要每天导出一份给他们，因此需要每天生成一份大数据量的excel。
首先想到的就是在定时任务中通过for循环分页访问数据库，然后分批导出到excel。但是for循环中访问数据库，如果测试不充分或者程序有bug会导致频繁访问数据库，会严重影响数据库的性能。其实在循环中访问数据库本来就是一种不好的习惯。
有什么好的方案或者建议吗？

Output:
我貌似get到了您的想法
总得来说就是觉得数据已经存进去了，但由于导出`excel`，需要再循环查询数据读出来，感觉有点"多此一举"，这个多此一举导致了循环访问数据库，对此感到不安
那我提供一种思路，不一定能解决你的问题，但是或多或少是一种思路叭
即：能不能在插入订单数据的同时也能发个通知，也就是做个消息中间件，这样消费者就是`execl`导出服务，读取消息直接此时就写入到`excel`中
当然那肯定要准备一个消息中间件了，看你百万的数据量，肯定`kafka`没跑了，至于如何往`kafka`里扔消息，这里面有两种方案可以提供给你

1. 在插入订单的代码中新增一个消息发布
2. 做数据库的CDC（Change data capture）处理，也就是数据库的数据变更捕捉处理

方案1 那就是很简单啦，直接加代码，但是呢由于要在之前的逻辑里加东西，那就不好说了，毕竟开闭原则嘛，修改以前的逻辑势必会带来一些风险
方案2 这就基本不用改以前的代码了，毕竟做的是`CDC`，当然不知道你们用的什么数据库，那`CDC`的具体方案就不一样了，如果以`mysql`举例，当然是基于它的`binlog`来做处理咯，随便搜一搜一大堆，你可以自己造轮子，也可以用别人早已经造好的，当然造好的确实需要花一些代价去学习啦。不过呢不用硬生生修改之前的逻辑，主要就是去解析增量的数据库日志就可以了
当然也许你会问，主动去解析日志文件跟去循环查询数据库不是还是差不太多么？
no no no，有些数据库是支持响应式的操作的，就是你主动查和数据库主动推送给你的区别，比如解析`mysql binlog`的工具`Maxwell`，好家伙，它就是伪装成`Slave`，这不就可以从`Master`节点获取到`binlog`了嘛，从而再发出来，如果发给`kafka`，你再做一个消费者服务，不就可以了么
总之`CDC`是一种数据集成方法吧，不同数据库实现`CDC`的方法并不相同，当然其实早已经有一个库整合了不少主流数据库，然后集成了自己一套`CDC`的接口，你可以去看看debezium，不过这玩意儿，我自己装起来很头大，后面公司最终的方案也没有用`debezium`，还是找到了我们自己使用的数据库的官方响应`API`完成的
仅做参考，希望对您有帮助，不过最后说一下，您提到："频繁访问数据库，会严重影响数据库的性能"
影响性能根本原因就是读写操作是一个库嘛，所以你也可以考虑分库啊，读写分离啊，是吧，就是导出专门是一个只读从库就可以了嘛，和主库分开部署，这样即使你现在这样做，频繁访问数据库其实影响也不大，如果还有很大影响，说明你从库的机器配置太低了。。。叭


Instruction:
请问现在那个使用那个跨前端技术会比较好。
React Native / Weex / Flutter / uni-app 如何选择好呢

Output:
ReactNative 适合有一定 React 前端基础的人。不过性能瓶颈是天坑，稍微复杂一点儿的组件还是得写原生配合。胜在出生较早，生态相对完善，社区活跃。
Flutter 是用得 Dart 基本就是重学一门语言了，但性能要比 RN 强很多。出生虽比 RN 晚，但后发制人，社区也很活跃。
uni-app 严格意义上来说不是跨端 App，只是 Web 浏览器套壳。你写 Web 有啥瓶颈，它就有啥瓶颈。（别说它也封装了一些 Native API，性能还不如 RN 呢）。
Weex 还活着？


Instruction:
美团前端二面，读代码题求解
```
var a = 0;
if (true) {
    a = 1;
    function a() {}
    a = 21;
    console.log(a);
}
console.log(a);
```
求两次 console 出来的值。
答案是21 1。
本菜鸡想了很久也没想明白第二个为啥是1。。
求大佬解惑 ?

Output:
21 1 的输出结果不完全正确，在不同的浏览器下结果不同
在safari下结果为21 21
在chrome下结果为21 1
同时ECMAScript规范中说函数声明可以嵌套在条件语句块内，但是其运行的结果依赖于JS解析器的实现，其结果具有不确定性,不推荐在生产环境下使用


Instruction:
JavaScript 两个对象大小比较的机制？
偶然见看到的一个关于类型转换的题目：
对象 ab 是两个字面量函数，在进行比较的时候，可以发现大小和相等的比较结果都是 `false`
```
var a = {b: 42};
var b = {b: 43};
```
```
a < b; //false
a == b; //false
a > b; //false

a <= b; //true
a >= b; //true
```
在这个过程之，a 和 b 比较的时候，到底比较的是什么？为什么 <=> 三个运算符都是 false。？
为什么 `a<=b` 是 true？
`a<=b == true` 是因为 JS 计算的是 `!(a>b)` 吗？

Output:
ES 规定如此。
`==`、`!=` 不说了，基础问题了；说下 `>`、`<` 这种吧，最后都会转换为数值形式做比较。
首先尝试调用对象的 `Symbol.toPrimitive` 方法得到原始值。
如果没有这个方法就再尝试调用 `valueOf`。
经过以上转换后，如果两边都是 `string`，则按 Unicode 逐位比较；否则，都强转成 `number` 比较。
`Object` 强转后就变成了 `NaN`。`NaN` 是个特殊的 `number`，它跟任意数（包括它自己）做任何比较运算，恒为 `false`。
至于 `>=`、`<=` 你说的对，确实是取反。
P.S. 完整讲述可以自己搜索一下 ECMA-262 文档中关于 Abstract Relational Comparison 的相关定义：https://tc39.es/ecma262/#sec-abstract-relational-comparison


Instruction:
关于实际代码中如何用策略模式处理频繁的 if else 的问题
直接上代码吧 都在代码里写清楚了
问题就是
如何把函数中 tabs.filter.forEach 这些几乎相同的逻辑 独立出来 之前学习了策略模式 但是想不到好的方案 请大佬指点一二
```
let tabs = [{index:0,name:'angelaBaby'},{index:1,'陈冠西'},{index:2,'李bingbing'},{index:3,'范特西'}]
let COMMAND_TYPE_LIST = {
    OTHER:'other',
    RIGHT:'right',
    SELF:'self',
}

/**
 * @desc 抽中的成员逻辑
 * @param {*} type:string  - 抽中的类型
 * @param {*} randomIndex:number - 抽中的数组 index
 * @example
 * 比如 type==='other' randomIndex=1 那么抽中的成员就是 0,2,3
 * 比如 type==='right' randomIndex=1 那么抽中的成员就是 2,3
 * 比如 type==='self' randomIndex=1 那么抽中的成员就是 1
 * @todo
 * 如何把 tabs.filter.forEach 这些几乎相同的逻辑 独立出来 之前学习了策略模式 但是想不到好的方案 请大佬指点一二
 */
function checkedPerson(type,randomIndex){
    if (type === COMMAND_TYPE_LIST.OTHER) {
        //抽中其他
        tabs
            .filter((item, index) => index !== randomIndex)
            .forEach((tab) => {
                //循环处理逻辑
            })
    } else if (type === COMMAND_TYPE_LIST.RIGHT) {
        //抽中右侧
        tabs
            .filter((item, index) => index > randomIndex)
            .forEach((tab) => {
                //循环处理逻辑
            })
    } else if (type === COMMAND_TYPE_LIST.SELF) {
        //抽中自身
        tabs
            .filter((item, index) => index === randomIndex)
            .forEach((tab) => {
                //循环处理逻辑
            })
    }
}
checkedPerson(COMMAND_TYPE_LIST.OTHER,2)//抽中的成员就是 0,1,3

```

Output:
解耦最终操作放在外面，可用性更高点
```
function checkedPerson1(type,randomIndex) {
    const other = (randomIndex, index) => index !== randomIndex;
    const right = (randomIndex, index) => index > randomIndex;
    const self = (randomIndex, index) => index === randomIndex;
    const dict = {
        other,
        right,
        self
    }
    return tabs.filter((item, index) => dict[type](randomIndex, index));
}
checkedPerson1('other', 1).forEach(item => {
    console.log(item);
});
```


Instruction:
.ts文件识别不了.vue 文件？
main.ts
```
import Vue from "vue";
import Component from "vue-class-component";
import App from "./App.vue";
```
报这个错误
Cannot find module './App.vue' or its corresponding type declarations.
tsconfig.json
```
{ // 编译选项
  "compilerOptions": {
    // 编译输出目标 ES 版本
    "target": "esnext",
    // 采用的模块系统
    "module": "esnext",
    // 以严格模式解析
    "strict": false,
    "jsx": "preserve",
    // 从 tslib 导入外部帮助库: 比如__extends，__rest等
    "importHelpers": true,
    // 如何处理模块
    "moduleResolution": "node",
    // 启用装饰器
    "experimentalDecorators": true,
    "esModuleInterop": true,
    // 允许从没有设置默认导出的模块中默认导入
    "allowSyntheticDefaultImports": true,
    // 定义一个变量就必须给它一个初始值
    "strictPropertyInitialization" : false,
    // 允许编译javascript文件
    "allowJs": true,
    // 是否包含可以用于 debug 的 sourceMap
    "sourceMap": true,
    // 忽略 this 的类型检查, Raise error on this expressions with an implied any type.
    "noImplicitThis": false,
    // 解析非相对模块名的基准目录
    "baseUrl": ".",
    // 给错误和消息设置样式，使用颜色和上下文。
    "pretty": true,
    // 设置引入的定义文件
    "types": ["webpack-env", "mocha", "chai"],
    // 指定特殊模块的路径
    "paths": {
      "@/*": ["src/*"]
    },
    // 编译过程中需要引入的库文件的列表
    "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
    "typeRoots": [
      "./types",
      "./node_modules/vue/types",
      "./src"
    ],
  },
  // ts 管理的文件
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  // ts 排除的文件
  "exclude": ["node_modules"]
}
```
shims-vue.d.ts
```
import Vue from "vue";
import VueRouter, { Route } from "vue-router";

declare module '*.vue' {
  export default Vue
}

declare module "vue/types/vue" {
  interface Vue {
    $router: VueRouter; // 这表示this下有这个东西
    $route: Route;
    $http: any;
    $Message: any;
    $Modal: any;
  }
}
```
第一次用ts写vue，不知道为什么报这个错误，
.vue文件里能识别.vue文件,.ts文件里就识别不了，但是页面能正常打开
package.json
```
{
  "name": "scgx",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "start": "vue-cli-service serve",
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "test:unit": "vue-cli-service test:unit"
  },
  "dependencies": {
    "axios": "^0.18.0",
    "element-ui": "^2.13.2",
    "vue": "^2.6.6",
    "vue-class-component": "^6.0.0",
    "vue-property-decorator": "^7.0.0",
    "vue-router": "^3.0.1",
    "vuex": "^3.0.1"
  },
  "devDependencies": {
    "@types/chai": "^4.1.0",
    "@types/mocha": "^5.2.4",
    "@vue/cli-plugin-babel": "^3.5.0",
    "@vue/cli-plugin-eslint": "^3.5.0",
    "@vue/cli-plugin-typescript": "^3.5.0",
    "@vue/cli-plugin-unit-mocha": "^3.5.0",
    "@vue/cli-service": "^3.5.0",
    "@vue/eslint-config-prettier": "^4.0.1",
    "@vue/eslint-config-typescript": "^4.0.0",
    "@vue/test-utils": "1.0.0-beta.29",
    "babel-eslint": "^10.0.1",
    "babel-plugin-component": "^1.1.1",
    "chai": "^4.1.2",
    "eslint": "^5.8.0",
    "eslint-plugin-vue": "^5.0.0",
    "less": "^3.0.4",
    "less-loader": "^4.1.0",
    "typescript": "^3.2.1",
    "vue-template-compiler": "^2.5.21",
    "vuex-class": "^0.3.2"
  }
}
```
vue.config.js
```
const path = require("path");
const sourceMap = process.env.NODE_ENV === "development";

module.exports = {
  // 基本路径
  publicPath: "./",
  // 输出文件目录
  outputDir: "dist",
  // eslint-loader 是否在保存的时候检查
  lintOnSave: false,
  // webpack配置
  // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
  chainWebpack: () => {},
  configureWebpack: config => {
    if (process.env.NODE_ENV === "production") {
      // 为生产环境修改配置...
      config.mode = "production";
    } else {
      // 为开发环境修改配置...
      config.mode = "development";
    }

    Object.assign(config, {
      // 开发生产共同配置
      resolve: {
        extensions: [".js", ".vue", ".json", ".ts", ".tsx"],
        alias: {
          vue$: "vue/dist/vue.js",
          "@": path.resolve(__dirname, "./src"),
          "@c": path.resolve(__dirname, "./src/components"),
          utils: path.resolve(__dirname, "./src/utils"),
          views: path.resolve(__dirname, "./src/views"),
          assets: path.resolve(__dirname, "./src/assets"),
          com: path.resolve(__dirname, "./src/components")
        }
      }
    });
  },
  // 生产环境是否生成 sourceMap 文件
  productionSourceMap: sourceMap,
  // css相关配置
  css: {
    // 是否使用css分离插件 ExtractTextPlugin
    extract: true,
    // 开启 CSS source maps?
    sourceMap: false,
    // css预设器配置项
    loaderOptions: {},
    // 启用 CSS modules for all css / pre-processor files.
    modules: false
  },
  // use thread-loader for babel & TS in production build
  // enabled by default if the machine has more than 1 cores
  parallel: require("os").cpus().length > 1,
  // PWA 插件相关配置
  // see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
  pwa: {},
  // webpack-dev-server 相关配置
  devServer: {
    open: process.platform === "darwin",
    host: "localhost",
    port: 3001, //8080,
    https: false,
    hotOnly: false,
    proxy: {
      // 设置代理
      // proxy all requests starting with /api to jsonplaceholder
      "/api": {
        target: "http://localhost:8989/",
        changeOrigin: true,
        ws: true,
        pathRewrite: {
          "^/api": ""
        }
      }
    },
    before: app => {}
  },
  // 第三方插件配置
  pluginOptions: {
    // ...
  }
};

```

Output:
不要再shims-vue.d.ts中最外层使用import，使用这种写法
```
declare module '*.vue' {
  import Vue from 'vue';
  export default Vue;
}

declare module "vue/types/vue" {
  import VueRouter, { Route } from 'vue-router';
  interface Vue {
    $router: VueRouter; // 这表示this下有这个东西
    $route: Route;
    $http: any;
    $Message: any;
    $Modal: any;
  }
}
```


Instruction:
webpack使用CopyWebpackPlugin插件一直报错，麻烦大佬看看？
```
const CopyWebpackPlugin = require("copy-webpack-plugin");
const path = require("path");

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
  module: {
    rules: [],
  },
  plugins: [
    new CopyWebpackPlugin([
      // {output}/file.txt
      { from: path.resolve(__dirname, './src/assets/'), },
    ]),
  ],
};
```
一直给我提示这个错误，我想知道到底错在哪？按照文档上配的，百度、google都没这个错误的。大致意思是缺少`{ from: path.resolve(__dirname, './src/assets/'), }`配置，我现在实在找不到错误在哪，麻烦大佬指明一下
```
Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
 - options[0] misses the property 'patterns'. Should be:
   [non-empty string | object { from, to?, context?, globOptions?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)
ValidationError: Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
    at validate (D:\vscode-workspace\brower-manager\node_modules\copy-webpack-plugin\node_modules\schema-utils\dist\validate.js:88:11)
    at new CopyPlugin (D:\vscode-workspace\brower-manager\node_modules\copy-webpack-plugin\dist\index.js:24:30)
    at Object.<anonymous> (D:\vscode-workspace\brower-manager\webpack.common.js:14:5)
    at Module._compile (D:\vscode-workspace\brower-manager\node_modules\v8-compile-cache\v8-compile-cache.js:192:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1153:10)
    at Module.load (internal/modules/cjs/loader.js:977:32)
    at Function.Module._load (internal/modules/cjs/loader.js:877:14)
    at Module.require (internal/modules/cjs/loader.js:1019:19)
    at require (D:\vscode-workspace\brower-manager\node_modules\v8-compile-cache\v8-compile-cache.js:161:20)
    at Object.<anonymous> (D:\vscode-workspace\brower-manager\webpack.dev.js:2:16)
    at Module._compile (D:\vscode-workspace\brower-manager\node_modules\v8-compile-cache\v8-compile-cache.js:192:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1153:10)
    at Module.load (internal/modules/cjs/loader.js:977:32)
    at Function.Module._load (internal/modules/cjs/loader.js:877:14)
    at Module.require (internal/modules/cjs/loader.js:1019:19)
    at require (D:\vscode-workspace\brower-manager\node_modules\v8-compile-cache\v8-compile-cache.js:161:20)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! brower-manager@1.0.0 dev: `webpack --config webpack.dev.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the brower-manager@1.0.0 dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

```

Output:
仔细看错误信息，缺少了 `patterns` 字段。实际上 copy-webpack-plugin 从 6.0 以后，把配置改成了
```
new CopyWebpackPlugin(
  patterns:
    [
      { from: path.resolve(__dirname, './src/assets/'), },
    ]
  ),
)
```


Instruction:
前端路由是全部都由后端返回，还是后端返回对应角色下的权限，然后前端通过遍历的方式来修改当前路由呢？
在看vue-element-admin中有个权限验证，现在不知道这2者有啥区别，请大佬说说有什么好的方式来处理这个动态路由
https://panjiachen.github.io/...

Output:
第一种后台返回路由，第二种后台返回权限。
共同点：
- 两种方法都可以实现需求
- 前端都要维护一份路由地址与模块文件地址的映射
- 后段返回的数据一般都要再遍历做二次处理
- 有关页面内元素（按钮）的权限都要另做处理
- 技术点都会涉及路由守卫和路由鉴权

差异点：
- 默认路由列表：方法一只维护home、login等无权限需求路由，其他路由需要后续通过接口和路由api：`addRoutes`动态添加；方法二需要维护一个全量的路由列表，不需要额外添加路由，通过配置每个路由的access数组来做鉴权。
- 路由跳转：因为方法一返回的就是该用户权限下的路由，所以不需要再做权限鉴权；方法二需要。
- 路由的自定义程度：方法一可以通过修改数据库的路由数据来自定义前端的菜单结构，因此也需要做一个实现路由重组的递归函数，拓展性更好；方法二针对的是菜单结构相对稳定的项目，一般不支持结构变动。
- 返回报文：一般来说，返回报文大小 方法一比方法二要大


Instruction:
promise then 的回调函数是在什么时候进入微任务队列的？
promise then 的回调函数是在遇到 resolve 语句的时候就被加入微任务队列，还是在遇到 then 语句的时候被加入到微任务队列？
在网上查了一些资料，发现有不同的说法：
1. 比如在《深入理解ES6》中文版 244 页里是这么说的：“调用 resolve( ) 后会触发一个异步操作， 传入 then( ) 和 catch( ) 方法的函数会被添加到任务队列中并异步执行”，所以 then 方法的回调应该是在调用 resolve 后就被加入到队列中的？
2. 对应的英文版原文是这么说的：“Calling resolve() triggers an asynchronous operation. Functions passed to then() and catch() are executed asynchronously, because these are also added to the job queue”
这个是知乎的回答：https://www.zhihu.com/question/62305365
这个是 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”
1、2 都认为 then 的回调函数是在遇到 resolve 语句的时候就被加入微任务队列，3、4 都认为是在遇到 then 语句的时候被加入到微任务队列的。到底哪一种说法是正确的呢？

Output:
都没问题。
关键在于，`then` 是在 `resolve` 之前被调用的，还是 `resolve` 之后呢？
`then` 在 `resolve` 之前，`then` 不会加微任务，而是缓存起来，`resolve` 看到缓存里又 `then` 的回调，于是加微任务。
`resolve` 在 `then` 之前，`resolve` 的时候还没有任何回调要执行，自然不会加微任务。`then` 的时候发现已经 fullfilled ，于是直接加微任务。
也就是说，他们都有可能加，也都有可能不加，就看调用时的 promise 的状态了。
你的引用有些只说明了其一，但是说明里条件写得还是很清楚的，比如 4 里 "because the promise is already fulfilled"


Instruction:
JS怎么获取变量名称（反射）
JS中怎么在程序执行的时候，获取变量名称。
比如通过一个函数返回指定参数的参数名。
```
jsvar paramName = 'asdf' // 不管等于什么。
var paramName2 = new Object(); // 不管等于什么。

function getParamName(p) {
    // ...实现过程
    var result = ...; // 这里只是模拟
    return result;
}

getParamName(paramName);
getParamName(paramName2);

```
最终参数的返回结果应该为：
```
output  Output:
  paramName
  paramName2

```
请问，类似的需求怎么实现，有没有变通的方法？
看了一下，感觉 http://segmentfault.com/q/1010000002761696#a-1020000002765874 说的比较合理。

Output:
2017.1.5 答案已重写
每一个上下文都有一个与之对应的变量对象，任何声明的变量都是这个变量对象的属性。全局上下文的变量对象是全局对象，因而在全局声明的变量就变成了全局对象的属性。相应地，函数上下文的变量对象是活化对象，在函数上下文声明的变量是活化对象的属性。然而，活化对象是引擎内部的一个对象，不可被外部访问，因而不可在 JS 中获取函数上下文变量的名称。
此外基本类型的函数实参是以传值的方式传入函数的，对象类型的实参是以引用的方式传入函数的，无论哪种方式，函数都只能得到传入的值或者引用，而无法访问调用函数的上下文的变量对象，因而不能在函数内部获得传入函数的变量的名称。
既然没有函数能够返回调用这个函数的上下文中变量的名称，JS 也没有提供能做到这件事的操作符，那么在执行上下文内部获取该执行上下文内部变量的名称也就是不可能的。
当然啦，对于函数代码的执行上下文，如果我们能获得这个函数的代码，就可以解析这段代码得到这段代码当中变量的名称。
示例代码：
```
function getParamName() {}

function fn() {
  var param1 = 0
  var a = 2

  console.log(getParamName(param1))
  console.log(getParamName(a))
}

function callWithVariableName(fn) {
  eval('(' + fn.toString().replace(/\bgetParamName\s*\(([a-zA-Z_$][\w_$]*)\)/g, function(u, v) {
    return "'" + v + "'"
  }) + '())')
}

callWithVariableName(fn)

```
控制台输出：
```
param1
a
```


Instruction:
在DolphinDB中，如何对连续的相同值分组
比如有表如下：
```
t = table(1 1 1 1 2 2 2 2 1 1 1 1 3 3 3 as bs_flag)
```
希望根据 bs_flag 进行分组，连续相同的 bs_flag 的行group 为一组
 即希望分组后是
1
2
1
3
如何写sql语句？

Output:
可以用
```
select first(bs_flag)  from t group by segmentby(first, bs_flag.rowNo(), bs_flag)
```
或
```
select first(bs_flag), first(bs_flag.rowNo()) from t group by eachPre(ne, bs_flag).cumsum()
```


Instruction:
DolphinDB的流数据表怎么查询
我有一个流数据表，然后
```
enableTableShareAndPersistence(table, tableName, [asynWrite=true], [compress=true], [cacheSize=-1], [retentionMinutes=1440], [flushMode=0])
```
我把cacheSize 设为100,000.
现在假设流进来的数据已经超过了100,000行, 也就是部分数据已经存入persisenceDir。如果用select * from tableName会不会返回所有的行？
问的原因，是因为我在考虑要不要单独建一个实时数据仓，来query所有已经流进来的数据。

Output:
用select * from tableName不会返回所有的行。默认情况下，流计算的表把所有数据保存在内存中。如果流数据表太大，系统可能会出现内存不足的情况。为了避免内存不足的问题，我们可以设置缓存大小的界限。如果流数据表的行数达到这个界限，前面一半的记录行会从内存中清理。
可以用getPersistenceMeta(table)观察一下。


Instruction:
在DolphinDB中怎么拼接Matrix
如果我有一个结果是一个ANY 向量,他的每一个元素是shape相同的Matrix,我怎么样可以把他合并成一个大的Matrix?  最好是纵向拼接,列数不变增加行数。

Output:
横向拼接两个矩阵：
a = 1..4$2:2
b = 1..4$2:2
a.join(b)
纵向拼接：用 a.transpose().join(b.transpose()).transpose()
假设ANY vector c，如下
```
c = [a, b]
def transposeJoin(a, b) {
  return a.transpose().join(b.transpose()).transpose()
}
reduce(transposeJoin, c)
```


Instruction:
提问关于 mysql得联合主键和复合主键的问题
如下sql：
CREATE TABLE `film_actor` (
`actor_id` smallint(5) unsigned NOT NULL,
`film_id` smallint(5) unsigned NOT NULL,
`name` varchar(50)  NOT NULL,
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`actor_id`,`film_id`) USING BTREE,
  KEY `idx_fk_film_id` (`film_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
（一）`primary key` 是联合主键还是复合主键，我个人理解的是联合主键，毕竟`actor_id`不是自增的？但是针对`actor_id`和`film_id`设值时，只能1-1的for primary key。
（二）但是如果`actor_id`设有自增`auto_increment`，然后`primary key`是 `primary key(actor_id,film_id)`这种是联合还是复合？
（三）又或者设有自增的`actor_id`，`primary key(actor_id,name)`是复合还是联合？求大神解答一下疑惑，谢谢

Output:
这个问题要是问外国开发者，TA们能一脸懵逼。
在英文语境中只有 `Composite Primary Key`（也有叫 `Compound Primary Key` 的），就是一个表中如果是多个字段组成一个主键，那么这个主键就被称为这玩意儿。
至于这玩意儿你翻译成“联合主键”、“组合主键”、“混合主键”还是“复合主键”，都特么是一回事儿。
结果到了中文编程界，不知道是哪位神仙起的头儿，非得编个“联合主键”和“复合主键”的区别出来。再加上中文编程界有一大特点，就是博客或者问答习惯性东抄西搬，结果错的知识也能流传广泛甚至成为“主流”。
搬一个“流传最广”的对于“联合主键”和“复合主键”区别的文章：
“联合主键”还是单一主键，只不过往往用在关联表里，一个关联表里会涉及到多个其他表的主键组合形成一条数据，你既可以为它们设置一个“复合主键”、也可以再新加一个自增列设为“联合主键”。
举例：
```
--- 学生表
CREATE TABLE `student` (
    `student_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `name` varchar(20) NOT NULL,
    PRIMARY KEY (`student_id`) USING BTREE
);

--- 科目表
CREATE TABLE `subject` (
    `subject_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `name` varchar(20) NOT NULL,
    PRIMARY KEY (`subject_id`) USING BTREE
);

--- 分数表，用所谓的“复合主键”
CREATE TABLE `score` (
    `student_id` int(10) unsigned NOT NULL,
    `subject_id` int(10) unsigned NOT NULL,
    `value` int(10) unsigned NOT NULL,
    PRIMARY KEY (`student_id`, `subject_id`) USING BTREE
);

--- 分数表，用所谓的“联合主键”
CREATE TABLE `score` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `student_id` int(10) unsigned NOT NULL,
    `subject_id` int(10) unsigned NOT NULL,
    `value` int(10) unsigned NOT NULL,
    PRIMARY KEY (`id`) USING BTREE,
    UNIQUE INDEX `un`(`student_id`, `subject_id`) USING BTREE
);
```
写在最后：
再次重申，这种概念是中文编程界（或者说是中文编程博客界）人为造出的。
上面的例子看看就得了，根本就是胡编一个 `联合主键` 的定义出来，你会发现它其实就是一个最简单的自增主键，只不过表的逻辑上 `student_id` + `subject_id` 是唯一的，`id` 就成了所谓的二者的 `联合主键`。


Instruction:
new Promise((resolve)=>{resolve()}) 与 Promise.resolve() 等价吗
### 处理以下类型的时候这个两个方法感觉差不多
参数是一个 Promise 实例
参数是一个thenable对象
参数不是具有then方法的对象，或根本就不是对象
但我看有人说：`promise.resolve(v)`不等于`new Promise(r => r(v))`，因为如果 v 是一个 Promise 对象，前者会直接返回 v，而后者需要经过一系列的处理（主要是 PromiseResolveThenableJob）

Output:
## 我自己做了一个详细的测试
先说结论：在v是一个promise实例的时候，`promise.resolve(v)`与`new Promise(r => r(v))`有明显的差异
区别表现：new Promise(r => r(v))的.then()回调会被推迟两个时序（事件循环）
原因：new Promise(r => r(v))里浏览器会创建一个 PromiseResolveThenableJob 去处理这个 Promise 实例，这是一个微任务。具体分析如下
```
    // v是一个实例化的promise，且状态为fulfilled
    let v = new Promise(resolve => {
      console.log("begin");
      resolve("then");
    });

    // 在promise里面resolve一个状态为fulfilled的promise

    // 模式一 new Promise里的resolve()
    // begin->1->2->3->then->4 可以发现then推迟了两个时序
    // 推迟原因：浏览器会创建一个 PromiseResolveThenableJob 去处理这个 Promise 实例，这是一个微任务。
    // 等到下次循环到来这个微任务会执行，也就是PromiseResolveThenableJob 执行中的时候，因为这个Promise 实例是fulfilled状态，所以又会注册一个它的.then()回调
    // 又等一次循环到这个Promise 实例它的.then()回调执行后，才会注册下面的这个.then(),于是就被推迟了两个时序
    new Promise(resolve => {
      resolve(v);
    }).then((v)=>{
        console.log(v)
    });

    //  模式二 Promise.resolve(v)直接创建
    // begin->1->then->2->3->4 可以发现then的执行时间正常了，第一个执行的微任务就是下面这个.then
    // 原因：Promise.resolve()API如果参数是promise会直接返回这个promise实例，不会做任何处理
/*     Promise.resolve(v).then((v)=>{
        console.log(v)
    }); */

    new Promise(resolve => {
      console.log(1);
      resolve();
    })
      .then(() => {
        console.log(2);
      })
      .then(() => {
        console.log(3);
      })
      .then(() => {
        console.log(4);
      });
```


Instruction:
上海字节跳动一道关于http缓存的面试题
首先这个问题是http的缓存，我答了强缓存和协商缓存。
我说道协商缓存，是会请求到后端服务器，然后对比响应头last-modified或者etag，来决定时候使用缓存。
此时面试官问我，已经请求到后端了，为什么还要再去取缓存，而不是直接使用response，我就没答出来。
网上搜了很多，主要还是都是介绍2种缓存的，并没有提到这个问题，望解答！

Output:
我猜你说的 response 指的是 response body？
协商缓存如果命中返回的是 304 啊……只有 header 没有 body。
虽然还是请求了一次服务器，但只需要传输 header 部分就可以了，节省了传输文件本身的开销。


Instruction:
如何高效的监控多台服务器，该做哪些方面的监控？
系统的服务器多了，独立运行的服务进程多了，服务进程间的通讯多了，该做那些监控，该怎么监控？有没有什么成熟的思想想法？

监控是不是可以分为2个方面：1）系统级别的监控(cpu,memory,io,disk,net)，服务是否存活

2)应用级别（各子系统业务相关异常监控）

具体的，怎么来实现这个监控，做到一个可灵活配置、扩展的插件式监控平台？感觉还是比较棘手
查阅了资料后，我打算先这么做：

1：Nagios作为CPU、内存、硬盘等各个基本非业务的监控

2：各个业务模块做自己相关的监控：服务异常监控、服务统计信息等

1）服务异常信息通过mq异步的发送给监控主服务器，由监控主服务器统一处理

2）服务统计信息先在本地模块内存汇总，然后定时间隔的发送给监控主服务器进行持久化等相关处理

Output:
`以下都是自己想到什么写什么

监控从方向来分为：　系统级别监控和业务逻辑层监控。一般的开源软件都是面向系统软件级别的监控，　不可能会有业务逻辑的监控；　业务逻辑的监控因为不同的应用而不同，　这个需要程序员预留接口可以进行监控，　运维是可以提需求的。

监控从功能上分为：　报警监控和性能监控。　报警监控，就像大家说的nagios是非常好的开源软件，　其实nagios提供的也是一种监控的框架，　所以他比较的灵活；　性能监控，　主要是用来查看变化趋势,　可以更好的找到问题,　或者提早发现问题,　有时候因为报警的阀值是需要不断的调整才能到最佳状态,像cacti和ganglia

监控的选择　一般要看你的服务器分布:

如果是分布式的机房,　机房很多,　那么对集中监控和处理要求比较高,　ganglia本身就有分布式特性,　是第一选择;　nagios需要再做些插件的优化和结构调整才能更好的支持分布式的需求.　因为分布式面临的问题是集中管理和可靠性,　可靠性:　网络传输可能出现的问题都要避免监控，才能让监控准确;　集中管理:　才可以减少工作量

如果是集中的,　在量很大的情况下还是建议使用ganglia,　如果小其它的很多监控都可以选择,　报警监控还是用nagios,　好像很少有他这样灵活的工具,　但一定要将配置改成最适合自己环境的,　并且最简单和快速的配置　需要自己制定一些规则会比较好。

如果说要监控配合的外围工具:　像短信报警　邮件　都需要自己做些工具会比较好　,都是为了保证报警的可靠性　监控前期一定要多关注是否跟上了需求　要做很多的调整　不是说搭建了就万事大吉了.
评下你的做法

查阅了资料后，我打算先这么做：

1：Nagios作为CPU、内存、硬盘等各个基本非业务的监控

＃其实nagios也可以监控业务逻辑　主要是首先要知道要监控哪些业务逻辑　再程序方面是否有相应的接口　如果没有是否可以做　再自己写一些相应的脚本　nagios和ganglia都可以很方便的写脚本。最关键的还是监控需求和程序的支持情况

2：各个业务模块做自己相关的监控：服务异常监控、服务统计信息等

1）服务异常信息通过mq异步的发送给监控主服务器，由监控主服务器统一处理

＃你应该说的是自己写监控再通过队列发送给主服务,如果是同机房当然还是写nagios的插件会比较好,这样是统一管理,而只需要写插件;　如果是机房是分布的,可以考虑nagios之间的消息传递写一些脚本完成,自己写的话是时间问题和管理上不统一的麻烦。

2）服务统计信息先在本地模块内存汇总，然后定时间隔的发送给监控主服务器进行持久化等相关处理

＃这一部分我建议是分成两部分:　第一部分是服务器基本信息,　像cpu　内存　硬盘　这些不会变化的可以间隔很长时间,　其实ganglia默认就有系统硬件的所有信息，　只是如果想放到表格里面对比就差些了；　反而对于系统用户　磁盘容量　各种配置文件　如计划任务　打开的服务　自启动的内容可以定时的执行和收集,　这个应该属于备份了,　但如果所有的配置集中处理之后,像使用puppet或者其它配置工作,这些都不需要做了。


Instruction:
java 如何通过反射修改类的私有方法
网上能找到的都是修改私有变量, 访问私有方法, 我想要修改私有方法, 请问如何操作?

Output:
反射是不能修改方法的，但是可以使用修改字节码的方式来实现修改。
使用javassist工具在类加载器加载这个类之前修改他的字节码。
比如修改这个方法的字节码：
org.jboss.resteasy.core.InjectorFactoryImpl.createMethodInjector()
```
ClassPool pool = new ClassPool(true);
CtClass ct = pool.getCtClass("org.jboss.resteasy.core.InjectorFactoryImpl");// 加载这个类
// 获取被修改的方法
CtMethod m = ct.getDeclaredMethod("createMethodInjector");
m.setBody("return \"已经被修改！\""); // 直接修改方法体
// 转为class
ct.toClass();
// 释放对象
ct.detach();
```


Instruction:
JS树结构的遍历、创建
这样树结构的数组：
```

let tree =[
     {id: '1',
        title: '节点1',
        children: [
          {
            id: '1-1',
            title: '节点1-1',
            children: [
              {
                id: '1-1-1',
                title: '节点1-1-1'
              },]
          },
          {
            id: '1-2',
            title: '节点1-2'
          }
        ]
      },
      {
        id: '2',
        title: '节点2',
        children: [
          {
            id: '2-1',
            title: '节点2-1'
          }
        ]
      }
    ]

```
我想把其中的某项取出创建新的数组，结构不变，例如这样
```
  getTree =[
     {
        title: '节点1',
        children: [
          {
            title: '节点1-1',
            children: [
              {
                title: '节点1-1-1'
              },]
          },
          {
            title: '节点1-2'
          }
        ]
      },
      {
        title: '节点2',
        children: [
          {
            title: '节点2-1'
          }
        ]
      }
    ]

```
不知道怎么写，不知道描述清楚没，我是新手，不耻下问啊...

Output:
你可以先了解一下什么是 递归
这个需求通过递归可以很轻易实现
```
function getTree(ary) {
  return ary.map(v => {
    const item = {
      title: v.title,  //这是创建的新对象 根据需要的键随意更改
    };
    if (v.children) item.children = getTree(v.children);
    return item;
  });
}
```
```
const newTree = getTree(tree);
console.log(newTree)
```


Instruction:
如何让一个元素hover时，让指定区域的产生背景色，在线等？
### 问题描述
现在一个div高为50px宽为200px，我想让它hover时，只让这个div的高为40px，宽为200px的区域产生背景色，切要居中
### 相关代码
css
```
div{
    height: 50px;
    width: 200px;
    background: slategrey;
}
div:hover{
    /*background: red;*/
}
```
html结构
```
<div>
    TEST
</div>
```
### 有什么解决方法吗？

Output:
```
div:hover {
  background: linear-gradient(to bottom,slategrey 5px,red 0,red 45px,slategrey 0);
}
```


Instruction:
请问vue或者uniapp如何实现背景色自动根据图片的主色进行渲染？
请问如何实现背景色自动根据图片的主色进行渲染？

Output:
把图片绘制到一个与图片大小相等的 canvas 上，然后在图片上取样，确定图片的主色，把这个色值作为背景色即可。
```
const picUrl = __YOUR_PIC_URL__;
const canvas = document.getElementById('yourCanvasId');
const ctx = canvas.getContext('2d');
const image = new Image();
image.setAttribute('crossOrigin', 'anonymous');
canvas.setAttribute('crossOrigin', 'anonymous');

image.addEventListener('load', e => {
    // image.removeEventListener('load', function(){});
    console.log('image.width:', image.width);
    const WIDTH = image.width;
    const HEIGHT = image.height;
    canvas.height = HEIGHT;
    canvas.width = WIDTH;
    ctx.drawImage(image, 0, 0, WIDTH, HEIGHT);
    const imageData = ctx.getImageData(0, 0, WIDTH, HEIGHT).data;

    // 这里为了简便，采用数组缓存颜色平均值
    // 如果需要进一步提高性能的话，可以使用 ArrayBuffer
    let colorArray = [
        imageData[0],  // red 通道
        imageData[1],  // green 通道
        imageData[2],  // blue 通道
        imageData[3]  // alpha 通道
    ];

    // 开启透明度时，imageData 的每四个值代表一个点的 RGBA值
    for(let cnt = 4; undefined !== imageData[cnt + 3]; cnt += 16){
        colorArray[0] = ((colorArray[0] + imageData[cnt]) >> 1);
        colorArray[1] = ((colorArray[1] + imageData[cnt + 1]) >> 1);
        colorArray[2] = ((colorArray[2] + imageData[cnt + 2]) >> 1);
        colorArray[3] = ((colorArray[3] + imageData[cnt + 3]) >> 1);
    }
    document.getElementById('mainWrap').style.backgroundColor =
      [
      'rgba(',
      ~~colorArray[0],
      ',',
      ~~colorArray[1],
      ',',
      ~~colorArray[2],
      ',',
      colorArray[3] / 255,
      ')'
    ].join('');
});
image.src = picUrl;
```
当然，如果图片不是特别花哨、要求不是特别高的话，可以将背景设为 transparent ，然后将图片设为伪元素的背景，再进行高斯模糊即可：
```
<div class="main-wrap">
</div>

<style>
    .main-wrap{
        background: transparent;
        position: relative;
        z-index: 1
    }
    .main-wrap::before{
        position: absolute;
        top: -100px;
        left: -100px;
        right: -100px;
        bottom: -100px;
        background: center no-repeat;
        background-size: cover;
        background-image: url(__YOUR_PIC_URL__);
        filter: blur(100px);
    }
</style>
```
代码没测试过，但是思路应该还算清晰，我怀疑 JS 不太可能跑得起来，需要多改进，DOM 操作最好改成 ref 引用。
时隔一天回来更新下，JS 代码经简单测试可用了，用例在 codepen。


Instruction:
使用axios发送请求的时候 什么时候算请求出错，什么情况算响应出错
在设置请求拦截器与响应拦截器的时候失败状态下的情况，遇到的一些疑问
```
Axios.interceptors.request.use（config={
    //这里会最先拿到你的请求配置
},err=>{
//这里什么情况下会进来？并且进来之后对你接下来的程序执行有什么影响
}）

Axios.interceptors.response.use（res ={
    //这里会最先拿到你的response
},err=>{
//这里什么情况下会进来？ 并且进来之后对你接下来的程序执行有什么影响
}）
```

Output:
```
Axios.interceptors.request.use（config={
    //这里会最先拿到你的请求配置
},err=>{
  // 这里极少情况会进来，暂时没有找到主动触发的方法，估计只有浏览器不兼容时才会触发，欢迎后面同学补充
  // 看了几个GitHub的issue，有人甚至提出了这个方法是不必要的（因为没有触发的场景），不过还是建议大家按照官方的写法，避免不必要的错误
  // 进来之后没法发起请求
}）

Axios.interceptors.response.use（res ={
    //这里会最先拿到你的response
    // 只有返回的状态码是2xx，都会进来这里
},err=>{
 // 目前发现三种情况会进入这里：
// 1. http状态码非2开头的都会进来这里，如404,500等
// 2. 取消请求也会进入这里，CancelToken，可以用axios.isCancel(err)来判断是取消的请求
// 3. 请求运行有异常也会进入这里，如故意将headers写错：axios.defaults.headers = '123',或者在request中有语法或解析错误也会进入这里
// 进入这里意味着请求失败，axios会进入catch分支
}）
```


Instruction:
一个面试题关于函数的优先级
```
function Foo(){
    getName = function() {
         alert(1)
    };
    return this
};
Foo.getName = function () {
    alert(2)
};
Foo.prototype.getName = function () {
    alert(3)
};
var getName = function () {
    alert(4)
}
function getName() {
    alert(5)
}
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName()；
```
打印出来的结果是？2411233
  但是我想的是 2514211.
  有疑惑的地方

Output:
挺有意思的一道题。
第一个 2 不用多解释，直接用的是 `Foo.getName` 静态方法。
第二个为啥是 4 呢？你会注意到最后有一个 `var getName = funtion() {}` 和一个 `function getName`，后声明的 `function` 咋没覆盖前面的 `var` 呢？因为 `function` 有函数提升，虽然是后声明的，反而会被提到当前作用域最前面去执行。（你可能会说 `var` 不也有变量提升吗？因为 JS 里函数是一等公民，函数提升比变量提升更优先！）
第三个和第四个为啥都是 1 呢？因为没 `new` 所以 `Foo()` 里的返回值 `this` 实际是 `window`，而 `window.getName` 上一步说了因为函数提升的原因，在执行 `Foo()` 之前其实是那个 `var getName`；但 `Foo()` 方法里给这个变量重新赋值了！
第五个是 2 也没啥讲的，虽然有 `new` 了，但 `Foo` 是引用而非调用，所以还是静态方法。
第六个第七个因为有 `new` 了、且调用了 `Foo()`，所以此时实际相当于实例化了一个 `Foo` 类型对象出来，那么后面的 `.getName()` 就是原型链方法了。
P.S. 最后两个连着的 `new` 可能容易迷惑，实际上的执行顺序是：
```
let a = new Foo();
let b = a.getName();
let c = new b;
```


Instruction:
原生js如何获取json字符串中某个对象的内容
有如下json字符串：
```
const str = `
      input: {
        label: "输入框input",
        name: "input",
        option: {
          rules: [{ required: true, message: "Please select your country!" }]
        },
        on: {
          change: e => {
            const { value } = e.target;
            console.log("change", value);
          }
        }
      },
      number: {
        label: "数字输入框",
        name: "input",
        type: "number",
        props: {
          min: 3,
          max: 500
        },
        option: {
          rules: [{ required: true, message: "Please select your country!" }]
        },
        on: {
          change: value => {
            console.log("change", value);
          }
        }
      }
    `;
```
怎样获取其中对象input或者number为字符串的内容，要得到的结果如下
获取input的结果：
```
{
        label: "输入框input",
        name: "input",
        option: {
          rules: [{ required: true, message: "Please select your country!" }]
        },
        on: {
          change: e => {
            const { value } = e.target;
            console.log("change", value);
          }
        }
      }
```
获取number的结果：
```
{
        label: "数字输入框",
        name: "input",
        type: "number",
        props: {
          min: 3,
          max: 500
        },
        option: {
          rules: [{ required: true, message: "Please select your country!" }]
        },
        on: {
          change: value => {
            console.log("change", value);
          }
        }
      }
```
原来使用 const json = JSON.parse(str); 转成json；再通过 json.input 获取需要的对象内容；然后通过JSON.stringify(json.input);转回需要的字符串；但这种方法会导致里面的 change为方法的内容获取不到。

Output:
这是一段`js`脚本。`eval`函数不安全，可以模拟实现类似功能。如下:
```
function equalEval(str){
   return new Function('return ' + str)();
}
let obj = equalEval(str);
console.log(obj.input);
console.log(obj.number);

```
这样相对安全一些。


Instruction:
为什么linux 创建文件是touch 而不是create
好奇~ 为什么linux 创建文件是touch 而不是create

Output:
touch 的作用本来不是创建文件，而是将指定文件的修改时间设置为当前时间。
就是假装“碰”（touch）了一下这个文件，假装文件被“修改”了，于是文件的修改时间就是被设置为当前时间。
这带来了一个副作用，就是当 touch 一个不存在的文件的时候，它会创建这个文件。
然后，由于 touch 已经可以完成创建文件的功能了，就不再需要一个单独的 create 了。


Instruction:
网站大量无用图片如何处理？
比如富文本这样的功能，或者一些存储图片的字段。
当执行编辑操作的时候，有时候数据库中新图片会替代旧图片（旧图片链接名称在数据库中不存在了），但旧图片的文件还存在在硬盘中。
这种已经没用的图片一般如何处理？
我想到的方案：
方案1：在编辑的时候就把没用的图片一同处理掉，但这样会增加很多代码量，因为很多图片的存储结构不同，需要在各个功能代码处写专门的处理函数。
方案2：定期处理。扫描图片在各个表中是否用到，没有用到就删除。但这样做的话，如果增加了新的功能，还要去添加"要扫描的表和字段"，遗漏的话会造成误删。
方案3：不处理。冗余图片不会对网站产生大的影响（猜测）。
求解答。

Output:
建一个图片文件表：
```
create table pic(
id int,
path varchar(256),
md5 varchar(32),
size int,
refer_count int,
)
```
refer_count 为引用计数，多少文章里用到了，就是多少，文章修改时，先减少再增加，少到为零就可以删了。
用md5做摘要，可以把重复上传的图版合二为一。size和可以与用户结合进行配额限制，防止被恶意使用。


Instruction:
关于 useEffect 重复调用以及依赖数组的问题?
关于`useEffect`有有一些疑惑疑惑, 如下, 代码已经放入codesandbox 的 CounterHook.js 文件中
代码简化如下:
```
const CounterHook = props => {
  const [count, setCount] = useState(0)
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    setLoading(true)
    console.log(loading) // false, true, false, ture...
    // 模拟发送数据
    setTimeout(() => {
      setLoading(false)
      setCount(1)
    }, 2000)
  })

  return ...
}
```
这里如果没有添加`useEffect`的依赖数组, 会造成无限循环. 不是特别理解为什么会造成无限循环. 个人打印了一下 loading, 发现一直不断重复输出 false, true, false, true....
### 第一个问题
个人对造成无限循环的理解:
- 在调用`useEffect`之前, loading 是 false
-
第一次调用`useEffect`:

类似`componentDidMount`, 此时 loading 被设置成了 true, 同时发出了一个异步请求
请求结束, loading 又被设置成了 false, 组件的 state 被更新了, 由于 `useEffect` 在组件更新更新时也会触发, 因此触发第二次`useEffect`:

- 第二次调用`useEffect`: 和第一次一样, 首先`componentDidMount`, 设置 loading 为 true...循环继续
第一次调用`useEffect`:
- 类似`componentDidMount`, 此时 loading 被设置成了 true, 同时发出了一个异步请求
- 请求结束, loading 又被设置成了 false, 组件的 state 被更新了, 由于 `useEffect` 在组件更新更新时也会触发, 因此触发第二次`useEffect`:
所以第一个问题是, 不知道这样理解造成无限循环对不对?
### 第二个问题:
如果将请求数据部分抽成一个函数, 如下;
```
const CounterHook = props => {
  const [count, setCount] = useState(0)
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    fetchApi()
  }, [fetchApi])

  const fetchApi = () => {
    setLoading(true)
    // 模拟发送数据
    setTimeout(() => {
      setLoading(false)
      setCount(1)
    }, 2000)
  }

  return ...
}
```
`useEffect`的依赖数组变成了一个函数, 而且此时似乎仍旧会造成无限循环. 同时有提示:
所以第二个问题为: 如果`useEffect`的依赖数组存在函数, 该如何理解这个函数是否"变化"? 例如上面例子里面, 为什么会造成无限循环, 函数到底是哪里"变化"了导致`useEffect`不断的被重新调用?
### 第三个问题
和第二个问题有关联, 按照提示修改, 使用`useCallback`包装了一下`fetchApi`这个函数,  代码如下:
```
const CounterHook = props => {
  const [count, setCount] = useState(0)
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    fetchApiCallback()
  }, [fetchApiCallback])

  const fetchApiCallback = useCallback(() => {
    setLoading(true)
    // 模拟发送数据
    setTimeout(() => {
      setLoading(false)
      setCount(1)
    }, 2000)
  }, [])

  return ...
```
问题: `useCallback`依赖添加了一个依赖数组, 里面为空, 似乎代码没有出现无限循环的情况, 请问该如何解释? `useCallback`到底使得函数的"变化发生了怎样的改变"?

Output:
第一个问题：
对。
第二个问题：
函数组件的每次渲染都是执行一遍这个函数，在你的例子中，也就是 `CounterHook` 函数。那么两次执行中创建的局部函数，还会是同一个引用吗？不会的。所以本次执行中的 `fetchApi` 和上次执行中的 `fetchApi` 是两个不同的函数，因此 `useEffect` 的依赖被更新了，触发执行。
第三个问题：
`useCallback` 的返回值即为它接收的第一个参数，直到依赖更新。因此使用 `useCallback` 包裹的 `fetchApi` ，在依赖更新之前，总是同一个函数。也就不会触发 `useEffect`。


Instruction:
为什么需要申请SSL证书？
最近在研究把现有网站换成https，看了下SSL原理介绍，有一点不明白，既然https的本质是为了在通讯过程中讯息对称加密的方式传输，为什么浏览器不直接支持服务端自己生产的加密证书，加密证书只需要提供RSA的公钥不就好了？为什么需要花很多钱申请这个证书呢

Output:
如果抛开安全只看加密，那确实，只要像你说的那样提供个公钥就行了。
但这样做的问题是，虽然确保了传输过程中的数据是被加密的，但没办法确保最后解密的那台服务器是你真的想要发送给它的那台。
举个例子，在不使用证书加密之前，我想给你（服务器）传纸条，中间需要经过N个人传话（如路由器等各级中间节点），那么在你收到消息的时候，很可能在中间某个传话的就给它篡改了，或者说没篡改、但是被传话的偷看了小秘密。
那么现在咱俩之间约定一个非对称加密的方式，你先给我个公钥，我用公钥把要给你的纸条加密了，你收到后再用私钥解密，这样中间传话的看不懂密码就没法偷看内容、即使瞎改的话你那解密不出来，你就知道纸条内容被篡改了。
到此为止就像你所说的那样，但这样还有个问题，那就是我怎么确认“你”是“你”？我现在喊：「`Bo丶niu`，我要给你传纸条了，给我个公钥」，结果一个实际叫 `niu丶Bo` 的人站出来了说「来来来，我就是 `Bo丶niu`，我给你公钥，你传纸条吧」，结果咱俩的小秘密最后发给这个不相干的人了。这就是中间人攻击（上面这个例子里其实就是 DNS 劫持）。
那怎么解决呢？现实中好办，传纸条前先看一下身份证，噢，“你”确实是“你”，行了，可以发了。
这是因为你信任身份证这个由国家颁发的凭证。那网络上的凭证谁来颁发？这就是证书签发机构的事儿了，它们作为“权威”给每个域颁发证书，就像国家给每个人颁发身份证一样，你信任这些机构，也就信任它们发的证，从而也就信任有证书这些网站了。（这里还有信任链的问题，不展开讲了）
现实中，你办个护照还需要交个工本费呢。想让证书颁发机构给你发证，那就要给它们钱。而且这个证还分三六九等，越权威的越值钱。
不想花钱怎么办？自己给自己签发呗！然后你让所有使用证书的人都去信任你这个签发人（早期 12306 就是这么干的，自己给自己签证书，你访问的时候还得先下载它们的证书导入到系统的信任链里去）。


Instruction:
通过docker命令行，报错：Fatal error, can't open config file，在容器内执行没问题
首先，我的dockerfile如下：
```
FROM redis:latest
COPY $PWD/redis.conf /root/
RUN ["chmod", "777", "/root/redis.conf"]
CMD ["redis-server", "/root/redis.conf"]
```
redis.conf文件的内容是从这里复制的https://raw.githubusercontent...
使用`docker build  .`之后，使用`docker run -it --rm 7141cd2da206`运行，
报以下错误：
```
1:C 03 Sep 2019 12:59:48.539 # Fatal error, can't open config file '/root/redis.conf'
```
但是，我通过bash进入容器：`docker run -it --rm 7141cd2da206 bash`
执行redis-server没有任何问题，可以启动成功：
```
root@7d50439a05df:/data# ls -l /root/redis.conf
-rwxrwxrwx 1 root root 58765 Sep  3 12:59 /root/redis.conf
```
```
root@7d50439a05df:/data# redis-server /root/redis.conf
8:C 03 Sep 2019 13:05:46.070 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
8:C 03 Sep 2019 13:05:46.070 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=8, just started
8:C 03 Sep 2019 13:05:46.070 # Configuration loaded
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 5.0.5 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 8
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

8: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.
8:M 03 Sep 2019 13:05:46.073 # Server initialized
8: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.
8:M 03 Sep 2019 13:05:46.073 * Ready to accept connections

```
很困惑啊。。。！！
-----更新------
把dockerfile里redis-server替换成绝对路径又可以了：
```
FROM redis:latest
COPY $PWD/redis.conf /root/
CMD ["/usr/local/bin/redis-server", "/root/redis.conf"]
```
???

Output:
用 docker inspect 可以看到，redis 的 docker 镜像的默认的 Entrypoint 是 `docker-entrypoint.sh` 。也就是说，CMD 定义的命令是由这个脚本执行的。
这个脚本的内容如下（可能不同的版本会有所不同）：
```
#!/bin/sh
set -e

# first arg is `-f` or `--some-option`
# or first arg is `something.conf`
if [ "${1#-}" != "$1" ] || [ "${1%.conf}" != "$1" ]; then
        set -- redis-server "$@"
fi

# allow the container to be started with `--user`
if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
        find . \! -user redis -exec chown redis '{}' +
        exec gosu redis "$0" "$@"
fi

exec "$@"
```
可以看到，当 CMD 的第一个元素为 `redis-server` 的时候，它将当前目录（WorkingDir，通过 docker inspect 可以看到是 `/data`） 的所有文件的所有者改为了 `redis` ，然后以 `redis` 用户运行命令。
Dockerfile 里，虽然将 `/root/redis.conf` 的权限改成了 777 ，但是 `/root` 目录的权限是 700 ，redis 用户不可读，于是出错。将 `/root` 的权限也改成 777 就可以解决。
========================
由于脚本在进行精确匹配，命令改为绝对路径后将不能匹配，会进入最后一行的 exec 。此时是用 root 用户跑的，所以有读权限，可以启动。
或者说，只要 CMD 的第一个元素不是 `redis-server` ，那么用户就是 root 。所以用 bash 进容器里再跑也是没有问题的。
最后，如果 CMD 改成: `CMD redis-server /root/redis.conf` ，这个 CMD 会被改写成：`CMD ["/bin/sh", "-c", "redis-server /root/redis.conf"]` 。参考 Dockerfile / CMD 文档 ，并且可以通过 docker inspect 看到实际的 Cmd 。这时，运行的用户也是 root ，也是有读权限的，可以运行。
在命令行指定 CMD 也会使用同样的规则，参考 docerker run / COMMAND 文档 ， 可以解释相对路径会找不到文件，而改成绝对路径就可以的问题。
======================
如果 CMD 的第一个参数以 `-` 开始，或者以 `.conf` 结束，那么 `docker-entrypoint.sh` 会在前面加一个 `redis-server` 。这是其中第一个 `if` 干的事情。此时，由于第一个参数是（新插入的）`redis-server` ，所以也会以 redis 用户运行。
也就是说，启动 redis 镜像时，`redis-server` 命令其实可以不写，只写参数。比如：`CMD ["/root/redis.conf"]` 。或者，`docker run -it --rm a7f182f6c6dd /root/redis.conf` 。


Instruction:
refresh token安全问题
如果`access_token`有效期一个小时，`refresh_token`有效期7天；
- 那么在这7内天我都可以通过`refresh_token`获得`access_token`那不是等价于`access_token`有效期为7天了吗？
- 7天的有效期也会让安全风险增加那为什么还要用`refresh_token`呢？

Output:
这是一个有关暴露风险大小和有效期时长的问题，如果我们只有一个 token ，每次请求中都要携带这个，那么它暴露的风险会很高，如果这个 token 的有效期还比较长，那么它一旦暴露，损失会很高，所以 access_token 的有效期需要比较短。
但是我们又不希望用户的登录有效期只能这么短，那么怎么办呢？refresh_token 的存在价值正在这里，refresh_token 只需要在刷新 access_token 的请求里面携带，相对于 access_token 而言，它暴露的风险小很多，所以即便它的有效期比较长，相对来说造成损失的可能性也没那么高。
更详细的看看这个Why Does OAuth v2 Have Both Access and Refresh Tokens?


Instruction:
js:关于遍历数组中对象封装数据问题
有个数组如下结构：
```
    let a = [
       {0: '内容11', 1: '内容12', 2: '内容13', 3: '内容14', head: '头部1'} ,
       {0: '内容21', 1: '内容22', 2: '内容23', 3: '内容24', head: '头部2'} ,
       {0: '内容31', 1: '内容32', 2: '内容33', 3: '内容34', head: '头部3'} ,
    ]
```
怎么变成下面的结构
```
     let b = [
         {头部1: '内容11', 头部2: '内容21', 头部3: '内容31'},
         {头部1: '内容11', 头部2: '内容21', 头部3: '内容31'},
         {头部1: '内容11', 头部2: '内容21', 头部3: '内容31'},
         {头部1: '内容14', 头部2: '内容24', 头部3: '内容34'},
        ]
```
写了好久，总有问题，希望能解决。谢谢！

Output:
```
// 你这期望值给的我也是看不懂 大致猜测是行变列

let a = [
    { 0: '内容11', 1: '内容12', 2: '内容13', 3: '内容14', head: '头部1' },
    { 0: '内容21', 1: '内容22', 2: '内容23', 3: '内容24', head: '头部2' },
    { 0: '内容31', 1: '内容32', 2: '内容33', 3: '内容34', head: '头部3' }
]

function transformList(arr) {
    if (!Array.isArray(arr)) return

    return arr.reduce((temp, item, i) => {
        Object.keys(item).forEach((key, j) => {
            if (key === 'head') return
            if (!temp[j]) temp[j] = {}

            temp[j][item.head] = item[key]
        })
        return temp
    }, [])
}

console.log(transformList(a))
// 打印
[ { '头部1': '内容11', '头部2': '内容21', '头部3': '内容31' },
  { '头部1': '内容12', '头部2': '内容22', '头部3': '内容32' },
  { '头部1': '内容13', '头部2': '内容23', '头部3': '内容33' },
  { '头部1': '内容14', '头部2': '内容24', '头部3': '内容34' } ]

```


Instruction:
为什么MySQL8.0直接把查询缓存的功能删除了呢？
一种说法是不建议使用查询缓存，因为查询缓存往往弊大于利。
查询缓存的失效非常频繁，只要有对一个表的更新，这个表上的所有的查询缓存都会被清空。
因此很可能你费劲地把结果存起来，还没使用呢，就被一个更新全清空了。对于更新压力大的数据库来说，查询缓存的命中率会非常低。除非你的业务有一张静态表，很长时间更新一次，比如系统配置表，那么这张表的查询才适合做查询缓存。
在我看来，大多数应用都把缓存做到了应用逻辑层，简单的如一个map的mybatis，复杂的可以用redis或者memcache，直接操作内存远远比走网络访问快，所以mysql直接抛弃了查询缓存？

Output:
MySQL服务器团队有一篇关于此的详细博客，其中Matt Lord说：
我们考虑了可以对查询缓存进行哪些改进，以及我们可以进行的优化，这些优化可以改善所有工作负载。
虽然这些选择本身是正交的，但工程资源是有限的。也就是说，我们正在转变战略，投资于更普遍适用于所有工作负载的改进。
建议把缓存放到客户端


Instruction:
js 树形结构数据 已知某一子节点 一次向上获取所有父节点
```
var res = [{
    code: 1,
    name: "湖北省",
    children: [{
        code: 1,
        name: "武汉市",
        children: [{
            code: 1,
            name: "汉阳区",
            children: [{
                code: 1,
                name: "水上分局1"
            }]
        }, {
            code: 1,
            name: "武昌区",
            children: [{
                code: 1,
                name: "水上分局2"
            }]
        }, {
            code: 1,
            name: "汉口区",
            children: [{
                code: 1,
                name: "水上分局3"
            }]
        }]
    }, {
        code: 1,
        name: "十堰市",
        children: [{
            code: 1,
            name: "郧阳区",
            children: [{
                code: 1,
                name: "安阳镇"
            }]
        }, {
            code: 1,
            name: "茅箭区",
            children: [{
                code: 1,
                name: "小川乡"
            }]
        }]
    }]
}]
```
已知树形结构 res。现在有一个对象是{code: 1,name: "水上分局"},想向上依次获取取得父级，比如说水上分局 父节点是汉阳区 汉阳区父节点是武汉市 武汉市父节点是湖北省 最后将 汉阳区  武汉市 湖北省 存起来 求指点

Output:
```
function treeFindPath (tree, func, path = []) {
  if (!tree) return []
  for (const data of tree) {
    // 这里按照你的需求来存放最后返回的内容吧
    path.push(data.name)
    if (func(data)) return path
    if (data.children) {
      const findChildren = treeFindPath(data.children, func, path)
      if (findChildren.length) return findChildren
    }
    path.pop()
  }
  return []
}

```
调用
```
treeFindPath(res, data=> data.name==='水上分局')
```
打印调用结果
```
["湖北省","武汉市","汉阳区","水上分局"]
```
随手给你写一个函数吧，这个确实比一般递归复杂那么一点点，就是要记录一下你遍历过的节点。


Instruction:
为什么要用vue-cli3？
其实这个问您要是想了解vue-cli3与vue-cli2相比是否存在一些不得不升级的好处和优点？
产生这个问题的原因是在试用完vue-cli3之后并没有觉得好用，反而觉得束手束脚，我cli2时，webpack想怎么配怎么配为什么到了cli3我要在vue.config.js中配置
众所周知vue-cli的通用配置并不适合每种情况,而在vue.config.js只能做增添和覆盖，所以一直没有用vue-cli3构建项目
所以想请教下 这个版本有没有值得升级的优点

Output:
好问题，vue-cli3相对vue-cli有很多重要的更新。
首先说一些vue-cli这些工具的初衷吧: 这些工具就是为了让开发者能够开箱即用快速地进行应用开发而开发的，它们秉承的是“约定大于配置”思想，简单说就是"能不配置的就不配置，你就按照我的方式来，也不要去争论这个好不好，快速进行业务开发才是正经事". 它们不建议你去配置，但也不会拦着你去配置。
另外Webpack对初学者并不是十分友好，‘又长又臭’的配置，普通开发者很难写入定义良好，性能优化的配置。不然就不会各种cli工具冒出来了，比如parcel，create-react-app。这些工具都宣称零配置，目的就是让开发者能够愉快的进行代码开发。
现在来看看Vue-cli v3的改进，以及思考这些有什么意义呢？

1. 抽离cli service层
Create-React-App是第一个做这种事情的。vue-cli3库现在包含以下两个模块：
- CLI: 即vue全局命令，主要用于项目创建和管理，包含了`vue create`、`vue ui`这些命令。CLI命令的做的事情比较少，所以更新不会太频繁(开发者也很少会去更新这些命令)
- Service层: 负责项目的实际构建，也就是webpack项目构建。这一块是频繁更新的，一般作为项目的局部依赖。

OK，这么做有什么意义呢？考虑这样一个场景，这也是一个痛点：
vue-cli3之前不算是一个构建CLI, 它顶多就是一个模板拷贝器, 所有webpack配置和构建命令都是耦合在具体的项目里面，package.json会包含一大堆开发依赖。
如果去跟进webpack或相关工具更新的朋友会有这种体会，升级不是一件容易的事情。比如你升级了babel-loader, 可能要连带webpack都升级，webpack升级后可能其他工具又不兼容了。
升级方面的痛点是其一。如果你的团队需要维护很多项目，你怎么对这些项目进行维护升级？每个项目都拷贝一下？如果某个项目做了特殊配置呢？
对于团队而言，项目构建这一块是应该尽量做到的统一和傻瓜化的，没有必要在这方面投入太多的精力，应该把事情外包给擅长这种事情的人去做。
另外不要排斥更新，更新可以获得更好的开发体验和构建速度、运行性能, 别人在这方面比你了解的更多。
分离了vue-cli-service之后，项目构建更新只是一个命令的事情，除非做了很多特殊化操作。特殊化操作应该封装到vue-cli的插件中。这就引出了vue-cli3的另外一个特色：插件

2. 插件化
相比create-react-app, vue-cli是在太仁慈了。vue-cli的插件机制很灵活，通过`webpack-chain`和`webpack-merge`可以实现webpack完全定制化。
可以对比一下市面上流行的cli工具的可扩展性：
对于vue-cli的插件实现机制可以看这篇文章。
因为vue-cli灵活的扩展性，所以它不仅限于vue本身，可以扩展支持react、anything...
按照上文说的，如果你要做深度的vue-cli定制化，不建议直接写在vue.config.js中，而是封装在插件中，独立的维护这个插件，然后项目再依赖这个插件。这样就可以简化升级的成本和复杂度。

3. GUI界面
虽然大部分人都觉得作用不大，因为确实对开发效率并实际的提升效果。就是看着舒服直观，这就够了。

4. 快速原型开发
vue-cli3也支持直接将一个vue文件跑起来，快速原型开发或验证某些想法时，挺不错。

5. 现代模式
给先进的浏览器配合先进的代码(ES6之后),同时兼容旧版本的浏览器，先进的代码不管从文件体积还是脚本解析效率都有较高的提升。
体积对比:
解析效率:
总结一下：
- 如果我们喜欢折腾，肯定会觉得vue-cli3束手束脚，这时候我们不是vue-cli3的目标用户；就比如我们团队就自己搞了一一个CLI构建工具: jm-cli, 根据自己的团队需求进行深度定制，不过我们这个工具是强约定的，包括目录结构、编码规范等等. 因为我们不推荐团队成员去搞特殊化定制，而且为了方便进行更新，所以干脆就不让扩展了，统一和规范对团队来说才是最重要的.
如果你有类似的开发经验，你会觉得vue-cli可能是所有构建CLI的最终归宿或者典范。

- 如果不想折腾，只想写代码，那就直接拿来用吧；
- 如果想折腾，又要考虑团队协作和构建工具链的维护成本，vue-cli是很适合的。当然你也可以造轮子
- 如果想学webpack的构建项目，也不推荐你使用vue-cli

就比如我们团队就自己搞了一一个CLI构建工具: jm-cli, 根据自己的团队需求进行深度定制，不过我们这个工具是强约定的，包括目录结构、编码规范等等. 因为我们不推荐团队成员去搞特殊化定制，而且为了方便进行更新，所以干脆就不让扩展了，统一和规范对团队来说才是最重要的.
如果你有类似的开发经验，你会觉得vue-cli可能是所有构建CLI的最终归宿或者典范。

最后给vue团队点个赞?
欢迎关注我，和我交流


Instruction:
Typescript内置类型中的Exclude实现原理？
#### lib.es5.d.ts
```
/**
 * Exclude from T those types that are assignable to U
 */
type Exclude<T, U> = T extends U ? never : T;
```
#### 问题
```
type AB = 'a' | 'b'
type BC = 'b' | 'c'
type Demo = Exclude<AB, BC> // => type Demo = 'a'
```
从结果上看，`T extends U`判断了 truthy 和 falsy，同时进行逻辑运算并把结果赋值给T，`extends`的这个功能官网有介绍吗？

Output:
`T extends U ? never : T` 表示如果 `T`是 `U`的子类返回`never`类型，如果不是返回`T`类型。
当`T`为联合类型的时候，它会自动分发条件。
TS 一些工具泛型的使用及其实现


Instruction:
计算一个整数数组中最大差值的元素？
#### 我用php实现的代码，比较暴力，类似于冒泡排序.
```
$arr = [4,2,7,5,11,13,9,1];
$a = 0;
$b = 0;
for ($i = count($arr) - 1; $i >= 0; $i--) {
    for ($j = 0; $j <= $i - 1; $j++) {
        $tmp = $arr[$i] - $arr[$j];

        if ($tmp > $a) {
            $a = $tmp;
            $b = $arr[$i];
        }
    }
}

echo $b;
```
求一个更优的算法，语言不限。

Output:
@Reming 的算法有一个小漏洞, 如果数据是这样的话, 算出来的实际上是有问题的.
```
[4, 2, 7, 5, 11, 13, 9, 0, 12]
```
个人认为, 这个问题有两个关注点:
- 最小值
- 最大差值

但和最大值无关, 我们需要关注的是最大差值, 可能最大值出现的时候, 最小值还没有出现, 而后面出现的数值减去最小值可能反而比较大. 上面的用例就是基于这种逻辑设计出来的.
修改后逻辑为: 向后循环遍历, 记录下到目前为止的最小值 以及 最大差值, 然后计算当前元素-目前为止最小值, 判断大小. 记录最大的差值即可.
基于 @Reming 的代码稍微修改了下:
```
var arr = [4, 2, 7, 5, 11, 13, 9, 0, 12];
var min = arr[0], maxDValue = 0;

arr.forEach((el, index) => {
  if (min > el) min = el;

  var diff = el - min;
  if (diff > maxDValue) {
    maxDValue = diff;
  };
});

console.log(maxDValue);
```
再补充一句, 实际上这个问题可以这样想:
- 假设有一个数组[a1, a2, a3, ..., an]
-
那么我们可以分两步计算出来最大差值

计算a1与左边元素的最大差值, a2与左边元素最大的差值, a3与左边元素的最大差值....an与左边元素的最大差值.
计算所有最大差值里的最大值.

- 其中第一步实际上就是就算am(m=1, 2, 3...)与其左边最小值的差值, 所以我们只需要记录当前最小值以及最大的差值即可.

那么我们可以分两步计算出来最大差值
- 计算a1与左边元素的最大差值, a2与左边元素最大的差值, a3与左边元素的最大差值....an与左边元素的最大差值.
- 计算所有最大差值里的最大值.


Instruction:
flutter：进入首页的时候判断是否登录，没登录则跳到登录页，这个怎么实现
进入首页的时候判断是否登录，没登录则跳到登录页，这个怎么实现

Output:
链接描述
这是我写的一个demo，实现了你要的功能
```
class _StartAppState extends State<StartApp>{

    var loginState;

    void initState(){
        super.initState();
        _validateLogin();
    }

    @override
    Widget build(BuildContext context){
        ScreenUtil.instance = ScreenUtil(width: 750,height: 1334)..init(context);

        final router = Router();
        Routes.configureRoutes(router);
        Application.router = router;

        print(loginState);
        if(loginState == 0){
            return LoginPage();
        }else{
            return HomePage();
        }
    }

    Future _validateLogin() async{
            Future<dynamic> future = Future(()async{
                SharedPreferences prefs =await SharedPreferences.getInstance();
                return prefs.getString("loginToken");
            });
            future.then((val){
                if(val == null){
                    setState(() {
                        loginState = 0;
                    });
                }else{
                    setState(() {
                        loginState = 1;
                    });
                }
            }).catchError((_){
                print("catchError");
            });

    }

}
```


Instruction:
面试遇到的问题，面试之后，感觉十分好奇
考官问我做的前端页面是组件切换还是跳转的页面。举个例子，比如一个 类似淘宝“个人中心” 页面上，可以选择不同的订单状态的tab，点击就会进入订单列表页面，这样的页面是直接用一个页面然后切换状态显示还是直接两个不同的页面呢？
我回答是两个页面，因为我觉得两个页面的内容都不一样，也符合跳转的逻辑。但是面试官明显的失望了，所以我后来琢磨是不是写成一个页面然后切换状态体验比较好，而且不用传递订单的状态参数过去呢？具体有什么原因呢？我想起来京东也是做成切换的，他的商品分类页面的搜索框，点击搜索框会切换到搜索页面，实际上是一个页面在切换状态显示不同的内容，这么做的意义是什么呢
如果说做成一个页面切换显示，那么就是单纯的v-if切换吗（我使用的是vue）

Output:
单独从京东的搜索界面来说。
大部分情况下搜索界面的内容不是很复杂，基本就是一个input，一些搜索记录和热搜的 item ，为页面加载不会带来太大的鸭梨，而且，一般搜索记录是本地存储，可以优先读入，提升用户体验，搜索记录是 ajax 后端读取，即使预读也不会有太多的鸭梨，这些都是可以用 Redis 做到缓冲，而且 搜索相对于用户体验体验来说，也应该是点击就能出现的，所以做成一个 `图层` 我觉得没什么问题，是一个比较好的设计。即使在 wap 2.0 时代，搜索只是嵌入在页面亦是如此，点击即可输入进行操作。
至于题干中的 个人中心 > 订单列表，无论从项目设计还是实践来说，都应该采用分页面的方式，当然现在的单页用了 router 后，只要后端不拖后腿(你可以提前预读)，页面载入也是很快的，对用户体验基本造成不了太大的影响，但是如果这两个页面混合在一起，那么对于相对来说，页面层级混乱，不容易管理。
如果单从开发来说，如果你对组件分割能够游刃有余，那也不是问题，直接做进去也是完全可以的，但是违背开发原则。
从面试的角度来讲，或许对方更想考察你对不同业务环境下该采用什么样的方式方法来处理问题是关键的，其次，因为这些不成定性的东西，大家基本都是按照自己第一感去处理，如果你能说服他，或者达成某些共识，在一定程度上还可以为自己加分。


Instruction:
npm 的 --unsafe-perm 参数是有何作用呢？
npm 的 --unsafe-perm 参数是有何作用呢？

Output:
这玩意儿看官方文档啊：https://docs.npmjs.com/misc/c...
就是说 npm 出于安全考虑不支持以 root 用户运行，即使你用 root 用户身份运行了，npm 会自动转成一个叫 nobody 的用户来运行，而这个用户几乎没有任何权限。这样的话如果你脚本里有一些需要权限的操作，比如写文件（尤其是写 /root/.node-gyp），就会崩掉了。
为了避免这种情况，要么按照 npm 的规矩来，专门建一个用于运行 npm 的高权限用户；要么加 --unsafe-perm 参数，这样就不会切换到 nobody 上，运行时是哪个用户就是哪个用户，即使是 root。


Instruction:
Java集合 modCount为什么不用volatile修饰？
2个线程 访问一个list 其中一个remove操作了 另一个在迭代 假如不用vol修饰 那么在迭代的那个线程可能感知不到modcount的变化啊
甚至于说官方认为有volatile是一个BUG？https://bugs.java.com/bugdata...

Output:
我觉得你是理解有误，首先Java集合中有`modCount`属性未加`volatile`的都是线程不安全的集合类，都是单线程集合类`single thread collections`,讲单线程集合类放到多线程中去讨论，是很不合适的。
所以你的假设，在多线程情况下的可见行问题，根本就不应该出现这个问题!因为你的思路就有问题。
要保证有这个属性的集合类的正确使用至少不会出现在多线程的编程中这是前提条件，为什么呢？
`fail-fast`机制是确保集合类遍历过程中集合类不会出现结构性修改（增、删元素）
一般认为在遍历时出现结构性修改那么遍历将无法保证所有元素均能被遍历到（新增时）也无法顺利完成遍历（删除时）
要在遍历是进行结构性修改必须配合`Iterator`提供的`remove()`方法
我觉得你应该考虑的问题是为什么会出现`fail-fast`机制这个东西，这个东西的出现是为了解决什么样子的问题。
你要记住`modCount`本身就不是为多线程准备的，再多线程情况下诸如`ArrayList`之类的集合类连本身线程安全都保证不了，又有什么必要去设计一个线程安全的`modCount`呢？
你要一个先天就不具备线程安全的类去实现线程安全的问题干嘛呢，这根本不是它考虑的问题，这完全没有必要。如果真这么做了，就不仅仅是设计过度的问题了。


Instruction:
JS正则中的$1的一个问题
```
var str = 'this is a test'
console.log(str.replace(/\b(\w)/g, ('$1'+'a').toUpperCase()))
// tAhis iAs aA tAest
```
为什么输出的不是TAhis IAs AA TAest
str.replace(/b(w)/g, ('$1').toUpperCase())，为什么调用的toUpperCase这个方法无效。

Output:
你对于toUpperCase的作用范围理解错了
```
str.replace(/\b(\w)/g, ('$1'+'a').toUpperCase())

```
相当于
```
str.replace(/\b(\w)/g, '$1A')

```
$1的大写还是$1,你只是把替换规则的字符串大写了，并没有把替换的结果大写
如果需要大写的话，用以下方法就可以了
str.replace(/b(w)/g, v => `${v}a`.toUpperCase())


Instruction:
echarts地图能不能通过加减按钮控制缩放
### 项目中用到了echarts的地图，在geo里有roam参数，不过是通过滚轮控制缩放的，这样用户体验不太好，能不能通过加减按钮或者地图比例尺的形式来控制缩放

Output:
可以试试我写的这个
```
<button onclick="roamMap(0)" style="position: absolute; z-index: 999">+</button>
<button onclick="roamMap(1)" style="position: absolute; left: 5%; z-index: 999">-</button>
```
```
    // 地图缩放 flag: 0->放大 1->缩小
    function roamMap(flag) {
        let currentZoom = nationalChart.getOption().geo[0].zoom; // 当前的缩放比例

        let increaseAmplitude = 1.2; // 点击按钮每次 放大/缩小 比例
        if (flag == 1) {
            increaseAmplitude = 0.8
        }

        nationalChart.setOption({
            geo: {
                zoom: currentZoom*increaseAmplitude
            }
        })
    }
```


Instruction:
如何让img里的图片自适应div，并填充不变形？
```
<div>
    <img src="..." alt="image">
<div>

img如何随父元素div改变尺寸，填充整个img，并且不变形？
就是background-size: cover;的感觉。

或者保持不变形，只显示图片的一部分也可以？

谢谢大家。
```

Output:
img标签在固定高宽的div里的显示，除了JS，以及背景图片，可以试一下使用css属性object-fit属性。
它的几个属性
```
fill（不保持纵横比缩放图片，使图片完全适应）
contain（保持纵横比缩放图片，使图片的长边能完全显示出来）
cover（保持纵横比缩放图片，只保证图片的短边能完全显示出来）
none（保持图片宽高不变）
scale-down（当图片实际宽高小于所设置的图片宽高时，显示效果与none一致；否则，显示效果与contain一致）
inherit
initial
unset

```


Instruction:
vscode怎么快速重启?
## 如题：
## 当
## 可是我在菜单没有找到
## 因为可能经常会用到

Output:
打开：“命令面板”
CTRL + SHITF + P
输入：
```
> Reload Window
```
也可以绑定`快捷键`
```
{
  "key": "ctrl+f5",
  "command": "workbench.action.reloadWindow",
  "when": "editorTextFocus"
}
```


Instruction:
vue中v-for写成render的形式，key怎么解决？
项目中有部分代码，写层render的形式比template会更好...
但是遇到了一个问题，我们都知道v-for的时候是必须要设置key的，当我用render去遍历一个数组的时候，key怎么设置呢？我将key放在单个组件的props或是domProps都不起作用。一下是render代码：
这里Goup和Cell都是vue对象...也就是components
```
render(h): any {
        const mapNode = (h): any =>{
            const conArray = [];
            let hVnode = ( vNodeName, part ): any =>{
                return h(vNodeName, {
                    props: {
                        part: part,
                        key: part.partId
                    },
                    domProps: {
                        key: part.partId
                    },
                });
            }
            for(let item of this.partList) {
                if(item.partType === 'group') {
                    conArray.push( hVnode(Group, item) );
                } else {
                    conArray.push( hVnode(Cell, item) );
                }
            }
            return conArray;
        }
        return h( 'div', {
                attrs: {
                    class: 'group-list',
                    id: "group-list"
                }
            },
            mapNode(h)
        );
    },
```
可行的方案是template，一下是代码
```
<template>
    <div class='group-list' id="group-list">
        <div v-for="item of partList" :key="item.partId">
            <template v-if="item.partType === 'group'">
                <Group :part="item"></Group>
            </template>
            <template v-else-if="item.partType === ''">
                <Cell :part="item"></Cell>
            </template>
        </div>
    </div>
</template>
```
以上render的形式key值不起作用，表现在删除数组的时候，一定会删除最后一个（即使我删除的是第一个数组对象）...

Output:
```
return h(vNodeName, {
  key: part.partId,
});
```
教个小诀窍，如果对`render`不是很熟，可以先写好`template`，然后借助`Vue.compile`来生成`render`
```
import Vue from 'vue';

const res = Vue.compile(`
<div class='group-list' id="group-list">
  <div v-for="item of partList" :key="item.partId">
      <template v-if="item.partType === 'group'">
          <Group :part="item"></Group>
      </template>
      <template v-else-if="item.partType === ''">
          <Cell :part="item"></Cell>
      </template>
  </div>
</div>
`);

console.log(res.render);
```
这样控制台会打印出来生成好的`render`函数，不明白可以参见内部细节


Instruction:
webpack 打包库时出现 window is not defined
按照官网的步骤进行库的打包 创建library
webpack.config.js
```
var path = require('path');

module.exports = {
  entry: './src/index.js',
  mode: 'production',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'webpack-numbers.js',
    library: 'webpackNumbers', // 支持多种模式的导出
    libraryTarget: 'umd'
  },
  externals: {
    lodash: {
      commonjs: 'lodash',
      commonjs2: 'lodash',
      amd: 'lodash',
      root: '_'
    }
  },
```
index.js
```
import _ from 'lodash';
import numRef from './ref.json';

export function numToWord(num) {
  return _.reduce(numRef, (accum, ref) => {
    return ref.num === num ? ref.word : accum;
  }, '');
}

export function wordToNum(word) {
  return _.reduce(numRef, (accum, ref) => {
    return (ref.word.toLowerCase() === word.toLowerCase()) ? ref.num : accum;
  }, -1);
}
```
使用 test.js 测试导出的包在 node 环境能否使用
```
const _ = require('lodash')

const webpackNmuners = require('../dist/webpack-numbers')

console.log(webpackNmuners.numToWord(4))

console.log(webpackNmuners.wordToNum('four'))
```
运行时报错
```
ReferenceError: window is not defined

```
查看打包出来的模块,发现确实存在 window 对象
如果存在 window 对象,那么这个模块就不能在 node 环境中使用
但是我现在的配置和官网都是一致的,不应该出现这种情况啊
现在要使库生效,我得手动进入打包后的文件把 window 改为 this
请问一下这是哪里出了问题,webpack 版本是 webpack 4.29.6

Output:
你需要在`output`里面设置`globalObject`
```
// webpack.config.js
module.exports = {
  ...
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'webpack-numbers.js',
    library: 'webpackNumbers',
    globalObject: 'this', // 添加这个选项
    libraryTarget: 'umd'
  }
  ...
}
```
output.globalObject


Instruction:
【编程进阶】js实现一个map函数
实现一个myOwnMap函数:
输入：
```
[1,2,3].myOwnMap((item, index) => {
    return item *2
})

```
输出： `[2,4,6]`

Output:
首先要搞清楚`map()`函数的用法，传入一个函数，函数允许传三个参数（数组每一项，数组索引，数组本身），并且`map()`函数有返回值,如此一来也就有思路了:
```
   Array.prototype.newMap = function(fn,context){
        if(typeof fn !== 'function')return;
        var newArr = [];
        for(var i = 0;i < this.length;i++){
            newArr.push(fn.call(context,this[i],i,this,context));
        }
        return newArr;
    }
    //调用
    [1,2,3].newMap(function(item){
        return item * 2;
    });//[2,4,6]

```


Instruction:
typescript声明联合类型元组后加入新元素
刚刚看ts的文档看到元组越界的时候，尝试了下
```
let x: [string, number];
x = ['hello', 10];
当访问一个越界的元素，会使用联合类型替代：
x[3] = 'world'; // OK, 字符串可以赋值给(string | number)类型
console.log(x[5].toString()); // OK, 'string' 和 'number' 都有 toString

x[6] = true; // Error, 布尔不是(string | number)类型
```
写到这里就会报错了，表示不能直接更改一个长度为2的数组的第三个索引值，试了下另一个教程的push方法，发现可以插入成功，但是依旧不能通过索引访问，也不能改变元组length属性
感到有些疑惑，ts是js超集，这里感觉不能直接改变数组元素呢，push之后元素已经插入了但是却访问不了该元素，又是怎么回事呢  求教

Output:
官方文档关于这一点上没有更新。
事实上在 Typescript 2.7（Fixed Length Tuples 一节中） 之后， Tuple 的定义已经变成了有限制长度的数组了。
```
interface NumStrTuple extends Array<number | string> {
    0: number;
    1: string;
    length: 2; // using the numeric literal type '2'
}
```
所以你不能再越界访问了。


Instruction:
闭包：js这样写有什么好处？
很多地方都可以看到js代码用
```
(function($){
    //代码
    var demo = function(){

    };

    var demo2 = function(){

    };
})(jQuery)
```
这样包起来，这是js闭包吧。把js代码写到这个里面有什么好处呢？
```
<script type="text/javascript">
    (function($){
        var hehe = funcion(){
            alert('hehe');
        };
    })(jQuery);
</script>
```

Output:
这是一个立即执行匿名函数，同时也是一个闭包。
闭包的作用主要有两个：减少全局变量，保护变量
举两个例子请您揣摩：
```
// 第一例：
var a = function(){
    alert('global');
};
(function(){
    var a = function(){
        alert('closure');
    }
    a();
})();
a();

// 第二例：
var setter = function(){
    var privateVar;
    return {
        set: function(v){
            privateVar = v;
        },
        get: function(){
            return privateVar;
        }
    };
}();

setter.set('hello world');
setter.get();
```


Instruction:
python爬虫程序的原理是什么？PHP不能写爬虫吗？
python爬虫程序的原理是什么？PHP不能写爬虫吗？

Output: 爬虫的原理是从一个起始`种子链接`开始，发`http请求`这个链接，得到该链接中的内容，然后大多使用`正则匹配`出页面里面的`有效链接`，然后将这些链接保存到待访问队列中，等待`爬取线程`取这个待访队列，一旦链接访问过了，为了有效的减少不必要的网络请求，我们应该把访问过的链接放到一个`已访问map`中，已防止重复抓取及死循环。我以上提到的过程可能是一个比较简单的爬虫实现，复杂的可能不会这么简单，但这里面有几个概念，一个是发`http请求`，一个是`正则匹配`你感兴趣的链接，一个是`多线程`，另外还有`两个队列`，理论上，任何能实现这么些概念的编程语言去写爬虫都是可以的，期间取舍还是看自己对熟练成都。