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

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

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

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

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

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

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

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

回答：`以下都是自己想到什么写什么

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

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

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

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

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

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

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

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

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

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

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

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

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

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

标签: 集群, 监控
问题：java 如何通过反射修改类的私有方法
网上能找到的都是修改私有变量, 访问私有方法, 我想要修改私有方法, 请问如何操作?

回答：反射是不能修改方法的，但是可以使用修改字节码的方式来实现修改。
使用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();
```

标签: java, javascript, oop
问题：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'
          }
        ]
      }
    ]
    
```
不知道怎么写，不知道描述清楚没，我是新手，不耻下问啊...

回答：你可以先了解一下什么是 递归
这个需求通过递归可以很轻易实现
```
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)
```

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

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

标签: css, html5, 前端, css3
问题：请问vue或者uniapp如何实现背景色自动根据图片的主色进行渲染？
请问如何实现背景色自动根据图片的主色进行渲染？

回答：把图片绘制到一个与图片大小相等的 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。

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

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

回答：```
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分支
}）
```

标签: axios
问题：一个面试题关于函数的优先级
```
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.
  有疑惑的地方

回答：挺有意思的一道题。
第一个 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;
```

标签: javascript, html5
问题：原生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为方法的内容获取不到。

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

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

标签: javascript, 前端
问题：为什么linux 创建文件是touch 而不是create
好奇~ 为什么linux 创建文件是touch 而不是create

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

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

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

标签: php, c#, python, java, go
问题：关于 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`到底使得函数的"变化发生了怎样的改变"?

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

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

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

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

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

标签: node.js, java, php, typescript, asp.net
问题：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'},  
        ]
```
写了好久，总有问题，希望能解决。谢谢！

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

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' } ]

```

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

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

标签: mysql
问题：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: "水上分局"},想向上依次获取取得父级，比如说水上分局 父节点是汉阳区 汉阳区父节点是武汉市 武汉市父节点是湖北省 最后将 汉阳区  武汉市 湖北省 存起来 求指点

回答：```
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==='水上分局')
```
打印调用结果
```
["湖北省","武汉市","汉阳区","水上分局"]
```
随手给你写一个函数吧，这个确实比一般递归复杂那么一点点，就是要记录一下你遍历过的节点。

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

回答：好问题，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团队点个赞?
欢迎关注我，和我交流

标签: vue.js, vue-cli
问题：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`的这个功能官网有介绍吗？

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

标签: typescript
问题：计算一个整数数组中最大差值的元素？
#### 我用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;
```
求一个更优的算法，语言不限。

回答：@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与左边元素的最大差值.
- 计算所有最大差值里的最大值.

标签: python, php, javascript, go, java
问题：flutter：进入首页的时候判断是否登录，没登录则跳到登录页，这个怎么实现
进入首页的时候判断是否登录，没登录则跳到登录页，这个怎么实现

回答：链接描述
这是我写的一个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");
            });
        
    }

}
```

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

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

标签: 前端
问题：npm 的 --unsafe-perm 参数是有何作用呢？
npm 的 --unsafe-perm 参数是有何作用呢？

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

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

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

标签: java, 多线程
问题：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这个方法无效。

回答：你对于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())

标签: javascript, 前端, 正则表达式
问题：echarts地图能不能通过加减按钮控制缩放
### 项目中用到了echarts的地图，在geo里有roam参数，不过是通过滚轮控制缩放的，这样用户体验不太好，能不能通过加减按钮或者地图比例尺的形式来控制缩放

回答：可以试试我写的这个
```
<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
            }
        })
    }
```

标签: echarts, 前端
问题：如何让img里的图片自适应div，并填充不变形？
```
<div>
    <img src="..." alt="image">
<div>

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

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

谢谢大家。
```

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

```

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

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

标签: visual-studio-code
问题：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值不起作用，表现在删除数组的时候，一定会删除最后一个（即使我删除的是第一个数组对象）...

回答：```
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`函数，不明白可以参见内部细节

