似水流年

似水流年 查看完整档案

北京编辑中国地质大学(北京)  |  计算机科学与技术 编辑微信公众号:君伟说  |  作者 编辑 blog.csdn.net/wayne214 编辑
编辑

编程开发工作者
微信公众号:君伟说。
微信技术交流群:公众号留言或加好友:备注思否,邀你进群

个人动态

似水流年 收藏了文章 · 2月15日

有了这篇Android面试葵花宝典,你就离进入大厂不远了

跳槽,这在 IT 互联网圈是非常普遍的,也是让自己升职加薪,走上人生巅峰的重要方式。那么作为一个普通的Android程序猿,我们如何才能斩获大厂offer 呢?

疫情向好、面试在即,还在迷茫踌躇中的后浪们,如何才能在面试中让自己脱颖而出,让面试官眼前一亮?

下面,我将结合我过往的面试经历来帮大家分析,在Android大厂面试过程中,我们需要注意的关键点以及我们需要做怎样的准备。

本文适合人群: 刚毕业的大学生、缺乏面试经验的求职者、致力于在大厂社招中寻找Android相关机会的开发者等。

文章末尾我将分享几篇干货满满的面试文章以及资料给大家,记得一定要好好收藏哦!!

面试前的准备

在这部分,我将详细讲解面试前我们需要做哪些方面的工作,以保证我们在面试过程中更加顺利。

准备一份漂亮的简历

一份漂亮的简历就是你进入大厂的敲门砖。

网上有很多教程教大家如何写出一份漂亮的简历,这里我就不做重复劳动了,直接分享给大家一个简历模板:https://github.com/geekcompan...

今天我就要逆向思维讲解一下什么样的简历是糟糕的,这里大家一定要检查一下自己的简历有没有如下的毛病:

  • 薪资期望定得过高或者过低。我们在简历上填写的期望薪资,建议和投递的岗位薪资范围较为接近,懒人可以直接填面议。因为定得过高,面试官看到之后可能会加大面试过程中提问问题的难度。(你想啊,你定的薪资都比面试官高那么多,人家心里什么滋味?还不把你往死里问,看看你到底值不值这个价?)但是如果你定得过低,面试官可能直接就选择忽视你的简历了,毕竟工资又不是面试官发的,人家只是想招进来一个有能力可以背锅的,你定得那么低,明显是对自己水平没信心,也就不会考虑你了。
  • 对自己盲目自信,自己搞不明白的也往简历里写,什么都写精通。这也是非常常见的问题。简历最讲究的是真诚,会什么就写什么,不要为了凸显自己多厉害而胡乱往上写,否则害的还是你自己。你要知道的是,一般好一点的面试官都会简单结合你简历上填写的内容进行针对性的提问。因为技术可提问的点非常多,但是面试的时间是有限的,那么如何才能快速地考察一个人的技术水平呢?最简单的方式就是结合这个人的工作经历进行针对性的提问。其实面试最基本的一项任务就是验证你简历内容的真实性
  • 简历内容过于丰富,技能内容与岗位描述匹配度不高。我就经常在Android招聘岗位上收到很多奇葩的简历。这些人的技能树通常是:C,Android,后台,js等,也就是俗称的全干工程师。说真的,即使你真的全会,你写的这个简历也只是适合小厂的面试,因为大厂是不会去招一个什么都会,什么都不精的人的。你需要在简历中着重突出你区别于其他人的优势,最好的做法就是什么样的岗位投递什么样的简历,多做几套简历作为备选。
  • 工作经历过于丰富。例如3年待过3家及以上数量的公司。工作经历丰富固然是好事,但你也不能全都写到简历里去,选择2~3家较为有名的公司介绍一下即可,否则别人会对你的团队协作能力以及忠诚度提出质疑。
  • 项目经验过于简单或者论文化。无论你的项目经验是多还是少,列举3~4个即可。除此之外,项目经验切忌不要论文化,我经常看到很多人的简历上项目经验是大段大段的描述,加起来可能有2~3页纸...说真的,你写这么多,面试官反而不会看,因为想全部看完实在是太累了。这里你只需要简单介绍一下项目的内容、你负责的模块和担任的角色、涉及到的技术以及最后项目的成果等即可。
  • 技术博客或者github主页没有什么内容也写到简历里。记住技术博客或者github主页这一类的,本来都属于加分项,可有可无的,但是如果你写了,面试官誓必会满怀期待地点进去看,如果这个时候呈现给他的却是空白页或者寥寥几行内容的话,这种一落千丈的感受会给面试官留下非常不好的印象。
  • 简历中填写很多对求职无关的内容。与职位要求无关的内容就不需要写到简历里去了。因为你的简历是拿去找工作用的,任何一个与找工作无关的内容写到简历里只会浪费你简历的空间。例如你的一些兴趣爱好或者无关证件。

自我介绍要背得滚瓜烂熟

自我介绍可以说是面试的必要环节,无论你参加什么形式的面试,面试官一定会首先让你做一个简单的自我介绍,所以自我介绍这一关一定要准备充分,最好做到烂熟于心。

自我介绍不是简历的重复背诵。我们在做自我介绍的时候,一定要把握好重点,切忌过长或者过短。

自我介绍的过程,也是一个自我推销的过程。你可以把面试官当作你的顾客,而把你自己当作推销的产品。你要做的就是使用最真诚的方式,把你个人的工作经验、优点、能力与面试公司的岗位需求紧密结合起来,让面试官相信招这个人进来确实可以分担工作的压力。

那么我们在做自我介绍的时候,需要介绍哪些内容呢?下面我简单列举一些内容供大家参考:

  • 个人基本信息。个人信息的介绍要突出重点。我们需要把重点放在与「公司需求」匹配的信息上,如果该信息匹配或有关联,那么我们就说,如果完全没关联,那就一句话带过或者不说。
  • 工作经历。如果你的工作经历非常丰富,那么简单挑1~2家和目前应聘公司类似的简单介绍一下即可,其实底层的逻辑就是过去经历是否与目前应聘岗位相匹配或有关联。
  • 项目经历。项目经历不要讲太多,挑一个匹配的或者印象最深刻的重点讲一下即可,其他的可以一笔带过。项目经历可以简单从四个维度展开:项目的背景、项目的内容、你在项目中承担的角色和工作、项目的成果或者业绩。
  • 未来愿景。说一些积极向上的内容,进一步说明自身与岗位相匹配,描绘未来愿景,从而更好地打动面试官。(要让面试官觉得招你进来是非常有价值的,小伙子不仅是冲着钱来的,还是有追求讲情怀的)

自我介绍不易过长,准备2~3分钟即可。与此同时,你平时还需要多加练习,根据不同的公司、不同的场合以及面试的不同岗位,进行不同内容的自我介绍。

面试前多刷刷面试题

面试前多刷面试题,是对面试最起码的尊重。

虽然我在这里不提倡大家临时抱佛脚,但是适当地抱一抱佛脚也比那些什么都不准备,就直接裸面的人要好很多,至少你的态度是端正的。

临近年终,很多人开始蠢蠢欲动了,这段时间面试的时候,我就经常能够面到几个啥都不准备,直接甩两膀子就过来面试的。面试基本上是一问三不知,要么就是说之前看过忘了...更有甚者直接就说,我就是出来面个试感受一下面试气氛以及最新行情的...

拜托,能不能给予面试最起码的尊重?你来面试也是需要花费面试官时间的,简单准备一下不香嘛?万一你运气好,恰好这家公司职位扩充,降低面试要求了呢?你这么随便,岂不是把白花花的机会全都给浪费掉了嘛!

面试前先了解一下应聘的公司及职位

提前了解一下应聘的公司及职位内容,可以避免一些不必要的尴尬:

“你知道我们公司是做什么的吗?”

“emm...”

“你知道我们这个岗位的工作内容吗?”

“emm...”

(老哥!你真的是来面试的吗?!)

如果你是面试官,你会用一个都不知道公司和岗位职责是什么的人吗?这至少说明了2个问题:

  • 1.他对这次面试是不重视的!(那他怎么会对他的工作重视呢?)
  • 2.录用他的风险很高!(他要是工作一段时间发现不适合怎么办?)

所以我们在面试前,一定要先在网上搜索一下应聘公司的详细资料以及职位信息:百度、脉脉、企查查、看准网,企业官网等都可以获取到。

那么提前了解这些信息对我们面试会有哪些方面的帮助呢?

  • 1.方便我们准备与之匹配的简历。如果你应聘的是一家做手机Rom定制开发的公司,那么你的简历就需要围绕着手机Rom定制以及Android Framework开发展开。
  • 2.方便我们准备自我介绍的重点。如果你应聘的是一个手机蓝牙开发的职位,那么你在自我介绍的时候就需要突出你在设备通讯以及bluetooth、ble方面的经验和能力。
  • 3.方便我们准备与面试相关的面试题。如果你应聘的部门是做技术中台的,那么你可能就需要多准备一些技术中台、设计模式、框架设计、算法方面的知识。
  • 4.方便我们准备面试时提问的问题。如果你对应聘企业的一些规章、福利或者工作内容有疑问的可以提前准备一些相关问题。

image

面试过程中需要注意的点

保持良好的心态

只要我们在面试之前做好充足的准备,那么我们就应该有足够的信心去面对接下来的各种提问,我们唯一需要做的就是保持良好的心态,下面我简单归纳几点:

  • 淡化成败意识。我们要以一个正常的心态去面对面试,毕竟这不同于研究生面试或者公务员面试那种考试性质的面试,即使没面上你也不会损失什么,何况还能积累面试的经验,所以我们有什么可以担心的呢,就权当是和面试官聊聊天,讨论讨论技术罢了。
  • 保持自信。很多面试官在面试的时候,喜欢采用"你确定吗?"这一类的反问句去反问应聘者的回答,以核实应聘者对知识的掌握是否牢靠。如果这个时候你就开始怀疑自己,出现举棋不定的情况的话,那么面试官可能就会认为你之前的回答只是道听途说,或者就是瞎猜的,根本就没有掌握这个知识点。
  • 不要紧张。紧张的表现主要包括:说话结巴,语无伦次,逻辑混乱,神情慌张,下意识做很多小动作,目光斜视等。这些在面试官看来都是紧张的表现,如果遇到好的面试官可能还会提醒你一下,否则面试基本是凉凉了。
  • 冷静思考。在考官提问问题之后一定要先冷静思考,理清思路,不要急于回答。当遇到问题不清楚或者疑惑的时候,可以主动询问面试官,表达自己的疑惑。这样一方面显得比较沉着冷静,稳重得体。另一方面也可以给自己留出时间理清思路清晰回答。

注意基本礼仪

无论任何时候,我们在与别人交谈的过程中都应当遵守最基本的礼仪。
  • 面试一定要准时,遇事提前沟通,不可随意放别人鸽子。
  • 说话一定要注意语速,不可过快或过慢,口齿要清晰。
  • 面试过程保持一定的严肃性,不可过于散漫甚至笑场。
  • 不要随意打断面试官的话,这是非常不礼貌的行为,
  • 回答面试官提出的问题时一定要有条理,逐句回答。
  • 视频或者电话面试的时候,一定要选择在一个相对安静的环境下进行。

合理运用表达技巧

一个人的语言表达艺术标志着你的成熟和素养。尤其是在大厂中,很多问题其实是可以通过沟通来解决的,所以一个人的语言表达能力往往也是面试官需要考核的内容。

我们应该学会在面试过程中合理运用表达技巧,去凸显自己的语言表达能力。

那么我们应该怎么做呢,这里我仅仅是简单列举一些供大家参考:

  • 吐字清晰、大方得体、语速适中。
  • 说话的语气要平和,不可忽高忽低,也不能过于情绪化。
  • 认真聆听面试官的发言,注意面试官一些细微的表情变化以及手势动作。
  • 必要时可以使用一些机智、幽默的话术。
  • 当语言并不能完全表达意思的时候,可以加上手势或者书面的形式加以描述。

多做一些积极的沟通

我们在面试过程中,难免会遇到一些我们平时从未接触过的内容,如果这个时候你只是简单地回复"我没做过"、"我不了解"、"之前工作没有这方面的要求"之类的消极回答,最终的面试总评可能会被标上不善于思考和分析问题,从而导致面试分数大打折扣,因为没有哪个面试官是喜欢不善于思考和分析的应聘者的,尤其你应聘的还是一个研发岗位。

这里我建议大家在面试过程中最好还是多做一些积极的回答,少做一些消极的回答,除非你对这个问题是彻底不了解。

这里我们可以先和面试官通个气,表明自己平时对这块接触得不多,不过可以简单分析一下。如果这个时候面试官没有明确你不需要继续进行下去的话,你就可以简单思考和分析一下,然后提出你的观点。如果遇到一些好一点的面试官,说不定还会提醒你一下,或者和你一起分析,这就非常棒了。

面试禁忌

我们在面试的过程中,一定要注意避雷,以下列举出来的禁忌一定不要去尝试触碰!

  • 切勿答非所问,偷换概念。当面试官提出一个你并不是很了解的问题时候,即使冷场也不要答非所问,进行偷换概念。因为面试最讲究的就是真诚二字。你这样做只会加深面试官对你的厌恶。
  • 切勿侃侃而谈。有很多人在面试时,为了能够在面试官面前一展"风采",常常是夸夸其谈,口若悬河,殊不知这其实是犯了大忌的。因为在面试官眼里,你这样啪啦啪啦没完没了地讲下去,面试官可能会有如下四种理解:

    • 没有快速答到要点,认为你并没有get到这个问题的本质,对这块掌握得不够。
    • 卖弄自己的知识,日后和这种人合作起来会不会很费力?
    • 废话连篇,浪费我的时间,这样的人工作起来效率是否会打折扣?
    • 知识掌握得还是比较详细的。(这可能是唯一一个为数不多的正面评价吧)
  • 切勿进行不当的反问。在一个不恰当的时机进行一个不恰当的反问,势必会导致很多麻烦。我们在面试过程中,一定不要和面试官进行争论或者反问面试官(虚心求教还是可以的)。如果面试官的水平或者度量还好的话可能没什么关系,但是也不能排除哪些个水平一般或者度量较小的面试官,你和他争论是没有任何好处的。你来这儿面试是为了找工作的,不是去争个对与错的,得罪了面试官没有任何好处。
  • 切勿套近乎。面试过程中,一定要注意保持与面试官的距离,不要上来就套近乎,整得好像你跟面试官很熟似的。即使问题答不上来也不要笑场,记住面试是一件非常严肃的事情,不要过于儿戏!
  • 切勿问与面试结果相关的问题。这里我需要明确的一点是,一轮面试下来,如果你是合适人选的话,面试官一定会告诉你下面面试的流程。你那样急吼吼地想要知道面试结果,非但没有任何意义,反而会加深面试官对你的厌恶。

image

Android技术面试一般涉及的要素

上文主要讲解了一些面试通用的技巧,下面就让我来简单讲解一下Android技术面试中主要涉及的内容有哪些。

Java基础

面试Android岗位,Java基础那是必问的。如果项目中使用kotlin比较多的话,可能还会问一些kotlin相关的问题。

Java, 作为一门基础语言,考核的是应聘者是否具备扎实的基本功。很多培训班或者非科班出身的人,经常会栽在这一环节。一般这个环节的问题答不上来的话,基本上是提前结束了。

那么常见面试的Java基础问题有哪些呢?下面我们简单列举一些供大家参考:

  • 1.Java集合类List,Map,Set相关的实现原理。
  • 2.Java线程池的实现原理和使用
  • 3.Java线程同步相关的知识点。
  • 4.Java锁机制,以及死锁产生的原因以及解决方案。
  • 5.Java反射、泛型、注解相关的知识点以及使用。
  • 6.Java类加载机制。
  • 7.Java虚拟机的资源回收机制以及算法。

以上基本上是面试Android岗位的常见考点,所以我们必须重视对Java语言的学习和理解,即便你在平时工作中使用kotlin较多,也不能忽视对Java基础知识的巩固和学习。

设计模式

设计模式其本身其实也是属于Java基础范畴的,只不过部分大厂对设计模式的要求较高,所以会单独拧出来进行考察。

很多大厂都喜欢招那些对代码有洁癖,有高追求的人进来。在他们眼里,追求的并不是这个功能如何实现,而是这个功能如何更好地实现。只要性能不佳或者扩展性不够强的话,结局基本上就是推翻重构。

其实设计模式的考核因人而异,面试官并不会过于为难你,因为设计模式其本身就是个非常虚的东西,很多人即使是了解设计模式,在平时的工作中也不一定会使用它们。所以设计模式的考核更多的是加分项,并不是必要项,所以即使答不上来其实也是没什么关系的。

但是如果你在简历中写了"熟悉/精通常用的设计模式"的时候,那么你就要小心了,因为你可能将会面临一波直击灵魂深处的拷问。

那么设计模式一般会考察哪些内容呢?下面我们简单列举一些供大家参考:

  • 1.java设计模式的六大设计原则以及它们的关系。
  • 2.单例模式、适配器模式、装饰者模式、代理模式、外观模式、策略模式、观察者模式、责任链模式、命令模式、状态模式、中介者模式。这十一种常用的设计模式是考核的重点,你需要掌握它们的优缺点以及使用的场景。
  • 3.适配器模式,装饰者模式,外观模式它们之间的区别是什么。
  • 4.代理模式、策略模式、状态模式它们之间的区别是什么。
  • 5.外观模式、中介模式它们之间的区别是什么。
  • 6.静态代理和动态代理的区别,什么场景使用,实现动态代理的几种方式。
  • 7.简单列举几个Android源码中使用到设计模式的例子。

以上我只是简单列举了一些设计模式常见的考点,因为设计模式的考核相对灵活,因此还是以实际应用场景为主。

例如,面试官可能会问你:简单列举几个你常用的设计模式,谈谈它们的优缺点以及使用的场景。

这个时候,大多数做Android开发的人脑海里可能只剩下单例模式、观察者模式这些个常常被他们滥用的设计模式。

这里我并不推荐大家说这两种设计模式,为什么呢?因为这两种设计模式并不能很好地诠释设计模式的美。而且你要知道任何东西听多了,人的心理是受不了的,这很容易导致面试官心态崩溃。

就拿我来说,只要一有人无脑回答单例模式或者观察者模式的时候,我都会情不自禁地提高问题的难度。你要知道,就是一个简简单单的单例模式,我也能给你问到心态崩溃。

所以听我的劝,不要一提到设计模式,你脑海里就只剩下单例模式或者观察者模式,多了解了解其他设计模式,对你会有很大的帮助。

注意:对设计模式不够了解的,可以参考我开源的 architect-java 项目,里面有我自己整理的一些简单的算法和设计模式的讲解,可以说非常实用。

Android基础

Android基础,不用说这是面试Android岗位必须要问的内容。要是连这个都答不上来,基本你的面试就提前结束了。

Android基础是任何Android面试都需要考核的内容。不过这也是按级别而定,一般高级开发工程师的面试,Android基础只是一笔带过。

那么Android基础有哪些呢?下面我们简单列举一些供大家参考:

  • 1.Handler机制以及相关知识。
  • 2.Activity和Fragment生命周期。
  • 3.Android四大组件相关的知识。
  • 4.Android进程间通信的方式。
  • 5.Context相关的知识。
  • 6.Activity的启动模式。
  • 7.Android动画相关知识。
  • 8.Android自定义组件相关知识。
  • 9.Android事件分发机制以及触摸事件冲突的处理。
  • 10.ANR产生的原因以及避免ANR的方式。
  • 11.内存泄漏产生的原因以及定位解决的方式。
  • 12.OOM产生的原因以及解决的方式。
  • 13.Android页面渲染机制以及优化方式。
  • 14.LinearLayout、FrameLayout、RelativeLayout和ConstraintLayout的理解和性能对比。
  • 15.Android各版本的特性。
  • 16.Android屏幕适配的技巧。
  • 17.MVC,MVP,MVVM的理解与实践。
  • 18.Android的主题、样式、属性相关的内容。
  • 19.JNI相关的知识。

以上内容是作为一名合格Android开发工程师所必备的知识点,也是常见的考点,请务必每条都要清楚掌握,这样你在面试过程中才能游刃有余。

Android源码分析

Android源码分析,算是要求较高的考核。不过这在大厂面试中非常普遍,因为很多大厂对Android源码的分析和理解都有相当高的要求。

那么常见的Android源码分析有哪些呢?下面我们简单列举一些供大家参考:

  • 1.Android系统的启动流程分析。
  • 2.APP启动的流程分析。
  • 3.Activity的启动流程分析。
  • 4.Zygote进程的创建和启动流程分析。
  • 5.Window窗口创建和加载的流程分析。
  • 6.Dalvik和ART的理解。
  • 7.RecyclerView的源码分析。

阅读源码是一件相对枯燥的事情,如果平时工作中涉及不到的话就很难坚持下去,因此需要非常强的毅力。不过话又说回来,如果你能够熟练地掌握Android源码的话,那么就非常有机会进入大厂了。

Android进阶技能

这部分一般是对Android高级开发工程师的考核,主要涉及的点主要是一些性能优化,技术细节方面的问题。

要想成为一名高级开发工程师,性能优化以及架构设计永远都是绕不开的话题。做技术如果只是广而不深的话,是不可能成为一名高级开发工程师的。只有不断提升自己的不可替代性,才能提高自己的价值。

那么常见的Android进阶技能有哪些呢?下面我们简单列举一些供大家参考:

  • 1.App稳定性优化。(crash、性能以及体验等)
  • 2.App启动速度优化。
  • 3.App内存优化。
  • 4.App界面绘制优化。
  • 5.App瘦身优化。
  • 6.App安全优化。
  • 7.网络请求优化。
  • 8.WebView使用优化。
  • 9.RecyclerView的缓存刷新优化。
  • 10.AOP技术的原理和实践。
  • 11.gradle脚本持续集成技术。
  • 12.App进程保活。

以上只是Android进阶技能的一小部分通用性技术,除此之外还有很多细分领域相关的进阶技能。总之,如果这项技术是你掌握而其他人普遍不了解的,那么它就属于进阶技能。

新技术研究

Android这些年的技术发展基本上已经趋向成熟,所以对于新技术的研究也并不是那么看中,可能面试官就是随口问一下,想要知道你的学习欲望强不强罢了。

那么有什么新的技术可以在业余时间进行研究呢?下面我们简单列举一些供大家参考:

  • 1.Android组件化。
  • 2.Android插件化。
  • 3.Android热更新技术。
  • 4.Android JetPack框架技术。
  • 5.Kotlin开发技术。
  • 6.Android Hook技术。
  • 7.AOP技术。
  • 8.依赖注入技术IoC。
  • 9.跨平台开发技术:ReactNative、Flutter等。

上面的内容,其实很多已经算不上新技术了,如果你现在还不了解的话,那么你最好花点时间了解一下,否则我只能说你是真的out了。

开源项目源码分析

开源项目源码分析和Android源码分析一样,也是考核应聘者对原理的理解。如果仅仅只是会使用而不对其原理加以了解的话,那么你也只能算是达到初级水平,这样是无法进入到大厂的。

那么开源项目的源码分析我们应该怎么做呢?首先我们需要带着问题一点点阅读源码,搞清楚其内部的实现逻辑,然后梳理出其大致的设计架构,画出UML图,最后总结出其中运用到的设计模式和思想。

那么有哪些优质的开源项目值得我们去研究其源码呢?下面我们简单列举一些供大家参考:

  • OkHttp
  • Retrofit
  • Glide
  • LeakCanary
  • RxJava
  • ARouter
  • EventBus
  • ButterKnife
  • GreenDao
  • Dagger2

以上我列举的基本上都是我们平时开发过程中经常使用到的开源项目,认真研究和分析他们的设计思想和精髓,并积极运用到我们平时的编码当中去,可以让我们的技术得到质的飞跃!

算法

部分大厂对Android开发工程师的算法也是有一定要求的,这部分没有什么好说的,打开LeetCode去多刷刷题就可以了。

虽说Android开发工程师也需要掌握一定的算法,不过和那些专业做算法的相比肯定是没那么高的要求的,我们并不需要把LeetCode的每道题都刷一遍,只要把一些简单和中等难度的题刷一遍就可以了。

那么常见的Android算法题有哪些呢?下面我们简单列举一些供大家参考:

  • 1.各类排序。(尤其二分法插入排序、归并排序需要着重掌握其思想)
  • 2.手写反转链表、链表复制、链表合并。
  • 3.手写队列或者链表等数据结构的实现。
  • 4.字符串匹配、去重问题。
  • 5.双指针算法问题。
  • 6.数组查重问题。
  • 7.二叉树的遍历和序列化。
  • 8.贪心算法相关问题。

一个好的算法可能极大地提升应用的性能,如果你平时有心的话就会发现在Android源码中也经常能看到算法的身影,感兴趣的可以阅读一下SparseArray的源码。

Android面试资料分享

资料不在于多,而在于精。下面我就简单分享一下曾经对我帮助比较大的几个面试资料。

最后

今天的文章可谓是积蓄了我这几年来的应聘和面试经历总结出来的经验,干货满满呀!如果你能够一直坚持看到这儿,那么首先我还是十分佩服你的毅力的。不过光是看完而不去付出行动,或者直接进入你的收藏夹里吃灰,那么我写这篇文章就没多大意义了。所以看完之后,还是多多行动起来吧!

可以非常负责地说,如果你能够坚持把我上面列举的内容都一个不拉地看完并且全部消化为自己的知识的话,那么你就至少已经达到了Android中级开发工程师以上的水平,进入大厂技术这块是基本没有什么问题的了。

另外,如果你有任何Android面试方面的问题,欢迎微信搜索公众号:【我的Android开源之旅】,届时我将回答你的疑惑!

我是xuexiangjys,一枚热爱学习,爱好编程,致力于Android架构研究以及开源项目经验分享的技术up主。获取更多资讯,欢迎微信搜索公众号:【我的Android开源之旅】
查看原文

似水流年 赞了文章 · 2月15日

有了这篇Android面试葵花宝典,你就离进入大厂不远了

跳槽,这在 IT 互联网圈是非常普遍的,也是让自己升职加薪,走上人生巅峰的重要方式。那么作为一个普通的Android程序猿,我们如何才能斩获大厂offer 呢?

疫情向好、面试在即,还在迷茫踌躇中的后浪们,如何才能在面试中让自己脱颖而出,让面试官眼前一亮?

下面,我将结合我过往的面试经历来帮大家分析,在Android大厂面试过程中,我们需要注意的关键点以及我们需要做怎样的准备。

本文适合人群: 刚毕业的大学生、缺乏面试经验的求职者、致力于在大厂社招中寻找Android相关机会的开发者等。

文章末尾我将分享几篇干货满满的面试文章以及资料给大家,记得一定要好好收藏哦!!

面试前的准备

在这部分,我将详细讲解面试前我们需要做哪些方面的工作,以保证我们在面试过程中更加顺利。

准备一份漂亮的简历

一份漂亮的简历就是你进入大厂的敲门砖。

网上有很多教程教大家如何写出一份漂亮的简历,这里我就不做重复劳动了,直接分享给大家一个简历模板:https://github.com/geekcompan...

今天我就要逆向思维讲解一下什么样的简历是糟糕的,这里大家一定要检查一下自己的简历有没有如下的毛病:

  • 薪资期望定得过高或者过低。我们在简历上填写的期望薪资,建议和投递的岗位薪资范围较为接近,懒人可以直接填面议。因为定得过高,面试官看到之后可能会加大面试过程中提问问题的难度。(你想啊,你定的薪资都比面试官高那么多,人家心里什么滋味?还不把你往死里问,看看你到底值不值这个价?)但是如果你定得过低,面试官可能直接就选择忽视你的简历了,毕竟工资又不是面试官发的,人家只是想招进来一个有能力可以背锅的,你定得那么低,明显是对自己水平没信心,也就不会考虑你了。
  • 对自己盲目自信,自己搞不明白的也往简历里写,什么都写精通。这也是非常常见的问题。简历最讲究的是真诚,会什么就写什么,不要为了凸显自己多厉害而胡乱往上写,否则害的还是你自己。你要知道的是,一般好一点的面试官都会简单结合你简历上填写的内容进行针对性的提问。因为技术可提问的点非常多,但是面试的时间是有限的,那么如何才能快速地考察一个人的技术水平呢?最简单的方式就是结合这个人的工作经历进行针对性的提问。其实面试最基本的一项任务就是验证你简历内容的真实性
  • 简历内容过于丰富,技能内容与岗位描述匹配度不高。我就经常在Android招聘岗位上收到很多奇葩的简历。这些人的技能树通常是:C,Android,后台,js等,也就是俗称的全干工程师。说真的,即使你真的全会,你写的这个简历也只是适合小厂的面试,因为大厂是不会去招一个什么都会,什么都不精的人的。你需要在简历中着重突出你区别于其他人的优势,最好的做法就是什么样的岗位投递什么样的简历,多做几套简历作为备选。
  • 工作经历过于丰富。例如3年待过3家及以上数量的公司。工作经历丰富固然是好事,但你也不能全都写到简历里去,选择2~3家较为有名的公司介绍一下即可,否则别人会对你的团队协作能力以及忠诚度提出质疑。
  • 项目经验过于简单或者论文化。无论你的项目经验是多还是少,列举3~4个即可。除此之外,项目经验切忌不要论文化,我经常看到很多人的简历上项目经验是大段大段的描述,加起来可能有2~3页纸...说真的,你写这么多,面试官反而不会看,因为想全部看完实在是太累了。这里你只需要简单介绍一下项目的内容、你负责的模块和担任的角色、涉及到的技术以及最后项目的成果等即可。
  • 技术博客或者github主页没有什么内容也写到简历里。记住技术博客或者github主页这一类的,本来都属于加分项,可有可无的,但是如果你写了,面试官誓必会满怀期待地点进去看,如果这个时候呈现给他的却是空白页或者寥寥几行内容的话,这种一落千丈的感受会给面试官留下非常不好的印象。
  • 简历中填写很多对求职无关的内容。与职位要求无关的内容就不需要写到简历里去了。因为你的简历是拿去找工作用的,任何一个与找工作无关的内容写到简历里只会浪费你简历的空间。例如你的一些兴趣爱好或者无关证件。

自我介绍要背得滚瓜烂熟

自我介绍可以说是面试的必要环节,无论你参加什么形式的面试,面试官一定会首先让你做一个简单的自我介绍,所以自我介绍这一关一定要准备充分,最好做到烂熟于心。

自我介绍不是简历的重复背诵。我们在做自我介绍的时候,一定要把握好重点,切忌过长或者过短。

自我介绍的过程,也是一个自我推销的过程。你可以把面试官当作你的顾客,而把你自己当作推销的产品。你要做的就是使用最真诚的方式,把你个人的工作经验、优点、能力与面试公司的岗位需求紧密结合起来,让面试官相信招这个人进来确实可以分担工作的压力。

那么我们在做自我介绍的时候,需要介绍哪些内容呢?下面我简单列举一些内容供大家参考:

  • 个人基本信息。个人信息的介绍要突出重点。我们需要把重点放在与「公司需求」匹配的信息上,如果该信息匹配或有关联,那么我们就说,如果完全没关联,那就一句话带过或者不说。
  • 工作经历。如果你的工作经历非常丰富,那么简单挑1~2家和目前应聘公司类似的简单介绍一下即可,其实底层的逻辑就是过去经历是否与目前应聘岗位相匹配或有关联。
  • 项目经历。项目经历不要讲太多,挑一个匹配的或者印象最深刻的重点讲一下即可,其他的可以一笔带过。项目经历可以简单从四个维度展开:项目的背景、项目的内容、你在项目中承担的角色和工作、项目的成果或者业绩。
  • 未来愿景。说一些积极向上的内容,进一步说明自身与岗位相匹配,描绘未来愿景,从而更好地打动面试官。(要让面试官觉得招你进来是非常有价值的,小伙子不仅是冲着钱来的,还是有追求讲情怀的)

自我介绍不易过长,准备2~3分钟即可。与此同时,你平时还需要多加练习,根据不同的公司、不同的场合以及面试的不同岗位,进行不同内容的自我介绍。

面试前多刷刷面试题

面试前多刷面试题,是对面试最起码的尊重。

虽然我在这里不提倡大家临时抱佛脚,但是适当地抱一抱佛脚也比那些什么都不准备,就直接裸面的人要好很多,至少你的态度是端正的。

临近年终,很多人开始蠢蠢欲动了,这段时间面试的时候,我就经常能够面到几个啥都不准备,直接甩两膀子就过来面试的。面试基本上是一问三不知,要么就是说之前看过忘了...更有甚者直接就说,我就是出来面个试感受一下面试气氛以及最新行情的...

拜托,能不能给予面试最起码的尊重?你来面试也是需要花费面试官时间的,简单准备一下不香嘛?万一你运气好,恰好这家公司职位扩充,降低面试要求了呢?你这么随便,岂不是把白花花的机会全都给浪费掉了嘛!

面试前先了解一下应聘的公司及职位

提前了解一下应聘的公司及职位内容,可以避免一些不必要的尴尬:

“你知道我们公司是做什么的吗?”

“emm...”

“你知道我们这个岗位的工作内容吗?”

“emm...”

(老哥!你真的是来面试的吗?!)

如果你是面试官,你会用一个都不知道公司和岗位职责是什么的人吗?这至少说明了2个问题:

  • 1.他对这次面试是不重视的!(那他怎么会对他的工作重视呢?)
  • 2.录用他的风险很高!(他要是工作一段时间发现不适合怎么办?)

所以我们在面试前,一定要先在网上搜索一下应聘公司的详细资料以及职位信息:百度、脉脉、企查查、看准网,企业官网等都可以获取到。

那么提前了解这些信息对我们面试会有哪些方面的帮助呢?

  • 1.方便我们准备与之匹配的简历。如果你应聘的是一家做手机Rom定制开发的公司,那么你的简历就需要围绕着手机Rom定制以及Android Framework开发展开。
  • 2.方便我们准备自我介绍的重点。如果你应聘的是一个手机蓝牙开发的职位,那么你在自我介绍的时候就需要突出你在设备通讯以及bluetooth、ble方面的经验和能力。
  • 3.方便我们准备与面试相关的面试题。如果你应聘的部门是做技术中台的,那么你可能就需要多准备一些技术中台、设计模式、框架设计、算法方面的知识。
  • 4.方便我们准备面试时提问的问题。如果你对应聘企业的一些规章、福利或者工作内容有疑问的可以提前准备一些相关问题。

image

面试过程中需要注意的点

保持良好的心态

只要我们在面试之前做好充足的准备,那么我们就应该有足够的信心去面对接下来的各种提问,我们唯一需要做的就是保持良好的心态,下面我简单归纳几点:

  • 淡化成败意识。我们要以一个正常的心态去面对面试,毕竟这不同于研究生面试或者公务员面试那种考试性质的面试,即使没面上你也不会损失什么,何况还能积累面试的经验,所以我们有什么可以担心的呢,就权当是和面试官聊聊天,讨论讨论技术罢了。
  • 保持自信。很多面试官在面试的时候,喜欢采用"你确定吗?"这一类的反问句去反问应聘者的回答,以核实应聘者对知识的掌握是否牢靠。如果这个时候你就开始怀疑自己,出现举棋不定的情况的话,那么面试官可能就会认为你之前的回答只是道听途说,或者就是瞎猜的,根本就没有掌握这个知识点。
  • 不要紧张。紧张的表现主要包括:说话结巴,语无伦次,逻辑混乱,神情慌张,下意识做很多小动作,目光斜视等。这些在面试官看来都是紧张的表现,如果遇到好的面试官可能还会提醒你一下,否则面试基本是凉凉了。
  • 冷静思考。在考官提问问题之后一定要先冷静思考,理清思路,不要急于回答。当遇到问题不清楚或者疑惑的时候,可以主动询问面试官,表达自己的疑惑。这样一方面显得比较沉着冷静,稳重得体。另一方面也可以给自己留出时间理清思路清晰回答。

注意基本礼仪

无论任何时候,我们在与别人交谈的过程中都应当遵守最基本的礼仪。
  • 面试一定要准时,遇事提前沟通,不可随意放别人鸽子。
  • 说话一定要注意语速,不可过快或过慢,口齿要清晰。
  • 面试过程保持一定的严肃性,不可过于散漫甚至笑场。
  • 不要随意打断面试官的话,这是非常不礼貌的行为,
  • 回答面试官提出的问题时一定要有条理,逐句回答。
  • 视频或者电话面试的时候,一定要选择在一个相对安静的环境下进行。

合理运用表达技巧

一个人的语言表达艺术标志着你的成熟和素养。尤其是在大厂中,很多问题其实是可以通过沟通来解决的,所以一个人的语言表达能力往往也是面试官需要考核的内容。

我们应该学会在面试过程中合理运用表达技巧,去凸显自己的语言表达能力。

那么我们应该怎么做呢,这里我仅仅是简单列举一些供大家参考:

  • 吐字清晰、大方得体、语速适中。
  • 说话的语气要平和,不可忽高忽低,也不能过于情绪化。
  • 认真聆听面试官的发言,注意面试官一些细微的表情变化以及手势动作。
  • 必要时可以使用一些机智、幽默的话术。
  • 当语言并不能完全表达意思的时候,可以加上手势或者书面的形式加以描述。

多做一些积极的沟通

我们在面试过程中,难免会遇到一些我们平时从未接触过的内容,如果这个时候你只是简单地回复"我没做过"、"我不了解"、"之前工作没有这方面的要求"之类的消极回答,最终的面试总评可能会被标上不善于思考和分析问题,从而导致面试分数大打折扣,因为没有哪个面试官是喜欢不善于思考和分析的应聘者的,尤其你应聘的还是一个研发岗位。

这里我建议大家在面试过程中最好还是多做一些积极的回答,少做一些消极的回答,除非你对这个问题是彻底不了解。

这里我们可以先和面试官通个气,表明自己平时对这块接触得不多,不过可以简单分析一下。如果这个时候面试官没有明确你不需要继续进行下去的话,你就可以简单思考和分析一下,然后提出你的观点。如果遇到一些好一点的面试官,说不定还会提醒你一下,或者和你一起分析,这就非常棒了。

面试禁忌

我们在面试的过程中,一定要注意避雷,以下列举出来的禁忌一定不要去尝试触碰!

  • 切勿答非所问,偷换概念。当面试官提出一个你并不是很了解的问题时候,即使冷场也不要答非所问,进行偷换概念。因为面试最讲究的就是真诚二字。你这样做只会加深面试官对你的厌恶。
  • 切勿侃侃而谈。有很多人在面试时,为了能够在面试官面前一展"风采",常常是夸夸其谈,口若悬河,殊不知这其实是犯了大忌的。因为在面试官眼里,你这样啪啦啪啦没完没了地讲下去,面试官可能会有如下四种理解:

    • 没有快速答到要点,认为你并没有get到这个问题的本质,对这块掌握得不够。
    • 卖弄自己的知识,日后和这种人合作起来会不会很费力?
    • 废话连篇,浪费我的时间,这样的人工作起来效率是否会打折扣?
    • 知识掌握得还是比较详细的。(这可能是唯一一个为数不多的正面评价吧)
  • 切勿进行不当的反问。在一个不恰当的时机进行一个不恰当的反问,势必会导致很多麻烦。我们在面试过程中,一定不要和面试官进行争论或者反问面试官(虚心求教还是可以的)。如果面试官的水平或者度量还好的话可能没什么关系,但是也不能排除哪些个水平一般或者度量较小的面试官,你和他争论是没有任何好处的。你来这儿面试是为了找工作的,不是去争个对与错的,得罪了面试官没有任何好处。
  • 切勿套近乎。面试过程中,一定要注意保持与面试官的距离,不要上来就套近乎,整得好像你跟面试官很熟似的。即使问题答不上来也不要笑场,记住面试是一件非常严肃的事情,不要过于儿戏!
  • 切勿问与面试结果相关的问题。这里我需要明确的一点是,一轮面试下来,如果你是合适人选的话,面试官一定会告诉你下面面试的流程。你那样急吼吼地想要知道面试结果,非但没有任何意义,反而会加深面试官对你的厌恶。

image

Android技术面试一般涉及的要素

上文主要讲解了一些面试通用的技巧,下面就让我来简单讲解一下Android技术面试中主要涉及的内容有哪些。

Java基础

面试Android岗位,Java基础那是必问的。如果项目中使用kotlin比较多的话,可能还会问一些kotlin相关的问题。

Java, 作为一门基础语言,考核的是应聘者是否具备扎实的基本功。很多培训班或者非科班出身的人,经常会栽在这一环节。一般这个环节的问题答不上来的话,基本上是提前结束了。

那么常见面试的Java基础问题有哪些呢?下面我们简单列举一些供大家参考:

  • 1.Java集合类List,Map,Set相关的实现原理。
  • 2.Java线程池的实现原理和使用
  • 3.Java线程同步相关的知识点。
  • 4.Java锁机制,以及死锁产生的原因以及解决方案。
  • 5.Java反射、泛型、注解相关的知识点以及使用。
  • 6.Java类加载机制。
  • 7.Java虚拟机的资源回收机制以及算法。

以上基本上是面试Android岗位的常见考点,所以我们必须重视对Java语言的学习和理解,即便你在平时工作中使用kotlin较多,也不能忽视对Java基础知识的巩固和学习。

设计模式

设计模式其本身其实也是属于Java基础范畴的,只不过部分大厂对设计模式的要求较高,所以会单独拧出来进行考察。

很多大厂都喜欢招那些对代码有洁癖,有高追求的人进来。在他们眼里,追求的并不是这个功能如何实现,而是这个功能如何更好地实现。只要性能不佳或者扩展性不够强的话,结局基本上就是推翻重构。

其实设计模式的考核因人而异,面试官并不会过于为难你,因为设计模式其本身就是个非常虚的东西,很多人即使是了解设计模式,在平时的工作中也不一定会使用它们。所以设计模式的考核更多的是加分项,并不是必要项,所以即使答不上来其实也是没什么关系的。

但是如果你在简历中写了"熟悉/精通常用的设计模式"的时候,那么你就要小心了,因为你可能将会面临一波直击灵魂深处的拷问。

那么设计模式一般会考察哪些内容呢?下面我们简单列举一些供大家参考:

  • 1.java设计模式的六大设计原则以及它们的关系。
  • 2.单例模式、适配器模式、装饰者模式、代理模式、外观模式、策略模式、观察者模式、责任链模式、命令模式、状态模式、中介者模式。这十一种常用的设计模式是考核的重点,你需要掌握它们的优缺点以及使用的场景。
  • 3.适配器模式,装饰者模式,外观模式它们之间的区别是什么。
  • 4.代理模式、策略模式、状态模式它们之间的区别是什么。
  • 5.外观模式、中介模式它们之间的区别是什么。
  • 6.静态代理和动态代理的区别,什么场景使用,实现动态代理的几种方式。
  • 7.简单列举几个Android源码中使用到设计模式的例子。

以上我只是简单列举了一些设计模式常见的考点,因为设计模式的考核相对灵活,因此还是以实际应用场景为主。

例如,面试官可能会问你:简单列举几个你常用的设计模式,谈谈它们的优缺点以及使用的场景。

这个时候,大多数做Android开发的人脑海里可能只剩下单例模式、观察者模式这些个常常被他们滥用的设计模式。

这里我并不推荐大家说这两种设计模式,为什么呢?因为这两种设计模式并不能很好地诠释设计模式的美。而且你要知道任何东西听多了,人的心理是受不了的,这很容易导致面试官心态崩溃。

就拿我来说,只要一有人无脑回答单例模式或者观察者模式的时候,我都会情不自禁地提高问题的难度。你要知道,就是一个简简单单的单例模式,我也能给你问到心态崩溃。

所以听我的劝,不要一提到设计模式,你脑海里就只剩下单例模式或者观察者模式,多了解了解其他设计模式,对你会有很大的帮助。

注意:对设计模式不够了解的,可以参考我开源的 architect-java 项目,里面有我自己整理的一些简单的算法和设计模式的讲解,可以说非常实用。

Android基础

Android基础,不用说这是面试Android岗位必须要问的内容。要是连这个都答不上来,基本你的面试就提前结束了。

Android基础是任何Android面试都需要考核的内容。不过这也是按级别而定,一般高级开发工程师的面试,Android基础只是一笔带过。

那么Android基础有哪些呢?下面我们简单列举一些供大家参考:

  • 1.Handler机制以及相关知识。
  • 2.Activity和Fragment生命周期。
  • 3.Android四大组件相关的知识。
  • 4.Android进程间通信的方式。
  • 5.Context相关的知识。
  • 6.Activity的启动模式。
  • 7.Android动画相关知识。
  • 8.Android自定义组件相关知识。
  • 9.Android事件分发机制以及触摸事件冲突的处理。
  • 10.ANR产生的原因以及避免ANR的方式。
  • 11.内存泄漏产生的原因以及定位解决的方式。
  • 12.OOM产生的原因以及解决的方式。
  • 13.Android页面渲染机制以及优化方式。
  • 14.LinearLayout、FrameLayout、RelativeLayout和ConstraintLayout的理解和性能对比。
  • 15.Android各版本的特性。
  • 16.Android屏幕适配的技巧。
  • 17.MVC,MVP,MVVM的理解与实践。
  • 18.Android的主题、样式、属性相关的内容。
  • 19.JNI相关的知识。

以上内容是作为一名合格Android开发工程师所必备的知识点,也是常见的考点,请务必每条都要清楚掌握,这样你在面试过程中才能游刃有余。

Android源码分析

Android源码分析,算是要求较高的考核。不过这在大厂面试中非常普遍,因为很多大厂对Android源码的分析和理解都有相当高的要求。

那么常见的Android源码分析有哪些呢?下面我们简单列举一些供大家参考:

  • 1.Android系统的启动流程分析。
  • 2.APP启动的流程分析。
  • 3.Activity的启动流程分析。
  • 4.Zygote进程的创建和启动流程分析。
  • 5.Window窗口创建和加载的流程分析。
  • 6.Dalvik和ART的理解。
  • 7.RecyclerView的源码分析。

阅读源码是一件相对枯燥的事情,如果平时工作中涉及不到的话就很难坚持下去,因此需要非常强的毅力。不过话又说回来,如果你能够熟练地掌握Android源码的话,那么就非常有机会进入大厂了。

Android进阶技能

这部分一般是对Android高级开发工程师的考核,主要涉及的点主要是一些性能优化,技术细节方面的问题。

要想成为一名高级开发工程师,性能优化以及架构设计永远都是绕不开的话题。做技术如果只是广而不深的话,是不可能成为一名高级开发工程师的。只有不断提升自己的不可替代性,才能提高自己的价值。

那么常见的Android进阶技能有哪些呢?下面我们简单列举一些供大家参考:

  • 1.App稳定性优化。(crash、性能以及体验等)
  • 2.App启动速度优化。
  • 3.App内存优化。
  • 4.App界面绘制优化。
  • 5.App瘦身优化。
  • 6.App安全优化。
  • 7.网络请求优化。
  • 8.WebView使用优化。
  • 9.RecyclerView的缓存刷新优化。
  • 10.AOP技术的原理和实践。
  • 11.gradle脚本持续集成技术。
  • 12.App进程保活。

以上只是Android进阶技能的一小部分通用性技术,除此之外还有很多细分领域相关的进阶技能。总之,如果这项技术是你掌握而其他人普遍不了解的,那么它就属于进阶技能。

新技术研究

Android这些年的技术发展基本上已经趋向成熟,所以对于新技术的研究也并不是那么看中,可能面试官就是随口问一下,想要知道你的学习欲望强不强罢了。

那么有什么新的技术可以在业余时间进行研究呢?下面我们简单列举一些供大家参考:

  • 1.Android组件化。
  • 2.Android插件化。
  • 3.Android热更新技术。
  • 4.Android JetPack框架技术。
  • 5.Kotlin开发技术。
  • 6.Android Hook技术。
  • 7.AOP技术。
  • 8.依赖注入技术IoC。
  • 9.跨平台开发技术:ReactNative、Flutter等。

上面的内容,其实很多已经算不上新技术了,如果你现在还不了解的话,那么你最好花点时间了解一下,否则我只能说你是真的out了。

开源项目源码分析

开源项目源码分析和Android源码分析一样,也是考核应聘者对原理的理解。如果仅仅只是会使用而不对其原理加以了解的话,那么你也只能算是达到初级水平,这样是无法进入到大厂的。

那么开源项目的源码分析我们应该怎么做呢?首先我们需要带着问题一点点阅读源码,搞清楚其内部的实现逻辑,然后梳理出其大致的设计架构,画出UML图,最后总结出其中运用到的设计模式和思想。

那么有哪些优质的开源项目值得我们去研究其源码呢?下面我们简单列举一些供大家参考:

  • OkHttp
  • Retrofit
  • Glide
  • LeakCanary
  • RxJava
  • ARouter
  • EventBus
  • ButterKnife
  • GreenDao
  • Dagger2

以上我列举的基本上都是我们平时开发过程中经常使用到的开源项目,认真研究和分析他们的设计思想和精髓,并积极运用到我们平时的编码当中去,可以让我们的技术得到质的飞跃!

算法

部分大厂对Android开发工程师的算法也是有一定要求的,这部分没有什么好说的,打开LeetCode去多刷刷题就可以了。

虽说Android开发工程师也需要掌握一定的算法,不过和那些专业做算法的相比肯定是没那么高的要求的,我们并不需要把LeetCode的每道题都刷一遍,只要把一些简单和中等难度的题刷一遍就可以了。

那么常见的Android算法题有哪些呢?下面我们简单列举一些供大家参考:

  • 1.各类排序。(尤其二分法插入排序、归并排序需要着重掌握其思想)
  • 2.手写反转链表、链表复制、链表合并。
  • 3.手写队列或者链表等数据结构的实现。
  • 4.字符串匹配、去重问题。
  • 5.双指针算法问题。
  • 6.数组查重问题。
  • 7.二叉树的遍历和序列化。
  • 8.贪心算法相关问题。

一个好的算法可能极大地提升应用的性能,如果你平时有心的话就会发现在Android源码中也经常能看到算法的身影,感兴趣的可以阅读一下SparseArray的源码。

Android面试资料分享

资料不在于多,而在于精。下面我就简单分享一下曾经对我帮助比较大的几个面试资料。

最后

今天的文章可谓是积蓄了我这几年来的应聘和面试经历总结出来的经验,干货满满呀!如果你能够一直坚持看到这儿,那么首先我还是十分佩服你的毅力的。不过光是看完而不去付出行动,或者直接进入你的收藏夹里吃灰,那么我写这篇文章就没多大意义了。所以看完之后,还是多多行动起来吧!

可以非常负责地说,如果你能够坚持把我上面列举的内容都一个不拉地看完并且全部消化为自己的知识的话,那么你就至少已经达到了Android中级开发工程师以上的水平,进入大厂技术这块是基本没有什么问题的了。

另外,如果你有任何Android面试方面的问题,欢迎微信搜索公众号:【我的Android开源之旅】,届时我将回答你的疑惑!

我是xuexiangjys,一枚热爱学习,爱好编程,致力于Android架构研究以及开源项目经验分享的技术up主。获取更多资讯,欢迎微信搜索公众号:【我的Android开源之旅】
查看原文

赞 9 收藏 6 评论 0

似水流年 发布了文章 · 1月28日

react设置img标签url网络地址不显示

问题

学习React Web页面开发的过程中,遇到了一个问题设置img标签的图片地址,没有任何显示,但是换另外一个图片地址就可以展示,但是通过浏览器直接访问图片地址是没有问题的,有点纳闷,就查阅了一下资料。
通过学习了解调,src设置网络图片无法展示,是因为浏览器在访问图片地址时会自动在请求上添加了refre字段,而有些网站服务器针对refre做了防盗链设计就返回了403,自然就无法展示。

解决方案

解决方案也很简单, 在react项目的public路径下,找到index.html文件,在head标签中添加如下代码即可

<meta name="referrer" content="no-referrer">

在这里插入图片描述

你Get到了吗?如果有问题或建议可以留个评论,喜欢此文章请点个赞或关注我,后边还有更多更精彩的文章,感谢!

查看原文

赞 0 收藏 0 评论 0

似水流年 关注了专栏 · 1月27日

大前端技术栈

大前端技术汇总

关注 1559

似水流年 收藏了文章 · 1月27日

前端知识体系-全系列(图谱+大纲)

前端知识体系(图谱)

前端知识体系大纲

前端工程化体系

前端工程化体系

node

node

主流技术栈

大纲

主流技术栈

React

Vue

vue

Angular

JavaScript

TypeScript

跨平台技术

大纲

跨端技术发展的三个阶段

Hybrid

ReactNative

Flutter

weex

小程序

快应用

ionic

Cordova

性能优化和监控

前端知识体系(大纲)

前端工程化体系

基础设施

  • 规范化

    • 前端标准(基础)

      • W3C
      • SPA
      • DOM
      • BOM
      • XHTML
      • XML
      • JSON
      • JSONP
      • HTTP
      • HTML5
      • CSS3
    • 编码规范

eslint

    - tslint
    - stylelint

- 命名规范

    - Pascal 大小写

        - 组成标识符的每个单词的首字母大写,其余字母小写的书写约定。对于缩写的双字母单词,要求全部大写

    - Camel 大小写

        - 标识符的首字母小写,每个后面连接的单词的首字母大写,其余字母小写的书写约定。对于缩写的双字母单词,要求它们出现在标识符首部时全部小写,否则全部大写

    - 匈牙利命名法

        - 变量名 = 属性 + 类型 + 对象描述

    - 常量的命名

        - 常量的名字应该都使用大写字母,并且指出该常量完整含义

- 目录规范
- commit提交规范

    - commitiizen
    - cz-customizable
    - commitlint

- 文档规范
- 接口规范
- 流程规范

    - gitflow
  • 基础构建优化

    • 压缩
    • 校验
    • 资源合并
    • 打包构建工具

      • Browserify
      • webpack
      • gulp
      • rollup
      • grunt
      • ...
    • 包管理工具

      • Bower
      • npm
      • yarn
  • 模块化

    • JS模块规范

      • 模块规范

        • AMD

          • RequireJS
        • CMD

          • seaJS
        • CommonJS

          • node模块系统
        • ES6+ Module
      • 模块加载机制原理
    • CSS模块化

      • css预处理器

        • Less
        • Sass

          • node-sass
          • dart-sass
        • Stylus
      • css Module
      • css in JS
    • 模块设计
  • 组件化

    • 组件化标准

      • Web Component
    • 组件设计

      • UI和功能拆分(独立性/自由组合)
    • 组件设计

      • 目录结构(就近维护)
  • 资源管理

    • 按需加载
    • 延迟加载
    • 缓存复用
    • CDN部署
    • 文件指纹
    • 请求合并
    • 异步同步加载

工具链

  • 脚手架

    • 脚手架工具原理
    • 命令行工作流
    • 项目模板设计
  • 搭建本地开发环境
  • 搭建本地mock环境
  • 自动化构建

    • webpack配置使用
    • 常用插件
    • webpack构建性能优化
    • 代码转换:ES与Babel
    • CSS预编译与postcss
    • 模块合并:webpack模块化构建
    • webpack增量更新构建
    • 资源定位
    • 自动刷新
  • 引入单元测试
  • 部署发布

    • Jenkins
    • 部署流程
    • 静态资源部署策略
  • 监控

    • 行为监控
    • 异常监控

      • 采集
      • 用户信息
      • 行为信息
      • 异常信息
      • 环境信息
    • 性能监控

      • 运行时监控

        • 文件级
        • 模块级
        • 函数级
        • 算法级
      • 网络请求速率
      • 系统性能

工作流

  • 本地工作流

    • 本地环境
    • 代码分离
    • 测试沙箱
  • 云平台工作流

    • 角色划分

      • 本地开发环境
      • gitlab
      • 云平台
    • 自动化构建与部署

      • gitflow与版本管理
      • webhook与自动构建
    • 持续集成与持续交付

      • 自动构建与测试
      • 生产环境的迭代版本、版本回流
      • Docker容器技术
    • IDE云平台开发

      • IDE工具

调试工具

  • Chrome

    • Element 标签页

      • 用于查看和编辑当前页面中的 HTML 和 CSS 元素
    • Network 标签页

      • 用于查看 HTTP 请求的详细信息,如请求头、响应头及返回内容等
    • Source 标签页

      • 用于查看和调试当前页面所加载的脚本的源文件
    • TimeLine 标签页

      • 用于查看脚本的执行时间、页面元素渲染时间等信息
    • Profiles 标签页

      • 用于查看 CPU 执行时间与内存占用等信息
    • Resource 标签页

      • 用于查看当前页面所请求的资源文件,如 HTML,CSS 样式文件等
    • Audits 标签页

      • 分析页面加载的过程,进而提供减少页面加载时间、提升响应速度的方案,用于优化前端页面,加速网页加载速度等
    • Console 标签页

      • 用于显示脚本中所输出的调试信息,或运行测试脚本等
  • firefox插件Firebug

    • Chrome浏览器出现之前常用的调试工具
  • IE的开发者工具
  • IETest

    • IE浏览器版本切换工具

      • 在开发Web项目的时候,经常会碰到需要在不同的IE版本中检查完成的网页是否能正常展现,这时就需要IETest帮我们模拟网页在IE5.5、IE6、IE7、IE8、IE9以及IE10等浏览器中的兼容性,让我们看一下辛苦做好的CSS样式或网站版面是否可以在各个主要浏览器正常显示
  • Emmet

    • HTML/CSS开发中的神器

https://www.emmet.io/

  • JSON 格式化和校验工具
  • Postman

    • 用于调试请求和响应
  • 移动端抓包调试

    • fiddler
    • Charles

node

基础知识

  • web服务

    • express

      • 中间件、生态完善
    • koa

      • 脱胎于express,提升异步编程体验
    • hapi

      • 遵循配置大于编码原则,沃尔玛前端团队出品
    • sails

      • 模仿ruby on rails框架
    • tsw

      • qq空间出品,集成了很多腾讯内部组件
    • Meteor

      • 快速搭建框架、10倍的减轻工作量
    • Feathers

      • 创建一个面向服务的架构,是一个很好地适合创建Node.js微服务
    • Keystone

      • Keystone是得到一个管理客户端并运行的最好的解决方案之一,以便管理来自MongoDB数据库的内容。管理界面自动从模型生成,具有所有CRUD操作和精细的过滤器。
    • Loopback

      • 内置许多函数,包括使用令牌和到任何类型的数据库连接器的认证
    • egg

      • 为企业级框架和应用而生,是阿里开源的企业级 Node.js 框架
    • Daruk

      • Daruk 是一款基于 Koa2,使用 Typescript 开发的轻量级 web 框架
    • uma

      • 58同城node框架
  • 模板引擎

    • handlebars
    • ejs
    • jade
  • 前端打包

    • webpak
    • fis
  • 任务管理

    • gulp
  • 单元测试

    • karma
    • mocha
    • jasmine
  • 包管理

    • npm
    • cnpm
    • yarn
  • 守护进程

    • pm2
    • forever

三大特点

  • 单线程

    Node.js不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,通过非阻塞I/O、事件驱动机制,让Node.js程序宏观上也是并行的

  • 非阻塞I/O

    由于Node.js中采用了非阻塞型I/O机制,因此在执行了访问数据库的代码之后,将立即转而执行其后面的代码,把数据库返回结果的处理代码放在回调函数中,从而提高了程序的执行效率。
    当某个I/O执行完毕时,将以事件的形式通知执行I/O操作的线程,线程执行这个事件的回调函数。为了处理异步I/O,线程必须有事件循环,不断的检查有没有未处理的事件,依次予以处理。
    阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。而非阻塞模式下,一个线程永远在执行计算操作,这个线程的CPU核心利用率永远是100%。所以,这是一种特别有哲理的解决方案:与其人多,但是好多人闲着;还不如一个人玩命,往死里干活儿。

  • 事件驱动event-driven

    在Node中,在一个时刻,只能执行一个事件回调函数,但是在执行一个事件回调函数的中途,可以转而处理其他事件(比如,又有新用户连接了),然后返回继续执行原事件的回调函数,这种处理机制,称为“事件环”机制。
    Node.js底层是C++(V8也是C++写的)。底层代码中,近半数都用于事件队列、回调函数队列的构建

技术架构

  • 底层架构

    • v8 engine

      • 虚拟机的功能,执行js代码
      • 提供C++函数接口,为nodejs提供v8初始化,创建context,scope等
    • libuv

      • 它是基于事件驱动的异步IO模型库,我们的js代码发出请求,最终由libuv完成,而我们所设置的回调函数则是在libuv触发
    • builtin modules

      • 它是由C++代码写成各类模块,包含了crypto,zlib, file stream etc 基础功能
      • v8提供了函数接口,libuv提供异步IO模型库,以及一些nodejs函数,为builtin modules提供服务
    • native modules

      • 它是由js写成,提供我们应用程序调用的库,同时这些模块又依赖builtin modules来获取相应的服务支持
  • node函数调用机制

通信协议

  • 网络协议

    • http/https

      • 推荐request.js
    • tcp

      • net模块
    • udp

      • dgram模块
  • 数据序列化协议

    • json

      • 文本协议,常用于http通信
    • protocol buffer

      • 二进制协议,常用于socket通信
      • js原生不支持,可以使用protobuf.js来解析
  • 接口协议

    • restful apis

      • 语义化,几乎所有web框架都支持
    • Graphql

      • 解决restful接口过于原子化的缺陷,facebook出品
      • 需要在前端和后台接口之前搭建一层graphql server做数据处理
    • RPC

      • 后台服务间通信
    • 网络序/本地序

      • Buffer模块api原生支持两种序列的转换

存储

  • 数据库

    • MySql
    • MongoDB
    • Oracle
    • MSSQL

      • 微软的SQLServer数据库服务器
    • PostreSQL

      • 功能强大的开源对象关系数据库系统
    • MariaSQL
  • 缓存

    • redis
    • memcache
    • nosql
    • mongodb
    • orm
    • sequelize(mysql)
    • bookshelf(mysql)
    • zookeeper
  • 消息队列

    • RabbitMQ

      • 实现了高级消息队列协议(AMQP)的开源消息代理软件
    • Kafka

      • 消息队列 Kafka 版是阿里云基于 Apache Kafka 构建的高吞吐量、高可扩展性的分布式消息队列服务
    • zmq

      • 是一个消息处理队列库,可在多个线程、内核和主机盒之间弹性伸缩
    • server render
    • websocket

      • 是一种在单个TCP连接上进行全双工通信的协议

设计模式

  • 单例模式

    • 保证一个类只有一个实例
  • 适配器模式

    • 适配器模式可以使原本由于接口不兼容而不能一起工作的那些类可以一起工作
  • 装饰模式

    • 可以通过继承的方式,为一个基类对象扩展功能
  • 观察者模式

    • 就是为某一对象添加一监听事件

主流技术栈

React

  • 简介

    • React 是一个 MVC 框架
    • React 主要是用来构建 UI
    • React 是起源于Facebook的内部项目,用于构建 Instagram 网站,在 2013.05 开源
  • 特点

    • 声明式

      • 使用 React 编写UI界面和写HTML几乎一样
    • 高效

      • React通过对DOM的模拟,最大限度地减少与DOM的交互
    • 灵活

      • React可以与已知的库或框架很好地配合
  • 生命周期

    • constructor

      • 构造函数
    • componentWillMount

      • 在渲染前调用,在客户端也在服务端(高版本已废弃)
    • componentDidMount

      • 在第一次渲染后调用,只在客户端
    • componentWillReceiveProps

      • 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用
    • shouldComponentUpdate

      • 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用
    • componentWillUpdate

      • 在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用
    • componentDidUpdate

      • 在组件完成更新后立即调用。在初始化时不会被调用
    • componentWillUnmount

      • 在组件从 DOM 中移除的时候立刻被调用
  • React思想

    • 组件编写顺序

      • 1.组件划分原则

        • 解耦
        • 复用
        • 适度
      • 2.编写静态组件
      • 3.分析State

        • 哪些是State

            1. 对组件进行两个灵魂质问
            1. 对State集合进行检查和去重
        • State保存的位置

          • 单一状态
          • 状态上移
        1. 添加交互行为
    • mock方式

      • server
      • public
  • Redux思想

    • 使用redux是在解决什么问题

      • 问题原因:数据状态包括API数据,本地数据和UI状态等随着项目扩大变的管理复杂
      • 解决问题的目的:防止管理状态失控
      • 解决问题的手段:使用redux将视图层和状态管理层从逻辑上解耦
    • State

      • 集中管理,全局唯一
      • 不可变性
      • 定义原则与React State定义原则相同
    • Action

      • 普通Acion

        • ActionCreators
        • ActionTypes
      • 异步Action

        • 异步action的创建

          • 请求开始action
          • 请求成功action
          • 请求失败action
        • 拓展reducer

          • 请求数据相关的state数据结构的变化
          • 请求数据相关的reducer内容扩充
        • 集成redux-thunk

          • 问题原因:净化react组件的代码,想将数据请求放在action当中做
          • 解决问题的目的:实现异步Action
          • 解决问题的手段:使用redux-thunk实现异步Action,抽离react中的数据请求代码
    • Reducer

      • combineReducers
    • Store
    • redux-devtools

      • 浏览器插件
      • 项目依赖库
  • React-Redux思想

    • 使用react-redux是在解决什么问题

      • 问题原因:reactUI层和redux状态层的相关代码冗杂在react组件中
      • 解决问题的目的:既能链接reactUI层和redux状态层,又不让两者代码糅合
      • 解决问题的手段:使用react-redux将视图层和状态管理层从代码上解耦
    • 功能

      • Provider组件
      • connect高阶HOC组件
      • map api
    • 容器性组件和展示性组件

      • 关注点
      • 对redux感知
      • 读数据
      • 写数据
      • 如何创建
    • 流程图总结

  • React-Router

    • 服务端路由和客户端路由的区别

      • 服务端路由:访问http://a就返回a.html,访问http://b就返回b.html,是服务器根据不同的路由返回不同的页面
      • 客户端路由:无论访问什么路径,返回的页面信息都是相同的,是通过js通过判断路径的不同来渲染不同的组件而已,所以叫做客户端路由
    • BrowserRouter和HashRouter区别

      • 之前说react-router-dom是将react-route和web-api做绑定,这些web-api具体指的就是HTML5 history API,利用这些pushState、replaceState等方法实现在客户端实现路由的操作
      • 哈希路由是使用url的hash部分作为路由信息,是通过使用页面不同的哈希和不同的组件之间做映射来完成的,哈希的出现主要为了兼容老版本浏览器,因为老版本的浏览器不支持history的API,所以通过哈希的变化来实现路由的变化。但是这样的情况在现在已经很少了,而且哈希的本身含义就是页面的定位,其逻辑也不符合路由的需求
    • 路由渲染组件的三种方式

      • component
      • render
      • children
    • 全新思维

      • 一切皆组件
      • 动态路由离散式声明法
  • 架构设计基础

    • React+Redux项目结构组织方式

      • type(按照类型)

        • 定义

          • 类型指的是该文件在项目当中充当的角色类型
        • 特点

          • 优点

            • 目录结构清晰却明确,功能文件比较紧凑
          • 缺点

            • 新添功能需要在不同的文件中做修改
            • 不利于多人合作下的代码表写和提交合并
      • function(按照功能模块)

        • 定义

          • 功能指的是按照功能或者页面将相关的文件写在同一个文件夹
        • 特点

          • 优点

            • 有利于新功能的开发和拓展
          • 缺点

            • 容易造成store当中存在大量重复性的数据
            • 同一状态在不同的模块中会有不一致的风险
      • Ducks(鸭子类型)

        • 定义

          • 将应用的状态作为模块的划分依据
        • 特点

          • 目录结构清晰紧凑,添加新功能只需添加新模块文件即可
          • 组件需要任何状态只需要引入对应的state模块文件即可
    • 三种设计Redux-State的依据

      • API为依据

        • 定义

          • 以后端API返回数据结构作为State的数据结构
        • 缺点

          • 大量数组类型的结构会造成重复数据的存在
      • UI为依据

        • 定义

          • 不同的UI显示都对应一份State
        • 缺点

          • State数量过多,容易出现错误的State和重复的State
      • 数据库基本原则为依据

        • 整个应用的状态按照领域分成若干子State,子State之间不能保存重复的数据
        • State以键值对的结构存储数据,以记录的key/Id作为记录的索引,记录中的其他字段都依赖于索引
        • State中不能保存可以通过已有数据计算而来的数据,即State中的字段不互相依赖
  • 架构设计进阶

    • selector函数

      • 使用selector是在解决什么问题

        • 问题原因:redux和容器性组件存在部分耦合,redux中的state结构变化会影响后者
        • 解决问题的目的:实现react容器性组件和redux状态层的终极解耦
        • 解决问题的手段:selectors是作为不同层级之间的接口不仅彻底解耦了层级,还使得不同层级通过接口进行安全交互和通讯得以实现
      • selector带来的好处

        • selector限制了层级的内部变化影响范围最多到接口
        • selector防止不同层级互相知道内部结构的风险
        • selector可以负责计算和过滤的工作
    • redux中间件(Middleware)

      • middleware的写法
      • middleware的本质
    • redux增强器(Enhancer)

      • Enhancer的写法
      • Enhancer和Middleware的关系

        • 实际上middleware是store enhancer的一种,中间件虽然比较低阶,但是它约束了我们的行为,而增强器enhancer虽然更加灵活,但是破坏redux底层结构的风险更大,所以如果你对redux整体的结构和逻辑都不是太熟悉,尽量就别用
  • 架构设计高级

    • reducer如何返回新的state对象

      • Object.assign
      • ES6扩展语法
      • Immutable

        • Immutable的常规使用
        • Immutable的优化
        • Immutable的选择考虑

          • 对项目的整体侵入性很强,我们需要改的地方很多,如果你的项目不是很大,且store当中的数据层级不是很多,结构不复杂,不推荐使用的,我们一定要根据需求去搭建架构,去决定是否使用某些工具
    • Reselect

      • 使用Reselect是解决什么问题

        • store当中的state发生了变化,每个容器型组件的mapStateToProps都要重新执行,产生的结果就是上述的这些selectors函数也要重复执行,也就导致了重复计算,使用Reselect创建的selectors函数,只要使用到的state没有发生变化,这个selectors函数就不会去重新计算,比如getVisibleTodos函数使用到了state.filter和state.todos,修改state.text并不会影响state.filter和state.todos,所以getVisibleTodos函数也就不会重复执行
      • Reselect的常规使用
      • Reselect的选择考虑
  • React Hooks

    • 特性

      • hooks 的出现使得你可以在不编写 class 的情况下使用状态管理以及其它 React 的特性
    • Hooks API

      • useState

        • 用来承担与类组件中的 state 一样的作用,组件内部的状态管理
      • useEffect

        • 可以用来模拟生命周期,即可以完成某些副作用
      • useLayoutEffect

        • 它与 useEffect 的用法完全一样,作用也基本相同,唯一的不同在于执行时机,它会在所有的 DOM 变更之后同步调用 effect,可以使用它来
      • useReducer

        • useState 的替代方案,它接收一个 (state, action) => newState 的 reducer 处理函数,并返回当前的 state 和 配套的 dispatch 方法。使用方法与 redux 非常相似
      • useCallback

        • 它有的作用:性能优化,父组件更新,传递给子组件的函数指针不会每次都改变,只有当依赖项发生改变的时候才会改变指针。避免了子组件的无谓渲染
        • 它的本质是对函数依赖进行分析,依赖变更时才重新执行。
      • useMemo

        • useMemo 用于缓存一些耗时的计算结果(返回值),只有当依赖项改变时才重新进行计算
      • useContext

        • 专门为函数组件提供的 context hook API,可以更加方便地获取 context 的值
        • useContext(MyContext) 接收一个 context 对象,当前获取到的值由上层组件中距离最近的 <MyContext.Provider> 的 value 决定
      • useRef

        • useRef 返回一个可变的 ref 对象,其 current 属性被初始化为传入的参数。返回的 ref 对象在组件的整个生命周期内保持不变
  • 未完待续...

Angular

JavaScript

  • JS变量

    • 变量声明

      • 声明

        • 显示声明

var 变量名

        - 隐式声明

自动添加到闭包

    - 陋习

        - 没有类型
        - 重复声明
        - 隐式声明
        - 不声明直接赋值

    - 提倡

        - 先声明后使用
        - 先赋值后运算

- 作用域

    - 全局变量

        - 包含

            - 在函数体外定义的变量
            - 在函数体内定义的无var的变量

        - 调用

            - 任何位置

    - 局部变量

        - 包含

            - 在函数体内部var声明的变量
            - 函数的参数变量

        - 调用

            - 当前函数体内部

    - 优先级

        - 局部变量高于同名全局变量
        - 参数变量高于同名全局变量
        - 局部变量高于同名参数变量

    - 特性

        - 忽略块级作用域
        - 全局变量是全局对象的属性
        - 局部变量是调用对象的属性
        - 作用域链

            - 内层函数可访问外层函数局部变量
            - 外层函数不能访问内层函数局部变量

        - 生命周期

            - 全局变量

                - 除非被显示删除,否则一直存在

            - 局部变量

                - 自声明起至函数执行完毕或被显示删除

            - 回收机制

                - 标记清除
                - 引用计数
  • JS数据类型

    • undefined

      • 使用var声明但未初始化
      • 区分空对象指针与尚未定义的变量
      • 对未初始化的变量及未声明的变量使用typeof都返回undefined
    • null

      • 逻辑上null表示一个空对象的指针
      • 使用typeof检测时会返回object
    • boolean

      • true为真false为假
      • true不一定=1 false不一定=0
      • 使用Boolean()进行转换

        • 转换为true

          • 任何非空字符串
          • 任何非空对象
          • 任何非零数字
        • 转换为false

          • 空字符串
          • 0和NaN
          • null及undefined
    • string

      • 特性

        • 0个或多个16位Unicode字符组成
        • 单引号与双引号不能交叉使用
        • 使用.length属性访问字符串长度

          • 转义序列表示一个字符串
          • 无法精确返回双字节字符串长度
        • 字符串一旦被创建,其值将不能改变,若要改变必须销毁原有字符串
      • 转义序列

        • n 换行
        • t 制表符
        • b 空格
        • r 回车
        • f 分页符
        • \ 斜杠\
        • ' 单引号
        • " 双引号
        • xnn 十六进制数,n代表0~F
        • unnnn 以十六进制表示一个Unicode字符
      • 类型转换

        • toString()

          • 使用类型

            • number
            • string
            • object
            • boolean
          • 参数

            • number类型的数值基数
        • String()

          • undefined
          • null
        • evel()

          • 计算字符串表达式的值并以数值的形式返回
    • number

      • 进制

        • 十进制
        • 八进制
        • 十六进制
      • 浮点数

        • 小数点后至少一位数字
        • 科学计数法

          • 小数点后带有6个0的浮点数
          • 以e为底*10的±N次幂
        • 最高精度

          • 17位小数
        • 缺陷

          • 存在舍入误差
          • 无法测试特定浮点数值
      • 数值范围

        • 最小值

          • Number.MIN_VALUE

            • 5e-324
        • 最大值

          • Number.MAX_VALUE

            • 1.7976931348623157e+308
        • 超出范围

          • 正无穷

            • Infinity
            • Number.POSITIVE_INFINITY
          • 负无穷

            • -Infinity
            • Number.NEGATIVE_INFINITY
          • 缺陷

            • 无法参与下一次计算
          • 检测方法

            • isFinite()

              • 可转换为数值 true
              • 不可转换为数值 false
      • NaN

        • 含义

          • Not a Number
          • 非数值
        • 特性

          • 任何涉及NaN的操作都将返回NaN
          • NaN与任何值都不相等包括自身
        • 检测

          • isNaN()

            • 可转换为数值 false
            • 不可转换为数值 true
      • 数值转换

        • Number()

          • Boolean

            • true

              • 1
            • false

              • 0
          • null

            • 0
          • undefined

            • NaN
          • String

            • 只包含数字

              • 十进制数
              • 前导0被忽略
            • 包含有浮点格式

              • 浮点数值
              • 忽略前导0
            • 包含有效十六进制数

              • 相同大小的十进制数
            • 空字符串

              • 0
            • 其他字符串

              • NaN
          • object

            • 基于toString转成字符串,再转换成数字
    • object

      • 定义

        • 一组数据或者功能的集合
      • 声明

        • var obj = new Object()
        • var obj = {}
      • 属性与方法

        • constructor

          • 保存拥有创建当前对象的函数
        • hasOwnProperty

          • 检测给定属性在当前对象中是否存在
        • isPrototypeOf

          • 检测传入的对象是否是另一个对象的原型
        • propertyIsEnumerable

          • 检测给定的属性是否能用for-in枚举
        • toLocaleString

          • 返回对象的字符串表示,该字符串与执行环境的地区对应
        • toString

          • 返回对象的字符串表示
        • valueOf

          • 返回对象的字符串、布尔或数值表示
  • 未完待续...

TypeScript

  • 基础类型

    • string

      • 同JavaScript用"或者'标识字符串

        • let name: string = "abc"
    • number

      • 数组

        • number[]

          • let list: number[] = [1,2,3]
        • Array<元素类型>

          • let list: Array<number> = [1,2,3]
      • 数字

        • let decLiteral: number = 6
    • boolean

      • let isDone: boolean = false
    • Tuple

      • 元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同
      • let x: [string, number];

x = ['hello', 10]; // OK

- enum

    - 枚举类型是对JavaScript标准数据类型的一个补充
    - enum Color {Red, Green, Blue}

let c: Color = Color.Green;

- Any

    - 未知的数据类型一般使用any

- Void

    - void类型像是与any类型相反,它表示没有任何类型

- Null 和 Undefined

    - undefined和null两者各自有自己的类型分别叫做undefined和null
    - 它们的本身的类型用处不是很大
    - 默认情况下null和undefined是所有类型的子类型

- Never

    - never类型表示的是那些永不存在的值的类型
    - never类型是任何类型的子类型,也可以赋值给任何类型
    - 没有类型是never的子类型或可以赋值给never类型(除了never本身之外)
    - 即使 any也不可以赋值给never

- Object

    - object表示非原始类型
    - 也就是除number,string,boolean,symbol,null或undefined之外的类型
  • 接口

    • 特殊符号

      • 可选

        • ?
      • 只读

        • readonly
      • 签名

        • 字符串型签名
        • 数组型签名

          • 数字型签名会将数字转换成字符串再去匹配
        • 如果同时使用那么数组型签名的返回值必须是字符串型签名的子类的返回值
    • 对象型接口

      • 普通模式

        • key需要对应上
      • 配合签名使用的option模式
    • 函数型接口

      • 参数

        • 不需要key对应,只需要相应位置的相应类型对应
      • 返回值
    • 类类型接口

      • 特点

        • 接口只需要描述类的公共部分,不会去检查私有部分
      • 构造函数的控制方式

        • 构造函数时金泰属性,不属于公共部分
        • 控制new过程
    • 接口继承

      • 接口的切割和继承
      • 特点:类可当做值也可以当做类型
  • 类class

    • 定义了一件事物的抽象特点,包含它的属性和方法
    • ES6类的使用

      • 属性和方法

        • 使用class定义类
        • 使用constructor定义构造函数
        • 通过new生成实例会自动调用构造函数
      • 类的继承

        • 使用extends关键字实现继承
        • 子类中使用super关键字来调用父类的构造函数和方法
      • 静态方法

        • 使用static修饰符修饰的方法称为静态类
        • 不需要实例化
        • 直接通过类来调用
    • TypeScript类的使用

      • 三种访问修饰符
      • public

        • public 修饰的属性或方法是公有的,可以在任何地方被访问到
        • 默认所有的属性和方法都是 public
      • private

        • private 修饰的属性或方法是私有的
        • 不能在声明它的类的外部访问
        • 很多时候,我们希望有的属性是无法直接存取的,这时候就可以用 private 了
        • 需要注意的是,TypeScript 编译之后的代码中,并没有限制 private 属性在外部的可访问性
        • 使用 private 修饰的属性或方法,在子类中也是不允许访问的
      • protected

        • protected 修饰的属性或方法是受保护的
        • 它和 private 类似,区别是它在子类中也是允许被访问的
    • 抽象类

      • 抽象类是供其它类继承的基类
      • 他们一般不会直接被实例化
      • 抽象类可以包含成员的实现细节
      • abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法
      • 抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
      • 抽象方法的语法与接口方法相似。 两者都是定义方法签名不包含方法体。 然而,抽象方法必须使用abstract关键字并且可以包含访问符
    • 类的类型

      • 实现方式类似接口
    • 类实现接口

      • 实现(implements)是面向对象中的一个重要概念
      • 一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),用 implements 关键字来实现
      • 这个特性大大提高了面向对象的灵活性
  • 函数

    • 有可选参数的函数

      • 调用函数时传的参数的数量或者类型不符合函数中定义的参数要求时,TypeScript编译器会报错
      • 在一些场景下我们不需要传所有的参数;TypeScript一个函数可选参数的特性;
      • 在TypeScript中通过在函数参数后面追加一个?,指定参数是可选的
    • 有默认参数的函数

      • 当函数有可选参数时,我们必须检测参数是否被传递了
      • 在声明函数签名时使用=提供一个默认值,即可指定函数参数是可选的;
      • TypeScript编译会在JavaScript输出结果中生成一个if结构
    • 有剩余参数的函数

      • add = (...foo:number[]):number => {}
  • 声明文件

    • 场景

      • 当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能
    • 什么是声明语句

      • 假如我们想使用第三方库 jQuery,一种常见的方式是在 html 中通过 <script> 标签引入 jQuery,然后就可以使用全局变量 $ 或 jQuery 了

        • $('body')
      • 但是在 ts 中,编译器并不知道 $ 或 jQuery 是什么东西
      • 这时,我们需要使用 declare var 来定义它的类型:

        • declare var $: (selector: string) => any;
      • declare var 并没有真的定义一个变量,只是定义了全局变量 $ 的类型,仅仅会用于编译时的检查,在编译结果中会被删除
    • 什么是声明文件

      • 通常我们会把声明语句放到一个单独的文件(index.d.ts)中,这就是声明文件
      • 声明文件必须以.d.ts为后缀
    • 第三方声明文件

      • 我们可以直接下载下来使用,但是更推荐的是使用 @types 统一管理第三方库的声明文件。
      • @types 的使用方式很简单,直接用 npm 安装对应的声明模块即可,以 jQuery 举例:

        • npm install @types/jquery --save-dev
    • 书写声明文件

      • 库文件使用场景

        • 全局变量

          • 通过 <script> 标签引入第三方库,注入全局变量
        • npm包

          • 通过 import foo from 'foo' 导入,符合 ES6 模块规范
        • UMD库

          • 既可以通过 <script> 标签引入,又可以通过 import 导入
        • 直接扩展全局变量

          • 通过 <script> 标签引入后,改变一个全局变量的结构
        • 在 npm 包或 UMD 库中扩展全局变量

          • 引用 npm 包或 UMD 库后,改变一个全局变量的结构
        • 模块插件

          • 通过 <script> 或 import 导入后,改变另一个模块的结构
      • 全局变量声明

        • 使用全局变量的声明文件时,如果是以 npm install @types/xxx --save-dev 安装的,则不需要任何配置。否则就需要在声明文件中声明全局变量
        • 全局变量的几种声明方式

          • declare var/const/let

            • 声明全局变量
          • declare function

            • 声明全局方法
          • declare class

            • 声明全局类
          • declare enum

            • 声明全局枚举类型
          • declare namespace

            • 声明(含有子属性的)全局对象
          • interface 和 type

            • 声明全局类型
  • 未完待续...

Vue

  • 简介

    • Vue是一个MVVM框架
    • Vue是用于构建用户界面的渐进式框架
    • 尤雨溪最开始想起名为 seed.js,但是npm已经被注册了,后来根据 ”view“起名为 vue
    • 2014年由Laravel框架作者推荐后逐渐流行
  • 特点

    • 易用

      • 已经会了 HTML、CSS、JavaScript?即刻阅读指南开始构建应用!
    • 灵活

      • 不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩。
    • 高效

      • 20kB min+gzip 运行大小
      • 超快虚拟 DOM
      • 最省心的优化
  • Vue思想

    • 数据驱动
    • 组件化
  • Vue API

    • 应用API

      • component

        • 注册或检索全局组件。注册还会使用给定的 name 参数自动设置组件的 name。
      • config

        • 包含应用配置的对象。
      • directive

        • 注册或检索全局指令。
      • mixin

        • 在整个应用范围内应用混入。一旦注册,它们就可以在当前的应用中任何组件模板内使用它。插件作者可以使用此方法将自定义行为注入组件。不建议在应用代码中使用。
      • mount

        • 将应用实例的根组件挂载在提供的 DOM 元素上
      • provide

        • 设置一个可以被注入到应用范围内所有组件中的值。组件应该使用 inject 来接收 provide 的值。
        • 从 provide/inject 的角度来看,可以将应用程序视为根级别的祖先,而根组件是其唯一的子级。
        • 该方法不应该与 provide 组件选项或组合式 API 中的 provide 方法混淆。虽然它们也是相同的 provide/inject 机制的一部分,但是是用来配置组件 provide 的值而不是应用 provide 的值。
        • 通过应用提供值在写插件时尤其有用,因为插件一般不能使用组件提供值。这是使用 globalProperties 的替代选择。
      • unmount

        • 在提供的 DOM 元素上卸载应用实例的根组件。
      • use

        • 安装 Vue.js 插件。如果插件是一个对象,它必须暴露一个 install 方法。如果它本身是一个函数,它将被视为安装方法。
        • 该安装方法将以应用实例作为第一个参数被调用。传给 use 的其他 options 参数将作为后续参数传入该安装方法。
        • 当在同一个插件上多次调用此方法时,该插件将仅安装一次
    • 全局API

      • createApp

        • 返回一个提供应用上下文的应用实例。应用实例挂载的整个组件树共享同一个上下文。
      • h

        • 返回一个”虚拟节点“,通常缩写为 VNode:一个普通对象,其中包含向 Vue 描述它应在页面上渲染哪种节点的信息,包括所有子节点的描述。它的目的是用于手动编写的渲染函数
      • defineComponent

        • 从实现上看,defineComponent 只返回传递给它的对象。但是,就类型而言,返回的值有一个合成类型的构造函数,用于手动渲染函数、TSX 和 IDE 工具支持。
      • defineAsyncComponent

        • 创建一个只有在需要时才会加载的异步组件
      • resolveComponent

        • 如果在当前应用实例中可用,则允许按名称解析 component。返回一个 Component。如果没有找到,则返回 undefined。
      • resolveDynamicComponent

        • 允许使用与 <component :is=""> 相同的机制来解析一个 component。返回已解析的 Component 或新创建的 VNode,其中组件名称作为节点标签。如果找不到 Component,将发出警告。
      • withDirectives

        • 允许将指令应用于 VNode。返回一个包含应用指令的 VNode。
      • createRenderer

        • createRenderer 函数接受两个泛型参数: HostNode 和 HostElement,对应于宿主环境中的 Node 和 Element 类型。
      • nextTick

        • 将回调推迟到下一个 DOM 更新周期之后执行。在更改了一些数据以等待 DOM 更新后立即使用它
    • options

      • Data

        • data

          • 返回组件实例的 data 对象的函数
        • props

          • props 可以是数组或对象,用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高阶选项,如类型检测、自定义验证和设置默认值。
        • computed

          • 计算属性将被混入到组件实例中。所有 getter 和 setter 的 this 上下文自动地绑定为组件实例。
        • methods

          • methods 将被混入到组件实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this 自动绑定为组件实例。
        • watch

          • 一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象
        • emits

          • emits 可以是数组或对象,从组件触发自定义事件,emits 可以是简单的数组,或者对象作为替代,允许配置和事件验证
      • DOM

        • template

          • 一个字符串模板作为 component 实例的标识使用。模板将会替换挂载的元素。挂载元素的内容都将被忽略,除非模板的内容有分发插槽。
        • render

          • 字符串模板的另一种选择,允许你充分利用 JavaScript 的编程功能。
      • 生命周期

        • beforeCreate->setup()

          • 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用
        • created->setup()

          • 在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el property 目前尚不可用
        • beforeMount->onBeforeMount

          • 在挂载开始之前被调用:相关的 render 函数首次被调用。
          • 该钩子在服务器端渲染期间不被调用。
        • mounted->onMounted

          • 实例被挂载后调用,这时 Vue.createApp({}).mount() 被新创建的 vm.$el 替换了。如果根实例挂载到了一个文档内的元素上,当 mounted 被调用时 vm.$el 也在文档内。
          • 注意 mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick
          • 该钩子在服务器端渲染期间不被调用
        • beforeUpdate->onBeforeUpdate

          • 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。
          • 该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行
        • updated->onUpdated

          • 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
          • 当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或侦听器取而代之。
          • 注意,updated 不会保证所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以在 updated 里使用 vm.$nextTick
          • 该钩子在服务器端渲染期间不被调用
        • activated

          • 被 keep-alive 缓存的组件激活时调用。
          • 该钩子在服务器端渲染期间不被调用。
        • deactivated

          • 被 keep-alive 缓存的组件停用时调用。
          • 该钩子在服务器端渲染期间不被调用。
        • beforeUnmount(3.0)->onBeforeUnmount

          • 在卸载组件实例之前调用。在这个阶段,实例仍然是完全正常的。
          • 该钩子在服务器端渲染期间不被调用。
        • unmounted(3.0)->onUnmounted

          • 卸载组件实例后调用。调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载。
          • 该钩子在服务器端渲染期间不被调用。
        • errorCaptured->onErrorCaptured

          • 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。
        • renderTracked(3.0)->onRenderTracked

          • 跟踪虚拟 DOM 重新渲染时调用。钩子接收 debugger event 作为参数。此事件告诉你哪个操作跟踪了组件以及该操作的目标对象和键。
        • renderTriggered(3.0)->onRenderTriggered

          • 当虚拟 DOM 重新渲染为 triggered.Similarly 为renderTracked,接收 debugger event 作为参数。此事件告诉你是什么操作触发了重新渲染,以及该操作的目标对象和键。
      • 选项/资源

        • directives

          • 包含组件实例可用指令的哈希表。
        • components

          • 包含组件实例可用组件的哈希表。
    • 实例property

      • $data

        • 组件实例观察的数据对象。组件实例代理了对其 data 对象 property 的访问。
      • $props

        • 当前组件接收到的 props 对象。组件实例代理了对其 props 对象 property 的访问。
      • $el

        • 组件实例使用的根 DOM 元素。
      • $options

        • 用于当前组件实例的初始化选项
      • $parent

        • 父实例,如果当前实例有的话。
      • $root

        • 当前组件树的根组件实例。如果当前实例没有父实例,此实例将会是其自己。
      • $slots

        • 用来访问被插槽分发的内容。
      • $refs

        • 一个对象,持有注册过 ref attribute 的所有 DOM 元素和组件实例。
      • $attrs

        • 包含了父作用域中不作为组件 props 或自定义事件。
    • 实例方法

      • $watch

        • 侦听组件实例上的响应式 property 或函数计算结果的变化。
      • $emit

        • 触发当前实例上的事件。附加参数都会传给监听器回调。
      • $forceUpdate

        • 迫使组件实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。
      • $nextTick

        • 将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
    • 指令

      • v-text

        • 更新元素的 textContent。如果要更新部分的 textContent,需要使用 Mustache 插值。
      • v-html

        • 更新元素的 innerHTML。注意:内容按普通 HTML 插入 - 不会作为 Vue 模板进行编译。如果试图使用 v-html 组合模板,可以重新考虑是否通过使用组件来替代。
      • v-show

        • 根据表达式的真假值,切换元素的 display CSS property。
        • 当条件变化时该指令触发过渡效果。
      • v-if

        • 根据表达式的真假值来有条件地渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建。如果元素是 <template>,将提取它的内容作为条件块。
        • 当条件变化时该指令触发过渡效果。
        • 当和 v-for 一起使用时,v-if 的优先级比 v-for 更高
      • v-else

        • 为 v-if 或者 v-else-if 添加“else 块”。
      • v-else-if

        • 表示 v-if 的“else if 块”。可以链式调用。
      • v-for

        • 基于源数据多次渲染元素或模板块
      • v-on

        • .stop - 调用 event.stopPropagation()。
        • .prevent - 调用 event.preventDefault()。
        • .capture - 添加事件侦听器时使用 capture 模式。
        • .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
        • .{keyAlias} - 仅当事件是从特定键触发时才触发回调。
        • .once - 只触发一次回调。
        • .left - 只当点击鼠标左键时触发。
        • .right - 只当点击鼠标右键时触发。
        • .middle - 只当点击鼠标中键时触发。
        • .passive - { passive: true } 模式添加侦听器
        • 绑定事件监听器。事件类型由参数指定。
      • v-bind

        • 动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。
      • v-model

        • .lazy - 监听 change 而不是 input 事件
        • .number - 输入字符串转为有效的数字
        • .trim - 输入首尾空格过滤
        • 在表单控件或者组件上创建双向绑定。
      • v-slot

        • 提供具名插槽或需要接收 prop 的插槽。
      • v-pre

        • 跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
      • v-cloak

        • 这个指令保持在元素上直到关联组件实例结束编译。和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到组件实例准备完毕。
      • v-once

        • 只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
      • v-is

        • 在 DOM 内模板使用时,模板受原生 HTML 解析规则的约束
    • 特殊指令

      • key

        • key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除/销毁 key 不存在的元素。
        • 有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
      • ref

        • ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
      • is

        • 使用动态组件。
    • 内置组件

      • component

        • 渲染一个“元组件”为动态组件。依 is 的值,来决定哪个组件被渲染。is 的值是一个字符串,它既可以是 HTML 标签名称也可以是组件名称。
      • transition

        • <transition> 元素作为单个元素/组件的过渡效果。<transition> 只会把过渡效果应用到其包裹的内容上,而不会额外渲染 DOM 元素,也不会出现在可被检查的组件层级中。
      • transition-group

        • <transition-group>提供多个元素/组件的过渡效果。默认情况下,它不呈现包装DOM元素,但可以通过tag属性定义一个。
        • 注意,每个 <transition-group> 的子节点必须有独立的 key,动画才能正常工作
      • keep-alive

        • <keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition> 相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。
        • 当组件在 <keep-alive> 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。
        • 主要用于保留组件状态或避免重新渲染。
      • slot

        • <slot> 元素作为组件模板之中的内容分发插槽。<slot> 元素自身将被替换。
      • teleport

        • 允许我们控制在 DOM 中哪个父节点下渲染了 HTML,而不必求助于全局状态或将其拆分为两个组件。
    • 响应式API

      • 响应式基础API

        • reactive

          • 返回对象的响应式副本
          • 响应式转换是“深层”的——它影响所有嵌套 property。在基于 ES2015 Proxy 的实现中,返回的 proxy 是不等于原始对象的。建议只使用响应式 proxy,避免依赖原始对象。
        • readonly

          • 获取一个对象 (响应式或纯对象) 或 ref 并返回原始 proxy 的只读 proxy。只读 proxy 是深层的:访问的任何嵌套 property 也是只读的。
        • isProxy

          • 检查对象是否是由 reactive 或 readonly 创建的 proxy。
        • isReactive

          • 检查对象是否是 reactive创建的响应式 proxy。
        • isReadonly

          • 检查对象是否是由readonly创建的只读 proxy。
        • toRaw

          • 返回 reactive 或 readonly proxy 的原始对象。这是一个转义口,可用于临时读取而不会引起 proxy 访问/跟踪开销,也可用于写入而不会触发更改
        • markRaw

          • 标记一个对象,使其永远不会转换为 proxy。返回对象本身。
        • shallowReactive

          • 创建一个响应式 proxy,跟踪其自身 property 的响应性,但不执行嵌套对象的深度响应式转换 (暴露原始值)。
        • shallowReadonly

          • 创建一个 proxy,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换 (暴露原始值)。
      • Refs

        • ref

          • 接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象具有指向内部值的单个 property .value。
        • unref

          • 如果参数为 ref,则返回内部值,否则返回参数本身。这是 val = isRef(val) ? val.value : val。
        • toRef

          • 可以用来为源响应式对象上的 property 新创建一个 ref。然后可以将 ref 传递出去,从而保持对其源 property 的响应式连接。
        • toRefs

          • 将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的ref。
        • isRef

          • 检查值是否是ref对象。
        • customRef

          • 创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数,该函数接收 track 和 trigger 函数作为参数,并应返回一个带有 get 和 set 的对象。
        • shallowRef

          • 创建一个 ref,它跟踪自己的 .value 更改,但不会使其值成为响应式的。
        • triggerRef

          • 手动执行与 shallowRef 关联的任何副作用。
      • Computed和watch

        • computed

          • 使用 getter 函数,并为从 getter 返回的值返回一个不变的响应式 ref 对象。
        • watchEffect

          • 在响应式地跟踪其依赖项时立即运行一个函数,并在更改依赖项时重新运行它。
        • watch

          • watch API 与选项式 API this.$watch (以及相应的 watch 选项) 完全等效。watch 需要侦听特定的数据源,并在单独的回调函数中执行副作用。默认情况下,它也是惰性的——即回调仅在侦听源发生更改时调用。
    • 组合式API

      • setup

        • 一个组件选项,在创建组件之前执行,一旦 props 被解析,并作为组合式 API 的入口点
        • props

          • setup 函数中的第一个参数是 props。正如在一个标准组件中所期望的那样,setup 函数中的 props 是响应式的,当传入新的 prop 时,它将被更新。
        • context

          • 传递给 setup 函数的第二个参数是 context。context 是一个普通的 JavaScript 对象,它暴露三个组件的 property
      • 生命周期钩子
  • Vuex
  • Vue-router
  • Vue-SSR
  • Vue-Loader
  • Vue-Cli

    • 通过 @vue/cli 实现的交互式的项目脚手架。
    • 通过 @vue/cli + @vue/cli-service-global 实现的零配置原型开发。
    • 一个运行时依赖 (@vue/cli-service)
    • Cli

      • CLI (@vue/cli) 是一个全局安装的 npm 包,提供了终端里的 vue 命令。它可以通过 vue create 快速搭建一个新项目,或者直接通过 vue serve 构建新想法的原型。你也可以通过 vue ui 通过一套图形化界面管理你的所有项目
    • Cli服务

      • CLI 服务 (@vue/cli-service) 是一个开发环境依赖。它是一个 npm 包,局部安装在每个 @vue/cli 创建的项目中。
      • CLI 服务是构建于 webpack 和 webpack-dev-server 之上的

        • 加载其它 CLI 插件的核心服务;
        • 一个针对绝大部分应用优化过的内部的 webpack 配置;
        • 项目内部的 vue-cli-service 命令,提供 serve、build 和 inspect 命令
    • Cli插件

      • CLI 插件是向你的 Vue 项目提供可选功能的 npm 包,例如 Babel/TypeScript 转译、ESLint 集成、单元测试和 end-to-end 测试等。Vue CLI 插件的名字以 @vue/cli-plugin- (内建插件) 或 vue-cli-plugin- (社区插件) 开头,非常容易使用。
      • 当你在项目内部运行 vue-cli-service 命令时,它会自动解析并加载 package.json 中列出的所有 CLI 插件。
      • 插件可以作为项目创建过程的一部分,或在后期加入到项目中。它们也可以被归成一组可复用的 preset
  • Vue-Devtools
  • vue-class-component

跨平台技术

跨端技术发展的三个阶段

  • 第一阶段是混合开发的web容器时代

    • 为了解决原生开发的高成本、低效率,出现了Hybrid混合开发
    • 原生中嵌入依托于浏览器的WebView
    • Web浏览器中可以实现的需求在WebView中基本都可以实现
    • 但是Web最大的问题是,它的性能和体验与原生开发存在肉眼可感知的差异
    • 因此并不适用于对性能和用户体验要求较高的场景
  • 第二阶段是以RN和Weex为代表的泛web容器时代

    • RN对Web标准进行了功能裁剪
    • 用户体验更接近于原生了
    • 由于进行了功能裁剪,所以RN对业务的支持能力还不到浏览器的5%
    • 因此仅适用于中低复杂度的低交互类页面。面对稍微复杂一点儿的交互和动画需求,都需要通过调用原生代码去扩展才能实现
  • 第三阶段是以Flutter为代表的自绘引擎时代

    • Flutter是构建Google物联网操作系统Fuchsia的SDK
    • 它使用Dart语言开发APP
    • 一套代码可以同时运行在iOS和Android平台上
    • Flutter采用自带的Native渲染引擎渲染视图,它是自己完成了组件渲染的闭环
    • 而RN、Weex之类的框架,只是通过JavaScript虚拟机扩展调用系统组件,最后是由Android或者iOS系统来完成组件的渲染

Hybrid

  • 为什么要引入hybrid开发

    • Native应对急速业务需求,APP迭代加快,频繁的发版已难以应付
    • Android渠道众多,apple store审核周期长
    • 纯native开发效率低,开发维护成本高,不支持热更新
    • 相对于其他动态发布技术,技术研发成本较低,使用语言更广泛,社区资源更丰富
  • 优劣势

    • 原生APP

      • 优点

        • 打造完美的用户体验
        • 性能稳定、操作速度快,上手流畅
        • 访问本地资源(通讯录,相册)
        • 设计出色的动效,转场
        • 拥有系统级别的贴心通知或提醒
        • 用户留存率高
      • 缺点

        • 分发成本高(不同平台有不同的开发语言和界面适配)
        • 维护成本高
        • 更新缓慢,根据不同平台,提交–审核–上线 等等不同的流程,需要经过的流程较复杂
    • Web APP

      • 优点

        • 发版完全自控随时更新开发成本小时间快
      • 缺点

        • 性能差弱网络无网络条件下体验差
    • Hybrid APP

      • 优点

        • 跨平台
        • 开发周期短、成本低
        • 用户体验良好
        • 可以即时修复bug、动态发版
      • 缺点

        • 仿原生iOS效果复杂
        • 机型兼容性
  • 整体架构

    • viewLayer(视图层)

      • H5

        • H5页面
        • webview引擎渲染
      • Native

        • Native页面
        • 系统原生引擎渲染
    • coreLayer(通信层)

      • 自定义webview资源拦截管理器

        • 内置资源管理
        • 缓存模块
        • 文件下载模块
      • 定义页面跳转管理器
      • 定义混合通信交互模块
  • 交互设计

    • 交互原理

      • 两种交互

        • native主动调用前端JS
        • H5主动与native发起通信
      • 交互过程(OC)

        • 搭建JS调用OC的桥梁,注册供JS调用的方法name
        • JS在调用Native注册方法

          • iOS:window.webkit.messageHandlers.自定义属性.postMessage()
          • Android:window.自定义方法
        • Native接收JS调用,解析处理,返回回调
    • 通信方式

      • 假跳转的请求拦截(不建议)

        • 假跳转的请求拦截 就是由网页发出一条新的跳转请求,跳转的目的地是一个非法的压根就不存在的地址
        • 比如:wbcst://testhost/action?params=xxx
        • 模拟http协议网络请求 scheme://host/action?params
        • 客户端会无差别拦截所有请求,真正的url地址应该照常放过,只有协议域名匹配的url地址才应该被客户端拦截
        • JS调用方式

          • a标签跳转
          • location.href跳转
          • iframe跳转
        • 不建议使用,android系统对url参数做了字节限制,无法进行大数据的通信
      • 弹窗拦截(不建议)

        • alert

          • 弹出个提示框,只能点确认无回调
        • confirm

          • 弹出个确认框(确认,取消),可以回调
        • prompt

          • 弹出个输入框,让用户输入东西,可以回调
        • 不建议使用,会无差别的拦截所有前端的window弹窗
      • JS上下文注入(推荐)

        • iOS

          • WKWebView scriptMessageHandler注入
        • android

          • addJavascriptInterface注入
        • 特点

          • 不通过任何拦截的办法,而是直接将一个native对象(or函数)注入到JS里面,可以由web的js代码直接调用,直接操作

ReactNative

  • 简介

    • 特性

      • Learn Once,Write AnyWhere
      • 提供了原生控件支持
      • 异步执行
      • 触屏处理
    • 设计理念

      • 既拥有Native的用户体验
      • 又保留React的开发效率
    • 优势

      • 它对比原生开发更为灵活,对比H5体验更为高效。
      • 替代传统的WebView,打开效率更高,和原生之间的交互更方便。
      • 多个版本迭代后的今天,它已经拥有了丰富第三方插件支持
      • 更方便的热更新
    • 劣势

      • 尽管是跨平台,但是不同平台Api的特性与显示并不一定一致
      • 调试’相对‘麻烦。
      • Android上的兼容性问题
    • 风险

      • 尽管Facebook有3款App(Groups、Ads Manager、F8)使用了React Native,随着React Native大规模应用,Appstore的政策是否有变不得而知
  • 环境搭建

  • 架构设计

    • Native
    • Bridge

      • 异步(asynchronous):不依赖于同步通信
      • 可序列化(serializable):保证一切 UI 操作都能序列化成 JSON 并转换回来
      • 批处理(batched):对 Native 调用进行排队,批量处理
    • JavaScript
  • 组件及布局

    • 核心组件

      • View
      • Text
      • ScrollView
      • Image
      • TextInput
    • 原生组件

      • 运行时RN为前端组件创建相应的android和iOS视图
      • RN就是对原生视图的封装
    • style

      • RN编写的应用的样式不是靠css来实现的
      • 而是依赖javascript来为你的应用来添加样式
      • 样式声明

        • 依赖导入

          • import React, { StyleSheet } from "react-native";
        • 调用React-Native的一个构造方法
        • 传入一个对象生成style
        • 和React的React.createCladd()语法是一样的,传入对象的key就相当于类名,每个类也是一个对象,可以配置各种样式参数
        • 注意

          • 对象key全部是驼峰写法
          • 长度不加单位
        • 示例

          • const styles = StyleSheet.create({
active: {  
    borderWidth: 2,  
    borderColor: ‘#ff00ff',  
},  

});

    - 样式使用

        - 外部引入

            - <View style={styles.base}></View>

        - 设置多个属性类

            - style={[styles.base,styles.backgroundColor]}

        - 行内样式

            -  style={{width:this.state.width}}  

- flexBox布局

    - 什么是FlexBox布局

        - 弹性盒模型(The Flexible Box Module),又叫Flexbox,意为“弹性布局”
        - 旨在通过弹性的方式来对齐和分布容器中内容的空间,使其能适应不同屏幕,为盒装模型提供最大的灵活性
        - 布局思想

            - 让容器有能力让其子项目能够改变其宽度、高度(甚至是顺序)
            - 以最佳方式填充可用空间

    - Flex布局基于flex-flow流

        - 水平的主轴(main axis)

            - 主轴的开始位置(与边框的交叉点)叫做main start
            - 结束位置叫做main end

        - 垂直的交叉轴(cross axis)

            - 交叉轴的开始位置叫做cross start
            - 结束位置叫做cross end

        - 项目默认沿主轴排列,单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size

    - 属性

        - 4个容器属性

            - flexDirection

                - 决定主轴的方向(即项目的排列方向)
                - row:主轴为水平方向,起点在左端。
                - row-reverse:主轴为水平方向,起点在右端
                - column(默认值):主轴为垂直方向,起点在上沿。
                - column-reverse:主轴为垂直方向,起点在下沿。

            - flexWrap

                - 默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap属性定义,如果一条轴线排不下,如何换行。
                - nowrap(默认值):不换行
                - wrap:换行,第一行在上方
                - wrap-reverse:换行,第一行在下方。(和wrap相反)

            - justifyContent

                - 定义了伸缩项目在主轴线的对齐方式
                - flex-start(默认值):伸缩项目向一行的起始位置靠齐。
                - flex-end:伸缩项目向一行的结束位置靠齐
                - center:伸缩项目向一行的中间位置靠齐。
                - space-between:两端对齐,项目之间的间隔都相等。
                - space-around:伸缩项目会平均地分布在行里,两端保留一半的空间

            - alignItems

                - 定义项目在交叉轴上如何对齐,可以把其想像成侧轴(垂直于主轴)的“对齐方式”。
                - flex-start:交叉轴的起点对齐。
                - flex-end:交叉轴的终点对齐 。
                - center:交叉轴的中点对齐。
                - baseline:项目的第一行文字的基线对齐。
                - stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

        - 2个项目属性

            - flex

                - 复合属性
                - 设置或检索伸缩盒对象的子元素如何分配空间
                - 其中第二个和第三个参数(flex-shrink、flex-basis)是可选参数
                - 默认值为“0 1 auto”

            - alignSelf

                - align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性
                - 默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch
  • UI渲染

    • 模块注入

      • RN模块注入

        • index->App
      • RN模块运行入口

        • AppRegistry

          • AppRegistry常用方法
          • registerConfig

            • static静态方法,用来注册配置信息
          • registerComponent

            • 注册组件
          • registerRunnable

            • 注册线程
          • runApplication

            • 进行运行应用
      • 入口组件注册

        • registerComponent
      • 加载jsbundle文件运行应用

        • runApplication
    • 页面启动UI渲染

      • APP启动
      • 读取模块Modules
      • 初始化根视图(RCTRootView)
      • 创建了一个实现 Objective-C 与 Javascript 交互的全局bridge(RCTBridge)
      • 读取Javascript代码(RCTBridgeloadSource)
      • 初始化Native模块化信息
      • 初始化 JavaScript 代码的执行器,即 RCTJSCExecutor 对象
      • 执行JS调用OC组件
      • 将flexbox布局转换成原生布局完成UI渲染
    • UI控件渲染流程

      • RCTRootView runApplication:bridge

        • 通知JS运行App
      • RCTBatchedBridge _processResponse:json error:error

        • 处理执行完JS代码(runApplication)返回的相应,包含需要添加多少子控件的信息。
      • RCTBatchedBridge batchDidComplete

        • RCTUIManager调用处理完成的方法,就会开始去加载rootView的子控件。
      • RCTUIManager createView:viewName:rootTag:props

        • 通过JS执行OC代码,让UI管理者创建子控件View
      • [RCTUIManager _layoutAndMount]

        • 布局RCTRootView和增加子控件
      • [RCTUIManager setChildren:reactTags:]

        • 给RCTRootView对应的RCTRootShadowView设置子控件
      • [RCTRootShadowView insertReactSubview:view atIndex:index++]

        • 遍历子控件数组,给RCTRootShadowView插入所有子控件
      • [RCTShadowView processUpdatedProperties:parentProperties:]

        • 处理保存在RCTShadowView中属性,就会去布局RCTShadowView对应UIView的所有子控件
      • [RCTView didUpdateReactSubviews]

        • 给原生View添加子控件
      • 完成UI渲染
    • 通信机制

      • OC生成一张模块配置表,包含所有模块和模块里的方法,根据特定的标识宏(RCT_EXPORT_MODULE()),将可以暴露的方法暴露给JS
      • 通信流程

        • ①js调用OC模块暴露出来的方法
        • ②把调用方法分解为ModuleName、MethodName、arguments,在丢给MessageQueue处理
        • ③把js的callback函数缓存在MessageQueue的一个成员变量里面,同时生成一个CallbackID来代表callback;在通过保存在MessageQueue的模块配置表把ModuleName、MethodName转成ModuleID、MethodID
        • ④把ModuleID、MethodID、CallbackID和其他参数传给OC(JavaScriptCore)
        • ⑤OC接到消息,通过模块配置表拿到对于的模块和方法
        • ⑥RCTModuleMethod对js传过来的参数进行处理
        • ⑦OC模块方法执行完,执行block回调
        • ⑧调用第6步中RCTModuleMethod生成的block
        • ⑨block带着CallbackID和block传过来的参数去掉用js里的MessageQueue方法invokeCallbackAndReturnFlushedQueue
        • ⑩MessageQueue通过CallbackID找到相应的js的callback方法
        • ⑪调用callback方法,并把OC带过来的参数一起传过去完成回调
    • 导航路由

      • StackNavigator

        • 用来跳转页面和传递参数
        • 参数

          • RouteConfigs
          • StackNavigatorConfig
        • navigation

          • navigate

            • 跳转到其他页面
            • routeName

              • 导航器中配置的路由名称
            • params

              • 传递参数到下一个页面
            • action
            • 示例

              • this.props.navigation.navigate('Find', {param: 'i am the param'});
          • state

            • 当前页面导航器的状态
            • params

              • 路由页面参数
            • key

              • 路由页面id
            • routeName

              • 路由页面名称
          • setParams

            • 更改路由的参数
            • 在组件挂载完成之后注册
            • componentDidMount() {
            • this.props.navigation.setParams({param:'i am the new param'})
          • goBack

            • 返回
            • goBack()

              • 回退到上一个页面
            • goBack(null)

              • 回退到任意一个页面
            • goBack('pathName')

              • 回退到指定页面
          • dispatch

            • 发送一个action
      • TabNavigator

        • 类似底部导航栏,用来在同一屏切换不同页面
      • DrawerNavigator

        • 侧滑菜单导航栏,用于轻松设置带抽屉的屏幕
    • 拆包

      • 目的

        • 解决jsbundle体积过大
        • 按需分步加载,提高加载效率
        • 提高热更新包diff/load效率
      • jsbundle组成

        • 头部(Polyfills)

          • 定义基本的JS环境
          • 主要是define,require等全局模块的定义
          • d()函数、__r()函数、__DEV 变量等
        • 中部(Module定义)

          • 模块定义,RN框架和业务的各个模块定义
          • 使用__d()函数定义所有用到的模块
          • 该函数为每个模块赋予了一个模块ID,模块之间的依赖关系都是通过这个ID进行关联的
        • 尾部(Require调用)

          • 引擎初始化和入口函数执行
          • 使用__r()函数引用根模块
      • 拆包方案

        • diff and patch

          • 将jsbundle通过diff,生成common和每个业务的patch包
          • 然后在APP运行时对common和patch合并成执行的jsbundle
        • 修改RN的bundle命令打包流程,使得直接生成common+business包
        • 修改RN的unbundle命令,生成common+business包
        • 使用metro拆包

          • 基础包和业务包打包

            • 抽离公共组件到base.js
            • base.js入口打包

              • 输出common.jsbundle
            • index.js入口打包

              • 输出business.jsbundle
          • 差异包打包

            • business.jsbundle基于common.jsbundle打差异包
            • 实现思路

              • business.jsbundle逐行扫描
              • 扫描内容如在common.jsbundle中没找到,用数组存放
              • 将数组转换为数据保存到差异包patch.jsbundle
    • 热更新

      • 前端业务代码提交入库
      • 基于热更新平台拆分当前项目
      • 资源打包上线CDN服务器
      • 前端资源添加版本号管理
      • 客户端拉取前端RN资源动态更新

Flutter

  • Flutter发展历程

    • 2014.10 - Flutter的前身Sky在GitHub上开源
    • 2015.10 - 经过一年的开源,Sky正式改名为Flutter
    • 2017.5 - Google I/O正式向外界公布了Flutter,这个时候Flutter才正式进去大家的视野
    • 2018.6 - 距5月Google I/O 1个月的时间,Flutter1.0预览版
    • 2018.12 - Flutter1.0发布,它的发布将大家对Flutter的学习和研究推到了一个新的起点
    • 2019.2 - Flutter1.2发布主要增加对web的支持
  • 简介

    • Flutter 是 Google推出并开源的移动应用开发框架
    • 主打跨平台、高保真、高性能
    • 开发者可以通过 Dart语言开发 App,一套代码同时运行在 iOS 和 Android平台
    • Flutter提供了丰富的组件、接口,开发者可以很快地为 Flutter添加 native扩展
    • 同时 Flutter还使用 Native引擎渲染视图,这无疑能为用户提供良好的体验
  • 框架

    • Framework

      • 纯 Dart实现的 SDK,类似于 React在 JavaScript中的作用
      • 它实现了一套基础库, 用于处理动画、绘图和手势
      • 基于绘图封装了一套 UI组件库
      • 根据 Material 和Cupertino两种视觉风格区分开来
    • Engine

      • 纯 C++实现的 SDK
      • 包括

        • Skia引擎
        • Dart运行时
        • 文字排版引擎等
      • 它是 Dart的一个运行时,它可以以 JIT 或者 AOT的模式运行 Dart代码
      • 这个运行时还控制着 VSync信号的传递、GPU数据的填充等,并且还负责把客户端的事件传递到运行时中的代码
    • Embedder

      • Embedder是操作系统适配层
      • 实现了

        • 渲染Surface设置
        • 线程设置
        • 平台插件等平台相关特性的适配
  • 组件渲染

    • 图像显示的基本原理

      • 显示器的CRT电子枪从上到下一行行扫描,扫描一行完成之后,显示器上就显示一帧画面,随后电子枪回到初始位置继续下一次扫描
      • 水平扫描时,显示器会发出一个水平同步信号(HSync)
      • 而当一帧画面绘制完成之后,电子枪恢复原位,准备下一次扫描之前,显示器会发出一个垂直同步信号(Vsync)
      • 显示器以固定的频率刷新,这个刷新率就是Vsync信号产生的频率
      • 图像的显示需要CPU、GPU和显示器一起配合完成

        • CPU负责图像数据计算
        • GPU负责图像数据渲染
        • 显示器则负责最终图像显示
      • CPU把计算好的需要显示的内容交给GPU
      • 由GPU完成渲染后放入帧缓冲区
      • 随后视频控制器根据垂直同步信号(Vsync)以每秒60次的速度
      • 从帧缓冲区读取帧数据交由显示器完成图像显示
    • Flutter绘制原理

      • 渲染流程

        • Dart
        • |
        • GPU
        • |
        • |
        • Compositor
        • Skia
        • GPU
      • 渲染流程1

        • GPU的VSync信号同步给到UI线程
        • UI线程使用Dart来构建抽象的视图结构(这里是Framework层的工作)
        • 绘制好的抽象视图数据结构在GPU线程中进行图层合成(在Flutter Engine层的工作)
        • 然后提供给Skia引擎渲染为GPU数据,最后通过OpenGL或者 Vulkan提供给 GPU
      • UI界面绘图流程

        • user Input

          • 用户输入是驱动视图更新的信号 如:滑动屏幕
        • Animation

          • 触发动画进度更新
        • Build

          • 框架开始build抽象视图数据
        • Layout

          • 视图布局
        • Paint

          • 视图绘制
        • Composite

          • 视图合成
        • Restorize

          • 最后进行光栅化处理把数据生成一个个真正的像素填充数据
  • Dart语言(基础)

    • 简介

      • Dart 语言在2011年10月由 Google 发布
      • 是一种 易于学习、 易于扩展、并且可以部署到 任何地方 的 应用 编程 语言
      • 设计的初衷是用来替换javascript的,所以刚开始Dart也就是用来作

为浏览器脚本运行在浏览器中的,但是一直没有被广大开发者重视。

    - Google并没有放弃Dart,又Dart编写孵化了一个移动开发框架Sky,
    - 之后又被命名为Flutter,进入了移动跨平台开发的领域

- 应用方向

    - 移动端开发

        - 核心是Flutter框架,它使用
        - Dart + C++ + Skia 开发,同
        - 一份代码编写运行在 iOS 和
        - Android 上的应用

    - 浏览器端

        - 我们用Dart来写Web后,编译器会自动
        - 将Dart文件编译为JavaScript文件进行
        - 运行,只不过我们写的语法规范是Dart语法

    - 服务器端

        - DartVM :就是写服务端的应用。比如写个
        - http 的服务,对应用提供 api ,都是及其简单的事情。

- 环境配置

    - 手动安装

        - 下载地址:http://www.gekorm.com/dart-windows/

    - 配置环境变量

        - 将dart-sdk的bin路径添加到path环境变量中

    - 在vscode中安装Code Runner插件,来调试我们的dart代码
    - 安装stagehand

        - pub global activate stagehand

    - 创建dart项目

        - stagehand dart-demo

    - 获取依赖包

        - pub get

- 常用内置类型

    - String

        - Dart 字符串是 UTF-16 编码的字符序列,可以使用单引号或者双引号来创建字符串
        - 可以使用三个单引号或者双引号创建多行字符串对象
        - 可以使用 r 前缀创建”原始raw”字符串
        - 可以在字符串中使用表达式: ${expression},如果表达式是一个标识符,可以省略 {},如果表达式的结果为一个对象,则 Dart 会调用对象的 toString() 函数来获取一个字符串

    - Numbers

        - int : 整数值
        - double : 64-bit双精度浮点数
        - int和double是num的子类

    - Booleans

        - bool对象未初始化的默认值是null

    - Lists

        - Dart中的数组称为List

    - Maps

        - map是一个关联键和值的对象
        - 键和值都可以是任何类型的对象
        - 每个键只出现一次

- 变量声明

    - var

        - 类似于JavaScript中的var
        - 它可以接收任何类型的变量
        - 但最大的不同是Dart中var变量一旦赋值,类型便会确定,则不能再改变其类型
        - Dart本身是一个强类型语言
        - 任何变量都是有确定类型的

    - dynamic

        - dynamic与var一样都是关键词
        - 声明的变量可以赋值任意对象
        - dynamic与Object相同之处在于,他们声明的变量可以在后期改变赋值类型
        - dynamic声明的对象编译器会提供所有可能的组合

    - Object

        - Object 是Dart所有对象的根基类
        - 也就是说所有类型都是Object的子类
        - 包括Function和Null
        - 所以任何类型的数据都可以赋值给Object声明的对象
        - Object声明的对象只能使用Object的属性与方法, 否则编译器会报错

    - final

        - 一个 final 变量只能被设置一次
        - final变量在第一次使用时被初始化
        - 被final或者const修饰的变量,变量类型可以省略

    - const

        - const 变量是一个编译时常量
        - 不能更改

- 函数

    - 函数声明
    - 对于只包含一个表达式的函数,可以使用简写语法
    - 函数作为变量
    - 函数作为参数传递
    - 可选的位置参数
    - 可选的命名参数
    - 参考链接:https://book.flutterchina.club/chapter1/dart.html

- 类class

    - 使用类成员

        - 对象的成员包括函数和数据(分别是方法和实例变量)
        - 你调用一个方法时,你在一个对象上调用它:这个方法可以访问那个对象的函数和数据
        - 使用点(.)引用实例变量或方法
        - 使用?.而不是.为了避免最左边的操作对象为空时出现异常

    - 使用构造函数

        - 可以使用一个创建函数来创建对象
        - 构造函数的名字可以是ClassName或者ClassName.indentifier

    - 构造函数

        - 通过创建一个与其类同名的函数来声明一个构造函数
        - 最常见的构造函数形式——生成构造函数——创建了一个类的新实例
        - this关键词引用到当前的对象

    - 抽象类

        - Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口
        - 抽象类通过abstract 关键字来定义
        - Dart中的抽象方法不能用abstract声明,Dart中没有方法体的方法我们称为抽象方法
        - 如果子类继承抽象类必须得实现里面的抽象方法
        - 如果把抽象类当做接口实现的话必须得实现抽象类里面定义的所有属性和方法
        - 抽象类不能被实例化,只有继承它的子类可以
        - 接口:使用implements关键字,一般使用抽象类定义接口。

- 包管理

    - Dart的软件包管理器是pub。
    - 托管软件包的存储库可以在https://pub.dartlang.org/ 找到
    - 

        - 每个Dart应用程序都有一个pubspec.yaml文件,包含了项目依赖包配置 类似package.json

    - 操作命令

        - pub get:获取应用程序依赖的所有包
        - pub upgrade:将所有依赖项升级到较新版本
        - pub build:构建应用

- 库

    - 自定义库

        - import 'lib/mylib1.dart' as lib1;

    - 系统内置库

        - import 'dart:math';
        - import 'dart:io';
        - import 'dart:convert';

    - pub包管理系统中的库

        - import 'package:dio/dio.dart';
  • Widget与Element

    • 什么是Widget

      • Flutter Widget采用现代响应式框架构建,中心思想是用widget构建你的UI
      • Widget描述了他们的视图在给定其当前配置和状态时应该看起来像什么
      • 当Widget的状态发生变化时, Widget会重新构建UI,Flutter会对比前后变化的不同, 以确定底层渲染树从一个状态转换到下一个状态所需的最小更改
      • Widget的功能是“描述一个UI元素的配置数据”, Widget其实并不是表示最终绘制在设备屏幕上的显示元素,而它只是描述显示元素的一个配置数据
    • Element

      • Flutter中真正代表屏幕上显示元素的类是Element,也就是说Widget只是描述Element的配置数据
    • 基础Widget

      • StatelessWidget

        • StatelessElement 间接继承自Element类,与StatelessWidget相对应
        • StatelessWidget用于不需要维护状态的场景
        • 它通常在build方法中通过嵌套其它Widget来构建UI
        • 在构建过程中会递归的构建其嵌套的Widget
      • StatefulWidget

        • 和StatelessWidget一样,StatefulWidget也是继承自Widget类,并重写了createElement()方法
        • 不同的是返回的Element 对象并不相同
        • StatefulWidget类中添加了一个新的接口createState()
        • createState() 用于创建和Stateful widget相关的状态,它在Stateful widget的生命周期中可能会被多次调用
      • State

        • 一个StatefulWidget类会对应一个State类,State表示与其对应的StatefulWidget要维护的状态
        • State中的保存的状态信息可以

          • 在widget 构建时可以被同步读取
          • 在widget生命周期中可以被改变,当State被改变时,可以手动调用其setState()方法通知Flutter framework状态发生改变,Flutter framework在收到消息后,会重新调用其build方法重新构建widget树,从而达到更新UI的目的
        • 常用属性

          • widget

            • 它表示与该State实例关联的widget实例
            • 由Flutter framework动态设置
          • context

            • StatefulWidget对应的BuildContext
            • 作用同StatelessWidget的BuildContext
        • 生命周期

          • StatefulWidget launched
          • initState

            • 当Widget第一次插入到Widget树时会被调用
            • 对于每一个State对象,Flutter framework只会调用一次该回调
            • 通常在该回调中做一些一次性的操作,如状态初始化、订阅子树的事件通知等
          • didChangeDependencies

            • 当State对象的依赖发生变化时会被调用
          • build

            • 它主要是用于构建Widget子树的
            • 会在如下场景被调用

              • 在调用initState()之后
              • 在调用didUpdateWidget()之后
              • 在调用setState()之后
              • 在调用didChangeDependencies()之后
              • 在State对象从树中一个位置移除后(会调用deactivate)又重新插入到树的其它位置之后
          • reassemble

            • 此回调是专门为了开发调试而提供的
            • 在热重载(hot reload)时会被调用
            • 此回调在Release模式下永远不会被调用
          • didUpdateWidget

            • 在widget重新构建时
            • Flutter framework会调用Widget.canUpdate来检测Widget树中同一位置的新旧节点,然后决定是否需要更新
            • 如果Widget.canUpdate返回true则会调用此回调
          • deactivate

            • 当State对象从树中被移除时,会调用此回调
          • dispose

            • 当State对象从树中被永久移除时调用
            • 通常在此回调中释放资源
          • StatefulWidget destoryed
      • 基础组件

        • Text

          • Text用于显示简单样式文本,它包含一些控制文本显示样式的一些属性
        • Image

          • Flutter中,我们可以通过Image组件来加载并显示图片,Image的数据源可以是asset、文件、内存以及网络
        • Container

          • Container是Flutter里很常用的容器组件, Container可以创建矩形视觉元素
      • 布局类组件

        • 线性布局

          • Row
          • Column
        • 弹性布局

          • Flex
        • 流式布局

          • Wrap
          • Flow
        • 层叠布局

          • Stack
          • Positioned
        • 对齐与相对定位

          • Align

Weex

小程序

快应用

ionic

  • 简介

    • ionic是一个用来开发混合手机应用的,开源的,免费的代码库
    • 可以优化html、css和js的性能,构建高效的应用程序
    • 可以用于构建Sass和AngularJS的优化
  • 特点

    • 具有原生APP的卓越运行性能
    • 可维护性高
    • 漂亮的Ui设计
    • 轻量级框架
    • 具有强大的命令行工具
    • 与AngularJS完美结合
  • 框架结构

    • CSS框架

      • 提供原生App质感的CSS样式模拟
      • ionic这部分的实现使用了ionicons图标样式库
    • JavaScript框架

      • 提供移动Web应用开发框架
      • ionic基于AngularJS基础框架开发
      • 遵循AngularJS的框架约束
      • ionic使用AngularJS UI Router实现前端路由
    • 命令行/CLI

      • 命令行工具集用来简化应用的开发、构造和仿真运行
      • ionic命令行工具使用了 Cordova,依赖于平台SDK(Android & iOS)实现将移动web项目打包成原生app
  • 基本布局

  • 交互通信

Cordova

  • 简介

    • Cordova提供了一组设备相关的API
    • 通过这组API,移动应用能够以JavaScript访问原生的设备功能,如摄像头、麦克风等
    • Cordova还提供了一组统一的JavaScript类库,以及为这些类库所用的设备相关的原生后台代码
    • Cordova支持如下移动操作系统:iOS, Android,ubuntu phone os, Blackberry, Windows Phone, Palm WebOS, Bada 和 Symbian
  • 架构

    • Web APP端

      • config.xml

        • CLI初始化项目在主目录下生成
        • 包含了整个app的一些基本信息

          • appName
          • app入口文件
          • 白名单
          • webview初始化的一些配置
          • plugin信息
          • 图标资源信息
      • Resources
      • HTML、JS、CSS
      • cordova.js核心代码

        • exec

          • 这是cordova 中js端的核心执行代码,所有的plugin的执行入口
          • successCallback -- 成功的回调
          • failCallback -- 失败的回调
          • service -- 所调用native plugin的类
          • action -- 所调用native plugin的类下的具体method
          • actionArgs -- 具体参数
        • pokeNative

          • JS通知Native调用native方法
          • 通过Webview相关协议拦截前端URL
          • JS端通过iframe发送request的相关请求
        • nativeCallback

          • native处理完前端请求后触发回调的统一入口
          • 以同步的方式来触发native -> js 的callBack
        • callbackFromNative

          • JS执行回调的地方
          • 根据cordova.callBacks的map以及回调的callBackId 还有状态(success 或者 fail)来执行相应的回调函数
          • 之后根据keepCallback来决定是否将该回调从callBacks的map中移除
    • Native端

      • cordova webview 引擎具体实现

        • CDVViewController

          • init --- 初始化程序
          • loadSettings --- 解析config.xml 将pluginsMap startplugin settings startPage等变量初始化到容器controller中,初始化plugin字典
          • viewDidLoad --- 先loadSettings,之后创建特殊存储空,根据CDVUIWebViewEngine初始化Webview,然后获取appURL加载index.html
        • CDVUIWebViewEngine

          • initWithFrame --- 创建webview
          • pluginInitialize --- 初始化webView中的一系列设置,创建delegate(CDVUIWebViewDelegate)
          • getConmmandInstance --- 获取command的实例
      • 容器初始化以及plugin初始化

        • Acceleromter
        • Geolocation
        • Carmera
        • Media
        • Device
        • Network
        • Contacts
        • Storage
  • JS&Native通信

    • 通信原理

      • 保存Cordova_plugin.js的 插件文件名字和地址
      • 插件的API呼出时,通过调用Cordova的exec模块将API的参数保存在CommandQueue的队列中。 CALLBACK则保存在JS侧的callbacks map里面
      • 添加一个空的iframe,iframe的src则指向gap://ready
      • 3的iframe的src设置以后,NATIVE侧UIWebviewDelegate#shouldStartLoadWithRequest则被呼出来
      • Webview的Delegatet判断gap://ready的情况下,则执行commandDelegate的处理
      • commandDelegate则从JS侧取出API的参数,内部实现则是通过 UIWebview#stringByEvaluatingJavaScriptFromString的返回值 取得CommandQueue里面的参数转换成JSON数据
      • 根据6的插件,执行NATIVE定义的插件实例
      • 插件中,有CALLBACK的情况下,成功失败的结果通过UIWebview#stringByEvaluatingJavaScriptFromString执行JS,JS端则根据传过来的CALLBACKID,从callbacks map取出回调函数并执行
    • 通信方式

      • iframe的方法(默认)
      • xmlHttpRequest的方法(iOS5.x版本因为 -webkit-scroll的IFRAME有BUG,则推荐使用)
  • 插件导入流程

    • Native

      • APP启动,MainViewController初始化之时,queue和command的DELEGATE初期化
      • config.xml文件解析,插件名设置到数组,插件文件和插件名设置到pluginMap,属性设置到setting
      • 在Webview类里面,加载index.html,index.html里面加载cordova.js、开始初期化
    • JS

      • 加载cordova.js时、内部的事件设置模块,NATIVE交互模块,初期化模块,插件加载
      • 插件模块是cordova_plugins.js文件定义的插件文件地址,文件名保存的MAP
      • deviceready事件发布后,插件的API可以使用了
      • 插件API执行后,模块MAP将插件文件加载,执行exec函数
      • 在index.html里面添加一个空的iframe、指定data-original=gap://ready,通知到Nativie

PWA

WebAssembly

Electron

VasSonic

QT

性能优化和监控

性能优化(基础)

  • 内容层面

    • DNS解析优化

      • DNS缓存
      • 减少DNS查找
      • keep-alive
      • 适当的主机域名
    • 避免重定向
    • 切分到多个域名
    • 杜绝404
  • 网络传输阶段

    • 减少传输过程中的实体大小

      • 缓存
      • cookie优化
      • 文件压缩
    • 减少请求的次数

      • 文件适当的合并
      • 雪碧图
    • 异步加载
    • 预加载、延后加载、按需加载
  • 渲染阶段

    • js放底部,css放顶部
    • 减少重绘和回流
    • 合理使用Viewport 等meta头部
    • 减少dom节点
    • BigPipe
  • 脚本执行阶段

    • 缓存节点,尽量减少节点的查找
    • 减少节点的操作(innerHTML)
    • 避免无谓的循环,break、continue、return的适当使用
    • 事件委托

大前端时代监控

  • 大前端时代前端监控的新变化

    • 大前端时代有哪些变化

      • 首先是Gmail的横空出世,开启了SPA的时代
      • Backbone/Angular等框架带来了MVVM模式的同时,也把JS从脚本语言提升到了工程语言
      • React Native/Weex把移动端开发从Hybrid模式进化到了跨端开发模式
      • Node.js问世为前端带来了更多的可能性
    • 前端变化给监控带来了什么样的改变

      • 传统监控模式能否适用于新的技术?比如PV统计
      • SPA模式下首屏如何计算?
      • 跨端开发给监控带来什么什么挑战?
      • 前端监控的上报模式在Node.js端是否合理?
    • SPA模式下的PV统计问题

      • 技术升级、体验升级、PV下降?
      • 原因

        • 页内路由代替了新的页面
      • 解决办法

        • hash路由:监听hash change变化上报PV
        • 非哈希路由:轻量hack pushState和replaceState
    • 首屏统计

      • 第一阶段:自定义打点时期

        • 页头和首屏dom分别通过 new Date()打点
        • 计算差值作为首屏时间
        • 再加上setTimeout(new Date(), 0)标记首屏可交互时间
      • 第二阶段:W3C标准时期

        • W3C性能小组引入了 Navigation Timing API 帮我们自动,精准的实现了性能测试的打点问题
        • Navigation Timing API

          • 卸载上一个页面
          • 重定向
          • 应用缓存
          • DNS域名解析
          • TCP链接
          • 请求页面
          • 响应
          • 页面处理
          • 触发load事件
      • 第三阶段:SPA盛行导致W3C标准失去原来的意义
      • 现阶段:用户感官指标FMP

        • first meaning paint
        • 主要内容可见时间
  • 前端监控的最佳实践

    • 主动监控

      • 配置告警规则
      • 通过错误聚类模块,精准定位问题
      • 增加性能样本分布统计
      • 再手起刀落,修复bug
    • 慢会话追踪
    • 搜索报错明细
    • 出错行为还原
  • 58北斗监控实现
查看原文

似水流年 赞了文章 · 1月27日

前端知识体系-全系列(图谱+大纲)

前端知识体系(图谱)

前端知识体系大纲

前端工程化体系

前端工程化体系

node

node

主流技术栈

大纲

主流技术栈

React

Vue

vue

Angular

JavaScript

TypeScript

跨平台技术

大纲

跨端技术发展的三个阶段

Hybrid

ReactNative

Flutter

weex

小程序

快应用

ionic

Cordova

性能优化和监控

前端知识体系(大纲)

前端工程化体系

基础设施

  • 规范化

    • 前端标准(基础)

      • W3C
      • SPA
      • DOM
      • BOM
      • XHTML
      • XML
      • JSON
      • JSONP
      • HTTP
      • HTML5
      • CSS3
    • 编码规范

eslint

    - tslint
    - stylelint

- 命名规范

    - Pascal 大小写

        - 组成标识符的每个单词的首字母大写,其余字母小写的书写约定。对于缩写的双字母单词,要求全部大写

    - Camel 大小写

        - 标识符的首字母小写,每个后面连接的单词的首字母大写,其余字母小写的书写约定。对于缩写的双字母单词,要求它们出现在标识符首部时全部小写,否则全部大写

    - 匈牙利命名法

        - 变量名 = 属性 + 类型 + 对象描述

    - 常量的命名

        - 常量的名字应该都使用大写字母,并且指出该常量完整含义

- 目录规范
- commit提交规范

    - commitiizen
    - cz-customizable
    - commitlint

- 文档规范
- 接口规范
- 流程规范

    - gitflow
  • 基础构建优化

    • 压缩
    • 校验
    • 资源合并
    • 打包构建工具

      • Browserify
      • webpack
      • gulp
      • rollup
      • grunt
      • ...
    • 包管理工具

      • Bower
      • npm
      • yarn
  • 模块化

    • JS模块规范

      • 模块规范

        • AMD

          • RequireJS
        • CMD

          • seaJS
        • CommonJS

          • node模块系统
        • ES6+ Module
      • 模块加载机制原理
    • CSS模块化

      • css预处理器

        • Less
        • Sass

          • node-sass
          • dart-sass
        • Stylus
      • css Module
      • css in JS
    • 模块设计
  • 组件化

    • 组件化标准

      • Web Component
    • 组件设计

      • UI和功能拆分(独立性/自由组合)
    • 组件设计

      • 目录结构(就近维护)
  • 资源管理

    • 按需加载
    • 延迟加载
    • 缓存复用
    • CDN部署
    • 文件指纹
    • 请求合并
    • 异步同步加载

工具链

  • 脚手架

    • 脚手架工具原理
    • 命令行工作流
    • 项目模板设计
  • 搭建本地开发环境
  • 搭建本地mock环境
  • 自动化构建

    • webpack配置使用
    • 常用插件
    • webpack构建性能优化
    • 代码转换:ES与Babel
    • CSS预编译与postcss
    • 模块合并:webpack模块化构建
    • webpack增量更新构建
    • 资源定位
    • 自动刷新
  • 引入单元测试
  • 部署发布

    • Jenkins
    • 部署流程
    • 静态资源部署策略
  • 监控

    • 行为监控
    • 异常监控

      • 采集
      • 用户信息
      • 行为信息
      • 异常信息
      • 环境信息
    • 性能监控

      • 运行时监控

        • 文件级
        • 模块级
        • 函数级
        • 算法级
      • 网络请求速率
      • 系统性能

工作流

  • 本地工作流

    • 本地环境
    • 代码分离
    • 测试沙箱
  • 云平台工作流

    • 角色划分

      • 本地开发环境
      • gitlab
      • 云平台
    • 自动化构建与部署

      • gitflow与版本管理
      • webhook与自动构建
    • 持续集成与持续交付

      • 自动构建与测试
      • 生产环境的迭代版本、版本回流
      • Docker容器技术
    • IDE云平台开发

      • IDE工具

调试工具

  • Chrome

    • Element 标签页

      • 用于查看和编辑当前页面中的 HTML 和 CSS 元素
    • Network 标签页

      • 用于查看 HTTP 请求的详细信息,如请求头、响应头及返回内容等
    • Source 标签页

      • 用于查看和调试当前页面所加载的脚本的源文件
    • TimeLine 标签页

      • 用于查看脚本的执行时间、页面元素渲染时间等信息
    • Profiles 标签页

      • 用于查看 CPU 执行时间与内存占用等信息
    • Resource 标签页

      • 用于查看当前页面所请求的资源文件,如 HTML,CSS 样式文件等
    • Audits 标签页

      • 分析页面加载的过程,进而提供减少页面加载时间、提升响应速度的方案,用于优化前端页面,加速网页加载速度等
    • Console 标签页

      • 用于显示脚本中所输出的调试信息,或运行测试脚本等
  • firefox插件Firebug

    • Chrome浏览器出现之前常用的调试工具
  • IE的开发者工具
  • IETest

    • IE浏览器版本切换工具

      • 在开发Web项目的时候,经常会碰到需要在不同的IE版本中检查完成的网页是否能正常展现,这时就需要IETest帮我们模拟网页在IE5.5、IE6、IE7、IE8、IE9以及IE10等浏览器中的兼容性,让我们看一下辛苦做好的CSS样式或网站版面是否可以在各个主要浏览器正常显示
  • Emmet

    • HTML/CSS开发中的神器

https://www.emmet.io/

  • JSON 格式化和校验工具
  • Postman

    • 用于调试请求和响应
  • 移动端抓包调试

    • fiddler
    • Charles

node

基础知识

  • web服务

    • express

      • 中间件、生态完善
    • koa

      • 脱胎于express,提升异步编程体验
    • hapi

      • 遵循配置大于编码原则,沃尔玛前端团队出品
    • sails

      • 模仿ruby on rails框架
    • tsw

      • qq空间出品,集成了很多腾讯内部组件
    • Meteor

      • 快速搭建框架、10倍的减轻工作量
    • Feathers

      • 创建一个面向服务的架构,是一个很好地适合创建Node.js微服务
    • Keystone

      • Keystone是得到一个管理客户端并运行的最好的解决方案之一,以便管理来自MongoDB数据库的内容。管理界面自动从模型生成,具有所有CRUD操作和精细的过滤器。
    • Loopback

      • 内置许多函数,包括使用令牌和到任何类型的数据库连接器的认证
    • egg

      • 为企业级框架和应用而生,是阿里开源的企业级 Node.js 框架
    • Daruk

      • Daruk 是一款基于 Koa2,使用 Typescript 开发的轻量级 web 框架
    • uma

      • 58同城node框架
  • 模板引擎

    • handlebars
    • ejs
    • jade
  • 前端打包

    • webpak
    • fis
  • 任务管理

    • gulp
  • 单元测试

    • karma
    • mocha
    • jasmine
  • 包管理

    • npm
    • cnpm
    • yarn
  • 守护进程

    • pm2
    • forever

三大特点

  • 单线程

    Node.js不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,通过非阻塞I/O、事件驱动机制,让Node.js程序宏观上也是并行的

  • 非阻塞I/O

    由于Node.js中采用了非阻塞型I/O机制,因此在执行了访问数据库的代码之后,将立即转而执行其后面的代码,把数据库返回结果的处理代码放在回调函数中,从而提高了程序的执行效率。
    当某个I/O执行完毕时,将以事件的形式通知执行I/O操作的线程,线程执行这个事件的回调函数。为了处理异步I/O,线程必须有事件循环,不断的检查有没有未处理的事件,依次予以处理。
    阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。而非阻塞模式下,一个线程永远在执行计算操作,这个线程的CPU核心利用率永远是100%。所以,这是一种特别有哲理的解决方案:与其人多,但是好多人闲着;还不如一个人玩命,往死里干活儿。

  • 事件驱动event-driven

    在Node中,在一个时刻,只能执行一个事件回调函数,但是在执行一个事件回调函数的中途,可以转而处理其他事件(比如,又有新用户连接了),然后返回继续执行原事件的回调函数,这种处理机制,称为“事件环”机制。
    Node.js底层是C++(V8也是C++写的)。底层代码中,近半数都用于事件队列、回调函数队列的构建

技术架构

  • 底层架构

    • v8 engine

      • 虚拟机的功能,执行js代码
      • 提供C++函数接口,为nodejs提供v8初始化,创建context,scope等
    • libuv

      • 它是基于事件驱动的异步IO模型库,我们的js代码发出请求,最终由libuv完成,而我们所设置的回调函数则是在libuv触发
    • builtin modules

      • 它是由C++代码写成各类模块,包含了crypto,zlib, file stream etc 基础功能
      • v8提供了函数接口,libuv提供异步IO模型库,以及一些nodejs函数,为builtin modules提供服务
    • native modules

      • 它是由js写成,提供我们应用程序调用的库,同时这些模块又依赖builtin modules来获取相应的服务支持
  • node函数调用机制

通信协议

  • 网络协议

    • http/https

      • 推荐request.js
    • tcp

      • net模块
    • udp

      • dgram模块
  • 数据序列化协议

    • json

      • 文本协议,常用于http通信
    • protocol buffer

      • 二进制协议,常用于socket通信
      • js原生不支持,可以使用protobuf.js来解析
  • 接口协议

    • restful apis

      • 语义化,几乎所有web框架都支持
    • Graphql

      • 解决restful接口过于原子化的缺陷,facebook出品
      • 需要在前端和后台接口之前搭建一层graphql server做数据处理
    • RPC

      • 后台服务间通信
    • 网络序/本地序

      • Buffer模块api原生支持两种序列的转换

存储

  • 数据库

    • MySql
    • MongoDB
    • Oracle
    • MSSQL

      • 微软的SQLServer数据库服务器
    • PostreSQL

      • 功能强大的开源对象关系数据库系统
    • MariaSQL
  • 缓存

    • redis
    • memcache
    • nosql
    • mongodb
    • orm
    • sequelize(mysql)
    • bookshelf(mysql)
    • zookeeper
  • 消息队列

    • RabbitMQ

      • 实现了高级消息队列协议(AMQP)的开源消息代理软件
    • Kafka

      • 消息队列 Kafka 版是阿里云基于 Apache Kafka 构建的高吞吐量、高可扩展性的分布式消息队列服务
    • zmq

      • 是一个消息处理队列库,可在多个线程、内核和主机盒之间弹性伸缩
    • server render
    • websocket

      • 是一种在单个TCP连接上进行全双工通信的协议

设计模式

  • 单例模式

    • 保证一个类只有一个实例
  • 适配器模式

    • 适配器模式可以使原本由于接口不兼容而不能一起工作的那些类可以一起工作
  • 装饰模式

    • 可以通过继承的方式,为一个基类对象扩展功能
  • 观察者模式

    • 就是为某一对象添加一监听事件

主流技术栈

React

  • 简介

    • React 是一个 MVC 框架
    • React 主要是用来构建 UI
    • React 是起源于Facebook的内部项目,用于构建 Instagram 网站,在 2013.05 开源
  • 特点

    • 声明式

      • 使用 React 编写UI界面和写HTML几乎一样
    • 高效

      • React通过对DOM的模拟,最大限度地减少与DOM的交互
    • 灵活

      • React可以与已知的库或框架很好地配合
  • 生命周期

    • constructor

      • 构造函数
    • componentWillMount

      • 在渲染前调用,在客户端也在服务端(高版本已废弃)
    • componentDidMount

      • 在第一次渲染后调用,只在客户端
    • componentWillReceiveProps

      • 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用
    • shouldComponentUpdate

      • 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用
    • componentWillUpdate

      • 在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用
    • componentDidUpdate

      • 在组件完成更新后立即调用。在初始化时不会被调用
    • componentWillUnmount

      • 在组件从 DOM 中移除的时候立刻被调用
  • React思想

    • 组件编写顺序

      • 1.组件划分原则

        • 解耦
        • 复用
        • 适度
      • 2.编写静态组件
      • 3.分析State

        • 哪些是State

            1. 对组件进行两个灵魂质问
            1. 对State集合进行检查和去重
        • State保存的位置

          • 单一状态
          • 状态上移
        1. 添加交互行为
    • mock方式

      • server
      • public
  • Redux思想

    • 使用redux是在解决什么问题

      • 问题原因:数据状态包括API数据,本地数据和UI状态等随着项目扩大变的管理复杂
      • 解决问题的目的:防止管理状态失控
      • 解决问题的手段:使用redux将视图层和状态管理层从逻辑上解耦
    • State

      • 集中管理,全局唯一
      • 不可变性
      • 定义原则与React State定义原则相同
    • Action

      • 普通Acion

        • ActionCreators
        • ActionTypes
      • 异步Action

        • 异步action的创建

          • 请求开始action
          • 请求成功action
          • 请求失败action
        • 拓展reducer

          • 请求数据相关的state数据结构的变化
          • 请求数据相关的reducer内容扩充
        • 集成redux-thunk

          • 问题原因:净化react组件的代码,想将数据请求放在action当中做
          • 解决问题的目的:实现异步Action
          • 解决问题的手段:使用redux-thunk实现异步Action,抽离react中的数据请求代码
    • Reducer

      • combineReducers
    • Store
    • redux-devtools

      • 浏览器插件
      • 项目依赖库
  • React-Redux思想

    • 使用react-redux是在解决什么问题

      • 问题原因:reactUI层和redux状态层的相关代码冗杂在react组件中
      • 解决问题的目的:既能链接reactUI层和redux状态层,又不让两者代码糅合
      • 解决问题的手段:使用react-redux将视图层和状态管理层从代码上解耦
    • 功能

      • Provider组件
      • connect高阶HOC组件
      • map api
    • 容器性组件和展示性组件

      • 关注点
      • 对redux感知
      • 读数据
      • 写数据
      • 如何创建
    • 流程图总结

  • React-Router

    • 服务端路由和客户端路由的区别

      • 服务端路由:访问http://a就返回a.html,访问http://b就返回b.html,是服务器根据不同的路由返回不同的页面
      • 客户端路由:无论访问什么路径,返回的页面信息都是相同的,是通过js通过判断路径的不同来渲染不同的组件而已,所以叫做客户端路由
    • BrowserRouter和HashRouter区别

      • 之前说react-router-dom是将react-route和web-api做绑定,这些web-api具体指的就是HTML5 history API,利用这些pushState、replaceState等方法实现在客户端实现路由的操作
      • 哈希路由是使用url的hash部分作为路由信息,是通过使用页面不同的哈希和不同的组件之间做映射来完成的,哈希的出现主要为了兼容老版本浏览器,因为老版本的浏览器不支持history的API,所以通过哈希的变化来实现路由的变化。但是这样的情况在现在已经很少了,而且哈希的本身含义就是页面的定位,其逻辑也不符合路由的需求
    • 路由渲染组件的三种方式

      • component
      • render
      • children
    • 全新思维

      • 一切皆组件
      • 动态路由离散式声明法
  • 架构设计基础

    • React+Redux项目结构组织方式

      • type(按照类型)

        • 定义

          • 类型指的是该文件在项目当中充当的角色类型
        • 特点

          • 优点

            • 目录结构清晰却明确,功能文件比较紧凑
          • 缺点

            • 新添功能需要在不同的文件中做修改
            • 不利于多人合作下的代码表写和提交合并
      • function(按照功能模块)

        • 定义

          • 功能指的是按照功能或者页面将相关的文件写在同一个文件夹
        • 特点

          • 优点

            • 有利于新功能的开发和拓展
          • 缺点

            • 容易造成store当中存在大量重复性的数据
            • 同一状态在不同的模块中会有不一致的风险
      • Ducks(鸭子类型)

        • 定义

          • 将应用的状态作为模块的划分依据
        • 特点

          • 目录结构清晰紧凑,添加新功能只需添加新模块文件即可
          • 组件需要任何状态只需要引入对应的state模块文件即可
    • 三种设计Redux-State的依据

      • API为依据

        • 定义

          • 以后端API返回数据结构作为State的数据结构
        • 缺点

          • 大量数组类型的结构会造成重复数据的存在
      • UI为依据

        • 定义

          • 不同的UI显示都对应一份State
        • 缺点

          • State数量过多,容易出现错误的State和重复的State
      • 数据库基本原则为依据

        • 整个应用的状态按照领域分成若干子State,子State之间不能保存重复的数据
        • State以键值对的结构存储数据,以记录的key/Id作为记录的索引,记录中的其他字段都依赖于索引
        • State中不能保存可以通过已有数据计算而来的数据,即State中的字段不互相依赖
  • 架构设计进阶

    • selector函数

      • 使用selector是在解决什么问题

        • 问题原因:redux和容器性组件存在部分耦合,redux中的state结构变化会影响后者
        • 解决问题的目的:实现react容器性组件和redux状态层的终极解耦
        • 解决问题的手段:selectors是作为不同层级之间的接口不仅彻底解耦了层级,还使得不同层级通过接口进行安全交互和通讯得以实现
      • selector带来的好处

        • selector限制了层级的内部变化影响范围最多到接口
        • selector防止不同层级互相知道内部结构的风险
        • selector可以负责计算和过滤的工作
    • redux中间件(Middleware)

      • middleware的写法
      • middleware的本质
    • redux增强器(Enhancer)

      • Enhancer的写法
      • Enhancer和Middleware的关系

        • 实际上middleware是store enhancer的一种,中间件虽然比较低阶,但是它约束了我们的行为,而增强器enhancer虽然更加灵活,但是破坏redux底层结构的风险更大,所以如果你对redux整体的结构和逻辑都不是太熟悉,尽量就别用
  • 架构设计高级

    • reducer如何返回新的state对象

      • Object.assign
      • ES6扩展语法
      • Immutable

        • Immutable的常规使用
        • Immutable的优化
        • Immutable的选择考虑

          • 对项目的整体侵入性很强,我们需要改的地方很多,如果你的项目不是很大,且store当中的数据层级不是很多,结构不复杂,不推荐使用的,我们一定要根据需求去搭建架构,去决定是否使用某些工具
    • Reselect

      • 使用Reselect是解决什么问题

        • store当中的state发生了变化,每个容器型组件的mapStateToProps都要重新执行,产生的结果就是上述的这些selectors函数也要重复执行,也就导致了重复计算,使用Reselect创建的selectors函数,只要使用到的state没有发生变化,这个selectors函数就不会去重新计算,比如getVisibleTodos函数使用到了state.filter和state.todos,修改state.text并不会影响state.filter和state.todos,所以getVisibleTodos函数也就不会重复执行
      • Reselect的常规使用
      • Reselect的选择考虑
  • React Hooks

    • 特性

      • hooks 的出现使得你可以在不编写 class 的情况下使用状态管理以及其它 React 的特性
    • Hooks API

      • useState

        • 用来承担与类组件中的 state 一样的作用,组件内部的状态管理
      • useEffect

        • 可以用来模拟生命周期,即可以完成某些副作用
      • useLayoutEffect

        • 它与 useEffect 的用法完全一样,作用也基本相同,唯一的不同在于执行时机,它会在所有的 DOM 变更之后同步调用 effect,可以使用它来
      • useReducer

        • useState 的替代方案,它接收一个 (state, action) => newState 的 reducer 处理函数,并返回当前的 state 和 配套的 dispatch 方法。使用方法与 redux 非常相似
      • useCallback

        • 它有的作用:性能优化,父组件更新,传递给子组件的函数指针不会每次都改变,只有当依赖项发生改变的时候才会改变指针。避免了子组件的无谓渲染
        • 它的本质是对函数依赖进行分析,依赖变更时才重新执行。
      • useMemo

        • useMemo 用于缓存一些耗时的计算结果(返回值),只有当依赖项改变时才重新进行计算
      • useContext

        • 专门为函数组件提供的 context hook API,可以更加方便地获取 context 的值
        • useContext(MyContext) 接收一个 context 对象,当前获取到的值由上层组件中距离最近的 <MyContext.Provider> 的 value 决定
      • useRef

        • useRef 返回一个可变的 ref 对象,其 current 属性被初始化为传入的参数。返回的 ref 对象在组件的整个生命周期内保持不变
  • 未完待续...

Angular

JavaScript

  • JS变量

    • 变量声明

      • 声明

        • 显示声明

var 变量名

        - 隐式声明

自动添加到闭包

    - 陋习

        - 没有类型
        - 重复声明
        - 隐式声明
        - 不声明直接赋值

    - 提倡

        - 先声明后使用
        - 先赋值后运算

- 作用域

    - 全局变量

        - 包含

            - 在函数体外定义的变量
            - 在函数体内定义的无var的变量

        - 调用

            - 任何位置

    - 局部变量

        - 包含

            - 在函数体内部var声明的变量
            - 函数的参数变量

        - 调用

            - 当前函数体内部

    - 优先级

        - 局部变量高于同名全局变量
        - 参数变量高于同名全局变量
        - 局部变量高于同名参数变量

    - 特性

        - 忽略块级作用域
        - 全局变量是全局对象的属性
        - 局部变量是调用对象的属性
        - 作用域链

            - 内层函数可访问外层函数局部变量
            - 外层函数不能访问内层函数局部变量

        - 生命周期

            - 全局变量

                - 除非被显示删除,否则一直存在

            - 局部变量

                - 自声明起至函数执行完毕或被显示删除

            - 回收机制

                - 标记清除
                - 引用计数
  • JS数据类型

    • undefined

      • 使用var声明但未初始化
      • 区分空对象指针与尚未定义的变量
      • 对未初始化的变量及未声明的变量使用typeof都返回undefined
    • null

      • 逻辑上null表示一个空对象的指针
      • 使用typeof检测时会返回object
    • boolean

      • true为真false为假
      • true不一定=1 false不一定=0
      • 使用Boolean()进行转换

        • 转换为true

          • 任何非空字符串
          • 任何非空对象
          • 任何非零数字
        • 转换为false

          • 空字符串
          • 0和NaN
          • null及undefined
    • string

      • 特性

        • 0个或多个16位Unicode字符组成
        • 单引号与双引号不能交叉使用
        • 使用.length属性访问字符串长度

          • 转义序列表示一个字符串
          • 无法精确返回双字节字符串长度
        • 字符串一旦被创建,其值将不能改变,若要改变必须销毁原有字符串
      • 转义序列

        • n 换行
        • t 制表符
        • b 空格
        • r 回车
        • f 分页符
        • \ 斜杠\
        • ' 单引号
        • " 双引号
        • xnn 十六进制数,n代表0~F
        • unnnn 以十六进制表示一个Unicode字符
      • 类型转换

        • toString()

          • 使用类型

            • number
            • string
            • object
            • boolean
          • 参数

            • number类型的数值基数
        • String()

          • undefined
          • null
        • evel()

          • 计算字符串表达式的值并以数值的形式返回
    • number

      • 进制

        • 十进制
        • 八进制
        • 十六进制
      • 浮点数

        • 小数点后至少一位数字
        • 科学计数法

          • 小数点后带有6个0的浮点数
          • 以e为底*10的±N次幂
        • 最高精度

          • 17位小数
        • 缺陷

          • 存在舍入误差
          • 无法测试特定浮点数值
      • 数值范围

        • 最小值

          • Number.MIN_VALUE

            • 5e-324
        • 最大值

          • Number.MAX_VALUE

            • 1.7976931348623157e+308
        • 超出范围

          • 正无穷

            • Infinity
            • Number.POSITIVE_INFINITY
          • 负无穷

            • -Infinity
            • Number.NEGATIVE_INFINITY
          • 缺陷

            • 无法参与下一次计算
          • 检测方法

            • isFinite()

              • 可转换为数值 true
              • 不可转换为数值 false
      • NaN

        • 含义

          • Not a Number
          • 非数值
        • 特性

          • 任何涉及NaN的操作都将返回NaN
          • NaN与任何值都不相等包括自身
        • 检测

          • isNaN()

            • 可转换为数值 false
            • 不可转换为数值 true
      • 数值转换

        • Number()

          • Boolean

            • true

              • 1
            • false

              • 0
          • null

            • 0
          • undefined

            • NaN
          • String

            • 只包含数字

              • 十进制数
              • 前导0被忽略
            • 包含有浮点格式

              • 浮点数值
              • 忽略前导0
            • 包含有效十六进制数

              • 相同大小的十进制数
            • 空字符串

              • 0
            • 其他字符串

              • NaN
          • object

            • 基于toString转成字符串,再转换成数字
    • object

      • 定义

        • 一组数据或者功能的集合
      • 声明

        • var obj = new Object()
        • var obj = {}
      • 属性与方法

        • constructor

          • 保存拥有创建当前对象的函数
        • hasOwnProperty

          • 检测给定属性在当前对象中是否存在
        • isPrototypeOf

          • 检测传入的对象是否是另一个对象的原型
        • propertyIsEnumerable

          • 检测给定的属性是否能用for-in枚举
        • toLocaleString

          • 返回对象的字符串表示,该字符串与执行环境的地区对应
        • toString

          • 返回对象的字符串表示
        • valueOf

          • 返回对象的字符串、布尔或数值表示
  • 未完待续...

TypeScript

  • 基础类型

    • string

      • 同JavaScript用"或者'标识字符串

        • let name: string = "abc"
    • number

      • 数组

        • number[]

          • let list: number[] = [1,2,3]
        • Array<元素类型>

          • let list: Array<number> = [1,2,3]
      • 数字

        • let decLiteral: number = 6
    • boolean

      • let isDone: boolean = false
    • Tuple

      • 元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同
      • let x: [string, number];

x = ['hello', 10]; // OK

- enum

    - 枚举类型是对JavaScript标准数据类型的一个补充
    - enum Color {Red, Green, Blue}

let c: Color = Color.Green;

- Any

    - 未知的数据类型一般使用any

- Void

    - void类型像是与any类型相反,它表示没有任何类型

- Null 和 Undefined

    - undefined和null两者各自有自己的类型分别叫做undefined和null
    - 它们的本身的类型用处不是很大
    - 默认情况下null和undefined是所有类型的子类型

- Never

    - never类型表示的是那些永不存在的值的类型
    - never类型是任何类型的子类型,也可以赋值给任何类型
    - 没有类型是never的子类型或可以赋值给never类型(除了never本身之外)
    - 即使 any也不可以赋值给never

- Object

    - object表示非原始类型
    - 也就是除number,string,boolean,symbol,null或undefined之外的类型
  • 接口

    • 特殊符号

      • 可选

        • ?
      • 只读

        • readonly
      • 签名

        • 字符串型签名
        • 数组型签名

          • 数字型签名会将数字转换成字符串再去匹配
        • 如果同时使用那么数组型签名的返回值必须是字符串型签名的子类的返回值
    • 对象型接口

      • 普通模式

        • key需要对应上
      • 配合签名使用的option模式
    • 函数型接口

      • 参数

        • 不需要key对应,只需要相应位置的相应类型对应
      • 返回值
    • 类类型接口

      • 特点

        • 接口只需要描述类的公共部分,不会去检查私有部分
      • 构造函数的控制方式

        • 构造函数时金泰属性,不属于公共部分
        • 控制new过程
    • 接口继承

      • 接口的切割和继承
      • 特点:类可当做值也可以当做类型
  • 类class

    • 定义了一件事物的抽象特点,包含它的属性和方法
    • ES6类的使用

      • 属性和方法

        • 使用class定义类
        • 使用constructor定义构造函数
        • 通过new生成实例会自动调用构造函数
      • 类的继承

        • 使用extends关键字实现继承
        • 子类中使用super关键字来调用父类的构造函数和方法
      • 静态方法

        • 使用static修饰符修饰的方法称为静态类
        • 不需要实例化
        • 直接通过类来调用
    • TypeScript类的使用

      • 三种访问修饰符
      • public

        • public 修饰的属性或方法是公有的,可以在任何地方被访问到
        • 默认所有的属性和方法都是 public
      • private

        • private 修饰的属性或方法是私有的
        • 不能在声明它的类的外部访问
        • 很多时候,我们希望有的属性是无法直接存取的,这时候就可以用 private 了
        • 需要注意的是,TypeScript 编译之后的代码中,并没有限制 private 属性在外部的可访问性
        • 使用 private 修饰的属性或方法,在子类中也是不允许访问的
      • protected

        • protected 修饰的属性或方法是受保护的
        • 它和 private 类似,区别是它在子类中也是允许被访问的
    • 抽象类

      • 抽象类是供其它类继承的基类
      • 他们一般不会直接被实例化
      • 抽象类可以包含成员的实现细节
      • abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法
      • 抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
      • 抽象方法的语法与接口方法相似。 两者都是定义方法签名不包含方法体。 然而,抽象方法必须使用abstract关键字并且可以包含访问符
    • 类的类型

      • 实现方式类似接口
    • 类实现接口

      • 实现(implements)是面向对象中的一个重要概念
      • 一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),用 implements 关键字来实现
      • 这个特性大大提高了面向对象的灵活性
  • 函数

    • 有可选参数的函数

      • 调用函数时传的参数的数量或者类型不符合函数中定义的参数要求时,TypeScript编译器会报错
      • 在一些场景下我们不需要传所有的参数;TypeScript一个函数可选参数的特性;
      • 在TypeScript中通过在函数参数后面追加一个?,指定参数是可选的
    • 有默认参数的函数

      • 当函数有可选参数时,我们必须检测参数是否被传递了
      • 在声明函数签名时使用=提供一个默认值,即可指定函数参数是可选的;
      • TypeScript编译会在JavaScript输出结果中生成一个if结构
    • 有剩余参数的函数

      • add = (...foo:number[]):number => {}
  • 声明文件

    • 场景

      • 当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能
    • 什么是声明语句

      • 假如我们想使用第三方库 jQuery,一种常见的方式是在 html 中通过 <script> 标签引入 jQuery,然后就可以使用全局变量 $ 或 jQuery 了

        • $('body')
      • 但是在 ts 中,编译器并不知道 $ 或 jQuery 是什么东西
      • 这时,我们需要使用 declare var 来定义它的类型:

        • declare var $: (selector: string) => any;
      • declare var 并没有真的定义一个变量,只是定义了全局变量 $ 的类型,仅仅会用于编译时的检查,在编译结果中会被删除
    • 什么是声明文件

      • 通常我们会把声明语句放到一个单独的文件(index.d.ts)中,这就是声明文件
      • 声明文件必须以.d.ts为后缀
    • 第三方声明文件

      • 我们可以直接下载下来使用,但是更推荐的是使用 @types 统一管理第三方库的声明文件。
      • @types 的使用方式很简单,直接用 npm 安装对应的声明模块即可,以 jQuery 举例:

        • npm install @types/jquery --save-dev
    • 书写声明文件

      • 库文件使用场景

        • 全局变量

          • 通过 <script> 标签引入第三方库,注入全局变量
        • npm包

          • 通过 import foo from 'foo' 导入,符合 ES6 模块规范
        • UMD库

          • 既可以通过 <script> 标签引入,又可以通过 import 导入
        • 直接扩展全局变量

          • 通过 <script> 标签引入后,改变一个全局变量的结构
        • 在 npm 包或 UMD 库中扩展全局变量

          • 引用 npm 包或 UMD 库后,改变一个全局变量的结构
        • 模块插件

          • 通过 <script> 或 import 导入后,改变另一个模块的结构
      • 全局变量声明

        • 使用全局变量的声明文件时,如果是以 npm install @types/xxx --save-dev 安装的,则不需要任何配置。否则就需要在声明文件中声明全局变量
        • 全局变量的几种声明方式

          • declare var/const/let

            • 声明全局变量
          • declare function

            • 声明全局方法
          • declare class

            • 声明全局类
          • declare enum

            • 声明全局枚举类型
          • declare namespace

            • 声明(含有子属性的)全局对象
          • interface 和 type

            • 声明全局类型
  • 未完待续...

Vue

  • 简介

    • Vue是一个MVVM框架
    • Vue是用于构建用户界面的渐进式框架
    • 尤雨溪最开始想起名为 seed.js,但是npm已经被注册了,后来根据 ”view“起名为 vue
    • 2014年由Laravel框架作者推荐后逐渐流行
  • 特点

    • 易用

      • 已经会了 HTML、CSS、JavaScript?即刻阅读指南开始构建应用!
    • 灵活

      • 不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩。
    • 高效

      • 20kB min+gzip 运行大小
      • 超快虚拟 DOM
      • 最省心的优化
  • Vue思想

    • 数据驱动
    • 组件化
  • Vue API

    • 应用API

      • component

        • 注册或检索全局组件。注册还会使用给定的 name 参数自动设置组件的 name。
      • config

        • 包含应用配置的对象。
      • directive

        • 注册或检索全局指令。
      • mixin

        • 在整个应用范围内应用混入。一旦注册,它们就可以在当前的应用中任何组件模板内使用它。插件作者可以使用此方法将自定义行为注入组件。不建议在应用代码中使用。
      • mount

        • 将应用实例的根组件挂载在提供的 DOM 元素上
      • provide

        • 设置一个可以被注入到应用范围内所有组件中的值。组件应该使用 inject 来接收 provide 的值。
        • 从 provide/inject 的角度来看,可以将应用程序视为根级别的祖先,而根组件是其唯一的子级。
        • 该方法不应该与 provide 组件选项或组合式 API 中的 provide 方法混淆。虽然它们也是相同的 provide/inject 机制的一部分,但是是用来配置组件 provide 的值而不是应用 provide 的值。
        • 通过应用提供值在写插件时尤其有用,因为插件一般不能使用组件提供值。这是使用 globalProperties 的替代选择。
      • unmount

        • 在提供的 DOM 元素上卸载应用实例的根组件。
      • use

        • 安装 Vue.js 插件。如果插件是一个对象,它必须暴露一个 install 方法。如果它本身是一个函数,它将被视为安装方法。
        • 该安装方法将以应用实例作为第一个参数被调用。传给 use 的其他 options 参数将作为后续参数传入该安装方法。
        • 当在同一个插件上多次调用此方法时,该插件将仅安装一次
    • 全局API

      • createApp

        • 返回一个提供应用上下文的应用实例。应用实例挂载的整个组件树共享同一个上下文。
      • h

        • 返回一个”虚拟节点“,通常缩写为 VNode:一个普通对象,其中包含向 Vue 描述它应在页面上渲染哪种节点的信息,包括所有子节点的描述。它的目的是用于手动编写的渲染函数
      • defineComponent

        • 从实现上看,defineComponent 只返回传递给它的对象。但是,就类型而言,返回的值有一个合成类型的构造函数,用于手动渲染函数、TSX 和 IDE 工具支持。
      • defineAsyncComponent

        • 创建一个只有在需要时才会加载的异步组件
      • resolveComponent

        • 如果在当前应用实例中可用,则允许按名称解析 component。返回一个 Component。如果没有找到,则返回 undefined。
      • resolveDynamicComponent

        • 允许使用与 <component :is=""> 相同的机制来解析一个 component。返回已解析的 Component 或新创建的 VNode,其中组件名称作为节点标签。如果找不到 Component,将发出警告。
      • withDirectives

        • 允许将指令应用于 VNode。返回一个包含应用指令的 VNode。
      • createRenderer

        • createRenderer 函数接受两个泛型参数: HostNode 和 HostElement,对应于宿主环境中的 Node 和 Element 类型。
      • nextTick

        • 将回调推迟到下一个 DOM 更新周期之后执行。在更改了一些数据以等待 DOM 更新后立即使用它
    • options

      • Data

        • data

          • 返回组件实例的 data 对象的函数
        • props

          • props 可以是数组或对象,用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高阶选项,如类型检测、自定义验证和设置默认值。
        • computed

          • 计算属性将被混入到组件实例中。所有 getter 和 setter 的 this 上下文自动地绑定为组件实例。
        • methods

          • methods 将被混入到组件实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this 自动绑定为组件实例。
        • watch

          • 一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象
        • emits

          • emits 可以是数组或对象,从组件触发自定义事件,emits 可以是简单的数组,或者对象作为替代,允许配置和事件验证
      • DOM

        • template

          • 一个字符串模板作为 component 实例的标识使用。模板将会替换挂载的元素。挂载元素的内容都将被忽略,除非模板的内容有分发插槽。
        • render

          • 字符串模板的另一种选择,允许你充分利用 JavaScript 的编程功能。
      • 生命周期

        • beforeCreate->setup()

          • 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用
        • created->setup()

          • 在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el property 目前尚不可用
        • beforeMount->onBeforeMount

          • 在挂载开始之前被调用:相关的 render 函数首次被调用。
          • 该钩子在服务器端渲染期间不被调用。
        • mounted->onMounted

          • 实例被挂载后调用,这时 Vue.createApp({}).mount() 被新创建的 vm.$el 替换了。如果根实例挂载到了一个文档内的元素上,当 mounted 被调用时 vm.$el 也在文档内。
          • 注意 mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick
          • 该钩子在服务器端渲染期间不被调用
        • beforeUpdate->onBeforeUpdate

          • 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。
          • 该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行
        • updated->onUpdated

          • 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
          • 当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或侦听器取而代之。
          • 注意,updated 不会保证所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以在 updated 里使用 vm.$nextTick
          • 该钩子在服务器端渲染期间不被调用
        • activated

          • 被 keep-alive 缓存的组件激活时调用。
          • 该钩子在服务器端渲染期间不被调用。
        • deactivated

          • 被 keep-alive 缓存的组件停用时调用。
          • 该钩子在服务器端渲染期间不被调用。
        • beforeUnmount(3.0)->onBeforeUnmount

          • 在卸载组件实例之前调用。在这个阶段,实例仍然是完全正常的。
          • 该钩子在服务器端渲染期间不被调用。
        • unmounted(3.0)->onUnmounted

          • 卸载组件实例后调用。调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载。
          • 该钩子在服务器端渲染期间不被调用。
        • errorCaptured->onErrorCaptured

          • 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。
        • renderTracked(3.0)->onRenderTracked

          • 跟踪虚拟 DOM 重新渲染时调用。钩子接收 debugger event 作为参数。此事件告诉你哪个操作跟踪了组件以及该操作的目标对象和键。
        • renderTriggered(3.0)->onRenderTriggered

          • 当虚拟 DOM 重新渲染为 triggered.Similarly 为renderTracked,接收 debugger event 作为参数。此事件告诉你是什么操作触发了重新渲染,以及该操作的目标对象和键。
      • 选项/资源

        • directives

          • 包含组件实例可用指令的哈希表。
        • components

          • 包含组件实例可用组件的哈希表。
    • 实例property

      • $data

        • 组件实例观察的数据对象。组件实例代理了对其 data 对象 property 的访问。
      • $props

        • 当前组件接收到的 props 对象。组件实例代理了对其 props 对象 property 的访问。
      • $el

        • 组件实例使用的根 DOM 元素。
      • $options

        • 用于当前组件实例的初始化选项
      • $parent

        • 父实例,如果当前实例有的话。
      • $root

        • 当前组件树的根组件实例。如果当前实例没有父实例,此实例将会是其自己。
      • $slots

        • 用来访问被插槽分发的内容。
      • $refs

        • 一个对象,持有注册过 ref attribute 的所有 DOM 元素和组件实例。
      • $attrs

        • 包含了父作用域中不作为组件 props 或自定义事件。
    • 实例方法

      • $watch

        • 侦听组件实例上的响应式 property 或函数计算结果的变化。
      • $emit

        • 触发当前实例上的事件。附加参数都会传给监听器回调。
      • $forceUpdate

        • 迫使组件实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。
      • $nextTick

        • 将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
    • 指令

      • v-text

        • 更新元素的 textContent。如果要更新部分的 textContent,需要使用 Mustache 插值。
      • v-html

        • 更新元素的 innerHTML。注意:内容按普通 HTML 插入 - 不会作为 Vue 模板进行编译。如果试图使用 v-html 组合模板,可以重新考虑是否通过使用组件来替代。
      • v-show

        • 根据表达式的真假值,切换元素的 display CSS property。
        • 当条件变化时该指令触发过渡效果。
      • v-if

        • 根据表达式的真假值来有条件地渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建。如果元素是 <template>,将提取它的内容作为条件块。
        • 当条件变化时该指令触发过渡效果。
        • 当和 v-for 一起使用时,v-if 的优先级比 v-for 更高
      • v-else

        • 为 v-if 或者 v-else-if 添加“else 块”。
      • v-else-if

        • 表示 v-if 的“else if 块”。可以链式调用。
      • v-for

        • 基于源数据多次渲染元素或模板块
      • v-on

        • .stop - 调用 event.stopPropagation()。
        • .prevent - 调用 event.preventDefault()。
        • .capture - 添加事件侦听器时使用 capture 模式。
        • .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
        • .{keyAlias} - 仅当事件是从特定键触发时才触发回调。
        • .once - 只触发一次回调。
        • .left - 只当点击鼠标左键时触发。
        • .right - 只当点击鼠标右键时触发。
        • .middle - 只当点击鼠标中键时触发。
        • .passive - { passive: true } 模式添加侦听器
        • 绑定事件监听器。事件类型由参数指定。
      • v-bind

        • 动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。
      • v-model

        • .lazy - 监听 change 而不是 input 事件
        • .number - 输入字符串转为有效的数字
        • .trim - 输入首尾空格过滤
        • 在表单控件或者组件上创建双向绑定。
      • v-slot

        • 提供具名插槽或需要接收 prop 的插槽。
      • v-pre

        • 跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
      • v-cloak

        • 这个指令保持在元素上直到关联组件实例结束编译。和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到组件实例准备完毕。
      • v-once

        • 只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
      • v-is

        • 在 DOM 内模板使用时,模板受原生 HTML 解析规则的约束
    • 特殊指令

      • key

        • key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除/销毁 key 不存在的元素。
        • 有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
      • ref

        • ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
      • is

        • 使用动态组件。
    • 内置组件

      • component

        • 渲染一个“元组件”为动态组件。依 is 的值,来决定哪个组件被渲染。is 的值是一个字符串,它既可以是 HTML 标签名称也可以是组件名称。
      • transition

        • <transition> 元素作为单个元素/组件的过渡效果。<transition> 只会把过渡效果应用到其包裹的内容上,而不会额外渲染 DOM 元素,也不会出现在可被检查的组件层级中。
      • transition-group

        • <transition-group>提供多个元素/组件的过渡效果。默认情况下,它不呈现包装DOM元素,但可以通过tag属性定义一个。
        • 注意,每个 <transition-group> 的子节点必须有独立的 key,动画才能正常工作
      • keep-alive

        • <keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition> 相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。
        • 当组件在 <keep-alive> 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。
        • 主要用于保留组件状态或避免重新渲染。
      • slot

        • <slot> 元素作为组件模板之中的内容分发插槽。<slot> 元素自身将被替换。
      • teleport

        • 允许我们控制在 DOM 中哪个父节点下渲染了 HTML,而不必求助于全局状态或将其拆分为两个组件。
    • 响应式API

      • 响应式基础API

        • reactive

          • 返回对象的响应式副本
          • 响应式转换是“深层”的——它影响所有嵌套 property。在基于 ES2015 Proxy 的实现中,返回的 proxy 是不等于原始对象的。建议只使用响应式 proxy,避免依赖原始对象。
        • readonly

          • 获取一个对象 (响应式或纯对象) 或 ref 并返回原始 proxy 的只读 proxy。只读 proxy 是深层的:访问的任何嵌套 property 也是只读的。
        • isProxy

          • 检查对象是否是由 reactive 或 readonly 创建的 proxy。
        • isReactive

          • 检查对象是否是 reactive创建的响应式 proxy。
        • isReadonly

          • 检查对象是否是由readonly创建的只读 proxy。
        • toRaw

          • 返回 reactive 或 readonly proxy 的原始对象。这是一个转义口,可用于临时读取而不会引起 proxy 访问/跟踪开销,也可用于写入而不会触发更改
        • markRaw

          • 标记一个对象,使其永远不会转换为 proxy。返回对象本身。
        • shallowReactive

          • 创建一个响应式 proxy,跟踪其自身 property 的响应性,但不执行嵌套对象的深度响应式转换 (暴露原始值)。
        • shallowReadonly

          • 创建一个 proxy,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换 (暴露原始值)。
      • Refs

        • ref

          • 接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象具有指向内部值的单个 property .value。
        • unref

          • 如果参数为 ref,则返回内部值,否则返回参数本身。这是 val = isRef(val) ? val.value : val。
        • toRef

          • 可以用来为源响应式对象上的 property 新创建一个 ref。然后可以将 ref 传递出去,从而保持对其源 property 的响应式连接。
        • toRefs

          • 将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的ref。
        • isRef

          • 检查值是否是ref对象。
        • customRef

          • 创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数,该函数接收 track 和 trigger 函数作为参数,并应返回一个带有 get 和 set 的对象。
        • shallowRef

          • 创建一个 ref,它跟踪自己的 .value 更改,但不会使其值成为响应式的。
        • triggerRef

          • 手动执行与 shallowRef 关联的任何副作用。
      • Computed和watch

        • computed

          • 使用 getter 函数,并为从 getter 返回的值返回一个不变的响应式 ref 对象。
        • watchEffect

          • 在响应式地跟踪其依赖项时立即运行一个函数,并在更改依赖项时重新运行它。
        • watch

          • watch API 与选项式 API this.$watch (以及相应的 watch 选项) 完全等效。watch 需要侦听特定的数据源,并在单独的回调函数中执行副作用。默认情况下,它也是惰性的——即回调仅在侦听源发生更改时调用。
    • 组合式API

      • setup

        • 一个组件选项,在创建组件之前执行,一旦 props 被解析,并作为组合式 API 的入口点
        • props

          • setup 函数中的第一个参数是 props。正如在一个标准组件中所期望的那样,setup 函数中的 props 是响应式的,当传入新的 prop 时,它将被更新。
        • context

          • 传递给 setup 函数的第二个参数是 context。context 是一个普通的 JavaScript 对象,它暴露三个组件的 property
      • 生命周期钩子
  • Vuex
  • Vue-router
  • Vue-SSR
  • Vue-Loader
  • Vue-Cli

    • 通过 @vue/cli 实现的交互式的项目脚手架。
    • 通过 @vue/cli + @vue/cli-service-global 实现的零配置原型开发。
    • 一个运行时依赖 (@vue/cli-service)
    • Cli

      • CLI (@vue/cli) 是一个全局安装的 npm 包,提供了终端里的 vue 命令。它可以通过 vue create 快速搭建一个新项目,或者直接通过 vue serve 构建新想法的原型。你也可以通过 vue ui 通过一套图形化界面管理你的所有项目
    • Cli服务

      • CLI 服务 (@vue/cli-service) 是一个开发环境依赖。它是一个 npm 包,局部安装在每个 @vue/cli 创建的项目中。
      • CLI 服务是构建于 webpack 和 webpack-dev-server 之上的

        • 加载其它 CLI 插件的核心服务;
        • 一个针对绝大部分应用优化过的内部的 webpack 配置;
        • 项目内部的 vue-cli-service 命令,提供 serve、build 和 inspect 命令
    • Cli插件

      • CLI 插件是向你的 Vue 项目提供可选功能的 npm 包,例如 Babel/TypeScript 转译、ESLint 集成、单元测试和 end-to-end 测试等。Vue CLI 插件的名字以 @vue/cli-plugin- (内建插件) 或 vue-cli-plugin- (社区插件) 开头,非常容易使用。
      • 当你在项目内部运行 vue-cli-service 命令时,它会自动解析并加载 package.json 中列出的所有 CLI 插件。
      • 插件可以作为项目创建过程的一部分,或在后期加入到项目中。它们也可以被归成一组可复用的 preset
  • Vue-Devtools
  • vue-class-component

