Hawei

Say Hi.


  • Home

  • About

  • Tags

  • Categories

  • Archives

1.Type.md

Posted on 2020-04-12 | In deep-js-foundations-v2-noteBook

Deep-js-fundations

Type

js类型的描述

语言特性: 动态语言, 在运行时确定类型, 所以与静态语言不同的是,在初始化的时候并不需要我们指定变量的类型.

分类:

  1. 基本类型
    • undefined
    • string
    • number
    • boolean
    • symbol
    • null
  2. 引用类型
    • object
    • function
    • array
  3. 草案阶段的类型
    • bigInt

bigInt: 可以表示无限大的数, 例如:

1
2
var n = 42n;
typeof n === 'bigint';

typeof

使用typeof可以判断的类型有

  • undefined
  • number
  • string
  • boolean
  • object
  • symbol
  • function

这里要注意一个特殊的例子:

1
typeof null === 'Object'

请写一个增强的判断js类型的函数.要求可判断引用类型(arr, funciton, Data)

1
2
3
4
5
const isType = (value) => {
return Object.prototype.toString.call(value).match(/(?<= )\w+/)[0]
// String Number Null Undefined Object Date RegExp Symbol Boolean Function
}
// 这里涉及了正则的一个知识,就是匹配以xxx开头的字符串(不包含xxx), 那么就要使用正则的前置断言(?<=[这是xxx的内容])

undefined vs undeclared

这是两个不相等的关系.undeclared:在我可以触及的作用域从未创建过。undefined: 我肯定这是一个变量, 只是现在还没有值.

而在ES6语法中,我们在let定义一个变量之前去使用它,那么就会报错,这是临时死区的概念: 在定义这个变量之前的scoped都是临时死区, 无法访问。

1
2
typeof a; // referentceError.
let a;

NaN 与 isNaN

NaN 并不是指“Not A Number”, 虽然它的翻译确实如此.

NaN指的是一个无效的number, Invalid number.

我认为就是经过运算后无法转换成数字类型的都是NaN.

1
2
3
4
5
6
let myAge  = Number(42) // 42
let myCode = Number('tx123') // NaN
myAge - 'Some' // NaN
NaN === NaN // false
isNaN(myCode) // true
Number.isNaN(myCode) // false

negative Zero

让我们看一下-0的特性

1
2
3
4
5
6
7
8
let a= -0
a === -0
a.toString() // '0'
a === 0 // true
a > 0 // false
a < 0 // false
Object.is(a, -0) // true
Object.is(a, 0) // false
  1. -0 等于0
  2. -0 不大于0
  3. -0 不小于0
  4. 只能用Obect.is进行判断

应用:

1
2
3
4
5
6
7
Math.sign(-3) // -1
Math.sign(3) // 1
Math.sign(0) // 0
// 判断正负的函数
function sign (v) {
return v !== 0 ? Math.sign(v) : Object.IS(V, -0) ? -1 : 1;
}

Object.is polyfill

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// TODO: define polyfill for `Object.is(..)`
if (Object.is || true) {
Object.is = (a, b) => {
// 工具函数
const isNegZero = v => v == 0 && (1 / v) == -Infinity
const isNaN = v => v !== v
const xNegZero = isNegZero(a)
const yNegZero = isNegZero(b)

if (xNegZero || yNegZero) {
return xNegZero && yNegZero
} else if (isNaN(a) && isNaN(b)) {
return true
} else {
return x === y
}
}
}

fundational Object

use New Keyword

  1. object
  2. array
  3. function
  4. data
  5. regexp
  6. error

don’t use new Keyword

  1. string
  2. number
  3. boolean
1
2
3
4
var sum = new Function('a', 'b', 'return a + b');
console.log(sum(2, 6));
// expected output: 8
Function.length // 数组参数的长度

抽象运算符(Abstract Operation:ToPrimitive)

如果我们要使用到基础类型, 那么我们就会通过一个算法去转换它, 成为我们需要的类型

number

  1. valueOf()
  2. toString()

