Open amenzai opened 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 往控制台打印数据也是副作用。
设备像素 & 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
页面跳转到真实网址:
<meta http-equiv="refresh" content="0;url=http://www.baidu.com/">
简介
map
方法和reduce
方法组合而成 MapReduce 算法。在函数式编程中,函数就是一个管道(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
大O表示法,用于描述算法的性能和复杂程度。
当讨论大O表示法时,一般考虑的是CPU(时间)占用。
// 页面路由
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')
);
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')
);
构建工具
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
<div abcdef>
div[abcdef]{}
react
作用域指一个变量的作用范围。它是静态的(相对于上下文对象), 在编写代码时就确定了。
作用:隔离变量,不同作用域下同名变量不会有冲突。
全局作用域
直接编写在script标签中的JS代码,都在全局作用域。
函数作用域 调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁。每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的。
函数执行上下文
在调用函数, 准备执行函数体之前, 创建对应的函数执行上下文对象(虚拟的, 存在于栈中)。
形参变量==>赋值(实参)==>添加为执行上下文的属性
arguments==>赋值(实参列表), 添加为执行上下文的属性
var定义的局部变量==>undefined, 添加为执行上下文的属性
function声明的函数 ==>赋值(fun), 添加为执行上下文的方法
this==>赋值(调用函数的对象)
执行上下文栈
1.在全局代码执行前, JS引擎就会创建一个栈来存储管理所有的执行上下文对象 2.在全局执行上下文(window)确定后, 将其添加到栈中(压栈) 3.在函数执行上下文创建后, 将其添加到栈中(压栈) 4.在当前函数执行完后,将栈顶的对象移除(出栈) 5.当所有的代码执行完后, 栈中只剩下window
作用域与执行上下文的区别
全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了。而不是在函数调用时
全局执行上下文环境是在全局作用域确定之后, js代码马上执行之前创建
函数执行上下文是在调用函数时, 函数体代码执行之前创建
作用域是静态的, 只要函数定义好了就一直存在, 且不会再变化
执行上下文是动态的, 调用函数时创建, 函数调用结束时就会自动释放
联系
执行上下文(对象)是从属于所在的作用域
全局上下文环境==>全局作用域
函数上下文环境==>对应的函数使用域
Q1 你的技术栈主要是react,那你说说你用react有什么坑点?
render() {
const b = 0;
return <div>
{
!!b && <div>这是一段文本</div>
}
</div>
}
空格字符
当中文和英文混杂的时候,使用
 
, 
等空格实现冒号的完美对齐还是有些困难的,除非英文使用的是等宽字体,于是乎,我们就可以使用普通的
空格做英文字符的宽度调节。再科普点关于字符的实用知识吧:
&#x
配上charCode值;\u
配上charCode值;content
属性,直接使用\
配上charCode值。因此,想在
HTML/JS/CSS
中转义“我”这个汉字,分别是:我
\u6211
, 如console.log('\u6211');
\6211
, 如.xxx:before { content: '\6211'; }
考虑到直接
 
这种形式暴露在HTML中,可能会让屏幕阅读器等辅助设备读取,从而影响正常阅读流,因此,我们可以进一步优化下,使用标签,利用伪元素,例如: