GithubHelp home page GithubHelp logo

suoyuesmile / suo-blog Goto Github PK

View Code? Open in Web Editor NEW
242.0 13.0 42.0 17.42 MB

:fox_face:技术博客文章、笔记、实战、技术探讨、资源收集等等

Red 0.01% C++ 13.91% JavaScript 80.59% TypeScript 2.54% Shell 2.96%

suo-blog's Introduction

🚀 It's my records of the journey from phper to fronter, now sharing to you and hoping that these make sence for you. if you like it, please star it! Thank You!

本博客将持续更新,喜欢请收藏STAR一下,更多内容在suosmile关注一下,谢谢~:yum:

微信群 公众号

文章将优先发布于掘金平台,点击关注掘金账号哦。如果需要接受通知请关注微信公众号@前端攻城狗!

公众号

前端技术实战、研究总结

个人技术博客文章列表

编号 名称 状态
0001 记一次忏悔的前端面试经验(Vue 双向绑定原理) 完成
0002 关于这些天杭州各厂面试汇总(从JavaScript各种原理到框架源码 完成
0003 3个小时能把 React 学到哪种程度? 完成
0004 如何让 Promise 控制业务流程(Re 同步异步 开始一步一步深入) 完成
0005 理解promise、 generator 、async & await 之间的联系 完成
0006 吃透移动端 1px 完成
0007 吃透移动端 H5 响应式布局 完成
0008 吃透移动端 H5 与 hybrid 完成
0009 吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧《上》 完成
0010 吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧《中》 完成
0011 吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧《下》 完成
0012 杭州前端面试通关新手入门指南 完成
0013 TypeScript 语言精髓与项目实战 10月计划
0014 Vue 到 React 全面比较与上手指南 10月计划
0015 Node 入门练习 10月计划
0016 前端技术框架与架构的思索与探索 10月计划

每日一个编程小题

编号 名称 状态 难度
0001 1.两数相加 完成 简单
0002 7.整数反转 完成 简单
0003 9.回文数 完成 简单
0004 13.罗马数字转整数 完成 简单
0005 14.最长公共前缀 完成 简单
0006 20.有效的括号 完成 简单
0007 26.删除排序数组中的重复项 完成 简单
0008 27.移除元素 完成 简单
0009 28.实现-str-str 完成 简单
0010 35.搜索插入位置 完成 简单
0011 58.最后一个单词的长度 完成 简单
0012 66.加一 完成 简单

前端开放研究点 todo

JavaScript

编号 名称 状态
0001 闭包 10月计划
0002 this 10月计划
0003 new 10月计划
0004 深浅拷贝 10月计划
0005 promise 计划
0006 async、await 计划
0007 原型与原型链 计划
0008 继承 计划
0009 防抖与节流 计划
0010 类型判断 计划
0011 运行机制 计划

CSS

编号 名称 状态
0001 常用开发技巧 10月计划
0002 BFC 10月计划
0003 布局 10月计划
0004 flexbox 10月计划
0005 计量单位 计划
0006 提升UI效果 计划
0007 对齐 计划
0008 过渡与动画 计划
0009 预编译 计划
0010 高级用法 计划

HTML

编号 名称 状态
0001 常用开发技巧 10月计划
0002 语义化开发 10月计划
0003 块级与内联 10月计划
0004 DOM 树分析 10月计划
0004 PUG 相关 10月计划

TypeScript

编号 名称 状态
0001 常用开发技巧 10月计划
0002 类型增强与推断 10月计划
0003 面向对象开发 10月计划
0004 高级技巧 10月计划
0004 装饰器 10月计划

Node

编号 名称 状态
0001 常用开发技巧 10月计划
0002 服务提供 10月计划
0003 面向对象开发 10月计划
0004 高级技巧 10月计划
0004 装饰器 10月计划

Vue

编号 名称 状态
0001 常用开发技巧 10月计划
0002 服务提供 10月计划
0003 面向对象开发 10月计划
0004 高级技巧 10月计划
0004 装饰器 10月计划

React

编号 名称 状态
0001 常用开发技巧 10月计划
0002 服务提供 10月计划
0003 面向对象开发 10月计划
0004 高级技巧 10月计划
0004 装饰器 10月计划

Webpack

编号 名称 状态
0001 常用开发技巧 10月计划
0002 服务提供 10月计划
0003 面向对象开发 10月计划
0004 高级技巧 10月计划
0004 装饰器 10月计划

浏览器

编号 名称 状态
0001 常用开发技巧 10月计划
0002 服务提供 10月计划
0003 面向对象开发 10月计划
0004 高级技巧 10月计划
0004 装饰器 10月计划

编程基础笔记

c & c++

c c++
c语言基础之数据类型 c++变量解析
c数组 c++数组、向量、字符串
c函数 c++函数
c字符串 c++类
c内存管理 c++面向对象
c文件IO c++操作符重载
Reference Reference
c/c++ 中文参考手册 c 语言编程透视
c++ 并发编程指南 Linux C编程一站式学习
100个gdb小技巧 100个gcc小技巧
c/c++ Primer C++ Primer 5th Answers
---------------表格内容填充物---------------- ---------------表格内容填充物----------------

数据结构 & 算法

数据结构 算法
数据结构之向量 算法与数据结构知识归纳整理
数据结构之列表 用来度量算法好坏的方法
数据结构之二叉树 算法之排序
数据结构之图 以串为基础的算法
数据结构之二叉搜索树 算法之递归
数据结构之高级搜索树 算法之迭代
数据结构之优先级队列 算法之动态规划
数据结构之散列表 算法之贪心算法
--------------------------------------------------- -----------------------------------------------------

编译原理相关

编译原理
数据结构之向量 算法与数据结构知识归纳整理
数据结构之列表 用来度量算法好坏的方法
数据结构之二叉树 算法之排序
数据结构之图 以串为基础的算法
数据结构之二叉搜索树 算法之递归
数据结构之高级搜索树 算法之迭代
数据结构之优先级队列 算法之动态规划
数据结构之散列表 算法之贪心算法
--------------------------------------------------- -----------------------------------------------------

入门资料收集

HTML & CSS 简单入门

Reference Reference
W3C入门手册教程 CSS语法参考
MDN HTML 中文文档 CSS3动画手册
HTML和CSS编码规范 CSS3动画制作工具
学习CSS布局 Emmet 文档
--------------------------------------------------- -----------------------------------------------------

JavaScript & jQuery 基础入门

Article Article
JavaScript继承设计机制 JavaScript同源策略与规避
jQuery设计** jQuery最佳实践
JavaScript严格模式 JavaScript快速排序
JavaScript模块化编程 JavaScript异步编程
JavaScript的this用法 JavaScript定义类的方法
JavaScript面向对象编程 JavaScript闭包原理与分析
Reference Reference
廖雪峰JavaScript全栈教程 jQuery 解构
阮一峰 JavaScript基础教程 简单易懂的JQuery魔法
JavaScript中的this陷阱的最全收集 How to write jQuery plugin
Promise迷你书(中文版 You Don't Need jQuery
前端框架最新排名 TOP 100 如何实现一个类jQuery?
--------------------------------------------------- -----------------------------------------------------

PHP 基础入门

Reference Reference
w3c中php快速入门手册 ThinkPHP 入门视频教程(网盘)
学习php的正确道路 PHP 官方手册
php官方组成员鸟哥的博客 深入理解PHP内核
最热门php开发社区:phpchina PHP扩展开发及内核应用
--------------------------------------------------- -----------------------------------------------------

MySQL & Web Server 基础入门

Reference Reference
21分钟MySQL入门教程 Apache Spark 设计与实现
MySQL慕课网中免费进阶教程 Nginx开发从入门到精通
常用sql语句大集合 OpenResty最佳实践
MySQL索引数据结构及算法原理 Apache 中文手册
--------------------------------------------------- -----------------------------------------------------

Laravel & Yii 基础入门

Reference Reference
Laravel5.1 中文文档 YiiBook几本Yii框架的在线教程
Laravel 5.1 LTS 速查表 深入理解 Yii 2.0
Laravel 最大的**开发者社区 Yii 框架中文文檔
--------------------------------------------------- -----------------------------------------------------

Linux & Git 基础入门

Reference Reference
Linux安装镜像(Unbutu16) Git window安装包
鸟哥的Linux私房菜 Pro Git 中文版
The Linux Command Line 猴子都能懂的GIT入门
UNIX TOOLBOX 廖雪峰Git教程
--------------------------------------------------- -----------------------------------------------------

Sublime & Vim 简单使用

Reference Reference
Sublime使用技巧之快捷键 exvim--vim 改良成IDE项目
Sublime插件大全 Vim中文文档
--------------------------------------------------- -----------------------------------------------------

Markdown 简单使用

Reference Reference
Markdown 语法说明 (简体中文版) Markdown入门参考
Mdeditor(国内在线markdown编辑器) Stackedit(国外markdown编辑器)
Mditor轻量级的markdown编辑器 lepture-editor
Markdown-editor
--------------------------------------------------- -----------------------------------------------------

Weapp 基础教程

Reference Reference
微信小程序简易教程 微信小程序官方组件库
微信小程序入门教程(视频) 有赞小程序ui组件
--------------------------------------------------- -----------------------------------------------------

NodeJS & AngularJS 基础入门

Reference Reference
Node.js 看了就懂系列 AngularJS最佳实践和风格指南
你信不信5天学会NodeJS AngularJS中译本
从零开始的nodejs世界生活 AngularJS入门教程
赶紧的Node.js入门系列 构建自己的AngularJS
Node初学者入门,NodeJS教程 在Windows环境下构建AngularJS项目
--------------------------------------------------- -----------------------------------------------------

React & Vue 文档

Reference Reference
React教程 我是菜鸟系列 Vue官网
React.js快速开始系列 Awesome-vue这是啥很厉害的样子
轻松入门React和Webpack Vue开发这论坛
Redux 中文文档 移动端Vue组件集合
React介绍及实践教程 桌面端Vue集合
React.js amazeui UI Vue菜鸟教程
React Native 中文版 Vue快速入门
--------------------------------------------------- -----------------------------------------------------

Front-end 整理一些资料

Reference Reference
前端知识汇总 前端开发大系概览图
免费的编程中文书籍索 前端书籍大全
前端免费书籍大全 重新介绍JavaScript(JS教程)
Gitbook Front-End-Develop 前端开发指南
前端开发笔记本 大前端工具集
前端开发者手册 结合个人经历总结的前端入门方法
前端学习计划 前端知识体系图
--------------------------------------------------- -----------------------------------------------------

Front-end 规范相关

Reference Reference
github工程师代码书写习惯 HTML&CSS编码规范 by @mdo
前端编码规范之js - by yuwenhui 前端编码规范之js - by 李靖
Airbnb JavaScript 编码规范 AMD与CMD规范的区别
AMD与CMD规范的区别 KISSY 源码规范
前端代码规范及最佳实践 百度前端规范
JavaScript风格指南/编码规范 网易前端开发规范
前端规范资源列表 Web 前端开发规范文档
--------------------------------------------------- -----------------------------------------------------

性能优化相关

Reference Reference
性能优化页面渲染 移动前端性能优化指南
前端开发者必看的看的前端性能优化 前端性能再优化
前端性能优化进阶大道 前端性能指导书
YSLOW中文介绍 Yahoo团队实践分享:网站性能
加载,不只是少一点点 12306谈谈网站前端性能
【高性能前端1】高性能HTML 【高性能前端2】高性能CSS
静态资源版本更新与缓存 静态资源管理与模板框架
HTTPS连接的前几毫秒发生了什么 Yslow
阿里无线前端Pt.1 加载期优化) 前端网页性能最佳实践
--------------------------------------------------- -----------------------------------------------------

suo-blog's People

Contributors

suoyuesmile avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

suo-blog's Issues

JavaScript事件代理、冒泡、循环

自从买了JavaScript程序设计这本书,一直没时间看,今天兴起看了里面的事件的章节。现在用最简洁的语言来总结一下关于JavaScript中的事件。
下面是我要谈论的几个方面,重点解释以下名词:
1.事件
2.事件流
3.事件冒泡与事件捕获
4.事件代理

关于这些天杭州各厂面试汇总(从JavaScript各种原理到框架源码)

首先呢,统计一下情况:

本人校招进入新三板上市企业工作一年,并有半年多一线互联网实习经验

来到杭州投出简历 24 封,收到面试邀约 10 次

result = 正式offer * 2 + 口头offer * 1

令人头疼的是并没拿到自己想要的 offer,理想的公司大多连面试机会都不给...

伤脑筋...明天还有两家电话面试,过了大半个月,还是打算继续面下去...

理想公司:

  • 服:简历都没过(惨)还被一个蚂外包招聘diss我这样的一年工作经验都外包都够呛(晕)
  • *赞:投了很多遍,简历全部卡在HR上了(惨)
  • *猫:没敢投(吓)
  • **车:一下午全部面完,环境一般,每轮面试都等了很长时间,两轮技术面后又和HR聊了一个多小时技术问题,表示很无奈,从此对大搜车印象大大折扣。回去等通知,一周之后说经验不符。敢情经验不符,你让我去面试个球(气)
  • *吧:HR主动找,问
你会 React ?我答会
你会移动端吗?我答会
你有过 H5 经验吗?我答有
对不起,面试官说经验不符
???(懵)
  • **顺:只招应届生了

考题汇总:

  • this 指向 * 10 (必考有没有,这都不知道还学啥JavaScript--笑)
  • 同步异步或者事件机制 * 8
  • Vue 双向绑定实现原理 * 8
  • 箭头函数 * 6(考察 ES6 使用情况)
  • call apply bind 的使用和区别 * 6 (问到this很可能问到这些)
  • 常用 Array 函数 * 6
  • Vuex 应用及其原理 * 6
  • Vue 父子兄弟通信 * 5
  • Redux 原理 * 5
  • dom 事件 * 5
  • Vdom 原理及diff算法 * 5
  • Promise机制 * 5
  • 原型链及面向对象相关知识 * 4
  • HTTPS 安全性 * 3
  • 闭包 * 3
  • 变量提升 * 3
  • HTTP 状态码 * 2
  • Proxy 和 其他一些 ES6 新特性
  • 防抖与节流 * 1
  • 深浅拷贝原理和实现 * 1
  • getComputedStyle * 1
  • rem * 1 (考察关于移动端布局到问题)
  • 其他忘记了...

聊聊面试题

this 指向什么? 一起源于 this

《You dou't kown JavaScript》 这本书讲等最清楚了

首先是两个误解:

  1. this 指向自身,根据英语翻译来说,这是一种自然的想法,其实不然,这是一个误解。
  2. this 指向函数作用域,这个在某种情况下是正确的

其次是四种情况

  1. 默认绑定
var name = 'lufei'
function show() {
    var name = 'namei'
    console.log(this.name)
}
show()
// lufei

可以看出最后 this 绑定在全局对象上,所以结果是 lufei

  1. 隐式绑定
function show() {
    var member = 'namei'
    console.log(this.member)
}
var member = 'zoro'
var caomao = {
    member: 'lufei',
    showMember: show
}

caomao.showMember()
// lufei

这里最后通过 caomao 来调用这个函数,函数中的 this 则被绑定到 caomao 这个对象上

  1. 显式绑定
var caomao = {
    member: 'lufei'
}
var member = 'zoro'
function show() {
    var member = 'namei'
    console.log(this.member)
}
show.call(caomao)
// lufei

通过 callapplybind 我们可以显示的改变 this 的绑定

  1. new 绑定
    最后一种是使用 new 调用函数,或者说是构造函数调用时
function SeaPoacherBoat(member) {
    this.member = member
}
var caomao = new SeaPoacherBoat('lufei')
console.log(caomao.member) // lufei

这段代码会执行以下操作:

  1. 创建一个全新的对象
  2. 进行原型(prototype)链接
  3. 将 新对象 绑定到函数调用的 this
  4. 如果没有返回其他对象,则自动返回一个新对象

它们绑定的优先级是 new > 显示绑定 > 隐式绑定 > 默认,这也是很容易理解的,new 是生成了一个全新的对象优先级是最高的,显示绑定函数要起作用优先级一定要高于隐式绑定,默认绑定是最低的这个也无可厚非

最后一句话总结 this 是运行期间绑定,和它声明的环境无关,只与调用它的对象有关

我们知道了它的指向,要想改变它怎么办呢?

改变 this 指向最直接的方法是 call, apply, bind,来看一下下面这段代码

var name = '草帽海贼团'
var caomao = {
    name: '路飞'
}

function printMember(arg1, arg2) {
    var name = '娜美'
    console.log(this.name)
    console.log(arg1, arg2)
}

printMember('山治', '索隆') // 草帽海贼团 山治 索隆
printMember.call(caimao, '山治', '索隆') // 路飞 山治 索隆
printMember.apply(caimao, ['山治', '索隆']) // 路飞 山治 索隆
printMember.bind(caimao, '山治', '索隆')() // 路飞 山治 索隆 

根据上面代码,this 现在指向的 window 对象,所以打印的是草帽海贼团而不是娜美
下面我们通过三种方式将 this 指针绑定到 caomao 这个对象,所以最后打印的都是路飞

很明显它们的区别无非就在于形式的不同,以call为基础来说,apply 是将后面的参数合成一个数组一起传人函数,bind最后返回的是一个函数,只有调用这个函数后才算执行。

有一种特殊情况就是把 nullundefined 作为this的绑定对象传人进去,这样的实际情况是采用的默认绑定原则
那么这有什么用途呢?常见用于展开数组来,看一段代码

function print(a, b) {
    console.log(a, b)
}

print.apply(null, [1, 2])

还有呢, 使用bind用于柯里化

var foo = print.bind(null, 1)

foo(2)

也就是延迟执行最终的结果

是不是所有函数都可以绑定this 呢?

没错你可能很快想到就是箭头函数,普通函数来说,this是运行期绑定,而 ES6新规则里箭头函数并没有绑定 this,它是不存在 this的绑定的。那在箭头函数中存在this 会怎么样呢

// 情景一,全局范围内调用箭头函数
var foo = () => { console.log(this) }
foo() // window

// 情景二,对象中调用
function monkey() {
    var bar = () => console.log(this)
    bar()
}

var obj = {
    monkey: monkey
}
var other = {
    obj: obj
}

other.obj.monkey() // { monkey }

之前很多人对箭头函数中的 this 都有一些误解,认为箭头函数中的 this 自身绑定或者是任何绑定在最终调用方式上。其实不然,从上面代码中我们可以看出箭头中的 this 绑定在离最近外层的对象 obj 上, 而不是最终调用对象 other 上。

我们知道了 this 的指向的对象调用它的函数,那么调用它的时候到底发生了什么?我们需要知道JS执行机制到底是怎么样的

console.log(run)
var run
function run(run) {
    var run = 2
    this.run = run
    console.log(this, arguments)
    console.log(run)
}
run('1') 
console.log(run)
run = 3
console.log(run)


我们来分析一下它的运行方式
首先开始预解析,它有个规则是变量声明提升,我们可以知道函数声明会被提升到最上面,其次是变量。声明后的变量不会重复声明,所以第二次声明的变量不生效,我们手动来做一次转换

// 提升函数声明
function run(run) {
    console.log(this, arguments)
    var run = 2
    this.run = run
    console.log(run)
}
// 提升变量声明
var run
console.log(run)
run('1') 
console.log(run)
run = 3
console.log(run)

所以第一个 log 会打印出函数而不是变量

开始按顺序执行下面的语句,此时遇到一个run()的调用
run推入到执行栈中,进行以下几个步骤:

  1. 绑定 this 和 初始化参数, 根据之前谈到的规则,this 绑定到调用它的全局对象 window,所以第二个 log 打印出 window对象和传递过来的参数

  2. 同样在函数作用域中开始执行预解析,执行语句,函数中又定义了一个run。我们知道作用域原理是就近查找,存在一个屏蔽作用,run 函数作用域中的 run 此刻就是 2,所以第三个 log 会打印出 2this.run = run 将全局中的 run 赋值为 2

  3. 执行完成后,run 函数出栈,继续执行全局语句,run 的值已经被改变成 2,所以此刻第四个 log 也打印出了 2,最终又被改变成 3,所以最后一个 log ,打印出了 3

聊聊框架

Vue 和 React 你学哪一个?
哎呀!头疼, 能不能不要选啊,选 React 都说 React待遇好,大厂都爱React

HR问,你Vue 多少经验?没有,bye~,不符合项目经验。那就学 Vue 呗,好上手,越来越流行。

HR问,你React 多少经验?没有,bye~,不符合项目经验。- -

大家仰望天空叹息到,学不动了...不怕学不动了,就怕学到的东西马上就过时了。

所以只有学到真正底层基础**的东西才是真正重要的。

就算哪天没有这些框架了也能马上撸一个出来。

分享想法

最近找工作萌生了一个 开源 idea

  • 痛点一:每次制作需要去找模版,去制作模版,而对于我们前端而言,更加擅长制作个性在线简历,可不可以考虑使用前端技术制作一个在线简历模版,开源免费供大家使用,大家开发自己的主题,大家不需要花钱去模版网站找那些并不适合自己的简历模版。

  • 痛点二:对于前端来说,知识点太杂,面试考点太多。简历不单单是一个介绍,也是我们技术的一个总结。通过开发一个工具自动识别我们简历里面的技术点,模拟面试官给出一些面试考察的题目,让我们知道自己的不足,持续的学习和进步。

  • 痛点三:对于简历,我们不应该一份简历进行海投,应该针对不同的岗位职责进行修改。所以我们可以开发一个输入职位地址,自动匹配简历与岗位中的差异并标记。这样我们就知道自身与岗位职责之间又多大差距,然后努力去接近它。同时我们需要对不同简历进行管理。

以上都是目前各大招聘网站和简历制作网站所没有的需求,这是我们技术人员和求职者自身的诉求。

而目前各大招聘网站更加注重招聘者的需求,往往不会管应聘者的需求,甚至要求各种付费的一些功能。

这个开源项目不是为了取代招聘网站,而是做一个从学习->工作->求职环节的一个补充。

需求

  • v1.0.0 在线简历编辑功能,自己制作主题功能...

  • v2.0.0 技术匹配识别功能,模拟面试功能,面试评分功能...

  • v3.0.0 简历管理功能,职位匹配功能...

  • v4.0.0 内推,代码练习,文章订阅...

技术实现

待定...

开源计划

https://github.com/suoyuesmile/resume-promotion

感谢阅读

第二次发文章,技术不到位多多海涵,里面技术点一部分来自 You don't kown JavaScript,另一部分来自平时看过的文章和平时的总结。以后会持续更新,也算是对自己技术相关原理的总结。推荐大家去认真看看这本书,相信你会有更大的收获。

高清电子书资源(请私聊,我单独发给你)

下期预告(待定)

函数又来自哪?同时数组又来自哪?原型链又是什么东西?

我们已经有了函数,为什么还要箭头函数?箭头函数仅仅是替代函数写法吗?

我们知道 Vue 通过 Object.defineProperty() 劫持对象,那么它数组又是怎么劫持的呢?

函数有个执行栈,我们知道同步函数是在执行栈里执行,那异步函数呢?

说到异步,怎么实现异步的?异步与同步最大的区别在于什么?

回调函数可以实现异步,为什么还要用 Promise?

Promise 异步就很好用了,为啥又有 asyncawait

------------------------------更新-------------------------------------

2019.7.3 更新 工作已确定,帮忙内推的朋友多谢了...去了一家小型待遇还不错的小公司
2019.12.6 更新 前一天还在谈论技术方案,今天公司倒闭缱散了,又成自由人了... 希望下家稳定些...

[掘金地址](https://juejin.im/post/5d14bb9a5188255d3f6ca8f6)

七夕佳节:谈谈面向对象

第一次接触面向对象是C++课堂上,那是不知道啥是面向对象,觉得十分高深。那时初级到不行,脑袋里面只会想,只要能跑出结果就可以啦,管那么多干啥。恍惚之间两年过去了,其中学了C++的面向对象,学了JAVA的面向对象,又学了PHP的面向对象,现在到了Javascript,种种经历让我对面向对象有了不同的理解,学了这么多面向对象,而我的对象却和我分手了😭,由此我感到了作为程序员的痛

Javascript 从对象到面向对象

问题

  1. 什么是对象?
  2. 对象和数组有什么区别?
  3. 对象的实例有哪几种方式?
  4. 面向对象的核心**是什么?
  5. 怎么实现面向对象中的继承?

理解promise、 generator 、async & await 之间的联系

Promise 处理异步代码相对于纯回调函数比较有序明了,但是对于同步函数写法还是挺繁琐的,下面有两种语法糖让异步更加清晰简洁

生成器

generator 函数

像指针一样下移,有点像在debug代码

function* gen() {
	yield 1
	yield 2
	yield 3
}
let g = gen()
console.log(g.next())
console.log(g.next())
console.log(g.next())
console.log(g.next()) 

  • 中断并完成下移return()
function* gen() {
	yield 1
	yield 2
	yield 3
}
let g = gen()
console.log(g.next())
console.log(g.next())
console.log(g.return('完成'))
console.log(g.next()) 

  • 中断并抛出异常 throw()
function* gen() {
	try {
		yield 1
		yield 2
		yield 3
	} catch(e) {
		console.log(e)
	}

}
let g = gen()
console.log(g.next())
console.log(g.next())
console.log(g.throw('异常'))
console.log(g.next()) 


如果在异步函数里面使用 generator 函数怎样?

function promise() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
          resolve('resolved')
    }, 1000)
  })
}

function* generate() {
 	promise().then((res) => {
    console.log(res)
  })
}

function fn() {
  const res = generate().next()
  console.log(res)
}

fn()

现在发现,异步代码不需要then回调了,看起来和同步函数写法一样

不过现在我们有了asyncawait函数,将生成器进一步封装,也可以说出语法糖

async、await函数

使用Promise 写法写一个简单的例子

function promise() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
          resolve('resolved')
    }, 1000)
  })
}

function fn() {
 	promise().then((res) => {
    console.log(res)
  })
}

fn()

改写成 async 函数

async function asyncFn() {
  console.log(await promise())
}

asyncFn()

async 和 then 一样 可以达到同一个的效果,而且代码中没有回调函数的影子了

多条异步链的情况

function promise() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
          resolve(1)
    }, 1000)
  })
}

function fn() {
 	const p =  promise().then((res) => {
    	console.log('第一个then', res)
    	return res === 2 ? new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(2)
        }, 500)
   	 	}) : new Promise((resolve, reject) => {
        setTimeout(() => {
          reject(3)
        }, 500)
   	 	})
  }).then((res) => {
    console.log('第二个then', res)
  }).catch((err) => {
    console.log('异常', err)
  })
}

fn()

使用 async 改写

function promise() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
          resolve(1)
    }, 1000)
  })
}

function promise2() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
          resolve(2)
    }, 500)
  })
}

function promise3() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
          resolve(3)
    }, 500)
  })
}

async function asyncFn() {
	const step1_res = await promise()
	console.log('第一步的结果:', step1_res)
	try {
    if (step1_res === 2) {
      console.log('第二步的结果:', await promise2())
    } else {
			console.log('第二步的拒绝的结果:', await promise3())
    }
 	}
	catch(err) { 
		console.log('异常:',  err)
	}
}
asyncFn()

用同步的代码写出了异步的效果

什么是最好的学习方式?

说说我自己的方法吧

  • 带着问题去学习,学习某个知识点之前,搞清楚自己要学到哪些东西
  • 程序员式自问自答(比如就是我这种形式,😀),问自己问题,自己能准确思路清晰答出来,就算是领悟了
  • 学会问问题,像知乎,谷歌,stack flow,网友 等等问问题,问的问题的质量越高,说明学的越深入,哈哈,欢迎向我提问

如何让 Promise 控制业务流程(Re 同步异步 开始一步一步深入)

对写文章这件事已经阁了3个月了,工作太忙很难抽出大块时间来总结写作。现在稍微闲赋些,准备好好对以前的技术做一下总结。为什么要写关于 Promise 呢?有以下 3 点

  1. 之前面试时候,面试官问 Promise 问的比较多,实在要对它进行一个好好总结了,也是 JavaScript 比较难懂的一个技术点,平时我面试别人时候,也喜欢问 Promise 相关的,保证他在工作中能够熟练运用,自己能封装axios,能控制比较复杂的同步异步流程等...

  2. 这三个月的工作中,自己也总是遇到关于 Promise 的一些运用场景,有时候又比较疑惑一些地方,也是为自己总结一下 Promise,以后在工作中更加运用自如。

    接下来我从最基础的同步异步谈起,再通过图示谈他的语法,如何自己写一个Promise,再谈一下我在工作中遇到的 Promise,最后谈一下 新的语法 asyncawait Promise 的结合和比较

  3. 网上关于Promise的介绍大多数是一些语法的介绍,大多没有结合场景和同步异步相关理解来谈。对于理解Promise的前世今生还是不够深入,不够具体。

理解同步异步

理解JS执行原理

console.log(1)
setTimeout(() => {
	console.log(2)
}, 1000)
console.log(3)


如果延迟时间为0

console.log(1)
setTimeout(() => {
	console.log(2)
}, 0)
console.log(3)

console.log(1)
setTimeout(() => {
	console.log(2)
}, 2000)
console.log(3)
setTimeout(() => {
	console.log(4)
}, 1000)
console.log(5)
setTimeout(() => {
	console.log(6)
}, 0)
console.log(7)
setTimeout(() => {
	console.log(8)
}, 1000)
console.log(9)

这里可以发现几点

  • 1,3,5,7,9 是同步代码,6,4,8,2是异步代码,同步先于异步执行
  • 单看同步代码,按位置顺序依次执行
  • 单看异步代码,不同执行时间,越长越靠后执行。相同执行时间,按位置顺序依次执行

这里我们总结下同步与异步的规律

  • 代码中存在异步函数,不管需要时间多久,都要在同步完成后执行
  • 同步按位置顺序执行;异步按时间长短执行,同样时间长短时,按位置顺序执行

这是一个怎样的机制,JS引擎又是如何处理的呢?

我找到了一张这样的图

首先来解释一下这个图:这是JS的事件循环,分为3个步骤

  1. 引擎将同步、异步函数按次序载入到执行栈里面
  2. 执行栈的将异步函数放入异步线程里面
  3. 线程根据任务完成时间依次推入任务队列中执行

如何处理异步呢, 最初的方法是使用回调

理解回调

引入一下知乎上的高赞回答

现在我们把它用代码写出来看看

function fetchSomething() {
  console.log('去取货!')
}

function buySomething(callback) {
  console.log('没货了!')
  setTimeout(() => {
    console.log('有货了!')
    callback()
  }, 1000)
}

buySomething(fetchSomething)


用简单的语言描述就是:将一个函数作为参数传给另一个函数调用

要搞清楚的一点是,回调和异步没有直接的关系,也可以同步回调,也可以异步回调。我们是通过回调这个机制来实现异步的操作,例如

// 这个一个请求的异步函数,来实现异步操作
function getSomePeopleName(params, callback) {
  setTimeout(() => {
    let data

    if (params === 'suo') {
      data = 'yue'
    }
    
    console.log(callback(data))
  }, 1000)
}
console.log(getSomePeopleName('suo', (data) => '我是回调函数:' + data))


回调函数的结果一定是在回调函数里面,如果我是这样一个流程呢?

A -> B -> C -> D

function A(callback) {
  console.log('开始执行A')
  setTimeout(() => {
      callback('A')
  }, 500)
}

function B(callback) {
  console.log('开始执行B')
  setTimeout(() => {
      callback('B')
  }, 400)
}

function C(callback) {
  console.log('开始执行C')
  callback('C')
}

function D(callback) {
  console.log('开始执行D')
  setTimeout(() => {
      callback('D')
  }, 200)
}

A((a) => {
  B((b) => {
    C((c) => {
      D((d) => {
        console.log(a, b, c, d)
      })
    })
  })
})


由上可知,回调函数有几个特定

  • 使用回调函数嵌套,回调函数一定在上一个回调之后执行,用于可以控制流程,不会出现异步函数在执行顺序的混乱,即使同步异步函数混合
  • 回调函数解构嵌套,代码不够清晰,俗称回调地狱

那么有没有更好的异步操作机制呢?这里我们就要谈到 Promise

深入 Promise

为什么要有Promise?

ES6 标准中 Promise 语法

  • Promise是一个构造函数

我们写一个简单的 Promise 看看

new Promise(() => {})

// 有一个参数executor的构造函数
// executor 也是一个函数,具有两个参数 resolve, reject 是两个回调函数,当执行到回调函数时,会执行
const isResolve = true
new Promise((resolve, reject) => {
	if (isResolve) {
		resolve()
	} else {
		reject()
	}
})


可以看到 Promise 的状态从pending变成resolved

如果将 isResolve 置为 false 呢?


Promise 状态从 pending 变成 rejected 同时抛出一个异常,并且异常未被捕获,所以我们写Promise时候一定要加上catch 来捕获异常

const isResolve = false
new Promise((resolve, reject) => {
	if (isResolve) {
		resolve()
	} else {
		reject('我拒绝你')
	}
}).catch((err) => {
  console.log('捕获异常', err)
})


现在我们把异常捕获到了,但是神奇的事情发生了,异常状态应该是rejected,怎么变成 resolved了呢?
我们或许很纳闷,这个放在后面讨论,我们先看看 then 怎么处理的

const isResolve = true
new Promise((resolve, reject) => {
	if (isResolve) {
		resolve('通过')
	} else {
		reject('我拒绝你')
	}
}).then((res) => {
  console.log('resolve', res)
}, (res) => {
  console.log('reject', res)
})


isResolve = false


我们可以看到 then 是怎么处理的

  1. 如果 前面resolve()调用,Promise状态为 resolvedthen则执行第一个回调函数参数
  2. 如果 前面reject()调用,Promise状态为 rejectedthen则执行第二个回调函数参数
  3. then 执行回调函数之后Promise 的 状态都为 resolved

下面进一步验证下

const isResolve = false
new Promise((resolve, reject) => {
	if (isResolve) {
		resolve('通过')
	} else {
		reject('我拒绝你')
	}
}).catch(err => {
  console.log('我捕获到了', err)
}).then((res) => {
  console.log('resolve', res)
}, (res) => {
  console.log('reject', res)
})


果然呢,catch之后,then还会去执行,并且resolve 的参数为 undefined

问题是现在我们如何控制一个流程呢?Promise并不能直接给我们进行长流程的分支选择

下面有一个简单流程


尝试使用Promise去控制流程

const process = [102, 204]
new Promise((resolve, reject) => {
  if (process[0] === 101) {
     setTimeout(() => {
      console.log(101)
      resolve(101)
    }, 1000)
  } else {
    setTimeout(() => {
      console.log(102)
      reject(102)
    }, 1000)
  }
}).then(() => {
  if (process[1] === 201) {
    setTimeout(() => {
      console.log(201)
    }, 500)
  } else {
    setTimeout(() => {
      console.log(202)
    }, 500)
  }
}, () => {
    if (process[1] === 203) {
    setTimeout(() => {
      console.log(203)
    }, 500)
  } else {
    setTimeout(() => {
      console.log(204)
    }, 500)
  }
}).catch((err) => {
  console.log(err)
})


下面我们试试更加复杂的流程

Promise 调用链:then 的作用

单个Promise没办法控制长流程,我们怎么将Promise形成一个控制链呢,需要理解then的返回在其中起到的作用

promise.then(onFulfilled, onRejected) 
  • 接收两个参数,onFulfilledpromiseresolved 状态被调用

  • 接收两个参数,onRejectedpromiserejected 状态被调用

  • 返回值比较复杂,下面用表格列出来

    序号 场景 返回的Promise状态改变为 回调函数参数值
    1 返回1 个值 resolved 返回值
    2 没有返回 resolved undefined
    3 抛出错误 rejected 错误
    4 resolved的Promise resolved 返回的Promise回调的参数值
    5 rejected的Promise rejected 返回的Promise回调的参数值
    6 pending的Promise pending 返回的Promise回调的参数值

我们可以看出想要控制then 的后续流程,必须通过这 6 种情况来控制
下面来测试一下 这 6 种情况是否符合我们的预期

  1. 返回一个值
new Promise((resolve, reject) => {
		resolve('通过')
}).then((res) => {
  console.log('1', res)
  return res // then的返回值
}).then((res) => {
  console.log('2', res)
})


2. 不返回


3. 抛出错误


4. resolved的Promise


5. rejected的Promise


6. pending的Promise

看图写代码

分析特点:

这样就比较复杂了,还要考虑暂停的问题,但是根据我们上面测试到的,通过then的返回值控制流程也没有想象那么难

task([101, 201])
function task(testPath) {
  console.log('开始测试', testPath)
  new Promise((resolve, reject) => {
    console.log('000')
    if (101 === testPath[0]) {
      resolve('101')
    } else {
      reject('102')
    }
  }).then((res) => {
    console.log('201', '上一个返回:' + res)
    return new Promise(() => {})
  }, (res) => {
    if (202 === testPath[1]) {
      console.log('202',  '上一个返回:' + res)
      return '202'
    } else {
      console.log('203',  '上一个返回:' + res)
      throw '203'
    }
  }).then((res) => {
      console.log('301',  '上一个返回:' + res)
      return Promise.resolve('301')
  }, (res) => {
       console.log('302',  '上一个返回:' + res)
      return Promise.resolve('302')
  }).then((res) => {
    console.log('401',  '上一个返回:' + res)
    return Promise.reject('401')
  }).catch((err) => {
    console.log(err)
  })
}



  • Promise.resolve() 等同用 new Promise((resolve, reject) => resolve())
  • Promise.reject() 等同用 new Promise((resolve, reject) => reject())
  • Promise.all()
// 作为参数promise 数组中,所有promise状态都是resolved才回调then第一个,只要有一个reject就reject
Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]).then((res) => {
  console.log('通过', res)
}, (res) => {
  console.log('拒绝', res)
})


返回值为全部值的一个数组

Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.reject(3)]).then((res) => {
  console.log('通过', res)
}, (res) => {
  console.log('拒绝', res)
})


返回值仅返回拒绝的那个

  • Promise.race()
Promise.race([new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(1)
  }, 1001)
}), new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(2)
  }, 1002)
})]).then((res) => {
  console.log('通过', res)
}).catch((res) => {
  console.log('拒绝', res)
})


race 相当于竞赛,多个Promise竞赛,谁先状态变成resolvedrejected,谁就执行下面的回调(根据时间来抉择)

下节预告

Promise 到 generator 再到 async & await

Promise 实际应用

对异步请求封装

流程控制

手写一个Promise

后记

总结一下,从同步异步到回调,在到Promise的语法和应用全部都可以在谷歌浏览器的控制台中输出测试。通过一点点代码的编写和输出,才会让我们思维更清晰,对Promise的理解更深刻。之后再总结工作中用到的Promise,以后也会慢慢将asyncawait结合Promise来谈关于 es6 以后异步相关的新特性。

记一次忏悔的前端面试经验(Vue 双向绑定原理)

2019年6月6号,为了爱情,我离开工作了一年多的广州来到了杭州这个互联网城市。开始我的前端面试之旅...

放下拧螺丝的扳手,开始造起了飞机...

面试的第一家,一开始就问 Vue 双向绑定怎么实现
一脸蒙蔽,之前看过源码,但是没有深入研究,只回答出了使用 Object.defineProperty

Object.defineProperty(obj, prop, {
    // ...
    get: function() {}
    set: function() { // ... }
})

要是再给我一次机会我会这样回答

Vue 双向绑定,使用数据劫持和发布订阅模式实现的

然后我再画一个图来描述整个实现过程是怎样的

vue2.0 采用的是 Object.defineProperty 进行数据劫持的

主要实现原理是使用描述对象中的set方法进行拦截,并发送订阅器信号

// ... 
let dep = new Dep()
return Object.defineProperty(obj, prop, {
    // ...
    get: function(key) {
        dep.target = this
        dep.addSub()
        // ...
    }
    set: function(newVal) {
        val = newVue;
        // 发送一个dep信号
        dep.notify()
        // ...
    }
})

而 vue3.0 中可能会采用 Proxy 来实现数据劫持

let target = {}

let p = new Proxy(target, {
    set: function() {
        //...
    },
    get: function() {
        //...
    }
})

为啥呢?

我们知道 Object.defineProperty 是有局限性的,他的拦截的 target 就是单纯的对象的key的值

所以呢,对象属性的删减,数组,数组长度的改变,它就没法进行劫持了

而 ES6 的新特性,Proxy,它可以拦截对象,数组几乎一切对象包装类型

但是 Proxy 没法兼容 IE,所以 Vue3.0 底层还是采用 Object.defineProperty

而 使用 Proxy 作为一个 api ,也就是说:

我们不兼容IE, 就大胆用 Proxy 双向绑定而且不会有属性删减和数组劫持不到的问题

我们要兼容IE,就用原来的双向绑定,但是要注意它的不能劫持部分变化的缺陷

从上图我们可以看到,Observer 观察了 object 值的变化,这是一种观察者模式

Observer 将观察的信号发布给订阅器这是一种 发布订阅模式

那么观察者模式与发布订阅模式有什么区别呢?

我们先谈观察者模式

什么是观察者模式,首先有一个观察者,一个被观察者,被观察者这里是数据,而观察者是Observer,被观察者发生变化时,主动发生信号给被观察者

按照这个思路来说,我们也能想象尤大,当时设计双向绑定时候,思考怎样去监听这个数据的变化,也就是如何使用观察者模式来实现,而恰好对一个对象的处理中有个对象方法我们可以使用,就是 Object.defineProperty

假如没有这个方法我们怎么实现呢?

这就是 angular 的另外一种实现方式脏检测,也就是不停的轮询数据的变化情况,显然脏检测对性能消耗比较大

再谈谈发布订阅模式

在软件架构中,发布订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。

这里很明显了,区别就在于,不同于观察者和被观察者,发布者和订阅者是互相不知道对方的存在的,发布者只需要把消息发送到订阅器里面,订阅者只管接受自己需要订阅的内容

由此发布订阅模式是一种松耦合的关系,watcherObserver 之间是互相不受影响

后记

感谢观看,第一次

吃透移动端 1px

前言

最近在写移动端 H5 应用,遇到一个值得记录下来的点。现在从它的由来到实现,我们来聊一下移动端 1px,说 1px 不够准确,应该说成 1 物理像素

通过阅读下面文章,你将会理解以下问题:

问题

  • 为什么有 1px 这个问题?
  • 实现 1px 有哪些方法?这些方法分别有哪些优缺点?
  • 开源项目中使用的哪些解决方案?
  • 如何在项目中处理 1px 的相关问题?

由来

基本概念

首先,我们要了解两个概念,一个是像素(pixel)可以简写为px,另外一个是设备像素比(DPR)

像素 :指在由一个数字序列表示的图像中的一个最小单元,单位是 px,不可再次分割了。

设备像素比(DPR): 设备像素比 = 设备像素 / 设备独立像素。

下面我来简单解释下几个概念

  • CSS 像素 (虚拟像素):指的是 CSS 样式代码中使用的逻辑像素,在 CSS 规范中,长度单位可以分为两类,绝对单位以及相对单位。px 是一个相对单位,相对的是设备像素。
  • 设备像素 (物理像素):指设备能控制显示的最小物理单位,意指显示器上一个个的点。从屏幕在工厂生产出的那天起,它上面设备像素点就固定不变了,和屏幕尺寸大小有关。
  • 设备独立像素 (逻辑像素):可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如: CSS 像素),这个点是没有固定大小的,越小越清晰,然后由相关系统转换为物理像素。

也就是说,当逻辑像素是 1pt 时,在 DPR 为 2 的 设备上显示为 2px 的物理像素

参考数据

各种类型的 iphone 手机屏幕设备的参数

注:这里的缩放因子呢,就是 DRP 的值

设计稿对比数据

会有人好奇,为什么设计稿上显示是 750x1334 呢,这是因为设计稿是显示的物理像素

而我们 css 中的像素是逻辑像素应该为 375x 667,在编写代码时要将自定义宽度设置成 375px

那么此时设计稿上的 1px 宽度实际代表的 css 参数应该是 0.5px 对应物理像素 1px,那么怎么实现这个物理像素为 1px 呢

实践

归根结底有两种方案,一种是利用 css 中的transfrom:scaleY(0.5),另一种是设置 媒体查询根据不同 DPR 缩放

解决方案一

原理

利用 css 的 伪元素::after + transfrom 进行缩放

为什么用伪元素?
因为伪元素::after::before是独立于当前元素,可以单独对其缩放而不影响元素本身的缩放

伪元素大多数浏览器默认单引号也可以使用,和伪类一样形式,而且单引号兼容性(ie)更好些

实现

<div class="cell border-1px"> cell <div>

<style>
.cell {
    width: 100px;
    height: 100px;
}
<!--全部边框-->
.border-1px:after {
    content: '';
    position: absolute;
    box-sizing: border-box;
    top: 0;
    left: 0;
    width: 200%;
    height: 200%;
    border: 1px solid #000;
    border-radius: 4px;
    -webkit-transform: scale(0.5);
    transform: scale(0.5);
    -webkit-transform-origin: top left;
}

<!--单边框,以上边框为例-->
.border-1px-top:before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    border-top: 1px solid red;
    transform: scaleY(.5);
    transform-origin: left top;
}
</style>

解决方案二(升级方案一)

原理

使用 less 对公共代码(方案一)封装,同时增加媒体查询分别对不同 DPR 的设备,进行不同的缩放

.border(
    @borderWidth: 1px; 
    @borderStyle: solid; 
    @borderColor: @lignt-gray-color; 
    @borderRadius: 0) {
    position: relative;
    &:before {
        content: '';
        position: absolute;
        width: 98%;
        height: 98%;
        top: 0;
        left: 0;
        transform-origin: left top;
        -webkit-transform-origin: left top;
        box-sizing: border-box;
        pointer-events: none;
    }
    @media (-webkit-min-device-pixel-ratio: 2) {
        &:before {
            width: 200%;
            height: 200%;
            -webkit-transform: scale(.5);
        }
    }
    @media (-webkit-min-device-pixel-ratio: 2.5) {
        &:before {
            width: 250%;
            height: 250%;
            -webkit-transform: scale(.4);
        }
    }
    @media (-webkit-min-device-pixel-ratio: 2.75) {
        &:before {
            width: 275%;
            height: 275%;
            -webkit-transform: scale(1 / 2.75);
        }
    }
    @media (-webkit-min-device-pixel-ratio: 3) {
        &:before {
            width: 300%;
            height: 300%;
            transform: scale(1 / 3);
            -webkit-transform: scale(1 / 3);
        }
    }
    .border-radius(@borderRadius);
    &:before {
        border-width: @borderWidth;
        border-style: @borderStyle;
        border-color: @borderColor;
    }
}

.border-all(
	@borderWidth: 1px; 
	@borderStyle: solid; 
	@borderColor: @lignt-gray-color; 
	@borderRadius: 0) {
    .border(@borderWidth; @borderStyle; @borderColor; @borderRadius);
}

其他方案:

  • 使用图片:兼容性最好,灵活行最差,不能改变颜色、长度
  • 使用 viewportremjs 动态改变 viewportscale 缩放,缺点在于不适用于已有的项目,例如:使用 vhvw 布局的
        <meta name="viewport" id="WebViewport" content="initial-scale=1,    maximum-scale=1, minimum-scale=1, user-scalable=no">
  • 使用 css 渐变linear-gradient或者box-shadow

上述 3 种方案均有致命缺陷暂不推荐使用

兼容性

最后看一下兼容性如何,主要是伪元素、transform:scalemin-device-pixel-ratio 这几个关键词的兼容性

开源库的解决方案

vant 组件库

跳去 github 查看相关代码

使用less写的

.hairline-common() {
  position: absolute;
  box-sizing: border-box;
  content: ' ';
  pointer-events: none;
}

.hairline(@color: @border-color) {
  .hairline-common();

  top: -50%;
  right: -50%;
  bottom: -50%;
  left: -50%;
  border: 0 solid @color;
  transform: scale(0.5);
}

也是采用第一种解决方案

ant-design-mobile 组件库

跳去 github 查看相关代码

.scale-hairline-common(@color, @top, @right, @bottom, @left) {
  content: '';
  position: absolute;
  background-color: @color;
  display: block;
  z-index: 1;
  top: @top;
  right: @right;
  bottom: @bottom;
  left: @left;
}

.hairline(@direction, @color: @border-color-base) when (@direction = 'top') {
  border-top: 1PX solid @color;

  html:not([data-scale]) & {
    @media (min-resolution: 2dppx) {
      border-top: none;

      &::before {
        .scale-hairline-common(@color, 0, auto, auto, 0);
        width: 100%;
        height: 1PX;
        transform-origin: 50% 50%;
        transform: scaleY(0.5);

        @media (min-resolution: 3dppx) {
          transform: scaleY(0.33);
        }
      }
    }
  }
}

.hairline(@direction, @color: @border-color-base) when (@direction = 'right') {
  border-right: 1PX solid @color;

  html:not([data-scale]) & {
    @media (min-resolution: 2dppx) {
      border-right: none;

      &::after {
        .scale-hairline-common(@color, 0, 0, auto, auto);
        width: 1PX;
        height: 100%;
        background: @color;
        transform-origin: 100% 50%;
        transform: scaleX(0.5);

        @media (min-resolution: 3dppx) {
          transform: scaleX(0.33);
        }
      }
    }
  }
}
.hairline(@direction, @color: @border-color-base) when (@direction = 'bottom') {
  border-bottom: 1PX solid @color;
  html:not([data-scale]) & {
    @media (min-resolution: 2dppx) {
      border-bottom: none;
      &::after {
        .scale-hairline-common(@color, auto, auto, 0, 0);
        width: 100%;
        height: 1PX;
        transform-origin: 50% 100%;
        transform: scaleY(0.5);
        @media (min-resolution: 3dppx) {
          transform: scaleY(0.33);
        }
      }
    }
  }
}

.hairline(@direction, @color: @border-color-base) when (@direction = 'left') {
  border-left: 1PX solid @color;

  html:not([data-scale]) & {
    @media (min-resolution: 2dppx) {
      border-left: none;

      &::before {
        .scale-hairline-common(@color, 0, auto, auto, 0);
        width: 1PX;
        height: 100%;
        transform-origin: 100% 50%;
        transform: scaleX(0.5);

        @media (min-resolution: 3dppx) {
          transform: scaleX(0.33);
        }
      }
    }
  }
}

.hairline(@direction, @color: @border-color-base, @radius: 0) when (@direction = 'all') {
  border: 1PX solid @color;
  border-radius: @radius;

  html:not([data-scale]) & {
    @media (min-resolution: 2dppx) {
      position: relative;
      border: none;

      &::before {
        content: '';
        position: absolute;
        left: 0;
        top: 0;
        width: 200%;
        height: 200%;
        border: 1PX solid @color;
        border-radius: @radius * 2;
        transform-origin: 0 0;
        transform: scale(0.5);
        box-sizing: border-box;
        pointer-events: none;

        // @media (min-resolution: 3dppx) {
        //   width: 300%;
        //   height: 300%;
        //   border-radius: @radius * 3;
        //   transform: scale(0.33);
        // }
      }
    }
  }
}

这个值得研究下,比 vant 和 第一种解决方案有点不同,主要在于处理了 DPR 为 2 和为 3 的两种情况,相比来说更加完善。

这里 PX 大写,为了防止插件将 px 转成 rem 等单位

总结

通过该文,你大概了解 1px 问题的来龙去脉了吧,也明白了如何解决相关问题,如果这票文章能解决你的疑问或者工作中问题,不妨点个赞收藏下。

由于技术水平有限,文章中如有错误地方,请在评论区指出,感谢!

接下我应该会关于移动端 H5 布局问题和一些踩坑进行一段学习工作总结,不妨点个关注。

3个小时能把 React 学到哪种程度?

2019年7月3日 天气小晴

现在早上9点,准时开始学习 React

半个小时过一遍 React 官方文档和教程 (9:00 - 9:30)

扫视一遍它的基本介绍(5分钟)

我们看到下面介绍了三个 React 最重要的特性:

  • 声明式:它是说:React 创建用户界面很简单,当数据改变就会高效的更新和立即渲染组件。同时声明式可以让你的代码更加可预测和易调试

怎么就是可预测的和易调试呢,暂时不是很理解

  • 组件化:可以创建一个管理自身状态的组件,通过组合这些组件来创造复杂的UI。因为组件逻辑是用 JavaScript 写的而不是模版,所以你可以传更丰富的数据到你的APP,同时还可以与 DOM 解藕。

  • 一学多用:不需要新的技术栈,重新写新的代码就可以开发一些新的功能。比如用作服务器渲染,React Native 编写移动端代码。


再往下扫,给出了 React 的 4 个简单的小例子

  • Helloworld(认识 组件 和 props)
class HelloMessage extends React.Component {
  render() {
    return (
      <div>
        Hello {this.props.name}
      </div>
    );
  }
}

ReactDOM.render(
  <HelloMessage name="Taylor" />,
  document.getElementById('hello-example')
);

看到它使用 ES6 的继承,继承了一个组件的基类,此刻充满好奇心的你,肯定会想我继承的这个 React.Component 到底是啥?(先留着之后去看 React 的源码)

没有写构造函数,说明它直接继承了基类的构造函数

里面有一个 render 函数 return 一个貌似模版的东西,这个就是最简单的组件

紧接着下面一个 ReactDOM.render函数接受两个参数一个是组件标签,一个id查找,现在大概的意思就是render函数就是要把组件渲染到找到id的这个地方。
组件标签里面的属性就给组件中作为this.props的属性。而且我们知道父组件通过 props 可以将数据传递给子组件

  • 定时器(认识 状态state)
class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = { seconds: 0 };
  }

  tick() {
    this.setState(state => ({
      seconds: state.seconds + 1
    }));
  }

  componentDidMount() {
    this.interval = setInterval(() => this.tick(), 1000);
  }

  componentWillUnmount() {
    clearInterval(this.interval);
  }

  render() {
    return (
      <div>
        Seconds: {this.state.seconds}
      </div>
    );
  }
}

ReactDOM.render(
  <Timer />,
  document.getElementById('timer-example')
);

我们看到第二个例子会发现里面多了很多其他的东西:

  • 构造函数
  • state
  • 声明周期函数

发现我们可以在组件里面定义组件的构造函数,而且可以在构造函数里面初始化一个名为 状态(state)的东东。

怎样去理解状态(state)这个词?

我们假设组件是有生命的,它必然有个生命周期。大致分给三个阶段:

出生----> 变化----> 死亡 (对应) 创建----> 更新----> 销毁

伴随着生命周期的变化,它身上的属性也在发生变化,比如体温、寿命、心情、皮肤好坏、细胞生命力,甚至思维模式。我们可以把这些变化的属性成为状态(state)

但是作为它的创建者,我们即为它的上帝,所以需要控制管理它的状态的变化。所以我们在每一个阶段的变化中加了一个钩子,在相应的阶段去定义一些程序。

这些大概是我看完这段代码最粗浅的理解吧 。

  • Todo(一个小型增删改查APP)
class TodoApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = { items: [], text: '' };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  render() {
    return (
      <div>
        <h3>TODO</h3>
        <TodoList items={this.state.items} />
        <form onSubmit={this.handleSubmit}>
          <label htmlFor="new-todo">
            What needs to be done?
          </label>
          <input
            id="new-todo"
            onChange={this.handleChange}
            value={this.state.text}
          />
          <button>
            Add #{this.state.items.length + 1}
          </button>
        </form>
      </div>
    );
  }

  handleChange(e) {
    this.setState({ text: e.target.value });
  }

  handleSubmit(e) {
    e.preventDefault();
    if (!this.state.text.length) {
      return;
    }
    const newItem = {
      text: this.state.text,
      id: Date.now()
    };
    this.setState(state => ({
      items: state.items.concat(newItem),
      text: ''
    }));
  }
}

class TodoList extends React.Component {
  render() {
    return (
      <ul>
        {this.props.items.map(item => (
          <li key={item.id}>{item.text}</li>
        ))}
      </ul>
    );
  }
}

ReactDOM.render(
  <TodoApp />,
  document.getElementById('todos-example')
);

这个主要是对一下事件的一些运用,增加,删除数组的元素然后更新 dom 相关的操作。在React 中我们能很容易办到。

  • 输入绑定(认识插件和双向绑定)
class MarkdownEditor extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = { value: 'Hello, **world**!' };
  }

  handleChange(e) {
    this.setState({ value: e.target.value });
  }

  getRawMarkup() {
    const md = new Remarkable();
    return { __html: md.render(this.state.value) };
  }

全部快速过一遍,尝试跟着敲一遍。哦,原来 React 是这么用的!!!

总结一下 React 可以做什么呢?

  • 创建一个简单组件,父组件可以通过 props 传值给子组件
  • 还可以创建拥有状态的组件,添加生命周期钩子管理组件状态
  • 对数据增删改查,渲染在 UI
  • 通过事件实现表单的双向绑定

差不多知道怎么用了,我们现在系统的来看一下文档,给以后深入研究铺路
接下来我们去系统的看看它相关的一些概念...

开始进入DOC 系统性的学习下有关 React 的文档概念相关(20分钟)

  1. 安装运行 React
    安装运行有三种方式:
  • 直接使用 script 标签引入
<div id="like_button_container"></div>
  <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>

  <!-- Load our React component. -->
  <script src="like_button.js"></script>
  
<script src="https://unpkg.com/react@16/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js" crossorigin></script>
  • 在 node 环境下安装
npx create-react-app my-app
cd my-app
npm start
  • 使用 CDN
  1. React 的相关概念
  • 简单的例子
ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('root')
);

大致理解为通过ReactDOM对象的render函数,将<h1>Hello, world!</h1>挂载在 id 为 root 下面

  • 我们来了解下JSX,长这个样子:
const element = <h1>Hello, world!</h1>;

这个写法称为JSX, 它既不是字符串,也不是HTML,而是JavaScript 的一种扩展。
看到它有几个特点:
它可以赋值给 一个引用

插入变量和函数
它可以使用{}插入变量和函数

const element = <h1>Hello, {name}</h1>;
// or
const element = (
  <h1>
    Hello, {formatName(user)}!
  </h1>
);

插入在属性值中

const element = <img src={user.avatarUrl}></img>;

可以嵌套子节点

const element = (
  <div>
    <h1>Hello!</h1>
    <h2>Good to see you here.</h2>
  </div>
);

防止xss攻击

const title = response.potentiallyMaliciousInput;
// This is safe:
const element = <h1>{title}</h1>;

通过babel编译后长这个样子

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);
  • 渲染节点是怎么渲染的
    不像浏览器DOM, React 节点是一些简单的对象,所以很容易创建,而且它主要关心的是需要更新的部分。

HTML 中始终存在一个唯一的 root 节点<div id="root"></div>,React DOM 回去管理这个root 下面的东西。

然后把 JSX 和 这个root节点,传递给 ReactDOM.render(),使用这个方法吧节点渲染出来

那么它是怎么更新的呢?

React 节点是 immutable(不变的),一旦创建就不能改变它的子节点和属性,所以唯一能更新的方法就是,创建一个新的节点,传到ReactDOM.render()重新渲染

现在就很清楚了,也就是它要更新UI,存在两个状态,一个是更新前到,一个是更新后的

React 仅仅会更新它必须更新的部分,也就是差异的部分

这个可以放到后面研究,大概是使用 diff 算法比较 虚拟dom树 差异后来更新真实dom

现在我们大致清楚它是如何渲染和更新的了

  • 组件和 props
    组件和函数一样接受一个输入值,返回一个React element

创建组件的两种方式:
通过函数创建

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

通过ES 6 class 创建

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

组件也可以组合成一个复杂的组件

return (
  <div>
    <Welcome name="Sara" />
    <Welcome name="Cahal" />
    <Welcome name="Edite" />
  </div>
);

组件的扩展

function Avatar(props) {
  return (
    <img className="Avatar"
      src={props.user.avatarUrl}
      alt={props.user.name}
    />
  );
}

父组件传值到子组件(props)

All React components must act like pure functions with respect to their props.
它这里强调了就像纯函数一样,所有 React 组件中props也是一样不能直接改变它

  • 状态和生命周期
    之前也提到,大概组件会有三个阶段,每个阶段具体会有几个生命周期方法,大概罗列一下:

载入(挂载阶段 Mounting...)constructor(构造)、 static getDerivedStateFromProps(处于初始化挂载和更新之间,返回一个更新需要的对象或者null(不更新))、render(渲染 DOM )、componentDidMount(完成挂载)

变化(更新阶段 Updating...):static getDerivedStateFromProps(同上)、shouldComponentUpdate(更新前,决定是否更新,返回false不更新)、render(更新 DOM)、getSnapshotBeforeUpdate(更新完成前捕获DOM的信息,然后返回一个参数给DidUpdate 使用)、componentDidUpdate(更新完成)

销毁(卸载阶段 Unmounting...):componentWillUnmount(卸载前)

还有 2 个错误处理的钩子 static getDerivedStateFromError(),componentDidCatch()
具体了解访问 https://reactjs.org/docs/react-component.html

如何使用生命周期钩子呢?

将生命周期钩子添加到Class中

class Clock extends React.Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
		//...
  }
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
      </div>
    );
  }
}

常用做法

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
  componentWillUnmount() {
    clearInterval(this.timerID);
  }

componentDidMount()设置定时器(异步操作),componentWillUnmount()清除相关异步操作

如何更新状态呢?
使用this.setState({comment: 'Hello'});更新状态,不要直接修改state,因为这样不会重新渲染组件

  • 事件机制
    事件处理和 DOM0 很相似但是有这些不同的地方
function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

驼峰而不是全小写

传递函数作为事件处理而不是字符串

需要使用 preventDefault 而不是返回false阻止浏览器默认事件

我们可以通过 箭头函数将 this 绑定到点击事件处理函数上

  handleClick = () => {
    console.log('this is:', this);
  }

或者在初始化时候就绑定

  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }
  • 条件渲染

大概可以分为两种方式
在render函数外部判断,通过return 返回或者引用不同的 React element

if (isLoggedIn) {
	button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
	button = <LoginButton onClick={this.handleLoginClick} />;
}

在render函数内部判断,使用三元操作符来判断

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
      )}
    </div>
  );
}
  • 列表和 key
    使用数组map()来渲染多组件
const listItems = numbers.map((number) =>
  <li>{number}</li>
);

渲染多组件需要使用 唯一的Key 来提高渲染性能,这个也和 diff 算法有关,大概是Key识别组件后,就可以直接复用了旧VDOM的节点了

<ul>
  {props.posts.map((post) =>
    <li key={post.id}>
      {post.title}
    </li>
  )}
</ul>

We don’t recommend using indexes for keys if the order of items may change. This can negatively impact performance and may cause issues with component state. Check out Robin Pokorny’s article for an in-depth explanation on the negative impacts of using an index as a key. If you choose not to assign an explicit key to list items then React will default to using indexes as keys.

如果列表的顺序可能改变的话,这里不推荐使用 index 作为 keys,它可能造成性能问题。大概是因为数组顺序改变了和 改变前的index 和 改变后的index 与组件不对应,这样也是没法复用的。(猜测)这里放在后续研究,这篇文章有讲 https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318

  • 表单相关
    这里提到了一个新的名词“"受控组件",大概意思就是它可以通过输入来控制和改变自己的状态,一般组件只能通过 setState()改变状态,而它可以通过输入改变,它是受到用户输入控制的。
    大概有以下几种: input, textarea,select ...

我们这样可以通过这种特性来实现一个双向绑定, 这里暂时留着后面补充

  • 状态提升
    这个为来解决两个组件值同步问题的,有点像联级查询
    通常来说,组件与组件之间是独立的,一个组件的状态改变不会影响另外一个组件。但是我们现在需要一个组件状态变化,另外一个组件状态也会变化,那该怎么办呢?

现在就又一种方式,给两个组件加一个相同的状态作为桥梁,一旦这个状态改变,同时改变这两个状态的其他状态,这样就达到了更新另一个组件状态的目的。

class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
    this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
    this.state = {temperature: '', scale: 'c'};
  }

  handleCelsiusChange(temperature) {
    this.setState({scale: 'c', temperature});
  }

  handleFahrenheitChange(temperature) {
    this.setState({scale: 'f', temperature});
  }

  render() {
    const scale = this.state.scale;
    const temperature = this.state.temperature;
    const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
    const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;

    return (
      <div>
        <TemperatureInput
          scale="c"
          temperature={celsius}
          onTemperatureChange={this.handleCelsiusChange} />

        <TemperatureInput
          scale="f"
          temperature={fahrenheit}
          onTemperatureChange={this.handleFahrenheitChange} />

        <BoilingVerdict
          celsius={parseFloat(celsius)} />

      </div>
    );
  }
}
  • 组合和继承
    组合和继承真的是老生常谈的话题,设计模式里面推荐是使用组合,原因就在于组合是松耦合的模式,继承是紧耦合的模式。父亲的改变必定会影响到儿子的改变,所以会谨慎使用集成。

除非是父是很稳定不变的,像接口那样只是一个约束,而且约束原则不会频繁变化,使用继承是恰当的。但是一般情况使用组合实现松耦合。

  1. 高级指南(这里还有很多地方不是特别理解,后续添加)
  • Higher-Order Components(高阶组件)
  • Optimizing Performance(性能优化)
  • Reconciliation(协调)
  • Refs (引用)
  • Portals (门)
  • Render Props(渲染 Props)
  • Static Type Checking(静态类型检查)
  • Uncontrolled Components(非受控组件)
  • Web Components(web 组件)
  1. 了解相关API(这里还有很多地方不是特别理解,后续添加)
  • React
  • React.Component
  • ReactDOM
  • ReactDOMServer
  • Shallow Renderer
  • JS Environment Requirements
  • Glossary
  1. 研究新特性(Hooks)

Hooks 是什么?

为了让你放心大胆的使用,它给出了你使用Hooks的三大好处

  • 完全选择性加入:你不想用可以不需要学习和使用,使用它不需要重写你已有的组件代码
  • 100%的向后兼容:它不会中断现有的改变
  • 现在就可以用:16.8 之后就可以用了

为啥要用Hooks?

它可以让你不使用class也可以使用状态和其他功能

  • 组件之间的逻辑很难重用
  • 组件太复杂难以理解
  • class会造成迷惑

可能这些问题,在真正投入使用,真正实践的时候才会遇到吧,暂时先不讨论
看看它怎么去重用逻辑和去除 class 的?

mport React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

这里它通过 useState 来接受一个初始的状态,调用一个setCount函数来控制状态的逻辑.
点击按钮,就会调用这个函数,一旦调用这个函数,就触发了状态的变更。

也就是说我们可以任意时刻去管理状态了,函数组件中就可以了。

这个变更带来的一个直接的好处就是:我们完全可以将组件的某些处理状态的逻辑抽离出来单独处理。

这大概是我最初浅的认识,还需要实践中检验,之后会给出例子。

看看它的API

  1. FAQ
  • Virtual DOM and Internals(虚拟DOM 和它内部实现介绍-fiber)
    之后再去研究

一个小时做一个后台项目的一个小订单管理页面

提出一个需求(2分钟)

/**
* 订单管理页面,包含3个部分
* 1. 筛选栏,包含日期选择、单选、输入、查询按钮
* 2. 表格,包含ID,商品信息,商品数量,金额,状态,操作
* 3. 分页
*/

选择技术方案(3分钟)

尽可能的简单快速的实现它

  • UI组件 antd
  • 预处理 sass
  • 获取数据 axios
  • 模拟数据 json-sever
  • 测试 jest
  • 路由,状态管理,持续集成...暂不需要

动手简单的实践一下(45分钟)

由于篇幅原因,具体实践请看下篇文章…这里跳转(之后添加链接)

效果展示和调优(10分钟)

大概差不多是这种效果
这个不是最终效果,还需要调优...

深入技术栈来研究 (10:00 - 11:00)

知乎上/掘金上搜索一些讲 React 比较好的书,诶,发现两本,很快搞到资源了

  • 《React 精髓》

  • 《深入 React 技术栈》

浅读这两本之后会写一篇博客,对里面知识和作者想法进行梳理

开始大致过一遍这两本书的内容

总结下阅读这两本书的感觉

两本书写的都很好,而且它们刚好侧重点不同,前者侧重于里面核心api的设计**和理念,后者侧重于实际开发中的一些技术难点

之后会有精读的文章出来,请持续关注…

深入源码(11:00 - 11:30)

阅读 React 源码(15分钟)

进入 github 仓库 https://github.com/facebook/react
头一眼看到全是代码很懵,不知道看啥好

首先来搜一些目录结构图,我们要知道

  • 哪个版本?
  • 哪里上手?
  • 我们应该看什么?
  • 这些目录都是做什么用的?
  • 需要掌握哪些东西?
  • 看完后有什么收获?

之后会有深入研究的文章出来,请持续关注

阅读 antd 源码 (15分钟)

现在还有点时间,我们跑去 antd 的github里面,看看它的各个组件是怎么写的
尝试自己写一个 dialogtable 以后再做

差不多粗略看完源码我们对 React 有些许了解了

现在开始了解一下它的相关生态了

逛逛生态圈(11:30 - 12:00)

组件库(10分钟)

  • antd

  • antd pro

  • 其他组件库

状态管理(10分钟)

React and redux based, lightweight and elm-style framework.
D.Va拥有一部强大的机甲,它具有两台全自动的近距离聚变机炮、可以使机甲飞跃敌人或障碍物的推进器、 还有可以抵御来自正面的远程攻击的防御矩阵。

Dva 是基于 React + Redux + Saga 的最佳实践沉淀

app.model({
  namespace: 'count',
  state: {
    record: 0,
    current: 0,
  },
  reducers: {
    add(state) {
      const newCurrent = state.current + 1;
      return { ...state,
        record: newCurrent > state.record ? newCurrent : state.record,
        current: newCurrent,
      };
    },
    minus(state) {
      return { ...state, current: state.current - 1};
    },
  },
  effects: {
    *add(action, { call, put }) {
      yield call(delay, 1000);
      yield put({ type: 'minus' });
    },
  },
  subscriptions: {
    keyboardWatcher({ dispatch }) {
      key('⌘+up, ctrl+up', () => { dispatch({type:'add'}) });
    },
  },
});
  • immutable(不变性的库)

路由(3分钟)

  • react-router(这个同Vue Router 区别不大)

node 相关(4分钟)

  • Umi JS(一个插件,构建,测试,打包工具集)

  • SSR

后续会着重研究SSR相关原理和实践

其他(3分钟)

  • Jest
    (单元测试相关 facebook 出版,react 默认)

两个优势,第一个是一次安装全部拥有,
二是比之前 Karma 系列多了一个快照测试,主要是用了比对dom结构,进行回归测试相关

  • 其他UI框架

    自制简单开源 React UI 计划中...

后记

惨痛经历:本来写了 3400 多字,有次突然发现少了一些篇章,然后急忙按撤回,撤回最后成了全空状态。自动保存后,草稿全被覆盖,丢失了,后来又重新写的,悲惨。

提醒大家如果想写博客,一定不要在线写,直接本地写,写完复制到在线,加图片后直接发布。

感谢阅读

感谢你能阅读到这个地方,还没放弃…

作者能力有限,里面或许有些许文字错误,和一些技术上错误的理解,欢迎在评论中指出改正

本篇文章只是记录了本人 3 个小时学习 React 的经历,可能对那些学习的比较零散而没有章法的人有一些帮助,通过分享出一个学习路线,让他们系统性的构建知识。要想真正掌握 React 里面的相关技术还是要花很长时间的。

如果你想去深入研究下它的话,希望你能看完本篇文章后,可以花更多时间去琢磨里面的一些点和程序的设计。

最后希望各位的技术都有长足的进步,而不是仅仅局限在一些工作的业务上。

下期预告

找工作结束了,下周大概就会正式入职了,写作博客的时间会相对比较少,但是还是希望多多去研究学习,总结一下学到的点,分享给大家。

下期博文的话,内容大概是关于 Vue 的一些思考和在工作中运用的实践总结(时间待定)

还有就是关于上一期后面面试题的研究,也会慢慢研究,之后会出一个系统性的总结(待定)

原创声明

本文完全原创,全部是经过作者3个小时的学习,和一天多思考总结出来的成果。允许转载,但需标明作者和原文链,谢谢!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.