->to number
原则: 把所有值转换为number后返回

  1. Object: 调用valueOf方法
  2. String: 调用toPrimitive
  3. 调用顺序是: valueOf()->toString()
  4. 但是要注意, 所有的valueOf都是返回this
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    // 最普遍的例子
    “” -> 0
    “0” -> 0
    “-0” -> -0
    “009” -> 9
    “3.1415926” -> 3.1415926
    “0.” -> 0
    “.0” -> 0
    “.” -> NaN
    “0xaf” -> 176
    // 特殊字符
    false-> 0
    true-> 1
    null-> 0
    undefind-> 0
    // 特殊例子
    [''] -> 0
    [0''] -> 0
    ['-0'] -> -0
    [null] -> 0
    ['undefind'] -> 0
    [1, 2, 3] -> NaN
    [[[]]]-> 0
    // 如果你重写了valueOf()方法,那么会应用到强制转换上
    {
    valueOf() {
    return 3;
    }
    }
    num = {valueOf() {return 3}}
    num + 1 // 4

String

  1. toString()
  2. valueOf()

->TO String:
原则: 把所有的值强制转化为String后返回

  1. Object: 调用toString方法
  2. String: 调用toPrimitive
  3. 调用顺序是: toString()->valueOf()

看个例子:

1
2
3
4
5
6
7
8
[]->""
[1, 2, 3]-> '1, 2, 3'
[null, undefined]-> '.'
[[[], [], []], []]-> '...'
[...]->'...'

{}-> ‘[Object Object]’
{toString() {return 'X'}}-> "X"

->toBoolean

  1. false
    • “”
    • 0/-0
    • null
    • NaN
    • false
    • undefined
  2. true: !false

coercion rules

大概有以下规则

  1. ‘+’: 如果为加号, 只要有一边是字符串, 则会把两边作为字符串处理
  2. ‘-‘: 只会把运算符两边作为数字来处理
  3. 布尔值:
    • !!
    • 0: false/ !0: true
    • Boolean(value)

常见的触发场景:

  1. 使用模板字符串
  2. 字符串拼接(使用+号)
  3. 对对象的某个属性进行数学运算的时候, 会触发
    1
    2
    3
    4
    5
    6
    const addAStudent = number => number + 1;
    addAStudent(student.count) // 171
    // solution1
    addAStudent(+student.count)
    // solution2
    addAStudent(Number(student.count))

    隐式转换

    访问字符串的长度值,就是一种隐式转换:
    string是基本类, 而这个基本类并不是一个对象,那么js会判定你想要把string当做一个对象访问,以便获取到String的长度值。
    “someText”.length

在所有语言, 我们都要处理类型转换。而在js中,我们遵循的基本原则就是aka(讲道理,我理解就是上面说的三种转换)

边界转换事件

  1. ‘’ -> number
  2. boolean -> number
  3. 3>2>1 || 1>2>3
    边界转换发生在字符串和数字转换之间

强制转换的应用

每个语言都要处理类型转换, 而每个语言都存在边际转换的情况,我们要做的是掌握这些边际问题,然后应用起来。

但是我们可以通过一些编码风格防止这些边界情况,例如使用typescript.以及,在你的代码中使用全等===。

营造学习文化

通过code review的方式, 让团队形成这样一种文化, 有助于帮助成员更好的了解他手中的工具, 当成员收到了代码审查,应该认真的去看,如果你发现了一些愚蠢的事,那么你应该让他过来,认真的说出这件事,让他避开那个边界情况做这样的事,是让大家成为更好的开发者。
你写的代码就像你在跟代码阅读者沟通, 他们应该可以理解。不然你在做的东西就是shit.浪费时间。

code communication

  1. 好的代码本身就是注释
  2. 但是注释本身也是必要的,特别是在一些复杂的业务逻辑上,在入口函数就说明它的入参结构, 功能, 代码组织方式,会减少很多维护者阅读代码的时间

隐式转换

  1. 隐式转换在一些写静态语言的人看来,是一种魔法,他们无法理解,为什么要做这样的事,所以认为这是js语言的弱点。
  2. 隐式转换是一种抽象概念。不是所有抽象都是好的,但是有些抽象是必要的。
  3. 提升代码清晰度的一个方法是,抽象不必要的细节,让阅读者关注我们需要他关注的地方。最常见的例子是: 比较运算符
  4. 我希望你是拥有分析能力的工程师,而不是写代码的猴子

理解特性

原则1: 有用的判断依据是, 你需要读者专注的点是重要的

原则2: 危险的是, 你写的东西如果有让人看不懂的地方,那么这就是危险的

原则3: 让读者能看得懂你的代码,并理解它

== 与 ===

两者区别:
=== 会检测类型与值, == 只会检测value, 那么意味着会触发强制转换

== 算法

  1. 优先转换成数字进行比较
  2. 若为非数字的原语(string, boolean, object, array), 那么会优先转换为原语

边际问题:

1
2
[] == false;
[] == true;

你应该避免进行以下的比较

  1. 使用 == 比较 “”/0/“ ”
  2. 使用 == 比较非原语(boolean/string/number)
  3. 如果要使用到 == true or == false,那么我更建议你去使用 === 做比较

优先使用 ==的情况

遵循两个原则

  1. 明确类型,比不知道类型好
  2. 静态类型(Typescript)不是唯一的方式让你去明确你的类型的方法

如果了解 == 双方的类型

  1. 场景1: == 不适用与不知道类型的比较场景, 当你不确定比较元素的类型的时候,不要使用==
  2. 场景2: == 适用于你知道两者的类型,并且期望它进行转换的场景(当你确定类型一样的情况下 == 与 === 是一样的情况)
  3. 场景3: 两者元素类型不一样的时候,使用 === 这样的逻辑注定错误

总结: 如果类型确定,那么优先使用 == 将是你最好的选择

如果不了解 === 双方的类型

  1. 建议: 如果你不能确认比较双方的类型是什么,那么你不够了解你的代码,建议重构, 基准是你能明白类型是什么
  2. 类型不能确定会让你代码的阅读者困惑, 所以当你需要给代码阅读者明显的信号,让他注意这个地方的时候,请使用 ===
  3. 如果类型处于不确定的状态下, 使用 === 真的是一个保护措施

总结: 如果你代码中,不能确定类型,那么使用 === 保护你的代码时必要措施
当然,如果你代码里都是 === 那么,你要表达的东西是,我不相信(不知道)每一个比较两边的类型

我们写的代码应该是类型确定和明显会让代码质量更高,如果类型确定,那么优先使用== ,如果类型不确定,那么优先使用 === 保护你的代码

futureEnglish-week4.md

Posted on 2020-04-12 | In futureLearnEnglish

week3: About Hobbies

vocabulary:
character
rugby
cricket

A
reading book
not like study
playing football
like cook
dancing
single
music- rock

B 
cooking
music - rock 
dancing

Grammar

The Present Continuous Tense

主语 + Be动词 + 动词-ing

positive
I am playing football.

Nagative
I am not playing football.

Asking question about present continuous tense

Quetion style 1

Be动词 + 主语 + 动词-ing

positive

Are you reading?

futureEnglish.md

Posted on 2020-04-12 | In futureLearnEnglish

week3: About Hobbies

vocabulary:
Coughing
Slapping
Carrying

Singing
Sailing
Sneezing

essay

Presentation
Prayer

Listen pratice

Mo is coughing paracetamol.

Grammar

I like + v-ing(动词ING形式) + Obj(主语)

positive
I like playing football.

Nagative
I don’t like play football.

Expressing strong Like and dislike

like -> love

I like reading./ I love reading

don’t like -> hate

I don’t like study./ I love study.

Asking question about likes and dislikes

Quetion style 1

Do you like + v-ing?

positive

Yes. I do/I love + v-ing

nagative

No, I don’t./I hate + v-ing.

Quetion style 2

What do you like doing?

answer

I like/love + v-ing

Asking more information.

Quetion style 1

What kind of + non + do you like?

answer

I like + adj + non

explames

What kind of books do you like?

I like tech book.

call-apply-bind.md

Posted on 2020-04-12 | In interview

call

先看call做了什么?

  1. call的第一个参数为函数体内部的this指向
  2. 其余作为参数单个传入(非数组)函数体
  3. 立即执行函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Function.prototype.myCall = (context) => {
    if(typeof this !== 'function') {
    throw new TypeError('Error')
    }

    context = context || window
    context.fn = this
    const args = [...arguments].slice(1)
    const result = context.fn(...args)
    delete context.fn
    return result
    }

    apply

    与call的区别在于第一个参数后的传参方式, 是以数组的方式传入
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Function.prototype.myApply = (context) => {
    if(typeof this !== 'function') {
    throw new TypeError('Error')
    }

    context = context || window
    context.fn = this
    const args = [...arguments].slice(1)
    const result = context.fn(args)
    delete context.fn
    return result
    }

bind 主要注意一点是, 记得区分出new和普通调用的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Function.prototype.myBind = (context) => {
if(typeof this !== 'function') {
throw new TypeError('Error')
}

// 获取到函数体
const fnBody = this
const args = [...arguments].slice(1)
return function F() {
// 当使用new 方法调用该函数时
if(this instanceof F) {
return new fnBody(...args, ...arguments)
}
// 正常调用
return fnBody.apply(context, args.concat(...arguments))
}
}

什么是闭包?闭包的作用是什么?.md

Posted on 2020-04-12 | In interview

什么是闭包?闭包的作用是什么?

什么是闭包

Closure是函数有能力记住和访问变量的词法作用域, 在函数本身已经执行完成后。(数据持久性)

闭包出现的原因

由于js引擎的垃圾回收机制, 在执行我们的代码的时候,js维护着一个调用栈。在函数执行完成的时候,由垃圾回收机制去处理这个调用栈(调用栈内包含函数的词法作用域), 要销毁调用栈的时候,发现还存在引用。那么垃圾回机制就不处理它。这就导致这个函数的词法作用域保留了下来,也让该函数具有了数据持久性。有利也有弊,基于垃圾回收机制,如果你的闭包内存有大量数据, 那么它是不会被清除的, 这就需要我们自己手动的去处理它。

闭包的作用

  1. 私有化变量, 封装变化
  2. 构建块级作用域: 关于那道题setTimeout, 应该还有一种答案.虽然看起来比较麻烦,但是它可以跑
    1
    2
    3
    4
    5
    6
    7
    8
    console.log('方案3: setTimeout内闭包');
    for (let i = 0; i <= 3; i++) {
    setTimeout(((i) => {
    return () => {
    console.log(i);
    }
    })(i), i * 1000);
    }
  3. 函数式编程里的偏函数用到了闭包
    1
    2
    3
    4
    5
    6
    const addOperator = x => y => x + y;
    const add1Operator = addOperator(1);
    const add2Operator = addOperator(2);

    add1Operator(1); // 2
    add2Operator(1); // 3

如何正确判断this的指向.md

Posted on 2020-04-12 | In interview

如何正确判断this指向

首先,我们知道js运行时, 会产生维护一个调用栈。 在js引擎逐行执行代码的时候,会动态的去对这个栈进行维护(进入一个函数,产生一个调用栈, 也就是我们说的产生一个局部作用域, 函数运行完成,退出函数, 这个栈跟着也就弹出, 把控制权回到上一层)。那说this的时候,为什么要扯调用栈呢?

这是因为,this是在运行时绑定的,而不是在编写时绑定的, 它是什么只取决于调用方式, 与函数声明的位置无关.

那问题来了,什么是调用位置?

调用位置指的是代码执行到这个地方的时候, 他的调用上下文是什么?当前环境是什么?让我们来看一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
a();

function a () {
console.log('a');
// 在window下调用
// 当前在a的执行环境

b();
}

function b () {
console.log('b');
// 在a下调用
// 当前在b的执行环境
c();
}

function c () {
// 在b下调用
// 当前在c的执行环境
console.log('c')
}

(这也是一个调用栈的关系, 脑补一下栈的结构, 先进后出。global - a -> b -> c -> c(done) -> b(done) -> a(done) -> global)

在我们理解了调用位置后,获取调用位置。在调用过程中如何绑定this对象呢?

四个规则:

规则1: 默认绑定

该规则优先级最低.

在全局环境下, this会被默认的指向全局对象.(浏览器的话就是window)
看一个例子:

1
2
3
4
var b = 1;
function a () {
console.log(this.b); // 此时, this 指向了window, 那么相当于直接访问全局变量b, 所以该行等价于-》 console.log(b)的效果, 然后这就变成了作用域的问题.....
}

But, 这里有个问题是, 如果你使用了严格模式,this不会默认绑定到全局对象,而是被绑定到undefind

规则2: 隐式绑定

当我的this, 存在上下文环境, 并且该环境下this有指向的时候, 那么this, 指向该上下文.看个例子:

1
2
3
4
5
6
7
8
9
10
var student = {
name: 'Nancy',
getName
}

function getName () {
console.log(this.name)
}

student.getName() // Nancy

规则3: 显式绑定

call/apply/bind绑定

啊, 这里是不是要说这三个函数的不同之处?

  1. call, 绑定第一个参数为this, 后调用, 参数不以数组的形式传入
  2. apply, 绑定第一个参数为this, 后调用,参数以数组的形式传入
  3. bind, 绑定第一个参数为this, 后不调用

这里的第二步就是显式绑定, 显示绑定时最常见的情况,也是我们预料中this的合理行为。这个不多说了。

规则4: new关键字绑定

啊, 这里是不是要说new关键字了。我记得有道面试题,问new做了什么事?

  1. 创建一个object
  2. 创建object到prototype的链接
  3. 显示绑定this到object
  4. 执行函数体
  5. 返回这个object

判定顺序:

1. 你用new关键字了吗?
    ->嗯(绑定到new后返回的对象里)
    ->2
2. 你用显式绑定了吗?
    ->嗯(...)
    ->3
3. 有没有存在上下文绑定的情况?
    ->嗯(...)
    -> 4
4. 只有默认绑定给你选了(注意严格模式下)

PS: ES6要格外注意箭头函数, 箭头函数的this指向,大家可以看一下这个issues

反正我只记住了一句话: 所有的箭头函数都没有自己的this,都指向外层。然后放一个例子:

1
2
3
4
5
var obj = {
fn: x => console.log(this)
}

obj.fn() // 浏览器环境下: window

数组去重.md

Posted on 2020-04-12 | In interview

#数组去重

大方向啊,先考虑非嵌套数组去重。

然后拓展题, 尝试一下先写测试的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
const test = (fn, arg, result) => {
// 绝对是一个新的思路呢
}

// 解:

// em....我们可以使用, ES6的set
const unit1 = arr => {
return new Set(arr);
}

unit1([1, 2, 3, 1]);

//em....reduce.
const unit2 = arr => {
return arr.reduce((result, item) => {
result.includes(item) ? result : result.push(item);
return result;
}, [])
}

unit2([1, 2, 3, 1, NaN, NaN, -0, 0, +0, null, null]);


// em....map, 感觉和reduce一样一样的, 不写了。
// em....for.
const unit3 = arr => {
const result = []
arr.map(item => {
result.includes(item) ? void 0: result.push(item);
});
return result;
}

unit3([1, 2, 3, 1, NaN, NaN, -0, 0, +0, null, null]);

// em...对象的key值不能重复可以利用一下.
const unit4 = arr => {
let result = [];
let obj = {};
arr.map(item => {
obj[item] = null;
})
for(i in obj) {
result.push(i)
}

return result;
}
unit4([1, 2, 3, 1, NaN, NaN, -0, 0, +0, null, null]);

往深的看,嵌套数组去重.往深了走.

  1. 包含数组

  2. 包含对象

那么子问题是, 如何判断一个对象是不是相同.

数组其实就递归使用上面的方法就好呀.

但是再往深的看,其实这里如果自己写判断相等的函数还是涉及到一些坑, 比如类型。js的类型判断有几个坑, 比如-0, NaN, 所以我墙裂推荐大家使用数组的includes方法,它本身的实现已经考虑到js变态的类型机制了。当然你完全可以自己写判断两个元素是否相等的函数, 这绝对没问题.

简历.md

Posted on 2020-04-12 | In interview

期望薪资: 12k以上

工作经验

2017-11-24至今
职位: 中级工程师(二级)-HW/工程师B-MAG(web方向)
深圳软通动力信息技术有限公司
工作职责描述: 作为前端负责人, 在项目中根据用户故事进行开发, 并负责一定的管理工作, 组织项目组内晨会,技术方案定制, 同时对部分需求进行开发, 不定期组织总结和分享.
团队人数: 5人 直接上级: 项目经理
在职荣誉:

  • 18年十一月, 荣获华南区2018年优秀应届生奖项(有证书)
  • 18年十二月, 荣获优秀新员工奖项(有证书)
  • 2019年绩效为: S/A/S
  • 在职期间经历二次调级

在职业绩:

  • 2019年6月: 支撑华为营销系统BCM的开发, 在时间少任务重的情况下, 有质量的完成了开发任务, 得到华为方的好评.
  • 2019年年初: 能力突出, 在esales2.0版本的时候作为前端负责人, 负责需求的评估分析/技术方案定制. 完成了脚手架的搭建,营销经理模块的开发, 项目从0-1.
  • 2018年5月: 负责esales手机端H5大赛答题系统的开发.
  • 2017至2018年: 在负责华为面向销售人员的电子商务系统,esales平台开发, 完成了其中管理文档平台的性能优化和重构的任务.得到华为方的好评.

自我评价:

  • 对开发工作有浓厚的兴趣
  • 持续精进, 实现自我价值
  • 关注前端领域的技术趋势
  • 能很快的融入团队, 学习能力强
  • 性格开朗, 与团队成员相处和睦
  • 有敏捷开发迭代经验,能把控开发进度, 并发现风险, 并且处理风险的能力

项目经验
华为BCM营销平台/lead模块 2019年5月-至今
项目描述:BCM营销平台是管理营销方案的一个平台. 主要负责对营销活动的管理.lead模块基于线索,根据线索进行流程化的管理.
项目基础: UI框架基于Vue和elementUI, 使用Vuex进行状态管理, 使用VueRouter进行路由以及权限控制, 使用git进行版本控制。
岗位/职责: 前端开发负责人

  • 负责前端项目版本需求分析评估
  • 任务分配, 需求方案定制
  • 代码规范管理, git版本控制
  • 组织codeReview
  • 并对需求进行开发, 解决部分开发问题.

esales2.0 2019年1月-5月
项目描述: esales2.0是提供给华为销售人员使用的电子商务系统.已经迭代2个大版本.该系统为门户类系统.主要为销售人员提供数据可视化, 流程可视化的功能.一站式销售平台.
项目基础: UI框架基于Vue的AUI(华为内部自研框架)与ElementUI,使用Vuex进行状态管理,使用VueRouter进行路由控制,图表库使用了Echart进行开发,使用Git进行版本控制.
岗位/职责: 前端开发负责人

  • 负责前端项目脚手架的搭建
  • 需求分析, 项目风险评估,方案定制
  • 代码协作管理
  • 对需求进行开发.

esales2.0APP H5 竞赛答题 2018.6月-12月
项目描述:esales2.0是基于esalesPC2.0开发的APP, 有ios端和安卓端.功能是PC端的缩小版.
项目基础: UI框架基于Vue的ElementUI, 图表库使用Echart.与客户端的同学协作开发混合应用.
岗位/职责: 核心开发

  • 需求分析,方案定制
  • 完成与原生APP的交互(路由和状态)
  • 解决部分兼容性问题

esales1.0PC 真实性文档管理平台2.0 2017.12-2018.6
项目描述: 文档管理平台是esales1.0下的一个子应用, 主要功能是提供给销售完成单子之后相关的文件管理.
项目基础: 基于谷歌的dojo与jquery进行开发.图表库使用Echart进行开发.
岗位/职责: 核心开发

  • 基于原有的项目进行开发和维护
  • 对已有的工程进行性能优化
  • 对当前较为混乱的工程进行部分重构优化
  • 跟踪当前存在的生产问题并且修复