标签: vue.js
问题：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`里面设置`globalObject`
```
// webpack.config.js
module.exports = {
  ...
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'webpack-numbers.js',
    library: 'webpackNumbers', 
    globalObject: 'this', // 添加这个选项
    libraryTarget: 'umd'
  }
  ...
}
```
output.globalObject

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

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

回答：首先要搞清楚`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]




```

标签: javascript
问题：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之后元素已经插入了但是却访问不了该元素，又是怎么回事呢  求教

回答：官方文档关于这一点上没有更新。
事实上在 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'
}
```
所以你不能再越界访问了。

标签: typescript
问题：闭包：js这样写有什么好处？
很多地方都可以看到js代码用
```
(function($){
    //代码
    var demo = function(){
    
    };
    
    var demo2 = function(){
    
    };    
})(jQuery)
```
这样包起来，这是js闭包吧。把js代码写到这个里面有什么好处呢？
```
<script type="text/javascript">
    (function($){
        var hehe = funcion(){
            alert('hehe');
        };
    })(jQuery);
</script>
```

回答：这是一个立即执行匿名函数，同时也是一个闭包。
闭包的作用主要有两个：减少全局变量，保护变量
举两个例子请您揣摩：
```
// 第一例：
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();
```

标签: javascript
问题：python爬虫程序的原理是什么？PHP不能写爬虫吗？
python爬虫程序的原理是什么？PHP不能写爬虫吗？

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

标签: python
问题：关于递归问题   js
原数据格式
```
let obj =[
        {1:'20190805',2:'1',3:'success'},
        {1:'20191120',2:'1.1',3:'success'},
        {1:'20190212',2:'1.1.1',3:'success'},
        {1:'20190212',2:'1.1.2',3:'success'},
        {1:'20190212',2:'1.1.3',3:'success'},
        {1:'20190212',2:'1.2',3:'success'},
        {1:'20190212',2:'1.2.1',3:'success'},
        {1:'20190212',2:'2',3:'success'},
        {1:'20190212',2:'2.1',3:'success'},
        {1:'20190212',2:'2.2.1',3:'success'},
        {1:'20190212',2:'2.2',3:'success'},
        {1:'20190212',2:'2.3',3:'success'},
        {1:'20190212',2:'2.3.1',3:'success'},
        ...
        ]
```
最后想要下面这种结果格式，请问该怎么实现呢
```
let data = [
        {1: '20190805', 2: '1', 3: 'success', children: [
            {1: '20191120', 2: '1.1', 3: 'success', children: [
                {1: '20190212', 2: '1.1.1', 3: 'success'},
                {1: '20190212', 2: '1.1.2', 3: 'success'},
                {1: '20190212', 2: '1.1.3', 3: 'success'},
            ]}, {1: '20191120', 2: '1.2', 3: 'success', children: [
                    {1: '20190212', 2: '1.2.1', 3: 'success'},
                ]
            }]
        },
        {1: '20190212', 2: '2', 3: 'success', children: [
            {1: '20190212', 2: '2.1', 3: 'success', children: [
                {1: '20190212', 2: '2.2.1', 3: 'success'},
            ]},
            {1: '20190212', 2: '2.2', 3: 'success'},
            {1: '20190212', 2: '2.3', 3: 'success', children: [
                {1: '20190212', 2: '2.3.1', 3: 'success'}]
            }]
        },
        ...
    ]
```

回答：```
/**
 *
 * @param {Array} source
 * @returns {Array} 分类好的数据
 */
function mark(source) {
  var temp = {};
  source.forEach(item => {
    temp[item["2"]] = item;
  });
  source.forEach(item => {
    var key = item["2"],
      parent;
    //子级
    if (key.length > 1) {
      //子级的父 id
      key = key.slice(0, -2);
      parent = temp[key];
      if (parent) {
        parent.children = parent.children || [];
        parent.children.push(item);
      }
    }
  });
  return Object.keys(temp).reduce((ret, key) => ret.concat(key.length === 1 ? temp[key] : []), []);
}


```

