Coder Social home page Coder Social logo

learn-books's Introduction

Learn-Books

📖📒读书笔记&书单

😊评分标准

  • 超级超级超级推荐 🌟🌟🌟🌟🌟🌟🌟 (必读必读必读)
  • 超级推荐🌟🌟🌟🌟🌟 (一定要读的)
  • 推荐🌟🌟🌟🌟 (可以读的)
  • 一般🌟🌟🌟 (可读可不读的)
  • 还行🌟🌟 (不建议浪费时间读的)
  • 不推荐🌟 (浪费时间的书)

🍓读书笔记

🍒已读书单(技术外)

  • 《精要主义》-格雷戈 麦吉沃恩 -- 推荐🌟🌟🌟🌟 (2020.06)
  • 《你当像鸟飞往你的山》-塔拉 -- 推荐🌟🌟🌟🌟 (2020.05)
  • 《财富自由之路》-博多 舍费尔 -- 超级推荐🌟🌟🌟🌟🌟 (2020.04)
  • 《局外人》-加缪 -- 一般🌟🌟🌟 (2020.03)
  • 《富兰克林自传》-本杰明 富兰克林 -- 超级推荐🌟🌟🌟🌟🌟 (2020.03)
  • 《动物庄园》-奥威尔-- 推荐🌟🌟🌟🌟 (2020.03)
  • 《曾国藩传》-张宏杰-- 超级推荐🌟🌟🌟🌟🌟 (2020.02)
  • 《人生的智慧》-叔本华-- 超级推荐🌟🌟🌟🌟🌟 (2020.02)
  • 《百年孤独》-加西亚 马尔克斯 -- 超级超级超级推荐 🌟🌟🌟🌟🌟🌟🌟 (2020.02超爱的一本)
  • 《小狗钱钱》-博多 舍费尔 -- 推荐🌟🌟🌟🌟 (2020.02)
  • 《半小时漫画经济学》-陈磊 -- 一般🌟🌟🌟 (2020.01)
  • 《谁动了我的奶酪》-约翰逊 -- 推荐🌟🌟🌟🌟 (2020.01)
  • 《杀死一只知更鸟》-哈柏 李 -- 推荐🌟🌟🌟🌟 (2020.01)
  • 《当我谈跑步时,我谈些什么》-树上春树 -- 推荐🌟🌟🌟🌟 (2020.01)
  • 《被讨厌的勇气》-岸见一朗 古贺史健 -- 超级推荐🌟🌟🌟🌟🌟 (2020.01)

书单

  • 技术-前端相关

    JS

    • 《你不知道的JS》(上) -- 超级推荐🌟🌟🌟🌟🌟
    • 《你不知道的JS》(中) -- 超级推荐🌟🌟🌟🌟🌟
    • 《你不知道的JS》(下)-- 一般🌟🌟🌟(相比上中两本,这个有点水了。。)
    • 《 JavaScript高级程序设计》(小红书/红宝书)
    • 《 JavaScript设计模式与开发实践》
    • 《编写可维护的JavaScript》
    • 《JavaScript DOM编程艺术 (第2版)》
    • 《javascript忍者秘籍》

    CSS

    Node

    • 《深入浅出NodeJS》

    Vue

    重构&设计模式&web安全等

  • 思维&学习方法

    • 《从一到无穷大》
    • 《深奥的简洁:从混沌、复杂到地球生命的起源》约翰•葛瑞宾
    • 《只有偏执狂才能生存》
  • 传记

    • 《昂纳德·科恩传记》
    • 《爱因斯坦传》
    • 《本杰明·富兰克林自传》 -- 超级推荐🌟🌟🌟🌟🌟 (2020.03)
    • 《荣格自传》
    • 《约翰逊传》
  • 文学

    • 《达尔文的盲点》-- 弗兰克•雷恩
    • 《自私的基因》
    • 《深奥的简洁:从混沌、复杂到地球生命的起源》
    • 《第三种猩猩:人类的身世与未来》
  • 数学

    • 《什么是数学》
    • 《离散数学及其应用》
  • 物理

    • 《费恩曼物理学讲义》
  • 哲学

    • 《论老年》西塞罗
    • 《人生的智慧》叔本华 -- 超级推荐🌟🌟🌟🌟🌟 (2020.02)
  • 经济学

    • 《穷查理宝典》-- 超级推荐🌟🌟🌟🌟🌟 (2019.10)
    • 《原则》-- 超级推荐🌟🌟🌟🌟🌟 (2020.04)
    • 《彼特林奇的成功投资》-- 超级推荐🌟🌟🌟🌟🌟 (2020.04)
    • 《资本主义的未来》
    • 《穷查理年鉴》
    • 《财富公式:玩转拉斯维加斯和华尔街的故事》
    • 《巴菲特的投资组合》
    • 《聪明的投资者》
  • 心理学

    • 《心理学与生活》
    • 《社会心理学》
    • 《博弈论基础》
    • 《乌合之众》
  • 统计学

    • 《女士品茶:20世纪统计怎样变革了科学》
  • 历史学

    • 《万历十五年》
    • 《枪炮,病菌与钢铁》
  • 神经科学

    • 《追寻记忆的痕迹》
  • 新闻传播学

    • 《华尔街日报是如何讲故事的》

learn-books's People

Contributors

vstar18 avatar

Watchers

James Cloos avatar

learn-books's Issues

📒书单--经济学相关

  • 《穷查理宝典》

其实这不止是一个理财方面的书籍,书中还有很多生活的智慧,是一本全书。

  • 《资本主义的未来》
  • 《穷查理年鉴》
  • 《财富公式:玩转拉斯维加斯和华尔街的故事》
  • 《巴菲特的投资组合》
  • 《聪明的投资者》

美句摘录

  • 愿你有好运气,如果没有,愿你在不幸中学会慈悲。愿你被很多人爱,如果没有,愿你在寂寞中学会宽容。
  • 扔掉四样东西,没有意义的酒局,看不起你的亲戚,不爱你的人,虚情假意的朋友。拥有四样东西,扬在脸上的自信,长在骨子里的善良,融进血液的骨气,刻进生命里的坚强。
  • 人生就像迷舟于海,回不了头,甚至也不知道将要去哪,但这也正是命运的魅力,也并不绝望,世界很大,人生漫长,驶出这片海滩,我们的冒险也许才刚开始。
  • 把疲倦往期 装进质朴的长街;把失败恋爱,藏进路人的详谈;把起舞的今日 写成诗篇;多年后 也不遗憾;把无味春风 融进街边的早餐;把仰头月色 化为潇洒的释然;把漫长的故事 变成短暂 才配得起勇敢;
  • 不要为错过的蛋糕哭泣

《**简史》

中华文明的起源

  • 中华文化的形成很大程度上受其地理因素的影响。

  • 地理原因导致:

  • 与其他三大古老文明交流较少

  • 适合农业文明的发展

    • 特点:

    • 基本上都是边疆地区兴起的新政权推翻原有政权,边缘部族趁中原衰弱入主中原,并继承中原的文化传统。

    • 农业文明导致,年长的人拥有更多的耕种经验,不像西方的航海文明崇尚年轻,发展出弑父。所以发展出家长制,祖先崇拜。

夏商周

  • 周天子以礼治天下,分封制导致了血缘纽带的扩大,但是缺点是随着时间的流逝,血缘关系变淡,**集权被削弱。

春秋与战国

  • 春秋继承了周朝的礼,崇尚儒家**
  • 战国则是春秋的反面,是变法的天下,崇尚法家**

周秦之变,秦始皇统一六国

  • 分封制=》郡县制
  • 血缘原则(家大与国)=》君高于父
  • 小共同体,崇尚人之初,性本善=》大共同体,人与人之前感情淡漠

儒家

  • **:回到过去,西周时代,全面的复古,所以孔子没有著书,做的是传承五书。

《彼特林奇的成功投资》泛读笔记

  • 前情提要
    • 不管是牛市还是熊市,投资优秀的公司都可以让你获得满意的收益

  • 业余投资者的优势
    • 确保你在独立思考,不要为外界的因素干扰,并坚持自己的判断。
      1. 当你决定了依靠自己投资时,你应该努力独立思考。
      2. 意味着只依赖于自己的研究分析进行投资决策,而不要理会热门消息,证券公司的股票推荐,不要看你最喜爱的投资者的投资建议
      3. 如果你在平时的工作场所或者购物中心有一半的警觉,那么你的发现将会远远早于投资专家。
    • 奇妙的10倍股
      • 只要你的投资组合中有一只10倍股,那么你的投资业绩也将大大领先与其他人。
    • 油炸圈和苹果电脑
      • 事实上很多10倍股公司都是大家耳熟能详的公司
      • 油炸圈1年能卖多少的货品,而苹果电脑1年能买多少钱的货品
    • 普通常识的重要性
      • 在正确的时机买入和卖出股票
      • 在日常生活中发现大牛股
      • 发现一个很好的产品时,想一想这家公司是不是上市公司
      • 错过一个大牛股并不重要,你会错过很多,只要抓住你能抓住的那一个就好
      • 购买你熟悉的公司的股票,当你在使用他家的产品(喝咖啡或者试穿丝袜时),你就在做基本面分析
    • 不要投资与你根本不了解的公司
      • 容量为1兆的静态随机存取存储器(onemegabit S-Ram)
      • 互补金属氧化物半导体(complementary metal oxide semiconductor,C-Mos)
      • 双极简化指令系统(bipolar reduced instructive set computor,bipolar risc)
      • 浮点(floating point)
      • 数据输入/输出数组处理器(data I/O array processor)
      • 优化编译程序软件(optimizing compliler)
      • 如果你连这些数据是描述赛马奔跑还是其他的什么都搞不懂的话,最好不要投资这样的股票
      • 这条原则与查理芒格的投资原则相同
    • 椰菜娃娃畅销但股票不一定好
      • 畅销说明有发展潜力
      • 只有发展潜力是第一步
      • 第二步就是全面的分析,这个是一定要做的

  • 投资准备

  • 我是如何成为一个选股者的

    • 一些股票相关的提问
      • 你如何看待股票市场( 2020.05.07回答)
        • 是资本的战场
        • 是有坚毅品质的人才能大杀四方的地方
        • 股票市场风云莫测
        • 永远报有敬畏心
        • 做好风控
        • 不要想理所当然
      • 你对**的上市公司的信任度有多大
        • 一般
      • 你是否需要进行股票投资
        • 是的,我认为未来10年是**逐渐成为新一代大国的机会所在,而其股票市场目前处于相对地位,非常值得投资
      • 你期望从股票投资中得到什么样的投资回报
        • 财富自由,赚1000万
        • 成为像查理芒格,彼特林奇一样的成功投资者
      • 你是短线投资者还是长期投资者
        • 长期
      • 你对某些突如其来的、出乎意料的股价暴跌会如何反应
        • 开始会恐慌,然后分析情况,大多数情况下不会卖出(持有小于1年的情况下),目前我开始持股19年9月16日,第一支股票,比亚迪开始,到现在持续买入12支股票,没有进行卖出行为
      • 确定自己的投资目标,坚持自己的投资信念,否则你会在股票市场低迷时不惜一切抛出所有股票,最终只能成为股票市场的牺牲品。
    • 作者20世纪50年代的经历告诉他,股市难以预测,并且小规模投资者总是在不该悲观时悲观,不该乐观时乐观
    • 逻辑学对股票投资很有用,让作者看清了华尔街特有的不合逻辑性
    • 读到这里感觉作者好强
      • 1969年进入富达
      • 74年研究部经理助理提升为研究部经理
      • 77年掌管麦哲伦基金
      • 也就是说作者紧紧用了8年时间从职场小白晋升为管理者,强
    • 投资建议
      • 不要赌博。
      • 用你所有的积蓄买一些好股票,耐心长期持有,直到这些股票上涨然后才卖掉。
      • 如果一只股票不上涨,那就不要买它
  • 专业投资者的劣势

    • 投资竞争对手
      • 由于上市公司的70%的股票都掌握在专业机构手中,所以当你买卖一家公司的股票时,面临的投资竞争对手是专业投资者的可能性越来越大
      • 在**,目前的现状也是如此吗
    • 专业投资者的滞后性
      • 在先行的体制下,只有大多数的投资机构都认为一直股票适合购买,才可能开始吸引专业投资者的眼光
      • 通常一家小公司跟踪的投资分析师基本没有或者很少,而大公司如IBM则有40多个之多
    • 机构投资的严格限制
      • 事实上,为了保住饭碗,面临以下两种选择时,大多数经理人汇选择第二种
        • 投资不知名的公司有可能大赚一笔
        • 投资知名公司,只有少量的损失
        • 华尔街不成文的规定
          • 如果你购买的是IBM的股票而使客户遭受了小量的损失,那么你永远不会因此丢掉饭碗
          • 一般来说投资经理人一年花费1/4的时间解释自己为何这样投资
          • 客户的资产规模越大,花费说明的时间就越长
          • 投资经理人的独立思考经常会变为群体思考,只投资那些投资推荐列表上的股票,因为和大家选择一样的股票才能保住饭碗
            • 两个人是一对同伙,三个人是一群乌合之众;
    • 机构投资潜规则:洛克菲勒牡蛎
      • 基金管理者买入股票受到各种法律及文件的限制
        • 不可以购买无成长性行业的股票
        • 不能购买名字以“r”开头的公司的股票
        • 共同基金在任何一家上市公司的持股比例不能超过其总股本的10%
        • 对于任何一只股票的投资总额也不能超过基金总资产的5%
        • 基金不能购买任何一家市值低于某一标准的公司的股票,比如说市值不能低于1亿美元
        • **有类似的规定吗
    • 业余投资者要独立投资
      • 如果找不到基本面良好,十分具有吸引力的股票,可以不投资
  • 股票投资是赌博吗

  • 进入股市前的自我测试

  • 不要预测股市


  • 寻找10倍股

    • 最佳的办法就是在身边寻找,你家附近或者你工作的附近,大型购物中心
    • 对病人来说最好的药是那种药到病除,一次性根治的药,对于投资者来说,最好的药是病人需要不断购买的常用药
    • 判断一只股票会不会上涨不需要了解全部信息,但有重要的两点需要知道
      1. 一般来说石油专家比医生在买卖石油股票上有更大的优势
      2. 医生在医药股上的投资比石油专家有更大的优势
    • 你应该寻找这样的公司
      • 每股股票的资产价值超过了每股股票的市场价格
  • 6种类型公司股票

    • 无论你是怎样注意到一支股票的,在商场,在办公场所,从亲戚处听说,这只是一个开始
    • 不做研究就投资就如同不看牌就玩梭哈牌一样
    • 即使已经买入了股票,再对这家公司进行仔细分析研究也是必要的
    • 如果你因为一个产品很受欢迎而要购买这家公司的股票
      • 第一件事:判断这个产品对这家公司的净利润影响有多大
      • 例子:帮宝适纸尿裤很受欢迎,是宝洁公司的产品,但在宝洁公司的销售收入中,其销售收入只占很小一部分
      • 另外一种情况是,销售收入只占6%,但是利润却接近公司利润的50%
    • 公司越大,涨幅越小
      • 大公司,很难有几年上涨10倍的可能,即使它做的很好
      • 相同条件下,投资小公司可以获得更好的回报
    • 注意到这家公司后的第二步
      • 判断该公司在所处行业是一家大公司还是小公司
      • 确定这家公司属于哪种类型
        • 缓慢增长型
          • 通常是规模较大历史悠久的公司
          • 并不是公司一开始就缓慢增长
          • 风行一时的快速增长行业都面临即将增长缓慢的局面(以下是美国的情况)
            • 汽车行业
            • 钢铁
            • 化工
            • 电器设备
            • 计算机(现在计算机也在面临衰退)
        • 稳定增长型
          • 类似可口可乐,宝洁
          • 是否能获利在于你购买的时机和价格
          • 通常情况下,购买这类公司,股票上涨30%-50%,作者就会卖掉
          • 投资组合中应该有这类公司,在经济低迷时期有很大的保护作用
            • 美国百时美公司20年的收入只有一个季度下降
        • 快速增长型(这个是能大有所为的地方)
          • 特点:
            1. 规模小
            2. 新成立不久
            3. 成长性强
            4. 年平均增长率为20%-25%
            5. 不一定属于快速增长行业
              • 增长缓慢的行业中可以通过抢占竞争对手的市场份额
          • 寻找资产负债表良好又有着实实在在丰厚利润的公司快速增长型公司
        • 周期型

        • 隐蔽资产型
          • 隐蔽资产可能十分简单
            • 只是一大堆现金
            • 有时隐蔽资产则是房地产
          • 这些未被华尔街注意到的资产可能隐蔽在
            • 金属、
            • 石油、
            • 报纸、
            • 专利药品、
            • 电视台中,
            • 曼哈顿的航空权
            • 甚至隐藏在公司的债务中
              • 抵扣所得税的巨额亏损
        • 困境反转型
          • 尽管有些公司未能困境反转会让投资者赔钱,但偶然几次的成功使得对于困境反转型公司的投资非常激动人心,并且总体而言投资这类公司股票的投资回报非常丰厚。
      • 增长速度的判断
        • 相对于国民经济的增长速度
      • 一家公司不会一直是某一种类型
        • 因为公司的增长率不会保持不变
      • 不同类型的股票区别对待
        • 当你所购买的是一家有潜力发展成为另一个沃尔玛的年轻公司的股票,这家快速增长型公司有机会给你带来10倍的高回报,而你却把这家新公司当做稳定增长型公司并且仅仅为了兑现50%的回报就卖掉这只股票是十分愚蠢的。
        • 从另一方面来说,当Ralston Purina的股价已经翻了一番并且公司基本面看起来已经不再那么令人激动时,如果你还指望这只股票再次翻番而继续持有,那你肯定是疯了。
  • 13条选股原则

    • 前情提要
      • 如果你懂得一家公司的基本业务的话,那么对这家公司进行深入分析就容易多了。
      • 正是因为这个原因,我宁愿购买连裤袜公司的股票也不愿购买通信卫星公司的股票,宁愿购买连锁汽车旅馆公司的股票也不愿购买光纤公司的股票。
      • 公司业务越简单易懂我就越喜欢。
      • 当有人说:“这样的公司连傻瓜都能经营管理”时,这反而让我更加喜欢这家公司,因为或早或晚都有可能将会是一个傻瓜来经营管理这家公司
    1. 公司名字听起来枯燥乏味,甚至可笑则更好
      • 自动数据处理公司(Automatic Data Processing)就是一个很好的例子。
    2. 公司业务枯燥乏味
      • 当一家公司不仅名字枯燥乏味,而且经营的业务也枯燥乏味时,我却会感到非常兴奋
      • 业务和名称都枯燥乏味的公司保证能够避开华尔街那些所谓专业投资者们的关注,直到最后他们才发现各种利好消息,这才促使他们买入这种类型公司的股票,从而进一步推升股价。
    3. 公司业务令人厌恶
      • 比只是业务枯燥乏味的公司股票更好的是业务既枯燥乏味又令人厌恶的公司股票
      • 会导致证券分析师不会写这样公司的分析报告,进而列入买入名单
    4. 公司从母公司分拆出来
      • 大型母公司不愿看到分拆的子公司陷入困境,因为这会使母公司受到不利的公众影响
        • 因此,分拆出去的子公司通常具备十分良好的资产负债表
        • 从母公司中独立出来,它的管理人员就能够自由地大展手脚,他们能够进一步削减成本,采用富有创造性的改革措施来提高短期和长期盈利水平
      • 如果你听说某公司进行了分拆,或者如果你分配到一些新独立出来的子公司的股票,你应该马上研究一下是否应该再多买一些这种股票
      • 分拆完成一两个月后,你可以查看一下新公司的管理人员和董事这些内部人士中是否有人在大量购买自家公司的股票,如果有这种情况的话就表明他们对新公司的发展前景非常看好
    5. 机构没有持股,分析师不追踪
      • 这种情况频繁发生在银行、储蓄和贷款协会以及保险公司上,这是因为这类公司有好几千家之多,而华尔街却只追踪关注其中的50~100家公司。
      • 曾风光无限后来又被专业投资者打入冷宫的股票
      • 机构持股的数据资料????从哪里获得
    6. 公司被谣言包围:据传与有毒垃圾或黑手党有关
      • 很难想象有比垃圾处理业更完美的行业了
      • 因为它有着两个让人难以想象的传闻
        • 一是处理有毒垃圾
        • 二是受黑手党控制
    7. 公司业务让人感到有些压抑
      • SCI公司经营的恰恰是丧葬服务业务
    8. 公司处于一个零增长行业中
      • 在增长率为零的行业,特别是让人厌烦和压抑的行业中,你根本不用担心竞争的问题
      • 投资高增长行业没有什么刺激之处,除了看到这个行业的股票大跌以外
    9. 公司有一个利基
      • 利基指那些被市场中的**者/有绝对优势的企业忽略的某些细分市场
      • 无论如何夸大排他性的独家经营权对于一家公司或者公司股东们的价值也不过分
      • 一旦你在任何一种产品上获得了排他性的独家经营权,你就可以提高价格
      • 联合出版公司拥有一个利基,而《泰晤士镜报》(Times Mirror Company)公司却拥有好几个利基,其中包括《洛杉矶时报》(Los Angeles Times)、《每日新闻》(Newsday)、《哈特福德新闻报》(Hartford Courant)和《巴尔的摩太阳报》(Baltimore Sun)。甘尼特公司旗下拥有90家日报,并且它们中的大多数都是当地最大的日报
      • 医药公司和化学公司也都有自己的利基——其他公司不能仿制生产与它们完全相同的专利产品。
      • 拥有家喻户晓的著名品牌就几乎相当于拥有利基
        • 如美国惠氏公司生产的销量第一的止咳药惠菲宁(Robitussin)
        • 美国强生公司生产的感冒药泰诺(Tylenol)
        • 可口可乐
        • 万宝路
    10. 人们要不断购买公司的产品
      • 我宁愿购买生产药品、软饮料、剃须刀片或者香烟的公司的股票,也不愿购买生产玩具的公司的股票
    11. 公司是高技术产品的用户
    12. 公司内部人士在买入自家公司的股票
      • 当公司管理层持有公司股票时,那么如何更好地回报股东就成了管理层最优先考虑的事情
      • 这也正是为什么我更喜欢7位副总裁各自买入了1000股自家公司股票的公司,而不是只有总裁一个人买入了5000股自家公司股票的公司。
      • 公司内部人士卖出自家公司的股票通常没有什么意义,因而对此做出反应就会很愚蠢
        • 如果一只股票的价格从3美元涨到了12美元,并且有9位该公司管理人员都在卖出股票,我就会对此加以关注,特别是当他们卖掉自己持有的大部分股票时
    13. 公司在回购股票
  • 我避而不买的股票

    • 避开热门行业的热门股(我现在正在走在相反的路上。。。)
      • 避开的原因
        • 热门股票上涨得很快,总是会上涨到远远超过任何估值方法能够估计出来的价值
        • 但是由于支撑股价快速上涨的只有投资者一厢情愿的期望
        • 而公司基本面的实质性内容却像高空的空气一样稀薄
        • 所以热门股跌下去和涨上来的速度一样快
    • 小心那些被吹捧成“下一个”的公司
      • 下一个IBM、下一个麦当劳、下一个英特尔
      • 当人们把某一只股票吹成是下一个什么股票时,这表明不仅作为后来模仿者的这家公司的股票气数已尽,而且那只被追随的楷模公司也将要成为明日黄花。
    • 避开“多元恶化”的公司
      • 不是把赚来的钱用于回购股票或者提高分红,而是更喜欢把钱浪费在愚蠢的收购兼并上
        • 特点
          • 收购价格过于高估
          • 经营业务完全超出人们的理解范围
        • “多元化”的最终结果变成了“多元恶化”
        • 这并不是说凡是收购都是愚蠢的。在自家公司基本业务非常糟糕的情况下进行收购另寻发展之道就是一个非常好的策略
          • 协同作用是“把相关的业务组合成一个整体并使整体比部分运作得更好”,
    • 当心小声耳语的股票
      • 我总是尽量提醒自己(显然往往并不成功),如果公司的前景非常美好,那么等到明年或者后年再投资仍然会得到很高的回报
      • 为什么不能暂时不投资,等到公司有了良好的收益记录可以确信其未来发展很好时再买入它的股票呢?
      • 当公司用业绩证明自己的实力以后,仍然可以从这只股票上赚到10倍的回报,当你对公司的盈利前景有所怀疑时,看一段时间再做投资决定也不迟
    • 小心过于依赖大客户的供应商公司股票
      • 如果一家公司把25%~50%的商品都卖给了同一个客户,这表明该公司的经营处于十分不稳定的状态之中
  • 收益 收益 还是收益

    • 你要问的根本问题是:是什么因素使一家公司具有投资价值
    • 为什么这家公司的未来价值会比现在高
      • 最终还是归结为两点
        • 收益(更为重要的一个)
        • 资产
    • 资产减去负债后所得的结果为正数,就是你的净资产,或者是账面价值,或者财富净值
    • 股票的价格线与收益线的波动是并驾齐驱的,如果股票价格线的波动偏离了收益线,它迟早还会回到与收益线一致的趋势上
    • 判断股票价格是不是被高估的快捷方法就是比较股票价格走势线与收益线是否相符
  • 下单之前沉思2分钟

    • 如果公司只有成功的可能而事实上还没有做到非常成功,那么就根本不要购买他们的股票
    • 因为内部人士卖掉一只股票就否定这只股票是一个非常愚蠢的理由
  • 如何获得真实的公司信息

    • 经纪人
      • 年报
        • 阅读年报
          • 资产负债表
            • 流动资产中的现金资产(现金及现金等价物)
      • 季报
      • 招股说明书
    • 给上市公司打电话
    • 去上市公司拜访
      • 公司高级管理人员把办公室装饰得非常豪华之日,就是投资者应该为这家公司的收益开始忧心之时
    • 做一些实地调查研究
  • 一些重要的财务分析指标

    1. 某种产品在销售额中占的比例

    2. 市盈率

      • 不要买入过高市盈率的股票
        • 多少算高呢?
    3. 现金头寸

    4. 负债因素

      • 对于困境反转型公司和陷入困境的公司,很重要
      • 在危机之时,是负债而不是其他任何因素最终决定公司是否能够幸免于难还是破产倒闭
      • 长期负债好于短期负债
    5. 股息

      • 派发股息,并逐步提升的公司具有抗跌性
    6. 账面价值

      • 公司财务报告上的账面价值往往与公司的实际价值没有什么关系,账面价值经常严重高估或者低估了公司的真实价值
      • 当你为了账面价值而购买一只股票时,你必须仔细考虑一下那些资产的真实价值是多少
    7. 隐蔽资产

      • 账面价值也经常会低估公司资产的真实价值,而在这种公司的股票之中你可能会找到隐蔽资产型大牛股
      • 有时投资一家美国上市公司的最好方法就是投资这家上市公司的外国股东公司
    8. 现金流量

      • 指一家公司从业务经营中获得的现金流入超过现金流出的净流入数量
      • 很多人用现金流量对股票进行估值。
        • 如果一只股票为每股20美元,每股现金流量是2美元,那么它的市价现金流量比率就是10∶1,这是一个正常水平的标准比率
        • 如果一只股票为每股20美元,每股现金流量为4美元,那么现金收益率就是20%,这简直太棒了
        • 如果你发现一只股票为每股20美元,而每股现金流量为10美元,那么你应该把房屋进行抵押借款,把你所有的钱都押到这只股票上,能买多少就买多少,这种情况下大赌肯定能够大赢。
    9. 存货

      • 其中有一条关于存货情况的详细附注,我总是会仔细阅读一下这个附注,看看公司是否存在存货积压的现象
        • 当存货增长速度比销售增长速度更快时,这就是一个十分危险的信号了
  • 定期重新核查公司分析

  • 股票分析要点


  • 构建投资组合
  • 买入和卖出的最佳时机选择
  • 12种关于股价的最愚蠢且最危险的说法
  • 期权,期货与卖空交易
  • 5万个专业投资者也许都是错的

