漏洞安全分享栏目,目地基本建设维护保养我国 *** 信息安全权威性。
黑客挖地洞的关键思路
黑客思路,关键有二点。
-之一点
是黑客自身的思路
-第二点
是黑客进攻网站的思路
因此 不言而喻,今日说的便是黑客进攻网站情况下的思路了。
黑客思路拥有一定的科学论证。
那么就先拿念头做下事例。
例如
-我要吃
你能想起哪些,那麼肯定是吃,如果是吃得话,便会想起吃啥?那麼如果一系列的念头呢?
-我要吃。
-问:我为什么会饿?
-答:由于是我胃
-问:为何我能有胃?
-答:由于会胃消化吸收食材
-问:为何会胃消化吸收食材?
-答:由于我是微生物
-问:为何我能是微生物?
-答:不清楚
…
很奇特吧,很多人问了,为何我能拿这类神经大条难题来举个例子,当然,肯定是有我的大道理的。
黑客发掘漏洞也是根据这种的诸多不清楚的要素,挖出的漏洞。
接下去便说黑客的奇特思路
也是类似
我想发掘这一网站的漏洞 比如:原生态开发设计的商城系统
问:我想挖哪些?
答:漏洞
问:哦,我该挖哪些的漏洞?
答:自然是商城系统会存有的漏洞了
问:那麼这一商城系统会有哪些漏洞?
答:不知道啊,瞧瞧吧
问:你提前准备看哪儿?
答:先从主页看上去吧,看一下他的普遍漏洞
问:主页会有哪些漏洞?
答:主页会出现检索,产品信息这些,运用一些 *** 很有可能会获得到漏洞
问:假如没有呢?
答:那么就再次挖
问:那该挖哪儿?
答:购买商品
问:这儿会出現哪些漏洞?
答:数据泄露,付款漏洞,滥用权力这些的逻辑性漏洞
问:假如这儿也没有呢?
答:留言板留言系统软件或是取货时的评价系统软件,从这儿能够 试着指令实行,xss,csrf,上传文件,引入等实际操作
问:这儿也没有呢?
答:聊天室
问:那这儿也没有呢?
答:私人信息网页页面
问:如果这儿没有呢?
答:把前台接待能试的都试一下
问:假如前台接待没有呢?
答:那麼试着商户后台
问:假如商户后台也没有呢?
答:看一下文件目录泄漏吧,试着找寻一些比较敏感信息内容及其文件目录。
问:还没有呢?
答:C段…端口号…这些的一系列实际操作
……
问:都没有呢?
答:孔子不挖了。
……
这就是黑客发掘网站漏洞情况下的思路,自说自话,去渐渐地建立后边的事儿。有时灵光一现奇特的念头很有可能便会试着取得成功
这仅仅在其中一种思路,不一样种类网站每一个黑客都是会拥有归属于自身的不一样思路,之上仅仅我本人的思路。
今日的文章内容便说到这儿了,如果有喜爱的,能够 关注我或是共享文章内容。
ID: *** 安全大湿兄
--没经容许转截,创作者有权利开展诉讼。
参照owasp top10
参照黑云知识库系统
跳出来基本的都能够称作hack
排行第十的是Sam Curry和他的小伙伴们,大家有一个让人心痛的安全性漏洞 记忆力 。 这一重要但非常容易被忽略的漏洞基本上毫无疑问会危害到别的网站,并提示大家,即便你是一个权威专家,依然有一个地方能够 只是开展模糊不清检测并注意一切出现意外状况。
在本文中,Abdulrhman Alqabandi应用web和二进制进攻的结合体,对一切应用微软公司新的Chromium-Powered Edge(别名Edgium)浏览其网站的人开展进攻。
已经出示40,000美金的悬赏金,如今已开展了修复,但这依然是漏洞运用链的一个非常好的事例,该漏洞运用链融合了好几个低比较严重度漏洞以完成重要危害,还非常好地展现了互联网漏洞怎样根据权利来源于渗入您的桌面。 它启迪了大家大量的可攻击能力,以根据扫描仪chrome目标来检验它什么时候坐落于权利来源于上。
要进一步掌握电脑浏览器竞技场中的互联网漏洞错乱状况,请查询Firefox中的远程控制程序运行(运行内存毁坏以外)。
新任获奖者Orange Tsai与Meh Chang一起初次出面,并揭秘了在SSL VPN中出現了好几个没经身份认证的RCE 漏洞。
VPN在互联网技术上具有的权利影响力代表着,就纯碎的知名度来讲,它是更好是的挑选。 虽然所应用的技术性在非常大水平上是經典技术性,但他们应用了一些创造力的 *** 。 此项研究有利于引起对于SSL VPN的审批的浪潮,进而得到了很多发觉,包含上星期公布的一系列SonicWall漏洞。
当代网站是由诸多借助互相鉴别的服务项目拼接而成的, 当这种漏洞泄露时,信赖之网便会分裂。 持续集成储存库/系统日志中泄漏的商业秘密很普遍,而根据自动化技术搜索他们的概率乃至高些。
殊不知,EdOverflow等的此项研究系统化为被忽略的实例和潜在性的将来研究行业出示了新的思路。 这也很可能是繁华的网站/专用工具SSHGit的设计灵感来源于。
关心新奇的研究就是我工作中的关键一部分,可是当本文初次公布时,我依然彻底错过本文。 幸运的是,小区中的别人有着更机敏的双眼并得到候选人。
PaweHadrzyński 承继了.NET架构的不为人知的旧作用,并展现了怎么使用它来向随意节点上的URL途径加上随意內容,在我们意识到乃至我们自己的网站都适用它时,大家觉得一些焦虑。
这令人想到到“相对路径遮盖”进攻,这是一个很有可能会开启漏洞攻击链的秘密。 在该贴子中,它已用以XSS,但大家明显猜疑未来还会继续出現别的乱用状况。
Google输入框可能是地球上历经最严苛检测的键入,因而Masato Kinugawa是怎样保证XSS的,它是没法了解的,直至他根据与朋友LiveOverflow的协作表明了漏洞信息内容。
这两个视頻出示了一个有关怎样根据阅读文章文本文档和模糊来发觉DOM解析错误的靠谱详细介绍,另外也少见地展现了这一杰出漏洞运用身后的想像力。
Orange Tsai在几篇文章内容中开展了详细介绍了Jenkins具备预验证的RCE。 在绕开身份认证是好的,但大家更爱的不断创新应用元编程来建立一个侧门,在编译程序时实行,在诸多自然环境的管束。 大家期待未来会再度见到元编程。
这也是研究不断发展趋势的一个非常好的事例,由于之后该漏洞运用被好几个研究工作人员所改善。
该演说由本Sadeghipour和Cody Brocious简述了目前的SSRF技术性,展现了如何把他们运用到服务端的PDF *** 器,随后将DNS再次关联引进到组成中以得到优良的实际效果。
对于PDF *** 器的工作中是对作用类的刻骨铭心看法,而这种作用类太非常容易被忽略了。 大家之一次见到服务端电脑浏览器上的DNS再次关联出現在2018候选人目录中,而且HTTPRebind的公布应有利于使此进攻比过去更便于进攻。
最终,我对于此事可能是错的,可是我怀疑这一幻灯片很有可能非常值得称赞,因为它最后说动了amazon考虑到维护其EC两元数据信息结束点。
跨站泄露早已不断了很长期,最开始在十年前就被记下来,并在上年位居大家的前十名,直至今年,大家才刚开始意识到这类进攻类型以及巨大的瘋狂变异。
这般经营规模的个人信用难以平摊,但大家显而易见要谢谢Eduardo Vela用一种新技术应用简约地详细介绍了这一定义,共同奋斗创建已经知道的XS-Leak空间向量的公布明细,及其研究工作人员将XS-Leak关键技术的实际效果非常好。
XS-Leaks早已对Web安全行业造成了长久危害,由于他们在电脑浏览器XSS过滤装置的消退中充分发挥了关键功效。 块方式XSS过虑是XS-Leak空间向量的关键来源于,这与更槽糕的过虑方式难题紧密结合,以说动Edge和之后的Chrome舍弃过滤装置,它是web安全性的获胜,也是web安全性研究工作人员的灾祸一样。
在这篇学术研究市场研究报告中,Sajjad Arshad等选用了Omer Gil的Web缓存文件蒙骗技术性(该技术性在17年大家的前10名中排行第二),并在Alexa Top 5000网站上共享资源了对Web缓存文件蒙骗漏洞的系统软件研究。
出自于法律法规缘故,大部分攻击能力安全性研究是在技术专业审批期内或在有漏洞悬赏金方案的网站上开展的,可是根据用心的社会道德品行,此项研究能够 使您更普遍地掌握互联网上的安全性情况。 依靠用心设计的 *** (能够 轻轻松松地适用别的技术性),她们证实了Web缓存文件蒙骗依然是普遍现象的威协。
除开科学 *** 论外,另一个重要不断创新引进了五种新奇的途径搞混技术性,这种技术性扩张了易受攻击的网站的总数。 与很多出示程序流程自身对比,他们在纪录Web缓存文件出示程序流程的缓存文件个人行为层面也做得更强。 从总体上,它是小区将目前研究向着新的方位发展趋势的很好事例,也是实至名归的之一!
年复一年,大家见到杰出的研究来源于别人的念头,因而,我们要谢谢全部花时间发布她们的发觉的人,不管是不是候选人。
用好 VS Code 软件,不但能节约你的時间,还能提升工作效能。VS Code 有一个销售市场,它出示许多 软件。开发者能够 把软件安裝到文本编辑,提高在线编辑器作用。在主视图莱单中,挑选拓展选择项或按住 shift cmd X 就可以进到销售市场。
灵活运用 VS Code 软件,不但省时省力,还能提升工作效能,给你变成更强的开发者。
1 Live Server
该软件容许我们在变更 IDE 中的编码时,全自动重新加载 Web 网页页面。
一旦安裝 Live Server 后,在 html 文档上右键单击,可见到选择项 Open with Live Server[Alt L Q]。
下载链接:
2 Quokka.js
Quokka.js 会在你键入时全自动数值,并在 IDE 中复印結果。
下载链接:
3 Code Spell Checker
它是一款拼写检查程序流程,能够 为开发人员汇报一些普遍的语法错误。它很合适骆驼峰式编码。
下载链接:
4 GitLens
GitLens 可提高 Visual Studio Code 中内嵌的 Git 作用。
它不但能协助你根据 Git blame 注释形象化地见到编码创作者,并且还能够无缝拼接访问 和探寻 Git 储存库,根据强劲的较为指令得到有使用价值的看法这些。
下载链接:
5 Prettier
Prettier 是一个严苛根据标准的代码格式化程序流程。
它分析编码并应用自身的标准再次复印编码,进而完成设计风格一致。这是一个关键的专用工具,不用开发者做一切工作中 ,它就能让我们获得格式正确的代码。
Prettier 提供合理的默认值,但你也能在项目的根目录下提供一个配置文件来设置自己的标准,比如行长度、制表符 / 空格的数量等等。
下载地址:
6 ESLint
ESLint 是一款静态代码分析工具,用来识别 JavaScript 代码中出现的有问题的模式。
ESLint 中的规则是可配置的,用户可以定义和加载自己的规则。它还涵盖了代码质量和编码风格问题。
下载地址:
7 vscode-icons
该插件会基于文件扩展名在 the tree view 中的文件名旁添加图标,让你更容易地识别文件。
下载地址:
8 Live Saas Compiler
它能帮你实时把 SASS/Scss 文件编译 / 转译成 css 文件,并且提供在线浏览器重载。
下载地址:
9 JavaScript (ES6) code snippets
这个插件包含面向 VS Code 编辑器的 ES6 语法的 JavaScript 代码片段(支持 JavaScript 和 TypeScript)。
下载地址:
10 Browser Preview
它可以让你在编辑器中打开一个用于调试的真正的浏览器预览。
下载地址:
11 Path Intellisense
该扩展可以自动补全代码中的路径和文件名。
下载地址:
12 Bracket Pair Colorizer
这个扩展允许用颜色来标识匹配的括号。用户可以定义要匹配的字符和要使用的颜色。
下载地址:
13 Vim
VSCodeVim 是一个用于 Visual Studio Code 的 Vim 仿真器,为你的文本编辑器带来 Vim 的强大功能。
下载地址:
14 TODO Highlight
高亮显示代码中的 TODO、FIXME 及其他注解。
下载地址:
15 Color Highlight
这个扩展可以风格化在你的文件中找到的 css/web 颜色,所以你无需打开页面就能看到它们是什么颜色。
下载地址:
相关阅读:
链接:
在今天,Python里有很多开发框架用来帮助你轻松创建web应用。web开发框架存在的意义就在于可以快速便捷的构建应用,而不用去在意那些没必要的技术细节(协议、报文、数据结构)。
到2020年为止,基于Python创建的的web应用已经非常多了,国外知名的有 *** .com、instagram、reditt、国内有知乎、豆瓣等等。这些网站分别用到了不同的web框架来实现的,我们今天会一一讲到。
1. Django
Django应该是Python最知名、最有代表性的Web框架了。它的名字来自于Django Reinhardt,一位法国作曲家和吉他演奏家。在2000年初有一个报社的两位程序员为了给报社的报纸开发线上应用,开始用 Python编写网站,最后把他们的工作总结出一套开源框架,就是今天的Django了。
Django遵循了MVC开发模式,并将这个模式命名为MTV(MTV模式是Python中独有的)
M Model(数据模型,用于后端数据库模型定义和处理模块)
T Templates(模版,用于前端显示信息)
V View(视图,用于接收客户端请求、处理Model、渲染返回信息给客户端等)
(1) Django的优点和缺点
优点:
一站式开发解决方案,拧包入住
各种组件集成高度成熟,配置齐全
用户模型、权限认证体系健全
ORM数据库管理功能简单方便
自带后台管理功能
缺点:
配置相对复杂
简单应用采用Django有一种杀鸡用牛刀的感觉
(2) Django安装和初始化
Django下载方式有两种:
通过pip直接安装
通过源码下载并安装
安装之后通过startproject参数创建一个新的django项目 test_django/
cd test_django进入项目路径输入启动服务命令即可启动一个最简单的django服务。
最后访问下默认路径 看看django项目启动的效果。
启动成功,现在可以编写你的Django代码了。
2. Flask
如果说Django是大而全的方案代表,那么Flask就是小而精的方案代表。
Flask是基于Werkzeug工具箱编写的轻量级web开发框架,它主要面向需求简单,项目周期短的Web小应用。
Flask这个框架相对比较灵活,核心思想是Flask只完成基本的功能,别的功能都是靠各种第三方插件来完成的,实现了模块高度化定制。
(1) 常用的Flask插件如下:
Flask-SQLalchemy:操作数据库;
Flask-migrate:管理迁移数据库;
Flask-Mail:邮件;
Flask-WTF:表单;
Flask-script:插入脚本;
Flask-Login:认证用户状态;
Flask-RESTful:开发REST API的工具;
Flask-Bootstrap:集成前端Twitter Bootstrap框架;
Flask-Moment:本地化日期和时间;
Flask的两个主要核心应用是Werkzeug和模板引擎Jinja,除此以外,别的都是可以自由组装的,适合有洁癖的程序员。
(2) Flask优缺点
优点:
项目结构和配置简单
组件可以自由拆装
小项目或临时性项目比较适用
缺点:
组件高度自定义带来的就是各种组件之间的兼容性问题严重大型应用不适合,例如蓝图(blueprint)机制跟Django的url配置比起来其实差得很远
(2) Flask安装
我们通过pip直接安装
在任意位置新建一个py文件,hello.py 。
输入启动命令:
最后访问默认地址 打开flask默认启动页面。
3. Tornado
严格意义上来说Tornado不是一个Web框架,而是一个基于Python实现的异步处理框架,只是自带了WSGI处理相关的功能。
tornado和Flask一样,除了基本的Web处理功能和模版之外,其他功能组件都需要自行拼装。
(1) tornado的优缺点
优点:
短小精悍,性能比较好,不依赖Python多进程/多线程
支持异步非阻塞IO处理方式
支持websocket
缺点:
过于精简,只适用于纯接口化服务或者小型网站应用
(2) Tornado安装
同样使用pip进行安装。
新建一个hello.py 代码文件。
最后执行 python hello.py启动tornado服务,通过访问初始化页面
以上三种是Python开发中经常使用到的Web框架,还有一些不是那么常用的也一并给大家简单介绍一下。
4. TurboGears
据说豆瓣早期就是基于该框架进行开发的。
TurboGears是在几个著名的Python项目上组装搭建起来的一个框架,由SQLAlchemy,WebOb,Repoze,Genshi组成。
在某种意义上,TurboGears是将多个开源组件粘合在一起。和Django同样采用MVC架构。
TurboGears的优点:
支持聚合
强大的对象关系映射器
事务系统支持多数据库间事务
多数据库支持
以可重用的代码片段为模板
具有很多的灵活性,可以对接非标准组件
支持分片
模板系统使设计师的设计更轻松
5. Bottle
Bottle和Flask一样,也是一个轻量级的Web开发框架。
它不依赖于Python标准库外的任何库。于2009年被创造出来,它仅由包含模板、路由和一个WSGI抽象层的最小工具开始。对于程序员想寻找一个最轻量级的WSGI服务是一个很好的选择,用它可以最快速度的创建一个Web服务。
Bootle优点:
超轻量级
内建模板引擎和对Jinja2,Mako和Cheetah的支持
总结
今天给大家介绍了各种Python的Web开发框架,我个人常用的框架主要包括Django、Flask、Tornado。别的框架涉猎较少,也是因为流行度和易用性的关系。
针对于最常用的三种框架,我给大家一个使用建议:
正式项目、大型项目,确定需要长期开发和维护的项目建议选择Django,一劳永逸,不用考虑太多。
小型项目、临时性的项目,不怕折腾的,可以选择Flask。
小型项目、临时性项目或者一些简单的接口服务,可以选择Tornado,因为Tornado天生支持异步,所以很多需要做异步IO服务的也可以选择Tornado,另外Django3.0之后也开始全面支持异步了,建议大家观望。
原文
链接:
在一般的代码中很少会接触到进制和位运算,但这不代表我们可以不去学习它。作为一位编程人员,这些都是基础知识。如果你没有学过这方面的知识,也不要慌,接下来的知识并不会很难。本文你将会学习到:
进制转换按位操作符JavaScript进制转换手动实现进制转换
以下使用常见的十进制和二进制转换作为例子,其他进制的转换也是大同小异,感兴趣可以自己琢磨下。
根据 “逢十进一” 的法则进行计数时,每十个相同的单位组成一个和它相邻的较高的单位,这种计数法叫做十进制计数法,简称十进制。这种是我们最常用的计数法。
整数使用 “除二取余,逆序排列” 来转换为二进制,下面是18转换为二进制的例子:
就这么简单,将得出的余数逆序排列,即可得出18的二进制表示
小数使用的是 “乘二取整,顺序排列”,由于 *** 不同需要分开计算。下面是16.125转为二进制的例子:
将小数相乘的结果,取结果的整数顺序排列,得出小数位的二进制表示
根据 “逢二进一 ” 的法则进行计数时,每两个相同的单位组成一个和它相邻的较高的单位,这种计数法叫做二进制计数 法,简称二进制。用二进制计数时,只需用两个独立的符号“0”和“1” 来表示。
整数使用 “按权相加” 法,即二进制数首先写成加权系数展开式,然后按十进制加法规则求和。下面是101010转换位十进制的例子:
上面从右数依次是2的0次方,2的1次方,2的2次方... , 只取位数为1的结果,将它们相加就可以得到十进制。
10110.11转十进制:
按位操作符(Bitwise operators) 将其操作数(operands)当作32位的比特序列(由0和1组成),前 31 位表示整数的数值,第 32 位表示整数的符号,0 表示正数,1 表示负数。例如,十进制数18,用二进制表示则为10010。按位操作符操作数字的二进制形式,但是返回值依然是标准的JavaScript数值。
对于每一个比特位,只有两个操作数相应的比特位都是1时,结果才为1,否则为0。
用法: a & b 。
在判断一个数字奇偶时,可以使用 a & 1
因为奇数的二进制最后一位是1,而1的二进制最后一位也是1,通过 & 操作符得出结果为1
对于每一个比特位,当两个操作数相应的比特位至少有一个1时,结果为1,否则为0。
用法: a | b
将浮点数向下取整转为整数,可以使用 a | 0
对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。
用法: a ^ b
反转操作数的比特位,即0变成1,1变成0。
用法: ~ a
通过两次反转操作,可将浮点数向下取整转为整数
将 a 的二进制形式向左移 b (
用法: a > b
相比之下, -9 >> 2 得到 -3,因为符号被保留了。
与左移相反,右移一位在原数字基础上除以2
将 a 的二进制表示向右移 b (
用法: a >>> b
在非负数来说, 9 >>>2 和 9 >> 2 都是一样的结果
而对于负数来说,结果就大有不同了,因为 >>> 不保留符号,当负数无符号右移时,会使用0填充
可以使用无符号右移来判断一个数的正负
虽然 -1 >>> 0 不会发生右移,但 -1 的二进制码已经变成了正数的二进制码, -1 >>> 0 结果为4294967295
toString 常用于将一个变量转为字符串,或是判断一个变量的类型,例如:
你应该没想过 toString 可以用于进制转换,请看下面例子:
参数规定表示数字的基数,是 2 ~ 36 之间的整数,若省略该参数,则使用基数 10。该参数可以理解为转换后的进制表示。
parseInt 常用于数字取整,它同样可以传入参数用于进制转换,请看下面例子:
第二个参数表示要解析的数字的基数,该值介于 2 ~ 36 之间。如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果该参数小于 2 或者大于 36,则 parseInt 将返回 NaN。
记得有道面试题是这样的:
接下来,我们来一步一步的看下过程发生了什么?
虽然 JavaScript 为我们内置了进制转换的函数,但手动实现进制转换有利于我们理解过程,提高逻辑能力。对于初学者来说也是一个很不错的练习例子。以下只简单实现非负整数的转换。
基于 “除二取余” 思路实现
使用
基于 “按权相加” 思路实现
使用
如果把js内容直接放在这个head标签以内,button按钮不能正常点击更换body的背景颜色,报错提示:demo6.html:16 Uncaught TypeError: Cannot set property 'onclick' of null,分析解决办法如下:
问题归纳总结:
之一种解决办法直接js文件放在页面底部加载,第二种window onload()包裹起来,出现问题原因:W3School中介绍浏览器先加载完按钮节点才执行 *** ,当浏览器自顶向下解析时,找不到onclick绑定的按钮节点了,网页中的JavaScript脚本代码往往需要在文档加载完成后才能够去执行,否则可能导致无法获取对象的情况,window.onload是一个事件,window.onload表示页面加载完成后执行的函数,js按照页面自上而下的顺序说明的,页面上的Javascript代码是HTML文档的一部分,所以Javascript在页面装载时执行的顺序就是其引入标记!
链接:
函数被调用之后,会创建一个执行环境及作用域链.函数被执行完之后就会被释放掉.
闭包函数执行之后会保留当前活动变量在内部函数作用域链中,所以内部函数可以访问外部变量.
打印出的结果是多少
打印出的结果是什么
var声明的变量只有函数作用域与全局作用域,这循环中创建的i变量,会变量提升在函数顶部,所以函数打印i变量的值是10
打印出的结果是什么
let 声明的变量具有块级作用域,每轮循环i变量,其时都是一个新的i变量,所以myArr数组中存储了不同的数字
打印结果是多少
这只是创建并执行了10个函数,每个函数都传递了个i变量给参数给j,j存储了变量值,然后做为打印输出了,所以结果为0~9
个人博客地址 :
链接:
由于图片是web上更流行的内容类型之一,因此网站的页面加载时间很容易成为一个问题。
即使经过适当的优化,图像也会有相当大的重量。这可能会对访问者在访问网站内容之前等待的时间产生负面影响。很有可能,它们会失去耐心,转向其他地方,除非你能想出一个不影响速度感知的图像加载解决方案。
在本文中,您将学习有关延迟加载图像的五种 *** ,您可以将这些 *** 添加到web优化工具包中,以改进站点上的用户体验。
什么是延迟加载
延迟加载图像意味着在网站上异步加载图像——也就是说,在网站上面的折叠内容完全加载之后,甚至仅当它们出现在浏览器的视区中时,才有条件地加载它们。这意味着,如果用户不一直向下滚动,那么放在页面底部的图像甚至不会被加载。
许多网站都使用这种 *** ,但在图片密集的网站上尤其明显。尝试浏览你最喜欢的在线搜索网站,寻找高分辨率的照片,你很快就会意识到网站只加载有限数量的图片。当您向下滚动页面时,您将看到占位符图像快速填充真实图像以供预览。例如,请注意unsplash.com上的加载程序:将页面的该部分滚动到视图中会触发使用全分辨率照片替换占位符:
为什么要关心延迟加载图像?
至少有两个很好的理由可以让你考虑延迟的为你的网站加载图像:
● 如果您的网站使用JavaScript来显示内容或向用户提供某种功能,那么加载DOM很快就变得至关重要。脚本在开始运行之前,通常要等到DOM完全加载之后才开始运行。在有大量图像的站点上,延迟加载-或异步加载图像-可能会在用户停留或离开您的站点之间产生差异。
● 由于大多数延迟加载解决方案只在用户滚动到在视区中可以看到图像的位置时加载图像,因此如果用户从未到达该点,则永远不会加载这些图像。这意味着节省了大量的带宽,大多数用户,尤其是那些在移动设备和慢速连接 *** 问 *** 的用户,都会感谢您。
嗯,延迟加载图像有助于网站性能,但更好的 *** 是什么?
没有完美的方式。
如果您使用JavaScript,那么实现您自己的延迟加载解决方案应该不成问题。没有什么比自己编写代码更能让你控制了。
或者,您可以浏览web,寻找可行的 *** ,并开始使用它们。我就是这么做的,然后遇到了这五个有趣的技巧。
#1使用Intersection Observer API进行延迟加载
Intersection Observer API是一个现代化的界面,你可以利用它来延迟加载图像和其他内容。
下面介绍MDN如何引入此API:
Intersection Observer API提供了一种异步观察目标元素与祖先元素或顶级文档视 *** 叉的 *** 。
换句话说,异步观察的是一个元素与另一个元素的交集。
Denys Mishunov在交叉观察者和使用它的延迟加载图像上都有很棒的教程。这是他的解决方案的样子。
假设您想懒得加载图片库。每个图像的标记如下所示:
注意图像的路径如何包含在data-src属性内,而不是src属性中。原因是使用src意味着图像会立即加载,这不是你想要的。
在css中,您可以为每个图像赋予一个min-height值100px。这为每个图像占位符(没有src属性的img元素)提供了垂直维度。
在JavaScript文档中,然后创建一个配置对象,并将其注册到一个intersectionObserver实例中:
最后,迭代所有图像并将它们添加到此iterationObserver实例:
这个解决方案的优点是:实现起来很容易,很有效,并且让intersectionObserver在计算方面做大量的工作。
另一方面,虽然大多数浏览器的最新版本都支持交集观察器API,但并不是所有浏览器都一致支持它。幸运的是,有一个polyfill可用。
#2 Robin O *** orne逐步增强的延迟加载
罗宾·奥斯本提出了一个基于渐进增强的超级巧妙的解决方案。在这种情况下,使用JavaScript实现的延迟加载本身被认为是对常规html和css的增强。
渐进增强的原因吗那么,如果使用基于JavaScript的解决方案显示图像,如果禁用JavaScript或发生错误阻止脚本正常工作,会发生什么情况呢在这种情况下,如果没有渐进的增强,用户很可能根本看不到图像。不酷。
您可以在此Pen中查看O *** orne解决方案的基本版本的详细信息;在另一个Pen中,你可以看到一个更全面的解决方案,其中考虑了破坏JavaScript的情况。
这种技术有许多优点:
● 渐进增强 *** 可确保用户始终可以访问内容。
● 它不仅适用于JavaScript不可用的情况,而且还适用于JavaScript 崩溃的情况:我们都知道容易出错的脚本,特别是在运行大量脚本的环境中。
● 它延迟加载滚动图像,因此如果用户不滚动到浏览器中的位置,则不会加载所有图像。
● 它不依赖于任何外部依赖,因此不需要框架或插件。
#3 Lozad.js
实现延迟加载图像的一种快速简便的替代 *** 是让js库为您完成大部分工作。
Lozad是纯JavaScript中高性能,轻量级和可配置的延迟加载器,没有依赖关系。您可以使用它来延迟加载图像,视频,iframe等,并使用Intersection Observer API。
您可以使用npm / Yarn包含Lozad并使用您选择的模块捆绑器导入它:
或者,您可以使用CDN简单地加载库,并将其添加到标签中html页面的底部:
接下来,对于基本实现,将类lozad添加到标记中的资源:
最后,在 *** 文档中实例化Lozad:
您将找到如何使用lozad github存储库上的库的所有详细信息。
如果您不想深入了解Intersection Observer API的工作方式,或者您只是在寻找适用于各种内容类型的快速实现,那么Lozad是一个很好的选择。
只有,请注意浏览器支持,并最终将此库与Intersection Observer API的polyfill集成。
#4延迟加载,模糊图像效果
如果你是一个中等水平的读者,你肯定已经注意到网站是如何在帖子中加载主图片的。
您首先看到的是图像的模糊、低分辨率副本,而它的高分辨率版本正被延迟加载,媒体网站上的高分辨率,延迟加载图像。
您可以通过多种方式使用这种有趣的模糊效果来延迟加载图像。
我最喜欢的技术是Craig Buckler。以下是此解决方案的所有优点:
● 性能:只有463个字节的CSS和1,007个字节的缩小JavaScript代码
● 支持视网膜屏幕
● 无依赖性:不需要jQuery或其他库和框架
● 逐步增强以抵消旧版浏览器和JavaScript失败
#5 Yall.js
Yall是一个功能丰富的延迟加载脚本,适用于图像,视频和iframe。更具体地说,它使用了Intersection Observer API,并在必要时巧妙地依靠传统的事件处理程序技术。
在文档中包含Yall时,需要按如下方式对其进行初始化:
接下来,要延迟加载一个简单img元素,您需要在标记中执行的操作是:
请注意以下事项:
● 您添加类慵懒的元素
● 值src是占位符图像
● 要延迟加载的图像的路径位于data-src属性内。
Yall的好处包括:
● Intersection Observer API具有出色的性能
● 神奇的浏览器支持(它可以追溯到IE11)
● 没有必要的其他依赖。
链接:
css中的var()函数可用于插入自定义属性(有时称为“css变量”)的值,而不是插入其他属性值的任何部分。随着sass,less预编译的流行,css也随即推出了变量定义var函数。var()函数,就如同sass和less等预编译软件一样,可以定义变量并且进行对应的使用。
语法:
参数:
●custom_property:这是必需的参数。自定义属性的名称必须以两个破折号( - )开头。
●value:可选参数。自定义属性的回退值,用于自定义属性在使用的上下文中无效的情况。如果自定义属性无效,则使用它。
示例:
链接:
想要使用使用JavaScript替换数组中的项,要如何实现?
*** 1:使用splice() ***
avaScript中的数组类型为我们提供了splice() *** ,该 *** 通过在所需索引处删除和插入新元素来帮助我们替换现有数组的项。
语法:
注意:Splice() *** 从包含start_index元素开始删除数组中的零个或多个元素,并将这些元素替换为参数列表中指定的零个或多个元素。
Splice() *** 直接修改数组,与类似命名的Slice() *** 不同。
示例:
输出:
*** 2:使用数组的map()和filter() ***
JavaScript中的map() *** 通过调用父数组中每个元素上的特定函数来创建数组。 arr.filter() *** 用于从给定数组中创建一个新数组,该数组仅由满足参数函数设置的条件的给定数组中的元素组成。
语法:
示例:
输出:
链接:
Number()和parseInt()都可以用来进行数字的转换,那么parseInt()和Number()之间的区别是什么?
parseInt()函数:
parseInt()函数用于解析字符串并将其转换为指定基数的整数。它需要两个参数,要解析的字符串和要使用的基数。基数是一个介于2和36之间的整数,表示数字的基数。
如果parseInt()在解析过程中遇到不符合指定基数的字符,它将忽略该字符和所有后续字符。然后它将解析到该点的值作为一个整数返回。在这种情况下,允许使用前导或尾随的空格。
如果parseInt()函数得到参数如果以数字开头,就会返回开头的合法数字部分;如果以非数字开头,则它将返回NaN。此NaN值不是任何基数的有效数字,不能用于任何数学计算。
语法:
Number()函数:
Number()函数用于创建基本类型Number对象。它接受一个参数,即数字的值。此值可以使用字符串传递,Number函数将尝试将其表示为数字。如果参数无法转换为数字,则返回NaN值。此NaN值不是有效数字,不能用于任何数学计算。
语法:
parseInt()和Number()之间的区别
下面通过实例来看看parseInt()和Number()之间的区别。
示例1:
这个例子显示parseInt()试图将值转换为可以转换为整数的最后一个字符。后面的空白和字符将被忽略,因为它们是无效的。另一方面,Number()函数只返回NaN。
示例2:
parseInt()仅返回整数值的区别,而Number()返回包括浮点的所有数字。
区别:
1、当转换的内容包含非数字的时候,Number() 会返回NaN(Not a Number);parseInt() 要看情况,如果以数字开头,就会返回开头的合法数字部分,如果以非数字开头,则返回NaN。
2、parseInt()仅返回整数值的区别,而Number()返回包括浮点的所有数字。
链接:
html文件乱码一般是因为编码格式不匹配造成的,只要匹配好html文件的编码格式就可。
下面是一个中文乱码的html:
效果图:
HTML中的编码方式有三个:gb2312,gbk,utf-8;现在大部分浏览器默认编码的是utf-8。我们只需要把HTML编码方式设置为utf-8,就可以解决html中文乱码的问题。
解决 *** :
在head节点加入标签,把字符声明为UTF-8
或者简写:
解析:
● http-equiv="Content-Type"表示描述文档类型
● content="text/HTML;文档类型,这里为html,如果js就是text/JavaScript,
● charset=utf-8 页面字符集,编码,eg:gb2312,iso-8859-1,utf-8
示例:
链接:
在前端开发中,我们要经常用到js中的数组的内置 *** ,在控制台中的打印中,我们可以看到数组中的内置 *** 。Array.concat()该 *** 可以合并一个或者多个数组,Array.copyWithin() 该 *** 复制数组内的某些值到到另一个索引位置
标签表示任务的进度(进程),例:可定义完成多少工作,还有多少工作可以下载等等。该标签可与JavaScript结合使用,来显示任务的进度,创建动态的进度条。
注释: 标签不适合用来表示度量衡(例如,磁盘空间使用情况或查询结果)。如需表示度量衡,请使用 标签代替。
语法:
属性: 标签由两个属性组成
● max:表示完成任务所需的总工作量。
● value:表示已完成的工作量。
示例1:
示例2:
与JavaScript结合使用,创建简单动态进度条
效果图:
浏览器支持:
Internet Explorer 10, Firefox, Opera, Chrome 以及 Safari 6 支持 标签。
注释:Internet Explorer 9 以及更早的版本不支持 标签。
链接:
在JavaScript中值undefined和null都表示”无”,那么它们之间有什么区别?
undefined:
在 JavaScript 中, undefined 是一个没有设置值的变量。
typeof 一个没有值的变量会返回 undefined。
null:
在 JavaScript 中 null 表示 "什么都没有"。
null是一个只有一个值的特殊类型。表示一个空对象引用。
undefined和null的区别:
● undefined表示一个变量没有被声明,或者被声明了但没有被赋值(未初始化),一个没有传入实参的形参变量的值为undefined,如果一个函数什么都不返回,则该函数默认返回undefined。null则表示“什么都没有”,即“空值”。
● Javascript将未赋值的变量默认值设为undefined;Javascript从来不会将变量设为null。它是用来让程序员表明某个用var声明的变量时没有值的;
● undefined不是一个有效的jsON,而null是;
● null 和 undefined 的值相等,但类型不等:undefined的类型(typeof)是undefined;null的类型(typeof)是object。
● null和undefined之间的主要区别在于它们被转换为原始类型的方式。
在'null'上执行算术转换时,则值为0,可以使用以下代码片段验证此转换。
执行时,此代码的将输出
但是,“undefined”不执行任何此类转换。如果您尝试将“undefined”添加到数字中,您将获得NaN或Not-a-Number。以下代码片段说明了“undefine”的这一方面。
执行时,代码将输出:
链接:
最近遇到一个需求,需要限制文本框输入数字,而number类型的输入框有箭头,个人不是很喜欢,因此想要寻求其它途径实现。本想通过网上找个现成的插件,然而百度,谷歌一番都没有找到满意的答案,至于随手一搜出来的方案或多或少都有点缺陷。因此自己动手,丰衣足食。
想要获取当前URL的协议,可以使用JavaScript的location.protocol属性。
什么是协议?
*** 协议定义了 *** 设备之间通信的规则和约定。通过采用这些规则,两个设备可以相互通信并且可以交换信息。
常见的协议:
● ftp:文件传输协议(FTP)是一种标准 *** 协议,用于在计算机 *** 上的客户端和服务器之间传输计算机文件。
● http:超文本传输协议(HTTP)是分布式系统的应用协议。
● https:安全超文本传输协议(HTTPS)是超文本传输协议(HTTP)的扩展,用于安全通信并广泛用于Internet。
● file:用于文件或本地服务器系统。
● mailto:用于邮件系统。
如何获取URL的协议?
location的protocol属性是一个可读可写的字符串,可设置或返回当前 URL 的协议。
语法:
返回值:返回当前URL的协议,包括冒号(:)。
示例:
链接:
依赖注入是Angular的重要特性之一,依赖注入简化了Angular解析模块/组件之间依赖的过程。依赖注入(Dependency Injection,简称DI)是一种软件设计模式,在这种模式下, 一个或更多的依赖(或服务)被注入(或者通过引用传递)到一个独立的对象(或客户端)中,然后成为了该客户端状态的一部分。
该模式分离了客户端依赖本身行为的创建,这使得程序设计变得松耦合,并遵循了依赖反转和单一职责原则。与服务定位器模式形 成直接对比的是,它允许客户端了解客户端如何使用该系统找到依赖 .
angular的依赖注入
angular 有自己的 DI 框架,所以在实现依赖注入的过程被隐藏了,我们只需要很简单的步骤就可以使用其强大的依赖注入功能。
angular的依赖注入可以分为三个步骤:
● 得到依赖项
● 查找依赖项所对应的对象
● 执行时注入
Angularjs 提供很好的依赖注入机制。以下5个核心组件用来作为依赖注入:
● value
● factory
● service
● provider
● constant
value
Value 是一个简单的 JavaScript 对象,用于向控制器传递值(配置阶段):
factory
factory 是一个函数用于返回值。在 service 和 controller 需要时创建。
通常我们使用 factory 函数来计算或返回值。
provider
Angularjs 中通过 provider 创建一个 service、factory等(配置阶段)。
Provider 中提供了一个 factory *** get(),它用于返回 value/service/factory。
constant
constant(常量)用来在配置阶段传递数值,注意这个常量在配置阶段是不可用的。
示例:factory机制
链接:
跨站点脚本(XSS)攻击是一种注入类型,其中恶意脚本被注入到其他良性和可信赖的网站中。那么Angular怎么防御xss攻击?
当攻击者使用Web应用程序将恶意代码(通常以浏览器端脚本的形式)发送给不同的最终用户时,就会发生XSS攻击。允许这些攻击成功的缺陷非常普遍,并且发生在Web应用程序在其生成的输出中使用来自用户的输入而无需验证或编码它的任何地方。
Angular怎么防御xss攻击
要阻止XSS攻击,必须防止恶意代码进入DOM。Angular将所有数据视为不受信任的数据;因此,默认情况下,它会清理所有数据。这实质上意味着您的数据中找到的任何html标记都会被转义。为了使您仍能够在页面上显示html数据,Angular可以使用不同的技术(如使用DOMSanitizer API等)来清理数据,以便以足够安全的形式转换数据, *** 入到DOM树中。
清理可以对不受信任的值的检查,将其转换为可安全插入DOM的值。
防止服务器XSS攻击的 *** :
避免XSS攻击的主要要求是防止不受信任的数据(恶意脚本/代码)被注入DOM树。
● 作为服务器端处理的一部分,在将所有数据作为Http响应发送之前将其转义。这意味着如果响应数据由HTML / JavaScript标签组成,它们将被转义。
● 避免生成Angular模板作为服务器端处理的一部分。这可能导致模板注入,从而当页面在浏览器中加载时导致DOM操纵。
防止客户端XSS攻击的 *** :
防止客户端XSS攻击的主要目标是避免因执行恶意脚本执行而修改DOM树。请注意,恶意脚本可能会因反射或存储的XSS攻击而到达。Angular使用以下一些技术来避免客户端XSS攻击:
● 使用innerHTML属性显示带有HTML标记的内容:
Angular提供innerHTML属性,可用于防止所有数据的自动化,以显示为组件视图的一部分。由HTML标记组成的HTML代码段可以通过将其分配给模板中元素的innerHTML属性来专门从不安全的脚本标记元素进行清理,如下所示。
脚本中的不安全标记元素将从内容中删除。使用innerHTML属性有助于从脚本注入中清理服务器响应数据,同时确保HTML元素显示为可信数据。
以下是模板代码app.component.html,如上面的组件中所述。请注意组件的成员变量htmlSnippet,它包含HTML代码段。
加载到页面中的上述模板显示如下:
● 使用DOMSanitizer API防止Angular自动清理:
Angular提供了DOMSanitizer bypassSecurityTrustXXX API,可用于防止数据的自动清理。
● 必须避免直接使用DOM API:
应该避免直接使用DOM API,例如ElementRef。浏览器内置DOM API不会自动清理数据。因此,可以注入脚本,从而创建XSS漏洞。
● 内容安全策略(CSP):
应适当设置CSP以避免XSS攻击。所有需要做的是将content-security-policy设置为HTTP标头的一部分。
链接:
跨域,前端开发中常常遇到的问题。Angularjs实现跨域方式类似于Ajax,使用CORS机制。以下阐述一下Angularjs中使用$http实现跨域请求数据。
Angular *** XMLHttpRequest:$http用于读取远程server的数据
一、$http.jsonp【实现跨域】
1. 指定callback和回调函数名,函数名为 *** ON_CALLBACK时,会调用success回调函数。 *** ON_CALLBACK必须全为大写。
2. 指定其他回调函数,但必须是定义在window下的全局函数。url中必须加上callback。
二、$http.get【实现跨域】
1、 在server端设置同意在其它域名下訪问
2、 Angular *** 端使用$http.get()
三、$http.post【实现跨域】
1、 在server端设置同意在其它域名下訪问,及响应类型、响应头设置response.setHeader("Access-Control-Allow-Origin", "*");
2、Angular *** 端使用$http.post(),同一时候设置请求头信息
四、实现方式
跨域方式一【 *** ONP】:
*** 一:
*** 二【返回值。须要使用相应callback *** 接收,但怎样置于$scope】:
跨域方式二【$http.get()】:
跨域方式三【$http.post()】:
链接:
Node-RED是一种基于Node.js的编程工具,用于以新颖有趣的方式将硬件设备,API和在线服务连接在一起。它提供了一个基于浏览器的编辑器,可以使用调色板中的各种节点轻松地将流连接在一起,只需单击即可将其部署到运行时。
吾辈的博客原文地址:
吾辈已经写了一个 TypeScript/JavaScript Cli 工具 liuli-cli,如有需要可以使用这个 Cli 直接生成一个开箱即用 SDK 项目,然后就可以直接开始写自己的代码,不需要太过关心下面的内容了 -- 因为,它们都已然集成了。
如果我们想要写一个 JavaScript SDK,那么就不太可能将所有的代码都写到同一个 js 文件中。当然了,想做的话的确可以做到,但随着 JavaScript SDK 内容的增加,一个 js 文件容易造成开发冲突,以及测试上的困难,这也是现代前端基本上都依赖于打包工具的原因。
现今更流行的打包工具是 webpack,然而事实上对于单纯的打包 JavaScript SDK 而言 webpack 显得有些太重了。webpack 终究是用来整合多种类型的资源而产生的(react *** /vue *** /Babel/TypeScript/Stylus),对于纯 JavaScript 库而言其实并没有必要使用如此 强大 的工具。而 rollup 就显得小巧精致,少许配置就能立刻打包了。
该记录的代码被吾辈放到了 GitHub,有需要的话可以看下。
开始之前,我们必须要对以下内容有所了解
[x] JavaScript[x] npm[ ] babel[ ] uglify[ ] eslint
安装 rollup
在根目录创建一个 rollup.config.js 配置文件
添加一个 npm script
然后运行 npm run build 测试打包,可以看到 dist 目录下已经有 bundle.js 文件了
好了,到此为止我们已经简单使用 rollup 打包 js 了,下面的内容都是可选项,如果需要可以分节选读。
然而,我们虽然已经将 main.js 打包了,然而实际上我们的代码没有发生什么变化。即:原本是 ES6 的代码仍然会是 ES6,而如果我们想要尽可能地支持更多的浏览器,目前而言还是需要兼容到 ES5 才行。
所以,我们需要 babel,它能够帮我们把 ES6 的代码编译成 ES5。
附:babel 被称为现代前端的 jquery。
首先,安装 babel 需要的包
在 rollup.config.js 中添加 plugins
添加 babel 的配置文件 .babelrc
再重新运行 npm run build,可以看到 bundle.js 中的代码已经被编译成 ES5 了。
那么,生产中的代码还需要做什么呢?是的,压缩,减小 js 代码的体积是必要的。接下来,我们还需要使用 uglify 压缩我们打包后的 bundle.js 代码。
首先仍然是安装 uglify 相关的包
然后在 rollup.config.js 中引入插件就好了
如果我们想要需要多人协作统一代码风格,那么可以使用 ESLint 来强制规范。
首先,全局安装 eslint
然后使用 eslint cli 初始化
下面的三项问题选择
How would you like to configure ESLint (Use arrow keys)
Use a popular style guideWhich style guide do you want to follow (Use arrow keys)
Standard ()What format do you want your config file to be in (Use arrow keys)
JavaScriptWould you like to install them now with npm
y
然后,我们发现项目根目录下多出了 .eslintrc.js,这是 eslit 的配置文件。然而,我们需要对其稍微修改一下,不然如果我们的代码中出现了浏览器中的对象,例如 document,eslint 就会傻傻的认为那是个错误!
修改后的 .eslintrc.js 配置
当我们查看打包后的 bundle.js 时发现 eslint 给我们报了一堆错误,所以我们需要排除掉 dist 文件夹
添加 .eslintignore 文件
添加 rollup-plugin-eslint 插件,在打包之前进行格式校验
然后引入它
这个时候,当你运行 npm run build 的时候,eslint 可能提示你一堆代码格式错误,难道我们还要一个个的去修复么?不,eslint 早已考虑到了这一点,我们可以添加一个 npm 脚本用于全局修复格式错误。
然后运行 npm run lint,eslint 会尽可能修复格式错误,如果不能修复,会在控制台打印异常文件的路径,然后我们手动修复就好啦
添加代码映射文件
其实很简单,只要在 rollup.config.js 启用一个配置就好了
多环境打包
首先移除掉根目录下的 rollup.config.js 配置文件,然后创建 build 目录并添加下面四个文件
修改 npm 脚本
那么,关于使用 rollup 打包 JavaScript 的内容就先到这里了,有需要的话后续吾辈还会继续更新的!
链接:
原文
这篇文档的目的是解释 nginx ingress 控制器是如何工作的,特别是 nginx 模型的构建以及为什么需要它。
nginx ingress 控制器目标是组织 nginx 配置文件, 当 nginx 的配置文件发生任何更改时都需要重新加载,当配置文件中upstream 的内容有变更时(例如 当部署的应用中的 endpoints 变更时), nginx 的配置文件不会被重新加载,我们使用 ngx_http_lua_module 模块完成 endpoints 的变更,请继续往下看是如何操作的。
通常来说,k8s 控制器利用同步循环模式去检查控制器中资源的变更或者更新,为了达到这个目的,我们需要使用来自集群中不同的对象来构建一个模型,特别是(没有顺序要求) ingresses、Services, Endpoints, Secrets, and Configmaps 来生成一份和时间点相关的配置文件用来反映集群的状态。为了从集群中获取对象,我们使用 Kubernetes Informers 特别是FilteredSharedInformer,Informers 允许通过回掉机制对每一个独立的资源对象在添加、删除、更新时做出相关的反映,不幸的是,没有一种方式能够知道 nginx 的配置文件中具体哪一处发生了变化,因此,当每次发生变更时,我们不得不重新构建一次完成的配置模型与当前正在运行的模型进行比较,如果新的模型和当前的相等,那就避免生成新的配置从而去触发 nginx 重载,除此之外,我们检查如果仅仅是 Endpoints 不一样, 我们发送一个 HTTP POST 到 lua 处理模块,它运行在 nginx server 内部,从而避免重新生成新的配置触发 nginx 重新加载,如果新的配置模型和正在运行的模型比较后不仅仅是 Endpoints 不一样,那么就基于新的配置模型生成配置文件替换正在运行的配置文件触发 nginx 重新加载,
利用模型一是为了避免不必要的 reload 发生再一个是为了检查配置的定义冲突。
nginx 的最终配置文件来源于 Go template, 利用新的模型作为模版的需要的变量。
构建模型是一个昂贵的操作,由于这个原因,使用同步循环是必须的,通过使用 work queue 可以避免变更丢失,同时去掉 sync.Mutex的使用,额外的在循环开始和循环结束时创建时间窗允许丢弃不必要的更新,很重要的一件事情是集群中的任何变更都会都过 informer 发送到控制器中,这也是使用 work queue 的一个原因。
构建模型步骤通过CreationTimestamp 字段对 ingress 规则进行排序,比如 旧规则优先如果在多个 ingress 中相同主机的的相同路径被定义,最后的定义生效如果多个 ingress 包含了相同主机的相同 TLS 部分内容,最后的定义生效如果多个 ingresses 定义的一个注解影响了 server 部分的配置,那么最后的定义生效创建 nginx servers 的列表(每一个主机)创建 nginx upstreams 列表如果多个 ingresses 定义了同一个主机的不同路径,ingress controller 会降这些定义合并注解会被应用到 ingress 中所有的路径每一个 ingresses 可以定义不同的注解,这些注解不会被共享
以下列表描述了需要 reload 的场景
新的 ingress 资源被创建TLS section 添加到已经存在的 ingress 中更改 ingress 的注解不仅仅影响到了 upstream 的配置,例如 load-balance 注解更改不需要执行 reload 操作从 ingress 中添加或者移除路径移除 Ingress, Service, Secret一些缺失的对象从 ingress 中可以获得,比如 Service 或者 SecretSecret 被更新
某种情况下应该避免 reload, 特别是 endpoints 的变更, 比如 pod 的启动或者替换,完全删除重新加载超出了Ingress 控制器的范围。这将需要大量工作,并且在某些时候没有任何意义。 仅当 NGINX 更改了读取新配置的方式时,这才可以更改,基本上,新的更改不会替代工作进程
当每一次 endpoint 变更时,控制器能够从看得见的 services 中获取 endpoints,生成相关的后端对象,然后将这些对象发送到运行在 ngixn 内部的 lua 处理模块中, Lua 代码反过来将这些对象存储在共享内存区域, 每一次请求到来时 balancer_by_lua 会通过配置的负载均衡算法选择一个后端对象来处理,nginx 则关心其余的事情,这种方式避免了当 endpoint 变化时发生 reload,注意当 upstream 的注解发生变更时也会避免发生 reload。
在具有频繁部署应用程序的相对较大的群集中,此功能可以节省大量 Nginx 重载,否则会影响响应延迟,负载均衡质量(每次重载 Nginx 都会重置负载平衡状态)等等
因为 ingress 制器使用同步循环工作模式,所以它将配置应用于所有匹配的对象。如果某些 Ingress 对象的配置损坏,例如nginx.ingress.kubernetes.io/configuration-snippet 批注中的语法错误,则生成的配置将变为无效,不会重新加载,因此没有 ingress 将会被考虑。
为了防止这种情况的发生,nginx 入口控制器选择性的暴漏一个 准入验证 Webhook 服务器,以确保传入的 ingress 对象的有效性。 Webhook 进来的 ingress 加入到 ingresses 列表中,生成配置并调用 nginx 以确保配置没有语法错误。
链接:
至今也写了四年多代码,但如何在功能不断增多的同时写出可读、可维护、可扩展的或者说优雅的代码一直令我感到非常困惑。
最近读了《Clean Architecture》以及 Domain Driven Design(简称 DDD) 相关软件架构的书,对这个问题有了进一步的思考。
虽然读过《代码大全》、《Clean Code》、《重构》、《Design Patterns》等书,也在编程中不断实践,但逐渐发现书中的技巧更着重细节的打磨,关注点在于如何把一个函数、类、模块设计好。不过大量模块集成后的系统质量却难以保证。
为什么不是“没有设计就是糟糕设计”。因为当软件的复杂度很低时,无论如何都可以达到不错的质量。对于一个小模块,只需几个类就可以实现预期的功能。
但需求永无止境,功能堆叠难以避免。新功能可能是基于原模块修改,添加一些新类和新函数,也可能是通过新模块实现。此时模块、类、函数之间的交互逐渐复杂,虽然整个系统还可以理解,但是混乱的种子已经埋下。
长此以往,人员的来来往往伴随着千人千面的设计,整个系统难以避免的走向了大泥球。
大泥球的代码依旧可以运行,依旧可以为用户提供功能,依旧可以在上面修修补补,为什么这会成为一个问题呢?
因为现实中的需求和业务总是在不断的变化中,这也要求软件不断的发生变化以适应需求的变化,而失控的代码恰恰导致变化的成本非常高昂。
复杂的依赖关系意味着每一行代码修改的结果都会如同涟漪一般扩散到依赖的代码,导致难以预料的后果。
边界含糊的模块、类、函数互相交织,再没人能理解整个系统。缺失的上下文导致变更时,程序员只能从代码中重建对应的逻辑,往往落入盲人摸象的困境,而基于不完整理解的产物通常是四不像的怪物。
长此以往,变更、维护的成本会越来越高,软件易修改、可扩展的优点丧失殆尽,退化为“硬件”。
在大泥球中工作绝对不是一件愉快的事情,接手过旧有代码的人都可以理解,因为大泥球还有另外一个俗称“屎山”。从个人来说,为了愉快的编码,肯定不希望自己的代码变成大泥球。对公司来讲,代码的可扩展性、稳定性、可维护性是公司竞争力的来源,如果你可以比对手花更低的成本,更好更快的响应用户需求,自然能步步争先。
软件经过几十年的发展,能做的事情越来越多,复杂度越来越高。在这个过程中,大家花了很多的时间去思考怎么样才能更好的管理复杂度,因为软件的极限在于我们能多大程度上理解我们所创建的系统。
面向对象、垃圾回收、函数式编程、设计模式等都是思考的结晶,但它们更着重于技术的实现,随着软件不断整合复杂的现实世界,我们需要从更广阔的角度、用更好的方式来建模业务逻辑,DDD 即是其中流行的架构范式之一。
以技术为中心的架构设计
以技术为中心的思考方式通常能以最快的速度搞定需求。当开发一个功能时,首先考虑的是数据库怎么设计,接口怎么定义,需不需要缓存,如何利用框架已有的功能等,有了一个大概轮廓后,编码、测试、上线,不断循环。但从架构设计的角度,让代码跑起来只是之一步,如果新代码不能跟旧代码在整体设计上进行集成,最后很可能变成大泥球一般的四不像怪物。不过就算我们以良好的服务设计、模块化设计、类设计、接口设计将新功能优雅的整合进现有模块,以技术为中心的开发方式依旧有其更大的弊病。
在工作中,我常常听到客户经理、销售、产品对研发说:你为什么不说人话?因为通常来说,需求的发起方是来自销售、产品这些业务专家,他们对业务的建模(心智模型)通常跟我们以技术为中心的思考方式不同。他们并不了解微服务、关系型数据库、Mongodb、Redis、Route、Graphql、RESTful、gRPC 等技术术语,他们了解的是业务逻辑、业务对象及其交互。不懂技术的业务专家,不懂业务的技术,他们的沟通成果可想而知。
在实际的开发中,研发通常会将业务逻辑简称为 crud(增删改查),认为技术是骨,业务是皮,业务逻辑不过是一些简单、琐碎的编码过程,笑称专注于此的程序员为码农。长此以往,每个功能内含的底层业务逻辑被割裂,零碎的分散在整个代码库中。而新需求通常是基于业务专家的建模,此时谁还有能力从整个代码库中还原出整个业务蓝图并予以修改呢?
为什么要发明高级编程语言而不使用汇编?因为编程时通常不需要关心底层的寄存器、指令集。
为什么要发明 ORM 而不是用 SQL ?因为 SQL 作为关系型数据库,不是以面向对象的思考方式设计。
为什么要发明图形化界面而不使用命令行?因为大部分用户习惯通过图形化的方式来认知世界。
设计应当以终端用户的体验为中心,而架构说到底不过是设计的别名。当心智模型和底层逻辑匹配时,变更、维护、扩展的成本因此降低。而业务软件的用户是谁呢?业务专家以及熟悉该业务的用户。
基于以上的思考,一些人在 20 年前提出了领域驱动设计(Domain Driven Design),简称 DDD,试图扭转这一趋势,提倡以业务为中心的架构设计。
以 DDD 的进行架构设计,首先不是关注语言、数据库、框架、RESTful、gRPC 等,而是从梳理业务逻辑出发,通过与业务专家的深入讨论,构建符合业务逻辑的模型,再通过各种各样的技术实现支撑业务逻辑的建模。在这个过程中要严格分离业务逻辑和技术实现,因为通常业务逻辑和技术实现有不同的变化速率以及变化方向。
一个产品有人使用,必然是有其核心优势,优势所在即其核心领域。比如今日头条的核心优势不是资讯,不是爬虫,而是其推荐引擎。资讯、爬虫、甚至抖音的短视频都是基于其推荐引擎的次级领域。对于一个影评网站来说,核心领域则是其评分、评论机制。而用户系统,包括登录、注册、重置密码、头像等功能,只能算是一些通用领域。
这样的话,我们可以基于业务领域的重要性进行划分:
核心域(Core Domain):产品竞争力的来源和优势所在,例如头条的推荐引擎。支撑域(Support Domain):实现核心域的辅助领域。例如资讯、短视频的管理,以及如何依赖推荐引擎进行分发。通用领域(Generic Domain):例如用户管理。这里是各种框架、库、第三方服务大放异彩的地方。
每个领域应该保证其中的核心概念具有精确的定义,否则“名不正,则言不顺”。正如用户管理领域中的用户跟推荐系统中的用户是不同的概念,具有不同的属性和行为,各有其偏重。
下图以保单为例,我们在承保时,关注的是保单的价格和理赔条件,在审核时,可能关注的是承保人的健康状况,保单是否为本人签名,而理赔时则关注对应的赔偿金额。如果强行把不同阶段的逻辑都整合到一个保单对象,必然会导致逻辑繁杂、主次不分。
DDD 专注业务复杂度,致力于将业务专家的心智模型建模为技术模型。这个过程需要业务专家和技术人员深入沟通、并肩协作,通过大量的信息传递,在不断的讨论、质疑、磨合中提炼最终的模型。建模是 DDD 最重要的实践过程,也是 DDD 最难以落地的困难之一:对业务感兴趣并喜欢深入钻研的程序员并不多。
这个问题随着团队人数的增长,会越来越严峻。对个人开发者来说,设计和开发都在一人之手,自然也不存在沟通的问题。对于小型团队,如果不能保证团队成员对产品感兴趣,只能通过文档、培训等来普及领域知识。随着领域知识的不断增长和复杂化,超过个人的承载能力后,划分不可避免。
领域建模需要深入设计,有人会疑惑:“那是不是需要整体设计完后才能开始编码,这不是退回到瀑布流的开发模式?” 并不是。很多 DDD 的倡导者本身也是敏捷和极限编程的支持者。他们认为一开始就认为设计出完美、精确的领域模型是不现实的。随着业务的扩张收缩、产品开发方向的变化,我们会不断获得新的领域知识,领域建模在开发、沟通、实践过程中会被不断精炼、完善。旧概念的理解会越来越透彻,新概念会不断涌现,一些不相关的概念会被剥离,因此代码的渐进式重构不可避免。领域驱动设计(DDD)也意味着对业务领域的深入理解驱动着设计的不断变化。
DDD 提倡我们要尊重现实世界的业务逻辑,尊重已有业务专家的经验,以业务为中心驱动架构设计,更好的为业务服务。
对我来说真有当头棒喝的效果,毕业这几年已经习惯从技术的角度看问题,相信技术万能论。“当你手上有一把锤子的时候,看所有的东西都是钉子”,有时候效果很好,有时候却一叶障目,但长此以往,目光越来越狭窄是必然的。
DDD 落地还有很多技术细节,有机会的话下次在谈。这里也欢迎喜欢编程、架构设计、DDD 的小伙伴一起来探讨。
原文来自:
链接:
flux四大元素:Dispatcher:根据注册派发动作(action),Store: 存储数据,处理数据,Action:用于驱动Dispatcher,View: 用户界面视图。flux的目的:纠正MVC框架的无法禁绝view与model通信的缺点。Redux基本原则:继承Flux基本原则:单向数据流
new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例
先看看 new 实现了哪些功能, 先来看一段代码:
从上面代码可以知道,实例 person 可以:
访问到 Person 构造函数里的属性访问到 Person.prototype 中的属性
这个是最基本的了,也是刚学会new一个对象就知道这是new的特点
探讨完上面,接下来看看new还做了什么?来看几个例子
从构造函数直观看,最后是没有 return语句的,但我们从返回结果也可以看出构造函数时默认情况会返回一个新对象
我们尝试在构造函数最后返回一个对象
打印出来的结果可以看书:return 之前的代码片段都被覆盖了,最后返回 return 后面的对象。
如果构造函数最后return的不是对象呢,试下基本数据类型
从打印出来的结果可知,和没有return效果一样。
mdn上把内部操作大概分为4步:
创建一个空的简单JavaScript对象(即{ } );链接该对象(即设置该对象的构造函数)到另一个对象 ;(因此this就指向了这个新对象)执行构造函数中的代码(为这个新对象添加属性);如果该函数没有返回对象,则返回this。
new 是关键词,不可以直接覆盖。这里使用 create 来模拟实现 new 的效果。
来看看上面是怎么一步步模拟实现的:
用new Object() 的方式新建了一个空对象 obj取出之一个参数,即是传入的构造函数。shift 会修改原数组,数组原来的之一个元素的值。将 obj 的原型指向构造函数,这样 obj 就可以访问到构造函数原型中的属性使用 apply,改变构造函数 this 的指向。将this指向obj对象 就可以访问到构造函数中的属性处理返回值。构造函数返回值有三种情况:没有return,默认返回之前创建的对象返回一个对象返回的不是对象,默认返回之前创建的空对象
在上面我们用instanceof *** 来判断是否为对象
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
测试:
模拟实现成功!
链接:
瀑布流又称瀑布流式布局,是比较流行的一种网站页面布局方式。视觉表现为参差不齐的多栏布局,即多行等宽元素排列,后面的元素依次添加到其后,等宽不等高。这里只是实现了简单的效果,话不多说上效果图。
代码
wxml基本布局
wxss样式代码
基本思路就是利用wx:if和数组的下标对2取余来判断是排在左列还是排在右列,这里面很重要的一个属性就是mode='widthFix',即表示图片宽度固定,高度自适应,由此即可实现效果。
最后在函数onReachBottom中修改数据即可实现上拉加载。当然实现瀑布流的 *** 有很多,查了一下通过css3中属性column-count也可以实现同样的效果。
链接:
当一个函数被保存为对象的一个 *** 时,如果调用表达式包含一个提取属性的动作,那么它就是被当做一个 *** 来调用,此时的this被绑定到这个对象。此时的this是指obj1这个对象,obj1.fn()实际上是obj1.fn.call(obj1),事实上谁调用这个函数,this就是谁。
一个Angular应用一般情况下包含多个组件,而且要让组件互相之间能进行通讯(数据传送),这样才能构成一个有机的完整系统。
下面例举一个实际遇到的情况:
上图页面包含两个组件,“新增班级组件”和“选择教师组件”,在新增班级时需要选择改班级的管理教师,管理教师列表要从数据库中获取。选择好教师后,“选择教师组件”要把选择的教师对象传递回“新增班级组件”,这其中涉及到对象传递称为通讯。
组件之间有几种典型的关系:父子关系、兄弟关系、没有直接关系
父子关系说明:有A、B两个组件(不一定在同一个模块),如果A组件的view页面中引用了B的selector标签,则称A为B的父组件,或B为A的子组件。
了解完组件存在的关系,相应地,组件之间有以下几种典型的通讯方案:
直接的父子关系:父组件直接访问子组件的 public 属性和 *** 直接的父子关系:借助于 @Input 和 @Output 进行通讯没有直接关系:借助于 Service 单例进行通讯利用 cookie 和 localstorage 进行通讯利用 session 进行通讯
假设BComponent是AComponent的子组件。
对于有直接父子关系的组件,父组件可以直接访问子组件里面 public 型的属性和 *** ,示例代码片段如下:
显然,子组件B里面必须暴露一个 public 型的 childFunction *** ,就像这样:
以上是通过在模板里面定义局部变量的方式来直接调用子组件里面的 public 型 *** 。在父组件的内部也可以访问到子组件的实例,需要利用到 @ViewChild 注解,示例如下:
如果通过 @ViewChild 注解,父组件直接访问子组件,那么两个组件之间的关系就被固定死了。父子两个组件紧密依赖,谁也离不开谁,不能单独使用了。尽量避免这样做。
同样假设BComponent是AComponent的子组件。
我们可以利用 @Input 装饰器,让父组件直接给子组件传递参数,子组件BComponent上这样写:
父组件view上可以这样设置 title 这个参数(这个参数可以是个父组件想要传给子组件的变量或对象等):
前面是父组件->子组件传递数据,过程相对简单,下面是子组件->父组件传数据,过程较复杂。
@Output 的本质是事件机制,我们可以利用它来监听子组件上派发的事件,子组件上这样写:
EventEmitter:在angular中组件通过定义EventEmitter 事件弹射器的方式由子组件向父组件发送数据。
selected是一个事件,触发 selected 事件的方式如下:
在子组件上定义一个 *** onChange(),使子组件view能够调用该 *** 触发 selected 事件:
父组件可以这样监听selected事件:
使用我们刚刚在子组件中定义的@Output() selected
*** 名需要在C层中定义,而参数名可以随性起,但我们一般为起名为$event以示此处为该组件的一个弹射器。
原文:
链接:
近些年,移动端普及化越来越高,开发过程中选用 Native 还是 H5 一直是热门话题。Native 和 H5 都有着各自的优缺点,为了满足业务的需要,公司实际项目的开发过程中往往会融合两者进行 Hybrid 开发。Native 和 H5 分处两地,看起来无法联系,那么如何才能让双方协同实现功能呢?
这时我们想到了 Codova ,Codova 提供了一组与设备相关的 API ,是早期 js 调用原生代码来实现原生功能的常用方案。不过 *** Bridge 真正在国内广泛应用是由于移动互联网的盛行。
*** Bridge 是一种 *** 实现的 Bridge,连接着桥两端的 Native 和 H5。它在 APP 内方便地让 Native 调用 *** , *** 调用 Native ,是双向通信的通道。 *** Bridge 主要提供了 *** 调用 Native 代码的能力,实现原生功能如查看本地相册、打开摄像头、指纹支付等。
H5 与 Native 对比
nameH5Native稳定性调用系统浏览器内核,稳定性较差使用原生内核,更加稳定灵活性版本迭代快,上线灵活迭代慢,需要应用商店审核,上线速度受限制受网速 影响较大较小流畅度有时加载慢,给用户“卡顿”的感觉加载速度快,更加流畅用户体验功能受浏览器限制,体验有时较差原生系统 api 丰富,能实现的功能较多,体验较好可移植性兼容跨平台跨系统,如 PC 与 移动端,iOS 与 Android可移植性较低,对于 iOS 和 Android 需要维护两套代码
*** 调用 Native
*** 调用 Native 的实现方式较多,主要有拦截 URL Scheme 、重写 prompt 、注入 API 等 *** 。
拦截 URL Scheme
Android 和 iOS 都可以通过拦截 URL Scheme 并解析 Scheme 来决定是否进行对应的 Native 代码逻辑处理。
Android 的话,Webview 提供了 shouldOverrideUrlLoading *** 来提供给 Native 拦截 H5 发送的 URL Scheme 请求。代码如下:
iOS 的 WKWebview 可以根据拦截到的 URL Scheme 和对应的参数执行相关的操作。代码如下:
这种 *** 的优点是不存在漏洞问题、使用灵活,可以实现 H5 和 Native 页面的无缝切换。例如在某一页面需要快速上线的情况下,先开发出 H5 页面。某一链接填写的是 H5 链接,在对应的 Native 页面开发完成前先跳转至 H5 页面,待 Native 页面开发完后再进行拦截,跳转至 Native 页面,此时 H5 的链接无需进行修改。但是使用 iframe.src 来发送 URL Scheme 需要对 URL 的长度作控制,使用复杂,速度较慢。
重写 prompt 等原生 *** ***
Android 4.2 之前注入对象的接口是 addJavaScriptInterface ,但是由于安全原因慢慢不被使用。一般会通过修改浏览器的部分 Window 对象的 *** 来完成操作。主要是拦截 alert、confirm、prompt、console.log 四个 *** ,分别被 Webview 的 onJsAlert、onJsConfirm、onConsoleMessage、onJsPrompt 监听。其中 onJsPrompt 监听的代码如下:
iOS 由于安全机制,WKWebView 对 alert、confirm、prompt 等 *** 做了拦截,如果通过此方式进行 Native 与 *** 交互,需要实现 WKWebView 的三个 WKUIDelegate *** *** 。代码示例如下:
使用该方式时,可以与 Android 和 iOS 约定好使用传参的格式,这样 H5 可以无需识别客户端,传入不同参数直接调用 Native 即可。剩下的交给客户端自己去拦截相同的 *** ,识别相同的参数,进行自己的处理逻辑即可实现多端表现一致。如:
另外,如果能与 Native 确定好 *** 名、传参等调用的协议规范,这样其它格式的 prompt 等 *** 是不会被识别的,能起到隔离的作用。
##### 注入 API
基于 Webview 提供的能力,我们可以向 Window 上注入对象或 *** 。 *** 通过这个对象或 *** 进行调用时,执行对应的逻辑操作,可以直接调用 Native 的 *** 。使用该方式时, *** 需要等到 Native 执行完对应的逻辑后才能进行回调里面的操作。
Android 的 Webview 提供了 addJavascriptInterface *** ,支持 Android 4.2 及以上系统。
*** 调用示例:
iOS 的 UIWebview 提供了 JavaScriptScore *** ,支持 iOS 7.0 及以上系统。WKWebview 提供了 window.webkit.messageHandlers *** ,支持 iOS 8.0 及以上系统。UIWebview 在几年前常用,目前已不常见。以下为创建 WKWebViewConfiguration 和 创建 WKWebView 示例:
*** 调用示例:
Native 调用 ***
Native 调用 *** 比较简单,只要 H5 将 *** *** 暴露在 Window 上给 Native 调用即可。
Android 中主要有两种方式实现。在 4.4 以前,通过 loadUrl *** ,执行一段 *** 代码来实现。在 4.4 以后,可以使用 evaluateJavascript *** 实现。loadUrl *** 使用起来方便简洁,但是效率低无法获得返回结果且调用的时候会刷新 WebView。evaluateJavascript *** 效率高获取返回值方便,调用时候不刷新WebView,但是只支持 Android 4.4+。相关代码如下:
iOS 在 WKWebview 中可以通过 evaluateJavaScript:javaScriptString 来实现,支持 iOS 8.0 及以上系统。
如何引用
由 H5 引用
在我司移动端初期版本时采用的是该方式,采用本地引入 npm 包的方式进行调用。这种方式可以确定 *** Bridge 是存在的,可直接调用 Native *** 。但是如果后期 Bridge 的实现方式改变,双方需要做更多的兼容,维护成本高
由 Native 注入
这是当前我司移动端选用的方式。在考虑到后期业务需要的情况下,进行了重新设计,选用 Native 注入的方式来引用 *** Bridge。这样有利于保持 API 与 Native 的一致性,但是缺点是在 Native 注入的 *** 和时机都受限, *** 调用 Native 之前需要先判断 *** Bridge 是否注入成功
使用规范
H5 调用 Native *** 的伪代码实例,如:
以下简要列出通用 *** 的抽象,目前基本遵循以下规范进行双端通信。
由于初期版本选择了由 H5 本地引用 *** Bridge,后期采用 Native 注入的方式。现有的 H5 需要对各种情况做兼容,逻辑抽象如下:
上述内容简要介绍了 *** Bridge 的部分原理,希望对从未了解过 *** Bridge 的同学能有所帮助。如果需要更深入的了解 *** Bridge 的原理和实现,如 *** Bridge 接口调用的封装实现, *** 调用 Native 时的回调的唯一性等。大家可以去查阅更多资料,参考更详细的相关文档或他人的整理成文的沉淀。
本文首发于政采云前端团队博客:小白必看, *** Bridge 初探
链接:
首先来思考一个问题:是否有一种 *** 可以从子组件填充父组件的插槽?
最近一位同事问我这个问题,答案很简单:可以的。但我的解决方案可能和你想的完全不一样,这是涉及一个棘手的vue架构问题,但也是一个非常有趣的问题。
在我们的应用程序中,我们有一个顶部栏,其中包含不同的按钮、搜索栏和其他一些控件。根据每个人所在的页面,它可能略有不同,因此我们需要一种基于每个页面配置它的 *** 。
为此,我们希望每个页面都能够配置操作栏。看起来很简单,但这里有个问题
这个顶部栏(我们称之为ActionBar)实际上是我们的主布局的一部分,结构如下:
根据你所在的页面/路线动态注入App的位置。
我们可以使用ActionBar上的一些插槽来配置它。 但是,我们如何从App组件中控制这些插槽?
首先,更好是尽可能清楚地知道我们要解决的问题。
我们来看一个具有一个子组件和一个插槽的组件:
我们可以这样填充Parent的插槽:
这里没什么特别的。
填充子组件的插槽很容易,这也是使用插槽的最常见方式。
但是,有没有一种 *** 可以控制从Child组件内部进入Parent组件slot的内容呢?
换种说法:我们可以让子组件填充父组件的插槽吗?来看看我想到的之一个解决方案。
数据流经组件树的唯一途径是使用props。 而向上通信的 *** 是使用事件。这意味着,如果要让子组件与父组件进行通信,我们需要使用事件来实现。
因此,我们将使用事件来将内容传递到ActionBars槽中
我们将要放入插槽中的所有内容打包到SlotContent组件中。 一旦创建了应用程序组件,我们就会发出slot-content事件,并传递我们要使用的组件。
我们的组件结构如下:
监听该事件,并将slotContent设置为我们的App组件发送给我们的任何内容。 然后,使用内置的Component,就可以动态地渲染该组件。
但是,通过事件传递组件感觉很奇怪,并非是主流的做法。幸运的是,还有一种 *** 可以完全避免使用事件。
由于Vue组件只是 js 对象,因此我们可以向它们添加所需的任何属性。无需使用事件传递插槽内容,我们只需将其作为字段添加到组件中即可:
在主页中通过 App.slotContent 获取对应的组件
这更像是静态配置,更美观、更简洁,但这仍然是不对的。
理想情况下,我们不会在代码中混合使用范式,所有操作应该都是以声明方式完成。
但是在这里,我们没有将我们的组件组合在一起,而是将它们作为 js 对象传递。如果我们能以正常的Vue方式把我们想要的写在插槽里就好了。
Vue 中的 Portal 技术 在 Vue 项目中,我们使用模板来声明 dom
嵌套关系,然而有时候一些组件需要脱离固定的层级关系,不再受制与层叠上下文,比如说 Modal 和 Dialog
这种组件就希望能够脱离当前模板所在的层叠上下文。
在 Vue 中有两种方式来实现这种效果,一种是使用指令,操作真实 dom,使用熟知的 dom 操作 *** 将指令所在的元素 append
到另外一个 dom 节点上去。另一种方式就是定义一套组件,将组件内的 vnode 转移到另外一个组件中去,然后各自渲染。
它们的工作方式和你想象的完全一样。你可以把任何东西从一个地方传送到另一个地方。在我们的例子中,我们将元素从DOM中的一个位置“传送”到另一个位置。
无论组件树如何显示,我们都可以控制组件在DOM中的显示位置。
例如,假设我们想要填充一个modal。但是我们的modal必须在根页面处渲染,这样我们才能正确地覆盖它。首先,我们要在modal中指定我们想要的:
然后,在我们的modal组件中,我们将拥有另一个将内容渲染出来的 portal:
这是一项改进,因为现在我们实际上是在编写html,而不仅仅是传递对象。 它更具声明性,更容易查看应用程序中发生的事情。
由于 portal 在背后执行一些操作以在不同位置渲染元素,因此它完全打破了DOM渲染在Vue中工作方式的模型。 看起来您正在正常渲染元素,但根本无法正常工作,这可能会引起很多混乱和沮丧。
还有一个很大的问题,稍后我们会讲到。
“提升状态”是指将状态从子组件移动到父组件或祖父组件,将它向上移动到组件树中。
这可能对应用程序的体系结构产生较大的影响。对于我们的目的,这会是更简单的解决方案。
这里的“状态”是我们试图传递到ActionBar组件插槽中的内容。但是该状态包含在Page组件中,我们不能真正将 page 特定的逻辑移到layout组件中。 我们的状态必须保留在我们正在动态渲染的Page组件内。
因此,我们必须提升整个Page组件才能提升状态。当前,我们的Page组件是Layout组件的子组件:
解除它需要我们将其翻转,并使Layout组件成为Page组件的子组件。 我们的Page组件看起来像这样:
现在,我们的Layout组件将看起来像这样,我们可以在其中使用插槽插入页面内容:
但这还不能让我们自定义任何内容。 我们必须在Layout组件中添加一些命名的插槽,以便我们可以传递应放置在ActionBar中的内容。
最简单的 *** 是使用一个插槽来完全替代ActionBar组件:
这样,如果你不指定“actionbar”插槽,默认使用ActionBar组件。 但我们可以使用自己的自定义ActionBar配置覆盖此插槽:
对我来说,这是一种理想的处理方式,但是它确实需要我们重构页面的布局方式。 对于界面复杂点的,这可能是一项艰巨的任务。
当我们之一次定义问题时:
我们可以让子组件填充父组件的插槽吗
但实际上,这个问题与props没有任何关系。 更简单地说,它是关于使子组件控制在其自己的子树之外渲染的内容。
我们可以这样表述问题
组件控制在其子组件之外渲染的内容的更佳 *** 是什么?
通过这个镜头检查我们提出的每个解决方案,都会为我们提供一个有趣的新视角。
向父组件发出事件
数据流经组件树的唯一途径是使用 props。 而向上通信的 *** 是使用事件。这意味着,如果要让子组件与父组件进行通信,我们需要使用事件来实现。
静态配置
只是将必要的信息提供给其他组件,而不是主动地要求另一个组件做事情。
传送门
组件无法控制其子树之外的内容。这里的每个 *** 都是让另一个组件执行我们的命令并控制我们真正感兴趣的元素不同的方式。
在这方面,使用 portal 更好的原因是它们允许我们将所有这些通信逻辑封装到单独的组件中。
提升状态
提升状态是一种比我们前面看到的3种更简单、更强大的技术,这里我们的主要限制是我们想要控制的内容在子组件之外。
最简单的解决 *** 是:
提升状态以及操纵该状态的逻辑,使我们可以拥有更大范围的组件,并将目标元素包含在该组件中。如果可以这样做,这是解决此特定问题以及所有相关问题的最简单 *** 。
请记住,这并不一定意味着要提升整个组件。 你也可以重构你的应用程序,以将逻辑移到组件树中更高的组件中。
如果熟悉软件工程设计模式的人可能已经注意到,我们在这里所做的是依赖注入,这是我们在软件工程中已经使用了几十年的技术。
它的用途之一是编写易于配置的代码。在我们的例子中,我们在使用的每个Page中以不同的方式配置Layout组件。
当调换Page和Layout组件时,我们正在执行所谓的控件反转。
在基于组件的框架中,父组件控制子组件的操作,因此我们选择让Page来控制Layout组件,而不是由Layout组件控制Page。
为了做到这一点,我们使用插槽为Layout组件提供完成任务所需的内容。
正如我们所看到的,使用依赖注入可以使我们的代码更加模块化和易于配置。
我们讨论了解决这个问题的4种不同 *** ,展示了每种 *** 的优缺点。然后我们更进一步,将问题转化为一个更一般的问题,即控制组件子树之外的内容。
、提升状态和依赖项注入是两个非常有用的模式。它们是我们武器库中更好的工具,因为它们可以应用于无数的软件开发问题。
但最重要的是,希望你还能学会:
通过使用一些常见的软件模式,将一个丑陋解决方案的问题转变成一个非常优雅的问题。许多其他的问题都可以用这种 *** 解决,即把一个丑陋的、复杂的问题转化成一个更简单、更容易解决的问题。
原文:
链接:
Babel 是一个通用的多功能 JavaScript 编译器,但与一般编译器不同的是它只是把同种语言的高版本规则转换为低版本规则,而不是输出另一种低级机器可识别的代码,并且在依赖不同的拓展插件下可用于不同形式的静态分析。(静态分析:指在不需要执行代码的前提下对代码进行分析以及相应处理的一个过程,主要应用于语法检查、编译、代码高亮、代码转换、优化、压缩等等)
安 *** abel
创建babel.config.js
export导出/暴露
import导入
使用npx执行js文件
webpack基本使用
设置webpack的打包入口/出口 ( 默认会将dist/main.js 作为默认的打包输出js文件 )
设置webpack的自动打包
配置html-webpack-plugin
因为自动打包每次都要访问 还有找到对应的index.html,比较繁琐。所以配置html-webpack-plugin 后访问 可以直接打开html文件。
配置自动打包相关参数 (自动打包后vscode可以直接弹出页面)
webpack中的加载器
通过loader打包非js模块:默认情况下,webpack只能打包js文件,如果想要打包非js文件,需要调用loader加载器才能打包 loader加载器包含:
1).less-loader
2).sass-loader
3).url-loader:打包处理css中与url路径有关的文件
4).babel-loader:处理高级js语法的加载器
5).postcss-loader
6).css-loader,style-loader
安装style-loader,css-loader来处理样式文件
没有安装前用webpack打包css文件会报错!
安装less,less-loader处理less文件
安装sass-loader,node-sass处理less文件
安装post-css自动添加css的兼容性前缀(-ie-,-webkit-),即自动给那些有兼容性问题的样式自动加前缀
打包样式表中的图片以及字体文件
在样式表css中有时候会设置背景图片和设置字体文件,一样需要loader进行处理使用url-loader和file-loader来处理打包图片文件以及字体文件
打包js文件中的高级语法
在编写js的时候,有时候我们会使用高版本的js语法,有可能这些高版本的语法不被兼容,我们需要将之打包为兼容性的js代码,所以需要安 *** abel系列的包
.vue单文件组件
传统vue组件的缺陷: 全局定义的组件不能重名,字符串模板缺乏语法高亮,不支持css(当html和js组件化时,css没有参与其中) 没有构建步骤限制,只能使用H5和ES5,不能使用预处理器(babel)
解决方案: 使用Vue单文件组件,每个单文件组件的后缀名都是.vue 每一个Vue单文件组件都由三部分组成
1).template组件组成的模板区域
2).script组成的业务逻辑区域
3).style样式区域
配置.vue文件的加载器
在webpack中使用vue
使用webpack打包发布项目
Vue脚手架 Vue脚手架可以快速生成Vue项目基础的架构。
使用命令创建Vue项目
基于ui界面创建Vue项目
基于2.x的旧模板,创建Vue项目
分析Vue脚手架生成的项目结构
node_modules:依赖包目录
public:静态资源目录
src:源码目录
src/assets:资源目录
src/components:组件目录
src/views:视图组件目录
src/App.vue:根组件
src/main.js:入口js
src/router.js:路由js
babel.config.js:babel配置文件
Vue脚手架的自定义配置
通过 package.json 进行配置 [不推荐使用]
通过单独的配置文件进行配置,创建vue.config.js
Element-UI的基本使用
基于图形化界面自动安装
链接:
1.升级到4.0之后未能正常使用
处理:npm i webpack webpack-cli webpack-dev-server webpack-merge -D
2. Error: Plugin could not be registered at 'html-webpack-plugin-before-html-processing'. Hook was not found.
处理:由于html-webpack-plugin和webpack4.0未匹配,升级html-webpack-plugin插件
3. TypeError: Cannot read property 'vue' of undefine
处理:由于vue-loader和webpack4.0未匹配,需要升级vue-loader, npm i vue-loader -D,
并且修改配置build/webpack.base.conf.js,加入
4. Uncaught TypeError: Cannot assign to read only property 'exports' of object ‘#
解决:修改配置build/webpack.base.conf.js
把这段注释//include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
加入这段:include: [resolve('src'), resolve('test')]
链接:
无论是工作或者面试中,this指向问题是经常遇到的。所以这篇文章把常见的指向问题列出来给大家,避免踩坑。首先我们要知道,在函数中this到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了,也就是说,this的指向完全取决于函数调用的位置。因为this的取值是作用域环境的一部分,每次调用函数,都会在不同的作用域环境。
1:全局环境中
在浏览器环境严格模式中(区别于node),this默认指向window。立即执行函数,默认的定时器等函数,this也是指向window。
2:对象函数中
如果函数作为对象的一个属性被调用时,函数中的this指向该对象。
首先调用fn()为什么结果为10,因为新建了变量fn,相当于fn=function(){ console.log(this.x)}, 函数中this默认指向window,故输出为10。而 obj.f() 中this 指向obj,所以this.x=obj.x, 输出结果为20。
3:构造函数中
构造函数创建的实例的属性指向构造函数的prototype。
4:箭头函数中
箭头函数的this是在定义函数时绑定的,不是在执行过程中绑定的,箭头函数中的this取决于该函数被创建时的作用域环境。
setTimeout默认指向window,但是,在箭头函数中,this的作用域环境在man内,故this指向了man。也就是说此时的this可以忽略外围包裹的setTimeout定时器函数,看上一层及的作用域。
5:dom节点中
特别在是react中jsx语法中,我们通常要改变dom的this指向,不然获取不到指定的执函数。所以通常需要在函数声明使用bind绑定事件。
本文涉及到的案例是相对比较常见,如果想更加深入的理解this,可以参考github上的一篇文章 传送门
原文:
链接:
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
html5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
socket是在http基础上,对http进行升级,让连接用socket来完成。
一个典型的Websocket握手请求如下:
客户端请求
服务器回应
Connection 必须设置 Upgrade,表示客户端希望连接升级。Upgrade 字段必须设置 Websocket,表示希望升级到 Websocket 协议。Sec-WebSocket-Key 是随机的字符串,服务器端会用这些数据来构造出一个 SHA-1 的信息摘要。把 “Sec-WebSocket-Key” 加上一个特殊字符串 “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,然后计算 SHA-1 摘要,之后进行 BASE-64 编码,将结果做为 “Sec-WebSocket-Accept” 头的值,返回给客户端。如此操作,可以尽量避免普通 HTTP 请求被误认为 Websocket 协议。Sec-WebSocket-Version 表示支持的 Websocket 版本。RFC6455 要求使用的版本是 13,之前草案的版本均应当弃用。Origin 字段是可选的,通常用来表示在浏览器中发起此 Websocket 连接所在的页面,类似于 Referer。但是,与 Referer 不同的是,Origin 只包含了协议和主机名称。其他一些定义在 HTTP 协议中的字段,如 Cookie 等,也可以在 Websocket 中使用。
原生socket较复杂,一般都通过框架来使用websocket,socket.io封装了websocket。
socket.io文档
安装:
服务端创建服务端IO对象 io=require('socket.io')(httpServer);监视连接 io.on('connection',function(socket))通过emit 、 onon(name,function(data){}) :绑定监听emit(name,data): 发送消息
客户端引入客户端socket.io-client 库io(url) 连接服务端,得到socket对象(如果不指定url,将会连接默认主机地址)通过emit,on实现通信
上面服务端如果使用socket.emit 实现的是服务端和客户端的一对一发送数据,那么如何将服务端收到的数据发送给其他用户,来实现聊天室效果呢?
这里就需要io.emit 发送数据给当前连接此服务器的所有用户。
服务端
客户端
接下来根据官网的方案进行优化
Here are some ideas to improve the application:
Broadcast a message to connected users when someone connects or disconnects.
在服务端,通过io.on('connection') 监听用户连接。
socket.on('disconnect') 监听用户断开。
通过回调向客户端传递提示信息。 socket.id 可以用来独一无二的表示当前会话的客户端id
Add support for nicknames.
Don’t send the same message to the user that sent it himself. Instead, append the message directly as soon as he presses enter.
通过监听keydown事件,判定 event.which 的值是否为 13(enter的Unicode码是13)。如果是则emit 消息
Add “{user} is typing” functionality.
通过监听input事件,来更新type信息
Show who’s online.Add private messaging.
更多案例在官方仓库中查找
namespace允许用户去分配路径,这个的好处是可以减少TCP资源,同时进行通道隔离
默认的namespace是/ 通过 of *** 可以自定义namespace
对于每个namespace,都可以定义多个频道,也就是room,用户可以 join 和 left
有的时候需要将数据从一个进程发送到令一个进程,可以通过redis adapter
原文:
链接:
jsonp是一种跨域通信的手段
原理:
事先定义一个用于获取跨域响应数据的回调函数,并通过没有同源策略限制的script标签发起一个请求(将回调函数的名称放到这个请求的query参数里),然后服务端返回这个回调函数的执行,并将需要响应的数据放到回调函数的参数里,前端的script标签请求到这个执行的回调函数后会立马执行,于是就拿到了执行的响应数据。
缺点:
jsONP只能发起GET请求
之一步:设定一个script标签
第二步:callback定义了一个函数名,而远程服务端通过调用指定的函数并传入参数来实现传递参数,将function(response)传递回客户端
第三步:客户端接收到返回的js脚本,开始解析和执行function(response)
来看一个一个简单的jsonp实现,其实就是拼接url,然后将动态添加一个script元素到头部。
前端js示例:
服务器端代码:
可靠的jsonp实例:
使用示例:
CSRF攻击
前端构造一个恶意页面,请求 *** ONP接口,收集服务端的敏感信息。如果 *** ONP接口还涉及一些敏感操作或信息(比如登录、删除等操作),那就更不安全了。
解决 *** :验证 *** ONP的调用来源(Referer),服务端判断Referer是否是白名单,或者部署随机Token来防御。
XSS漏洞
不严谨的 content-type导致的 XSS 漏洞,想象一下 *** ONP 就是你请求 然后返回 douniwan({ data }),那假如请求 alert(1) 不就返回 alert(1)({ data })了吗,如果没有严格定义好 Content-Type( Content-Type: application/json ),再加上没有过滤 callback 参数,直接当 html 解析了,就是一个 *** 裸的 XSS 了。
解决 *** :严格定义 Content-Type: application/json,然后严格过滤 callback 后的参数并且限制长度(进行字符转义,例如换成>)等,这样返回的脚本内容会变成文本格式,脚本将不会执行。
服务器被黑,返回一串恶意执行的代码
可以将执行的代码转发到服务端进行校验 *** ONP内容校验,再返回校验结果。
链接:
JavaScript中的变量提升说的是在程序中可以在变量声明之前就进行使用:
可以看到,在变量a声明之前我们可以正常调用a,代码的实际的表现更像是这样的:
但实际上,代码并没有被改变,上面的代码只是我们猜测的,其实JavaScript引擎在执行这几行代码的时候并没有移动或是改变代码的结果。到底发生了什么呢?
变量提升
在代码的编译期间,即代码真正执行的瞬息之间,引擎会将代码块中所有的变量声明和函数声明都记录下来。这些函数声明和变量声明都会被记录在一个名为词法环境的数据结构中。词法环境是Javascript引擎中一种记录变量和函数声明的数据结构,它会被直接保存在内存中。所以,上面的console.log(a)可以正常执行。
什么是词法环境
所谓词法环境就是一种标识符—变量映射的结构(这里的标识符指的是变量/函数的名字,变量是对实际对象[包含函数和数组类型的对象]或基础数据类型的引用)。
简单地说,词法环境是Javascript引擎用来存储变量和对象引用的地方。
词法环境的结构用伪代码表示如下:
关于词法环境更多的了解可以看博主之前的译文:理解Javascript中的执行上下文和执行栈。
了解了词法环境接下来让我依次看下使用var,const,let,function,class声明的变量或函数的情况。
function声明提升
我们已经知道了,函数声明会在编译阶段就会被记录在词法环境中并且保存在内存中,因此我们可以在函数进行实际声明之前对该函数进行访问。
上面函数声明保存在词法环境中像下面这样:
所以在代码执行阶段,当Javascript引擎碰到helloWorld()这行代码,会在词法环境中寻找,然后找到这个函数并执行它。
函数表达式
注意,只有函数声明才会被直接提升,使用函数表达式声明的函数不会被提升,看下面代码:
如上,代码报错了。使用var声明的helloWorld是个变量,并不是函数,Javascript引擎只会把它当成普通的变量来处理,而不会在词法环境中给它赋值。
保存在词法环境中像下面这样:
上面的代码要想可以正常运行改写如下即可:
var变量提升
看一个使用var声明变量的例子:
如果按上面function函数声明的方式去理解,这里应该打印3,但实际上打印了undefined。
请记住:所谓的声明提升只是在编译阶段Javascript引擎将函数声明和变量声明存储在词法环境中,但不会给它们赋值。等到了执行阶段,真正执行到赋值那一行的时候,词法环境才会更新。
但上面的代码为什么打印了undefined呢?
Javascript引擎会在编译阶段将使用var声明的变量保存在词法环境中,并将它初始化为undefined。到了执行阶段,等执行到赋值那一行代码的时候,词法环境中变量的值才会被更新。
所以上面代码的词法环境初始化像下面这样:
这也解释了为什么前面使用函数表达式声明的函数执行会报错,为什么上面的代码会打印undefined。当代码执行到var a=3;这行代码的时候,词法环境中a的值就会被更新,此时词法环境会被更新如下:
let和const变量提升
看一个使用let声明变量的例子:
输出:
再看一个使用const声明变量的例子:
输出:
和var不同,相同结构的代码换成let或是const都直接报错了。
难道使用let和const声明的变量不存在变量提升的情况么?
实际上,在Javascript中所有声明的变量(var,const,let,function,class)都存在变量提升的情况。使用var声明的变量,在词法环境中会被初始化为undefined,但用let和const声明的变量并不会被初始化。
使用let和const声明的变量只有在执行到赋值那行代码的时候才会真正给他赋值,这也意味着在执行到变量声明的那行代码之前访问那个变量都会报错,这就是我们常说的暂时性死区(TDZ)。即在变量声明之前都不能对变量进行访问。
当执行到变量声明的那一行的时候,但是仍然没有赋值,那么使用let声明的变量就会被初始化为undefined;使用const声明的变量就会报错; 看实际的例子:
在代码编译阶段,Javascript引擎会把变量a存储在词法环境中,并把a保持在未初始化的状态。此时词法环境像下面这样:
此时如果尝试访问变量a或是b,Javascript引擎会在词法环境中找到该变量,但此时变量处于未初始化的状态,因此会抛出一个引用错误。
然后在执行阶段,Javascript引擎执行到赋值(专业点叫词法绑定)那一行的时候,会评估被赋值的值,如果没有被赋值,只是简单的声明,此时就会给let声明的变量赋值为undefined;此时词法环境像下面这样:
当执行到a=5这一行的时候,词法环境再次更新:
再看下使用const声明代码的情况:
输出:
上面代码直接报错,a的值也没有打印,直接报错,其实是代码在编译阶段就已经报错了,压根没执行到console.log(a);这一行代码。
注意:在函数中,只要是能在变量声明之后引用该变量就不会报错。
什么意思呢?看如下代码:
但下面代码就会报错:
这里报错的原因需要结合Javascript中的执行上下文和执行栈才能理解,因为此时全局执行上下文中词法环境中保存的变量a处于未初始化的状态,调用foo函数,创建了一个函数执行上下文,然后函数foo执行过程对全局执行上下文的变量a进行访问,但a还处于未初始化的状态(此时let a=20还没有执行)。因此报错。
这里需要纠正一个误区,就是let和const声明的变量只有暂时性死区,不存在变量提升,其实是不对的,举个例子证明理解一下:
上面的代码会被报错:
如果不存在变量提升,理论上不会报错才对。
class声明提升
与let、const类似,使用class声明的类也会被提升,然后这个类声明会被保存在词法环境中但处于未初始化的状态,直到执行到变量赋值那一行代码,才会被初始化。另外,class声明的类一样存在暂时性死区(TDZ)。看例子:
打印:
改写如下就可以正常运行了:
上面代码在编译阶段,词法环境像这样:
然后执行到class声明的那一行代码,此时词法环境像下面这样:
注意:使用构造函数实例化对象并不会报错:
上面代码正常运行。
类表达式
和函数表达式一样,类表达式也一样会被提升,比如:
报错:
要想正常运行,改写如下即可:
也就是说不管是函数表达式还是类表达式遵循的规则和变量声明是一样的。
结论
不管是var,const,let,function,class声明的变量还是函数都存在变量提升的情况。正确理解变量提升有助于我们写更好的代码。整个变量提升的情况总结如下:
var:存在变量提升,在编译阶段会被初始化为undefined;let: 存在变量提升,存在暂时性死区(TDZ),执行阶段,如果没赋值,则初始化为undefined;const: 存在变量提升,存在暂时性死区(TDZ),如果没有赋值,编译阶段就会报错;function:存在变量提升,在变量声明之前可以访问并执行;class: 存在变量提升,存在暂时性死区(TDZ);
链接:
新开发了一个vue-cli项目,想通过手机查看效果,发现访问不到,ip地址和端口号都没错但是手机访问不到,在本机电脑浏览器输入ip端口号一样访问不到,只能通过localhost:8080访问到,同一局域网下其他的手机和电脑并不能通过ip地址访问调试
循环遍历是写程序很频繁的操作,JavaScript 提供了很多 *** 来实现。这篇文章将分别总结数组和对象的遍历 *** ,新手可以通过本文串联起学过的知识。
*** 一:for 循环
for 循环是使用最多,也是性能优化更好的一种遍历方式。
同样常规的循环类型还有 while 循环和 do/while 循环。
它们之间的区别在于,for 循环预先知道循环次数,while 循环不知道循环次数,do/while 至少会循环次数。
*** 二:for-of 遍历
for-of 是 ES6 新增的语法。它直接遍历值,而不是数组下标(或对象属性)。
实际上,for-of 语句不仅可以循环遍历数组对象。
还可以迭代 Array、Map、Set、String 等对象。
for-of 的工作原理是,向循环对象请求一个迭代器对象,然后通过迭代器对象的next() *** 来获得返回值。
数组内置了 @@iterator,@@iterator不是迭代器,而是返回一个迭代器对象的函数。
上面代码中,value 表示当前遍历值,done 是布尔值,表示是否还有可以遍历的值。
需要注意的是,普通对象没有内置@@iterator,所以无法使用 for-of 遍历。
这么做的原因很复杂,简单来说,就是为了避免影响未来的对象类型。
不过,我们可以通过Object.defineProperty(...)给对象定义@@iterator。
详细可以通过这里了解。
*** 三:数组 ***
为了适应不同方式的遍历,JavaScript 内置了许多的数组 *** 。
例如比较常用的forEach() *** ,写起来,可以让代码更简洁。
map() ***
filter() ***
reduce() *** 是 ES5 新增,专为下面这种累加操作的设计的。
实际能做的事情远比这要丰富,本文只是简单介绍基本用法,详细可以查看本文。
every() *** 用于检测数组元素是否全部符合指定条件。
它通常和下面的some() *** 放在一起理解。
some() *** 用于检测数组是否存在一个符合指定条件的元素。
下面的例子是检测数组元素是否存在 Number 类型。
对象的遍历相对麻烦一些。
有两种方式可以实现对象的遍历,一种是直接使用 for-in 循环;另一方式,是将对象转换成数组,再进行遍历。
*** 一:for-in 循环
for-in 专门用于遍历对象的可枚举属性,包括 prototype 原型链上的属性,因此性能会比较差。
什么是可枚举属性?
从名字上可以看出,就是该属性会出现在对象的迭代(枚举)中,比如 for-in 循环中。
*** 二:Object.keys() 和 Object.getOwnPropertyNames()
Object.key()会返回一个数组,包含所有可枚举属性;Object.getOwnPropertyNames()也会返回一个数组,包含所有元素,不管是否可枚举。
需要说明的是,两者都只查找对象的自定义属性。
此外,还可以通过Reflect.ownKeys(obj) *** 来遍历。
它返回一个数组,包含对象自定义的属性,不管属性名是 Symbol 还是字符串,也不管是否可枚举。
链接:
将Web安全问题按照发生的区域来分类,发生在浏览器、Web页面中的安全问题就是前端安全问题。
同源:URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。
URL是否同源原因
是
是
否协议不同
否端口不同
否域名不同
浏览器的同源策略,限制了来自不同源的document或脚本,对当前document读取或设置某些属性。从一个域上加载的脚本不允许访问另外一个域的文档属性。
如果没有同源限制存在,浏览器中的cookie等其他数据可以任意读取,不同域下DOM可以任意操作,ajax可以任意请求。如果浏览了恶意网站那么就会泄漏这些隐私数据
在浏览器中,、、、等标签都可以加载跨域资源,而不受同源限制。
这些带src属性的标签每次加载时,实际上是由浏览器发起了一次GET请求。不同于XMLHttpRequest的是,通过src属性加载的资源,浏览器限制了JavaScript的权限,使其不能读、写返回的内容。
XSS,即Cross Site Script(跨站脚本攻击);为了和层叠样式表(Cascading Style Sheet)做出区分,在安全领域叫做 XSS。
XSS 攻击是指攻击者在网站上注入恶意的客户端代码,利用恶意脚本对客户端网页进行篡改,从而在用户浏览网页时,对用户浏览器进行控制或者获取用户隐私数据的一种攻击方式。有很多种方式进行 XSS 攻击,但它们的共同点为:将一些隐私数据像cookie、session发送给攻击者,将受害者重定向到一个由攻击者控制的网站,在受害者的机器上进行一些恶意操作。
攻击方式反射型XSS
恶意代码并没有保存在目标网站,通过引诱用户点击一个链接到目标网站的恶意链接来实施攻击。
攻击流程:
A给B发送一个恶意构造的URLB点击URL后跳转到具有漏洞的HTML页面HTML页面在B浏览器中执行JavaScript,可以执行B所具有权限下的命令存储型XSS
恶意代码被保存到目标网站的服务器中,这种攻击具有较强的稳定性和持久性,比较常见场景是在博客,论坛、OA、CRM等社交网站上。
攻击流程:
攻击者提交一条包含XSS代码的留言或其他数据到数据库当目标用户查询时,XSS的内容会从服务器解析之后加载出来浏览器将恶意代码当作正常脚本解析执行,可以执行浏览器所具有权限下的命令DOM Based XSS
基于DOM的XSS攻击是指通过恶意脚本修改页面的DOM结构,是纯粹发生在客户端的攻击。DOM型XSS攻击中,取出和执行恶意代码由浏览器端完成,属于前端JavaScript自身的安全漏洞。
攻击流程:
A给B发送一个恶意构造的URLB点击URL后HTML页面获取攻击性的代码,如通过location.hash获取的参数等攻击性代码当作HTML代码写入页面HTML页面在B浏览器中执行JavaScript,可以执行B所具有权限下的命令防范手段输入检查
在源头控制,把用户输入的一些不合法的东西都过滤或者编码掉,从而保证安全性。如移除用户提交的的DOM属性如onerror,移除用户上传的节点,,,节点等。
一般业务中是对客户端和服务端中同时进行输入检查。
输出检查
利用转义库对 HTML 模板各处节点进行充分的转义。
使用HttpOnly
通过设置HttpOnly,浏览器可以禁止页面的JavaScript访问带有HttpOnly属性的Cookie。它的目的并非是为了对抗XSS,而是对抗XSS之后的Cookie劫持攻击。
Cookie的使用过程:
浏览器向服务器发起请求,此时没有Cookie服务器返回Set-Cookie头,向浏览器写入Cookie在Cookie到期之前,浏览器访问该域下的所有页面,都将发送该Cookie
HttpOnly是在Set-Cookie的时候进行标记的
Set-Cookie: =[; =]
[; expires=][; domain=]
[; path=][; secure][; HttpOnly]
输入内容长度限制
对输入的内容限定合理长度,可以增加XSS攻击的难度
避免拼接HTML或者使用内联事件
前端使用拼接HTML或者内联事件的情况比较危险,建议替换为createElement、setAttribute及addEventListener的实现 *** ,或者采用成熟的框架进行渲染,如vue/react等
开启CSP网页安全政策(Content Security Policy)
一种由开发者定义的安全性政策申明,通过CSP所约束的责任指定可信的内容来源,(内容可以是指脚本、图片、style 等远程资源)。
CSP 的实质就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行,等同于提供白名单。
开启方式:
通过HTTP头信息的Content-Security-Policy字段在网页中设置标签
跨站请求伪造攻击,原理就是攻击者构造出一个后端请求地址,诱导用户点击或者通过某些途径自动发起请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,冒充用户执行某些操作。
攻击流程被攻击者登录A站点,并保留了登陆凭证攻击者诱使被攻击者访问B站点B站点向A站点发起请求,浏览器会默认携带A站点的CookieA站点接收请求后会对其进行验证,而且会误认为是被攻击者发起的请求,同时以被攻击者的身份执行相应的操作攻击方式GET类型
一般是利用标签等发起
在被攻击者访问页面时,浏览器会自动向src指向的地址发出请求
POST类型
通常是构造一个自动提交的表单在页面上,模拟用户完成了一次POST操作
链接类型
通常是需要诱骗用户点击才会触发
攻击特点攻击一般发生在第三方站点,被攻击站点无法防止攻击发生攻击手段为冒充受害者提交操作,而非直接窃取数据攻击过程中攻击者并不能获取到用户的登陆凭证,而只是冒充防范手段验证码
通过增加网站A的验证手段,例如增加图形验证码或短信验证码等等,只有通过验证的请求才算合法。但是这种方案拥有两个局限性,一个是增加开发成本,另外一个是降低用户体验。
验证Referer
根据 HTTP 协议,在 HTTP 头中有一个字段叫Referer,它记录了该 HTTP 请求的来源地址。通过验证Referer,可以检查请求是否来自合法的"源"。
验证Token
服务端随机生成token,保存在服务端session中,同时保存到客户端中,客户端发送请求时,把token带到HTTP请求头或参数中,服务端接收到请求,验证请求中的token与session中的是否一致。如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。
在一个Web页面下隐藏了一个透明的iframe(opacity:0),用外层假页面诱导用户点击,实际上是在隐藏的frame上触发了点击事件进行一些用户不知情的操作。
攻击流程攻击者构造一个诱导用户点击的内容,将页面放入到利用z-index和opacity将叠加到实际页面上方并透明化受害者访问到欺骗页面后,实际看到的是诱使点击的内容,点击之后则是有害页面攻击方式盗取用户资金获得用户敏感信息与XSS或者CSRF相配合,诱骗用户点击恶意链接防范手段设置X-FRAME-OPTIONS
服务器端可设置HTTP头X-Frame-Options:DENY来让浏览器主动禁止内嵌,但是这种方式需要结合HTTPS来实现,因为HTTP不可靠,容易被窃听篡改内容
链接:
问题像缝纫机上的丝线
杂乱而复杂
需要慢慢捋清
才能找到线的源头
“在么?”
“我使用XX框架启动报错,你帮忙看下?”
“我代码报错了,谁能帮我看下?”
“我发现一个诡异的问题”
生活中我们经常可以看到一些无效的问题,在开发运维工作中,经常可以看上面这些提问。比较有意思的例子是,工作中突然有个人找你,就说了句“在么?”。等你方便时回复“在,什么问题?”的时候,对方没回应。过了一会儿,对方又冒了一句“还在么?”。有一种像 TCP 连接需要做三次握手确认,这种交流是特别低效的。低效的问题有很多种,不能让对方快速清晰知道问题背景、具体问题的都算得上无效问题。然而在自己身上也有类似的经历。
这周和师兄联调一个接口,发现了一些数据不符合预期。于是我没想太多,就自然而然地将页面数据截图发给他,并且红色框框圈出问题的数据,直接发给他。然后说了句, “你这个数据有些问题,辛苦帮忙看下哈”。
我 以为 大家对项目的整体链路,整体设计都很清晰,只要轻轻点下问题就可以。结果一个简单的问题,却讨论半天,解释问题是什么。最后师兄抛出了一句,“ 你下次说问题时注意细节,建议说明背景、期望得到什么结果、实际是什么 ”。那一瞬间对自己冲击很大,是得好好思考下自己的反馈问题方式,学习如何能够高效表达一个问题,提高效率。
在平时生活或工作中,我们也经常能遇到别人向你寻求帮助或提问,或在遇到问题时也会让身边相关的人帮忙。社会合作体系导致我们必然会和身边的人共同协作完成工作,也有越来越多的问题需要反馈、沟通。大家时间都很忙,如果提出一个无效的问题往往耗费大家时间,影响效率。本文就说说自己的一些总结,希望对大家都有帮助。
先自己排查,上网查询。一般我们生活中或开发中遇到的很多问题都是别人经历过的,而且网上资源丰富。通过搜索引擎工具,大部分问题我们都可以查到,避免问身边人一些低效的问题。比如当自己想要投资理财,买基金,于是问专业人士“基金是什么,基金与活期的区别是什么?”。
自己排查问题的过程可以提高自己解决问题能力,正如一些InfoQ 的大神说的一样,问题见多了你就成为大神。见多了,积累多了你的能力就上去了。就像古代的一些名将,都是历经大大小小战役以后积累丰富经验。
另外,自己排查问题,明确背景、明确问题的本质,而不是只看到问题的表象。将反馈的问题提前定位,捋清楚, 看是否真的是对方的问题。避免查到最后是自己问题,却反馈给对方,出现尴尬的局面。
简单提炼问题的核心,通过简单的一句话能够描述出问题的核心和本质。根据专业领域不同,带上专业领域相关关键词,能够让对方一眼大致知道问题类型是什么,问题是什么。避免用了一大段详细描述以后,对方还不知道是什么问题。
类似一篇文章的核心思想、作文标题,能够一看就看出问题。避免使用“在么”, “系统起不来了” 等非常抽象的词描述。以我的例子,可以概括为“xx 接口返回的数据结果不符合预期”。这个也类似一个问题的代号,后续只要说这个标题大家都知道是哪个问题,方便沟通。
下面就是需要清晰描述具体问题是什么,更好包含期望达到的目标是什么,以及目前遇到的现状。例如:
问题:xx 接口调用时返回的数据结果中的总数和成功数字不符合预期。
期望 :结果中的总数应该大于成功数量。成功数量是实际执行成功的数量,不含有失败等数量。总数包含所有的数值。
现状: 总数小于了成功数量。
该过程主要让问题具体化,让对方更加明确问题所在。如果可能更好是加上相关截图、日志,证明事实真的是这样。避免出现质量同学和开发同学反馈问题时,开发同学习惯性用“我这边运行好好的,肯定是你使用有问题”来辩驳。
一个问题能够复现,就解决了90%。发现问题时,将问题出现的场景、条件捋清楚。场景是说明通过哪些步骤、哪些场合发生问题,通过什么方式能将问题复现。这些方便对方定位问题,提高排查效率。
有些问题是在极端条件下才能产生,开发平时也注意不到。如果仅仅是反馈问题,在他的认知里不可能会出现这个错误,他就会反驳你。所以场景和复现手段是非常必要的,一个程序会因为不同变量做出不同反应,这引起问题的变量就是场景。 描述的过程尽可能的具体,避免使用你和对方理解不同的概念,导致歧义 。
尽可能多地补充问题信息,能够让对方快速排查到问题。比如操作系统、操作系统版本、框架版本、具体排查的日志等。也可以将自己已经排查的点和相关日志贴出,说明目前阻塞的点在哪里,怀疑可能出错的地方。补充更多更详细的信息,也是避免双方理解不同导致的误会,影响沟通效率。
每个领域不同,补充的信息也就不同。比如注册中心相关问题,需要说明哪个订阅者无法订阅到哪个发布者的xxx服务。所以可以提供的信息如下:
服务:xxxx
发布者:xxxx , IP xxx.xxx.xxx.xxx
订阅者:xxxx , IP xxx.xxx.xxx.xxx
提问前更好自己过一遍,看有哪里描述不清晰的,哪里表达不通顺,以及是否可以通过现有的这套描述可以让对方很清晰的知道问题所在。
问题:XXX 版本的 XXX 接口调用返回的数据不符合预期。
期望 :xxx 接口的执行总数应该大于执行成功数量。执行成功数量应该只统计成功执行的数值不能包含其他值。
现状 :接口返回的成功数量大于执行总数;成功数量也不是具体的成功数值。
场景 :
xxxx
xxxx
xxxx
补充 :
客户端机器 ip xxxx
服务端机器 ip xxxx
请求流水号 xxxx
我排查的日志详情 xxx
最后对方帮你把问题解决完了,不要忘了说声感谢。
原文:
链接:
Hershell是一款功能强大的跨平台反向Shell生成器,该工具使用Go语言开发,基于TCP反向Shell实现其功能。该工具使用了TLS来保障数据通讯的安全性,并且提供了证书公共密钥指纹绑定功能来防止通信数据被拦截。
Hershell的当前版本支持以下操作系统:
虽然Meterpreter Payload有时也能用,但是这种 *** 很容易被反病毒产品检测到。因此,Hershell便应运而生,它可以给我们提供一个基于TCP的反向Shell,而且能够支持各种不同的操作系统平台。
Hershell使用Go语言开发,我们首先需要按照Go官方手册【 点我获取 】在我们的设备上完成Go环境的搭建,并设置好$GOPATH环境变量。
接下来,运行下列命令来获取项目源码:
在构建Payload时,我们可以选择使用已提供的Makefile来完成构建。此时,我们需要设置以下环境变量:
关于GOOS和GOARCH变量的设置,可以参考这篇【 文档 】。
当然了,我们也在Makefile中提供了一些可供参考的变量值:
针对上述列表中的目标平台,我们还需要设置LHOST和LPORT这两个环境变量。
代码开始执行之后,工具将给我们提供一个远程Shell,它是一个自定义的交互式Shell,允许我们通过Windows上的cmd.exe或Unix设备中的/bin/sh来执行系统命令。
Hershell支持的部分特定命令如下表所示:
run_shell : 获取系统Shell
inject : 向相同进程内存中注入一个shellcode(Base64编码),并执行代码。
meterpreter [tcp|http|https] IP:PORT :与多个处理器建立连接并从Metasploit获取第二阶段的反向TCP、HTTP或HTTPS Meterpreter,然后在内存中执行Shellcode(该功能目前仅支持Windows平台)。
exit : 退出程序
首先,我们需要使用下面的命令生成一个有效的证书:
我们可以使用各种工具来处理传入的连接,比如说:
下面是ncat的使用样例:
注意:目前该功能仅支持在Windows平台上使用。
该工具的Meterpreter使用场景目前仅支持下列Payload:
当你选择使用某个Payload之后,别忘了选择正确的传输端口(tcp、http或https)。
MeterpreterHandler使用样例如下:
接下来,在hershell中,使用meterpreter命令:
此时,我们将能够在msfconsole中获取到新的Meterpreter会话:
Hershell:【 GitHub传送门 】
原文
链接:
javascript中退出循环的 *** : *** 一、使用break语句退出循环。 *** 二、使用continue语句退出循环。 *** 三、使用return语句退出循环。break语句会使运行的程序立刻退出包含在最内层的循环或者退出一个switch语句。
Angular是一个基于TypeScript的开源Web应用程序框架,用于在html和JavaScript中构建Web应用程序。
Angular诞生于2009年,由Misko Hevery 等人创建,后为Google所收购,由Google维护。它最初是作为Google的一个项目启动的,但现在它是开源框架。
Angularjs是为了克服html在构建应用上的不足而设计的。HTML是一门很好的为静态文本展示设计的声明式语言,但要构建WEB应用的话它就显得乏力了。
Angularjs使用了不同的 *** ,它尝试去补足HTML本身在构建应用方面的缺陷。Angular *** 通过使用我们称为指令(directives)的结构,让浏览器能够识别新的语法。例如:
● 使用双大括号{{}}语法进行数据绑定;
● 使用DOM控制结构来实现迭代或者隐藏DOM片段;
● 支持表单和表单的验证;
● 能将逻辑代码关联到相关的DOM元素上;
● 能将HTML分组成可重用的组件。
链接:
Angular是一个开源框架,一个互联网应用程序框架,一个强大的前端框架,用于开发动态Web应用程序。那么Angular有哪些特点?
Angular的特点
1、数据的双向绑定
这可能是其最激动人心的特性吧,view层的数据和model层的数据是双向绑定的,其中之一发生更改,另一方会随之变化,这不用你写任何代码!
2、代码模块化,每个模块的代码独立拥有自己的作用域,model,controller等。
3、强大的directive可以将很多功能封装成html的tag,属性或者注释等,这大大美化了html的结构,增强了可阅读性。
4、依赖注入
依赖注入(Dependency Injection,简称DI)是一种设计模式, 指某个对象依赖的其他对象无需手工创建,只需要“吼一嗓子”,则此对象在创建时,其依赖的对象由框架来自动创建并注入进来,其实就是最少知识法则;模块中所有的service和provider两类对象,都可以根据形参名称实现DI。
将这种后端语言的设计模式赋予前端代码,这意味着前端的代码可以提高重用性和灵活性,未来的模式可能将大量操作放在客户端,服务端只提供数据来源和其他客户端无法完成的操作。
5、测试驱动开发
angularjs一开始就以此为目标,使用angular开发的应用可以很容易地进行单元测试和端对端测试,这解决了传统的js代码难以测试和维护的缺陷。
6、采用MVC模型:
Angular遵循软件工程的MVC模式,并鼓励展现,数据,和逻辑组件之间的松耦合.通过依赖注入(dependency injection),Angular为客户端的Web应用带来了传统服务端的服务,例如独立于视图的控制。 因此,后端减少了许多负担,产生了更轻的Web应用。
● Model:数据,其实就是angular变量($scope.XX);
● View:数据的呈现,Html+Directive(指令);
● Controller:操作数据,就是function,数据的增删改查;
Angular最初是作为Google的一个项目启动的,但现在它是开源框架。由于Angular框架是基于JavaScript框架构建的,因此如果用户了解JavaScript,则会更容易理解Angular。
链接:
Node.js是一个JavaScript运行环境,可以使JavaScript这类脚本语言编写出来的代码运行速度获得极大提升,那么安装后该如何卸载呢?
Windows平台下卸载nodejs
对于Windows平台来说,所有的应用程序的卸载 *** 都是一样的。
1、在【卸载程序】中卸载程序和功能
在桌面左下角单击【开始】按钮,然后选择【控制面板】,在控制面板窗口中找到【卸载程序】,单击打开。
打开后可以看到所有已经安装的程序,找到node.js,然后单击右键选择【卸载】等待一会后系统就会提示卸载完成。
2、重新启动(或者您可能会从任务管理器中杀死所有与节点相关的进程)。
3、寻找这些文件夹并删除它们(及其内容)(如果还有)。根据您安装的版本,UAC设置和CPU架构,这些可能或可能不存在:
4、检查您的%PATH%环境变量以确保没有引用Nodejs或npm存在。
5、如果仍然没有卸载,请在命令提示符下键入where node,您将看到它所在的位置 - 删除(也可能是父目录)。
6、重新启动,很好的措施。
Linux下卸载nodejs
1、先卸载 npm
2、 然后卸载Node.js
● 如果是 Ubuntu 系统并使用 apt-get 安装的,可以使用命令:
● 源文件安装的node, 卸载方式:首先cd到解压后到目录:
● mac 平台下brew安装的node(brew install node), 卸载方式:
○ 使用 brew uninstall node 命令卸载
○ 在终端下执行命令,卸载node其他相关目录
○ 执行 brew doctor 命令,查看还有哪些与node、npm相关的目录,并删除。之前因为缺少这一步骤,导致一直未完全卸载。
链接:
angular用nodejs主要是用它的npm工具包,npm里面有很多很方便的工具可以用在前端开发,例如:
● 合并js,css
● 压缩js
● 压缩图片
● 生成js的source map
● 编译 less 成css
● 运行测试unit test
● Grunt, Gulp任务管理,自动化上面所有的任务
Angular是一个开源框架的,以 JavaScript 编写的库,一个客户端的JavaScript MVC框架,用于开发动态Web应用程序。它最初是作为Google的一个项目启动的,但现在它是开源框架。
Node.js是一个基于Chrome V8引擎的 JavaScript 运行环境,一个让JavaScript运行在服务端的开发平台,它让JavaScript成为与php、Python、Perl、Ruby 等服务端语言平起平坐的脚本语言。
链接:
JavaScript中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。那么在node中全局对象是什么?
在浏览器JavaScript中,通常window是全局对象, 而Node.js中的全局对象是globa,所有全局变量(除了 global 本身以外)都是global对象的属性。在 Node.js 我们可以直接访问到global的属性,而不需要在应用中包含它。
global 最根本的作用是作为全局变量的宿主。按照 ECMAScript 的定义,满足以下条件的变量是全局变量:
● 在最外层定义的变量;
● 全局对象的属性;
● 隐式定义的变量(未定义直接赋值的变量)。
当你定义一个全局变量时,这个变量同时也会成为全局对象的属性,反之亦然。需要注 意的是,在 Node.js 中你不可能在最外层定义变量,因为所有用户代码都是属于当前模块的, 而模块本身不是最外层上下文。
注意: 更好不要使用 var 定义变量以避免引入全局变量,因为全局变量会污染命名空间,提高代码的耦合风险。
链接:
在node.js中modules(模块)与文件是一一对应的,也就是说一个node.js文件就是一个模块,文件内容可能是我们封装好的一些JavaScript *** 、 *** ON数据、编译过的C/C++拓展等,在关于node.js的误会提到过node.js的架构。其中http、fs、net等都是node.js提供的核心模块,使用C/C++实现,外部用JavaScript封装。
node.js中使用Common *** 规范实现模块功能,一个单独的文件就是一个单独的模块。通过require *** 实现模块间的依赖管理。通过require加载模块,是同步操作。
node.js的模块分类:
1、核心模块,编译二进制,加载速度最快,像 fs,http,events等。
2、文件模块,保存在硬盘上,加载速度比较慢,通过名称或路径来加载。
3、第三方模块,只指定名称则从node_modules目录下加载,查询的路径包括module.paths和全局目录。
全局目录:
windows中:环境变量NODE_PATH指定的路径。
linux中:$HOME/.node_modules和$HOME/.node_libraries目录
链接:
Node-RED是一种基于Node.js的编程工具,用于以新颖有趣的方式将硬件设备,API和在线服务连接在一起。它提供了一个基于浏览器的编辑器,可以使用调色板中的各种节点轻松地将流连接在一起,只需单击即可将其部署到运行时。
Node-Red提供基于网页的编程环境。通过拖拽已定义node到工作区并用线连接node创建数据流来实现编程。程序员通过点击‘Deploy’按钮实现一键保存并执行。程序以jsON字符串的格式保存,方便用户分享、修改。
Node-Red基于Node.js,它的执行模型和Node.js一样,充分利用其事件驱动的非阻塞模型。这使得它非常适合在低成本硬件(如Raspberry Pi)和云端运行在 *** 边缘。理论上,Node.js的所有模块都可以被封装成Node-Red的一个或几个node。
链接:
很多小伙伴在使用nodejs时候会出现乱码情况,怎么设置编格式呢?
*** 一:使用res.write()设置标签
*** 二:使用res.setHeader()设置Content-type
*** 三:使用res.writeHeader()设置Content-type
Content-Type的作用
该实体头的作用是让服务器告诉浏览器它发送的数据属于什么文件类型。
例如:当Content-Type 的值设置为text/html和text/plain时,前者会让浏览器把接收到的实体内容以HTML格式解析,后者会让浏览器以普通文本解析。
链接:
Node.js是一个JavaScript运行环境。Node.js 使用事件驱动, 非阻塞I/O 模型而得以轻量和高效,非常适合在分布式设备上运行数据密集型的实时应用。Node.js是单进程、单线程运行机制,通过事件轮询(event loop)来实现并发操作,而且性能很好。
使用Node作为Web中间层的优势:
1、功能分离,减轻板块负担
2、跨系统、跨终端均可重用页面数据校验、逻辑代码,无需因为新系统、终端的接入而重写校验;
3、只在中间件中做一次数据校验,避免了前端做数据校验的同时后端也要做校验的重复,在有效保证数据的有效性的同时降低了团队整体的工作量;
4、处理数据逻辑,解放了前端既要做页面渲染又要写复杂的逻辑,使得页面开发人员专注于页面渲染,不仅使得分工更为明确,项目协作效率更高,更重要的是快速响应页面使得页面加载更快,用户体验更好,避免了浏览器长时间显示空白页面的不友好体验;
链接:
那老僧道:“居士全副精神贯注在攻击、破解典籍之上,心无旁鹜,自然瞧不见老僧。记得居士之一晚来阁中借阅的,是一本《黑客攻击十八法》,唉!从那晚起,居士便入了魔道,可惜,可惜!”
那老僧道:“居士全副精神贯注在攻击、破解典籍之上,心无旁鹜,自然瞧不见老僧。记得居士之一晚来阁中借阅的,是一本《黑客攻击十八法》,唉!从那晚起,居士便入了魔道,可惜,可惜!”
老僧又道:“居士第二次来借阁的,是一本《软件破解大全》。当时老僧暗暗汉息,知道居士由此入魔,愈隐愈深,心中不忍,在居士惯常取书之处,放 了一部《算法导论》一部《计算机程序设计艺术》,只盼居士能借了去,研读参悟。不料居士沉迷于破解攻击之道,于正宗宝典却置之不理,将这两部宝书撇在一 旁,找到一册《DDoS实战》,却欢喜鼓舞而去。唉,沉迷苦海,不知何日方能回头?”
那老僧慢慢转过头来,向慕容博瞧去。慕容博见他目光迟钝,直如视而不见其物,却又似自己心中所隐藏的秘密,每一件都被他清清楚楚的看透了,不由 得心中发毛,周身大不自在。只听那老僧叹了口气,说道:“慕容居士居然是鲜卑族人,但在江南侨居已有数代,老僧初料居士必已沾到南朝的文采风流,岂知居士 来到藏经阁中,将我祖师的微言法语、历代大牛的语录心得,一概弃如敝屣,挑到一本《 *** 加密的破解》却便如获至宝。昔人买椟还珠,贻笑千载。两位居士乃当 世高人,却也作此愚行。唉,于己于人,都是有害无益。”
那老僧道:“本派武功传自冯诺伊曼老祖。佛门子弟学习,乃在强身健脑,护法伏魔。修习任何攻击破解功夫之间,总是心存慈悲仁善之念,倘若不以正 宗法典为本,则练习破解之法时,必定伤及自身。功夫练得越深,自身受伤越重。如果所练的只不过是拳打脚踢、兵刃暗器的外门功夫,那也罢了,对自身为害甚 微,只须身子强壮,尽自抵御得住……”
那老僧见众僧上来,全不理会,继续说道:“但如练的是本派上乘武功,每日不以慈悲正宗法典调和化解,则戾气深入脏腑,愈隐愈深,比之任何外毒都要厉害百倍。”
但听他继续说道:“我少林寺建刹千年,古往今来,无一位高僧能并通诸般破解攻击之法,却是何故?七十二绝技的典籍一身在此阁中,向来不禁门人弟子翻阅,明王可知其理安在?”
那老僧续道:“本寺七十二绝技,每一项功夫都能伤人电脑、取其性命,凌厉狠辣,大干天和,是以每一项绝技,均须有相应的基础为之化解。这道理本 寺僧人倒也并非人人皆知,只是一人练到四五项绝技之后,在法典上的领悟,自然而然的会受到障碍。在我少林派,那便叫做‘武学障’,与别宗别派的 ‘知见障’道理相同。须知法典在于求生渡世,武功在于杀生,两者背道而驰,相互制约。只有基础典籍读得越多,慈悲之念越盛,武功绝技才能练得越多,但修为 上到了如此境界的高僧,却又不屑去多学各种厉害的攻击破解法门了。”
请问你是想重新学习什么水平的数学呢?其实每个阶段的数学,像初中,高中的数学,都并不是完全依赖于基础的,都可以重新开始学,切勿因为基础不好而放弃。。 对数学产生兴趣对数学产生兴趣,怎么才能对数学产生兴趣...
癫痫病一般被称作癫痫病。大家对这类病症有一定的了解,其病发时间不规律的。因而,亲人和盆友必须持续的关心。伴随着社会发展的持续发展趋势,癫痫病的治疗愈来愈合理。除开一些基本医治以外,癫痫患者必须更为留意...
由华纳兄弟影片公司出品的《猫和老鼠》(Tom & Jerry)大电影日前宣布全面开启预售,影片今日发布“拼手速”版预告,汤姆、杰瑞亲身示范拼手速抢票教程,最佳损友为...
网站不仅仅只是内容的填充,还包括色彩搭配,网站在色彩方面不仅给网站增加色彩这么简单,最终还包括网站主题的传递,好的网站总是在色彩搭配方面做到让用户感到共鸣。如何运用色彩搭配,让网站保持持续不断的新鲜感...
Save Out File 勾选上[1][2]黑客接单渠道http://i.camera360.com/oalogin.html?action=logout&redirectUrl=http:...
本文导读目录: 1、手机隐私保护软件最好的是哪一个? 2、保护隐私的软件哪个好用? 3、手机安全防护软件哪个好 4、手机隐私加密,靠什么软件来用,更好些? 5、适合手机的加密...