bt365体育投注.主頁欢迎您!!

    <acronym id="zvmrr"></acronym>
    <td id="zvmrr"></td>
  • <tr id="zvmrr"><label id="zvmrr"></label></tr>
  • <acronym id="zvmrr"></acronym>
  • 待你如初

    待你如初 查看完整档案

    成都编辑成都大学  |  数字媒体技术 编辑  |  填写所在公司/组织填写个人主网站
    编辑
    _ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

    个人动态

    待你如初 发布了文章 · 10月29日

    前端安全编码规范

    前端安全编码规范

    前言

    随着互联网高速的发展,信息安全已经成为企业重点关注焦点之一,而前端又是引发安全问题的高危据点,所以,作为一个前端开发人员,需要了解前端的安全问题,以及如何去预防、修复安全漏洞。
    下面就以前端可能受到的攻击方式为起点,讲解web中可能存在的安全漏洞以及如何去检测这些安全漏洞,如何去防范潜在的恶意攻击。


    1. 跨站脚本攻击(Cross Sites Script)

    跨站脚本攻击,Cross Site Script(简称 CSS或)。指黑客通过“HTML注入”篡改了网页,插入了恶意的脚本(主要是JavaScript脚本),从而在用户浏览网页时,控制用户浏览器的一种攻击。

    了解了什么是XSS,那你一定想知道,它有什么危害以及如何去防御
    这里罗列一张列表:

    • 挂马
    • 盗取用户Cookie。
    • 钓鱼攻击,高级的钓鱼技巧。
    • 删除目标文章、恶意篡改数据、嫁祸。
    • 劫持用户Web行为,甚至进一步渗透内网。
    • 爆发Web2.0蠕虫。
    • 蠕虫式挂马攻击、刷广告、刷浏量、破坏网上数据
    • 其它安全问题

    常见的跨站脚本攻击也可分为:反射型XSS、存储型XSS、DOM Based XSS
    下面针对这三种常见的类型做具体的分析


    1.1 反射型XSS--也可被称为是HTML注入
    反射型XSS,也称为"非持久型XSS"简单的把用户输入的数据"反射"给浏览器,即黑客往往需要诱使用户"点击"一个恶意链接攻击才能成功,用户通过点击这个恶意链接,攻击者可以成功获取用户隐私数据的一种方式。如:"盗取用户Cookie信息"、"破坏页面结构"、"重定向到其他网站",盗取内网IP等。 

    那么既然反射型XSS也可以是HTML注入,那么它注入的关键自然也就从前端的HTML页面开始下手:

    1. 用户能够与浏览器页面产生交互动作(输入搜索的关键词,点击按钮,点击链接等等),但这些都需要去诱使用户去操作,说起来容易,做起来难。
    2. 用户输入的数据会被攻击方拼接出合适的html去执行恶意的js脚本,这样的过程就像是"一次反射"
    

    1.2 存储型XSS
    存储型XSS,也称为"`持久型XSS`",它与`反射型XSS`不同之处在于,它会将用户输入的数据"存储"在攻击方的服务器上,具有很强的"稳定性"。
    例如:访问某黑客写下的一篇含有恶意JavaScript代码的博客文章,黑客把恶意脚本保存到服务端。
    

    1.3 DOM based XSS
    从效果上来说,也是"反射型XSS",单独划分出来,是因为其形成是通过修改页面的"DOM节点"形成的XSS。
    例如:通过修改DOM节点上的绑定方法,用户无意间通过点击、输入等行为执行这些方法获取到用户的相关信息
    

    1.4 如何去检测是否存在XSS

    一般方法是,用户可以在有关键字输入搜索的地方输入<script>alert(123)</script>后点击搜索,若弹框出现展示123,说明存在XSS漏洞,这就说明前端并没有对用户输入的内容过滤处理。


    1.5 XSS的攻击方式

    1.Cookie劫持

    通过伪装一些`图片和按钮`等,诱使用户对其操作,使网页执行了攻击者的恶意脚本,使攻击者能够获取当前用户的Cookie信息

    2.构造GET和POST请求

    若某攻击者想删除某网站的一篇文章,首先获得当前文章的id,然后通过使用脚本`插入图片`发送一个`GET请求`,或`构造表单`,`XMLHTTPRequest`发送`POST请求`以达到删除该文章的目的

    3.XSS钓鱼

    `钓鱼`这个词一般认识是起源于`社会工程学`,黑客使用这个这门学科的理念思想,在未授权不知情的情况下诱骗用户,并得到对方对方的姓名、年龄、邮箱账号、甚至是银行卡密码等私人信息。
    
    比如:"某用户在某网站(已被攻击)上操作黑客伪造的一个登录框,当用户在登录框中输入了用户名(这里可能是身份证号等)和密码之后,将其信息上传至黑客的服务器上(该用户的信息就已经从该网站泄漏)"

    4.获取用户真实的IP地址

    通过第三方软件获取,比如客户端安装了Java环境(JRE),则可通过调用`Java Applet`的接口获取客户端本地的IP地址
    

    1.6 XSS的防御方式

    1.HttpOnly

    原理:浏览器禁止页面的Javascript访问带有HttpOnly属性的cookie。(实质解决的是:XSS后的cookie劫持攻击)如今已成为一种“标准”的做法
    
    解决方案:
    JavaEE给Cookie添加HttpOnly的方式为:
    response.setHeader("Set-Cookie","cookiename=value; Path=/;Domain=domainvalue;Max-Age=seconds;HTTPOnly");
    

    2.输入检查(XSS Filter)

    原理:让一些基于特殊字符的攻击失效。(常见的Web漏洞如XSS、SQLInjection等,都要求攻击者构造一些特殊字符)
    * 输入检查的逻辑,必须在服务端实现,因为客户端的检查也是很容易被攻击者绕过,现有的普遍做法是两端都做同样的检查,客户端的检查可以阻挡大部分误操作的正常用户,从而节约服务器的资源。
    
    解决方案:
    检查是否包含"JavaScript","<script></script>"等敏感字符。以及对字符串中的<>:"&/'等特殊字符做处理

    3.输出检查

    原理:一般来说除了富文本输出之外,在变量输出到HTML页面时,使用编码或转义的方式来防御XSS攻击
    
    解决方案:
    *   针对HTML代码的编码方式:HtmlEncode
    *   PHP:htmlentities()和htmlspecialchars()两个函数
    *   Javascript:JavascriptEncode(需要使用""对特殊字符进行转义,同时要求输出的变量必须在引号内部)
    *   在URL的path(路径)或者search(参数)中输出,使用URLEncode

    4.更严格的做法

    除了数字和字母外的所有字符,都使用十六进制的方式进行编码

    2. 跨站点请求伪造(Cross Sites Request Forgery)

    跨站点请求伪造,指利用用户身份操作用户账户的一种攻击方式,即攻击者诱使用户访问一个页面,就以该用户身份在第三方有害站点中执行了一次操作,泄露了用户的身份信息,接着攻击者就可以使用这个伪造的,但真实存在的身份信息,到某网站冒充用户执行恶意操作。

    但是,攻击者只有预测到URL的所有参数与参数值,才能成功地伪造一个请求(当然了,他可以在安全站点里以自己的身份实际去操作一下,还是能拿到参数的);反之,攻击者无法攻击成功

    下图通俗解释什么是CSRF,又是如何给用户带来危害的
    image.png

    参考上图,我们可以总结,完成一次CSRF攻击,必须满足两个条件

    • 用户登录受信任网站A,并且在本地生成Cookie
    • 在不登出网站A的情况下,访问有害网站B

    2.1 CSRF的原理
    CSRF攻击是攻击者利用**`用户身份`**操作用户账户的一种攻击方式
    
    如电影速度与激情5中吉赛尔使用内裤获取巴西大佬指纹,最后成功使用伪造指纹的手法打开保险柜,CSRF只不过是网络上这个手法的实现。
    

    2.2 CSRF的攻击方式

    1.浏览器的Cookie策略

    浏览器所持有的策略一般分为两种:
    Session Cookie,临时Cookie。保存在浏览器进程的内存中,浏览器关闭了即失效。
    Third-party Cookie,本地Cookie。服务器在Set-Cookie时指定了Expire Time。过期了本地Cookie失效,则网站会要求用户重新登录。
    

    * 在浏览网站的过程中,即使浏览器打开了Tab页,Session Cookie都是有效的,因此发起CSRF攻击是可行的。

    2.P3P头的副作用

    "P3P Header"是 "W3C" 制定的一项关于隐私的标准,全称是 "The Platform for Privacy Preference"(隐私偏好平台)
    
    如果网站返回给浏览器的 HTTP 头包含有 P3P 头,则在某种程度上来说,将允许 浏览器发送第三方 Cookie。在 IE 下即使是"<iframe>"、`<script>`等标签页将不再拦截第三方 Cookie 的发送。主要应用在类似广告等需要跨域访问的页面。
    

    3.GET,POST请求

    * 这里有个误区
    大多数 CSRF 攻击,都是通过 <img> 、 <iframe> 、 <script> 等带 src 属性的标签,这类标签只能发送一次 GET 请求,而不能发送 POST 请求,由此也有了认为 CSRF 攻击只能由 GET 请求发起的错误观点。
    
    构造一个 POST 请求,只需要在一个不可见的iframe窗口中,构造一个form表单,然后使用JavaScript自动提交这个表单。那么整个自动提交表单的过程,对于用户来说就是不可见的。
    

    2.3 CSRF的防御方式

    1.验证码

    原理:
    CSRF攻击过程中,用户在不知情的情况下构造了网络请求,添加验证码后,强制用户必须与应用进行交互
    
    *  优点:简洁而有效
    *  缺点:网站不能给所有的操作都加上验证码

    2.Referer Check

    原理:
    * 利用HTTP头中的Referer判断请求来源是否合法
    * Referer首部包含了当前请求页面的来源页面的地址,一般情况下Referer的来源页就是发起请求的那个页面,如果是在iframe中发起的请求,那么对应的页面URL就是iframe的src
    
    *  优点:简单易操作(只需要在最后给所有安全敏感的请求统一添加一个拦截器来检查Referer的值就行)
    *  缺点:服务器并非什么时候都能取到Referer
            1.很多出于保护用户隐私的考虑,限制了Referer的发送。
            2.比如从HTTPS跳转到HTTP,出于安全的考虑,浏览器不会发送Referer

    3.使用Anti CSRF Token

    原理:把参数加密,或者使用一些随机数,从而让攻击者无法猜测到参数值,也就无法构造请求的 URL,也就无法发起 CSRF 攻击。
    
    例子(增加token):
    *  比如一个删除操作的URL是:`http://host/path/delete?uesrname=abc&item=123`
    *  保持原参数不变,新增一个参数Token,Token值是随机的,不可预测
    *  http://host/path/delete?username=abc&item=123&token=[random(seed)]
    
    *  优点:比检查Referer方法更安全,并且不涉及用户隐私
    *  缺点:
            加密
            1. 加密后的URL非常难读,对用户非常不友好
            2. 加密的参数每次都在改变,导致用户无法对页面进行搜索
            3. 普通参数也会被加密或哈希,将会给DBA工作带来很大的困扰,因为数据分析常常需要用到参数的明文
            
            token
            1. 对所有的请求都添加Token比较困难

    需要注意的点

    1. Token需要足够随机,必须用足够安全的随机数生成算法
    2. Token应该为用户和服务器所共同持有,不能被第三方知晓
    3. Token可以放在用户的Session或者浏览器的Cookie中
    4. 尽量把Token放在表单中,把敏感操作由GET改为POST,以form表单的形式提交,可以避免Token泄露(比如一个页面:http://host/path/manage?username=abc&token=[random],在此页面用户需要在这个页面提交表单或者单击“删除”按钮,才能完成删除操作,在这种场景下,如果这个页面包含了一张攻击者能指定地址的图片<img data-original="http://evil.com/notexist" />,则这个页面地址会作为HTTP请求的Refer发送到evil.com的服务器上,从而导致Token泄露)
    2.4 XSRF

    当网站同时存在XSS和CSRF漏洞时,XSS可以模拟客户端浏览器执行任意操作,在XSS攻击下,攻击者完全可以请求页面后,读取页面内容中的Token值,然后再构造出一个合法的请求

    3. 点击劫持(ClickJacking)

    点击劫持是一种视觉上的欺骗手段。攻击者使用一个透明的、不可见的iframe,覆盖在一个网页上,然后诱使用户在网页上进行操作,此时用户将在不知情的情况下点击透明的iframe页面。通过调整iframe页面的位置,可以诱使用户恰好点击在iframe页面的一些功能性按钮上。

    比如,程序员小王在访问A网页时,点击空白区域,浏览器却意外打开了xx新葡京赌场的页面,于是他在A网页打开控制台,在空白区域发现了一个透明的iframe,该iframe嵌入了一个第三方网页的URL

    3.1 点击劫持防御方式
    1.X-Frame-Options HTTP响应头是用来给浏览器指示允许一个页面能否在`<frame>、<iframe>、<object>`中展现的标记
    
    #### 有三个可选的值
    1.  DENY:浏览器会拒绝当前页面加载任何frame页面(即使是相同域名的页面也不允许)
    2.  SAMEORIGIN:允许加载frame页面,但是frame页面的地址只能为同源域名下的页面
    3.  ALLOW-FROM:可以加载指定来源的frame页面(可以定义frame页面的地址)
    
    2.禁止iframe的嵌套
    if(window.top.location !== window.loaction){window.top.location === window.self.location}

    4. 其他安全问题

    4.1 跨域问题处理
        当服务端设置 'Access-Control-Allow-Origin' 时使用了通配符 "*",允许来自任意域的跨域请求,这是极其危险的
    
    4.2 postMessage 跨窗口传递信息
        postMessage 允许每一个 window(包括当前窗口、弹出窗口、iframes等)对象往其他的窗口发送文本消息,从而实现跨窗口的消息传递。并且这个功能不受同源策略限制。
        必要时,在接受窗口验证 Domain,甚至验证URL,以防止来自非法页面的消息。实际上是在代码上实现一次同源策略的验证过程。接受窗口对接口的信息进行安全检查。
        
    4.3 Web Storage
        Web Storage 分为 Session Storage 和 Local Storage。
        虽然受同源策略的约束,但当存有敏感信息时,也可能会成为攻击的目标。
        
    

    5. 总结

    1. 谨慎用户输入信息,进行输入检查(客户端和服务端同时检查)
    2. 在变量输出到HTML页面时,都应该进行编码或转义来预防XSS攻击
    3. 该用验证码的时候一定要添上
    4. 尽量在重要请求上添加Token参数,注意Token要足够随机,用足够安全的随机数生成算法

    6. 参考文献

    1. 十大常见web漏洞及防范
    2. hyddd
    3. CSRF攻击与防御
    4. 浅谈前端安全
    5. 前端安全
    查看原文

    赞 31 收藏 22 评论 0

    待你如初 发布了文章 · 9月23日

    如何在taro3.0项目中引用taro-ui以及如何在项目中使用iconfont cdn

    前言

    因为最近看成都这边越来越多的人开始从vue技术栈,转到react方向。而对于使用vue通过uniapp打包构建微信小程序,h5页面等方式来说,react也有自己独特的一体化多端解决方案

    来自强东bb旗下凹凸实验室荣誉出版的taro(泰罗),这名字是真牛皮,哪位仁兄想出来的?小时候肯定看了不少的奥特曼动画


    搭建taro项目

    废话不多说,想要看taro是通过什么造出来的,大家还是去官网慢慢看吧,反正跟微信小程序的差不多(就只是换了名字而已,实现都是差不多的),就是语法大部基于jsx的react写出来的。大家都是组件化开发,何必争来争去的呢?

    taro3.0 是凹凸实验室于20年7月左右的样子(想不起来了)出了一个beta版本,就是随便体验一下,像使用taroUI那种,想都别想,用了一大堆奇怪的报错。
    现在想看具体使用的就食用下方链接(不过这里按官方安装taroUI使用会有问题,解决方案在后文):

    taro介绍

    1. 首先我们安装taro脚手架(注意这里是全局安装,跟安装create-react-app一样)
    # 使用 npm 安装 CLI
    
    $ npm install -g @tarojs/cli
    
    # OR 使用 yarn 安装 CLI
    
    $ yarn global add @tarojs/cli
    
    # OR 安装了 cnpm,使用 cnpm 安装 CLI
    
    $ cnpm install -g @tarojs/cli
    1. 注意事项

    值得一提的是,如果安装过程出现sass相关的安装错误,请在安装后重试。

    $ npm install -g mirror-config-china
    1. 使用命令创建模板项目
    $ taro init myApp

    这里会让你填入,项目的名称,描述,使用的开发语言等
    (如果你不熟悉TSX的话就还是用JSX开发)
    模板建议是使用redux(反正大家基本都用这个),当然你会用mobx等其他的状态机当然更好咯!!!

    。。。。。。然后就等项目模板搭建好了
    搭建好模板之后,就可以从这个地方看起走了

    react使用taro

    当然taro在3.0也开始支持vue了!!!有兴趣也可以多多学习
    其实taro 2.0的文档对于使用react开发介绍的还是比较详细的。


    使用taro UI

    其实这个地方有个超级大坑,因为taro3.0出来后,我一直以为taro UI的文档是跟着taro一起更新的,但是当我照着taro UI的文档照做,并引入组件后,发现报了一大堆TS的错,差不多就是告诉你引入组件错误。于是度娘都要被我看透了,终于最后找到了一个解决方法,其他的根本就是引用2.0时期的解决方案(根本没卵用,字都不带改的)

    那个博主的意思大概就是这样的
    装taroUI依赖的时候这么安装

    # 修改package.json文件,然后执行npm install 安装
    # package.json
    
    "dependencies":{
         "taro-ui": "^3.0.0-alpha"
    }

    如果你不小心跟着文档安装了taro UI的话,就先把node_modules删了,然后把package.json文件中的原taro UI相关删掉,改成上述,重新npm install一下,剩下taro UI使用,css引用就跟文档一样就行了

    taroUI快速上手


    iconfont cdn使用

    随着前端大量开始使用各cdn的资源,本地存放一大堆静态文件的时代该说再见了。当然使用iconfont cdn还是有一定坑的,之前3.0beta版本的时候,我在度娘上查阅的方法基本上都没法将iconfont cdn上的资源引入到我本地的taro项目中,更多的还是教你如何在iconfont上下载静态资源引入到项目中。这样就增加了前端项目的大小。在我们写项目中,使用最少的代码,节约资源实现相同功能也是体现能力的一方面

    这里推荐一个工具,亲测,巨好用。

    taro项目的iconfont脚手架

    github地址

    这个仓库中有很多使用iconfont cdn的场景
    iconfont-cli


    1. 安装脚手架(这里只需要在项目中安装开发依赖就可以了)
    # Yarn
    yarn add taro-iconfont-cli --dev
    # Npm
    npm install taro-iconfont-cli --save-dev
    1. 生成配置文件
    npx iconfont-init
    # 可传入配置输出路径
    # npx iconfont-init --output iconfont.json

    此时项目根目录会生成一个iconfont.json的文件,内容如下:

    {
     "symbol_url": "请参考README.md,复制 http://iconfont.cn 官网提供的JS链接",
     "save_dir": "./iconfont",
     "use_typescript": false,
     "platforms": "*",
     "use_rpx": true,
     "trim_icon_prefix": "icon",
     "default_icon_size": 18
    }

    这里插入在iconfont建立项目的方式,按下图所示
    image.png 图一
    image.png 图二
    image.png 图三
    image.png 图四


    然后到图三去


    image.png
    再到本地的项目中
    image.png

    1. 注意事项(这里是个超级大坑)

    由于Taro3.0的架构变更,您需要在src/app.config.js下填写一次usingComponents

    // src/app.config.js
    import { useGlobalIconFont } from './components/iconfont/helper';
    export default {
     usingComponents: Object.assign(useGlobalIconFont()),
    }

    只有这样你才能真正的将你的icon图标引入到项目中来

    1. 生成针对于icon的taro组件
    npx iconfont-taro
    # 可传入配置文件路径(一般情况就会放到默认的iconfont.json下)
    # npx iconfont-taro --config iconfont.json

    生成后查看您设置的保存目录中是否含有所有的图标

    # 如果你在iconfont cdn上对你的图标有修改操作
    # 1. cdn上的链接symbol url会发生改变,你需要把最新的url更新到本地iconfont.json中的symbol_url中
    # 2. 然后需要重新执行 
    npx iconfont-taro
    # 重新在本地项目生成最新的taro组件
    1. 使用组件
    import React, { Component } from 'react';
    import IconFont from '../iconfont';
    class App extends Component {
     render() {
     return <IconFont name="alipay" />;
     # 一般iconfont上的名字是带前缀icon-的,可以在iconfont.json 文件中"trim_icon_prefix": "icon",将相应的前缀去掉就好了
     }
    }
    export default App;

    更多用法

    // 原色彩
    <IconFont name="alipay" />
    // 单色:红色
    <IconFont name="alipay" color="red" />
    // 多色:红色+橘色
    <IconFont name="alipay" color={['red', 'orange']} size={300} />
    // 不同格式的颜色写法
    <IconFont name="alipay" color={['#333', 'rgb(50, 124, 39)']} />
    // 与文字对齐
    <View style={{ display: 'flex', alignItems: 'center' }}>
     <Text>Hello</text>
     <IconFont name="alipay" />
    </View>

    这里在程序跑起来后可能还会报错这样的错误,照下面方式解决就好了
    image.png

    结尾

    以上就是使用taro3.0引入taroUI和iconfont cdn资源时可能会踩到的坑。这只是个入门的教程,不知道后面文档还会怎么修改,再看吧,taro3.0才出来没好久,文档有些解释的也不太清楚,还是得自己慢慢去踩坑,遇到了问题解决了,贡献出来,别人才可以少走点弯路。

    本来taro在成都这边的市场应用还不是特别广泛,一起打造良好的taro生态,也是每个程序员的责任

    查看原文

    赞 1 收藏 1 评论 0

    待你如初 提出了问题 · 2019-12-04

    关于在antdpro中使用多个iframe的问题

    我在做项目的时候使用了antdpro这个架构,当前的需求是在一个tab页中嵌套一个第三方的页面(表格),点击这个页面中的某一项需要打开这一项的详情页面,方式是点击之后重新打开一个新的tab页面,并在这个tab页面中内嵌一个新的iframe框架展示详情页。

    我自己的步骤:因为页面是用的第三方的,点击某项打开新tab页的那个方法是第三方写的(自己这边重写太麻烦了),我通过addEventListener('message')去监听点击的事件获取到了我所需要的title和url。我通过dva的 router.push(传参url)开启新tab页后,将url赋值给新tab页的iframe。

    遇到的问题就是:当你点击某一项去打开新的页面之后,新的iframe依然内嵌原来那个iframe的页面,而点击新的iframe页面中的某项之后,才能打开我想要的内嵌详情的iframe。

    ?????????这,什么鬼???

    关注 1 回答 0

    待你如初 收藏了文章 · 2019-09-18

    【React性能优化】 React组件优化

    简介:

    1.组件内: 传递参数的时候要少传,且每次传递的尽量是一份数据,不要每次这个数据都会被重新创建
    2.组件间:shouldComponent、pureComponent、immutable   
    

    单组件 - 属性传递优化

    1. 函数绑定优化 - 绑定函数的几种方式
      handleClick(event){
        // 你的事件处理逻辑
      }
    
    1. onclick={::this.handlerClick} 不建议,es7中的写法,等同于3
       onClick={this.handleClick.bind(this)}
    // 箭头函数中的上下文是所在全局的上下文,不决定于谁调用他
    2. onclick={() => this.handlerClick()}
       onClick={this.handleClick}
    
       handleClick = () => {
        console.log(this); 
      }
    // 所以我们需要在class的construct中将函数的执行作用域设为当前组件
    3. constructor(props, context) {
           super(props, context)
           this.handlerClick= this.handlerClick.bind(this)
       }
       onclick={this.handlerClick}

    Q: 上面那种方式最好?

    构造函数bind > 箭头函数 > 直接bind
    因为构造函数只会在app创建,执行一次,箭头函数和bind每次都返回一个新的函数,引起渲染

    Q: React事件机制,为什么拿不到this

        class Foo {
          constructor(name){
            this.name = name
        }
        
        display(){
            console.log(this.name);
          }
        }
        
        var foo = new Foo('Saurabh');
        foo.display(); // Saurabh
        
        //下面的赋值操作模拟了上下文的丢失。 
        //与实际在 React Component 中将处理程序作为 callback 参数传递相似。
        // 类声明和类表达式的主体以 严格模式 执行,主要包括构造函数、静态方法和原型方法。Getter 和 setter 函数也在严格模式下执行。
        var display = foo.display; 
        display(); // TypeError: this is undefined
    

    Q:为什么在使用bind能解决

    // 解决:构造函数中bind,对应第三种方法
    class Foo {
      constructor(name){
        this.name = name
        this.display = this.display.bind(this);
    }
    
    display(){
       console.log(this.name);
    }
    
    var foo = new Foo('Saurabh');
    foo.display(); // Saurabh
    
    var display = foo.display;
    display(); // Saurabh
    
    // 我们也可以在其他地方bind,对应第一种方法
    // 但由于构造函数是所有初始化发生的地方,因此它是编写绑定事件语句最佳的位置
    class Foo {
      constructor(name){
        this.name = name;
      }
    
      display(){
        console.log(this.name);
      }
    }
    
    var foo = new Foo('Saurabh');
    foo.display = foo.display.bind(foo);
    foo.display(); // Saurabh
    
    var display = foo.display;
    display(); // Saurabh

    Q:箭头函数为什么能解决

    1.箭头函数机制

    箭头函数没有 this,所以需要通过查找作用域链来确定 this 的值。
    这就意味着如果箭头函数被非箭头函数包含,this 绑定的就是最近一层非箭头函数的 this
    this 是有词法约束力的。这意味它可以使用封闭的函数上下文或者全局上下文作为 this 的值
    

    2.分析为什么能解决 - 箭头函数两种解决方式

    公共类字段语法: 箭头函数被包含在 Foo 类中或者构造函数中,所以它的上下文就是组件实例
    class Foo extends React.Component{
      handleClick = () => {
        console.log(this); 
      }
     
      render(){
        return (
          <button type="button" onClick={this.handleClick}>
            Click Me
          </button>
        );
      }
    }
    
    ReactDOM.render(
      <Foo />,
      document.getElementById("app")
    );
    
    
    回调中的箭头函数:箭头函数被包含在 render() 方法中,该方法由 React 在组件实例的上下文中调用
    class Foo extends React.Component{
     handleClick(event){
        console.log(this);
      }
     
      render(){
        return (
          <button type="button" onClick={(e) => this.handleClick(e)}>
            Click Me
          </button>
        );
      }
    }
    
    ReactDOM.render(
      <Foo />,
      document.getElementById("app")
    );

    Q: bind为何不能用 call和apply这种替代

    因为call和apply会立即执行,这是bind与call,apply的区别
    

    2.传递参数注意

    如果直接写一个对象在item处,则每次会生成新的
    so, 传递参数的时候要少传,且每次传递的尽量是一份数据,不要每次这个数据都会被重新创建

    const item = { firstName: 'Liu' }
    <Demo style={{ color: 'red' }} name={item}></Demo>
    
    <Demo {...this.state}></Demo>

    多组件优化

    1.shouldComponentUpdate

    // 浅比较前后两次的props的变化
    // 一般redux的state层次深,数据结构复杂,深层比较太消耗性能,得不偿失
    class Demo extends React.component {
      shouldComponentUpdate(nextProps, nextState) {
        if (compareObj(nextProps, this.props)) {
          return false
        }
        return true
      }
    
      render() {
        return <h2>{this.props.title}</h2>
      }
    }

    浅比较

    function compareObj(obj1, obj2) {
      if (obj1 == obj2) {
        return true
      }
      if (Object.keys(obj1).length !== Object.keys(obj2).length) {
        return false
      }
      for(let k in obj1) {
        if (obj1[k] !== obj2[k]) {
          return false
        }
      }
      return true
    }

    补充: 深比较的实现 - 浅比较的递归

    function compareObj(obj1, obj2) {
      if (obj1 == obj2) {
        return true
      }
      if (Object.keys(obj1).length !== Object.keys(obj2).length) {
        return false
      }
      for (let k in obj1) {
        if (typeof obj1[k] == 'object') {
          return compareObj(obj1[k], obj2[k])
        } else if (obj1[k] !== obj2[k]) {
          return false
        }
      }
      return true
    }

    React16 简易的写法 - 把nextProps每个都遍历比较了一遍

    class Demo extends React.PureComponent {
      render() {
        return <h2>{ this.props.title }</h2>
      }
    }

    2. immutablejs

    解决什么问题:

    immutablejs的出现就是为了解决可变数据结构深层比较的性能问题
    让我们更优更高效的比对数据,减少渲染
    

    优势:

    节省内存,降低可变的风险,可以用等号判断是否相等
    比较是直接拿地址得hash做对比,所以比较相等的复杂度特别低
    

    使用:

    将react, redux的数据全部改为使用immutable的数据类型来操作
    // 此时,定制shouldComponentUpdate就会特别简单高效
    class Demo extends React.component {
      shouldComponentUpdate(nextProps, nextState) {
        return is(nextProps, this.props)
      }
    
      render() {
        return <h2>{this.props.title}</h2>
      }
    }

    推荐immutable轻量级包:seamless-immutable

    Key

    建议:循环时,不要使用index来作为key,最好拿数值或者数组与其他的组合来确保key的唯一性

    <ul>
      {this.state.users.map((v,index) => <li key={index}>{v}</li>)}
    </ul>

    问题:

    如果我再数组前面插入数组,则整个数组的index都会发生变化,v-dom就没有存在的意义
    key用来标识同级的dom元素,其作用和重要性,详情请见另一篇blog - 深入diff和虚拟dom
    key变化了,react比对时,就会全部删除插入,不会进行复用移动
    
    查看原文

    待你如初 关注了用户 · 2017-08-31

    张小胖爱逼逼 @weespice_zzw

    前端开发 后台开发 在校学生 想做全栈

    关注 23

    待你如初 关注了用户 · 2017-06-14

    枫上雾棋 @fengshangwuqi

    I have a garden which named front-end.

    blog: https://fengshangwuqi.github.io

    关注 85

    认证与成就

    • 获得 34 次点赞
    • 获得 1 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 1 枚铜徽章

    擅长技能
    编辑

    开源项目 & 著作
    编辑

    (??? )
    暂时没有

    注册于 2017-06-14
    个人主页被 637 人浏览

    bt365体育投注