《曾国藩传》-张宏杰

中华古代文明实践者的标杆。

记忆里有很多名人提过要多读伟人传记,一直放在心上却未行动。这是第二次读传记,第一本是沈从文先生的,几乎是一口气读完此书,一天多一点的时间,读的心潮澎湃,久久不能平静。

在此书中作者曾说曾国藩资质平平,考秀才考了七次,我实在不能认同。从他的生平事迹中我了解到的是,他其实是有着成为一代伟人的所有条件的人。

  • 一,有恒
    其实我觉得大多数人都高看了聪慧的重要性,低估了坚毅品质的重要性,水滴石穿,曾国藩正式靠着坚持不懈的坚持自己的品行,**才有了盛世之名。

  • 二,忍
    纵观曾国藩的一生,他所经历的打击,所处的境遇非常人所能。而这些经历都没能杀死他,凡不能杀死他的必使他强大,忍常人之所不能忍。这是他身上最强大的品质之一。

  • 三,反省
    青年时期的曾国藩是傲然不可一世的,总觉得别人不行,与人交总不自觉带着鄙视之意,因此常树政敌,但并不觉得是自己不对,好在命运此时恰好的给予打击,使曾国藩认识到了自己的问题,并且真正的通过日记不断的反省,改变自己。

  • 四,平衡
    曾国藩个人是个真正的节俭之人,衣食住行皆从简,然而在当时的官场风气中,他又能适当的随波逐流,仅此一点,又有几人能够做到。有的人要么就是一生清廉的路如海瑞,最后处处被打击,无法做真正惠民之事,有的人要么就有贪婪之路如和珅,处处收敛钱财,置平民百姓国家社稷与不顾,然而曾国藩却能利用现有环境,办大事,放小事。

  • 五,思维的高度,远见
    曾国藩在当时的环境所做之事,在今天看来可能普通如常,然而在当时却是创世之举,第一个认识到中华民族在面对其他民族时应该持有的心态,不是应该自命不凡,与蛮夷相处,而应该平等待之,以诚待之等等

  • 六,时运
    古今中外,成大事者,人定三分,剩七分与天。运气真是一个人一生命运的支配者之一,如果当时有另外一个周瑜,曾国藩的命运是否会被改写。

而你我在读过这本书后又留下了些什么

《你不知道的JS》-中- 异步与性能-Promise

  • 更高级的异步模式
    • 通过上面的信息,我们已经得到了
      • 通过回调表达程序的异步会导致
        • 缺乏顺序性
        • 缺乏可信任行(控制反转)
    • Promise
      • promise所做的事

        • 把控制反转再反转回来
        • 我们不再将自己程序的未来传递给第三方
        • 而是让第三方给我们提供其任务何时结束的能力,然后我们来决定下一步做什么
      • promise类比

        • 在餐厅点餐时,我和服务员说,我要一个汉堡,并支付了1美元。此时已经发生了一个交易,但是我还没有拿到我的汉堡,服务员会给我一个带有订单号的收据。订单号就是一个承诺(Promise),代表着我将来能拿到的汉堡。
        • 当服务员喊到,订单113号时,我去柜台有两种情况
          1. 我拿到了我的汉堡(success)
          2. 服务员告诉我汉堡卖没了(fail)
        • 还有另外一种情况是我的订单号永远不会被叫到
      • promise特性

        • 一旦被决议,就是一个不会被改变的

          • 决议函数resolve(成功)
          • 决议函数reject(失败)
        • 值- promise是一个用来封装和组合未来值的易于复用的机制

        • 如何确定一个值是不是promise

          • p instanceof Promise(promise是由new promise创建的)
            • 问题:当前窗口的promise可能是由iframe传进来的
            • 库和框架可能实现自己的promise而不是ES6的promise
          • 任何具有then方法的函数和对象
            • 任何这样的值就是promise一致的thenable
      • promise信任问题

        • 回顾回调的信任问题(把回调传入工具函数foo)
          • 调用回调过早
          • 调用回调过晚(或者不调用)
          • 多次调用回调
          • 未能传递所需的参数或者环境
          • 吞掉可能出现的异常
      • 链式流

        • promise 的then返回一个promise,因此可以实现链式调用
          • 不管promise的then调用的完成回调返回的值是什么,都会被自动设置为被链接
          function delay(time) {
              return new Promise(function (resolve,reject) {
                  setTimeout(resolve,time)
              })
          }
          delay(1000)
          .then(() => {
              console.log('第二步,1秒之后')
              return delay(2000)
          })
          .then(() => {
              console.log('第三步,2秒之后')
              return delay(3000)
          })
          
      • promise术语

        • 决议resolve

          • 实际结果可能是成功可能是拒绝
          • 传入的是thenable的话,将展开
        • 完成fulfill

        • 拒绝reject

          • 传入的不会展开
        let testResolve =  new Promise((resolve, reject) => {
                resolve(Promise.reject('error'))
            })
        
        testResolve
            .then(function resolve(){
                console.log('不会被执行') 
        
            },function reject(){
                console.log('会被执行,nono') 
            })
        
      • 错误处理

        • 常见的错误处理方式就是try catch

          • 问题是try catch是同步的,无法用于异步操作
          function Bar () {
              setTimeout(() => {
                  throw Error('error')
              },100)
          }
          try{
              Bar();
          }
          catch {
              console.log('不会到达这里')
          }
          
        • 目前的解决方案

          • 回调函数的error-first风格
          • 多数程序员选择Promise后面加一个catch
            • 把错误传递给了链中的下一个promise
            var p = Promise.resolve(42)
            p.then(function fulfill(res){
                console.log(res.toLowerCase())
            })
            .catch((err) => { 
                console.log(err,'----')
            })
            
            • 这句话没读懂!!! 如果handleErrors(..)本身内部也有错误怎么办呢?谁来捕捉它?还有一个没人处理的promise:catch(..)返回的那一个。我们没有捕获这个promise的结果,也没有为其注册拒绝处理函数。你并不能简单地在这个链尾端添加一个新的catch(..),因为它很可能会失败。任何Promise链的最后一步,不管是什么,总是存在着在未被查看的Promise中出现未捕获错误的可能性,尽管这种可能性越来越低
        • 更好的解决方案

          • 这段好难,没看懂
      • Promise模式

        • 前提概要
          • 在异步操作中,在同一时刻,只能有一个异步操作在进行,异步1结束之后才能进行异步2,
          • 如果我需要并行执行异步怎么办呢
          • 在经典的编程术语中,门(gate)是一个所有并发操作都完成才能打开,进行下一步操作的东东
        • Promise.all
          • 参数:数组(通常由Promise实例组成)
          • 返回值:
            • 数组(传入参数的返回结果集合,与传入顺序有关,与完成顺序无关)
            • 主Promise在全部都完成的情况下财完成,如果其中一个失败的话,就会被立即拒绝,其他的Promise结构都被抛弃
          • 小Tips:
            • 参数数组虽然通常由Promise实例组成,但也可以是
              • Promise实例
              • thenable
              • 立即值
            • 每一个参数都被resolve处理为一个Promise
            • 如果是空数组的话,则立即完成
          • 比喻:
            • 跑步比赛
              • 全员都超过终点才算结束
        • Promise.race
          • 前提简介:

            • 类似经典编程中的门阀,只要由一个完成就结束
            • 在Promise中被称为竞态
          • 参数:数组(同Promise.all)

          • 返回值:

            • 一个值(不同于Promise all)
          • 小Tips

            • 参数不可以为空数组,因为是竞赛,为空则将永不会被决议永远不要传递空数组
            • 参数如果是立即值则第一个为结果
              • 比喻:跑步竞赛中站在终点参加竞赛的那个人
          • 比喻:

            • 跑步比赛,取第一名
        • all和race的变体
          • none
            • 与all相反,取所有的reject值
          • any
            • 任何一个
          • first
            • 取第一个完成
            • 和race的区别在哪
          • last
            • 取最后一个完成的值
        • 并发迭代这里不是很懂!!!
          • 类似与数组的forEach,map
          if(!Promise.map){
            Promise.map = function (vals,cb){
                return Promise.all(
                    vals.map(function (val){
                        return new Promise(function (resolve){
                        cb(val,resolve) 
                        })
                    })
                )
            }
          }
          let p1 = Promise.resolve(3);
          let p2 = Promise.resolve(2);
          let p3 = Promise.resolve(1);
          Promise.map([p1,p2,p3],function (val,done){
            console.log(val,'---')
            Promise.resolve(val)
            .then(function (item){
                done(item*2)
            }, done) 
          })
          .then(function (i){
            console.log(i,'----')
          })
          
          
      • Promise API概述

        • new Promise构造器
          • 必须使用new调用
          • 两个参数
            • resolve 可能是成功,可能是失败
              • 传入的是非Promise,非thenable值,用这个值完成
              • 传入Promise,thenable,取其最终的决议状态
            • reject 失败
        • resolve&reject
          • 创建一个已拒绝的Promise是使用Promise.reject
          var p1 = new Promise((resolve,reject) => {
              reject('error')
          })
          var p2 = Promise.reject('error');
          //p1和p2是对等的
          - resolve,传入的如果是Promise,则什么都不会做
          
        • then&catch
          • 每一个Promise都有一个then和catch
            • then有两个参数
              • resolve
              • reject
          • then&catch返回的都是一个Promise,用于链式调用
          • catch相当于then(null,reject)
        • Promise.all&Promise.race
      • Promise的局限性

        • 顺序错误处理
        • 单一值
        • 展开/传递参数
        • 单决议
        • 惯性
        • 无法取消的Promise
        • Promise性能

《你不知道的JS》-上-作用域

  • 什么是作用域

    • 几乎所有程序都提供了一个基本功能:可以储存变量当中的值,并在之后对这个值进行修改和访问
      • 变量储存在哪
      • 程序如何找到他们
    • 一套设计良好的规则来储存变量,并且可以之后很方便的找到这些变量。这套规则就是作用域。
  • 我的理解(比喻法)

    • 比喻法1
      • 采蘑菇
      • 怎样找到蘑菇,如何快速的采集蘑菇,这样的规则就是蘑菇作用域
    • 比喻法2
      • 下象棋
        • 马走日,象走田,卒子一去不回还
        • 在最初的开局,每一个棋子在什么样的地方
      • 这些规则就是棋域(作用域)
  • 编译原理(红色为书中,绿色为默写时的内容)

    • 传统语言中,执行前经历3步,编译一般分为3步,统称为编译
    • 但是js是在执行前进行编辑,它的处理更为复杂(在语法分析和代码生成阶段有特定的步骤来对运行性能进行优化,包括对冗余元素进行优化等进行垃圾处理等),在我们讨论的作用域的基础上,采用了很多方式以提升性能。
      • 传统编译步骤
        • 词法解析
          • 将字符组成的字符串分解为词法法单元token(词法单元是什么样的结构呢)
          • 结构是一个数组
            • var a = 1;
            [
                {
                    "type":"Keyword",
                    "value":"const"
                },
                {
                    "type":"Identifier",
                    "value":"a"
                },
                {
                    "type":"Puntuator",
                    "value":"="
                },
                {
                    "type":"Numeric",
                    "value":"1"
                },
            ]
            
        • 语法解析
          • 根据词法单元流(数组)生成AST树
            • 结构是一个层层包含的对象
            {
                "type":"Program",
                "body":[
                    {
                        "type":"VariableDeclarator",
                        "declartions":[
                            {
                                "type":"VariableDeclarator",
                                "id":{
                                    "type":"Identifier",
                                    "name":"a"
                                },
                                "init":{
                                    "type":"Literal",
                                    "value":1,
                                    "raw":"1"
                                }
                            }
                            
                        ]
                    }
                ]
            }
            
        • 代码生成
          • 将AST转换为程序可以识别的代码
            • 执行前经历3步,
      • 几个重要名次
        • 引擎
          • 从头到尾负责整个JavaScript程序的编译及执行过程。
        • 编译器
          • 引擎的好朋友之一,负责词法&语法分析及代码生成等脏活累活
        • 作用域
          • 引擎的另一位好朋友,负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。
  • 我的理解(比喻法)

    • 把大象装进冰箱需要3步
      • 第一步,打开冰箱门:词法分析=》字符串转换为token流

      • 第二步,把大象塞进去:语法分析=》token流转换为AST树

      • 第三步,关上冰箱门:代码转换=》把AST树转换为程序可以识别的代码

      • 人物:

        • 管家=》引擎:负责全体
        • 女仆=》编译器:负责脏活累活,语法解析和代码生成
        • 客人需求表=》作用域:负责整体规范,哪个人应该做什么,怎么做
      • 具体场景:

        • 主人家召开盛大活动程序运行
        • 由管家主持,女仆干活引擎执行代码,编译器编译代码
        • 女仆根据列出的客人需求表干活,但是客人有可能在或者离开,或者没来,女仆根据查看主人家房子(作用域)来确认哪个服务送到哪个客人的手里,哪个客人的需求不需要做,因为没来等引擎执行代码时,根据作用域查找变量
          • 女仆查看任务(每个客人来之前西欧提出了相应的需求)
            • 寻找客人是否在
              • 两种方式
                • 每一层的客人从左边的房间一间一间查看(LHS:需要找到变量本身)
                  • 从左边查看要进屋里查看
                  • 左边总是更难
                • 每一层的客人从右边的房间一间一间查看(RHS:找到变量的容器就可以)
                  • 从右边查看只在门口看就行了
                  • 如果这个客人没来,那么就直接把做好的饭菜放到主人家的顶楼
  • 作用域分类

    • 两种工作模式
      • 词法作用域(js,包括大部分语言都是词法作用域)
        • 定义在词法阶段的作用域
        • 根据代码编写时的位置确定作用域,词法分析时作用域不变
        • 不过可以欺骗(非严格模式下)
          • eval
            • 接受一个字符串作为参数,并将其中的内容视为好像在书写时就存在于程序中这个位置的代码
          • with
      • 动态作用域
  • 函数作用域和块级作用域

    • 函数声明&函数表达式

      • function foo() {}
    • 函数表达式

      • (function foo(){})()
    • 两者的区别:

      • 只要声明不是以function开头就是函数表达式
      • 标识符绑定的地方不同
        • 函数声明:绑定在所在作用域
        • 函数表达式:函数表达式自身
    • 具名和匿名

      • 函数表达式可以是匿名的
      • 函数声明不可以
      • 匿名缺点
    • js中的块级作用域

      • try/catch 中catch分句会创建一个作用域
      • let
        • let为变量劫持了所在作用域
        • let声明的变量不会在块级作用域中进行提升,声明的代码被运行之前,声明并不存在
      • const
        • 值是固定的
  • 动态作用域

    • 和js的关系
      • 是js的另一重要机制this,的表亲
      • js只有词法作用域,没有动态作用域,但是this的机制和动态作用域很像
    • 定义:
      • 作用域不是根据代码书写时静态确定的,而是在运行时动态确定的
      • 也就是作用域基于调用栈,而不是代码中的作用域嵌套
    • 和词法作用域的区别
      • 词法作用域关注函数在何处声明
      • 动态作用域关注函数从何处调用
  • 我的理解(比喻法)

    • 作用域就是主人家的房子
    • 房子里一层一层的楼层就是作用域嵌套
    • 我国的房子结构有两种类型(作用域工作模式)
      • 钢筋水泥房子(词法作用域/静态作用域)
        • 钢筋水泥结构的房子,在建造时就确定了整体结构(词法作用域在书写代码时确定作用域)
      • 木质构造(动态作用域)
        • 木质的房子(像魔法里面的楼梯可以随时移动那样),灵活,在使用时可以随便怎样移动楼梯(动态作用域在执行时确定作用域)
  • 变量提升

    • 直觉上我们会认为js是从上到下一行一行执行的
    • 但是是错误的
    • 执行前会进行编译
      • 编译阶段中的一部分工作就是找到所有声明,并用合适的作用域将他们关联起来
      • 声明(变量&函数)在编译阶段被处理,其他的逻辑留在原地等待执行
      • 这个过程被形象的称为变量提升
      • 每个作用域都会进行提升操作
      • 函数提升优先与变量提升,也就是说后面的变量名和函数名相同的会被忽略
  • 我的理解(比喻)

    • 主人家每一层楼层里的客人有一些会被优先招待,满足
    • 只有男主人(变量)和女主人(函数)的亲属会有这些特殊待遇
    • 女主人的地位更高,所以优先级最高,后面的如果有相同需求的男主人的亲戚的需求就被一起做了(省了一份力,忽略了)