标签: javascript, react.js
问题：微信浏览器H5页面软键盘关闭导致页面空缺的问题
1. 微信6.7.4 H5页面里的select,input软键盘弹起的时候页面会上移，软键盘关闭页面不会下移。导致页面空缺了一部分。
2. 微信6.7.3及其它版本不会有这个问题！页面会随着软键盘关闭而下移恢复正常！

回答：您可以尝试以下代码
```
            $('textarea').on('blur',function(){
                setTimeout(function(){
                    window.scrollTo(0, 0)
                },100)
            })
```

如果出现同页面有两个以上输入框，当输入完第一个未关闭软键盘就去点第二个输入框的时候，页面回滚到顶部，导致输入框被软键盘盖住的问题，也可以将以上代码改写一下：```
'$("input,textarea").on("blur",function(){
    setTimeout(function(){
        window.scrollTo(0,0);
    },100)
}).on('focus',function(){
    var clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
    var offsetTop = $(this).offset().top - (clientHeight / 4);
    setTimeout(function(){
        window.scrollTo(0,offsetTop);
    },100)
})
```

标签: javascript, html5
问题：Java8 unordered() 无序化无效
### Java8 unordered()无序化无效, 多次运行结果还是与流中元素顺序一致
// 多次运行结果: 5, 1, 2, 6, 3, 7, 4 没有达到无序的效果
Stream.of(5, 1, 2, 6, 3, 7, 4).unordered().forEach(System.out::println);
求大神指教
### 相关代码
```

    /**
     * S unordered(); 产生一个与当前流中元素相同的无序流, 当流本身就是无序或流已经无序, 会返回流本身
     */
    @Test
    public void unorderedTest() {
        Stream.of(5, 1, 2, 6, 3, 7, 4).forEach(System.out::println);
        
        // 多次运行结果: 5, 1, 2, 6, 3, 7, 4 没有达到无序的效果 TODO
        Stream.of(5, 1, 2, 6, 3, 7, 4).unordered().forEach(System.out::println);
    }


```

回答：`unordered()`操作不会执行任何操作来显式地对流进行排序。它的作用是消除了流必须保持有序的约束，从而允许后续操作使用不必考虑排序的优化。
您可以在Java 8文档中阅读此内容：
在流有序时, 但用户不特别关心该顺序的情况下，使用 unordered 明确地对流进行去除有序约束可以改善某些有状态或终端操作的并行性能。
可以比较下面的结果
```
   Stream.of(5, 1, 2, 6, 3, 7, 4).unordered().forEach(System.out::println);
   Stream.of(5, 1, 2, 6, 3, 7, 4).unordered().parallel().forEach(System.out::println);
```

标签: java
问题：vuedraggable中如何设置部分元素不可拖拽？
draggable渲染成了ul，但是想让ul中部分li元素可拖拽，部分li元素不可拖拽。
文档只给出了在option中设置disabled;sort等属性可以让整个标签不能拖拽，但是没有给出让子元素不可拖拽的实现方法。
如果要实现部分子元素可拖拽，部分子元素不可拖拽的话除了把一个ul拆分成两个ul还有其他方法吗？

回答：handle: selector 格式为简单css选择器的字符串，使列表单元中符合选择器的元素成为拖动的手柄，只有按住拖动手柄才能使列表单元进行拖动
根据上述进行配置可拖动手柄，例：handle：'.header'

标签: vue.js, draggable
问题：关于 js 函数默认值的问题
下面这两种写法为什么会产生两种不同的结果？求大佬详细解答.... 个人觉得是跟函数参数的块级作用域有关.....但是理解起来还是怪怪的，而且用 chrome debugger 来查看也觉得怪怪的，为啥最后那个输入 x，是根据 Block 来输出的？万分感谢~
```
function test (x, y = function t () { x = 2 }) {
  var x
  y()
  console.log(x) // undefined
}
test()
```
```
function test (x, y = function t () { x = 2 }) {
  // var x
  y()
  console.log(x) // 2
}
debugger
test()
```

