Skip to content
本页目录

2020

3.29

js 数据类型

原始数据类型

  • boolean
  • string
  • number
  • null
  • undefined
  • bigint (提案中)
  • symbol (ES6 引入表示独一无二的值)

引用数据类型(对象 Object)

  • 普通对象 Object
  • 数组对象 Array
  • 正则对象 RegExp
  • 日期对象 Date
  • 数学函数 Math
  • 函数对象 Function

3.30

null 是对象吗?为什么?

结论: null 不是对象。 解释: 虽然 typeof null 会输出 object,但是这只是 JS 存在的一个悠久 Bug。在 JS 的最初版本中使用的是 32 位系统,为了性能考虑 使用低位存储变量的类型信息, 000 开头代表是对象 然而 null 表示为全零,所以将它错误的判断为 object 。

call 和 apply 的区别

call 与 apply 的唯一区别

传给 fun 的参数写法不同:

apply 是第 2 个参数,这个参数是一个数组:传给 fun 参数都写在数组中。 call 从第 2~n 的参数都是传给 fun 的。

4.6

☺️ 😆 😆

变量提升

变量声明的提升是以变量所处的第一层词法作用域为“单位”的,即全局作用域中声明的变量会提升至全局最顶层,函数内声明的变量只会提升至该函数作用域最顶层。

js
var a;
console.log(a); // undefined
a = 'a';
var foo = () => {
  var a; // 全局变量会被局部作用域中的同名变量覆盖
  console.log(a); // undefined
  a = 'a1';
};
foo();

结论

ES6 新增了 let 和 const 关键字,使得 js 也有了“块”级作用域,而且使用 let 和 const 声明的变量和函数是不存在提升现象的,比较有利于我们养成良好的编程习惯。

函数提升

js
console.log(foo1); // [Function: foo1]
foo1(); // foo1
console.log(foo2); // undefined
foo2(); // TypeError: foo2 is not a function
function foo1() {
  console.log('foo1');
}
var foo2 = function () {
  console.log('foo2');
};
// 这里可能会有人有疑问? 为foo2会报错,不同样也是声明?
// foo2在这里是一个函数表达式且不会被提升

结论

函数提升只会提升函数声明,而不会提升函数表达式。

4.8

1、数组的长度问题

javascript
let jing = [1, 2];
jing[9] = 520;
console.log(jing.length); //10

数组的长度等于数组中最大索引值 + 1。

2、数据类型转换




node vue mongodb js

4.9

1、process.cwd() 与  __dirname 的区别

  • process.cwd()是代表打开终端的目录
  • __dirname 是代表当前运行文件的目录

image.png

4.10

1、Vim 常用命令

常用命令是 ESC,然后:wq(保存并退出),:q!(不保存并强制退出),i 进入 vim 模式。另外还有其它的,我可能都不会用到。。。按 ESC 键 跳到命令模式,然后:

  • w 保存文件但不退出 vi
  • :w file 将修改另外保存到 file 中,不退出 vi
  • :w! 强制保存,不推出 vi
  • :wq 保存文件并退出 vi
  • :wq! 强制保存文件,并退出 vi
  • q: 不保存文件,退出 vi
  • :q! 不保存文件,强制退出 vi
  • :e! 放弃所有修改,从上次保存文件开始再编辑

原文链接:http://caibaojian.com/vim.html
来源:前端开发博客

2、git 使用场景

写完代码后,我们一般这样
git add . //添加所有文件
git commit -m "本功能全部完成"

执行完 commit 后,想撤回 commit,怎么办?

git reset --soft HEAD^

这样就成功的撤销了你的 commit
注意,仅仅是撤回 commit 操作,您写的代码仍然保留。

HEAD^的意思是上一个版本,也可以写成 HEAD~1
如果你进行了 2 次 commit,想都撤回,可以使用 HEAD~2

git commit --amend

如果仅仅只是 commit -m 的注释信息写错了,可以这样
git commit --amend
此时会进入默认 vim 编辑器,修改注释完毕后保存就好了。

--soft、--mixed、--hard 几个参数的区别

--mixed:

意思是:不删除工作空间改动代码,撤销 commit,并且撤销 git add . 操作
这个为默认参数,git reset --mixed HEAD^ 和 git reset HEAD^ 效果是一样的。

--soft(安全的)

不删除工作空间改动代码,撤销 commit,不撤销 git add .

--hard

删除工作空间改动代码,撤销 commit,撤销 git add . 
注意完成这个操作后,就恢复到了上一次的 commit 状态。

4.11

1、map() 和 reduce() 函数

javascript
// // 让 2s 输出 ‘hello world’ 完成 test。
function test(callback) {
  setTimeout(() => {
    callback('jing');
  }, 2000);
}

test(function (str) {
  console.log(str);
});