《你不知道的JS》-中-混合环境javascript

  • 全局DOM变量

    • 我们都知道在一盒函数内直接a = 42的方式声明一个变量时,变量会提升至全局作用域。在浏览器的Window对象上创建一个新变量
    • 特殊的是在页面中已id方式创建的HTML(其他方式的不会)元素也会创建一个全局对象
    <div id="test"></div>
    console.log(typeof test)//'object'
    
  • 原生原型

    • 在开发是我们需要遵循的原则就是
      • 不要在原生原型上添加属性和方法
        • 因为一些成熟的方法会在后续的迭代中添加进来,造成冲突(比如一开始Array的原型上没有push这个方法)
  • <script> - 文件中我们可以使用内联js - 内联的代码中不可以带有字符串的<script></script>
      - 有,则代表结束
      ```
      <script>
          var code = <script>this is inline</script>
      </script>
      //错误的写法
      '<scr' + 'ipt>'//可以采用的解决方案
      ```
    
    • 外部引入js文件
    • 两者共享window全局对象
  • 保留字

    • 关键字:function

    • 预留关键字:在es6中有很多应用,如class extend

    • null

    • 布尔值true&false

    • 保留字可以用作对象的属性名

《你不知道的JS》-中-类型

  • 类型

    • js中的类型和其他强制类型语言不同
    • 很好的理解js中的类型才能处理好js程序中大量出现的强制转换
    • js中持有类型的不是变量,而是值
  • js内置类型

    • 基本类型
      • string
      • number
      • boolean
      • null
      • undefined
        • undefined&undeclered
        var a;
        typeof a //undefined
        typeof b //undefined
        console.log(a) a is undefined
        console.log(b) //ReferenceError b is not defiend
        
        • 两者是不同的,源于typeof的安全防范机制
          • 使用全局变量时
          function test () {
              if(DEBUG){
                  ....
              }
          }
          //如果没有定义,则直接报错不能执行
          function test () {
              if(typeof DEBUG !== 'undefined'){
                  
              }
          }
          //不会报错
          
            - 另一种解决方案是使用window(全局变量都定义在window上,而访问对象上不存在的变量不会报错Reference)
          
          • 使用局部变量时
          (function () {
              var test = function () {
                  if(typeof myUndef !== 'undefined'){
                      
                  }
              }
          })()
          
            - 另一种解决方案是通过显示的传参也是可以的(依赖注入)
          
      • symbol
      • 可以使用typeof检查基本类型(除了null)
    • 引用类型
      • object
        • 子类型
          • array
          • function
            • 可以调用的对象
            • 具有[[call]]属性
          • 内置对象
    • 数组
      • 特性:
        • 数组本质也是对象,所以可以储存除了数字及可以转换为数字以外的键
          • 但是,这样的不算进数组的长度
          var arr = [];
          arr[0] = 1;
          arr['test'] = 2;
          arr.length //1
          
        • 数组空串
          var arr = [];
          arr[0] = 1;
          arr[2] = 2;
          arr.length //3
          arr[1]//undefined,注意此处的undefined与直接给arr[1]赋值为undefined还不一样
          
      • 类数组
        • 解释:js中有这种类数组的存在,不可以使用数组的方法,但是可以通过下标获得值
        • 参数arguments
        • 获得页面的li组
        • 可以通过数组的一些方法转换为数组,indexOf,slice等
        function test(a,b) {
            arguments.map(item => item + '1');//报错
            var argCopy = Array.prototype.slice.call(arguments);
            argCopy.map(item => item + '1');//可以执行
            console.log(argCopy)
        }
        test(1,2);
        
        • es6废弃了argements
        • es6的Array.from()可以达到和slice一样的效果
          • Array.form(arrayLike,mapFn,thisArg) 可以从一个类数组中返回一个新的浅拷贝实例
    • 字符串
      • 引言:字符串有很多数组的特性,被称为字符串数组,他们都是类数组
      • 相同
        • 都有length
        • indexOf
        • concat
        • 特殊:字符串在现代浏览器下(ie6可不行奥)可以使用str[1]来获取,但正确的方式是str.charAt(1)
        var str = 'foo';
        var arr = ['f','o','o'];
        str.length;//3
        arr.length;//3
        str.indexOf('f') // 0
        arr.indexOf('f') //0
        str.concat('test');//footest
        arr.concat(['test'])['f','o','o','test']
        
      • 不同点
        • str是不可变的
        • 因此没有数组的一些可变更方法,如reverse
          • 可以通过将字符串先变为数组调用再转换为字符串实现
          var strReverse = str.split('').reverse().join('');//'oof'
          
        • 没有map,join等方法
          • 这个可以通过借用方式调用
          var strMap =  Array.prototype.map.call(str,(i)=>{
              return i + '.'
          }).join('')
          strMap//'f.o.o.'
          
    • 数字
      • 语法

        • js中的数值类型只有number数字,不区分“整数”和小数,其实JS中没有真正的整数,整数表示没有小数位的数字,42.0 也是整数
          • js中0可以被省略
          • 因此42.0 .42都是正确的书写方式,只是可读性不好不推荐
        • js中数字采用64位二进制双精度浮点数规则
        • 特别大或者特别小的采用指数位
          • toExponential
            • 和E表示方法同等
            var a = 1E5;
            a;//100000
            a.toExponential();//1e+5
            
          • toPrecision//指定有效数位的显示位数
          var a = 42.0;
          a.toPrecision(2);//42
          a.toPrecision(3);//42.0
          
        • 数字值可以使用Number对象进行封装,因此可以使用Number对象上的许多方法
          • toFixed
          • 注意.这个东东,.是一个有效的数字字符,首先被识别为数字字面量中的一部分,然后才是对象属性访问符
          var a = 42.
          a.toFixed(2)//42.00
          42.toFixed(2)//不能执行
          42..toFixed(2)//42.00
          
      • 较小的值

        • 这个就是著名的二进制双精度浮点数的相等问题
          0.1 + 0.2 === 0.3//false
        • ES6中我们可以使用Number.EPSILON,es5的polyfill
        if(!Number.EPSILON){
            Number.EPSILON = Math.pow(2,-52);
        }
        Math.abs(0.1 + 0.2 -0.3) < Number.EPSILON
        
      • 最大的安全范围

        • js中的最大值储存在Number.MAX_VALUE中为2的53次幂-1,最小值储存在Number
      • 整数检测

        • 检测是否为整数,es6中的方法isInteger
        var a = 42.3,b = 42.00;
        Number.isInteger(a)//false
        Number.isInteger(b)//true
        
        • 是否是一个有效的安全整数isSafeInteger
        Number.isSafeInteger(Math.pow(2,53))//false
        Number.isSafeInteger(Math.pow(2,53) -1)//true
        
    • 特殊数值
      • 不是值的值
        • null&undefined
          • null
            • empty value
            • 没有值
            • 是关键字,不是标示符
            • 值即是null
          • undefined
            • misssing value
            • 本应有值
            • 是标示符,不是关键字
            • 值即是undefined
            • 因此可以在非严格模式下被重新定义 undefined = 2
            • 因此建议使用void运算表示undefined void运算不改变表达式的结果,只是没有返回值,因此返回undefined
    • 特殊数字
      • 不是数字的数字--NaN

        • NaN早js中用来表达一个不是数字的数字,但这么说理解不当,应该说是无效数字
        var a = 2 / 'foo';
        var b = 'foo'
        a//NaN
        typeof a //number
        typeof b //string
        a === NaN//false
        a == NaN //false
        a != NaN //true
        
        • NaN仍然是数字
        • NaN 不等于NaN
        • window.isNaN&Number.isNaN
          • 判断一个数字是否是NaN的方式
          • window.isNaN的缺陷
          var a = 'foo';
          var b = 2 / 'foo';
          window.isNaN(a)//true
          window.isNaN(b)//true
          Number.isNaN(a)//false
          Number.isNaN(b)//true
          
      • 无穷数

        var a = 1 / 0;//Infinity即Number.POSITIVE_INFINITY
        var b = -1 / 0; -Infinity即Number.NEGATIVE_INFINITY
        var max = Number.MAX_VALUE;
        max + max;//Infinity
        
      • 零值

        • js中有一个常规的0,即+0
        • 和一个-0
        • 加法和减法运算不会得到-0
        var a = 0 * -3; -0
        var b = 0 / -3; -0
        var c = 0;
        c === a; //true
        
      • 特殊等式

        • Object.is() es6新加入的判断两个值是否相等
        Object.is( 2 / 'foo', NaN);//true
        Object.is(0 * -3, 0);//false
        Object.is(0 * -3, -0);//true
        
    • 值和引用
      • 基本类型的值通过值复制的方式来传递
      • 引用类型的值通过引用复制的方式来传递
      • 参数
        • 引用类型的参数实际上是将引用的一个复本传递进去了

《webpack实战》- 生产环境配置&打包优化

  • 生产环境关注的问题

    • 如何让用户更快的获得资源
      • 如何压缩
      • 如何添加环境变量优化打包
      • 如何最大限度的利用缓存
  • 线上&开发环境配置

    • 使用webpack-merge合并文件
    • 环境变量设置:DefinePlugin
    • source map:指将编译,打包,压缩后的代码映射回源代码的过程,以方便调试
      • source map原理
        • webpack对工程源码的每一步处理都有可能会改变代码的位置,结构,甚至所处文件,因此每一步都要生成对应的source map
        • 最后生成map文件,默认打包名+.map
        • 打开浏览器开发者工具,默认加载source map文件(所以对普通用户没有影响,但是有安全隐患,任何人都可以通过devtools看到源码)
        • 浏览器使用souce map对打包后的文件进行分析,分析出源代码的
      • source map配置
        module.exports = {
            devtool:'source-map'
        }
        //css,less等需要额外配置
        module.exports = {
            module:{
                rules:[
                    {
                        test:'/\.scss$/',
                        use:[
                            {
                                loader:'scss-loader',
                                options:{
                                    sourceMap:true
                                }
                            }
                        ]
                    }
                ]
            }
        }
        
    • 代码压缩:UglifyjsWebpack-Plugin/terser-webpack-pluginr(webpack 4:支持ES6+的代码)
      • source-map不仅可以帮助开发者调试源码,线上有问题时也有助于查看调用栈信息
        • 但是这样有极大的安全隐患
          • source-map
          • hidden-source-map
          • nosources-source-map
      • 压缩后的代码:移除多余的空格,换行以及执行不到的代码,缩短变量名,在不影响功能的前提下将代码替换为更简短的形式
      • 压缩css
        • 先提取(extract-text-webpack-plugin或者mini-css-extract-plugin)
        • 再压缩optimize-css-assets-webpack-plugin
  • 缓存

    • 资源hash
      • [email protected]。bundle是文件本身的名字,@后面跟的则是文件内容hash值,每当代码发生变化时相应的hash也会变化
    • 输出动态HTML
      • 资源名的改变,意味着html引用路径的改变,不想每次手动维护,使用html-webpack-plugin在打包结束后自动把最新的资源名同步过去
    • 使用chunk id更稳定
      • 对于缓存的应用是尽量让用户在启动时只更新代码改变的部分,对没有变化的部分使用缓存
    • bundle体积监控和分析
      • 为了保障用户使用的良好体验,我们可以在打包的时候对bundle的体积进行监控,以避免不必要的冗余模块被添加进来
      • vscode插件 import cost可以在引入模块时对体积进行实时监测
      • webpack-bundle-analyzer插件:帮助我们分析bundle的组成
        • 可以生成一个bundle模块的组成结构图
      • 自动化的对体积进行监控(bundlesize工具包)
        • 自动化测试的一部分
        • 它会根据我们配置的资源路径和最大体积验证最终的bundle是否超限
  • 打包优化

    • 多线程打包与HappyPack
      • HappyPack
        • 通过多线程打包提升打包速度
        • 工作原理
          • 打包过程中一项非常耗时的操作
          • loader对资源的转译处理
          • webpack是单线程的,一个模块依赖多个其他模块时,需要对这些模块逐个进行转译(串行),即使他们之间没有依赖关系
            • 此处就是HappyPack的有用之处
            • HappyPack适用那些转译工作很重的工程,如babel-loader或者ts-loader,对sass-loader等则收效
        • 工作流程
          • 从配置中拿到打包入口
          • 匹配loader规则,并对入口模块进行转译
          • 对转译后的模块进行依赖查找(如a.js中加载了b.js和c.js)
          • 对新找到的模块重复2,3步骤,直到没有新的模块被找到
        • 单个loader的优化
          • 在实际的使用过程中,要将原有的laoder替换成HappyPack,并将loader穿进去
          module:{
              rules:[
                  {
                      test:/\.js$/,
                      exculde:'node-modules',
                      loader:'babel-loader'
                  }
              ]
          }
          //使用HappyPack之后
          import HappyPack from 'h
          appyPack'
          module:{
              rules:[
                  {
                      test:/\.js$/,
                      exculde:/node-modules/,
                      loader:'happyPack/babel-loader?id=js'
                  }
              ]
          },
          plugins:[
              new HappyPack({
                  loaders:[
                      {
                      id:'js',    loader:'babel-loader',
                          options:{
                              presets:['react']
                          }
                      }
                  ]
              })
          ]
          
        • 多个loader优化
          • 使用HappyPack优化多个loader的时候,需要为每个loader设置一个id,否则HappyPack无法知道,rules与plugins如何一一对应
    • 缩小打包作用域
      • 提升性能的两个方面
        • 增加资源
          • 使用更多的CPU或者内存,用更多的计算能力来缩短执行任务的时间
          • 比如:HappyPack
        • 缩小范围
          • 针对任务本身
            • 去掉冗余的流程
            • 尽量不做重复性的工作等
          • 具体操作
            • exclude&include
            • noParse
              • 有些库我们希望webpack完全不用去解析,不需要应用任何loader规则,但仍然打包
              module.exports = {
                  module:{
                      noParse:/loadsh/
                  }
                  //忽略所有文件名中包含lodash的模块,
              }
              module.exports = {
                  module:{
                      noParse:function (fullPath) {
                          return /lib/.test(fullPath)
                      }
                  }
                  //忽略所有lib目录下的资源解析
              }
              
            • IgnorePlugin
              • 完全排除,被引用也不会被打包进资源文件中
            • Cache
              • 有些loader有一些cache配置项
              • 在执行下一次编译前会先检查源码文件是否有变化,如果没有就直接采用缓存
              • Webpack 5中添加了一个新的配置项“cache:{type:"filesystem"}”,它会在全局启用一个文件缓存(实验阶段,功能尚不完全,无法自动检测到缓存已经过期)
    • 动态链接库与DIIPlugin
      • DIIPlugin:借鉴了动态链接库的一些**
        • 动态链接库:当时的window受限于计算机内存空间较小的问题而出现的一种内存优化的方法
        • 当一段相同的子程序被多个程序调用的时候,为了减少内存消耗,可以将这个子程序储存为一个可执行文件,当被多个程序调用时,只在内存空间生成和使用同一个实例
      • DIIPlugin和Code Splitting
        • 共同点:都可以用来提取公共模块
        • 不同点:
          • Code Spliting:设置一些特定的规则,打包的过程中根据这些规则提取模块
            DIIPlugin:把vender完全拆出来,有自己的一整套Webpack配置并独立打包,实际构建时不用对它进行任何处理,直接取用即可
          • 所以理论上来说DIIPlugin要比code spliting要快
      • DIIPlugin配置
        • vender配置
          • 需要为动态链接库单独创建一个配置文件:webpack.vendor.config.js(举例)
          //webpack.vendor.config.js
          const path = require('path');
          const webpack = require('webpack');
          const dIIAssetPath = path.join(__dirname, 'dII');
          const dIILibraryName = 'dIIExample';
          
          module.exports = {
              entry: ['react'],//指定把哪些模块打包成vender
              output: {
                  path:dIIAssetPath,
                  filename:'vender.js',
                  library:dIILibraryName
              },
              plugins:[
                  new Webpack.DIIPlugin({
                      name:dIILibraryName,//导出的dll library的名字,它需要与output.library的值对应
                      path:path.join(dIIAssetPath, 'manifest.json')//资源清单的绝对路径,业务代码打包时将会使用这个清单进行模块索引
                  })
              ]
          }
          
        • vener打包(打包资源,并生成资源清单)
          • 执行webpack.vendor.config.js进行打包
          • 生成dII文件夹
            • vender.js:包含了库的代码
            • manifest.json:资源清单
        • 链接到业务代码
          • 如何将vender链接到项目中
            • 使用插件DllReferencePlugin&HashedModuleIdsPlugin
        • 潜在问题
          • id递增的问题
    • 死代码检查与TreeShaking
      • ES6 module依赖关系的构建是在代码编译时而非运行时
      • 所以webpack在打包过程中,可以帮助我们检测工程中没有被引用过的模块,这部分代码被成为死代码
      • 实现tree shaking的前提
        • 只对ES6 module有效
          • 有的时候我们发现引入了一个包,没有使用,但是bundle的体积并没有变小
          • 可能的原因时这个包采用的是CommonJS的导出模式
          • 目前为了兼容性,大部分npm上面的包还是采取的CommonJS,有部分包提供给了两种导出模式
          • 所以我们应该尽可能的使用ES6 module
      • 使用webpack进行依赖关系构建
        • 如果我们使用了babel-loader
        • 一定要禁用它的模块依赖解析
        • 如果由babel-loader来进行依赖解析的话,webpack接收到的就都是转化过的CommonJS形式的模块,无法进行tree-shaking
          module.exports = {
              module:{
                  rules:[
                      {
                          test:/\.js$/,
                          exclude:/node_modules/,
                          use:[
                              {
                                  loader:'babel-loader',
                                  options:{
                                      presets: [
                                          [@babel/preset-env { modules: false}]
                                      ]
                                  }
                              }
                          ]
                      }
                  ]
              }
          }
          
      • 使用压缩工具去除死代码
        • tree shaking只是为死代码打上标记,实际去除的是压缩工具
        • terser-webpack-plugin(webpack4之后开启mode:production即可)

《动物庄园》-奥威尔

读完不得不思索这样两个问题,第一,为什么同是穷苦生活出身的拿破仑最后会变成屠龙的少年,转而将剑指向共同奋斗过的伙伴?第二,如果斯诺夫没有被拿破仑驱逐成功而成为掌权者,后面的事情会不会改变,动物们是否能过上不被压榨,不被**的自由生活。

这些事情发生的本质原因一是人性善恶的矛盾,另一个重要的因素是制度问题。好的制度可以让坏人向好,坏的制度可以引人向恶。人在来到这个世界时带着相同分量的善与恶。善恶两性始终存在于一个人的身上,这就是人的两面性。善恶一念之间。人的恶本性与制度相博弈,导致无法产生一个所谓的完美制度,总是有制度的漏洞存在。人类的发展史就是一个人性与制度博弈的历史,最终将走向何方我们不得而知,毕竟我只是沧海一栗。

《重构:改变既有的代码设计》Martin Fowler

相关拓展书籍推荐:

  • 《重构手册》Bill Wake
  • 《重构与模式》Josh Kerievsky
  • 《重构HTML》Harlod
  • 《修改代码的艺术》 Feathers

什么情况下需要重构:

  1. 当添加新功能时,旧有逻辑变更复杂
  2. 当你二次书写相似的代码时

代码的坏味道

当我们想要书写不好的代码时,我们应该怎样做

  1. 神秘命名
  • 不要让人一眼就看明白这个变量或者函数是干什么的
  • 对应的重构手法:
    • 改变函数声明
    • 变量改名
    • 字段改名
  1. 重复的代码
  • 在一处以上的地方看到同样的代码

  • 对应的重构手法:

    • 提炼函数
  • 面对相似的代码

  • 对应的重构手法:

    • 移动语句:
      把相似的部分放在一起提炼
    • 函数上移
  1. 过长函数
    • 小函数的好处
      • 更易于分享
      • 更多的选择
    • 如何分解过长的函数
      • 当你感觉需要注释说明时就需要分解函数了
      • 一行代码也可以
      • 这个函数是干什么的命名
      • 条件表达式和循环也需要提炼
    • 对应的重构手法:
      • 查询取代临时变量
      • 引入参数对象
      • 保持对象完整
      • 以命令取代函数
      • 分解表达式
      • 以多态取代条件表达式
      • 拆分循环
  2. 过长参数列表
    • 当可以向某一个参数查询而获得另一个参数时(以查询取代参数)
    • 几个参数总是出现(引入参数对象)
    • 某个参数被用作区分函数行为的标记(移除标记参数)
    • 多个函数拥有相同的参数(函数组合成类)
  3. 全局数据
    • 全局数据会造成很多意想不到的bug,因为在任何地方都可以修改,而我们不知道具体在哪出做了修改
    • 对应的重构手法:
      • 封装变量
  4. 可变数据
    • 数据的修改会导致bug,因为你不知道在某一的当是否存在一个引用期望得到不同的值
    • 函数式编程:数据永不改变
      • 如果要更新一个数据结构,就返回一个新的数据副本,旧的数据仍然保持不变
    • 对应的重构手法:
      • 封装变量
        • 所有数据更新都通过少有的几个函数
      • 拆分变量
        • 当一个数据被用来在不同的时候存储不同的东西时
      • 移动语句
      • 提炼函数
      • 查询函数和修改函数分离
      • 移除设值函数
      • 查询取代派生变量
        • 当可变数据的值可以在其他的地方计算出来
      • 函数组合成类
      • 函数组合成变换
      • 将引用对象改变为值对象
  5. 发散式变化
  6. 霰弹式修改
  7. 依恋情结
  8. 数据泥团
  9. 基本类型偏执
  10. 重复的switch
  11. 循环语句
  12. 冗杂的元素
  13. 夸夸其谈通用性
  14. 临时字段
  15. 过长的消息链
  16. 中间人
  17. 内幕交易
  18. 过大的类
  19. 异曲同工的类
  20. 纯数据类
  21. 被拒绝的遗赠
  22. 注释

《你不知道的JS》-上-对象

对象

  • 声明方式

    • 声明形式(改变: 字面量 => 声明形式)
      var obj = {
          a:1,
          b:'test'
      }
      
    • 构造函数
    var objA = new Object();
    objA.a = 1;
    objA.b = 'test';
    
    • 两者的区别
      • 构造函数添加属性只能一个一个添加(这也是为什么我们通常使用字面量的方式创建对象)
  • 类型

