每日一问---es2020

ES2020新增方法

类的私有属性


通过在变量或函数前面添加一个简单的散列符号,我们可以将它们完全保留在类内部使用。

静态方法

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。
如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,
而是直接通过类来调用,这就称为“静态方法”。

静态属性

静态属性指的是 Class 本身的属性,即Class.propName,
而不是定义在实例对象(this)上的属性。

私有属性 私有方法

私有方法和私有属性,是只能在类的内部访问的方法和属性,外部不能访问。

class InnerStatic {
    // 静态属性
    static staticProps = 'string'; 
    // 静态方法
    static staticFun = ()=>{};    
    // 私有属性
    #message = 1; 
    // 私有方法
    #getMessage(){ 
        console.log('#message values', this.#message);
    }
    实例方法
    getMessage(){

    }
}
let instance = new InnerStatic();
instance.getMessage();
console.log(instance.#message) // Private name #message is not defined

无效合并操作符


因为 JavaScript 是动态类型的,所以在分配变量时需要牢记 JavaScript 对真 / 假值的处理。 如果我们有一个具有一些值的对象,有时候我们希望允许一些技术上有误的值,比如一个空字符串或者数字0。 设置默认值很快会变得烦人,因为它会覆盖应该是有效值的内容。

let person = {
  profile: {
    name: '',
    age: 0
  }
};
console.log('无效合并操作符', person.profile.name || 'Anonymous'); // Anonymous
console.log('无效合并操作符', person.profile.name ?? 'Anonymous'); // ''

可选的链接操作符


在点符号之前添加一个问号,我们可以使值的路径的任何部分可选

let person = {};

// console.log(person.profile.name ?? '');  // Cannot read property 'name' of undefined
console.log(person?.profile?.name);  // undefined

if (person?.profile?.name) {
  console.log('have name props');
} else {
  console.log('not exits name props');
}

可用于判断数据属性是否存在,不必写成冗长的 
person && person.profile && person.profile.name的格式

BigInt


通过在末尾加上字母 n 解决js中数字超过最大数值精度错误问题

const max = Number.MAX_SAFE_INTEGER;
console.log(max); // 9007199254740991
console.log(max + 1);
console.log(max + 2);
console.log(max + 3);

const bigNum = 1000000000000000000000000000000000000000000000n;

console.log(bigNum + 1n);  // 1000000000000000000000000000000000000000000001n

Dynamic Import 动态导入


如果您的文件中充满了实用函数,其中一些函数可能很少被使用,导入它们的所有依赖项可能只是浪费资源。 现在我们可以使用 async / await 在需要的时候动态导入依赖关系。

math.js

const add = (num1, num2) => num1 + num2;
export { add };

---------------------

index.js

const doMath = async (num1, num2) => {
  if (num1 && num2) {
    const math = await import('./math.js');
    console.log(math.add(5, 10));
  };
};

doMath(4, 2);

Promise.allSettled


接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束。

const p1 = new Promise((res, rej) => setTimeout(res, 1000));

const p2 = new Promise((res, rej) => setTimeout(rej, 1000));

Promise.allSettled([p1, p2]).then(data => console.log(data));

// [
//   Object { status: "fulfilled", value: undefined},
//   Object { status: "rejected", reason: undefined}
// ]

参考资料

es2020


title: 每日一问—
date: 2020-03-28
category: 技术 # 归类
tag: [‘技术’] # 标签
tagcloud: [‘技术’] # 云标签
archives: [‘技术’,’每日问题’,’web安全’] # 归档


页面字体以及格式

<div style="font-size:18px;color:#333;line-height:24px;font-family:楷体;"> </div>

问题标题

<font style="font-weight:700"></font>  <strong><strong>

引用

<font style="color:blue;"></font>

一般层级

#### ##### ######

注意事项

<font style="color:red;"></font>

加重

<font style="font-weight:700;color:#333;"></font>

每日一问---React生命周期

React生命周期

React版本 16.13.1

生命周期

constructor(props)
componentWillMount()  ===> UNSAFE_componentWillMount()
render()
componentDidMount()

componentWillReceiveProps(nextProps) ===> UNSAFE_componentWillReceiveProps
shouldComponentUpdate(nextProps, nextState)
componentWillUpdate(nextProps, nextState) ===> UNSAFE_componentWillUpdate
componentDidUpdate(prevProps, prevState, snapshot)
componentWillUnmount()

componentDidCatch

新的生命周期函数

static getDerivedStateFromProps(nextProps, prevState)

static getDerivedStateFromError()

getSnapshotBeforeUpdate()


constructor(props)

在 React 组件挂载之前,会调用它的构造函数。在这里可以进行state的初
始化操作和为事件处理函数绑定实例

componentWillMount()

在挂载之前被调用。它在 render() 之前调用,因此在此方法中同步调用 setState() 不会触发额外渲染

此方法是服务端渲染唯一会调用的生命周期函数

React 16.3版本中引入UNSAFE_componentWillMount别名
React 16.X版本中采用componentWillMount()会产生警告警告
React 17.0版本删除 componentWillMount()

render()

render() 方法是 class 组件中唯一必须实现的方法。
通过createElement方法返回对应类型的react渲染数据对象

render() 函数应该为纯函数,不能够有副作用


componentDidMount()

在组件挂载后(插入 DOM 树中)立即调用,在此处可以进行一些AJXA、DOM获取、订阅等副作用的操作


componentWillReceiveProps(nextProps)

在已挂载的组件接收新的 props 之前被调用

在挂载过程中不会调用,在组件props改变时候才会触发,内部this.state的改变不会触发componentWillReceiveProps()

React 16.3版本中引入UNSAFE_componentWillReceiveProps别名
React 16.X版本中采用componentWillReceiveProps()会产生警告警告
React 17.0版本删除 componentWillReceiveProps()

shouldComponentUpdate(nextProps, nextState)

当 props 或 state 发生变化时,shouldComponentUpdate 会在渲染执行之前被调用。返回值默认为 true。首次渲染或使用 forceUpdate() 时不会调用该方法。

  • 根据 shouldComponentUpdate 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。返回false则当下更改不会影响组件

  • 返回 false 并不会阻止子组件在 state 更改时重新渲染

  • 目前版本 如果 shouldComponentUpdate 返回 false,则不会调用UNSAFE_componentWillUpdate,render 和 componentDidUpdate

  • 在此中可以做是否渲染的优化操作


componentWillUpdate(nextProps, nextState)

当组件收到新的 props 或 state 时,会在渲染之前调用 componentWillUpdate。使用此作为在更新发生之前执行准备更新的机会。初始渲染不会调用此方法。

React 16.3版本中引入UNSAFE_componentWillUpdate别名
React 16.X版本中采用 componentWillUpdate() 会产生警告警告
React 17.0版本删除 componentWillUpdate()

componentDidUpdate(prevProps, prevState, snapshot)

在更新后会被立即调用。首次渲染不会执行此方法。


componentWillUnmount()

在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。


componentDidCatch(error, info)

此生命周期在后代组件抛出错误后被调用。

其接受两个参数

1.error 抛出的错误
2.info 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息。

getDerivedStateFromProps(props,state)

getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。

static getDerivedStateFromProps(props, state)

此方法可看做componentWillMount和componentWillReceiveProps的结合,但是有一些区别

1.在此静态方法中无权访问组件实例

2.需要返回一个对象更新state

3.每次渲染前触发此方法,componentWillReceiveProps仅在父组件重新渲染触发


getSnapshotBeforeUpdate(prevProps,PrevState)

getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()。

getDerivedStateFromError(error)

此生命周期会在后代组件抛出错误后被调用。它将抛出的错误作为参数,并返回一个值以更新 state

static getDerivedStateFromError(error) {
    // 更新 state 使下一次渲染可以显降级 UI
    return { hasError: true };
  }

生命周期执行流程

image

参考资料

生命周期执行流程
React-Component

每日一问---前端安全CSRF

关于前端安全CSRF

跨站请求伪造(英語:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。

1.攻击原理

假设用户登录到不受保护的某银行网站,并且使用会话 cookie 或 JWT cookie 进行身份验证,并进行转账操作

假如其转账操作的URL地址如下: 
http://www.examplebank.com/withdraw?account=AccoutName&amount=1000&for=PayeeName

攻击者欺骗用户执行脚本(通过点击垃圾邮件链接或类似)

用户进入第三方网站 
<img src="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman

由于不受保护的某银行网站的登录信息未过期,服务器将成功地验证用户身份并执行交易

在CSRF中攻击者并不直接获取用户信息,其只是欺骗用户浏览器,让其以用户的名义进行操作

2.攻击流程

image

3.预防策略

1.检查Referer字段

HTTP头中有一个Referer字段,这个字段用以标明请求来源于哪个地址。

image

在处理敏感数据请求时,通常来说,Referer字段应和请求的地址位于同一域名下。

以上面银行操作为例,

Referer字段地址通常应该是转帐按钮所在的网页地址,应该也位于www.examplebank.com之下。

而如果是CSRF攻击传来的请求,Referer字段会是包含恶意网址的地址,

不会位于www.examplebank.com之下,这时候服务器就能识别出恶意的访问。

但存在恶意篡改其Referer字段的可能

2.token验证
既然攻击者利用第三方cookie的方式去获取用户信息,并验证用户身份这种方式进行攻击,
可以采取增加一个独立的token进行认证,
在用户登录信任网站的时候,服务端生成一个唯一token并给到用户,
用户每次和服务端通信,都会校验token的有效性,
如果校验token失败,则认为可能是 CSRF 攻击而拒绝该请求。

参考资料

wiki百科
XSS CSRF 例子


title: 每日一问—
date: 2020-03-28
category: 技术 # 归类
tag: [‘技术’] # 标签
tagcloud: [‘技术’] # 云标签
archives: [‘技术’,’每日问题’,’web安全’] # 归档


页面字体以及格式

<div style="font-size:18px;color:#333;line-height:24px;font-family:楷体;"> </div>

问题标题

<font style="font-weight:700"></font>

引用

<font style="color:blue;"></font>

一般层级

#### ##### ######

注意事项

<font style="color:red;"></font>

加重

<font style="font-weight:700;color:#333;"></font>

每日一问---关于前端安全XSS

关于前端安全XSS

XSS

XSS,即 Cross Site Script,中译是跨站脚本攻击;其原本缩写是CSS,但为了和层叠样式表(Cascading Style Sheet)有所区分,因而在安全领域叫做 XSS

攻击者通过恶意插入脚本,实现对用户访问网站内容的控制

其大致分为三种类型

1.反射型(Reflected XSS)

当服务器端脚本立即使用 web 客户端提供的数据(最常见的是 HTTP 查询参数(例如 HTML 表单提交))来解析并向用户显示结果页面时,这些漏洞就会显现出来

反射 XSS 是攻击者发现页面有这样的漏洞时发生的攻击,例如:

假如页面的HTML是如下

<body>
...
<div> showing results for keyword 
<script> 
    document.write(
        window.location.href.substr(window.location.href.indexOf('q=') + 2)
    )
</script>
</div>
...
...JavaScript results...
...
</body>

在此输入URL地址

期望的 URL: https://mywebpage.com/search?q=javascript

如果恶意注入代码如下

恶意URL: https://mywebpage.com/search?q=<script>恶意代码</script>

当攻击者诱使用户点击这种恶意的 URL ,用户敏感数据会被泄露

攻击的流程如下

image

2.存储型(Stored XSS)

攻击者提供的数据被服务器保存,然后在正常浏览过程中返回给其他用户的“正常”页面上永久显示,而没有适当的 HTML 转义。

其攻击流程如下

image

3.基于DOM型(DOM based XSS)

恶意代码通过 JavaScript 代码完全在客户端反映出来的

这种攻击和反射型是类似的,但不同的是,恶意的 URL 部分将不会被发送到服务器。 例如:

期望 URL: https://mywebpage.com/search?q=javascript

基于DOM型

恶意 URL:  https://mywebpage.com/search#q=<script>恶意代码</script>

如果在页面中存在

var text = document.getElementById("text");
text.innerHTML  = malicious URL

就会破坏DOM结构,攻击者就可以通过脚本实现控制内容


如何防护

每一个可以由用户输入并在您的应用程序中使用的值(无论是在服务器端还是在客户端)都应该被视为不受信任的数据,因此应该在使用前进行处理!

输入检测

对用户输入的内容进行检测并转义

function escapeText(text) {
  return text.replace(/&/g, '&amp;')
             .replace(/</g, '&lt;')
             .replace(/>/g, '&gt;')
             .replace(/"/g, '&quot;')
}
输出检查

在服务端数据渲染HTML的时候,使用编码或转义的方式避免


参考资料

XSS CSRF 例子
github book
<<白帽子讲 Web 安全>>

页面字体以及格式

<div style="font-size:18px;color:#333;line-height:24px;font-family:楷体;"> </div>

问题标题

<font style="font-weight:700"></font>

引用

<font style="color:blue;"></font>

一般层级

#### ##### ######

注意事项

<font style="color:red;"></font>

加重

<font style="font-weight:700;color:#333;"></font>

每日一问---React中render函数

React中关于render函数返回一个元素

问题需求
当在render返回的方法中,需要返回多个根节点时候会如何
关于Jsx

由于react jsx是javascript的语法拓展,其本质是 通过React.createElement(type, config, children)来返回一个React元素

class App extends React.Component {
  render(){
    return (
      <div>
      hello
      </div>
    );
  }
}

转变这样

_createClass(App, [{
    key: 'render',
    value: function render() {
      return React.createElement("div", null, "hello");
    }
}]);

如果写成多个元素

class App extends React.Component {
  render(){
    return (
      <div>
      hello
      </div>
      <h1>more</h1>
    );
  }
}

其将会装换为

_createClass(App, [{
    key: 'render',
    value: function render() {
      return React.createElement("div", null, "hello");
      return React.createElement("h1", null, "more");
    }
}]);

其实际上不会转换成功(将会报错 Adjacent JSX elements must be wrapped in an enclosing tag)其方法return两次,这显然是错误

解决方法
1.父元素包裹
render() {
  return (
    <div>
      <h1>foo</h1>
      <h2>bar</h2>
    </div>
  );
}
2.采用 Fragment

在 React v16.2+以上版本中可以才用Fragment片段的方式

render() {
    return (
      <React.Fragment>
        <td>Hello</td>
        <td>World</td>
      </React.Fragment>
    );
}  
3.短语法 <> </>
render() {
    return (
      <>
        <td>Hello</td>
        <td>World</td>
      </>
    ); 
}


jsx部分 其转换为
React.createElement(React.Fragment, null, 
    React.createElement("td", null, "Hello"), 
    React.createElement("td", null, "World")
);    

可以看出 其实际上是React.Fragment的语法糖 可以写成

render() {
  return (
    <React.Fragment>
    <td>Hello</td>
    <td>World</td>
    </React.Fragment>
  );
}
4.返回数组

在 React v16.0+以上版本中可以才用返回数组的方式

render(){
    return [<div key={0}>hello</div>,<div key={1}>world</div>]
}

其会转化为

return [
    React.createElement("div", {key: 0}, "hello"),
    React.createElement("div", {key: 1}, "world")
];
参考资料

Adjacent JSX error

React fragments

每日一问---Class类中this绑定

class类中this绑定

类的方法内部如果含有this,默认指向类的实例,但是一些场景下使用,会导致this的指向偏离预期,所以需要绑定定义时候的this,也就是实例对象

如下

<!--html-->
<button id="btn">click</button>

<!--js-->
const btn = document.getElementById('btn');

class CheckThis {
  constructor(ele) {
    this.ele = ele;
    this.count = 0;
    this.ele.addEventListener('click', this.click);
  }
  click() {
    console.log(this); // DOM
    this.count++;
    console.log(this.count); // NaN
  }
}

const thisInstance = new CheckThis(btn);

在这里click方法中的this指的是dom节点而不是实例对象,

因为addEventListener()将this的指针设置为冒泡事件的DOM元素

相当于

var m = this.click;
this.ele.addEventListener('click', m) //此时m函数中this的指向创建事件的元素

再看一个例子

import React, { PureComponent } from 'react';
class Index extends PureComponent {
    testHandle(){
       console.log(this); // undefined
    };
    reder(){
        return (
            <Button onClick={this.testHandle}>click</Button>
        )
    }
}

React事件为合成事件,class并不会为方法自动绑定this到当前对象上,再由于class 内部是严格模式,所以 this 实际指向的是undefined,为避免这种this指向问题有几种方法来解决这种问题

1.使用箭头函数

直接在React元素中采用箭头函数

1
2
3
4
5
6
7
8
9
10
11
import React, { PureComponent } from 'react';
class Index extends PureComponent {
testHandle(){
console.log(this); // Index实例对象
};
reder(){
return (
<Button onClick={(event)=>this.testHandle(event)}>click</Button>
)
}
}

因为箭头函数中的this指向的是函数定义的对象,所以可以保证this总是指向当前组件的实例对象
优化点:直接在render方法中为元素事件定义事件的处理函数,每次render调用时,都会创建一个新的事件处理函数,带来额外的性能开销

2.组件方法

直接将组件的方法赋值给元素的事件属性,同时在类的构造函数中,将这个方法的this绑定到当前对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React, { PureComponent } from 'react';
class Index extends PureComponent {
constructor(props){
super(props);
this.state={}
this.testHandle = this.testHandle.bind(this);
}
testHandle(){
console.log(this); // Index实例对象
};
reder(){
return (
<Button onClick={this.testHandle}>click</Button>
)
}
}

这种方式的好处是每次render不会重新创建一个回调函数,没有额外的性能损失。但在构造函数中,为事件处理函数绑定this, 尤其是存在多个事件处理函数需要绑定时,这种模板式的代码还是会显得烦琐。而且对于函数传递参数来说不太方便

1
2
3
4
5
6
7
8
9
10
11
12
import React, { PureComponent } from 'react';
class Index extends PureComponent {
testHandle(params){
console.log(this,params); // Index实例对象, { test: '1' };
};
reder(){
const params = { test: '1' };
return(
<Button onClick={this.testHandle.bind(this,params)}>click</Button>
)
}
}

这种方式依然存在每次render都会创建一个函数的问题,但在需要为处理传递额外参数提供便利

3.属性初始化语法

使用ES 7的property initializers会自动为class中定义的方法绑定this

1
2
3
4
5
6
7
8
9
10
11
12
import React, { PureComponent } from 'react';
class Index extends PureComponent {
testHandle = (params)=>{
console.log(this,params); // Index实例对象, { test: '1' };
};
reder(){
const params = { test: '1' };
return(
<Button onClick={this.testHandle}>click</Button>
)
}
}

这种方式既不需要在构造函数中手动绑定this, 也不需要担心组件重复渲染导致的函数重复创建问题。但是, property initializers这个特性还处于试验阶段, 默认是不支持的,不过, 使用官方脚手架Create React App创建的项目默认是支持这个特性的。你也可以自行在项目中引入babel的transform-class-properties插件获取这个特性支持。

参考资料

引用 React+进阶之路