amenzai / myDiary

Record what you do every day
4 stars 0 forks source link

一些值得记录的知识点 #78

Open amenzai opened 5 years ago

amenzai commented 5 years ago

空格字符

当中文和英文混杂的时候,使用 ,  等空格实现冒号的完美对齐还是有些困难的,除非英文使用的是等宽字体,于是乎,我们就可以使用普通的 空格做英文字符的宽度调节。

再科普点关于字符的实用知识吧:

  1. HTML中字符输出使用&#x配上charCode值;
  2. 在JavaScript文件中为防止乱码转义,则是\u配上charCode值;
  3. 而在CSS文件中,如CSS伪元素的content属性,直接使用\配上charCode值。

因此,想在HTML/JS/CSS中转义“我”这个汉字,分别是:

  1. 我
  2. \u6211, 如console.log('\u6211');
  3. \6211, 如.xxx:before { content: '\6211'; }

考虑到直接 这种形式暴露在HTML中,可能会让屏幕阅读器等辅助设备读取,从而影响正常阅读流,因此,我们可以进一步优化下,使用标签,利用伪元素,例如:

.half:before { content: '\2002'; speak: none; }
.full:before { content: '\2003'; speak: none; }
amenzai commented 5 years ago

纯函数

一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用,我们就把这个函数叫做纯函数。

// bad 依赖外部参数
const a = 1
const foo = (b) => a + b
foo(2) // => 3

// good
const a = 1
const foo = (x, b) => x + b
foo(1, 2) // => 3
// good
const a = 1
const foo = (obj, b) => {
  return obj.x + b
}
const counter = { x: 1 }
foo(counter, 2) // => 3
counter.x // => 1

// bad
const a = 1
const foo = (obj, b) => {
  obj.x = 2
  return obj.x + b
}
const counter = { x: 1 }
foo(counter, 2) // => 4
counter.x // => 2

除了修改外部的变量,一个函数在执行过程中还有很多方式产生外部可观察的变化,比如说调用 DOM API 修改页面,或者你发送了 Ajax 请求,还有调用 window.reload 刷新浏览器,甚至是 console.log 往控制台打印数据也是副作用。

amenzai commented 5 years ago

移动端知识

设备像素 & CSS像素 & 设备独立像素

设备像素比

注意,当我们放大或者缩小屏幕的时候,window.devicePixelRatio是可变的

layout viewport

在IOS中layout viewport默认大小980px,在android中layout viewport为800px,很明显这两个值都大于我们浏览器的可视区域宽度。我们可以通过document.documentElement.clientWidth来获取layout viewport的宽度

visual viewport

有了layout viewport,我们还需要一个viewport来表示我们浏览器可视区域的大小,这个就是visual viewport。visual viewport的宽度可以通过window.innerWidth获取。

ideal viewport

这个viewport就叫做ideal viewport。但是不同的设备的ideal viewport不一样,有320px,有360px的,还有384px的......

vw & vh & vmin & vmax

touch 事件

避免 300ms 延迟:

点击穿透:

解决:不要混用 touch 和 click

amenzai commented 5 years ago

页面跳转到真实网址: <meta http-equiv="refresh" content="0;url=http://www.baidu.com/">

amenzai commented 5 years ago

函数式编程

简介

在函数式编程中,函数就是一个管道(pipe)。这头进去一个值,那头就会出来一个新的值,没有其他作用。

函数式编程有两个最基本的运算:合成和柯里化。

合成

如果一个值要经过多个函数,才能变成另外一个值,就可以把所有中间步骤合并成一个函数,这叫做"函数的合成"(compose)。

const compose = function (f, g) {
  return function (x) {
    return f(g(x));
  };
}

柯里化

所谓"柯里化",就是把一个多参数的函数,转化为单参数函数。

// 柯里化之前
function add(x, y) {
  return x + y;
}

add(1, 2) // 3

// 柯里化之后
function addX(y) {
  return function (x) {
    return x + y;
  };
}

addX(2)(1) // 3

函数式编程与命令式编程对比

假设我们想打印一个数组中所有的元素。我们可以用命令式编程,声明的函数如下:

var printArray = function(array) {
  for (var i = 0; i < array.length; i++) {
    console.log(array[i]);
  }
};
printArray([1, 2, 3, 4, 5]);

把这个例子转换成函数式编程:

// 负责迭代数组的函数
var forEach = function(array, action) {
  for (var i = 0; i < array.length; i++) {
    action(array[i]);
  }
};
// 接下来,我们要创建另一个负责把数组元素打印到控制台的函数
var logItem = function (item) {
  console.log(item);
};

// 最后,像下面这样使用声明的函数:
forEach([1, 2, 3, 4, 5], logItem);

有几点要注意:

有了ES2015的新功能,用JavaScript进行函数式编程变得更加容易了

JavaScript函数式工具箱—— map、filter和reduce

amenzai commented 5 years ago

算法复杂度

大O表示法,用于描述算法的性能和复杂程度。

当讨论大O表示法时,一般考虑的是CPU(时间)占用。

amenzai commented 5 years ago

路由

// 页面路由
window.location.href = 'http://www.baidu.com';
history.back();

// hash 路由
window.location = '#hash';
window.onhashchange = function(){
    console.log('current hash:', window.location.hash);
}

// h5 路由
// 推进一个状态
history.pushState('name', 'title', '/path');
// 替换一个状态
history.replaceState('name', 'title', '/path');
// popstate
window.onpopstate = function(){
    console.log(window.location.href);
    console.log(window.location.pathname);
    console.log(window.location.hash);
    console.log(window.location.search);
}

router.jsx

// react-router
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom'

class A extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
        return (
            <div>
            Component A

            <Switch>
                <Route exact path={`${this.props.match.path}`} render={(route) => {
                    return <div>当前组件是不带参数的A</div>
                }}/>
                <Route path={`${this.props.match.path}/sub`} render={(route) => {
                    return <div>当前组件是Sub</div>
                }}/>
                <Route path={`${this.props.match.path}/:id`} render={(route) => {
                    return <div>当前组件是带参数的A, 参数是:{route.match.params.id}</div>
                }}/>
            </Switch>
            </div>
        )
    }
}

class B extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
        return <div>Component B</div>
    }
}

class Wrapper extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
        return (
            <div>
                <Link to="/a">组件A</Link>
                <br/>
                <Link to="/a/123">带参数的组件A</Link>
                <br/>
                <Link to="/b">组件B</Link>
                <br/>
                <Link to="/a/sub">/a/sub</Link>
                {this.props.children}
            </div>
        );
    }
}

ReactDOM.render(
    <Router>
        <Wrapper>
            <Route path="/a" component={A}/>
            <Route path="/b" component={B}/>
        </Wrapper>
    </Router>,
    document.getElementById('app')
);
amenzai commented 5 years ago

react lifecircle

import React from 'react';
import ReactDOM from 'react-dom';

class Component extends React.Component{
    // 构造函数
    constructor(props){
        super(props)
        this.state = {
            data: 'Old State'
        }
        console.log('初始化数据','constructor');
    }
    // 组件将要加载
    componentWillMount(){
        console.log('componentWillMount');
    }
    // 组件加载完成
    componentDidMount(){
        console.log('componentDidMount');
    }
    // 将要接收父组件传来的props
    componentWillReceiveProps(){
        console.log('componentWillReceiveProps');
    }
    // 子组件是不是应该更新
    shouldComponentUpdate(){
        console.log('shouldComponentUpdate');
        return true;
    }
    // 组件将要更新
    componentWillUpdate(){
        console.log('componentWillUpdate');
    }
    // 组件更新完成
    componentDidUpdate(){
        console.log('componentDidUpdate');
    }
    // 组件即将销毁
    componentWillUnmount(){
        console.log('componentWillUnmount');
    }
    // 处理点击事件
    handleClick(){
        console.log('更新数据:');
        this.setState({
            data: 'New State'
        });
    }
    // 渲染
    render(){
        console.log('render')
        return (
            <div>
                <div>Props: {this.props.data}</div>
                <button onClick={()=>{this.handleClick()}}>更新组件</button>
            </div>
        );
    }
}