跨平台技术

跨端技术发展的三个阶段

  • 第一阶段是混合开发的web容器时代

    • 为了解决原生开发的高成本、低效率,出现了Hybrid混合开发
    • 原生中嵌入依托于浏览器的WebView
    • Web浏览器中可以实现的需求在WebView中基本都可以实现
    • 但是Web最大的问题是,它的性能和体验与原生开发存在肉眼可感知的差异
    • 因此并不适用于对性能和用户体验要求较高的场景
  • 第二阶段是以RN和Weex为代表的泛web容器时代

    • RN对Web标准进行了功能裁剪
    • 用户体验更接近于原生了
    • 由于进行了功能裁剪,所以RN对业务的支持能力还不到浏览器的5%
    • 因此仅适用于中低复杂度的低交互类页面。面对稍微复杂一点儿的交互和动画需求,都需要通过调用原生代码去扩展才能实现
  • 第三阶段是以Flutter为代表的自绘引擎时代

    • Flutter是构建Google物联网操作系统Fuchsia的SDK
    • 它使用Dart语言开发APP
    • 一套代码可以同时运行在iOS和Android平台上
    • Flutter采用自带的Native渲染引擎渲染视图,它是自己完成了组件渲染的闭环
    • 而RN、Weex之类的框架,只是通过JavaScript虚拟机扩展调用系统组件,最后是由Android或者iOS系统来完成组件的渲染

Hybrid

  • 为什么要引入hybrid开发

    • Native应对急速业务需求,APP迭代加快,频繁的发版已难以应付
    • Android渠道众多,apple store审核周期长
    • 纯native开发效率低,开发维护成本高,不支持热更新
    • 相对于其他动态发布技术,技术研发成本较低,使用语言更广泛,社区资源更丰富
  • 优劣势

    • 原生APP

      • 优点

        • 打造完美的用户体验
        • 性能稳定、操作速度快,上手流畅
        • 访问本地资源(通讯录,相册)
        • 设计出色的动效,转场
        • 拥有系统级别的贴心通知或提醒
        • 用户留存率高
      • 缺点

        • 分发成本高(不同平台有不同的开发语言和界面适配)
        • 维护成本高
        • 更新缓慢,根据不同平台,提交–审核–上线 等等不同的流程,需要经过的流程较复杂
    • Web APP

      • 优点

        • 发版完全自控随时更新开发成本小时间快
      • 缺点

        • 性能差弱网络无网络条件下体验差
    • Hybrid APP

      • 优点

        • 跨平台
        • 开发周期短、成本低
        • 用户体验良好
        • 可以即时修复bug、动态发版
      • 缺点

        • 仿原生iOS效果复杂
        • 机型兼容性
  • 整体架构

    • viewLayer(视图层)

      • H5

        • H5页面
        • webview引擎渲染
      • Native

        • Native页面
        • 系统原生引擎渲染
    • coreLayer(通信层)

      • 自定义webview资源拦截管理器

        • 内置资源管理
        • 缓存模块
        • 文件下载模块
      • 定义页面跳转管理器
      • 定义混合通信交互模块
  • 交互设计

    • 交互原理

      • 两种交互

        • native主动调用前端JS
        • H5主动与native发起通信
      • 交互过程(OC)

        • 搭建JS调用OC的桥梁,注册供JS调用的方法name
        • JS在调用Native注册方法

          • iOS:window.webkit.messageHandlers.自定义属性.postMessage()
          • Android:window.自定义方法
        • Native接收JS调用,解析处理,返回回调
    • 通信方式

      • 假跳转的请求拦截(不建议)

        • 假跳转的请求拦截 就是由网页发出一条新的跳转请求,跳转的目的地是一个非法的压根就不存在的地址
        • 比如:wbcst://testhost/action?params=xxx
        • 模拟http协议网络请求 scheme://host/action?params
        • 客户端会无差别拦截所有请求,真正的url地址应该照常放过,只有协议域名匹配的url地址才应该被客户端拦截
        • JS调用方式

          • a标签跳转
          • location.href跳转
          • iframe跳转
        • 不建议使用,android系统对url参数做了字节限制,无法进行大数据的通信
      • 弹窗拦截(不建议)

        • alert

          • 弹出个提示框,只能点确认无回调
        • confirm

          • 弹出个确认框(确认,取消),可以回调
        • prompt

          • 弹出个输入框,让用户输入东西,可以回调
        • 不建议使用,会无差别的拦截所有前端的window弹窗
      • JS上下文注入(推荐)

        • iOS

          • WKWebView scriptMessageHandler注入
        • android

          • addJavascriptInterface注入
        • 特点

          • 不通过任何拦截的办法,而是直接将一个native对象(or函数)注入到JS里面,可以由web的js代码直接调用,直接操作

ReactNative

  • 简介

    • 特性

      • Learn Once,Write AnyWhere
      • 提供了原生控件支持
      • 异步执行
      • 触屏处理
    • 设计理念

      • 既拥有Native的用户体验
      • 又保留React的开发效率
    • 优势

      • 它对比原生开发更为灵活,对比H5体验更为高效。
      • 替代传统的WebView,打开效率更高,和原生之间的交互更方便。
      • 多个版本迭代后的今天,它已经拥有了丰富第三方插件支持
      • 更方便的热更新
    • 劣势

      • 尽管是跨平台,但是不同平台Api的特性与显示并不一定一致
      • 调试’相对‘麻烦。
      • Android上的兼容性问题
    • 风险

      • 尽管Facebook有3款App(Groups、Ads Manager、F8)使用了React Native,随着React Native大规模应用,Appstore的政策是否有变不得而知
  • 环境搭建

  • 架构设计

    • Native
    • Bridge

      • 异步(asynchronous):不依赖于同步通信
      • 可序列化(serializable):保证一切 UI 操作都能序列化成 JSON 并转换回来
      • 批处理(batched):对 Native 调用进行排队,批量处理
    • JavaScript
  • 组件及布局

    • 核心组件

      • View
      • Text
      • ScrollView
      • Image
      • TextInput
    • 原生组件

      • 运行时RN为前端组件创建相应的android和iOS视图
      • RN就是对原生视图的封装
    • style

      • RN编写的应用的样式不是靠css来实现的
      • 而是依赖javascript来为你的应用来添加样式
      • 样式声明

        • 依赖导入

          • import React, { StyleSheet } from "react-native";
        • 调用React-Native的一个构造方法
        • 传入一个对象生成style
        • 和React的React.createCladd()语法是一样的,传入对象的key就相当于类名,每个类也是一个对象,可以配置各种样式参数
        • 注意

          • 对象key全部是驼峰写法
          • 长度不加单位
        • 示例

          • const styles = StyleSheet.create({
active: {  
    borderWidth: 2,  
    borderColor: ‘#ff00ff',  
},  

});

    - 样式使用

        - 外部引入

            - <View style={styles.base}></View>

        - 设置多个属性类

            - style={[styles.base,styles.backgroundColor]}

        - 行内样式

            -  style={{width:this.state.width}}  