回答：9.2.12 FunctionDeclarationInstantiation
如果存在函数默认值，那么会为函数体部分创建第二个环境记录，这个第二个环境是在函数默认值之下的。
类似于：
```
// ES6
function foo(x, y = function() { x = 2; }) {
  var x = 3;
  y(); // is `x` shared?
  console.log(x); // no, still 3, not 2
}
 
// Compiled to ES5
function foo(x, y) {
  // Setup defaults.
  if (typeof y == 'undefined') {
    y = function() { x = 2; }; // now clearly see that it updates `x` from params
  }
 
  return function() {
    var x = 3; // now clearly see that this `x` is from inner scope
    y();
    console.log(x);
  }.apply(this, arguments);
}
```
代码来自 es6-notes-default-values-of-parameters

标签: javascript
问题：java反射使用setAccessible(true)调用private方法问题
如题，定义了一个Person类有一个private方法
```
public Person {
    private void test();//private方法
}
```
使用反射来调用
先说有问题的方法
```
Constructor con= Person.class.getConstructor();//构造方法
Object object = con.newInstance();//生成对象
//有问题
Person.class.getDeclareMethod("test").setAccessible(true);
Person.class.getDeclareMethod("test").invoke(object);//报错不能访问
/*Person.class.getDeclareMethod("test").isAccessible()还是等于false*/
```
而使用下面的写法却可以
```
Method = Person.class.getDeclareMethod("test")；
method.setAccessible(true);
method.invoke(object);//不报错，正常执行
/*method.isAccessible()是true
而Person.class.getDeclareMethod("test").isAccessible()还是等于false
*/
```
这是Person.class.getDeclareMethod("test")方法的问题吗，这个问题在反射调用构造函数时也会出现，他们都有一个@CallerSensitive注解，是这个原因吗？望解答。

回答：每次获取方法得到不是同一个`Method`对象  
`setAccessable`仅作用于得到的方法对象，也不是全局的  
所以第一种写法会报错  
另外，`setAccessable`的属性并没有被包含在`Method`的`equals` 和`hashCode`中

标签: java
问题：一道关于js类型转换的面试题？
if([] == false){console.log('a')}
if({} == false){console.log('b')}
if([] == {}){console.log('c')}
if([]){console.log('d')}
这几道题的隐式转换的方式大神帮忙解答下吧

回答：对象和非对象之间的相等比较
ES5 规范 11.9.3.8-9 做如下规定：
`ToPrimitive`就是尝试返回它的原始值，也就是`string`或者`number`。
因此：
1. [] == false，`{[]}`会先通过`{valueOf}`，得到`{[]}`，不是原始值，再通过`{toString}`，得到`{""}`
2. ({}) == false，同上面步骤，最终的到`{"[object Object]"}`
3. 同上，`{''!="[object Object]"}`
4. 没有`{==}`，[]默认为true

标签: javascript
问题：合并数组用 concat 还是 扩展运算符比较好？
```
let arr1 = [1, 2];
let arr2 = [3, 4];
// concat
arr1 = arr1.concat(arr2);
// 扩展运算符
arr1 = [...arr1, ...arr2];
// 或者
arr1.push(...arr2);
```
哪种更好，为什么？性能？