const arr1 = [1, 2, 3, 4, 5];
// arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
let sum = arr1.reduce((acc, cur) => {
  // 0 + 10 => 10
  // 10 + 20 => 30
  // => 30
  console.log(acc, cur);
  return acc + cur;
}, 0);
// 回调函数第一次执行时,accumulator 和currentValue的取值有两种情况:
// 如果调用reduce()时提供了initialValue
// accumulator取值为initialValue,currentValue取数组中的第一个值;
// 如果没有提供 initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。
console.log(sum);

const arr = [{ age: 10 }, { age: 20 }];

// Array.prototype.myMap = function (cb) {
//   let t = [];
//   for (let i = 0; i < this.length; i++) {
//     t.push(cb(this[i]));
//     console.log(this[i])
//   }
//   console.log(t, '------')
//   return t;
// }
Array.prototype.myMap = function (cb) {
  return this.reduce((acc, current) => {
    // [] {age: 20}
    let res = cb(current);
    return acc.concat(res);
  }, []);
};
// // 先定义一个
// // 在返回
// // 写成 reduce

const newArr = arr.myMap((e) => {
  return {
    ...e,
    age: e.age * 2
  };
});
console.log(newArr);

2、npm 包 rimraf 的使用

  • rimraf.sync(路径,路径下某个文件夹的名字)    同步删除某个文件夹
  • rimraf.sync(path.join(process.cwd(),'文件夹名'))  同步删除某个文件夹

4.12

1、leetcode 151

api 法

javascript
var reverseWords = function (s) {
  return s
    .split(' ')
    .filter((item) => item)
    .reverse()
    .join(' ');
};

双指针法

javascript
/**
 *
 * @param {String} s
 */

var reverseWords = function (s) {
  let str = s.trim(); //去除两端空格
  let i = (j = str.length - 1);
  let jing = [];
  while (i >= 0) {
    while (str[i] != ' ' && i >= 0) {
      i--;
    }
    jing.push(str.substring(i + 1, j + 1)); //切割子串
    while (str[i] == ' ') {
      i = i - 1;
    }
    j = i;
  }
  return jing.join(' '); //数组变字符串
};

console.log(reverseWords('  hello   world!  ')); //world! hello

注意

  • substring()方法返回一个字符串在开始索引到结束索引之间的一个子集, 或从开始索引直到字符串的末尾的一个子集。
  • str.substring(indexStart[, indexEnd])
  • 参数

indexStart——需要截取的第一个字符的索引,该索引位置的字符作为返回的字符串的首字母。
indexEnd——可选。一个 0 到字符串长度之间的整数,以该数字为索引的字符不包含在截取的字符串内

4.13

1、react 入门学习

  • react 中只能通过setState来修改state中的数据——immutable


image.png

  • TodoList 代码优化


image.png

image.png

image.png

2、一些重点

  • react 采用声明式开发——可以减少大量 dom 代码
  • 可以与其他框架并存
  • 组件化
  • 单向数据流——父组件可以向子组件传数据,但是子组件不能改变这个数据
  • react 是一个视图层框架——大型项目需要其他数据层框架的支持
  • react 采用函数式编程——更容易自动化测试

4.14

手写一个深拷贝

javascript
/**
 * 手写一个深拷贝
 */
function deepClone(obj = {}) {
  // 如果obj不是对象和数组 或者是null 直接返回
  if (typeof obj !== 'object' || obj == null) {
    return obj;
  }

  let result; //初始化返回结果

  // 判断是对象还是数组
  if (obj instanceof Array) {
    result = [];
  } else {
    result = {};
  }

  for (let key in obj) {
    // 判断是否是自己的属性和方法
    if (obj.hasOwnProperty(key)) {
      // 递归调用
      result[key] = deepClone(obj[key]);
    }
  }
  return result; //返回结果
}

const obj1 = {
  age: 20,
  name: 'xxx',
  address: {
    city: 'beijing',
    jing: {
      love: 'hao',
      age: 20,
      address: '永新县'
    }
  },
  arr: ['a', 'b', 'c']
};

const obj2 = deepClone(obj1);
obj2.arr[0] = 'a1'; //改变属性值
obj2.address.city = 'shanghai'; //改变属性值
console.log(obj1.address.city); //测试
console.log(obj1.arr[0]); //测试
console.log(obj2.address.jing);

4.15

1、LeetCode 445 两数之和 2

