我所学的前端 - 开篇
一个是工程架构设计与最佳实践, 二是数据结构与算法。由于内容比较多,今天不谈数据结构与算法,只谈架构设计与最佳实践。
借2张图来展示我要说的知识。 第一张图是我自己粗略总结的,第二张图是我借用的(因为我面对如此多的知识实在下不去手)。
我把我的知识分为以下几点:
-
思维方式或者说思想
对应到软件设计中就是一些设计上的方法论,比如说在开发语言中思想的表现就是一些编程范式之类的。 对于在思想上的理解,作者也是一知半解。
本人的理解就是:
无论是底层的语言,还是垂直上升到一些项目的工程架构设计。 无论是小到一个组件 一个方法的设计 还是大到一个软件的开发,它的根本都在于两个字【设计】或者说是【结构设计】。提前设计好了一个东西的基本脉络,使之清晰可见,才能帮助我们更好的解决问题,在一定程度上避免了开发过程中的很多坑。相信这些坑我不说相信大家也都经历过。 1> 编程范式 - 思想在开发语言上的的具体表现 2> 设计模式 - 思想在工程设计中的的具体表现 - 代码实践的高度精炼 设计模式无关前端后端(或者说服务端?)。 为何不分?因为在开发过程中我逐渐认识到,无论前端后端,对于机器来说,它就是一个服务。无论你的工程是静态文件还是原生代码,它要被用户访问总要跑在一个服务上,或者是nginx/node/Apache等等。由此对比来说,后端的代码打包成字节码,也一样是跑在服务上的,从这个角度来说前后端是没有区别的。 至于前后端的区别产生在此不论。
先说说让我们爱而不得的那么多种设计模式。常说设计模式存在23+1种,我感觉掌握好常用的设计模式就可以了,设计模式之上是前辈们总结的七大设计原则,开发过程种尽量遵循这些设计原则,将会事半功倍。
设计原则:
单一功能原则
开放关闭原则
里氏代换原则
接口隔离原则
依赖反转原则
设计模式:
单例模式
工厂模式
观察者模式
发布订阅模式
代理模式
适配器模式
策略模式
命令模式
MVC
-
开发语言 - 或者说编程基础
开发语言千千万,作为一前端🐶, 我只玩过javascript, 还有一点Typescript。 当然还有HTML 和 CSS, 这2样也不能拉下。 语言是编程的基础,掌握好一门语言即可踏入程序员的深渊。 稍微列一下
1) html,或者说html5, 要掌握的要素包括 1> 元素 - 标记/标签, 要记住常用的标签,它们的用法,限制,场景,扩展等等。 这里可能会写一些常用标签: html meta head link(这个是用来链接外链的css资源的) title(这个是用来写页面标题的,我都要忘记了) style script noscript(还有一个这样的标签,表示无法运行的js代码或者js代码被禁用) div p span a(专门用来写链接) <ol ul li> (这一套用来写无序和有序列表) button form(这个是表单) select radio checkbox table tr th td br hGroup h1 ~ h6 nav section article header footer 2> 语义化 - 这是一种不强制要求遵循的软规范, 它要求的是 在写html元素及其属性的时候要尽量使用有对应语义的标签,这个是为了seo的搜索。 还可以方便理解,让别人读你的代码尽量很快的了解你在表达什么。 3> DOM, 这个是浏览器组织html标签的一种方式, 由于它是树形结构, 所以我们称之为DOM树。 由于dom是在浏览器知识中的概念,会在之后的宿主环境中进行提及。 2) CSS - 3) EcmaScript 基础数据类型 - 值类型 number string boolean null undefined symbol BigInt 复杂数据类型 - 引用类型 Object/Array/Function 基础语法 - 判断 if / 循环 for / 原型/原型链 - 类/实例化 正则 - 正则表达式 相关方法函数等 事件 - 事件机制 异步 - JS单线程/任务队列/Promise/工作线程 作用域和闭包 4) TypeScript相关常见面试题
// 手写数组转树 function // 树形数组铺平 // 防抖 // 节流 // 宏任务/微任务/任务队列/JS主线程 /********* let var **********/ // setTimeout中的表达式,表现为同步执行 for(let i = 0; i < 3; i++) { setTimeout(console.log(i)) } // 0 1 2 for(var i = 0; i < 3; i++) { setTimeout(console.log(i)) } // 0 1 2 // let 执行时会重新创建i变量,保持变量最新 for(let i = 0; i < 3; i++) { setTimeout(() => { console.log(i) }) } // 0 1 2 for(var i = 0; i < 3; i++) { setTimeout(() => { console.log(i) }) } // 3 3 3 /********* call bind apply **********/ // apply 传递this关键字的引用对象,并且方法会立即执行,参数接收时 - 可接收一个参数数组 // call 传递this关键字的引用对象,并且方法会立即执行,参数接收时 - 接收一系列的单独变量. // bind 传递this关键字的引用对象,返回一个函数的拷贝,带有绑定函数的上下文,并不会立即执行,只有在调用的时候thsi指向才会改变,参数接收时 - 接收一系列的单独变量. // 场景1: const person = { name: "yideng" }; function sayHi(age,test) { return `${this.name} is ${age}, ${test}`; } console.log(sayHi.call(person, 5, 6)); // yideng is 5, 6 调用时this引用改变,立即执行,参数依次进入 console.log(sayHi.bind(person, 5, 6)); //ƒ sayHi(age, test) { // return `${this.name} is ${age}, ${test}`; // } 调用时this引用改变,不会立即执行,参数依次进入 console.log(sayHi.apply(person, [5,6])) // yideng is 5, 6 调用时this引用改变,立即执行,参数分割 // 场景2: call 关于类数组对象在数组操作方法上的使用 - 可以使用的原因是因为类数组对象是存在length属性,而数组上的操作方法都是通过操作length属性来完成的,所以可以执行。 Array.prototype.slice.call() Array.prototype.indexOf.call() Array.prototype.reverse.call() Array.prototype.pop.call() Array.prototype.push.call() // 我们以类数组转数组 Array.prototype.slice.call()说明,通过执行Array.prototype.slice()方法遍历类数组对象,取出其中的key-value, 以key为下标返回新的数组, 如果 Array.prototype.slice.call()上存在参数,参数也会转移至slice中 // ep: let a = {0: '23', 2: {1:3}, 3: '3434',length: 3} Array.prototype.slice.call(a) // (3) ["23", empty, {…}]0: "23"2: {1: 3}length: 3__proto__: Array(0) let a = {0: '23', 2: {1:3, length: 2}, 3: '3434',length: 3} Array.prototype.slice.call(a,1) // (2) [empty, {…}]1: {1: 3, length: 2}1: 3length: 2__proto__: Objectlength: 2__proto__: Array(0) Array.prototype.slice.call(a,2) // [{…}]0: 1: 3length: 2__proto__: Objectlength: 1__proto__: Array(0) Array.prototype.slice.call(a,3) // [] Array.prototype.slice.call(a,4) // [] Array.prototype.slice.call(a) // (3) ["23", empty, {…}]0: "23"2: {1: 3, length: 2}length: 3__proto__: Array(0) Array.prototype.slice.call(a, 1) // (2) [empty, {…}]1: {1: 3, length: 2}length: 2__proto__: Array(0) Array.prototype.slice.call(a, 2) // [{…}] // 场景3: apply 执行可变函数 var allNumbers = [23, 11, 34, 56]; console.log(Math.max.apply(null, allNumbers)); // 56 console.log(Math.max(23, 11, 34, 56)); // 56 // 场景4: bind 执行函数柯里化 - 通过bind不断的把函数上下文锁定为一,逐步增加参数,实现函数的随意调用,或者减少控制者参数的操作步骤 -
宿主环境(运行环境) - 这个一般是2种 浏览器 和 nodeJS
浏览器: 相关知识 nodeJS: 相关知识 -
项目工程化
代码组织是关键 - (模块化-版本管理-依赖管理-语言增强-构建工具-CI/CD-代码质量检测)
-
工具
各种IDE(webstorm vscode vim sublime Text3 Atom) & 工作流工具(git CI/CD webpack postman charles) & 各种类库(lodash jquery 等) & 各种业务解决方案框架(vue react angular bakcbone Ember)
-
其他 - 计算机网络