回答：究竟用哪种还是得根据你实际需求来的
`concat`是`es5`时就有的，优点是`兼容性`高，不需要转译
`...`是`es6`新出的语法，`简化`了写法，代码看上去更简洁直观，但实际只是做了`封装`，底层还是用的原来的方法，如下为babel转译的结果
#### 第二种写法
```
arr1 = [...arr1, ...arr2];
  ↓ 相当于
function _toConsumableArray(arr) {
 if (Array.isArray(arr)) { 
   for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; 
   } else { return Array.from(arr); }
}
arr1 = [].concat(_toConsumableArray(arr1), arr2);
```
#### 第三种写法
```
arr1.push(...arr2);
  ↓ 相当于
arr1.push.apply(arr1, arr2);
```
再来看三种写法处理不同数据量的时间(数据分别为1,10,100) 单位:万
```
num:10000
 s1: 0.01813671875ms
 s2: 0.1808984375ms
 s3: 0.078857421875ms

num:100000
 s1: 0.8310546875ms
 s2: 10.428955078125ms
 s3: 8.025146484375ms

num:1000000
s1: 11.42724609375ms
s2: 83.867919921875ms
s3: Maximum call stack size exceeded
```
总结:
`concat`性能最优
在数据量极小时三者差异并不大
在数据有一定量时`concat`性能遥遥领先于 `arr1 = [...arr1, ...arr2]` 和 `arr1.push(...arr2)`
在数据过大时第三种方法会因为`apply`的特点由于数据量过大导致堆栈溢出

标签: javascript
问题：bind和call的笔试题，为什么用call和没用call执行的结果一样？
面试题是这样的：
```
var s = {
        s: 'student',
        getS:function(){
            console.log(this.s);
        }
};
var t = {
    s: 'teacher chen'
}
var getS = s.getS;
var getS1 = getS.bind(s);
```
正确的运行结果是：
```
getS1();  // student
getS1.call(t);  //student
```
var getS1 = getS.bind(s) 这一句的是说创建一个新函数，并且通过bind，将新函数的this绑定到对象s。输出student没错。但是，getS1.call(t)，不是通过call方法，将this绑定到对象t了吗？为嘛输出的仍然是student而不是teacher chen 呢?

回答：对这个问题很感兴趣，查了一些资料
以下是 MDN 里 bind 的 Polyfill , 可以看出来 bind 返回的函数只有用 new 方法当做构造函数调用时才会改变 this, 其他情况下的 this 一直是绑定的那个
```
if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          // this instanceof fNOP === true时,说明返回的fBound被当做new的构造函数调用
          return fToBind.apply(this instanceof fNOP
                 ? this
                 : oThis,
                 // 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    // 维护原型关系
    if (this.prototype) {
      // Function.prototype doesn't have a prototype property
      fNOP.prototype = this.prototype; 
    }
    // 下行的代码使fBound.prototype是fNOP的实例,因此
    // 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
    fBound.prototype = new fNOP();

    return fBound;
  };
}
```
另外，还有 https://blog.csdn.net/learnin... 这位作者做了一些实验,结论是：对哪个函数使用bind()方法即改变这个函数的this值，和内置其参数，或者说像克里化一样理解，先预置好参数

标签: javascript
问题：React组件方法全部用箭头函数这样好吗？
React的组件中不用bind(this)，全部用箭头函数，这样会有什么缺点吗？

回答：箭头函数的优点就是可以自动绑定上下文中的`this`箭头函数的优点是不会创建自己的`this`,它只会从自己的作用域链的上一层继承`this`.当然这也有可能是缺点,比如在你需要改变`this`的时候,这个时候就需要改成普通函数了.
我遇到的另外一种情况是需要使用装饰器的情况,普通的函数使用装饰器直接覆盖`descriptor.value`就好了.但是如果装饰在箭头函数上面的话`descriptor.value`为空,需要通过别的方法来操作,有点麻烦,最后我直接改成普通函数,在最外面加了层绑定`this`的装饰器解决的.
其实也没多少好纠结的,只要你明白什么情况下不能用,其他情况下就大胆用.当你什么时候遇到问题了,就在心中记一笔,这种情况不能用就好了.跟结束加不加分号一个道理.用多了之后能遇到的情况基本上都遇到了,至于没遇到的情况,等遇到在说呗.
箭头函数表达式

标签: react.js
问题：vue中v-if影响同级audio标签播放？
### 问题描述
#### 以下是部分代码
```
  <audio class="basic-audio" :src="audio" autoplay="autoplay" @ended="ended"></audio>

  <div class="content-region" v-if="chooseCard">
      <el-row type="flex" v-for="(item,index) in contentList" :key="index" >
          <el-col class="content-lattice"   v-for="(item,index1) in item"  :key="index1">{{item.name}}</el-col>
      </el-row>
  </div>
```