class App extends React.Component{
    // 构造函数
    constructor(props){
        super(props)
        this.state = {
            data: 'Old Props',
            hasChild: true
        }
        console.log('初始化数据','constructor');
    }
    onPropsChange(){
        console.log('更新props:');
        this.setState({
            data: 'New Props'
        });
    }
    onDestoryChild(){
        console.log('干掉子组件:');
        this.setState({
            hasChild: false
        });
    }
    render(){
        return (
        <div>
            {
                this.state.hasChild ? <Component data={this.state.data}/> : null
            }
            <button onClick={()=>{this.onPropsChange()}}>改变Props</button>
            <button onClick={()=>{this.onDestoryChild()}}>干掉子组件</button>
        </div>
        );
    }
}

ReactDOM.render(
    <App/>,
    document.getElementById('app')
);
amenzai commented 5 years ago

postcss

构建工具

function postcssTask() {
    return gulp.src().pipe(postcss[autoprefixer({}), cssnano])
}

css modules in webpack

rules: [{
    test: /\.css$/,
    use: ['style-loader', {
        loader: 'css-loader',
        options: {
            modules: true
        }
    }]
}]

angular vue 内置样式集成。

vue

react

amenzai commented 5 years ago

作用域

作用域指一个变量的作用范围。它是静态的(相对于上下文对象), 在编写代码时就确定了。

作用:隔离变量,不同作用域下同名变量不会有冲突。

全局作用域

直接编写在script标签中的JS代码,都在全局作用域。

函数作用域 调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁。每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的。

执行上下文

函数执行上下文

在调用函数, 准备执行函数体之前, 创建对应的函数执行上下文对象(虚拟的, 存在于栈中)。

  1. 对局部数据进行预处理
形参变量==>赋值(实参)==>添加为执行上下文的属性

arguments==>赋值(实参列表), 添加为执行上下文的属性

var定义的局部变量==>undefined, 添加为执行上下文的属性

function声明的函数 ==>赋值(fun), 添加为执行上下文的方法

this==>赋值(调用函数的对象)
  1. 开始执行函数体代码

执行上下文栈

1.在全局代码执行前, JS引擎就会创建一个栈来存储管理所有的执行上下文对象 2.在全局执行上下文(window)确定后, 将其添加到栈中(压栈) 3.在函数执行上下文创建后, 将其添加到栈中(压栈) 4.在当前函数执行完后,将栈顶的对象移除(出栈) 5.当所有的代码执行完后, 栈中只剩下window

作用域与执行上下文的区别

全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了。而不是在函数调用时

全局执行上下文环境是在全局作用域确定之后, js代码马上执行之前创建

函数执行上下文是在调用函数时, 函数体代码执行之前创建

作用域是静态的, 只要函数定义好了就一直存在, 且不会再变化

执行上下文是动态的, 调用函数时创建, 函数调用结束时就会自动释放

联系

执行上下文(对象)是从属于所在的作用域

全局上下文环境==>全局作用域

函数上下文环境==>对应的函数使用域

amenzai commented 5 years ago

Q1 你的技术栈主要是react,那你说说你用react有什么坑点?

  1. JSX做表达式判断时候,需要强转为boolean类型,如:
    render() {
    const b = 0;
    return <div>
    {
      !!b && <div>这是一段文本</div>
    }
    </div>
    }
  2. 尽量不要在 componentWillReviceProps 里使用 setState,如果一定要使用,那么需要判断结束条件,不然会出现无限重渲染,导致页面崩溃。
  3. 给组件添加ref时候,尽量不要使用匿名函数,因为当组件更新的时候,匿名函数会被当做新的prop处理,让ref属性接受到新函数的时候,react内部会先清空ref,也就是会以null为回调参数先执行一次ref这个props,然后在以该组件的实例执行一次ref,所以用匿名函数做ref的时候,有的时候去ref赋值后的属性会取到null。
  4. 遍历子节点的时候,不要用 index 作为组件的 key 进行传入。
amenzai commented 5 years ago

JS bridge

image