- flexBox布局

    - 什么是FlexBox布局

        - 弹性盒模型(The Flexible Box Module),又叫Flexbox,意为“弹性布局”
        - 旨在通过弹性的方式来对齐和分布容器中内容的空间,使其能适应不同屏幕,为盒装模型提供最大的灵活性
        - 布局思想

            - 让容器有能力让其子项目能够改变其宽度、高度(甚至是顺序)
            - 以最佳方式填充可用空间

    - Flex布局基于flex-flow流

        - 水平的主轴(main axis)

            - 主轴的开始位置(与边框的交叉点)叫做main start
            - 结束位置叫做main end

        - 垂直的交叉轴(cross axis)

            - 交叉轴的开始位置叫做cross start
            - 结束位置叫做cross end

        - 项目默认沿主轴排列,单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size

    - 属性

        - 4个容器属性

            - flexDirection

                - 决定主轴的方向(即项目的排列方向)
                - row:主轴为水平方向,起点在左端。
                - row-reverse:主轴为水平方向,起点在右端
                - column(默认值):主轴为垂直方向,起点在上沿。
                - column-reverse:主轴为垂直方向,起点在下沿。

            - flexWrap

                - 默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap属性定义,如果一条轴线排不下,如何换行。
                - nowrap(默认值):不换行
                - wrap:换行,第一行在上方
                - wrap-reverse:换行,第一行在下方。(和wrap相反)

            - justifyContent

                - 定义了伸缩项目在主轴线的对齐方式
                - flex-start(默认值):伸缩项目向一行的起始位置靠齐。
                - flex-end:伸缩项目向一行的结束位置靠齐
                - center:伸缩项目向一行的中间位置靠齐。
                - space-between:两端对齐,项目之间的间隔都相等。
                - space-around:伸缩项目会平均地分布在行里,两端保留一半的空间

            - alignItems

                - 定义项目在交叉轴上如何对齐,可以把其想像成侧轴(垂直于主轴)的“对齐方式”。
                - flex-start:交叉轴的起点对齐。
                - flex-end:交叉轴的终点对齐 。
                - center:交叉轴的中点对齐。
                - baseline:项目的第一行文字的基线对齐。
                - stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

        - 2个项目属性

            - flex

                - 复合属性
                - 设置或检索伸缩盒对象的子元素如何分配空间
                - 其中第二个和第三个参数(flex-shrink、flex-basis)是可选参数
                - 默认值为“0 1 auto”

            - alignSelf

                - align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性
                - 默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch
  • UI渲染

    • 模块注入

      • RN模块注入

        • index->App
      • RN模块运行入口

        • AppRegistry

          • AppRegistry常用方法
          • registerConfig

            • static静态方法,用来注册配置信息
          • registerComponent

            • 注册组件
          • registerRunnable

            • 注册线程
          • runApplication

            • 进行运行应用
      • 入口组件注册

        • registerComponent
      • 加载jsbundle文件运行应用

        • runApplication
    • 页面启动UI渲染

      • APP启动
      • 读取模块Modules
      • 初始化根视图(RCTRootView)
      • 创建了一个实现 Objective-C 与 Javascript 交互的全局bridge(RCTBridge)
      • 读取Javascript代码(RCTBridgeloadSource)
      • 初始化Native模块化信息
      • 初始化 JavaScript 代码的执行器,即 RCTJSCExecutor 对象
      • 执行JS调用OC组件
      • 将flexbox布局转换成原生布局完成UI渲染
    • UI控件渲染流程

      • RCTRootView runApplication:bridge

        • 通知JS运行App
      • RCTBatchedBridge _processResponse:json error:error

        • 处理执行完JS代码(runApplication)返回的相应,包含需要添加多少子控件的信息。
      • RCTBatchedBridge batchDidComplete

        • RCTUIManager调用处理完成的方法,就会开始去加载rootView的子控件。
      • RCTUIManager createView:viewName:rootTag:props

        • 通过JS执行OC代码,让UI管理者创建子控件View
      • [RCTUIManager _layoutAndMount]

        • 布局RCTRootView和增加子控件
      • [RCTUIManager setChildren:reactTags:]

        • 给RCTRootView对应的RCTRootShadowView设置子控件
      • [RCTRootShadowView insertReactSubview:view atIndex:index++]

        • 遍历子控件数组,给RCTRootShadowView插入所有子控件
      • [RCTShadowView processUpdatedProperties:parentProperties:]

        • 处理保存在RCTShadowView中属性,就会去布局RCTShadowView对应UIView的所有子控件
      • [RCTView didUpdateReactSubviews]

        • 给原生View添加子控件
      • 完成UI渲染
    • 通信机制

      • OC生成一张模块配置表,包含所有模块和模块里的方法,根据特定的标识宏(RCT_EXPORT_MODULE()),将可以暴露的方法暴露给JS
      • 通信流程

        • ①js调用OC模块暴露出来的方法
        • ②把调用方法分解为ModuleName、MethodName、arguments,在丢给MessageQueue处理
        • ③把js的callback函数缓存在MessageQueue的一个成员变量里面,同时生成一个CallbackID来代表callback;在通过保存在MessageQueue的模块配置表把ModuleName、MethodName转成ModuleID、MethodID
        • ④把ModuleID、MethodID、CallbackID和其他参数传给OC(JavaScriptCore)
        • ⑤OC接到消息,通过模块配置表拿到对于的模块和方法
        • ⑥RCTModuleMethod对js传过来的参数进行处理
        • ⑦OC模块方法执行完,执行block回调
        • ⑧调用第6步中RCTModuleMethod生成的block
        • ⑨block带着CallbackID和block传过来的参数去掉用js里的MessageQueue方法invokeCallbackAndReturnFlushedQueue
        • ⑩MessageQueue通过CallbackID找到相应的js的callback方法
        • ⑪调用callback方法,并把OC带过来的参数一起传过去完成回调
    • 导航路由

      • StackNavigator

        • 用来跳转页面和传递参数
        • 参数

          • RouteConfigs
          • StackNavigatorConfig
        • navigation

          • navigate

            • 跳转到其他页面
            • routeName

              • 导航器中配置的路由名称
            • params

              • 传递参数到下一个页面
            • action
            • 示例

              • this.props.navigation.navigate('Find', {param: 'i am the param'});
          • state

            • 当前页面导航器的状态
            • params

              • 路由页面参数
            • key

              • 路由页面id
            • routeName

              • 路由页面名称
          • setParams

            • 更改路由的参数
            • 在组件挂载完成之后注册
            • componentDidMount() {
            • this.props.navigation.setParams({param:'i am the new param'})
          • goBack

            • 返回
            • goBack()

              • 回退到上一个页面
            • goBack(null)

              • 回退到任意一个页面
            • goBack('pathName')

              • 回退到指定页面
          • dispatch

            • 发送一个action
      • TabNavigator

        • 类似底部导航栏,用来在同一屏切换不同页面
      • DrawerNavigator

        • 侧滑菜单导航栏,用于轻松设置带抽屉的屏幕
    • 拆包

      • 目的

        • 解决jsbundle体积过大
        • 按需分步加载,提高加载效率
        • 提高热更新包diff/load效率
      • jsbundle组成

        • 头部(Polyfills)

          • 定义基本的JS环境
          • 主要是define,require等全局模块的定义
          • d()函数、__r()函数、__DEV 变量等
        • 中部(Module定义)

          • 模块定义,RN框架和业务的各个模块定义
          • 使用__d()函数定义所有用到的模块
          • 该函数为每个模块赋予了一个模块ID,模块之间的依赖关系都是通过这个ID进行关联的
        • 尾部(Require调用)

          • 引擎初始化和入口函数执行
          • 使用__r()函数引用根模块
      • 拆包方案

        • diff and patch

          • 将jsbundle通过diff,生成common和每个业务的patch包
          • 然后在APP运行时对common和patch合并成执行的jsbundle
        • 修改RN的bundle命令打包流程,使得直接生成common+business包
        • 修改RN的unbundle命令,生成common+business包
        • 使用metro拆包

          • 基础包和业务包打包

            • 抽离公共组件到base.js
            • base.js入口打包

              • 输出common.jsbundle
            • index.js入口打包

              • 输出business.jsbundle
          • 差异包打包

            • business.jsbundle基于common.jsbundle打差异包
            • 实现思路

              • business.jsbundle逐行扫描
              • 扫描内容如在common.jsbundle中没找到,用数组存放
              • 将数组转换为数据保存到差异包patch.jsbundle
    • 热更新

      • 前端业务代码提交入库
      • 基于热更新平台拆分当前项目
      • 资源打包上线CDN服务器
      • 前端资源添加版本号管理
      • 客户端拉取前端RN资源动态更新

Flutter

  • Flutter发展历程

    • 2014.10 - Flutter的前身Sky在GitHub上开源
    • 2015.10 - 经过一年的开源,Sky正式改名为Flutter
    • 2017.5 - Google I/O正式向外界公布了Flutter,这个时候Flutter才正式进去大家的视野
    • 2018.6 - 距5月Google I/O 1个月的时间,Flutter1.0预览版
    • 2018.12 - Flutter1.0发布,它的发布将大家对Flutter的学习和研究推到了一个新的起点
    • 2019.2 - Flutter1.2发布主要增加对web的支持
  • 简介

    • Flutter 是 Google推出并开源的移动应用开发框架
    • 主打跨平台、高保真、高性能
    • 开发者可以通过 Dart语言开发 App,一套代码同时运行在 iOS 和 Android平台
    • Flutter提供了丰富的组件、接口,开发者可以很快地为 Flutter添加 native扩展
    • 同时 Flutter还使用 Native引擎渲染视图,这无疑能为用户提供良好的体验
  • 框架

    • Framework

      • 纯 Dart实现的 SDK,类似于 React在 JavaScript中的作用
      • 它实现了一套基础库, 用于处理动画、绘图和手势
      • 基于绘图封装了一套 UI组件库
      • 根据 Material 和Cupertino两种视觉风格区分开来
    • Engine

      • 纯 C++实现的 SDK
      • 包括

        • Skia引擎
        • Dart运行时
        • 文字排版引擎等
      • 它是 Dart的一个运行时,它可以以 JIT 或者 AOT的模式运行 Dart代码
      • 这个运行时还控制着 VSync信号的传递、GPU数据的填充等,并且还负责把客户端的事件传递到运行时中的代码
    • Embedder

      • Embedder是操作系统适配层
      • 实现了

        • 渲染Surface设置
        • 线程设置
        • 平台插件等平台相关特性的适配
  • 组件渲染

    • 图像显示的基本原理

      • 显示器的CRT电子枪从上到下一行行扫描,扫描一行完成之后,显示器上就显示一帧画面,随后电子枪回到初始位置继续下一次扫描
      • 水平扫描时,显示器会发出一个水平同步信号(HSync)
      • 而当一帧画面绘制完成之后,电子枪恢复原位,准备下一次扫描之前,显示器会发出一个垂直同步信号(Vsync)
      • 显示器以固定的频率刷新,这个刷新率就是Vsync信号产生的频率
      • 图像的显示需要CPU、GPU和显示器一起配合完成

        • CPU负责图像数据计算
        • GPU负责图像数据渲染
        • 显示器则负责最终图像显示
      • CPU把计算好的需要显示的内容交给GPU
      • 由GPU完成渲染后放入帧缓冲区
      • 随后视频控制器根据垂直同步信号(Vsync)以每秒60次的速度
      • 从帧缓冲区读取帧数据交由显示器完成图像显示
    • Flutter绘制原理

      • 渲染流程

        • Dart
        • |
        • GPU
        • |
        • |
        • Compositor
        • Skia
        • GPU
      • 渲染流程1

        • GPU的VSync信号同步给到UI线程
        • UI线程使用Dart来构建抽象的视图结构(这里是Framework层的工作)
        • 绘制好的抽象视图数据结构在GPU线程中进行图层合成(在Flutter Engine层的工作)
        • 然后提供给Skia引擎渲染为GPU数据,最后通过OpenGL或者 Vulkan提供给 GPU
      • UI界面绘图流程

        • user Input

          • 用户输入是驱动视图更新的信号 如:滑动屏幕
        • Animation

          • 触发动画进度更新
        • Build

          • 框架开始build抽象视图数据
        • Layout

          • 视图布局
        • Paint

          • 视图绘制
        • Composite

          • 视图合成
        • Restorize

          • 最后进行光栅化处理把数据生成一个个真正的像素填充数据
  • Dart语言(基础)

    • 简介

      • Dart 语言在2011年10月由 Google 发布
      • 是一种 易于学习、 易于扩展、并且可以部署到 任何地方 的 应用 编程 语言
      • 设计的初衷是用来替换javascript的,所以刚开始Dart也就是用来作

为浏览器脚本运行在浏览器中的,但是一直没有被广大开发者重视。

    - Google并没有放弃Dart,又Dart编写孵化了一个移动开发框架Sky,
    - 之后又被命名为Flutter,进入了移动跨平台开发的领域

- 应用方向

    - 移动端开发

        - 核心是Flutter框架,它使用
        - Dart + C++ + Skia 开发,同
        - 一份代码编写运行在 iOS 和
        - Android 上的应用

    - 浏览器端

        - 我们用Dart来写Web后,编译器会自动
        - 将Dart文件编译为JavaScript文件进行
        - 运行,只不过我们写的语法规范是Dart语法

    - 服务器端

        - DartVM :就是写服务端的应用。比如写个
        - http 的服务,对应用提供 api ,都是及其简单的事情。

- 环境配置

    - 手动安装

        - 下载地址:http://www.gekorm.com/dart-windows/

    - 配置环境变量

        - 将dart-sdk的bin路径添加到path环境变量中

    - 在vscode中安装Code Runner插件,来调试我们的dart代码
    - 安装stagehand

        - pub global activate stagehand

    - 创建dart项目

        - stagehand dart-demo

    - 获取依赖包

        - pub get

- 常用内置类型

    - String

        - Dart 字符串是 UTF-16 编码的字符序列,可以使用单引号或者双引号来创建字符串
        - 可以使用三个单引号或者双引号创建多行字符串对象
        - 可以使用 r 前缀创建”原始raw”字符串
        - 可以在字符串中使用表达式: ${expression},如果表达式是一个标识符,可以省略 {},如果表达式的结果为一个对象,则 Dart 会调用对象的 toString() 函数来获取一个字符串

    - Numbers

        - int : 整数值
        - double : 64-bit双精度浮点数
        - int和double是num的子类

    - Booleans

        - bool对象未初始化的默认值是null

    - Lists

        - Dart中的数组称为List

    - Maps

        - map是一个关联键和值的对象
        - 键和值都可以是任何类型的对象
        - 每个键只出现一次

- 变量声明

    - var

        - 类似于JavaScript中的var
        - 它可以接收任何类型的变量
        - 但最大的不同是Dart中var变量一旦赋值,类型便会确定,则不能再改变其类型
        - Dart本身是一个强类型语言
        - 任何变量都是有确定类型的

    - dynamic

        - dynamic与var一样都是关键词
        - 声明的变量可以赋值任意对象
        - dynamic与Object相同之处在于,他们声明的变量可以在后期改变赋值类型
        - dynamic声明的对象编译器会提供所有可能的组合

    - Object

        - Object 是Dart所有对象的根基类
        - 也就是说所有类型都是Object的子类
        - 包括Function和Null
        - 所以任何类型的数据都可以赋值给Object声明的对象
        - Object声明的对象只能使用Object的属性与方法, 否则编译器会报错

    - final

        - 一个 final 变量只能被设置一次
        - final变量在第一次使用时被初始化
        - 被final或者const修饰的变量,变量类型可以省略

    - const

        - const 变量是一个编译时常量
        - 不能更改

- 函数

    - 函数声明
    - 对于只包含一个表达式的函数,可以使用简写语法
    - 函数作为变量
    - 函数作为参数传递
    - 可选的位置参数
    - 可选的命名参数
    - 参考链接:https://book.flutterchina.club/chapter1/dart.html

- 类class

    - 使用类成员

        - 对象的成员包括函数和数据(分别是方法和实例变量)
        - 你调用一个方法时,你在一个对象上调用它:这个方法可以访问那个对象的函数和数据
        - 使用点(.)引用实例变量或方法
        - 使用?.而不是.为了避免最左边的操作对象为空时出现异常

    - 使用构造函数

        - 可以使用一个创建函数来创建对象
        - 构造函数的名字可以是ClassName或者ClassName.indentifier

    - 构造函数

        - 通过创建一个与其类同名的函数来声明一个构造函数
        - 最常见的构造函数形式——生成构造函数——创建了一个类的新实例
        - this关键词引用到当前的对象

    - 抽象类

        - Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口
        - 抽象类通过abstract 关键字来定义
        - Dart中的抽象方法不能用abstract声明,Dart中没有方法体的方法我们称为抽象方法
        - 如果子类继承抽象类必须得实现里面的抽象方法
        - 如果把抽象类当做接口实现的话必须得实现抽象类里面定义的所有属性和方法
        - 抽象类不能被实例化,只有继承它的子类可以
        - 接口:使用implements关键字,一般使用抽象类定义接口。

- 包管理

    - Dart的软件包管理器是pub。
    - 托管软件包的存储库可以在https://pub.dartlang.org/ 找到
    - 

        - 每个Dart应用程序都有一个pubspec.yaml文件,包含了项目依赖包配置 类似package.json

    - 操作命令

        - pub get:获取应用程序依赖的所有包
        - pub upgrade:将所有依赖项升级到较新版本
        - pub build:构建应用

- 库

    - 自定义库

        - import 'lib/mylib1.dart' as lib1;

    - 系统内置库

        - import 'dart:math';
        - import 'dart:io';
        - import 'dart:convert';

    - pub包管理系统中的库

        - import 'package:dio/dio.dart';
  • Widget与Element

    • 什么是Widget

      • Flutter Widget采用现代响应式框架构建,中心思想是用widget构建你的UI
      • Widget描述了他们的视图在给定其当前配置和状态时应该看起来像什么
      • 当Widget的状态发生变化时, Widget会重新构建UI,Flutter会对比前后变化的不同, 以确定底层渲染树从一个状态转换到下一个状态所需的最小更改
      • Widget的功能是“描述一个UI元素的配置数据”, Widget其实并不是表示最终绘制在设备屏幕上的显示元素,而它只是描述显示元素的一个配置数据
    • Element

      • Flutter中真正代表屏幕上显示元素的类是Element,也就是说Widget只是描述Element的配置数据
    • 基础Widget

      • StatelessWidget

        • StatelessElement 间接继承自Element类,与StatelessWidget相对应
        • StatelessWidget用于不需要维护状态的场景
        • 它通常在build方法中通过嵌套其它Widget来构建UI
        • 在构建过程中会递归的构建其嵌套的Widget
      • StatefulWidget

        • 和StatelessWidget一样,StatefulWidget也是继承自Widget类,并重写了createElement()方法
        • 不同的是返回的Element 对象并不相同
        • StatefulWidget类中添加了一个新的接口createState()
        • createState() 用于创建和Stateful widget相关的状态,它在Stateful widget的生命周期中可能会被多次调用
      • State

        • 一个StatefulWidget类会对应一个State类,State表示与其对应的StatefulWidget要维护的状态
        • State中的保存的状态信息可以

          • 在widget 构建时可以被同步读取
          • 在widget生命周期中可以被改变,当State被改变时,可以手动调用其setState()方法通知Flutter framework状态发生改变,Flutter framework在收到消息后,会重新调用其build方法重新构建widget树,从而达到更新UI的目的
        • 常用属性

          • widget

            • 它表示与该State实例关联的widget实例
            • 由Flutter framework动态设置
          • context

            • StatefulWidget对应的BuildContext
            • 作用同StatelessWidget的BuildContext
        • 生命周期

          • StatefulWidget launched
          • initState

            • 当Widget第一次插入到Widget树时会被调用
            • 对于每一个State对象,Flutter framework只会调用一次该回调
            • 通常在该回调中做一些一次性的操作,如状态初始化、订阅子树的事件通知等
          • didChangeDependencies

            • 当State对象的依赖发生变化时会被调用
          • build

            • 它主要是用于构建Widget子树的
            • 会在如下场景被调用

              • 在调用initState()之后
              • 在调用didUpdateWidget()之后
              • 在调用setState()之后
              • 在调用didChangeDependencies()之后
              • 在State对象从树中一个位置移除后(会调用deactivate)又重新插入到树的其它位置之后
          • reassemble

            • 此回调是专门为了开发调试而提供的
            • 在热重载(hot reload)时会被调用
            • 此回调在Release模式下永远不会被调用
          • didUpdateWidget

            • 在widget重新构建时
            • Flutter framework会调用Widget.canUpdate来检测Widget树中同一位置的新旧节点,然后决定是否需要更新
            • 如果Widget.canUpdate返回true则会调用此回调
          • deactivate

            • 当State对象从树中被移除时,会调用此回调
          • dispose

            • 当State对象从树中被永久移除时调用
            • 通常在此回调中释放资源
          • StatefulWidget destoryed
      • 基础组件

        • Text

          • Text用于显示简单样式文本,它包含一些控制文本显示样式的一些属性
        • Image

          • Flutter中,我们可以通过Image组件来加载并显示图片,Image的数据源可以是asset、文件、内存以及网络
        • Container

          • Container是Flutter里很常用的容器组件, Container可以创建矩形视觉元素
      • 布局类组件

        • 线性布局

          • Row
          • Column
        • 弹性布局

          • Flex
        • 流式布局

          • Wrap
          • Flow
        • 层叠布局

          • Stack
          • Positioned
        • 对齐与相对定位

          • Align

Weex

小程序

快应用

ionic

  • 简介

    • ionic是一个用来开发混合手机应用的,开源的,免费的代码库
    • 可以优化html、css和js的性能,构建高效的应用程序
    • 可以用于构建Sass和AngularJS的优化
  • 特点

    • 具有原生APP的卓越运行性能
    • 可维护性高
    • 漂亮的Ui设计
    • 轻量级框架
    • 具有强大的命令行工具
    • 与AngularJS完美结合
  • 框架结构

    • CSS框架

      • 提供原生App质感的CSS样式模拟
      • ionic这部分的实现使用了ionicons图标样式库
    • JavaScript框架

      • 提供移动Web应用开发框架
      • ionic基于AngularJS基础框架开发
      • 遵循AngularJS的框架约束
      • ionic使用AngularJS UI Router实现前端路由
    • 命令行/CLI

      • 命令行工具集用来简化应用的开发、构造和仿真运行
      • ionic命令行工具使用了 Cordova,依赖于平台SDK(Android & iOS)实现将移动web项目打包成原生app
  • 基本布局

  • 交互通信

Cordova

  • 简介

    • Cordova提供了一组设备相关的API
    • 通过这组API,移动应用能够以JavaScript访问原生的设备功能,如摄像头、麦克风等
    • Cordova还提供了一组统一的JavaScript类库,以及为这些类库所用的设备相关的原生后台代码
    • Cordova支持如下移动操作系统:iOS, Android,ubuntu phone os, Blackberry, Windows Phone, Palm WebOS, Bada 和 Symbian
  • 架构

    • Web APP端

      • config.xml

        • CLI初始化项目在主目录下生成
        • 包含了整个app的一些基本信息

          • appName
          • app入口文件
          • 白名单
          • webview初始化的一些配置
          • plugin信息
          • 图标资源信息
      • Resources
      • HTML、JS、CSS
      • cordova.js核心代码

        • exec

          • 这是cordova 中js端的核心执行代码,所有的plugin的执行入口
          • successCallback -- 成功的回调
          • failCallback -- 失败的回调
          • service -- 所调用native plugin的类
          • action -- 所调用native plugin的类下的具体method
          • actionArgs -- 具体参数
        • pokeNative

          • JS通知Native调用native方法
          • 通过Webview相关协议拦截前端URL
          • JS端通过iframe发送request的相关请求
        • nativeCallback

          • native处理完前端请求后触发回调的统一入口
          • 以同步的方式来触发native -> js 的callBack
        • callbackFromNative

          • JS执行回调的地方
          • 根据cordova.callBacks的map以及回调的callBackId 还有状态(success 或者 fail)来执行相应的回调函数
          • 之后根据keepCallback来决定是否将该回调从callBacks的map中移除
    • Native端

      • cordova webview 引擎具体实现

        • CDVViewController

          • init --- 初始化程序
          • loadSettings --- 解析config.xml 将pluginsMap startplugin settings startPage等变量初始化到容器controller中,初始化plugin字典
          • viewDidLoad --- 先loadSettings,之后创建特殊存储空,根据CDVUIWebViewEngine初始化Webview,然后获取appURL加载index.html
        • CDVUIWebViewEngine

          • initWithFrame --- 创建webview
          • pluginInitialize --- 初始化webView中的一系列设置,创建delegate(CDVUIWebViewDelegate)
          • getConmmandInstance --- 获取command的实例
      • 容器初始化以及plugin初始化

        • Acceleromter
        • Geolocation
        • Carmera
        • Media
        • Device
        • Network
        • Contacts
        • Storage
  • JS&Native通信

    • 通信原理

      • 保存Cordova_plugin.js的 插件文件名字和地址
      • 插件的API呼出时,通过调用Cordova的exec模块将API的参数保存在CommandQueue的队列中。 CALLBACK则保存在JS侧的callbacks map里面
      • 添加一个空的iframe,iframe的src则指向gap://ready
      • 3的iframe的src设置以后,NATIVE侧UIWebviewDelegate#shouldStartLoadWithRequest则被呼出来
      • Webview的Delegatet判断gap://ready的情况下,则执行commandDelegate的处理
      • commandDelegate则从JS侧取出API的参数,内部实现则是通过 UIWebview#stringByEvaluatingJavaScriptFromString的返回值 取得CommandQueue里面的参数转换成JSON数据
      • 根据6的插件,执行NATIVE定义的插件实例
      • 插件中,有CALLBACK的情况下,成功失败的结果通过UIWebview#stringByEvaluatingJavaScriptFromString执行JS,JS端则根据传过来的CALLBACKID,从callbacks map取出回调函数并执行
    • 通信方式

      • iframe的方法(默认)
      • xmlHttpRequest的方法(iOS5.x版本因为 -webkit-scroll的IFRAME有BUG,则推荐使用)
  • 插件导入流程

    • Native

      • APP启动,MainViewController初始化之时,queue和command的DELEGATE初期化
      • config.xml文件解析,插件名设置到数组,插件文件和插件名设置到pluginMap,属性设置到setting
      • 在Webview类里面,加载index.html,index.html里面加载cordova.js、开始初期化
    • JS

      • 加载cordova.js时、内部的事件设置模块,NATIVE交互模块,初期化模块,插件加载
      • 插件模块是cordova_plugins.js文件定义的插件文件地址,文件名保存的MAP
      • deviceready事件发布后,插件的API可以使用了
      • 插件API执行后,模块MAP将插件文件加载,执行exec函数
      • 在index.html里面添加一个空的iframe、指定data-original=gap://ready,通知到Nativie

PWA

WebAssembly

Electron

VasSonic

QT

性能优化和监控

性能优化(基础)

  • 内容层面

    • DNS解析优化

      • DNS缓存
      • 减少DNS查找
      • keep-alive
      • 适当的主机域名
    • 避免重定向
    • 切分到多个域名
    • 杜绝404
  • 网络传输阶段

    • 减少传输过程中的实体大小

      • 缓存
      • cookie优化
      • 文件压缩
    • 减少请求的次数

      • 文件适当的合并
      • 雪碧图
    • 异步加载
    • 预加载、延后加载、按需加载
  • 渲染阶段

    • js放底部,css放顶部
    • 减少重绘和回流
    • 合理使用Viewport 等meta头部
    • 减少dom节点
    • BigPipe
  • 脚本执行阶段

    • 缓存节点,尽量减少节点的查找
    • 减少节点的操作(innerHTML)
    • 避免无谓的循环,break、continue、return的适当使用
    • 事件委托

大前端时代监控

  • 大前端时代前端监控的新变化

    • 大前端时代有哪些变化

      • 首先是Gmail的横空出世,开启了SPA的时代
      • Backbone/Angular等框架带来了MVVM模式的同时,也把JS从脚本语言提升到了工程语言
      • React Native/Weex把移动端开发从Hybrid模式进化到了跨端开发模式
      • Node.js问世为前端带来了更多的可能性
    • 前端变化给监控带来了什么样的改变

      • 传统监控模式能否适用于新的技术?比如PV统计
      • SPA模式下首屏如何计算?
      • 跨端开发给监控带来什么什么挑战?
      • 前端监控的上报模式在Node.js端是否合理?
    • SPA模式下的PV统计问题

      • 技术升级、体验升级、PV下降?
      • 原因

        • 页内路由代替了新的页面
      • 解决办法

        • hash路由:监听hash change变化上报PV
        • 非哈希路由:轻量hack pushState和replaceState
    • 首屏统计

      • 第一阶段:自定义打点时期

        • 页头和首屏dom分别通过 new Date()打点
        • 计算差值作为首屏时间
        • 再加上setTimeout(new Date(), 0)标记首屏可交互时间
      • 第二阶段:W3C标准时期

        • W3C性能小组引入了 Navigation Timing API 帮我们自动,精准的实现了性能测试的打点问题
        • Navigation Timing API

          • 卸载上一个页面
          • 重定向
          • 应用缓存
          • DNS域名解析
          • TCP链接
          • 请求页面
          • 响应
          • 页面处理
          • 触发load事件
      • 第三阶段:SPA盛行导致W3C标准失去原来的意义
      • 现阶段:用户感官指标FMP

        • first meaning paint
        • 主要内容可见时间
  • 前端监控的最佳实践

    • 主动监控

      • 配置告警规则
      • 通过错误聚类模块,精准定位问题
      • 增加性能样本分布统计
      • 再手起刀落,修复bug
    • 慢会话追踪
    • 搜索报错明细
    • 出错行为还原
  • 58北斗监控实现
查看原文

赞 19 收藏 18 评论 0

似水流年 关注了用户 · 1月27日

浅夏晴空 @qianxiaqingkong

基于移动端技术的一些探索反思总结及讨论

关注 492

似水流年 收藏了文章 · 1月18日

2020最新:100道有答案的前端面试题(上)

网上的面试题一大堆,鱼龙混杂,一方面多数题目质量不高,另一方面有答案的很少,即使拿到面试题对自己的帮助也不大。

最近我花了一些时间,为大家整理了2020年各一、二线互联网公司的前端面试题,内容包括JavaScript、算法、网络&安全、Vue、React等大量的前端知识点和相关面试题。答案和解析也整理在文中了,整理不易,麻烦各位走过路过的壮士给颗star,如果可以star fork watch三连更好,感谢😄 🙏

因篇幅太长,本文收录前50道,后50道将在下篇更新,欢迎关注。

173382ede7319973.gif

1.写一个 mySetInterVal(fn, a, b),每次间隔 a,a+b,a+2b 的时间,然后写一个 myClear,停止上面的 mySetInterVal

公司:头条

分类:JavaScript

答案&解析

2.合并二维有序数组成一维有序数组,归并排序的思路

公司:头条

分类:算法

答案&解析

3.斐波那契数列

公司:腾讯、CVTE、微软

分类:算法

答案&解析

4.字符串出现的不重复最长长度

公司:腾讯

分类:算法

答案&解析

5.介绍chrome 浏览器的几个版本

公司:滴滴

分类:网络&安全

答案&解析

6.React 项目中有哪些细节可以优化?实际开发中都做过哪些性能优化

公司:滴滴、掌门一对一、网易、有赞、沪江、喜马拉雅、酷家乐、快手

分类:React

答案&解析

7.react 最新版本解决了什么问题 加了哪些东西

公司:滴滴

分类:React

答案&解析

8.说一下 Http 缓存策略,有什么区别,分别解决了什么问题

公司:滴滴、头条、网易、易车、脉脉、掌门一对一、虎扑、挖财、爱范儿

分类:网络&安全

答案&解析

9.介绍防抖节流原理、区别以及应用,并用JavaScript进行实现

公司:滴滴、虎扑、挖财、58、头条

分类:JavaScript、编程题

答案&解析

10.前端安全、中间人攻击

公司:滴滴

分类:网络&安全

答案&解析


前端刷题神器

扫码进入前端面试星球🌍,解锁刷题神器,还可以获取800+道前端面试题一线常见面试高频考点

173382ede7319973.gif


11.对闭包的看法,为什么要用闭包?说一下闭包原理以及应用场景

公司:滴滴、携程、喜马拉雅、微医、蘑菇街、酷家乐、腾讯应用宝、安居客

分类:JavaScript

答案&解析

12.css 伪类与伪元素区别

公司:滴滴

分类:Css

答案&解析

13.有一堆整数,请把他们分成三份,确保每一份和尽量相等(11,42,23,4,5,6 4 5 6 11 23 42 56 78 90)

公司:滴滴

分类:算法

答案&解析

14.实现 lodash 的_.get

公司:滴滴

分类:JavaScript

答案&解析

15.实现 add(1)(2)(3)

公司:滴滴

分类:JavaScript

答案&解析

16.实现链式调用

公司:滴滴

分类:JavaScript

答案&解析

17.React 事件绑定原理

公司:滴滴、沪江

分类:React

答案&解析

18.类数组和数组的区别,dom 的类数组如何转换成数组

公司:海康威视

分类:JavaScript

答案&解析

19.webpack 做过哪些优化,开发效率方面、打包策略方面等等

公司:滴滴、快手、掌门一对一、高思教育

分类:工程化

答案&解析

20.说一下事件循环机制(node、浏览器)

公司:滴滴、伴鱼、高德、自如、虎扑、58

分类:Node、JavaScript

答案&解析

21.如何封装 node 中间件

公司:滴滴、酷狗

分类:Node

答案&解析

22.node 中间层怎样做的请求合并转发

公司:易车

分类:Node

答案&解析

23.介绍下 promise 的特性、优缺点,内部是如何实现的,动手实现 Promise

公司:滴滴、头条、喜马拉雅、兑吧、寺库、百分点、58、安居客

分类:JavaScript、编程题

答案&解析

24.实现 Promise.all

Promise.all = function (arr) {
  // 实现代码
};

公司:滴滴、头条、有赞、微医

分类:JavaScript、编程题

答案&解析

25.React 组件通信方式

公司:滴滴、掌门一对一、喜马拉雅、蘑菇街

分类:React

答案&解析

26.redux-saga 和 mobx 的比较

公司:掌门一对一

分类:React

答案&解析

27.说一下 react-fiber

公司:头条、滴滴、菜鸟网络、挖财、喜马拉雅

分类:React

答案&解析

28.手写发布订阅

公司:滴滴、头条

分类:JavaScript

答案&解析

29.手写数组转树

公司:滴滴

分类:JavaScript

答案&解析

30.手写用 ES6proxy 如何实现 arr[-1] 的访问

公司:滴滴

分类:JavaScript

答案&解析

31.请写出下面代码执行的的结果

console.log(1);
setTimeout(() => {
  console.log(2);
  process.nextTick(() => {
    console.log(3);
  });
  new Promise((resolve) => {
    console.log(4);
    resolve();
  }).then(() => {
    console.log(5);
  });
});
new Promise((resolve) => {
  console.log(7);
  resolve();
}).then(() => {
  console.log(8);
});
process.nextTick(() => {
  console.log(6);
});
setTimeout(() => {
  console.log(9);
  process.nextTick(() => {
    console.log(10);
  });
  new Promise((resolve) => {
    console.log(11);
    resolve();
  }).then(() => {
    console.log(12);
  });
});

分类:JavaScript

答案&解析


173382ede7319973.gif

31.写出执行结果

function side(arr) {
  arr[0] = arr[2];
}
function a(a, b, c = 3) {
  c = 10;
  side(arguments);
  return a + b + c;
}
a(1, 1, 1);

分类:JavaScript

答案&解析

32.写出执行结果

var min = Math.min();
max = Math.max();
console.log(min < max);

分类:JavaScript

答案&解析

33.写出执行结果,并解释原因

var a = 1;
(function a () {
    a = 2;
    console.log(a);
})();

分类:JavaScript

答案&解析

34.写出执行结果,并解释原因

var a = [0];
if (a) {
  console.log(a == true);
} else {
  console.log(a);
}

分类:JavaScript

答案&解析

35.写出执行结果,并解释原因

(function () {
  var a = (b = 5);
})();

console.log(b);
console.log(a);

分类:JavaScript

答案&解析

36.写出执行结果,并解释原因

var fullname = 'a';
var obj = {
   fullname: 'b',
   prop: {
      fullname: 'c',
      getFullname: function() {
         return this.fullname;
      }
   }
};
 
console.log(obj.prop.getFullname()); // c
var test = obj.prop.getFullname;
console.log(test());  // a

分类:JavaScript

答案&解析

37.写出执行结果,并解释原因

var company = {
    address: 'beijing'
}
var yideng = Object.create(company);
delete yideng.address
console.log(yideng.address);

分类:JavaScript

答案&解析

38.写出执行结果,并解释原因

var foo = function bar(){ return 12; };
console.log(typeof bar());  

分类:JavaScript

答案&解析

39.写出执行结果,并解释原因

var x=1;
if(function f(){}){
    x += typeof f;
}
console.log(x)

分类:JavaScript

答案&解析

40.写出执行结果,并解释原因

function f(){
      return f;
 }
console.log(new f() instanceof f);

分类:JavaScript

答案&解析

41.写出执行结果,并解释原因

var foo = {
        bar: function(){
            return this.baz;
        },
         baz:1
    }
console.log(typeof (f=foo.bar)());

分类:JavaScript

答案&解析

42.说一下React Hooks在平时开发中需要注意的问题和原因?

答案&解析


43.Vue组件中写name选项有除了搭配keep-alive还有其他作用么?你能谈谈你对keep-alive了解么?(平时使用和源码实现方面)

分类:Vue

答案&解析

44.Vue 为什么要用 vm.$set() 解决对象新增属性不能响应的问题 ?你能说说如下代码的实现原理么?

Vue.set (object, propertyName, value) 
vm.$set (object, propertyName, value)

分类:Vue

答案&解析

45.既然 Vue 通过数据劫持可以精准探测数据在具体dom上的变化,为什么还需要虚拟 DOM diff 呢?

分类:Vue

答案&解析

分类:Vue

答案&解析

46.下面代码输出什么?

for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 1);
}

分类:JavaScript

答案&解析

47.写出执行结果,并解释原因

const num = {
  a: 10,
  add() {
    return this.a + 2;
  },
  reduce: () => this.a -2;
};
console.log(num.add());
console.log(num.reduce());

分类:JavaScript

答案&解析

48.写出执行结果,并解释原因

const person = { name: "yideng" };

function sayHi(age) {
  return `${this.name} is ${age}`;
}
console.log(sayHi.call(person, 5));
console.log(sayHi.bind(person, 5));

分类:JavaScript

答案&解析

49.写出执行结果,并解释原因

["1", "2", "3"].map(parseInt);

分类:JavaScript

答案&解析

50.写出执行结果,并解释原因

[typeof null, null instanceof Object]

分类:JavaScript

答案&解析

前端刷题神器

扫码进入前端面试星球🌍,解锁刷题神器,还可以获取800+道前端面试题一线常见面试高频考点

173382ede7319973.gif


本文首发微信公众号:前端先锋

欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章

欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章

欢迎继续阅读本专栏其它高赞文章:


查看原文

似水流年 发布了文章 · 1月16日

ReactNative自定义车牌号输入框及键盘实现

项目中用到了自定义的车牌号及键盘,按照公司需求做了部分优化处理,现在做个记录,页面展示及效果如下:
在这里插入图片描述

动态使用效果,b站视频

github地址:VehicleTextInput

感谢大佬提供的思路:https://juejin.cn/post/684490...

觉得文章不错的,给我点个赞哇,关注一下呗!
技术交流可关注公众号【君伟说】,加我好友一起探讨
交流群:wayne214(备注技术交流)邀你入群,抱团学习共进步
查看原文

赞 0 收藏 0 评论 0

似水流年 发布了文章 · 1月9日

ReactNative集成个推消息推送

前言

最近项目中需要集成消息推送功能,在以往的项目中都是使用的极光推送方案,现在的公司安卓端使用的是个推消息推送,所以计划在本次使用RN重构项目的过程中也采用了个推方案, 即个推官方提供的推送SDK React Native 插件(支持 Android & iOS)react-native-getui
项目ReactNative版本号:0.63.4

集成

1. 自动添加依赖

yarn add react-native-getui

cd ios
pod install

2.手动添加配置

安卓部分

1.在android/build.gradle中添加maven地址中添加配置
maven {
            url "http://mvn.gt.igexin.com/nexus/content/repositories/releases/"
        }

在这里插入图片描述

2.android目录下,在app/build.gradle中添加如下配置

dependencies中添加依赖

implementation project(':react-native-getui')
3.android--> defaultConfig中添加如下配置
ndk {
            abiFilters "armeabi", "armeabi-v7a", "x86_64", "x86"
        }
        // 配置个推的三个参数
        manifestPlaceholders = [
                    GETUI_APP_ID : "your app id",
                    GETUI_APP_KEY : "your app key",
                    GETUI_APP_SECRET : "your app secret"
                ]

注意:yourAppId/yourAppKey/yourAppSecret 需要去个推官网 注册后,在后台配置获取。

4.在android/app/AndroidManifest.xml 的<application>标签内添加meta-data
<!-- 配置个推的三个参数 -->
      <meta-data android:name="PUSH_APPID" android:value="${GETUI_APP_ID}" tools:replace="android:value"/>
      <meta-data android:name="PUSH_APPKEY" android:value="${GETUI_APP_KEY}" tools:replace="android:value"/>
      <meta-data android:name="PUSH_APPSECRET" android:value="${GETUI_APP_SECRET}" tools:replace="android:value"/>


      <meta-data android:name="MEIZUPUSH_APPID" android:value="" tools:replace="android:value"/>
      <meta-data android:name="MEIZUPUSH_APPKEY" android:value="" tools:replace="android:value"/>

      <meta-data android:name="MIPUSH_APPID" android:value="" tools:replace="android:value"/>
      <meta-data android:name="MIPUSH_APPKEY" android:value="" tools:replace="android:value"/>

      <meta-data android:name="OPPOPUSH_APPKEY" android:value="" tools:replace="android:value"/>
      <meta-data android:name="OPPOPUSH_APPSECRET" android:value="" tools:replace="android:value"/>

      <meta-data android:name="com.vivo.push.app_id" android:value="" tools:replace="android:value"/>
      <meta-data android:name="com.vivo.push.api_key" android:value="" tools:replace="android:value"/>

      <meta-data android:name="com.huawei.hms.client.appid" android:value="" tools:replace="android:value"/>
5.在MainApplication.java的文件里添加以下信息
import com.getui.reactnativegetui.GetuiModule;

@Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
    // 初始化个推模块
    GetuiModule.initPush(this);
    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
  }

ReactNative项目中JS调用代码

class GetuiPush extends Component{

  componentDidMount() {
    this._initGetuiPushListener()
  }

  _initGetuiPushListener = () => {
  //订阅消息通知
    this.receiveRemoteNotificationSub = NativeAppEventEmitter.addListener(
      'receiveRemoteNotification',
      (notification) => {
        switch (notification.type) {
          case "cid":
            console.log('初始化获取到cid', JSON.stringify(notification))
            break;
          case 'payload':
            console.log('payload 消息通知', JSON.stringify(notification))
            break
          case 'cmd':
            console.log('cmd 消息通知', 'cmd action = ' + notification.cmd)
            break
          case 'notificationArrived':
            console.log('notificationArrived 通知到达', JSON.stringify(notification))
            break
          case 'notificationClicked':
            console.log('notificationArrived 通知点击', JSON.stringify(notification))
            break
          default:
            break
        }
      }
    );
  }

  componentWillUnmount() {
  // 移除消息监听
    this.receiveRemoteNotificationSub &&
      this.receiveRemoteNotificationSub.remove();
  }

  render() {
    return null;
  }
}

遇到的问题

按照以上的步骤就可以正常通过个推官网进行推送消息到手机上了,但是。。。
凡是就怕但是,哈哈。 在进行公司项目的业务推送的时候,手机通知栏竟然没有任何反应,没有推送消息文字和声音提示,这就很难受了。
接下来,我开始检查手机的通知设置以及和同事进行测试,发现他的安卓原生项目是可以正常收到推送的,问了后台同事说也没有特别的设置,这。。。
后来看了同事的Android代码,发现这边竟然是使用的个推的透传消息,然后进行的处理。 oh my god!
见招拆招,拜读了个推的官网,是这样介绍透传(自定义消息)和普通消息的区别的。

通知消息和透传

  • 通知消息:

通知展示时效果:响铃、震动、通知是否可清除,下拉大图、长文本。
通知点击后效果:打开应用首页、打开应用内指定页面、打开浏览器指定网页。

  • 透传消息:

即自定义消息,效果由开发者自行管理,个推只负责消息传递,不做任何处理,默认不会在通知栏中展示,开发者需自行处理展示方式或后续动作。

在这里插入图片描述

看了以上说明之后大体明白了, 又和后台同事沟通了一下,确实采用的透传方式,这意味着通过透传方式进行消息推送,如果需要进行用户提示的话,就需要开发者自行实现了。

ReactNative处理透传消息

如果需要透传信息通过通知栏提醒用户的话,就相当于本地进行消息推送了。这里可以通过实现原生代码的方式进行处理,也可以使用一些第三方进行处理,这里推荐react-native-push-notification进行处理。
在使用这个库的时候,可能会遇到如下错误提示:
在这里插入图片描述
只需要进行如下设置, 将requestPermissions设置为false:

/**
   * (optional) default: true
   * - Specified if permissions (ios) and token (android and ios) will requested or not,
   * - if not, you must call PushNotificationsHandler.requestPermissions() later
   * - if you are not using remote notification or do not have Firebase installed, use this:
   *     requestPermissions: Platform.OS === 'ios'
   */
  requestPermissions: false,

总结

本文分享到此结束,欢迎大家留言交流技术和职场生活。

觉得文章不错的,给我点个赞哇,关注一下呗!
技术交流可关注公众号【君伟说】,加我好友一起探讨
交流群:wayne214(备注技术交流)邀你入群,抱团学习共进步
查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 55 次点赞
  • 获得 2 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 2 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

注册于 2017-04-20
个人主页被 1.4k 人浏览