回答：可以了解一下`vue`中`diff`算法相关的实现。比如这篇文章。
这种情况应该会出现于`audio`前后（不仅限于相邻）的兄弟节点中都存在`v-if`的情况。
因为`vue`中`diff`是基于同层级比较的，并且`updateChildren`方法中的`VNode`比较是从节点左右两侧向中间靠拢的，所以当`audio`前后都存在`v-if`时，`virtual dom`重新渲染时，会将`audio`这个`dom`进行移动，所以实际上`audio`是会被从父节点移除然后再重新加入（可以通过给`audio`绑定`DOMNodeRemoved`来验证）。
由于`audio`被移除过，所以播放会被停止。至于`v-show`没有此问题，是因为`v-show`前后`dom`结构未发生改变。

标签: 音频, vue.js, 前端, javascript
问题：vuex中存储的数据在页面刷新之后都是失去，我想让vuex中的数据在刷新之后不会丢失怎么办。
1.vuex中存储的数据在刷新页面(F5)之后会丢失全部的数据
2.我想刷新页面之后不丢失。同时我还不想存储在window中的session和local中
vuex中有没有相应的数据存储方法或者设置可以做到这样的效果

回答：你的这个业务场景跟vuex没有关系吧？
vuex就是一个“提升变量”的一个工具，它是将state当做全局变量存储。F5刷新页面之后自然随着页面的刷新重新初始化state。
目前想让浏览器记住数据，一般都会采用cookie或者localStorage等方法，如果有什么其它方法，欢迎分享。

标签: vue.js, vuex, vue-router, vue-cli, javascript
问题：java nio 与 nio 的关系
## 以前遇到问题，总是可以在网上找到绝对正确的答案，现在遇到的很多问题，博客上会有很多种不同的答案，比如说关于java nio，有人说是同步非阻塞，还有人说是异步阻塞，我只知道java nio是采用的reactor模式，也可以说是io多路复用，netty也是这种方式。希望大鸟们可以给我一个详细的解释，关于java nio与linux nio，在此谢过大家

回答：首先我想说下我对 同步异步 阻塞非阻塞的理解：
`同步异步 指的是线程在处理一件事的时候，能不能去处理另外一件事，然后过一会再给上一件事结果`
`阻塞非阻塞 指的是线程在处理一件事的时候，会不会被阻塞住 （linux 里的NIO 意思就是no block io）`
这在java 等编程语言里 ，应该是一种编程模型，
而在linux 的IO模型里 ，这种表述就不成立 ，因为不管什么IO模型，在从内核复制到用户态的过程 中都是阻塞的，即使是 同步非阻塞模型，
在linux  模型中，阻塞非阻塞指的是 使用系统调用看用户态准备好没有这个过程 ，而对于linux多路复用，系统调用select也阻塞，也没有办法去做别的任务，看起来他应该是同步阻塞，但他却比linux的同步阻塞要好得多，
因为同步阻塞模型是对一个IO ，而多路复用是对多个IO，
我之前也纠结过同步非阻塞和异步非阻塞的事情，但是后来想了想，这个东西要从不同的层面看，就拿netty来说，从整体来看，是属于异步非阻塞，accept的线程处理完请求，交给后面的reactor，
那accept的线程不就去处理别的请求了，这不就达到了异步非阻塞，但他内部reactor 使用的是多路复用模型 而不是 真正的 异步非阻塞模型，
所以说了这么多，其实还是想表达 同步异步，阻塞非阻塞 ，只是一种编程思路，不用去纠结，也不要被linux的IO模型搞混了，
还有就是java的NIO 是 new IO 的意思，不是noblock io ,因为他除了提供selector之外，还有其他的io特性提供，比如大文件的处理