js中的对象有很多特殊子类型

  • 特殊子类型

    • 数组(组织方式(改变:内部实现 => 组织方式)比普通的对象复杂)
    • null
    typeof null//object
    

    (改变:typeOf null === object //true => typeof null//object)

      - 原因:js底层设计,基本类型都使用二进制表示,前3位0开头的判断为object,null的二进制表示(<font color=red>改变:前3位 => 二进制表示</font>)都是0
    
    • 函数:js中的一等公民(可以调用的对象)
    • 内置对象:长的很像基本类型
      • Number
      • String
        • 实际上我们在代码中所写的
          var str = 'test';
          typeof str //string
          var strObj = new String('test');
          typeof strObj //object
          strObj instanceof String //true
          
          改变: Object => String
        • 子类型在内部借用了Object的toString方法
        • str并不是一个对象,而知识一个字面量,不可变
        • 需要使用String的属性或者方法,才能str.length
        • js会为我们进行自动的隐式转换(字面量=>String对象)
      • Boolean
      • Function
      • Date(只有内置,没有基本类型)
      • RegExp(只有内置,没有基本类型)
      • null,undefined没有内置类型
      • Array
      • Object
      • Error
  • 内容(即对象中的东西,被我们称为属性)

    • 属性的名称储存在对象中,是一个字符串
    • 其为一个指针,指向储存的位置(改变:值=>位置)
    • 属性访问方法
      • object.str :属性访问
      • object[str] :键访问
      • 可计算属性名
        • 表达式
        let prefix = 'myObj'
        obj = {
            [prefix + 'a']:'test',
            [prefix + 'b']:12,
        }
        
        
        • Symbol( 不透明且无法预测的值)
        var obj = {
            [Symbol.someone]:'test'
        }
        
  • 属性与方法

    • 在某些语言中,属于某一对象的函数,被称之为方法
    • 但在js中函数永远不会属于某一个对象
      • 有某些情况会导致在函数执行时,this指向对象(隐式绑定),但这是在执行时 根据调用的位置动态绑定的
    • 对象中的函数只是对同一函数的多个引用

《webpack实战》- 样式处理&代码分割

  • 前情提要

    • 除了js,打包大型项目中另一重要问题就是如何处理样式
      • 手工的维护css成本非常高昂
      • 如何解决浏览器兼容问题
      • 如何处理组件之间的样式隔离
  • 样式处理

    • 分离样式文件
      • 通过style-loader和css-loader,我们可以在js文件中引入css打包样式
      • 但是通过style标签方式引入的css,如何输出单独的文件呢
        • plugins
          • mini-css-extract-plugin
            • 专门用于提取样式到css文件
            • 支持按需加载css
    • 样式预处理
      • sass-loader
      • less-loader
    • PostCSS
      • 必须一个单独的配置文件postcss.config.js
      • 特性
        • 自动前缀
          • 与Autoprefixer结合 npm i autoprefixer
      • stylelint
        • stylelint是一个CSS的质量检测工具,就像eslint一样,我们可以为其添加各种规则
        • 统一项目的代码风格,确保代码质量。
      • cssNext
        • postcss可以和cssnext结合,让我们使用最新的css特性
    • CSS Modules
      • CSS Modules是近年来比较流行的一种开发模式,其理念就是把CSS模块化
        • 每个CSS文件中的样式都拥有单独的作用域,不会和外界发生命名冲突。
        • 对CSS进行依赖管理,可以通过相对路径引入CSS文件。
        • 可以通过composes轻松复用其他CSS模块。

  • 代码分割
    • 前情提要

      • 为什么需要代码分割
        • 保障首屏的加载速度
        • 按需加载
      • 分割的好处
        • 提升性能
        • 开发中减少了重复模块打包
        • 减小整体资源体积
        • 合理分割后的代码可以更有效的利用客户端缓存
      • 分割的问题
        • 应该对哪些模块进行分割
        • 分割后的代码如何管理
    • 代码分割与公共模块提取

      • 手动拆分
      • webpack 插件
        • CommonChunksPlugin webpack4之前
          • 提取范围:chunks

            • chunks配置项可以规定从哪些入口中提取公共模块
          • 提取的规则: minChunks

            • CommonsChunkPlugin的默认规则是只要一个模块被两个入口chunk所使用就会被提取出来
            • 接受参数
              • 数字
                • 只有该模块被n个入口同时引用才会进行提取
              • Infinity
                • 所有模块都不会被提取
                • 这样设置的目的
                  • 为了生成一个没有任何模块而仅仅包含Webpack初始化环境的文件,这个文件我们通常称为manifest
              • 函数
                • 让我们更细粒度地控制公共模块。
                • Webpack打包过程中的每个模块都会经过这个函数的处理,当函数的返回值是true时进行提取
          • hash与长效缓存

            • 提取后的资源不仅仅是模块内的代码,还包含webpack的运行时
            • 需要将运行时的代码单独提取出来
            new webpack.optimize.CommonsChunkPlugin({
              name: 'manifest',
              minChunks: Infinity
            }),
            //manifest的CommonsChunkPlugin必须出现在最后,否则Webpack将无法正常提取模块。
            
          • CommonChunksPlugin的不足

            • 一个CommonChunksPlugin只能提取一个vender,多个需要重复设置
            • manifest实际上会使浏览器多加载一个资源,这对于页面渲染速度是不友好的。
            • 无法处理异步加载的模块
        • SplitChunks webpack4之后
          • 解决CommonChunksPlugin的不足
          • 默认提取条件
            • 提取的chunk可被共享或者来自node-modules目录
            • 提取后的js chunk体积大于30kb,css chunk体积大于50kb
            • 按需加载过程中,并行请求的的资源最大值小于等于5
            • 在首次加载时,并行请求的资源数最大值小于等于3
    • 资源异步加载原理

      • import
        - 返回一个Promise
        - 支持/webpackChunkName/配置名字

《Webpack实战》- webpack简介与模块化

  • webpack是什么

    • 核心功能是解决模块之前的依赖,把各个模块按照特定的规则和顺序组织在一起,最终打包输出一个或多个文件
  • 为什么需要使用Webpack

    • 模块化
      • JS中的模块化
        • 在很长一段时间里JS是没有模块化概念的
          • 因为最初JS的设计是以恶搞小型的脚本语言,用来实现网页上一些简单的动态特性
          • 模块化显得冗余
        • 随着发展,我们需要在JS文件中通过script标签的方式引入其他模块
          • 缺点:
            • 需要手动维护JS的加载顺序
            • 每个script都意味这向服务器发送一次请求,HTTP2.0之前,建立连接的成本是很高的,过多的请求会严重拖慢页面的加载速度
            • 全局作用域污染
          • 优点:
            • 通过导入和导出语句我们可以清晰地看到模块间的依赖关系
            • 模块可以借助工具来进行打包,在页面中只需要加载合并后的资源文件,减少了网络开销。
            • 多个模块之间的作用域是隔离的,彼此不会有命名冲突
    • webpack优点
      • webpack默认支持多种模块化 标准
        • CommonJS

          • 历史
            • 2009年提出的包含模块,文件,IO,控制台在内的一系列标准
            • NodeJS采用了CommonJS中的一部分,并在其基础上进行了一系列的调整
            • 现在我们讨论的CommonJS其实讨论的是NodeJS中的版本
            • CommonJS最初只为服务端设计
            • 直到有了Browserify,一个运行在Node平台的模块打包工具,可以将CommonJS模块打包成可以运行在浏览器环境下的单个文件
          • 不同
            • CommonJS与在页面直接使用script标签插入页面的不同
              • script引入的顶层作用域是全局,在进行变量和函数声明的时候会污染全局环境
              • CommonJS会形成一个属于模块自己的作用域,所有的变量和函数只有自己可以访问,外部是不可见的
          • 导出
            • 导出是模块向外暴露的唯一方式
            • CommonJS的导出的两种方式
              • module.exports
                module.exports = {
                    name:'index',
                    sayHi:function () {
                        console.log('sayHi');
                    }
                }
                
                • CommonJS内部有一个module对象用于存放当前模块的信息,可以理解为在每一个模块的内部自定义了以下逻辑
                  var module = {}
                  //模块自身逻辑
                  module.exports = {...}
                  
                  • module.exports用于指向向外暴露的内容
              • exports.name = ....
                exports.name = 'index';
                exports.sayHi = function () {
                    console.log('sayHi');
                }
                
                • 机制是将exports指向了module.exports,而module.exports在初始化的时候是一个空对象
                  var module = {
                      exports:{
                          
                      }
                  }
                  var exports = module.exports
                  //注意事项:
                  1. 不要直接给exports对象赋值,会导致其失效(exports指向了新的对象,而module.exports还是原来的空对象,所以不会导出)
                  2. exports和module.exports不要混用
                  
          • 导入
            • CommonJS使用require导入
            • require的时候,有两种情况
              • require的模块是第一次加载,首先执行该模块,然后导出内容
              • require的模块曾被加载过,导入代码不会再次执行,而是直接导出上次执行后的结果
              • 模块会有一个module对象用来存放其信息,这个对象中有一个属性loaded用于记录该模块是否被加载过。它的值默认为false,当模块第一次被加载和执行过后会置为true,后面再次加载时检查到module.loaded为true,则不会再次执行模块代码
        • AMD

        • ES6

          • JS之父 Brendan Eich在设计这门语言的时候并没有包含模块的概念,2015年,ES6版本发布才有了这个新特性
          • 注意点:ES6 Module自动采用严格模式
          • 导出:(两种形式)
            • 命名导出
              //写法1
              export const name = 'es6 module';
              export const sayHi = function () {}
              //写法2
              const name = 'es6 module';
              const sayHi = function () {}
              export {
                  name,
                  sayHi
              }
              //或者
               export {
                  name,
                  sayHi as testsayHi//as关键字对变量重命名
              }
              
            • 默认导出
              export default {
                  name:'test',
                  sayHi:function () {}
              }
              
              • 默认导出只能有一个
              • 可以理解为对外输出了一个default的变量
        • ES6与CommonJS的区别

          • 实际开发中我们经常是两者混用的
          • 最大的区别是,依赖是静态的还是动态的
            • 动态:模块依赖关系的建立在代码运行阶段
            • 静态:建立在编译阶段
          • 路径表达式
            • ES6不支持导入的路径是一个表达式
            • CommonJS支持
          • 值拷贝与动态映射
            • CommonJS实际上是值的拷贝,因此我们可以在引入的模块中更改值,但不影响原文件中的值
            • ES6的值实际上是引入模块的动态映射,不可以更改
          • 循环依赖
            • A和B两个模块之间是否存在直接的循环依赖关系是很容易被发现的。但实际情况往往是A依赖于B,B依赖于C,C依赖于D,最后绕了一大圈,D又依赖于A
        • ES6的优势

          • 死代码检测和排除
            • ES6可以通过静态分析,在打包时去掉这些未曾使用过的模块,以减小打包体积
          • 编译器优化
            • CommonJS本质上导入的是一个对象,es6直接倒入变量,减少了引用层级,程序效率更高
        • 其他模块方案

          • AMD(Asynchronous Module Definition 异步模块定义)

            • 特点:异步导入模块
            • 优点:
              • 模块加载是非阻塞的,不会阻塞浏览器
            • 缺点:
              • 语法冗长
              • 容易造成回调地狱
          • npm模块

            • js没有java那样的标准库,因此处理URL,日期解析等,需要自己手动封装工具接口。
      • code splitting
      • Webpack可以处理各种类型的资源

📒书单--计算机相关

代码书写

  • 《代码整洁之道》
  • 《编码的奥秘》

算法&数据结构

  • 《数据结构与算法分析》
  • 《算法导论》

版本控制

  • 《Git权威指南》

大一统

  • 《计算机程序设计艺术》

《局外人》-加缪

读完真有一种不知如何是好的心情。 可惜与厌恶两种情绪一直在我脑海中纠缠。

因为什么可惜呢? 我想着按照作者的描述,主人公默尔索毕竟不是一个穷凶极恶的人,只是因为没有在母亲的葬礼上表现出悲伤而在一起案件中被判处死刑。 毕竟书中作者多次这样描写到,“我”本性善良,只是不善言谈,朋友们作证时也说“我”是一个正直,甚至老实的人。法官,辩护律师和记者似乎都是一伙的,只因为我没有在母亲的葬礼上表现出悲伤而想要给“我”安上一个没有丝毫人性,没有道德原则,蓄意杀人的罪名。

然而事实真的是这样吗?我认为默尔索并不是一个无辜之人,他确实对一切都不放在心上,母亲死了,他关注的是守夜的困苦和天气的炎热。此处我稍微感觉有点不一样,但不知这个人到底怎样。接着一直相处的玛丽想要与他结婚他也并不觉得有什么,无所谓,完全一个局外人的身份。到这时我开始有点小头绪了,默尔索确实对世间的情爱毫无兴趣,并无关心。亲情也好,爱情也罢。然后游手好闲,暴力倾向的雷蒙想与他交朋友,他也并觉得不可。并且为他在警察局作出伪证。此时我感觉到的是他的毫无原则,随波逐流。我不能再说服自己这是一个有道德的人。

但一直到这时我也仍不觉得有任何问题,他究竟是一个怎样的人其实并没有真相,作者给我们呈现的也许只是他的一小面,并且我们只是带着自己的有色眼镜在看待这个世界及这个世界上的人,而每个人都有选择做什么样的人的自由。

但是,可但是当他举起枪的那一刹那一切就不一样了,至少以我目前所形成的价值观和世界观来看,没有人在自己没有受到威胁的前提下拥有伤害他人的权利,这么轻易的剥夺他人的性命。他本可以转身走开,然后归咎与阳光太灼热,他开了枪,并且在第一枪之后的几秒后连开4枪。我实在不能再说服自己对他抱有同情,甚至产生了厌恶。

这本书告诉我的就是一件事的好坏与怎样描述它有很大的关系,但最终如何给这件事定性应该取决与你自己的判断,不要为他人的花言巧语所蒙蔽,带着批判性的眼光去感受。

《穷查理宝典》--彼得 考夫曼--泛读笔记

第一章节--查理芒格传略

论如何度过晚年生活,其实给我的感觉是,第一章讲老年,也符合芒格的**,因为很多事他都提倡反着想,总是反着想。那如何过好这一生,也许就看你想度过一个什么样的晚年,晚年是年轻生活的积累,如果你的生活方式是对的,那你年轻的时光就会很快乐,而晚年也将很快乐。

晚年不应该是行将就木的代名词,相反老年应该是智慧的结晶,可以给年轻人很多忠告,但这些忠告应该是和智慧的结合,而要成为一位睿智的老者,年轻时就应该不断的积累,不断的思考。像你崇敬的人学习,可以多看一些传记。


第二章--芒格的生活、学习和决策方法

芒格的多元思维模型

  • 原因:我们面临的是一个纷繁复杂的世界,蝴蝶效应处处可见,有太多因素之间是相互影响的
  • 行动:需要精通各个主要学科的最重要的几个理论,在处理任何事情是都把他们全部应用上,而不是仅仅使用一个。
  • 结论:通过多元思维模型将纷繁复杂的问题简化为一些基本要素
  • 原则:想清楚不应该做的事,运用多元思维模型分析将要做的事,耐心的等待,在机会来临的时候,且仅当机会来临的时候投下大的资产。

投资评估的过程

  • 方式:
  • 方面:
  • 内部公司经营状况
  • 所处的大环境
  • 国家的政策

投资原则检查清单

  • 风险: 所有的投资应该从测量风险开始
  • 测算合适的安全边际
  • 避免和道德品质有问题的人进行交易
  • 坚持为预定的风险要求合适的补偿
  • 永远记住通货膨胀和利率的风险

独立

  • 客观和理性的态度需要独立思考
    你是正确的还是错误的不在于别人怎么说,而在于你的推理正确与否
    随大流只会让你泯于众人
  • 准备:唯一的获胜方法是工作,工作,工作并希望拥有一点洞察力(现在本人可以感受到的是唯一能进步的方法就是不断的,一点一点地学习,向乌龟一样,坚持下去,不久你会发现,你已经摔开别人很长的路了)
  • 通过广泛的阅读把自己培养成一个终身学习者,培养好奇心,每天努力使自己聪明一点
    比求胜意愿更重要的是做好准备的意愿
  • 熟练的掌握各大学科的基本思维模型
    如果你想要变聪明,要不停的问,为什么,为什么(思考,唯有不断的动脑思考才能使你进步)
  • 谦逊:承认自己的无知是智慧的开端
  • 在自己的能力范围之内行事
  • 辨认和核查否定性的证据
  • 抵制追求虚假的精确和错误的确定性的重要性(准则是真实)
  • 你是最容易被自己愚弄的人,千万不要这样做

严格分析:使用科学方法和检查清单减少错误和忽视

  • 区分价格和价值,过程和行动,财富和规模
  • 记住浅显的好过掌握深奥的
  • 考虑总体的风险和效益,永远关注潜在的二阶效应和更高层次的影响
  • 要超前想,往后想,总是反过来想,反过来想

配置:正确的配置资本是投资者最重要的工作

  • 最好的用途总是由第二好的用途衡量出来的
  • 好主意特别少--当时机来临时,狠狠的下注
  • 别爱上投资项目-要依情况而定,照机会而行

耐心:克制人类天生爱行动的偏好

  • 复利是世界上第八大奇迹,不是非常必要的时候,别去打扰它
  • 避免多余的交易税和摩擦成本,永远不要为了行动而行动
  • 幸运来临时要保持头脑清醒
  • 享受结果,也享受过程

决心:当时机出现时,坚决采取行动

  • 当别人贪婪时,要害怕,当别人害怕时,要贪婪
  • 机会只眷顾由准备的人

改变:在生活中要学会改变

  • 认识和适应你身边的世界的真实本质,别指望世界来适应你
  • 不断地挑战和修改你最爱的观念
  • 正式显示,即使你不喜欢他-尤其你不喜欢他的时候

专注:别把事情搞复杂,记住你原本要做的事

  • 声誉和正直是你拥有的最有价值的财产--并且可以瞬间化为乌有
  • 避免妄自尊大和厌倦无聊的情绪
  • 别因为过度关心细节而忽略显而易见的东西
  • 千万要排除不需要的信息
  • 直面你的大问题,别把他们藏起来
  • 诚实是最好的策略
  • 说真话,就无须记住你的谎言了

第三章--芒格主义:查理的即席谈话

成功的关键

  1. 记住浅显的,好过掌握深奥的;吸取最棒的前辈们已被实践证明的洞见,避免犯下常见的错误。
  2. 为自己设立底线,有些事即使不犯法也不应该去做,做一个正直,善良,诚实,有道德的人
  3. 耐心,等待,唯有当正确的时机来临时,果断的狠狠的采取行动,在这之前,请做好准备

投资建议

  1. 个人方面:耐心等待好时机,并且能辨认出好时机,有浓厚的兴趣去弄明白现在正在发生什么
  2. 集中投资:不是把鸡蛋放在一个篮子里,而是不要投资100个公司,10个就可以了
  3. 错误的投资课程,分析各种系数是没有用的,主旨在于用合理的价钱购买拥有保持拥有可持续竞争优势的公司
  4. 小的投资者可以买一些小的股票,寻找那些确实很难找到的错误定价的机会
  5. 清楚你的能力圈,在其之内行事

思维模型

本书中反复提及思维模型的重要型

  1. 建立你自己的基本学科的重要思维模型,不断的揣摩把它变成你自己的东西。
  2. 在思考问题的使用刻意练习,运用尽可能多的思维模型。
  3. 尽可能的重复第一步和第二步,直到他们成为你日常生活的一部分。

关于如何幸福,获得成功的一些建议

  • 阅读
    查理本人就是一个行走的书袋子,尤其喜欢传记,并且将一些名人的传记与当时的环境和性格联系起来
  • 如何变得富有
    确保今天的你比昨天的你聪明了一点,不断的不断的努力,积累到一定时间的时候,你就能得到你想要的
  • 妒忌
    妒忌是唯一一个能让你只能获得痛苦的东西,那你为什么要妒忌呢?
  • 反着想
    如何幸福的度过一生,避免哪些让你不幸的东西就好了
  • 找到好配偶
    自己变得优秀,好配偶都不是傻瓜
  • 满足自己拥有的
  • 减少物质需求
    你并不需要那么多物质方面的东西,别拥有那么多大量愚蠢的需求

第四章--查理十一讲

第一讲:哈佛西湖中学毕业演讲

演讲的主题是如何生活的痛苦,这里查理的表现再一次强调了逆向思维,他似乎一直处于逆向思维中。

  • 建议1,反复无常,不要一直虔诚的做一件你正在做的事
    (正向:可靠的品质极为重要)
  • 建议2,只从自身获取成长的经验,千万不要像身边的或者过去的人学习他们成功或者失败的经验
  • 建议3,如遇打击,别爬起来,一蹶不振,消沉下去
  • 建议4,不要避免这些让你能过上痛苦人生的事。

其中一句我不能再认同

我们任何人都可以通过一个在一开始无法察觉直到堕落之力强大打无法挣脱的过程而染上某些恶习。

在此贴上一个很好的诗歌

《如果》
如果你能保持冷静,当你身边的人们都变得疯狂,纷纷指责你
如果你能相信自己,当所有人都怀疑你,且让他们怀疑去吧
如果你遭等待,却不因等待而疲倦,
或者遭受欺骗,却不用谎言回击,
或者遭受憎恨,却不用憎恨反击,
能够不得意忘形,也能够不巧言令色,
如果你能与凡人交谈,且彬彬有礼,
或与国王同行,而不奴颜婢膝,
如果仇敌和密友都无法伤害你,
如果你在乎每个人,但不会缺了谁就不行,
如果你在想发泄愤怒的那一分钟去进行六十秒的跑步,
大地以及大地上的万物都将属于你,
而更重要的是你将是真正的男人,我的孩子。


书中提及的一些书

  • 本杰明-富兰克林 《穷查理年鉴》
  • 西赛罗 《论老年》
  • 枪炮,病菌与钢铁
  • 自私的基因
  • 冰河世纪
  • 达尔文盲点
  • 深奥的简洁
  • 詹姆斯 博斯威尔写的约翰逊传记
  • 财富方程式 --威廉 庞德斯
  • 只有偏执狂才能生存 -- 安迪 格鲁夫
  • 聪明的投资者 本杰明 格雷厄姆
  • 沃伦巴菲特的投资组合--罗伯特哈格斯特朗

书中推崇的一些人

  • 本杰明,富兰克林
  • 西塞罗
  • 德摩斯蒂尼
  • 约翰尼 卡森
  • 塞缪尔 约翰逊
  • 本杰明 格雷厄姆

一些不知道的要查询的东西

  • 1990年所罗门债券危机
  • 1990年代末期互联网经济泡沫
  • 狄斯雷利的权宜之计
  • 费马-帕斯卡的系统与世界运转的方式惊人的一致。

一些很好的话

  • 每天起床的时候,争取变得比你以前更聪明一点。认真的、出色的完成你的任务。慢慢的,你会有所进步,但这种进步不一定很快。但你这样能够为你快速进步打好基础。每天慢慢向前挪一点,到最后---如果你足够长寿的话,大多数人得到了他们应该得到的东西。

  • 如果你担心通货膨胀,最好的预防手段之一就是在你的生活中别拥有大量愚蠢的需求---你不需要很多物质的商品。

  • 我们遇到的所有人都是善与恶的结合体


本书中提到的一些普世智慧

  • 掌握八九十个思维模型就可以让你成为拥有普世智慧的人。而这其中非常重要的只有几个。要掌握这些思维模型并不难,难的是要在日常生活中习惯于几乎每天都应用它。

  • 数学:复利原理、排列组合原理,决策树理论

  • 会计学:

  • 工程学:质量控制理论

  • 统计学:高斯分布

  • 生物学:

  • 心理学:误判心理学、双轨分析、巴浦洛夫联想、心里否认

  • 物理学

  • 全归因治疗法

  • 你必须领悟所有比你自己的学科更加基础的学科的所有基础**。只有掌握了那些最基础的知识和原理,你们才能够清清楚楚的解释问题。而且你们要永远承认你们所用的基础知识来自哪些学科。当你们使用物理学时,要说你们时在使用物理学。

  • 股票就是一个公司的部分所有权,股票的价格就是股票的价值,也就是公司的价值所决定的,而公司的价值又是由公司的盈利情况及净资产决定的。

  • 反着想,总是反着想,逆向思维的重要性。

《你不知道的JS》-上-行为委托

前提: 在原型部分,我们了解到一些很重要的事情

  1. 在类或者继承的背景下讨论原型是不准确的,
  2. 实际上[[prototype]]是对象的一个内部链接引用另一个对象
  3. 也就是说原型链本质上是对象之间的关联
  • 面向委托的设计模式

    • 原型并不是面向类的设计模式

    • 部分面向类的设计模式依然有效,如封装

    • 类理论

      • 编写一些类似的任务
        • 父类People
          • 含有通用的方法
        • 子类Men,Women
          • 含有自己的个性方法
          • 可以重写(多态)父类的一些方法
          • 添加新行为可以使用super调用这个方法的原始版本
    • 委托理论

      • 定义一个people对象,包含通用方法分
      • 定义一个新对象Men,使用Object.create()关联到People
      • 定义一个新对象Women,使用Object.create()关联到People
      • 实现Men,需要Men + People
      • 注意事项:
        • 委托禁止相互委托,因为这样会导致一个循环
    • 类和委托理论的比较(实现同样的功能)

      var People = function (name) {
        this.name = name;  
      }
      People.prototype.sayHi = function (){
          return 'i am ' + this.name
      }
      var XiaoHong = function (name){
          People.call(this,name)
      }
      XiaoHong.prototype = Object.create(People.prototype)
      XiaoHong.prototype.sayHello = function () {
          console.log('haha' + this.sayHi())
      }
      var human1 = new XiaoHong('xiaohong');
      var human2 = new XiaoHong('xiaohong2');
      human1.sayHello();
      human2.sayHello();
      
      • 委托
      var People = {
          init:function (name) {
            this.name = name;  
          },
          sayHi:function (){
              return 'hi i am' + this.name;
          }
      }
      var XiaoHong = Object.create(People);
      XiaoHong.sayHello = function () {
          console.log('hello' + this.sayHi() + '.')
      }
      var a1 = Object.create(XiaoHong);
      var a2 = Object.create(XiaoHong);
      a1.init('xiaohong1');
      a1.sayHello();
      a2.init('xiaohong2');
      a2.sayHi();
      
  • 类和对象(在实际前端开发中的应用,创建UI控件)

    • 控件类
      • **:写一个父类,拥有通用的属性及方法,然后写子组件继承自父类,特殊行为重写父类
      //父类
      function Widget (width,heigth) {
          this.weigth = weigth || 50;
          this.height = height || 50;
          this.$ele = null;
      }
      Widget.prototype.render = function ($where) {
          if(this.$ele){
               this.$ele.css({
                   width:this.width + 'px',
                   heigth:this.height + 'px'
               }).append($where)
          }
      }
       //子类
       function Button (width,heigth,label) {
           //调用super构造函数
           Widget.call(this,weight,heigth);
           this.label = label;
           this.$ele = $('<button>').text(this.label)
       }
       //让Button继承Widget
       Button.prototype = Object.create(Widget.prototype);
       //重写render
       Button.prototype.render = function ($where) {
           //super 调用
           Widget.prototype.render.call(this,$where);
           this.$ele.click(this.onClick.bind(this);
       }
       Button.prototype.onClick = function (evt) {
          console.log('button' + this.label + 'clicked'); 
       }
       $(document).ready(function () {
           var $body = $(document.body);
           var btn1 = new Button(120,40,'hello');
           var btn2 = new Button(120,80,'world');
           btn1.render($body);
           btn2.render($body);
       })
      
      • es6语法糖
      class Widget {
          constructor(width,height){
             this.width = width || 50;
             this.height = height || 50;
             this.$ele = null;
          }
          render ($where) {
              if(this.$ele){
                  this.$ele.css({
                       width: this.width + 'px',
                       height: this.height + 'px'
                  }).append($where)
              }
          }
      }
      class Button extends Widget {
          constructor(width,height,label) {
              super(width,height)
              this.label = label;
          }
          render ($where) {
             super.render($where); 
             this.$ele.click(this.onClick.bind(this))
          }
          onClick() {
              console.log('button' + this.label + 'clciked')
          }
          
      }
      
      • 看起来es6写起来简洁多了,但实际上class实现super仍然是使用prototype
    • 委托控件对象
    var Widget = {
        init:function (width,height) {
            this.width = width || 50;
            this.height = height || 50;
            this.$ele = null;
        }
        render: function ($where) {
            if(this.$ele){
               this.$ele.css({
                        width: this.width + 'px',
                        height: this.height + 'px'
                   }).append($where) 
            }
        }
    }
    var Button = Object.create(Widget);
    Button.draw = function (width,height,label) {
        this.init.call(this,width,height);
        this.label = label;
        this.$ele = $('<button>').text(this.label);
    }
    Button.insert = function ($where) {
        this.render.call(this,$where)
        this.$ele.click(this.onClick.call(this))
    }
    Button.onClick = function () {
        console.log('button' + this.label + 'clicked');
    }
    
  • 更好的语法

    • es6新增的简洁方法声明可以提高间接性
    var Foo = {
        test() {
           //es6 
        },
        sayHi:function SayHi() {
            //es5
        }
    }
    
    • 缺点
      • 实际是一个匿名函数
        • 匿名函数的缺点
          • 调用栈更难追踪
          • 更难自我引用
          • 理解更难
        • 在简洁方法声明中只有第二个缺点
    var Foo = function () {
        test(i) {
            if(i < 10){
                return Foo.test(i+1);
            }
        }
        sayHi:function sayHi(i) {
            if(i < 10){
                return sayHi(i+1)
            }
        }
    }
    
  • 内省

《人生的智慧》读后感--叔本华

人生的智慧不在于追求幸福,而是避免痛苦。

青年时代的我们还没有那么多的经历告诉我们,你的欲望越多,得到的话,得到的快乐越多,快乐越转瞬即逝。得不到的话,失望越多,痛苦越多。所以无论结果怎样意欲带给你的是更多的痛苦和短暂的快乐。

生存与世,为了过的幸福,你要做的也许就是

  1. 放平心态,不要因为别人或愚蠢或讽刺而心生愤怒,要无视。
  2. 与人交往要长久的在细小之处观察,与公正善良之人相处,因为一个人的本性是永远无法改变的。如果他做了一件让你愤怒的事,要思考,这个人的价值是否值得你忍受。因为再遇见同样的情景他还会如此做即便他发自肺腑的保证永不再犯。
  3. 不要在别人面前展示你的智慧和**,因为这样做会让人觉得你在讽刺他自己的愚蠢而心生怨恨。
  4. 不要评论他人,两个人做一件事已经说明了不一样。
  5. 为老年生活存储足够的金钱和健康,所以在年轻时就应该理财,节约,锻炼身体。
  6. 所有已经发生的事都是无可避免的必然事件。
  7. 如果你能做到完全的依赖自己,你的所有需求都能从自身获得,那么你就得到了幸福。

《你不知道的JS》-中- 异步与性能- 生成器

  • Promise解决了回调的控制反转

  • 那么回调的另一个缺点

    • 基于回调的异步不符合大脑对任务步骤的规划方式
    • 则由ES6的迭代器-generator来完成
  • Generator

    • 打破完整运行
      • 前情提要
        • 我们在js中的函数,一般依赖一个假定,一旦开始,就一定运行到结束
          • 不会有其他代码打断并插入其中
          let x = 1;
          function foo() {
              x++;
              bar();
              console.log(x)
          }
          function bar() {
              x++;
          }
          foo();
          //console的结果是3
          //我们确信bar()在x++和console之间运行
          //但如果不是呢,结果就是2
          
          
          • 如果我们希望bar不在现在的位置,但是仍然可以在现在的位置打断并插入呢
            • 在这个位置打断,以合作式的方式实现这样的中断(并发)
            • ES6中表示中断的语法是yield(表达一种合作式的控制放弃)
              let x = 1;
              function *foo() {
                  x++;
                  yield;
                  console.log(x)
              }
              function bar() {
                  x++;
              }
              //构造一个迭代器it来控制这个生成器
              //生成器和迭代器的关系是??迭代器控制生成器的执行吗?
              let it = foo();//此处并没有执行生成器*foo,而是构造了一个迭代器,来控制它
              //启动foo
              it.next();
              //*foo在yield处暂停,在这个点上第一个it.next()调用结束,此时*foo仍在运行并且是活跃的,只是处于暂停状态
              //yeild提出一个问题,此处插入什么,由第二个it.next()回答
              
              //yeild是双向的消息传递
                  //yeild作为一个表达式可以发出消息相应next的调用
                  //next也可以向暂停的yeild表达式发送值
                  //yeild和next组合,在生成器的执行过程中形成一个双向消息传递系统
                  
                  //第一个生成器的启动it.next()不需要传递值
                      //因为只有暂停的yeild可以接这个值,而第一个启动的next没有对应的暂停yeild
                  
                    //第一个next在问一个问题*foo生成器要给我的下一个值是什么
                    //第一个yeild回答这个问题
              bar();
              it.next();
              //此处的it.next()调用从暂停处恢复了*foo生成器的执行,此处不是必须的
              
              //next的调用结果是一个对象,拥有一个value属性,持有*foo返回的值(有的话)
              
              //yield会导致*foo在执行过程中发送一个值
              
            • *代表生成器,以区分正常函数
            • 生成器是一类特殊的函数,可以一次或者多次启动和暂停,并不一定非得完成
      • 输入和输出
        • 生成器本质还是一个函数,所以拥有函数的特性,输入参数和输出值
      • 多个迭代器
        • 通过一个迭代器控制一个生成器时
          • 每一个迭代器生成了一个生成器的实例
          • 通过迭代器控制的是这个生成器实例
          • 生成器的多个实例可以同时运行,它们甚至可以彼此交互,也就是交替执行这里不懂哭唧唧
    • 生成器产生值
      • 生产者与迭代器
      • iterable
      • 生成器迭代器
    • 异步迭代生成器(生成器应用于异步开发)
      • 如何解决了回调函数的问题
        • js常规回调函数形式
          function foo(x,y,cb) {
              ajax(`jttp://rtyuiol?name=${x}?age=${y}`,
                  cb
              )
          }
          foo('wei',18, function (error,text){
              if(error){
                  console.log(error);
              }else {
                  console.log(text);
              }
          })
          
        • 使用生成器形式
          function foo(x,y) {
              ajax(`jttp://rtyuiol?name=${x}?age=${y}`,function (error,text){
                  if(error){
                      it.throw(error)
                  }else{
                      it.next(text)
                  }
              })
          }
          function *main(x,y) {
             try {
                 let text = yeild foo(x,y)
                 console.log(text);
             }catch {
                 console.log(error)
             }
          }
          let it = main(11,31);
          it.next();//启动
          
    • 生成器+Promise
      • 以上解决了回调的顺序性问题,但缺乏了Promise的控制反转
      • 支持Promise的Generator Runner
        • async await
      • 生成器中的Promise并发
    • 生成器委托
      • 为什么用委托
      • 消息委托
      • 异常委托
      • 异步委托
      • 递归委托
    • 生成器并发
    • 形实转换程序
    • ES6之前的转换器
      • 手工转换
      • 自动转换

《Vue深入浅出》

数据双向绑定原理

变化侦测

  • Object
    • 一个状态绑定多个依赖,如何在状态发生变化时通知依赖进行更新DOM呢
    • Vue2.0引入虚拟DOM,在状态发生变化时,通知组件,然后组件进行虚拟DOM对比
    • 那么如何侦测状态发生了变化呢
      • Object.defineProperty
        function defineReactive(data,key,val) {
           Object.defineProperty(data,key,{
               enumerable: true,
               configurable: true,
               get: funtion () {
                  return val; 
               },
               set: function (newVal) {
                if(newVal === val){
                   return; 
                }
                val = newVal;
               }
           }) 
        }
        
        • 如何收集依赖呢?
        • 在getter中收集依赖
        • 在setter中触发依赖
        • 改造defineReactive
        function defineReactive(data, key, val){
           let dep = [];//用来储存被收集的依赖
           Object.definePeoperty(data,key,{
               enumerable: true,
               configureable: true,
               get: function () {
                   dep.push(window.target) //新增
                   return val;
               },
               set: function (newVal){
                   if(val === newVal){
                       return;
                   }
                   for(let i = 0; i < dep.length; i++){
                       dep[i](newVal,val)
                   }
                   val = newVal;
               }
           })
        }
        
        • 进一步优化
        export default class Dep {
           constructor () {
               this.subs = [];
           }
           addSubs (sub) {
               this.subs.push(sub);
           }
           removeSub (sub)  {
               remove(this.subs,sub);
           }
           depend () {
               if(window.target){
                   this.addSubs(window.target);
               }
           }
           notify () {
               const subs = this.subs.slice()//复制一个新数组for(let i = 0; i < subs.length; i++) {
                   subs[i].update()
               }
               
           }
        }
        function remove(arr ,item){
            if(arr.length){
                const index = arr.indexOf(item);
                if(index > -1) {
                    return arr.splice(index,1);
                }
            }
        }
        
        function defineReactive(data, key, val){
            let dep = new Dep();
            Object.defineProperty(data, key, {
               enumerable: true,
               configurable: true,
               get: function () {
                   dep.depend();
                   return val;
               },
               set: function (newVal) {
                   if(va === newVal){
                       return;
                   }
                   val = newVal;
                   dep.notify()
               }
            })
        }
        
        • 这里我们收集的依赖是window.target

          • window.target是什么?
          • 当属性发生变化后,使用它的地方很多,而且类型不一(数据,模版,watch),这时需要抽象一个能够集中处理的类。- 然后我们收集依赖只收集这个封装好的类的实例,通知也只通知他一个,然后他再通知其他地方。
          • 命名为watcher(数据的中介),watcher可以订阅任意数据的变化,在数据变化时去通知依赖。
        • object的侦听有缺点

          • 当添加对象属性时,无法侦测
          • 当使用delete删除时,无法侦测
          • 原因:vue通过Object.definePrpperty来将对象的key转换成getter和setter的形式来追踪变化,但是此方法只能侦测是否被读取和改变,无法侦测新增和删除
          • 解决方案:Vue提供了vm.$set& vm.$delete
      • ES6 Proxy
  • Array
    • Array采用与Object不同侦测方式的原因就是Object的侦测方法是通过Object.defineProperty,然而当我们改变数组时使用array.push(list)等Array原型上的方法来改变的方式无法适用
    • 采用什么方法呢
      • 可以使用一个拦截器覆盖Array.prototype,这样每当使用Array原型上的方法时,实际上都是使用的拦截器中提供的方法
      const arrayProto = Array.prototype;
      export const arrayMethods = Object.create(arrayProto);
      [
          'push',
          'pop',
          'shift',
          'unshift',
          'splice',
          'sort',
          'reverse'
      ].forEach(function (method){
          //缓存方法
          const original = arrayProto[method];
          Object.defineProperty(arrayMethods,method,{
              enmuerable:false,
              configurable: true,
              writable: true,
              value:function mutator (...args) {
                return original.apply(this,...args);  
              }
          })
      })
      
      • 知识点:
        • propto in {} in关键字检查一个对象中,以及原型中是否有某一属性
        • Object.defineProperty()
        • Object.hasOwnPropertyDescriptors():获取一个对象自身所有属性的描述符
        let obj = { 3:'222'};
        console.log(Object.getOwnPropertyDescriptors(obj) )
        {
            3:{
                value:'222',
                configurable:true,
                wirtable:true,
                enumerable: true
            }
        }
        

📒书单--自然科学

  • 《达尔文的盲点》-- 弗兰克•雷恩
  • 《自私的基因》
  • 《深奥的简洁:从混沌、复杂到地球生命的起源》
  • 《第三种猩猩:人类的身世与未来》

《财富自由之路》

以前我将自由定义为可以去做自己喜欢做的事,后来我明白自由是自律的去执行我计划好的事情。作者从自身经历之中总结了人呢都可以成功的路径以供后人参考。

首先我们要知道在很多成功人士身上有共同的一些品质,那就是坚毅,责任,自信和持续不断的努力。

自信指的是,在自身经历的基础上,遇事可以依靠自己。其实我们或多或少都明白,世上没有真正的感同身受,在很多时候,能给你力量的是你自己,能帮助你的也只有你自己,你全盘为自己的生命负责。并且你需要负责的也只有自己。

你无需对他人的表现负责,只需要对他人的表现的你的反应负责。如果你想推卸责任,完美3部曲交给你,

  1. 基因的错。
  2. 父母的错。
  3. 客观环境的错。

除了对我们所做的事负责外,我们还需要为我们没有做的事情负责,因为显而易见的是逃避责任有太大的诱惑力。

责任也意味着控制权。我们要知道我们目前为止的信仰决定了现在的我们,而如果现在的我们不是我们希望的自己,

那么你应该做的就是改变自己的信仰。信仰决定你采取的行动,而行动带来果实。

要想拓宽自己的控制领域,你可以从4个方面入手。

  1. 走出舒适圈。如果你面临以个选择,选择难走的那条路,不要让自己一直处于自己的舒适圈内。
    我知道处在舒适圈很舒服,但是在未来将会变成巨大的痛苦。很多老员工在年纪大了之后被辞退,成为没有收入之人,难道你
    要让自己处于那样的境地吗,还是选择在你有选择权的时候作出改变。

  2. 不断的发现问题。如果你做一件事情,一直没有问题,那说明你跨出的步子并不大,你还在自己的能力范围之内,出现问题说明这件事在我们的处理范畴之内,但是控制范围之外。这样才能不断的增强自己的能力,如果想取得100分的成绩,去犯200分的错误。不断的学习充实自己吧。

  3. 提问。正确的提问方式是我如何能做到?而不是我能不能做到。关注在如何成功上面。提问的顺序也很重要,如果你要去做一件事,先问自己为什么要去做这件事,然后在根据问题设想自己可能遇到的问题,再提问如何处理问题。

  4. 扩大自己的个人范畴。如果你只关心自己的一亩三分地,那么你就只对那么大的领域拥有控制权。想要成功,你要做的就是在更多的领域,更大的范围内提高自己的责任和权利。

总的来说,如果你想优化你的生活,你应该不断的成为自己能成为的最好的人。我们可以从5个方面改变自己。健康,财务,关系,情感和人生的意义。5个方面同等重要,而奇迹发生在5个层面之上。

书中再次提到写成功日记建立自己的自信心和制作自己的梦想相册时刻提醒自己,以及自律和坚持不懈,寻找志同道合的优秀朋友等成功的方法。然而读完全本,我觉得重要的是度过一本好书是很重要,更重要的是如何让书中的内容为我所用,正如作者说的,才华就如咖啡,没有倒进杯子里就一文不值。知识也是如此,没有实践的知识就如同没有倒进杯子的咖啡。

《你不知道的JS》-中- 原生函数

  • 原生函数
    • js中自有的一些函数常见的有
      • String
      • Number
      • Boolean
      • Array
      • Function
      • Object
      • Error
      • RegExp
      • Date
      • Symbol
    • 原生函数可以当作构造函数来使用,但是实际上生成的不是基本类型,而是基本类型的封装对象
    var a = new String("abc");
    typeof a //object
    a instanceof String //true
    console.log(a)
    {
        0:'a',
        1:'b',
        2:'c',
        PrimitiveValue:'abc'
    }
    
    • 内部属性[[class]]
      • 所有typeof为object的对象都有一个属性[[class]]
      • 可以使用Object.prototype.toString.call()来间接访问,此值不可以被改变
      • 通常该值和原生函数相同,null和undeifned没有原生构造函数,但他们的值是Null和Undefined
    • 封装对象包装
      • 即封箱操作
      • 基本类型并没有.length .indexOf等方法,实际上是进行了封箱操作才可以使用这些属性和方法
      • 正常情况下你不需要自己封箱,js自己做了性能优化来决定是否进行封箱
      • 特殊情况下的自行封箱操作可以使用Object,而不要使用new ...
      var a = 'str';
      var b = new String(a);
      var c = Object(a);
      typeof a //string
      typeof b //object
      typeof c //object
      
      //Boolean有一个很特殊的点
      new Boolean(false) //true
      
    • 拆封
      • 在使用封装对象的基本类型的时候会进行隐式拆封--valueOf
      var a = new String('abc');
      var b = a + '';//'abc'
      typeof a //object
      typeof b //string
      
    • 原生函数作为构造函数
      • Array

        • 构造函数Array比较特殊的点在于不是必须使用new来调用,没有的时候会自动补上
        var a = new Array(1,2,3);
        var b = Array(4,5,6);
        console.log(a)//[1,2,3]
        console.log(b)//[4,5,6]
        
        • 当使用Array函数并且只传入一个参数的时候,这个参数会被默认为数组的长度而不是数组的值,因此会创建一个稀疏数组
        var arr = Array(3)
        console.log(arr)//[empty,empty,empty]
        
        • 但是这个稀疏数组和使用Array(undefined,undefined)创建的还略有区别
        a.join('-');'--'
        b.join('-');'--'
        a.map((v,i)=> i)//empty*3
        b.map((v,i)=> i)//[undefined,undefined,undefined]
        
          - 之所以会造成这样的区别是join在执行的时候会先假定数组不为空,map并不会
          - 创建含有三个空值的稀疏数组可以采用这种方法
          ```
          var arr = Array.apply(null,{length:3});
          arr//[undefined,undefined,undefined]
          ```
              - 在执行的时候,apply参数是一个数组,因此会访问arr[0],arr[1],arr[2],但是他们都没有值,因此会返回undefined ???这里有点不太懂,为什么会访问arr[0]
        
      • Object,Function&RegExp

        • 原则就是尽量不要使用
      • Date&Error

        • Date和Error算是最常用的原生函数了
        • new Date()获取时间
          • 不传参数,获得当前时间
          • 必须使用new调用,可以使用new Date().getTime()来获取当前时间戳
            • ES6新增了函数Date.now来快速获取当前值
            • 不使用new调用的话会得到一个当前时间的字符串值
        • Error 抛出错误
          • 抛出错误主要是为了获取当前的执行栈的上下文
      • Symbol

        • es6新加入的基本类型,符号,代表具有唯一性的特殊值
        • 常被用来做对象的属性名
          • 可以保障属性名是唯一的
          • 通常用来做私有属性(代替_前缀的属性)
      • 原生原型

        • 原生函数都有自己的原型,但是有一些他们的值很特殊
          • Function.prototype
            • 空函数
          • Array.prototype
            • 空数组
          • RegExp.prototype
            • 空的正则

《你不知道的JS》-中- 强制类型转换

  • 值类型转换

    • 我们知道在声明一个字符床变量时js会对他进行对象类型包装,从而使其可以使用String原型上的方法--这个其实不是真正的强制类型转换,但在js中我们统称为强制类型转换
    • 本书将强制类型转换区分为
      • 显式强制类型转换
        • 显式,顾名思义是可以让你一眼看出来的
        var a = 'test';
        var b = a + "";//隐式强制类型转换
        var c = String(a);//显式强制类型转换
        
      • 隐式强制类型转换
        • 一些不易察觉的类型转换
  • 抽象值操作

    • 定义:在ES5的第9节中介绍了基本类型Sting,Number和Boolean之间的转换规则

      • toString
      • toNumber
      • toBoolean
      • ToPrimitive
    • toString处理非字符串类型到字符串类型的强制类型转换

      • number 返回字符串数值,不过特别大的使用指数表示
      var num = Number.MAX_VALUE;
      num.toString()//"1.7976931348623157e+308"
      
      • boolean 返回"true""false"
      • null "null"
      • undefined "undefined"
      • 对于普通对象来说调用toString(Object.prototype.toString)返回的是其属性[[class]]的值(前提是没有更改的情况下),如[object Object]
        • 但是如果toString被重新定义过的话则是调用被重新定义的方法
        • Array上的toString返回的是join(',')
        var arr = [1,2,3]
        arr.toString();//'1,2,3'
        
        • 将对象强制转换为字符串t实际上调用的是抽象方法toPrimitive
    • JSON字符串化

      • 工具函数JSON.stringify在对JSON数据序列化为字符串时实际也使用了toString,但是不是严格意义上的强制类型转换
        • 如果对象有自身的toJSON方法,会优先调用该方法,用它的返回值来进行序列化时,因此在对不安全数据进行处理时,应该自定义toJSON方法,以返回可以处理的值
        var o = {};
        var obj = {
            a:42,
            b:o,
            c:function(){}
        }
        o.e = obj;
        obj.toJSON = function () {
            return {a:this.a};
        }
        JSON.stringify(obj)//"{"a":42}"
        
      • 对于安全格式的JSON数据,JSON.stringfy可以得到字符串化的json数据
        • 安全格式指可以呈现为有效的JSON数据
          • 可以转换为字符串的
          JSON.stringify("test")//""test""总是返回带有双引号的字符串
          JSON.stringify(12)//"12"
          
        • 非安全格式
          • undefined
          • function
          • symbol
          • 对象造成的死循环
            • 进行序列化会报错
          • 对象中包含的这些数据会被自动忽略,数组中则返回null(保障单元位置不变)
          var b = undefined;
          var c = function () {}
          var d = [1,undefined,function (){}]
          JSON.stringify(b)//undefined
          JSON.stringify(c)//undefined
          JSON.stringify(d)//[1,null,null]在数组中会被忽略
          
        • JSON.stringify不常见的使用方法
          • 可选参数:用来指定哪些属性应该被处理,哪些被忽略
            • 可以是一个数组
              • 数组必须是字符串数组
              • 在进行字符串化的时候会返回字符串数组包含的键
            • 可以是一个函数
              • 整个对象会调用该函数,每个属性再调用一遍????这个不太懂哎
    • toNumber

      • 有时我们需要对非数值类型的值当做数字来使用,比如数字运算,因此有了toNumber
        • true =》 1
        • false =》 0
        • null =》 0
        • undefined =》 NaN
        • "" =》 0
        • 字符串 =》 NaN
        • 对象
          • 先将其转换为基本类型
          • 然后再处理
            • 因此Number([]) //0
      • 转换算法toPrimitive
        • 先使用valueof
        • 未返回基本类型的情况下再调用toString
      Number("") //0
      Number([])//0 [].valueOf() => [] [].toString() => "" 数组的toString相当于join(',')
      Number(['a']) //NaN 
      Number({})//NaN
      
      • 这里引申了其他的知识点
          • 进行了隐式转换
        • 调用valueOf => toString :[object Object]
      {} + {} //[object Object][object Object]
      {} + [] //这里的{}不是一个对象,而是一个空代码块 ,所以算+[]的值,隐式转换为0
      
      • es6中新加入了创建对象的方法Object.create(null),原型为null,没有toString和valueOf方法,所以不会进行强制类型转换
    • toBoolean

      • 假值
        • js中规定的转换为boolean的假值有以下几种
          • null
          • undefined
          • false
          • ""
          • +0 -0 NaN
        • 除了假值外的就是真值
      • 假值对象
        • js中有一些特殊的被添加进来的对象
          • document.all
            • 表示所有页面上的标签
            • Boolean转换为false
            • 应用场景:if(Boolean(document.all)) { //这是IE浏览器}
  • 显式强制类型转换

    • String,Number(字符串与数字之间的转换)
      • 遵循ToString,ToNumber规则
          • 也是一种显式强制类型转换
          • 常用操作
            • 将日期转换为时间戳
            var d = + new Date()
            var date = new Date().getTime()//更推荐
            var dateT = Date.now() //更推荐,es6新增语法
            
        • ~x基本相当于-(x+1)
        • 常用操作
          • if(~a.indexOf('a'))//如果找到的话
    • toString
      • 涉及隐式转换,需要先转换魏相应的对象
    • 解析与转换的区别(parseInt/parseFloat)
      • parseInt是解析
        • 参数只接收字符串形式,不是会进行强制转换
        • 遇到不是数字的则停止,并忽略后面的
        • 第二个参数为解析的基数,几进制
        parseInt('8e1') //8
        Number('8e1') //NaN
        parseInt(1/0) //NaN 'Infinity'
        parseInt(1/0,19) //18 I在19进制里面魏18,后面的被省略
        
    • 转换为布尔
      • 常见方式
        • Boolean
        • !!
  • 隐式强制类型转换

    • 凡事都有两面性

    • 目前很多人都说隐式强制类型转换有很多弊端,因此因噎废食

    • 那我们来谈谈他的好处

      • 减少冗余代码
      • 增加代码可读性
    • 字符串和数字之间的隐式强制类型转换

      var a = "42";
      var b = "0";
      var c = 42;
      vvar d = 0;
      a + b //"420
      c + d //42
      
      • 为什么+号在处理的时候进行了不同的操作
      • 通常我们的解释是当+号任意一方有字符串时,我们执行的是字符串拼接
        var arr1 = [1,2];
        var arr2 = [3,4];
        arr1 + arr2//"1,23,4"
        
        • 为什么arr1,arr2都不是字符串,但+将其都转换为字符串然后进行了拼接
        • 其深层的规则,则是+ 号两边,任意一边是字符串或者通过以下两种方式可以转换为字符串的话,就做拼接,否则就是加法
          • 这里的转换为字符串包括
            • String
              • 直接调用toString
            • ToPrimitive抽象操作
              • 先调用valueOf
              • 然后调用toString
    • 布尔值到数字的隐式强制类型转换

      • 在进行条件判断时使用
      function onlyOne(a,b) {
          if(a || b) {
              return false
          }
          return true
      }
      //但是当参数变为3个,5个甚至10个,我们应该如何判断呢
      function onlyOne () {
          let sum = 0;
          for(let i = 0; i < arguments.length; i++) {
              sum += arguments[i]
          }
          if(sum){
              return false;
          }
          return true;
      }
      
    • 隐式强制转换为布尔

      • 判断的地方
        • if()
        • while()
        • ? :
          ....
    • 逻辑运算符 || &&

      • 我们称|| && 为逻辑运算符,但是其结果并不一定返回布尔值
      • 更恰当的称呼可以是选择器运算符
      • a || b ,a && b
        • 先将其强制转换魏布尔值,再进行判断
        • a || b,如果a为真则返回a,否则返回b
        • a && b ,如果a为真则返回b,否则返回a
      • 常见使用场景
        • 默认值
        function print(a,b){
            var a = a || 'hello';
            var b = b || 'word';
            return a + b;
        }
        
        • 短路(上面的写法也是短路)
        function test() {
            
        }
        var a = 42;
        a && test();//只有a为真的时候才执行
        
    • Symbol的强制类型转换

      • 以上的显式和隐式的转换唯一区别在于可读性,但有一个例外-Symbol
      • Symbol可以被显示强制类型转换为string,但是不能被隐式强制转换为string或者number
        • Symbol可以被隐式转换为布尔-true
        var s = Symbol('test')
        String(s);//"Symbol(test)"
        Boolean(s);//true
        Number(s);//typeError
        if(s || "") {
            console.log('boolean')//boolean
        }
        s + "test"//typeError
        s + 12 //typeError
        
  • 宽松相等和严格相等

    • == 和===的区别
      • 在常用的说法中,我们常说== 比价的是值,===不仅比较值还比较类型
      • 正确的解释是 == 允许在相等比较中进行强制转换,而===不允许
      • == 和=== 都会检查操作数的类型,区别在于操作数类型不同时他们的处理方式
        • 两者之间的性能
        • == 不仅要判断是否相等,还要进行强制转换,但是其发生的时间在微妙级别所以不必考虑

《你不知道的JS》-中- 异步与性能-回调

  • 回调是js异步编程的基础模式,但绝不是唯一

    • 回调
    //A
    var a;
    ajax('xxxxx',function (){
        //B
    })
    //C
    
      - 分析
          - 在这段程序中,A&C是程序的现在部分,B是将来部分(异步就是由现在和将来组成),现在部分执行后,经过一段不确定的时间的等待,将来的部分执行
    
    • 嵌套回调及链式回调
      //硬编码
      listen("click",handler);
      function handler(res) {
          setTimeout(request,500); 
      }
      function request() {
          ajax('xxxx',response);
      }
      function response(text) {
          if(text === 'hello'){
              handler();
          }else if(text === 'world'){
              request();
          }
      }
      
      • 回调地狱
        • 导致的最大问题
          • 我们需要通过硬编码的方式来简化代码。
          • 硬编码的程序很脆弱,因为他没有考虑到偏离的异常情况
          • 进行了硬编码出错处理的程序会变得很难维护并且难以复用
      • 信任问题
        • 我们知道在现在的A&C执行后,在一个第三方(这里是ajax)的控制下,C在将来的某一时刻发生,注意,在此发生了控制转移(js=》第三方工具)
        • 通常我们将在程序中某一部分的执行控制交给第三方的操作称为控制反转。
        //作者的举例在我们日常开发中确实可能存在,一个付款程序,最后你需要调用某第三方库完成交易以追踪交易数据
        //第三方库analytics,trunckPurchase追踪函数 将来的时间你需要向客户收费并感谢
        analytics.trunckPurchase(purchaseData,function () {
            chargeCreditCard();
            thankMessage();
        })
        //某一天某一个客户被收了5次款,因为第三方的原因回调调用了5次
        
        • 进行修补代码,创建一个chunk来处理多个并发进程
        let flag;
        analytics.trunckPurchase(purchaseData,function () {
            if(!flag){
                flag = true;
                chargeCreditCard();
                thankMessage();
            }
            
        })
        
        • 然而还有其他的情况

          • 如果第三方根本不调用这个回调怎么办
          • 调用回调过早
          • 没有把所需的参数成功的传给你的回调
          • 吞掉可能出现的错误或者异常
        • 针对这些你将不得不做大量的逻辑处理,回调真地狱

        • 回调的最大问题就是控制反转,他会导致信任链的完全破裂

          • 如果你的程序中出现了这种控制反转的回调,而你没有进行任何逻辑来解决所有这些控制反转出现的信任问题,那么你的程序就有bug,隐藏的bug也是bug
    • 尝试挽救回调
      • 分离回调(ES6的Promise就是采用的这种方式,):一个用于通知成功,一个用于通知失败(可选,意味着可吞掉)
        ajax('xxxx',success,failre)
        
      • error-first(Node风格)
        -错误先行
  • 更高级的异步模式

    • 通过上面的信息,我们已经得到了
      • 通过回调表达程序的异步会导致
        • 缺乏顺序性
        • 缺乏可信任行(控制反转)
    • Promise
      • promise所做的事

        • 把控制反转再反转回来
        • 我们不再将自己程序的未来传递给第三方
        • 而是让第三方给我们提供其任务何时结束的能力,然后我们来决定下一步做什么
      • promise类比

        • 在餐厅点餐时,我和服务员说,我要一个汉堡,并支付了1美元。此时已经发生了一个交易,但是我还没有拿到我的汉堡,服务员会给我一个带有订单号的收据。订单号就是一个承诺(Promise),代表着我将来能拿到的汉堡。
        • 当服务员喊到,订单113号时,我去柜台有两种情况
          1. 我拿到了我的汉堡(success)
          2. 服务员告诉我汉堡卖没了(fail)
        • 还有另外一种情况是我的订单号永远不会被叫到
      • promise特性

        • 一旦被决议,就是一个不会被改变的

          • 决议函数resolve(成功)
          • 决议函数reject(失败)
        • 值- promise是一个用来封装和组合未来值的易于复用的机制

        • 如何确定一个值是不是promise

          • p instanceof Promise(promise是由new promise创建的)
            • 问题:当前窗口的promise可能是由iframe传进来的
            • 库和框架可能实现自己的promise而不是ES6的promise
          • 任何具有then方法的函数和对象
            • 任何这样的值就是promise一致的thenable
      • promise信任问题

        • 回顾回调的信任问题(把回调传入工具函数foo)
          • 调用回调过早
          • 调用回调过晚(或者不调用)
          • 多次调用回调
          • 未能传递所需的参数或者环境
          • 吞掉可能出现的异常
      • 链式流

        • promise 的then返回一个promise,因此可以实现链式调用
          • 不管promise的then调用的完成回调返回的值是什么,都会被自动设置为被链接
          function delay(time) {
              return new Promise(function (resolve,reject) {
                  setTimeout(resolve,time)
              })
          }
          delay(1000)
          .then(() => {
              console.log('第二步,1秒之后')
              return delay(2000)
          })
          .then(() => {
              console.log('第三步,2秒之后')
              return delay(3000)
          })
          

📒书单--前端相关书单

个人认为在精不在多,而且读过要有所思考,不可为读而读
读书四件套

  1. 泛读->快速浏览本书所讲内容,了解框架
  2. 初读->这一遍可以根据书中所讲内容记录笔记,初读笔记,边记边思考,问题是理解的老师,
    形成对本书的初步理解
  3. 细读->这一次要根据书中所讲内容及初读笔记整理本书概要,并且用自己的说法讲述,细读笔记
  4. 精读-> 这一边在能够根据自己的说法概括本书内容大概并且详细讲解其中某一块内容时,思考在其他书籍中有哪些书籍讲了同样的事情,并分析每一本书的优劣,形成自己的思考。

JS

  • 《你不知道的JS》(上)
  • 《 JavaScript设计模式与开发实践》
  • 《编写可维护的JavaScript》
  • 《JavaScript DOM编程艺术 (第2版)》
  • 《javascript忍者秘籍》

CSS

  • 《CSS权威指南》
  • 《CSS揭秘》

Node

  • 《深入浅出NodeJS》

Vue

重构&设计模式

📒书单--思维&学习方法

  • 《从一到无穷大》
  • 《深奥的简洁:从混沌、复杂到地球生命的起源》约翰•葛瑞宾
  • 《只有偏执狂才能生存》

《你不知道的JS》- 上 - This

  • this基本详情

    • 关键字
    • 被自动定义在所有函数的作用域中
  • 为什么加入this机制

  • 对this的误解

    • 指向自身
    • 指向函数的作用域
      • 某种情况下是对的
      • 某种情况下是错的
    • js中this和对象类似,可见的标识符都是它的属性
      • 但是作用域对象无法通过js代码访问
      • 存在与js引擎中
  • this到底是什么

    • this是在运行时绑定的,不是在书写时绑定
    • this的绑定和函数的声明位置没有关系,只与如何调用有关系
    • 当一个函数被调用,会创建一个执行上下文
      • 执行上下文包含函数在哪里被调用(调用栈)
      • 调用方式
      • 传入的参数等
    • this就是执行上下文的一个属性,会在函数执行过程中用到
  • this到底指向谁

    • 需要先找到函数的调用位置
      • 调用栈
      • 我们关心的调用位置就是当前正在执行的函数的前一个调用中
        function baz() {
            //当前的调用栈是baz
            //当前的调用位置是全局
            bar()
        }
        function bar() {
            //当前的调用栈是bar
            //当前的调用位置是baz
            foo()
        }
        function foo() {
            //当前的调用栈是foo
            //当前的调用位置是bar
        }
        baz()
        
    • 判断应用哪种绑定规则(4种)
      • 默认

        • 独立函数调用
          • 非严格模式下指向全局对象
          • 严格模式下指向undefined
          • 为什么严格模式下绑定的是undefined???
        function foo () {
           console.log(this.a) 
        }
        var a = 2;
        foo();//this指向全局对象
        
      • 显式

        • call,apply
          • 在调用时将this绑定在第一个参数上
      • 隐式

        • 调用位置是否有上下文对象(或者是否被某个对象包含)
        function foo() {
            console.log(this.a);
        }
        var obj = {
            a :2,
            foo:foo
        }
        var obj1 = {
            a :3,
            obj:obj
        }
        obj.foo();
        obj1.obj.foo();//2
        
          - 调用位置会使用obj上下文来引用函数
          - 对象属性链只有在上一层或者说最后一层在调用位置中起作用
        
        • 隐式绑定问题
          • 隐士丢失
            • 被隐式绑定的函数会丢失绑定对象
              function foo() {
                  console.log(this.a);
              }
              var obj = {
                  a: 2,
                  foo: foo
              }
              var bar = obj.foo;
              var a = 'global';
              bar();
              
            • bar是obj.foo的引用,但是实际上它引用的是foo本身
              • 实际上是一个不带任何修饰的调用,应用默认绑定
            • 函数传参传入回调函数
              • 其实就是隐式赋值
      • new 绑定

        • 实际上不存在构造函数调用,只有函数的构造调用
        • new时发生了什么
          • 创建了一个新的对象
          • 新对象会被执行prototype连接
          • 新对象会绑定到函数调用的this
          • 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象
      • 4种绑定优先级

        1. new
        2. 显式绑定
        3. 隐式绑定
        4. 默认
      • 绑定列外

        • 被忽略的this
          • 在call,apply应用时传入null的话,会被忽略,实际执行的是默认绑定规则
            • 但是会有一些副作用
        • 更安全的this
          • 更安全的做法是传入一个特殊对象
          • Object.create(null)和{}很像,但是并不会创建Object. prototype这个委托,所以它比{}“更空”
            bind进行柯里化是???
            function foo (a,b) {
                console.log(a,b)
            }
            var ø = Object.create(null);
            foo.apply(ø,[ a, b])//2,3
            //使用bind进行柯里化
            

《Vue深入浅出》-- patch

  • patch
    • 是什么
      • 本质上就是通过对比oldVnode和vnode,渲染不同的部分(手段)
      • 渲染视图(目的)
    • 如何渲染DOM
      • 新增DOM节点
        • 什么情况下新增
          • 首次渲染(oldVnode没有)
          • oldVnode与vnode不一样时,以vnode为准
        • 如何创建节点
          • 我们是根据vnode的类型来创建DOM元素,但vnode有5种类型,其中只有三种会被创建并插入到DOM元素中
            • 元素节点
            • 注释节点
            • 文本节点
          • 创建步骤
            1. 判断是否有tag属性(只有元素节点有tag属性)
            2. 是=》 使用createElement方法创建真实节点 =》 appendChild方法插入到指定父节点(其中创建子节点是递归的方式)
            3. 不是。判断是否有isComment属性(只有文本节点有这个属性)
            4. 有isCommont =》文本节点 =》 调用createTextNode方法创建真实的文本节点并插入到指定父节点
            5. 没有isComment=》 调用createComment方法创建并插入到指定父节点
      • 删除DOM节点
        • 新增中已提及,当oldVnode与vnbode不同时,需要使用vnode生成的DOM替换oldVnode的DOM(先插入到旧节点旁边,再将旧节点删除)
        • 如何删除
          • removeChild
      • 修改需要更新的DOM节点
        • 新旧节点是同一个节点
        • 进行更细致的对比,替换其中的变化
        • 如何更新节点
          1. 判断是否是静态节点(静态节点就是一旦渲染到页面,无论日后状态如何变化,都不会发生任何变化的节点)
          //举例
          <p>我是一个静态节点</p>
          
          1. 如果不是静态节点,需要以新的虚拟节点为准来更新视图。

          2. 此时分为两种情况。

          3. 当新生成的vnode有text属性时(文本节点),并且和oldVnode的text属性不一样时,直接调用setTextContent更新

          4. 没有text属性(元素节点)

          5. 判端元素节点是否有children子节点

          6. 有子节点。
            判断oldVnode是否有子节点

            • 有。对两个子节点进行更详细的对比
              • 更新节点
              • 新增节点
                • vnode中的newChildren(子节点列表)有一个节点在oldvnode中不存在,则新增
              • 删除节点
              • 移动节点位置
            • 没有子节点
          7. 无子节点。

            • 当新创建的节点即没有text,也没有children,说明是一个空节点。此时如果oldVnode中有子节点就删除子节点,有text就删除text。
        • 更新子节点
          • 上面在更新节点的时候我们看到当vnode和oldVnode中的子节点都存在,会进行进一步的详细比较,那么是怎么比较,更新的呢(循环新子节点和旧子节点做对比)
          • 分为4种情况
            • 新增节点
              • 什么情况下新增:
                • 新子节点中有一个节点在旧子节点列表中不存在
                • 放在什么位置
                  • 有oldChildren里面所未处理节点的前面
            • 删除节点
              • 什么情况下新增:
                • 旧子节点中有一个节点在新子节点列表中不存在
              • 当newChildren循环结束后,如果oldChildren中还有未被处理的节点,那就是需要删除的
            • 更新节点
              • 新子节点中有一个节点和旧子节点列表中一个节点相同并且位置相同
            • 移动节点
              • 什么情况下移动:
                • 新子节点中有一个节点和旧子节点列表中一个节点相同,但是位置不同
              • 移动到哪里
                • 所有未处理节点的最前面
          • 优化策略
            • 通常情况下并不是所有子节点都会移动
            • 避免循环查找浪费性能
            • 快捷查找
              • 新前&旧前(所有未处理节点的第一个和最后一个)
                • 是同一个,更新即可
                • 不是,使用下面3种
                • 下面3种也没有匹配,再使用循环在oldChildren中查找
                • 大部分情况下使用这4种方式可以找到,省去了很多循环的时间
              • 新后&旧后
              • 新后&旧前
                • 移动到所有未处理节点后面
              • 新前&旧后
                • 移动到左右未处理节点前面
            • 如何区分已处理和未处理节点
              • oldStartIdx
              • oldEndIdx
              • newStartIdx
              • newEndIdx
              • 只有在oldStartIdx <= oldEndIdx&& newStartIdx <=newEndIdx,才进入循环
              • 每次根据情况newStartIdx++,oldStartIdx++,newEndIdx--,oldEndIdx--
            • 其他的循环逻辑

    • 流程
    graph LR
    Start((patch)) --> Vendor[oldVnode是否存在]
    Vendor --> |不存在| Solution(新增) 
    Vendor --> |存在| Function[ oldVnode和vnode是否是一个节点]
    Function --> 
    |是| solu[使用patchNode进行更详细的对比]
    Function --> 
    |不是| solu1[使用vnode创建新的节点并插入到旧节点旁边]
    solu1 --> solu2[删除旧节点]
    

《webpack实战》- 预处理器

  • 在日常开发中经常预编译代码

    • 例子:使用Babel转译ECMAscript中的新特性
    • 使用scss或者less编写样式
  • webpack一切皆模块

  • loader

    • 什么是loader
      • 输入与输出
        • webpack4之前,必须都是字符串
        • webpack4之后,可以是字符串,AST对象,source map
      • 特性
        • 链式的
        //如在工程中编译SCSS时,我们可能需要如下loader:
        Style标签=style-loader(css-loader(sass-loader(SCSS)))
        
        • webpack本身只认识javascript,对于其他类型的资源必须预先定义一个或者多个loader对其进行转译,输出为webpack可以接收的形式再继续进行,因此loader做的实际上是一个预处理的工作
    • loader配置
      • 与loader相关的配置都在module对象中
      • module.rules代表模块的处理规则
        • test
          • 可以接收一个为正则或者元素为正则的数组
        • use
          • 字符串:一个loader可以使用字符串
          • 数组:多个loader需要写成数组(倒序执行)
        • exclude&include
          • 接收绝对路径
          • 字符串或者正则,以及由它们组成的数组
          • exclude,include同时存在的时候exclude优先级更高
        • resource&issuer
          • resource:被加载模块
          • issuer:加载模块
          • test,use,exclude等都是针对resource的配置
        • enforce:指定loader执行顺序
          • inline:官方不推荐使用了
          • normal:默认
          • pre:代表将在所有正常的loader之前执行
          • post:代表将在所有的loader之后执行
    • 常用loader介绍
      • babel-loader

        • 功能:处理ES6+代码,将其编译为ES5
        • 安装:npm i babel-loader @babel/core @babel/preset-env
          • babel-loader:使Babel与Webpack协同工作的模块
          • @babel/core:Babel编译器的核心模块
          • @babel/preset-env:它是Babel官方推荐的预置器,可根据用户设置的目标环境自动添加所需的插件和补丁来编译ES6+代码。
        • 注意事项:
          • exclude:添加node_modules,以免拖慢打包速度
          • cacheDirectory配置项:启动缓存机制,重复打包未改变过的模块时防止二次编译
          • 由于@babel/preset-env会将ES6 Module转化为CommonJS的形式,这会导致Webpack中的tree-shaking特性失效(关于tree-shaking会在第8章详细介绍)。将@babel/preset-env的modules配置项设置为false会禁用模块语句的转化,而将ES6 Module的语法交给Webpack本身处理。
      • ts-loader

        • 功能:用于连接Webpack与Typescript的模块
        • 安装:npm i ts-loader typescript
        • 注意事项:
          • Typescript本身的配置并不在ts-loader中,而是必须要放在工程目录下的tsconfig.json中
      • html-loader

        • 功能:将HTML文件转换为字符串,并进行格式化。使得我们可以把一个HTML片段作为js引入
          • header.html将会转化为字符串,并通过document.write插入页面中。
        • 安装:npm i html-loader
      • handlebars-loader

        • 功能:用于处理handlebars模板
        • ??handlebars是什么
      • file-loader

        • 功能:用于打包文件类型的资源,并返回其publicPath
          • 对png、jpg、gif这类图片资源使用file-loader,然后就可以在JS中加载图片了。
        • 安装:npm i file-loader
        • 注意事项:
          • 可以设置publicPath
          • file-loader中options.publicPath会覆盖Webpack配置的publicPath
      • url-loader

        • 功能:url-loader与file-loader作用类似,唯一的不同在于用户可以设置一个文件大小的阈值,当大于该阈值时与file-loader一样返回publicPath,而小于该阈值时则返回文件base64形式编码
        • 安装:npm i url-loader
      • vue-loader

        • 功能:处理vue组件
        • 安装:npm i vue-loader
        • 注意事项:
          • 除了必要的vue与vue-loader以外,还要安装vue-template-compiler来编译Vue模板,以及css-loader来处理样式

《Vue快跑》

vue基础

  • v-if/v-show

    • v-if:为真时才渲染,所以性能开销大,需要频繁切换时可使用v-show
    • v-show:如元素含有图片,可以提前加载
  • vue的响应式

    • 如何实现的:
      • vue修改了每个添加到data上的对象,当该对象发生变化时vue会收到通知,从而实现响应式。
      • 对象的每个属性会被替换为getter和setter方法,因此可以像使用正常对象一样使用它,但当你修改这个属性的时候,vue会知道它发生了变化。
      • Object.defineProperty()
      • 同时vue还使用代理方法封装了被观察的数组对象上的一些数组方法(如splice),来观察数组方法何时被调用,这也是为什么你使用splice()时,vue知道你更新了数组并触发了必要的视图更新。
  • 动态设置html

    • 这一功能务必谨慎使用,因为可能造成安全漏洞XSS攻击
    • 用户可以输入或者改动的地方不可以使用
    • v-html只处理你信任的数据
  • 计算属性

    • 计算属性可以实现复杂的逻辑,当然这一点方法也可以做到
    • 区别在于:计算属性是响应式缓存,也就是说在值不变的情况下,不会重复计算,而是使用缓存,大大提升性能。
    • 并且计算属性有getter和setter属性
  • 侦听器(与计算属性类似,可以监听数据的变化)

    • 大部分的工作无需侦听器,可以使用带有set的计算属性就可以
    • 适用于侦听器的集中情况
      • 异步处理
      • 监听数据对象的某一个属性
  • 过滤器

    • 适用于:对字符串或者数字的显示变化进行处理
    • 实践:可以把所有过滤器放在单独的filters.js中
    • 使用注意:过滤器是组件中唯一一个不可以使用this的地方,原因在于过滤器需要是一个纯函数(输入的值相同则返回同样的值)
    • 只可以在插值和v-bind的指令地方使用过滤器
  • 事件

    • 可以说很常见了,经常被简写为@
    • 事件修饰符
      • @click.prevent(阻止事件默认行为:如跳转)
      • @click.once(只触发一次)
  • 生命周期

    • new Vue()时初始化,初始化前beforeCreate会被调用
    • created
    • 解析模版,挂载DOM,前beforeMount
    • mounted(注意,vue2.0版本中并不确保mounted触发时元素已经被添加到DOM上了,可以使用nextTick
    • DOM更新,前,beforeUpdate
    • updated
    • 组件销毁,前,beforeDestroy
    • destroyed
  • 自定义指令

    • 什么情况下可以使用自定义指令呢?

组件

  • 数据,方法,计算属性

    • 数据data:组件和实例之前的data有所不同
      • 组件的data是一个函数
      • 实例的data是一个对象
      • 原因:一个组件可以在一个页面多次引用,为了避免他们共享一个数据
  • 传递数据

    • props:
      • 通过html的属性传入组件的
      • 验证:
        • 单一传递数据时props是一个数组
        • 当需要验证是props是一个对象
        props:{
            price:Number
            //或者
            gender:[Boolean,String]
        }
        
        • 也可以进行多项目认证
        props:{
            price:{
                type:Number,
                required:true,
                validator(value){
                    return value > 0
                }
            }
        }
        
      • 响应式
        • 父组件传递给子组件的数据发生变化时,子组件的数据也会被更新
      • 数据流和.sync修饰符
        • 单向下行绑定(防止子组件在无意中更改数据)
        • .sync可以使数据变为双向绑定
  • 使用插槽slot将内容传递给组件

    • 传递给组件的内容会替换掉它里面的slot元素输出到页面上
    • 具名插槽:一个组件内有多个插槽的时候就需要具名插槽
    • 作用域插槽:
  • 自定义事件

  • 混入

    • 混入类似与utils
    • 可以在不同的组件中复用相同的逻辑代码
    • 当混入和组件合并时,除声明周期外的所有代码,混入将被组件所替代,生命周期会被放进一个数组里并全部执行(因此在定义混入的数据时,应该订单自己的私有属性,可以在名字前面加入前缀,如$_logMixin_log())
  • vue-loader和.vue文件

    • 组件自定义的属性和外部传入的属性之前的问题:
    • class和style会被合并,其他的会被覆盖
  • 非prop属性

  • 组件和v-for指令

  • 总结

使用Vue添加样式

  • 绑定class

    • 数组形式
    <div :class="[firstClass,secondClass]"></div>
    
    • 对象形式(属性值为真展示)
    <div :class="{'firstClass':,isFirstClassTrue}"></div>
    
    • 混用
    <div 
    :class="[
        baseClass,
        {'firstClass':,isFirstClassTrue}
    ]"></div>
    
  • 绑定style

    • 通常情况下使用class是更改的选择
    • 在动态绑定样式的时候可以选择style
    <div
    v-for="n in items"
    :style="{
        backgroundColor:getColor(n)
    }"></div>
    getColor(n){
        return `hsl(${(n-1)*30},100%,75%)`;
    }
    
  • 用Vue-loader实现Scoped CSS

    • 原理
      • 使用了scoped的css只作用域该组件,在html中展现的就是给每个元素添加了data属性
      • 然后又将它添加到了css选择器中
    • 缺点
    • 适用场景
  • 用Vue-loader实现CSS Modules

    • scoped css的替代方案
    <template>
        <p :class="$style.number">测试</p>
    </template>
    <style module>
        .number {
            ...
        }
    </style>
    
      - .number样式会被一个随机的样式名称取代,实际渲染的html
      ```
       <p class="_3gAVtKk0CevA6g0YqugHN5_0">测试</p>
      ```
      - 可以通过$style.number进行引用
    
    • 什么情况下需要使用module,而不是scoped???
  • 预处理器

render函数和jsx

📒书单--传记

  • 《昂纳德·科恩传记》
  • 《爱因斯坦传》
  • 《本杰明·富兰克林自传》
  • 《荣格自传》
  • 《约翰逊传》

《人生的智慧》-叔本华

人生的智慧不在于追求幸福,而是避免痛苦。

青年时代的我们还没有那么多经历告诉我们,你的欲望越多,得到的话,得到的快乐越多,快乐越转瞬即逝。得不到的话,失望越多,痛苦越多。所以无论结果怎样意欲带给你的是更多的痛苦和短暂的快乐。

生存于世,为了过的幸福,你要做的也许就是

  • 1.放平心态,不要因为别人或鲁莽或讽刺而心生愤怒,要无视。
  • 2.与人交往要长久的在细小之处观察,与公正善良道德之人相处,因为一个人的本性是永远不会改变的。如果他做了一件让你愤怒的事,要思考,这个人的价值是否值得你忍受。因为再遇见同样的情景他还会如此做即便他方式发自肺腑的保证永不再犯。
  • 3.不要在别人面前展示你的智慧和**,因为这样会让人觉得你在讽刺他自己的愚蠢而心生怨恨。
  • 4.不要评论他人,两个人做一件事已经说明了不一样。
  • 5.为老年生活储存足够的金钱和健康,所以在年轻时就应该理财,节约,锻炼身体。
  • 6.所有已经发生的事都是无可避免的必然事件。
  • 7.如果你能做到完全的依赖自己,你的所有需求都能从自身获得,那么你就得到了幸福。

《webpack实战》-资源输入与输出

  • webpack
    • 资源的输入与输出
      • 概念理解
        • chunk
          • 字面意思:代码块,根据配置不通,一个工程打包可能生成一个或多个代码块
          • 比喻:文件袋,里面又很多文件,每一个文件都是一个模块
          • webpack会从入口处开始检索,将具有以来关系的模块生成一个依赖树,最终得到一个chunk
        • bundle
          • 由chunk得到的打包产物,我们称之为bundle
      • 配置资源入口
        • 主要目的:
          1. 确定入口模块位置,告诉webpack从哪里还是打包
          2. 定义chunk name
            • 又一个入口,可以默认为main
            • 多个入口就要自定义chunk name,作为改chunk的唯一标示
          • context是什么
            • 资源入口的路径前缀
            • 用处:多个入口时可以使得入口书写更简洁
            • 注意:必须使用绝对路径
        • 配置方法:
          • entry支持字符串
          • 数组
            entry:['bable-profill','./src/index.js']//使用数组的最后一项作为实际的入口,相当于
            entry:'./src/index.js';
            
            //index.js
            import 'babel-profill';
            
          • 对象
            • 要想定义多入口文件,必须使用对象形
            • 对象的属性名是chunk name,属性值是入口路径
          • 函数
            • 返回上面任意值即可
            • 支持使用Promise进行异步操作
        • 实际应用
          • SPA
            • 多数配置一个entry
              • 优点:只会产生一个JS文件,依赖关系清晰
              • 缺点:应用规模大的时候导致体积过大,降低页面渲染速度
              • 一点点改动,都需要重新下载整个资源
                • 解决方案
                  • 提取vender(什么是vender)
                  • 工程所使用的第三方库和框架集中打包产生的bundle
                    - 这一部分不会经常变动,可以有效的利用缓存
      • 配置资源出口
        • 配置项
          • filename:控制输出资源的名字
            • 字符
              • 也可以是相对路径
              output:'./dist/index.js';
              
            • 多入口时
              module.exports = {
                  entry:[
                            vendor:'./src/app.js',
                      main:'./src/index.js'
                  ],
                  output:{
                      filename:'[name].js'
                      //[name]会被替换为chunk name,最后项目中实际生成的资源是vendor.js与app.js
                  }
              }
              
          • path
            • 功能:指定资源的输出位置
            • 必须为绝对路径
          • publicPath
            • 功能:指定资源的请求位置
            • 什么是资源路径
              • 页面中有两种资源
                • 由页面的HTML里面的script请求的直接资源
                • 由js或者css请求的间接资源(异步加载的js,css请求的图片等)
              • 资源路径就是指间接资源路径
            • 3种形式
              1. HTML相关
                • 以当前HTML所在路径加上相对路径
                //html位置http://example.com/app/index.html
                //异步加载的资源名为0.chunk.js
                publicPath:''//实际路径http://example.com/app/0.chunk.js
                publicPath:'./src'//实际路径http://example.com/app/src/0.chunk.js
                publicPath:'../assets'//实际路径http://example.com/aassets/0.chunk.js
                
              2. HOST相关
                • publicPath的值以'/'开始
                //html位置http://example.com/app/index.html
                //异步加载的资源名为0.chunk.js
                publicPath:'/'//实际路径http://example.com/0.chunk.js
                publicPath:'./js/'//实际路径http://example.com/js/0.chunk.js
                
              3. CDN相关
                • 以上都是相对路径,也可以使用绝对路径配置,这种情况一般是静态资源放在CDN上
                • 以协议或者相对协议开始
                //html位置http://example.com/app/index.html
                //异步加载的资源名为0.chunk.js
                publicPath:'http://www.cdn.com/'//实际路径http://www.cdn.com/0.chunk.js
                publicPath:'//www.cdn.com/assets/'//实际路径//www.cdn.com/assets/0.chunk.js
                
              • 注意点:
                • webpack-dev-server中也有一项publicPath配置
                • 指定的是webpack-dev-server上的静态资源的路径
                output:{
                    path:path.join(__dirname,'dist'),
                    devServer:{
                        publicPath:'/assets/'
                    }
                }
                
                • Webpack配置中output.path为dist目录,因此bundle.js应该生成在dist目录。但是当我们启动webpack-dev-server的服务后,访问localhost:3000/dist/bundle.js时却会得到404。这是因为devServer.publicPath配置项将资源位置指向了localhost:3000/assets/,因此只有访问localhost:3000/assets/bundle.js

《如何高效学习》

高效学习:指机械性学习的相反面,不是单纯的死记硬背

高效学习步骤:

  1. 获取
    • 指的是信息的来源,方式多种
      • 阅读
      • 听课
    • 目标
      • 信息要精确
      • 信息量要压缩
    • 找出薄弱环节
      • 学习习惯不好,容易分心,无法长时间集中注意力
      • 笔记记的不好
        • 太多=》没有时间思考
        • 太少=》信息不精确
  2. 理解
    • 获取之后接下来的步骤就是理解
    • 并且放在上下文中联系(这就是高速公路,连接每一个模型的纽带)
  3. 拓展
    • 这是最重要的部分
    • 拓展更多的模型和高速公路
    • 举例
      • 学习一个公式
        • 公式是怎么来的(深度拓展)
        • 公式中的每一个成分代表的真实含义是什么
        • 公式中的哪些成分可以做些改变
        • 改变后结果会怎样
        • 其他公式和这个公式之前的联系,相同与不同
        • 这个公式可以与哪些结构相联系(纵向拓展)
    • 找出薄弱环节
      • 无法举一反三
  4. 纠错
    • 在拓展的知识中寻找错误,并删除
    • 可采用的方法
      • 放在现实世界中检验
      • 阅读相反观点的书籍
  5. 应用
    • 实践出真知,任何不能经受现实的磨练的道理都不是真理
    • 找出薄弱环节
      • 书呆子,道理我都懂。。。

信息结构

信息有不同的种类,那么学习不同信息的方式也应该是不同的,就像不同大小的子弹需要装在不同型号的手枪里,才能发挥自己的威力。

  • 随意信息
    • 特点:一系列基本事实,没有逻辑规律,容易遗忘
    • 具体:医学中的,人有206块骨头
    • 学习方式:
      • 联想法
      • 挂钩法
      • 压缩法
  • 观点信息
    • 特点:存在争论的信息,李白和杜甫的诗哪个更好?
    • 难点:需要检查大量信息以寻找其中的模式
    • 学习方法:
      • 速读技巧
      • 图表法
  • 过程信息
    • 特点:
      • 教导你怎么行动的信息
      • 大多数过程信息都有一个正确的模型
        • 内在化
        • 比喻法
        • 图表法
        • 模型纠错
    • 实例:如何滑雪
    • 学习方法:
      • 不断的实践
      • 反复的练习
  • 具体信息
    • 特点:实际生活中可以观察到,听到的信息
    • 具体:生物学里的人体构造,牙齿,骨骼等
    • 学习方法:大多数方法都可以应用
  • 抽象信息
    • 特点:逻辑性强,需要想象力
    • 具体:化学,心理学
    • 学习方法:
      • 内在化
      • 比喻法
      • 模型纠错

如何学习

  • 判断信息属于哪一类

整体性学习技巧

  • 获取信息
    • 快速阅读(提高阅读速度和理解力)
      • 读的更快且理解的更好,你所获得的知识就更多
      • 推荐书籍:快速阅读突破
      • 方法:
        • 指读法
          • 以手指控制你阅读的速度
          • 可以轻松提高你的阅读速度
        • 练习阅读法
          • 指读法可以提高你的阅读速度,但是速度并不是唯一的追求,还需要理解
          • 联系:
            • 计时3分钟,阅读一份文章,然后默写出你记住的知识点
            • 再阅读一遍文章,边看边记录下所有知识点
            • 比较两份记录,
        • 积极阅读法
          • 准备一个笔和笔记本,记录下标题和副标题
          • 每读完一部分(指读法),尽量记下
            • 这段文章的观点是什么
            • 如何记住这些观点
            • 如何拓展及应用这些观点
          • 在你熟悉这种方法后,只需要在你理解困难的地方使用即可
      • 练习
        • 一到两本书籍
        • 3周每天15min练习阅读法
        • 指读法2周
        • 每周一次积极阅读
    • 笔记流
  • 联系观点
    • 比喻
    • 内在化
    • 图表法
  • 随意信息的处理
    • 联想法
    • 挂钩法
    • 信息压缩技术
  • 知识扩展
    • 实际应用
    • 模型纠错
    • 以项目为基础的学习

《如何高效学习》

高效学习:指机械性学习的相反面,不是单纯的死记硬背

推荐书籍:精力管理:管理精力,而非时间,是高效、健康与快乐的基础》(The Power of Full Engagement)
《批处理:节省时间,减轻压力的20个小技巧》
《Zen to Done》
《how to be a stright-A student》
《how to win at college》

高效学习步骤:

  1. 获取
    • 指的是信息的来源,方式多种
      • 阅读
      • 听课
    • 目标
      • 信息要精确
      • 信息量要压缩
    • 找出薄弱环节
      • 学习习惯不好,容易分心,无法长时间集中注意力
      • 笔记记的不好
        • 太多=》没有时间思考
        • 太少=》信息不精确
  2. 理解
    • 获取之后接下来的步骤就是理解
    • 并且放在上下文中联系(这就是高速公路,连接每一个模型的纽带)
  3. 拓展
    • 这是最重要的部分
    • 拓展更多的模型和高速公路
    • 举例
      • 学习一个公式
        • 公式是怎么来的(深度拓展)
        • 公式中的每一个成分代表的真实含义是什么
        • 公式中的哪些成分可以做些改变
        • 改变后结果会怎样
        • 其他公式和这个公式之前的联系,相同与不同
        • 这个公式可以与哪些结构相联系(纵向拓展)
    • 找出薄弱环节
      • 无法举一反三
  4. 纠错
    • 在拓展的知识中寻找错误,并删除
    • 可采用的方法
      • 放在现实世界中检验
      • 阅读相反观点的书籍
  5. 应用
    • 实践出真知,任何不能经受现实的磨练的道理都不是真理
    • 找出薄弱环节
      • 书呆子,道理我都懂。。。

信息结构

信息有不同的种类,那么学习不同信息的方式也应该是不同的,就像不同大小的子弹需要装在不同型号的手枪里,才能发挥自己的威力。

  • 随意信息
    • 特点:一系列基本事实,没有逻辑规律,容易遗忘
    • 具体:医学中的,人有206块骨头
    • 学习方式:
      • 联想法
      • 挂钩法
      • 压缩法
  • 观点信息
    • 特点:存在争论的信息,李白和杜甫的诗哪个更好?
    • 难点:需要检查大量信息以寻找其中的模式
    • 学习方法:
      • 速读技巧
      • 图表法
  • 过程信息
    • 特点:
      • 教导你怎么行动的信息
      • 大多数过程信息都有一个正确的模型
        • 内在化
        • 比喻法
        • 图表法
        • 模型纠错
    • 实例:如何滑雪
    • 学习方法:
      • 不断的实践
      • 反复的练习
  • 具体信息
    • 特点:实际生活中可以观察到,听到的信息
    • 具体:生物学里的人体构造,牙齿,骨骼等
    • 学习方法:大多数方法都可以应用
  • 抽象信息
    • 特点:逻辑性强,需要想象力
    • 具体:化学,心理学
    • 学习方法:
      • 内在化
      • 比喻法
      • 模型纠错

如何学习

  • 判断信息属于哪一类

整体性学习技巧

  • 获取信息

    • 快速阅读(提高阅读速度和理解力)
      • 读的更快且理解的更好,你所获得的知识就更多
      • 推荐书籍:快速阅读突破
      • 方法:
        • 指读法
          • 以手指控制你阅读的速度
          • 可以轻松提高你的阅读速度
        • 练习阅读法
          • 指读法可以提高你的阅读速度,但是速度并不是唯一的追求,还需要理解
          • 联系:
            • 计时3分钟,阅读一份文章,然后默写出你记住的知识点
            • 再阅读一遍文章,边看边记录下所有知识点
            • 比较两份记录,
        • 积极阅读法
          • 准备一个笔和笔记本,记录下标题和副标题
          • 每读完一部分(指读法),尽量记下
            • 这段文章的观点是什么
            • 如何记住这些观点
            • 如何拓展及应用这些观点
          • 在你熟悉这种方法后,只需要在你理解困难的地方使用即可
      • 练习
        • 一到两本书籍
        • 3周每天15min练习阅读法
        • 指读法2周
        • 每周一次积极阅读
    • 笔记流
      • 重点:知识繁多的时候,使用线条将各部分的知识点连接起来,形成一张知识网

      • 分类

        • 简单笔记流
        • 混合笔记流
          -课下笔记流: 结合课上记笔记的形式,课下整理成笔记流
          • 批注流:将老师说的话写上批注
      • 练习

        • 2周内每天练习一次,把课堂上的笔记拿出来,按照笔记流的方式重新记录记录知识点并在知识点之前画线
        • 练习将其他技术融合到笔记流中(图表法,比喻法,信息压缩技术)
  • 联系观点

    • 比喻
      • 用途:
        • 使用你有经验的东西描述你不曾有经验的东西,以加深你的理解
      • 例子:
        • 条件反射:巴浦洛夫的实验,按铃,然后给狗食物,一段事件后,按铃,不给食物,狗也会分泌唾液
        • 作者比喻法:人在雪地中行走,茫茫天地没有路,走出一条,以后就会在这条路上行走
        • 我的比喻:吃饭,连续一个月到一家店里吃饭,某一天开始不想去这家吃饭了,结果还是不知不觉的走到这家店
      • 问题:比喻法其实不是很精准的描述,可能是某一方面很像,我们要多尝试想象多种比喻,在不同的方向上运用比喻,以便记得更准确
      • 步骤:
        1. 确定你要深入理解和记忆的信息
        2. 在你个人的经验中寻找与信息相似的部分,要达到完全符合不太可能,找到十几个部分符合的不完美比喻
        3. 重复2步骤,检查比喻不恰当的部分呢
      • 技巧:
        • 要有寻找的欲望
        • 注意第一个出现的念头
        • 优化和测试你的比喻
      • 练习:
        • 2周内每天一次好好阅读学习内容,至少记录5个观点
        • 针对每一个观点,写一个比喻法
        • 假如比喻不能完美阐释观点,寻找更多的比喻
        • 能否用这个比喻解释给10岁的孩子
    • 内在化
      • 什么是内在化:视觉化是将一种东西想象成图片或者影像,内在化则是视觉化的加强版,在视觉化的基础上增加触感,听觉和情感等,这样加强的练习会让知识记得更加深刻。
      • 具体例子:数学中的矩阵计算行列式的问题:左上和右下的数字相乘减去右上和左下的数字相乘
        • 想象有一个2 ✖️ 2的表格,右手从左上移动到右下,在表格中留下蓝色的痕迹,右手的重量加重,然后左手从右上移动到左下,留下红色的痕迹,右手的重量减轻
      • 如何进行内在化
        • 确定要内在化的概念
        • 从建立脑海中的图像开始
        • 脑海中的图像是静态的,还是动态的
        • 加上其他的感官
        • 加入更多的感情和情感
        • 不断重复和优化图像,直到你一想到它就能很快地回忆起知识
      • 练习
        • 取一张白纸和笔,准备作画
        • 打开课本,找到两个概念或观点
        • 在脑海中建立图像,将感觉和情感加上去
        • 根据脑海中所想,快速画出概念的图像(1min之内)来
        • 2周每天选几个概念练习
    • 图表法
      • 是内在化的简化
      • 类型:
        • 流程图

          • 适用范围:
            • 绘制一系列的流程:如蛋糕怎么做
            • 绘制历史事件:创建分支将事件练习在一起
            • 绘制一个系统:如函数在程序中如何执行
        • 概念图

          • 建立知识点之间的联系
            • 小说中的人物关系
        • 图像

          • 简单的涂鸦
      • 练习:
        • 找到一个观点或者一系列概念,准备画图表
        • 设定2-5min,画图表
        • 时间一到,停止画图,计算你画了多少信息,建立了多少练习
        • 2周练习
    • 以上的三种联系观点的方法可以混合使用,比喻,内在化和图表
  • 随意信息的处理

    • 联想法
      • 适用信息:随意信息
      • 将信息连接在一起,一旦进入某一个链,可以轻松到达其他得到信息链
      • 使用方法:
        1. 创造顺序(香蕉-苹果-葡萄-牛奶-鸡蛋)
        2. 给顺序中的每一项设置一个符号(符号需要可以很快联想到原始知识,顺序中有重复内容时使用不同颜色区分)
        3. 创建属于自己的联想(创造夸张的图像将符号联系在一起)
        4. 回忆刚创建的练习,是否可以轻松联系各个知识
      • 练习:
        • 选择可以组成洗个顺序的一组知识,可以是公式,历史等
        • 重复上面联想法
        • 练习一周后,将练习过的知识点拿出来检查否仍然记忆深刻
        • 2周后,开始限定时间,提高速度
      • 注意:本书作者更喜欢内在化,图表法和比喻法学习知识
    • 挂钩法
    • 信息压缩技术
  • 知识扩展

    • 实际应用
      • 练习:
        • 每周抽出一点时间,将学习到的知识运用在生活中。
        • 罗列更多可能会使用的地方
    • 模型纠错
      • 不断的实践和反思
    • 以项目为基础的学习
  • 整体性学习的实际应用-费曼技巧

    1. 选择要学习的概念(一张白纸,左上写下概念)
    2. 设想你是一名老师,需要教导一个学生理解这个概念
    3. 当你感到疑惑的时候,返回
    4. 简单化和比喻(如果你的解释很晦涩就会很难懂)

超越整体性学习

高效率学生的关键点

  • 能量管理

    1. 增加你的能量储备
      • 每天至少锻炼40min
      • 每天保障7-8h睡眠
      • 饮食戒高糖,高脂肪,多吃粗粮
      • 多喝水
      • 少食多餐,7分饱
    2. 将你的日程表由线性的改为循环型的
      • 集中小部分时间做大部分工作,有张有弛
      • 一周休息一天,将7天的活放在6天里面完成
      • 晚上不干活,将工作放在早上完成
      • 设定90分钟,这个时间里集中精力完成学习
  • 不要学习

    • 在没有明确的学习目的的情况下,读死书
  • 绝不拖延时间

    • 周/日目标体系
      • 每周周末,列出下周的目标,包括下周应该学习的内容,阅读的书籍等
      • 每天晚上,列出日计划,检查周计划的完成
  • 批处理

    • 什么是批处理:将那些散在的,但是类似的事情集中起来一起处理
    • 作者使用的方式:在一周的一个时间内将要读的内容全部读完或者将一周要写的3篇文章全部写完
    • 技巧
      • 使用批处理的工作不可以耗费太久的时间,超过3小时的事情就不适用了
      • 一次性完成作业。
        • 如果完成一个作业的时间不超过8小时,就坐下一次性完成它。
      • 提高注意力阀值
        • 通过不断的处理批处理事物,可以快速提高你的注意力集中时长
  • 有组织

    1. 所有物品都放在固定位置
    2. 随身携带一个笔记本
    3. 坚持日历和做事清单
  • 自我教育

    • 方向
      • 编程
      • 写作
      • 心理学等
    • 作者经常进行自我教育
      • 学习并且重要的是不断的应用到生活中
      • 采用项目为基础的学习方式
    • 养成良好的习惯
      • 每日阅读
        • 作者检出每日阅读并且每周至少阅读一本书,每年至少读50-70本书
      • 每日练习
      • 每日目标
      • 每日习惯
        • 坚持某个习惯30天
        • 坚持下去
        • 享受这个习惯
        • 寻找特殊的时段:早上阅读
      • 克服挫折和失败
        • 写下任何障碍
        • 使用网络
          • 如果你不明白某一问题,就查找答案
        • 找一本关于怎么做的工具书
        • 换一个角度试试
          • 碰到某一障碍,尝试取学习其他相关的知识,再回过头来看
      • 设置目标
        • 一个有吸引力的目标可以帮助你快速成长
        • 举例
          • 每年的阅读量达到。。。
          • 在一定的期限内,学会某一件事
        • 方法
          • 写下目标
          • 让目标具体化
          • 设定有些困难,但是努力一下可以达到的目标
          • 将目标的完成转化为每日和每周的具体行动
          • 经常看看你的目标(至少一周检查一下)

整体性学习小结

  • 从智力挑战开始
    • 至少坚持3周
    • 一次只做一个挑战,人的精力有限
    • 比喻,内在化和图表法优先,这是整体性学习的核心
    • 使用奖励材料
    • 记录下学习的过程
  • 概念小结
    • 结构
      • 关于某一个学科的知识之间联系的综合,是你大脑中的城市
    • 模型
      • 将信息压缩成最基本的单元,使用比喻,内在化和图表法形成模型
    • 高速公路
      • 不同结构之间的联系

《CSS揭秘》

  • 尽量减少重复(同理适用与其他编程语言)
    • 尽量减少在改变时需要重复编辑的地方
    • 举例
      • 现在我们有一个按钮
      button {
        padding:6px 16px;
        border: 1px solid #ccc;
        background:#58a linear-gradient(180deg,#77a05b, #58a);
        border-radius:4px;
        box-shadow: 0 1px 5px gray;
        color:white;
        text-shadow:0 -1px 1px #315566;
        font-size:12px;
        line-height:30px;
      }
      
      • 问题:
        • 如果不同大小的按钮时不能复用代码,需要改变行高还有padding,因为他们都写成了绝对值
      • 解决方案:如果两个数值之前存在关联,就用代码表现出来
      font-size:125%;/*假设父级的字体大小是16px*/
      line-height:1.5;/*设置数字,此数字会与当前的字体尺寸相乘来设置行间距。*/
      
      • 问题:想要一个类似的不同颜色,需要改变text-shadow,box-shadow,background,border四个属性
      • 解决方案:把半透明的黑色或者白色叠加在主色调上
      button {
        padding:0.3em 0.8em;
        border: 1px solid rgba(0,0,0,0.1);
        background:#58a linear-gradient(hsla(0,0%,100%,0.2), transparent);
        border-radius:0.2em;
        box-shadow: 0 0.05em 0.25em rgba(0,0,0,0.5);
        color:white;
        text-shadow:0 -.05em 05em rgba(0,0,0,0.5);
        font-size:125%;
        line-height:1.5;
      }
      .red{
          background-color:red;
      }
      
      • 其他技巧

《你不知道的JS》-上-混合对象类&原型

混合对象类

面向类的设计模式:实例化,继承,多态

js中的类都是类似类,并不是真正的类,包括es6的class

类的机制

  • 构造
    • 一个类相当于一个蓝图,根据蓝图我们可以构建除一个又一个具有基本功能的房屋
    • 为了获得真正可以交互的对象,我们必须构建一个东西,被称为实例
  • 继承
    • 可以直接使用父类的方法
  • 多态
    • 子类可以重写父类的某一方法
    • 子类中可以引用父类或者祖先类中的方法(引用的其实是复制的结果 )
  • 多重继承
    • 实际在js中不存在多重继承的形式,但是人们使用了各种方法模拟它
    • 多重继承是指,一个类可以继承两个及以上的父类
      • 这样会导致一个问题
      • 钻石问题
        • 当B,C继承自A,而A的try方法分别被B,C重写(多态),那么D继承自B,C使用的是哪一个try方法呢

原型

  • [[property]]

    • 每一个js对象上都有一个[[property]]属性,上面是对其他对象的一个引用
    • 在查找对象的一个属性时,执行的是[[Get]]操作,本对象上没有,则会遍历[[property]]链来查找
    • [[property]]的尽头就是Object.property,所以Object.property上面有许多共用的方法,toString,valueOf等
  • 属性的设置和屏蔽

    • 在设置属性时,会发生这样的几种情况(使用的是=设置,而不是Object.defineProperty)
      • myObject上面含有此属性
        • 执行的是类似[[Put]]的操作,直接重写此属性的值
      • myObject上面不含有此属性,[[property]]原型链上含有此属性
        • 它的数据属性writable:true
          • 产生屏蔽属性,在myObject上创建此属性
        • 它的数据属性writable:false
          • 非严格模式下,不产生屏蔽属性
          • 严格模式下报错
        • 它的属性是一个setter
          • 会调用此setter,但不会在myObject上定义这个属性,也不会重写这个setter
      • myObject上,以及[[property]]上都含有此属性
        • 发生屏蔽,查找[[property]]最底层的属性
      • myObject上面不含有此属性,[[property]]原型链上也不含有此属性
        • 执行类似[[Get]]的操作遍历查找,没有直接在myObject上面创建此属性
  • 继承

    • 继承实际上是复制原型的引用,而不是直接赋值
    function People(name) {
        this.name = name;
    }
    People.prototype.sayHi = function (){
        return "my name is " + this.name;
    }
    function Young(age,name){
        People.call(this,name);
        this.age = age;
    }
    //这里我们显示的将Young的原型指向People的原型
    //此处不可以直接 Young.prototype =People.prototype;这样会导致修改Young的原型也会导致People的原型被修改啊
    //Young.prototype = People.prototype;
    //Young.prototype.sayHello = function (){
    //   console.log('两者都被修改了')
    //}
    //People的原型上面也增加了sayHello方法
    //Object.create是创建一个新的空对象,并将对象关联到传入的对象,将原始的关联对象抛弃
    Young.prototype = Object.create(People.prototype);
    var xiaoHong = new Young(16,'xiaohong');
    xiaoHong.sayHi();//my name is xiaohong
    
      • es6之前可以使用Object.create
      • es6之后可以使用Object.setPrototypeOf(Young.prototype,People.prototype)
    • 如何判断一个对象的原型是否关联了另一个对象的原型的,这个问法在类语言中叫做内省
      -a instanceof b
      - 缺点:只能判断一个对象和函数之前的关系。不能判断两个对象之前的关联
      - 语意:在a的原型链中是否存在b的原型
      • People.prototype.isPrototypeOf(xiaoHong) //b.isPrototypeOf(a)
        • 可以检查到继承的
      • 直接获取原型链
        function Foo(){
            
        }
        var a = new Foo();
        
        • Object.getPropotypeOf(a) === Foo.prototype;//true
        • Object.getPropotypeOf(xiaoHong) === People.prototype;//false
        • 缺点:检查不到继承的
  • 对象关联

    • 我们知道对象的[[prototype]]可以关联到其他对象上,这是模式类的实现,创建对象与对象之间的关联
    • Object.create
      • 这是一个很强大的方法
      • 原因:
        • 可以创建没有副作用的关联
          • new 会创建.prototype和constructor
        • 可以在es5之前的环境下模拟部分功能
        if(!Object.create){
           Object.create = function (o ) {
              function F () {
                  
              }
              F.prototype = 0;
              return new F();
           }
        }
        

《你不知道的JS》-中-语法

  • 语句和表达式

    • var a = 42;是一个声明语句
      • 语句都有一个结果值,在控制台会打印出来
      • var语句的结果值是undefined
        • 这就是为什么我们经常在控制台看到undeifned
      • 语句的结果值是最后一个语句或者表达式的值
        • 现在的语法规定我们不能将语句的结果赋值给另一个变量(语句当作表达式使用)
        • 如果我们想要获得这个结果值
          • 为什么要获得语句的结果值
            • 可以不用将语句封装为函数再返回值了
          • 如何让获得语句的结果值
            • ES7中增加了do
            var a,b;
            a = do{
                if (true) {
                    b = 3 + 3;
                }
            }
            
            • eval(不建议采用)
            var a,b;
            a = eval("if (true) {
                b = 3 + 3;
            }")
            
    • 语句的副作用
      • 大多数语句是没有副作用的
      var a = 42;
      
      • 个别会有
        • 函数
        var a = 1;
        function test () {
            a = a + 1;//副作用:a的值被改变了
        }
        test()
        
        • 一元运算符
        var a = 42;
        b = a++;
        a//43
        b//42 副作用a的值被改变,++先返回表达式的值,然后才+
        
          - 如何得到b =43
          ```
          var a = 42;
          b = (a++,a);
          ```
          - ++a++会报错,因为a++先返回42,然后执行++42,++不能用在42上面
        
        • = 赋值等号
        • delete运算符
      • 上下文规则
        • 大括号{}

          • 对象常量
          var a = {
              b:function () {
                  
              }
          }
          
          • 标签
            • 这是一个js很不常见的技巧
            • 用途:跳转循环
            foo:for(let i = 0; i < 4;i++){
                for(let j = 0; j < 4; j++){
                    //如果i和j相等,跳进外层循环
                    if(i == j) {
                        continue foo;
                    }
                    console.log(i,j)
                }
            }
            
        • 代码块

        [] + {}//[object Object]
        {} + []//0
        
        • 对象解构
        • else if和可选代码块
          • js中实际上没有else if ,else if实际是另一个if代码块
    • b = a;是一个赋值表达式
  • 运算符优先级

    • ,< = < ? : < || < &&
    • 短路
      • 意义是执行最短路径
      • && 和|| 如果左边可以得到结果的话就无需执行右边
  • 自动分号

    • js有自动分号插入机制,会为没有;结尾的代码自动补全
    • 前提是两个代码之间没有空格和注释之外的其他内容
  • 暂时性死区

    • TDZ:指代码中的变量还没有初始化而不能被引用
  • 函数参数

    • 函数参数也会引发TDZ
    function add (a = 42, b = a + b +1){
        console.log(a,b)
    }
    add();//b is not defined
    
    • 参数如果为undefined或者未传入则取默认参数
  • try...finally

    • try可以和catch
    • try也可以和finally一起使用
      • 规则
        • finally里面的代码一定会执行
        • finally如果抛出异常,则函数终止
        • finally中的return值会覆盖try和catch中的值
        function foo() {
            try{
                console.log('test')
                return 1
            }finally {
                return 42
            }
        }
        foo();
        
  • switch

Recommend Projects

  • React photo React

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

  • Vue.js photo Vue.js

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

  • Typescript photo Typescript

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

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

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

Recommend Topics

  • javascript

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

  • web

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

  • server

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

  • Machine learning

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

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

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

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.