javascript
/*
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
function ListNode(val) {
  this.val = val;
  this.next = null;
}
var a1 = new ListNode(5);
var a2 = new ListNode(0);
var a3 = new ListNode(2);
a1.next = a2;
a2.next = a3;

var a4 = new ListNode(2);
var a5 = new ListNode(9);
var a6 = new ListNode(8);
a4.next = a5;
a5.next = a6;

var addTwoNumbers = function (l1, l2) {
  let arr1 = [],
    arr2 = []; //定义两个数组存放链表数据
  while (l1) {
    arr1.push(l1.val);
    l1 = l1.next;
  }
  while (l2) {
    arr2.push(l2.val);
    l2 = l2.next;
  }

  let jing = 0;
  let dummy;
  while (arr1.length > 0 || arr2.length > 0 || jing !== 0) {
    let sum1 = arr1.length > 0 ? arr1.pop() : 0;
    let sum2 = arr2.length > 0 ? arr2.pop() : 0;
    let sum = sum1 + sum2 + jing;
    jing = (sum / 10) | 0; //按位或操作符 也常用来取整
    let newNode = new ListNode(sum % 10);
    newNode.next = dummy;
    dummy = newNode;
  }
  return dummy;
};
// addTwoNumbers(a1, a4)
console.log(addTwoNumbers(a1, a4));

注意:

2、react 基础学习

  • PropTypes 和 defaultProps 用于类型检测
  • state 和 props 改变都会重新执行一次 render() 函数
  • 父组件的 render() 函数执行一次 所有的子组件都会执行一次 render()函数

3、react 虚拟 DOM

  • 1、state 数据
  • 2、JSX 模板
  • 3、数据 + 模板 生成虚拟 DOM (虚拟 DOM 就是一个 JS 对象,用它来描述真实的 DOM)
javascript
//虚拟DOM如下
['div', { id: 'jing' }, ['span', {}, 'hello world']];
  • 4、用虚拟 DOM 的结构生成真实的 DOM 来显示
javascript
//真实DOM如下
<div id="jing">
  <span>hello world</span>
</div>
  • 5、state 发生了变化
hello world——hello jing
  • 6、数据 + 模板 生成新的虚拟 DOM (极大的提升了性能)
javascript
//虚拟DOM如下
['div', { id: 'jing' }, ['span', {}, 'hello jing']];
  • 7、比较原始虚拟 DOM 和 新的虚拟 DOM 的差异,发现差异是 span 标签中的内容**(极大的提升了性能)**
  • 8、最后只要操作 DOM 改变 span 中的内容就可以了

4.16

1、纯函数的概念

  • 没有任何副作用
  • 易于测试
  • 易于缓存

2、手写实现  lodash.js 中的  _.memoize()

html
<script src="https://cdn.bootcss.com/lodash.js/4.17.15/lodash.min.js"></script>
<script>
  // 纯函数
  // FP:数学家
  // f(x) = x ^ 2 + b
  // 没有任何副作用,同样的输入一定会有同样的输出
  const add = (a, b) => a + b;
  // add(1, 2) => 3 结果缓存起来
  // add(1, 2) => 3 下一次输入 1,2 ,得到结果 3,3 其实没必要计算
  // add(1, 2) => 3
  let c = 100;
  const add1 = (a, b) => a + b + c;
  // add1(10, 20) => 130
  // c = 200
  // add1(10, 20) => 230 ?

  const add3 = (a, b) => {
    // 副作用 会对外部环境造成影响
    c = 300;
    console.log(c);
    return a + b;
  };
  // fs.readFile('./index.html', 'utf8', (err, res) => {
  //   console.log(res);
  // })
  // Math.random();  Date.now()
  // 业务代码:不是全部用 FP,可能会用到 FP 其中几个思想
  // node

  // 优点:
  // 易于测试
  // expect(add(10, 20)).equal(30)
  // 构造外部变量 c = 10, 准备外部 index.html
  // expect(add1(10, 20)).equal(40)
  // 易于缓存
  function min(a, b) {
    console.log('re cal');
    return a - b;
  }
  console.log(min(5, 4));
  console.log(min(5, 4));
  console.log(min(5, 4));
  const mMin = _.memoize(min);
  // add 有缓存功能
  console.log(mMin(10, 8));
  console.log(mMin(10, 8));
  console.log(mMin(10, 8));
  // 缓存在 map
  let map = {};
  function minMemoize(a, b) {
    let key = `${a}${b}`;
    if (map[key] !== undefined) return map[key];
    console.log('re cal');
    let res = a - b;
    // 缓存一下, 依据什么东西??
    map[key] = res;
    return res;
  }
  function memoize(fun) {
    let map = {};
    // 带有缓存
    return function (...args) {
      // fun 需要的 args
      let key = JSON.stringify(args);
      if (map[key] !== undefined) return map[key];
      // 真正的计算
      let res = fun(...args);
      // 缓存一下
      map[key] = res;
      //
      return res;
    };
  }
  const mMin1 = memoize(min);
  console.log(mMin1(12, 12));
  console.log(mMin1(12, 12));
  console.log(mMin1(12, 12));
</script>

4.17

1、react 基础学习

1、react.createElement()

  • 接受三个参数 react.createElement('div', {}, 'jingjinghaohao')
  • 参数用途参照虚拟 DOM

2、react 中 ref 的使用(获取 DOM)

image.png

3、setState()是一个异步方法

  • 错误

image.png

  • 正确

image.png

4、react 生命周期函数

image.png

4.18

1、react 生命周期函数的应用

  • 前面讲到在 react 中,父组件的 render() 函数执行的时候,子组件中的 render() 函数也会重新执行。为了减少不必要的页面重新渲染,可以在子组件中的 shouldComponentUpdate() 生命周期函数中返回 false。
  • componentDidMount()中做获取数据操作最好

2、pureComponent(纯组件)

  • React15.3 中新加了一个  PureComponent  类,顾名思义, pure  是纯的意思,PureComponent  也就是纯组件,取代其前身  PureRenderMixin ,PureComponent  是优化  React  应用程序最重要的方法之一,易于实施,只要把继承类从  Component  换成  PureComponent  即可,可以减少不必要的  render  操作的次数,从而提高性能,而且可以少写  shouldComponentUpdate  函数,节省了点代码。

4.19

1、leetcode 11 题 盛最多水的容器

javascript
/**
 * @param {Array} height
 */

var maxArea = function (height) {
  let jing = 0,
    max = 0;
  let i = 0,
    j = height.length - 1;
  while (j > i) {
    if (height[j] > height[i]) {
      jing = height[i] * (j - i);
      i++;
    } else {
      jing = height[j] * (j - i);
      j--;
    }
    max = Math.max(max, jing); //每次更新最大值
  }
  return max;
};
console.log(maxArea([1, 8, 6, 2, 5, 4, 8, 3, 7]));
// 49

2、redux 入门学习

createStore()—创建 store 的 API

javascript
import { createStore } from 'redux';
import reducer from './reducer';
const store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());

export default store;

store.getState()—获取 store 数据

javascript
this.state = store.getState();

store.dispatch()—派发 action 给 reducer

javascript
handleInputChange(e) {
    const action = {
      type: 'change_input_value',		//type用于reducer中判断
      value: e.target.value
    }
    store.dispatch(action);
  }

store.subscribe()—订阅 store 改变

javascript
store.subscribe(this.handleStoreChange);

只要 store 里面的数据发生改变,**store.subscribe()**这个函数的回调函数就会执行

4.20

1、react 中的 UI 组件和容器组件

2、无状态组件

  • 当一个普通组件中只有一个 render() 函数的时候,可以用无状态组件替换。
  • 无状态组件就是一个函数
  • UI 组件一般可以用无状态组件替换

3、无状态组件的优势

  • 无状态组件性能更好
  • 因为无状态组件没有继承自 component,没有各种生命周期函数。

4、redux 的中间件

  • 中间件是 redux 的中间件,不是 react 的中间件
  • 中间件两边是 action 和 store

4.21

1、typescript 基础类型的认识

  • number
  • string
  • boolean
  • null
  • undefined
typescript
let isDone: boolean = false;

let age: number = 20;
let binaryNumber: number = 0b1111;

let firstName: string = 'viking';
let message: string = `Hello, ${firstName}, age is ${age}`;

let u: undefined = undefined;
let n: null = null;

// null 和 undefined 是所有类型的子类型
let num: number = undefined;

// any类型
let notSure: any = 4;
notSure = 'maybe it is a string';
notSure = true;

notSure.myName;
notSure.getName();

// 联合类型
let numberOrString: number | string = 234;
numberOrString = 'abc';

// 数组类型
let arrOfNumbers: number[] = [1, 2, 3, 4];
arrOfNumbers.push(5);

// 元组
let user: [string, number] = ['viking', 1];

2、cookie session


HTTP 协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录;Session 和 Cookie 的主要目的就是为了弥补 HTTP 的无状态特性

Session 的缺点

Session 机制有个缺点,比如 A 服务器存储了 Session,就是做了负载均衡后,假如一段时间内 A 的访问量激增,会转发到 B 进行访问,但是 B 服务器并没有存储 A 的 Session,会导致 Session 的失效。

  • 会话 Cookie 中缺少 HttpOnly 属性会导致攻击者可以通过程序(JS 脚本、Applet 等)获取到用户的 Cookie 信息,造成用户 Cookie 信息泄露,增加攻击者的跨站脚本攻击威胁。
  • 如果在 Cookie 中没有设置 HttpOnly 属性为 true,可能导致 Cookie 被窃取。

禁用 Cookies,如何使用 Session ?

  • 如果禁用了 Cookies,服务器仍会将 sessionIdcookie 的方式发送给浏览器,但是,浏览器不再保存这个 cookie (即 sessionId ) 了。
  • 如果想要继续使用 session,需要采用 url 重写的方式来实现

cookie也是支持跨域的,http请求的时候设置 withCredentials=true 即可;JWT 本身没有什么支不支持跨域的概念,就看你把它放哪儿了;cookieJWT 原理还是有区别的,如果使用 cookie 的话,实际上cookie里面存的是 sessionID,后端就需要有个地方存储 sessionID和登录信息的映射,如果使用JWT的话,不需要这个地方来存映射,其实就是用计算时间换存储空间。

4.24

3、react hooks 初识