技能特长:

  • 前端基础(HTML5/CSS/CSS3/JS)扎实, 熟悉开发必要流程
  • 熟练使用CSS编译器SCSS, 模块化css
  • 熟练掌握JS, 日常ES6进行开发
  • 掌握css3动画特性
  • 有前后端分离, 前后端联调经验
  • 有前端工程化的经验, 熟悉Webpack构建
  • 熟练掌握Vue,以及Vue相关的生态系统(Vuex/VueRouter)
  • 基本掌握React以及相关生态
  • 熟悉node.js有开发RESTAPI的经验
  • 会使用Linux命令行,了解Nginx服务器
  • 日常使用vscode作为IDE, postman作为接口调试工具
  • 工作细致, 对自己的任务负责到底, 有较强的适应/沟通/表达能力
  • 熟悉项目各阶段软件实施的工作流程
  • 有敏捷开发团队及迭代开发的经验

教育经历
2014/09- 2018/06
桂林电子科技大学
本科 | 机械设计制造及其自动化

简易版Promise.md

Posted on 2020-04-12 | In interview

手写简易版Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// 常量存Promise的状态
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
function MyPromise(fn) {
const that = this
// promise初始状态为pending
that.state = PENDING
// value为resolve时, 传递的参数
that.value = null
// resolve的回调队列
that.resolvedCallbacks = []
// reject回调队列
that.rejectedCallbacks = []

// resole函数实现
function resolve(value) {
// 只有状态为panding才能修改状态
if(that.state === PENDING) {
// 状态改为resolved
that.state = RESOLVED
// 把值传入value
that.value = value
// 执行resolve回调队列
that.resolvedCallbacks.map(cb => cb(that.value))
}
}

function reject(value) {
// 同上
if(that.state === PENDING) {
that.state = REJECTED
that.value = value
that.rejectedCallbacks.map(cb => cb(that.value))
}
}

try{
fn(resolve, reject)
} catch (e) {
reject(e)
}
}

MyPromise.prototype.then = function(onFulfilled, onRejected) {
const that = this
// 判断传入的是否为函数, 如果非函数包装一层往下执行透传
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
onRejected = typeof onRejected === 'function' ? onRejected : r => {
throw r
}

// 如果状态为panding, 那么把then中的参数(resolve, reject)传入队列
if(that.state === PENDING) {
that.resolvedCallbacks.push(onFulfilled)
that.rejectedCallbacks.push(onRejected)
}

// 如果状态为resolved那么执行onFulfilled函数
if(that.state === RESOLVED) {
onFulfilled(that.value)
}

// 如果状态为reject那么执行onrejeted函数
if(that.state === REJECTED) {
onRejected(that.value)
}
}

new MyPromise((res, rej) => {
setTimeout(() => {
res(1)
}, 0)
}).then(value => {
console.log(value)
})

so, 你觉得一个Promise的结构是怎么样?

  1. 我需要一个对象来保存该promise的状态, 执行的回调队列, 每次promise的结果(promise链)
  2. 我需要rejected/resolved函数, 触发对应状态的回调队列
  3. 我需要then函数解决Promise链问题