标签: linux, java
问题：关于Promise中this的指向问题？
## 代码
```
class Dog {
  constructor() {
    this.name = 'adong';
  }

  start() {
    this.p().then(this.say);
  }

  p() {
    return new Promise((resolve, reject)=>{
      resolve('good');
    })
  }
  
  say(str) {
    console.log(this);
    console.log(this.name + str);
  }
}

let dog = new Dog();
dog.start();
```
## 题目描述
`say`方法单独调用时没有问题的，但是在`Promise`的`then`里面再调用`this`就变为`undefined`了，哪个大神帮忙分析一下，谢谢！
### 错误显示
```
undefined
(node:5784) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'name' of undefined
    at say (D:\NodeJS\Test\test2.js:18:22)
```

回答：```
class Dog {
  constructor() {
    this.name = 'adong';
  }

  start() {
    this.p().then(this.say.bind(this));
  }

  p() {
    return new Promise((resolve, reject)=>{
      resolve('good');
    })
  }
  
  say(str) {
    console.log(this);
    console.log(this.name + str);
  }
}

let dog = new Dog();
dog.start();

```
你上面的调用写法，其本质就是：
```
class Dog {
  constructor() {
    this.name = 'adong';
  }

  start() {
    // this.p().then(this.say)  本质如下
    this.p().then(function(str){
        console.log(str);  // good
        console.log(this); //undefined
        //console.log(this.name + str); //this.name会报错，注释掉
    });
  }

  p() {
    return new Promise((resolve, reject)=>{
      resolve('good');
    })
  }
  
  say(str) {
    console.log(this);
    console.log(this.name + str); 
  }
}

let dog = new Dog();
dog.start();
```
promise的then方法传入的是一个回调函数参数！所以 then(this.say)实质只是将this.say作为一个参数使用，所以不存在this
1>.  回调函数为匿名函数时，回调函数的this会指向window，需要对回调函数bind(this)。
2>.  回调函数为箭头函数时，回调函数的this会指向他的直接上层，本例中指向dog。

标签: node.js, javascript, promise, this
问题：TOKEN加在HEADER里，使用HTTPS通信，有安全隐患吗？
在写一个WEB API，我现在是把TOKEN放在网页请求头HEADER里，使用HTTPS跟服务器进行通信。
请问这样会不会被人劫持到TOKEN呢？有点担心伪造请求。 求指点~谢谢！

回答：`token`的作用是保证数据来源的可信,至于`token`本身的安全不在它的职责范围内.
比如用 jwt 生成的,里面存储的信息都是不加密的,他只保证里面信息的正确,比如`{id:12345}`我用这个数据生成一个`token`,这个`token`分为三段信息,第一段是头部`Header`,第二部分就是我们的数据`Payload`,通过`base64`加密,第三部分是加密的签名,通过`Header`和`Payload`以及我们的私钥生成.
当客户端带着这个`token`访问服务器的时候,我会通过我们的私钥来验证整个数据的完整性,如果通过验证,就说明这个信息是可信的.当信息被篡改时,比如有人拿到`token`,并把数据改成`{id:56789}`,但是他没有私钥,所以没法生成正确的签名,当服务端验证`token`的时候通不过,我们就知道这个数据经过了篡改,然后执行相应的处理.
这是`token`的作用,用来保证数据可信.保证这个`token`在其所在的权限范围内,而不会超出其权限范围之外,比如别的用户的信息.
当然你可以根据需求,在加上别的措施,比如就不想别人知道`token`里面的数据,那就可以在给这个数据加一下密.
或者当心这个`token`会被别人获取,照成这个用户的损失,那就需要在加别的手段来保证,比如通过验证来访的 ip ,比如设置更短的过期时间,比如你用的`HTTPS`,或者添加更多的验证等等.通过增加第三方的窃取成本,来降低被窃取的几率.
你可以把`token`想象为银行的验钞机,验钞机的职责是验证假钞保证收进来的钱都是真钱,至于这个钱是偷的抢的,还是正常交易所得,那就不是验钞机管的了,那是警察叔叔管的.

标签: html