typescript
import React, { useState, useEffect } from 'react';
import useMousePosition from '../hooks/useMousePosition'; //自定义 Hooks
const LikeButton: React.FC = () => {
  const [like, setlike] = useState(0); //useState
  const [on, setOn] = useState(true);
  const positions = useMousePosition();
  useEffect(() => {
    document.title = `点击了${like}`;
  });
  return (
    <>
      <button
        onClick={() => {
          setlike(like + 1);
        }}
      >
        {like}
      </button>
      <button
        onClick={() => {
          setOn(!on);
        }}
      >
        {on ? 'on' : 'off'}
      </button>
      <h1>
        X: {positions.x}, Y : {positions.y}
      </h1>
    </>
  );
};

export default LikeButton;

4.25

js web API

1、DOM 的本质

2、DOM 节点操作

  • property:修改对象属性,不会体现到 html 结构中
  • attribute:修改 html 属性,会改变 html 结构
  • 两者都有可能引起 DOM 重新渲染  

3、DOM 结构操作

4、性能优化

  • DOM 查询做缓存
javascript
// 不缓存 DOM 查询结果
for (let i = 0; i < document.getElementsByTagName('p').length; i++) {
  // 每次循环 都会计算 length 频繁进行 DOM 查询
}
// 缓存 DOM 查询结果
const pList = document.getElementsByTagName('p');
const len = pList.length;
for (let i = 0; i < len; i++) {
  // 缓存 len 只进行了一次 DOM 查询
}
  • 把频繁的操作改为一次性操作 document.createDocumentFragment()
javascript
const list = document.getElementById('list');

// 创建一个文档片段,此时还没有插入到 DOM 结构中
const frag = document.createDocumentFragment();

for (let i = 0; i < 20; i++) {
  const li = document.createElement('li');
  li.innerHTML = `List item ${i}`;

  // 先插入文档片段中
  frag.appendChild(li);
}

// 都完成之后,再统一插入到 DOM 结构中
list.appendChild(frag);

console.log(list);

4.28

  • 如果对象有两个具有相同名称的键,则将替前面的键。它仍将处于第一个位置,但具有最后指定的值。
javascript
const obj = { a: 'one', b: 'two', a: 'three' };
console.log(obj);
//{ a: "three", b: "two" }
  • 所有对象键(不包括Symbols)都会被存储为字符串,即使你没有给定字符串类型的键。 这就是为什么obj.hasOwnProperty('1')也返回true
  • 上面的说法不适用于Set。 在我们的Set中没有“1”set.has('1')返回false。 它有数字类型1set.has(1)返回true
javascript
const obj = { 1: 'a', 2: 'b', 3: 'c' };
const set = new Set([1, 2, 3, 4, 5]);

obj.hasOwnProperty('1');
obj.hasOwnProperty(1);
set.has('1');
set.has(1);

//true true false true
  • 使用var关键字,您可以用相同的名称声明多个变量。然后变量将保存最新的值。
  • 您不能使用letconst来实现这一点,因为它们是块作用域的。
  • 关闭选项卡后,将删除存储在sessionStorage中的数据。
  • 如果使用localStorage,数据将永远存在,除非例如调用localStorage.clear()

4.29

html 块级元素和行内元素

https://www.cnblogs.com/yanqiu/p/8987126.html?tdsourcetag=s_pctim_aiomsg

querySelector 和 getElementBy、、、系列的区别

  • 前者查出来的是一个 NodeList
  • 后者是一个 HTMLCollection

4.30

我的婧婧过生日,希望她身体健康、快快乐乐。

5.2

1、div 垂直居中

方法一

  • magin:auto;
  • position:absolute;
  • left: 0;  bottom: 0;   right: 0;  top: 0;

方法二

  • left:50%;    top:50%;
  • transform: translate(-50%, -50%)
  • position: absolute;

方法三

  • left:50%;    top:50%;
  • magin-top: -height/2;
  • magin-left: -width/2;

2、antd 初使用

  • Icon 的使用方式——版本 3 和版本 4 不一样了

5.3

Vue  "复"习

1、自定义 v-model

  • props
  • mode

注意一一对应如下图!!
image.png

2、插槽 slot

  • 默认插槽
  • 作用域插槽
  • 具名插槽

3、动态组件

  • 通过 :is

image.png

  • 当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题。
  • 这时可以用 keep-alive 把频繁切换、想缓存的组件缓存下来,在用 keep-alive 包裹的组件之间切换的时候,上一个组件不会被销毁,进入的组件也不会重新渲染。

4、异步组件

  • 不在统一的引入组件,而在需要用的时候用 import() 函数导入
  • 这样可以使得一个大组件加载的更快,性能优化的意思。


就是用图片中下面这种加载组件的方式代替上面的那个。起到 异步加载 的效果

image.png

4、vue 抽取不同组件相同逻辑

  • mixins (就是一段数据代码)

  • mixins 不是完美的解决方案

  • vue 3.0 Composition API 旨在解决这个问题

5.5

leetcode 384

javascript
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