使用Class机制重构,重构不了, 如果使用了setTimeout在resolve中取不到this, 走不下去头痛

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
class MyPromise {
constructor(fn) {
const that = this
this.state = PENDING
this.value = null
this.resolvedCallbacks = []
this.rejectedCallbacks = []
try{
fn(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
// resole函数实现
resolve(value) {
// 只有状态为panding才能修改状态
if(this.state === PENDING) {
// 状态改为resolved
this.state = RESOLVED
// 把值传入value
this.value = value
// 执行resolve回调队列
this.resolvedCallbacks.map(cb => cb(this.value))
}
}

reject(value) {
// 同上
if(this.state === PENDING) {
this.state = REJECTED
this.value = value
this.rejectedCallbacks.map(cb => cb(this.value))
}
}

then(onFulfilled, onRejected) {
// 判断传入的是否为函数, 如果非函数包装一层往下执行透传
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
onRejected = typeof onRejected === 'function' ? onRejected : r => {
throw r
}

// 如果状态为panding, 那么把then中的参数(resolve, reject)传入队列
if(this.state === PENDING) {
this.resolvedCallbacks.push(onFulfilled)
this.rejectedCallbacks.push(onRejected)
}

// 如果状态为resolved那么执行onFulfilled函数
if(this.state === RESOLVED) {
onFulfilled(this.value)
}

// 如果状态为reject那么执行onrejeted函数
if(this.state === REJECTED) {
onRejected(this.value)
}
}
}

new MyPromise((res, rej) => {
setTimeout(() => {
res(1)
}, 0)
}).then(value => {
console.log(value)
})

获取能力的三大要素_百分之二十-知识与问题-系统化训练.md

Posted on 2020-04-12 | In 圈外个人发展课程

如何高效的获取能力

关键词: 20%|知识与问题|系统化训练

20%

小扎说过, 掌握百分之20的技术就能解决百分之80的工程问题。

28法则果然在哪里都受欢迎。
核心观点提到, 获取一种能力最快的方法是掌握其中核心的20%,而最有效的方式就是找对师傅.这件事对我来说很重要,所以至今我都在遵循这个原则,特别是找师傅.

  1. 在大学的时候,我大学室友和我脑子一热, 大家一起买了吉他,随书附赠的还有30天吉他弹唱精通,于是我们开始练习。我总是发现哪里不对,因为吉他的教材会从乐理开始跟你讲, 各种手法和理论知识,说一定要记住,很重要, 于是我们练不下去了。放弃。吉他吃灰。
    工作后,突然觉得不对劲,大家都可以学会的东西,凭啥我就不可以, 我又买了一把。然后这次,我直接找到了我的好朋友朋友,他是当年学校的乐队吉他手。我一不懂就问他,他也很乐意教。慢慢的发现, 自己好像上道了。这20%的师傅真的不亏。

  2. 工作后,我对于跟我一起入职的同学们来说, 我技术进步得很快。我明白我做了什么。我们大家一开始进来的时候,都是自己学,没有方向,触摸不到百分之二十。于是我找了技术最强的大佬。我就跟着他,帮他干活,同时也问他问题,后来自然而然的,就掌握要领了。那这百分之二十就是师傅领进门的含义?

知识与问题

我学习一门新的语言或者框架的时候,一开始大家都是看官方文档, 从头看到尾。真的很累,我甚至会觉得痛苦,感觉看
不完。因为技术文档都是对这语言或框架的全部信息,我就算背下来,还是很容易忘记。后来我发现,对于语言或者一门新的
框架,要了解的仅仅是其中我们最常用的语法,然后就开始去遇到问题->查文档->解决问题->遇到问题。一句话,文档是用来查的, 而不是背的。

系统化训练

其实工程人员的工作内容都是高度重复的。俗称企业螺丝钉。但是其实,反过来想,对于一个工程的运作和理解真的很重要, 无论是你的开发能力和架构能力, 以及团队协调甚至是应变能力。都是一个系统中缺一不可的一环。把工程当作一个系统,然后去理解它,那么你获得的就不止是开发能力。其实这也是系统化思维的内容。

偏题了,对于系统化训练,飞行员的检查清单,应该算是系统化的典型?飞行员都会有自己的检查清单,并且在模拟训练的时候,他们会遇到各种各样的问题,第一反应就会开始去查检查清单,然后行动,并且在工作一定的时间后,飞行员还要回去学校重新模拟训练。

如果他们只单独的学习开飞机,那么应该不能算是拥有一个飞行员恩多能力。

如果你需要某种能力, 为什么不去找一个好老师,然后把你的知识和问题结合,形成组块,最后再通过系统化的训练把组块联通起来获得这种能力呢?

PS:尝试根据知识去问问题.

<1…4567>

Hawei

Fullstack Engineer

61 posts
16 categories
3 tags
RSS
© 2022 Hawei
Powered by Hexo
|
Theme — NexT.Muse v5.1.4