function shuffle(arr) {
  let len = arr.length;
  for (let i = 0; i < len; i++) {
    let randomIndex = Math.floor(Math.random() * (len - i)); //向下取整
    [arr[len - i - 1], arr[randomIndex]] = [arr[randomIndex], arr[len - i - 1]];
  }
  return arr;
}
console.log(shuffle(arr));

5.10

初识 Redis

js
set jing meinv    //添加 key-value数据

get jing  //meinv 通过 key 获取 value

del jing         // 删除一个数据

setex key time value  //设置过期时间

keys *  //查出所有已经设置的 key

redis-server.exe redis.windows.conf 手动启动 Redis redis-cli -p 6378 指定端口启动 auth 密码 验证密码

live-server --cors 设置允许跨域访问

5.12

next 中的页面跳转

js
import Link from 'next/link';
import Router from 'next/router';
import { Button } from 'antd';
export default () => {
  function goToB() {
    Router.push('/test/b');
  }
  return (
    <>
      <Link href="/a">
        <Button>Index</Button>
      </Link>
      <Button onClick={goToB}>test B</Button>
    </>
  );
};
  • 1、采用 Link 标签
  • 2、采用 Router.push('路径')

Link 标签其实底层也是用 Router.push('路径')来实现页面跳转的

5.15

next 中 _app.js 作用

  • 固定 Layout
  • 保持一些公用的状态
  • 给页面传入一些自定义数据(重写一个 MyApp)
  • 自定义错误处理
js
import App from 'next/app';

import 'antd/dist/antd.css';
import Layout from '../compontents/Layout';
class Myapp extends App {
  static async getInitialProps({ Component, ctx }) {
    console.log('app init');
    let pageProps;
    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx);
    }
    return {
      pageProps
    };
  }

  render() {
    const { Component, pageProps } = this.props;
    console.log(Component);
    return (
      <Layout>
        <Component {...pageProps} />
      </Layout>
    );
  }
}

export default Myapp;

5.17

State Hooks 基础

  • 实现一个计时器
js
import React, { useEffect, useState, useReducer } from 'react';

//类组件
class MyCount extends React.Component {
  state = {
    count: 0
  };

  componentDidMount() {
    this.interval = setInterval(() => {
      this.setState({
        count: this.state.count + 1
      });
    }, 1000);
  }

  // 在 componentWillUnmount 生命周期函数里面清除定时器之类的
  // 不然会造成内存泄漏
  componentWillUnmount() {
    if (this.interval) {
      clearInterval(this.interval);
    }
  }

  render() {
    return <span>{this.state.count}</span>;
  }
}

// useReducer
// 定义一个 'Reducer' 函数,它接受两个参数,第一个为 state,第二个为 action。 然后根据传进来的 action 操作 state
function countReducer(state, action) {
  switch (action.type) {
    case 'add':
      return state + 1;
    case 'minus':
      return state - 1;
    default:
      return state;
  }
}

// 函数组件 hooks
function MyCountFunc() {
  // const [count, setCount] = useState(0)  //useState实现

  // useReducer 接受一个操作state的函数和 state 的初始值
  const [count, dispatchCount] = useReducer(countReducer, 0); //useReducer实现

  useEffect(() => {
    const interval = setInterval(() => {
      // setCount(count => count + 1)    //useState
      dispatchCount({ type: 'minus' });
    }, 1000);
    return () => clearInterval(interval);
  }, []);
  return <span>{count}</span>;
}

export default MyCountFunc;

Effect Hooks 基础

useEffect

  • 页面初始化useEffect会执行 return 前面的代码。
  • 然后页面的任何数据更新了,组件就会重新渲染,就是先把原来的组件取消挂载,然后挂载重新渲染的组件。
  • 如下代码,初始化打印 effect invoked,更新页面先打印effect deteched,然后打印effect invoked
  • useEffect里面第二个参数是个数组 [],这个数组里面放useEffect用到的外面的数据(依赖)。然后useEffect就会根据数组里面的数据来判断要不要重新执行。只有写在里面的数据发生改变的时候,useEffect才会重新执行。如果是个空数组,不管啥数据改变了,useEffect都会执行。
js
useEffect(() => {
  console.log('Effect invoked');
  return () => console.log('Effect deteched');
}, []);

useLayoutEffect 与 useEffect 的区别

  • useLayoutEffectuseEffect 先执行。
  • useLayoutEffect 是在页面更新时DOM树渲染成HTML之前执行的
  • useEffect 是在页面更新时DOM树渲染成 HTML 之后执行的
  • 所以很少用 useLayoutEffect,因为如果useLayoutEffect执行时间过长,页面渲染就会等待,造成页面卡顿,降低用户体验。

5.18

Redux reducer

1、是一个纯粹的方法,不应该有任何副作用

  • 就是不能在 reducer 中依赖外部变量。

2、有任何数据更新应该返回新的对象

  • redux 中使用 reducer 返回 state 的时候必须返回一个新对象!!!
  • 因为在 js 中判断一个对象是否相等比较的是它们在栈中对堆的引用地址。
  • 如果不返回一个新对象,在 ReactDOM 对比节点是否相同的时候就算你修改了某个状态,但是返回的还是原来的对象, React 就会认为此 DOM 没变,就会产生错误。

3、可以用 combineReducers 合并不同的 reducer

实例代码

js
import { createStore, combineReducers } from 'redux';

const countInitialState = {
  count: 0
};

const userInitialState = {
  username: 'jing'
};

const ADD = 'ADD';

function countReducer(state = countInitialState, action) {
  // console.log(state, action)
  switch (action.type) {
    case ADD:
      return { count: state.count + 1 };
    default:
      return state;
  }
}

const UPDATE_USERNAME = 'UPDATE_USERNAME';
function userReducer(state = userInitialState, action) {
  switch (action.type) {
    case UPDATE_USERNAME:
      return {
        ...state,
        username: action.username
      };
    default:
      return state;
  }
}

// 使用 combineReducers 合并 reducer
const allReducers = combineReducers({
  count: countReducer,
  username: userReducer
});

// createStore中 传入合并后的 reducer
const store = createStore(allReducers, {
  count: countInitialState,
  username: userInitialState
});

// console.log(store.getState())
// store.dispatch({ type: 'ADD' })

store.subscribe(() => {
  console.log(store.getState());
});

// 通过 dispatch 一个 action 来操作数据
store.dispatch({ type: ADD });
store.dispatch({ type: UPDATE_USERNAME, username: 'jingjing20' });

// console.log(store.getState())

export default store;

5.19

OAuth 认证方式如何保证安全性

https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/

5.20

今天放假

咋代码也不能停!

LeetCode 125 验证回文串

  • 题目描述 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。

说明:本题中,我们将空字符串定义为有效的回文串。

示例 1:

输入: "A man, a plan, a canal: Panama" 输出: true 示例 2:

输入: "race a car" 输出: false

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/valid-palindrome

解法一(API 大法)

js
var isPalindrome = function (s) {
  let newStr = s
    .replace(/[^0-9a-zA-Z]/g, '')
    .toLowerCase()
    .split('');
  return newStr.join('') == newStr.reverse().join('');
};

解法二(双指针)

js
var isPalindrome = function (s) {
  let newStr = s.replace(/[^0-9a-zA-Z]/g, '').toLowerCase();
  let l = 0,
    r = newStr.length - 1;

  while (l < r) {
    if (newStr[l] != newStr[r]) {
      return false;
    }
    l++;
    r--;
  }
  return true;
};

5.21

进程与线程

概念

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中实际运作单位。

区别

内存使用方面的区别

  • 进程拥有操作系统分配给它的单独的内存,默认情况一个进程的分配的内存无法给另一个进程共享。
  • 一个进程里面的所有线程可以共享进程内存。

通信机制方面的区别

  • 进程之间很难互通,可以通过 IPC (进程间通信)。
  • 线程之间共用一块内存,通信方便快捷。

量级方面的区别

  • 线程相对于进程创建起来更轻、更快,使用的资源更少。

nodemon 使用

"start": "nodemon --watch main.js --exec \"electron .\""

  • --watch 监听哪个文件
  • --exec 执行哪个文件
  • 用 \ 转义""

5.22

window.onload 和 DOMContentLoaded 的区别

DOM 完整的解析过程:

  • 1、解析 HTML 结构
  • 2、加载外部脚本和样式表文件
  • 3、解析并执行脚本代码(js)
  • 4、DOM 树构建完成
  • 5、加载图片等外部文件
  • 6、页面加载完毕

在第 4 步的时候 DOMContentLoaded 事件会被触发。

在第 6 步的时候 load 事件会被触发。

5.23

Infinity

  • Infinity 是一个 JavaScript 标准内置对象

  • 全局属性 Infinity 是一个数值,表示无穷大。

  • Infinity 是全局对象(global object)的一个属性,即它是一个全局变量。

  • Infinity 的初始值是 Number.POSITIVE_INFINITY。Infinity(正无穷大)大于任何值。该值和数学意义上的无穷大很像,例如任何正值乘以 Infinity 为 Infinity, 任何数值除以 Infinity 为 0(注意,这里说的是正数乘以 Infinity 为 Infinity!Infinity * 0 为 NaN。

slice(begin, end)

begin

  • 提取起始处的索引(从 0 开始),从该索引开始提取原数组元素。
  • 如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取。
  • slice(-2) 表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。
  • 如果省略 begin,则 slice 从索引 0 开始。
  • 如果 begin 大于原数组的长度,则会返回空数组。

end

  • 提取终止处的索引(从 0 开始),在该索引处结束提取原数组元素。
  • slice 会提取原数组中索引从 begin 到 end 的所有元素
  • slice(1,4) 会提取原数组中从第二个元素开始一直到第四个元素的所有元素 (索引为 1, 2, 3 的元素)。
  • 如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。 slice(-2,-1) 表示抽取了原数组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素)。
  • 如果 end 被省略,则 slice 会一直提取到原数组末尾。
  • 如果 end 大于数组的长度,slice 也会一直提取到原数组末尾。

9.1

webpack 中的 HappyPack

  • 由于运行在 Node.js 之上的 Webpack 是单线程模型的,所以 Webpack 需要处理的事情需要一件一件的做,不能多件事一起做。 我们需要 Webpack 能同一时间处理多个任务,发挥多核 CPU 电脑的威力,HappyPack 就能让 Webpack 做到这点,它把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。

图片转 base64 格式

  • 一般小于 8kb 是明显可以的
  • 超过 16kb 一般是不建议的
  • 超过 32kb 一般是明显不应该的

10.22

echarts 纵轴展示 0% ~100%

js
optionCopy.yAxis = [
  {
    type: 'value',
    min: 0,
    max: 100,
    interval: 25,
    axisLabel: {
      fontSize: 10,
      formatter: '{value} %'
    }
  }
];

10.26

a 标签上的 href 用来向后端传递参数时只能写死,不能用变量。

给 DOM 元素添加属性

js
this.linkAdom.setAttribute('href', `kim://thread?id=${this.groupId}&type=4`);

11.02

监听浏览器切换 Tab 页的 API visibilitychange

js
document.addEventListener('visibilitychange', function () {
  // 浏览器切换事件
  if (document.visibilityState === 'hidden') {
    // 离开当前tab标签
    console.log('离开当前tab标签'); // 这里可以做一些我们想做的操作,比如说清除页面的轮刷定时器。
  } else {
    // 回到当前tab标签
    console.log('回到当前tab标签'); // 这里可以做一些我们想做的操作,比如重新开启页面的轮刷定时器。
  }
});

11.6

some 位运算

求除以 2 的余数可以用位与运算符:n & 1,如下所示:

js
0101
    &
0001
0001  5 & 1 = 1
js
0110
    &
0001
0000  6 & 1 = 0

上面位运算的应用

  • LeetCode 1356. 根据数字二进制下 1 的数目排序
js
给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。
如果存在多个数字二进制中 1 的数目相同,则必须将它们按照数值大小升序排列。
请你返回排序后的数组。

示例 1

输入:arr = [0,1,2,3,4,5,6,7,8]
输出:[0,1,2,4,8,3,5,6,7]
解释:[0] 是唯一一个有 01 的数。
[1,2,4,8] 都有 11
[3,5,6] 有 21
[7] 有 31
按照 1 的个数排序得到的结果数组为 [0,1,2,4,8,3,5,6,7]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-integers-by-the-number-of-1-bits
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
js
/**
 * @param {number[]} arr
 * @return {number[]}
 */
var sortByBits = function (arr) {
  const sortJing = (n) => {
    let count = 0;
    while (n != 0) {
      count += n & 1;
      n = n >> 1;
    }
    return count;
  };
  return arr.sort((a, b) => {
    return sortJing(a) - sortJing(b) || a - b;
  });
};

看到的字符串 API

String.fromCharCode()

  • 静态 String.fromCharCode() 方法返回由指定的 UTF-16 代码单元序列创建的字符串。
js
String.fromCharCode(97); // a

JavaScript 中的字符集

  • 为什么 JavaScript 不选择更高级的 UTF-16,而用了已经被淘汰的 UCS-2 呢?

  • 答案很简单:非不想也,是不能也。因为在 JavaScript 语言出现的时候,还没有 UTF-16 编码。

  • 1995 年 5 月,Brendan Eich 用了 10 天设计了 JavaScript 语言;10 月,第一个解释引擎问世;次年 11 月,Netscape 正式向 ECMA 提交语言标准。对比 UTF-16 的发布时间(1996 年 7 月),就会明白 Netscape 公司那时没有其他选择,只有 UCS-2 一种编码方法可用!

JavaScript 字符函数的局限

  • 由于 JavaScript 只能处理 UCS-2 编码,造成所有字符在这门语言中都是 2 个字节,如果是 4 个字节的字符,会当作两个双字节的字符处理。JavaScript 的字符函数都受到这一点的影响,无法返回正确结果。 现在 ES6 基本解决了这个问题。

来源 http://www.ruanyifeng.com/blog/2014/12/unicode.html

JS 变量提升的本质

  • 变量提升只是一种表象
  • 透过表象背后隐藏的其实是 JavaScript 的一些重要特性
  • JavaScript 是一种动态语言 它有 编译、执行两个阶段
  • JS 和其他语言一样,都要经历编译和执行阶段。正是在这个短暂的编译阶段里,JS 引擎会搜集所有的变量声明,并且提前让声明生效。至于剩下的语句,则需要等到执行阶段、等到执行到具体的某一句的时候才会生效。这就是变量提升背后的机制。

MIT Licensed