chenweiyang

导航

 

    web(World Wide Web)

           即全球广域网,也称为万维网,它是一种基于超文本和HTTP的、全球性的、动态交互的、跨平台的分

    布式图形信息系统。是建立在Internet上的一种网络服务,为浏览者在Internet上查找和浏览信息提供了图

    形化的、易于访问的直观界面,其中的文档及超级链接将Internet上的信息节点组织成一个互为关联的网状

    结构。

    

//////////////////

// this.setState //

//////////////////

异步:

    1. react 本身的事件

    2. 在 生命周期里 setState 都是异步的

同步:

    1. 原生事件

    2. setTimetou setTimeInteval

    3. axios 回调里

 

///////////////////////

// index 可以当 key //

///////////////////////

 * 怎么解决这个问题: shortid 或者 唯一的 id

 * 怎么实现一个类似的 shortid 

    getId = () => Math.random()

    shortId 封装: 数据中人为添加id: shortId

 

///////////

//  路由  //

///////////

 * 文件拆出   所有路由拆出一个文件

 * Switch组件,确保路由只匹配一个页面

 * link 跳转   navlink 带class属性的跳转

 * 路由传参  query 和 动态路由

    query  直接拼接  使用 location.search获取,获取可以直接qs.parse()解析

    动态路由  路由后设置动态变量  使用 this.props.match.params.动态变量 获取

 

/////////////////////////

///  redux状态管理  ////

////////////////////////

 * 流程 view->action->reduce->渲染   (只有一个store,单一数据源)

 

 * redux 与 react-redux

    redux(状态管理)  --  react-redux(react版本状态管理)

 

 * 使用流程:

    { createStore (创建store) , combineReducers (合并reducer) } from redux

    { Provider } from react-redux

    

    cons defaultState = { } //state默认值

    function list ( state = defaultState , action ){

      //处理数据逻辑

      switch ( ) {

        case '处理逻辑名'://case值唯一,匹配时会全局查找

          return { ...state( 用于备份state,防止冲突 ) , name: action.payload };

        default :

          break ;

      }

    }

 

    var myReducers = combineReducers ({ list })

 

    const action = {

        type: '选择要操作的逻辑',

        payload: '转递参数'

    }

 

    var store = createStore ( myReducers )

    

    store.dispatch (action)//调用action

 

    <Provider store = { store }>

         包裹项目

    </Provider>

 

 * 组件内使用redux

    import { connect } from 'react-redux'

    import { xxx } from '/action/xxx'

    17之前 

            connect( 

 state => { value: state.reducer( .value ) },

{ xxx (引入的action) }

            )( 组件 )

     17之后

           @connect( state =>({

              value: state.reducer( .value )

            }), {

              xxx ( 引入的reducer )

            }

          ) 组件

 

 * redux-promise 插件

    action 中只能写同步代码

    使action中,可以直接使用axios请求,并直接返回请求到的数据

    const action = {

      type: '选择要操作的逻辑',

      payload: axios.get( url )

    }

    //先当于在action中,直接取到 axios.get( url ).then( res=> {}) 中的res

                                                                                                                       

 

//////////////

// flex 布局 //

//////////////

 

 * 使用 flex: 1; 时,为防止溢出导致布局变化,在布局方向上添加

     width: 1px 或 height: 1px

 

////////////////////

//// 数据持久化 ////

////////////////////

 

 *  import { persistStore } from 'redux-persist'

     import { PersistGate } from 'redux-persist/lib/integration/react'

     /////////  index.js配置  //////////

 

     ////////  reducer持久化需要配置   ////////

 * import { persistReducer } from 'redux-persist'

    import  storage  from 'redux-persist/lib/storage'

    import  sessionStorage  from 'redux-persist/lib/storage/session'

    import  autoMergeLevel2  from 'redux-persist/lib/stateReconciler/autoMergeLevel2'

    

    import  doData  from './reducers/doData'  // reducer

 

    //需要对哪些 state 持久化

    const rootPersistConfig = {

      key: 'root',

      storage: sessionStorage,//storage 类型

      stateReconciler:autoMergeLevel2,    // 层级

      whiteList: ['doData']   //白名单 想让谁持久,就放谁

    }

 

    //抽离一个需要持久化的公共 reducer

    const myPersistReducer = persistReducer(

      rootPersistConfig,

      doData

    )

 

    const store = createStore(

      myPersistReducer,

      composeEnhancers(

        applyMiddleware(promise)

      )

    )

 

    <Provider store = { store }>

        <PersistGate loading = { null } persistor={ PersistStore( store ) }>

             包裹项目

        </Provider>

    </Provider>

 

 * redux-thunk -- 以函数的形式写action

    import { redux-thunk } from 'redux-thunk'

 

    export function getxxx () {

        return dispatch => {

            dispatch({

                type: ' getList ',

payload: ' 参数 '

            })

        }

    }

 

    applyMiddleware( redux-thunk )       //注意将中间件添入

 

////////////////

/////node /////

////////////////

 

 * npm view 插件 versions   //查看插件版本

 

/////////////////

///    antd     ///

/////////////////

 

 * Form 表单回填  ( antd 版本3 )

 

    Form.create({

      mapPropsToFields( props ) {

        return {

          username: Form.createFormField({

            value: '65464',

          }),

          password: Form.createFormField({

            value: '98798797',

          })

        }

      }

    })( 组件名 )

 

////////////////////////

/// React 生命周期 ////

///////////////////////

 * 16.4

    1. 加载阶段: constructor( ),render( ),componentDidMount( )

    2. 更新阶段: componentWillReceiveProps( ),shouldComponentUpdate( ),render( ),

                         componentWillUpdate( ),componentDidUpdate( )

    3. 卸载阶段: componentWillUnmount( )

 

 * 16.4 之后: 

    加载阶段: consructor( ),getDerivedStateFromProps( ),render( ),componentDidMount( )

    更新阶段: getDerivedStateFromProps( nextProps, prevState ),shouldComponentUpdate( ),render( ),

                getSnapshotBeforeUpdate( prevProps, prevState ),componentDidUpdate( )

    卸载阶段: componentWillUnmount( )

 

    注意: getSnapshotBeforeUpdate( prevProps, prevState ),

             getDerivedStateFromProps( nextProps, prevState )    //两者都必须有返回值

             state或者props改变就触发

             比较props的值是否有改变

             

 

///////////////

///    es6    ///

///////////////

 

 * includes():返回布尔值,表示是否找到了参数字符串。

    startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。

    endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。

 

 * this : 代表当前执行的对象

 

 *  constructor(){ }   //构造过程    new 的过程也是构造

    // 创建一个空对象{ }

    // 执行构造器

    // 把所有的 this 替换成 { }

    // 最终返回 空对象

 

 * var xxx = ( ) => { }     // 被定义之后,this产生并固定不变

 

 * 箭头函数 与 普通函数 -- 区别

    //箭头函数 没有 arguments

    //箭头函数 不能当构造器使用

    //箭头函数 没有自己的this

    //箭头函数 this 是在定义的时候就不变了

 

 * 数组扩展方法

    map()    // 返回新数组,长度与原数组长度相同

    filter()    // 返回新数组,返回符合条件的数据

    reduce()    //两个参数,第一个参数是回调函数,第二个参数为默认第一项值

    find()    //返回真 结束循环 并把当前值返回

    findIndex()    //返回真 结束循环 并把当前值的下标返回

    for of    // 数组中值的循环

 

 * 对象扩展方法

    keys()    //遍历key值返回为一个数组

    entries(){}    //将对象变为二维数组 每一对key和值变为一个数组

     is

    深浅拷贝

    Object.assign() , { ...obj }     //浅拷贝

    JSON.parse( JSON.stringify( obj ) )    //可以实现深拷贝存在bug

    // 过滤undefined

    // 如果对象中有function,拷贝后的对象会丢失这个function

    // 如果对象中存在循环引用的情况也无法正确实现深拷贝

    递归 , lodash    //深拷贝

 

 * Symbol 变量

    // 具有唯一性  多用于object的key

 

 * Promise

    //解决回调地狱

    //三种状态: 进行中 已成功 已失败

 

    const promise = new Promise(( resolve, reject ) => {

        resolve( '成功' )

        reject( '失败' )

    })

    //resolve()    回调函数(成功)

    //reject()    回调函数(失败)

 

    链式操作    // 等待上一个promise改变状态后再执行下一个

    promise

        .then(res => {

            console.log( res )        // 打印resolve()中的 '成功'

        })

        .catch(err => {

            console.log( err )        // 打印reject()中的 '成功'

        })

 

    Promise.all ([promise, promise2]).then( res => {

        console.log(res)// 所有promise返回resolve时,才执行

//失败时,只返回失败项的状态

    })

    Promise.race ([promise, promise2]).then( res => {

        console.log(res)// 此状态为最先改变的promise的状态

    })

 

    Promise.resolve( 任意类型 )  快速创建一个成功的promise 参数为then打印的参数值

    Promise.reject( 任意类型 )  快速创建一个失败的promise 参数为catch打印的参数值

 

 * Generator 

    const promise = new Promise(( resolve, reject ) => {

        resolve( '成功' )

        reject( '失败' )

    })

    function* fn() {

        yield promise

        yield 'hello'

    }

    const f = fn()

    console.log( f.next() )//返回{ value:'xxx', done: false }

    console.log( f.next() )//返回{ value:'xxx', done: false }

    console.log( f.next() )//返回{ value:'undefined', done: true } done为true,结束

    f.next(参数)//参数为上一个yield的返回值

 

 * 宏任务 - 微任务

    宏任务: setTimeout setInterval

    微任务: resolve reject await

    同步任务

 

    同步任务 > 微任务 > 宏任务    //优先级

 

 * event loop 事件循环机制

    1.先执行同步任务

    2.微任务调用栈[resolve(1), resolve(2), resolve(3)] await

    3.宏任务: setTimeout setInterval I/O(异步操作) DOM渲染

 

 * async

    含义:相对于Promise链式操作与Generator的优化,使得异步操作更加方便,返回值为

    Promise对象

    内部与await联合使用,await后面的任务会等到await代码执行完之后再执行

    await 接收任意类型 通常接收异步方法 

    const data = await promise()    //用变量接收值,等同于执行一个then,若状态为失败,

    则需用.catch()接收返回,此时data接收失败的值,并且后面的await不会执行

    推荐写法 try{

        data = await promise()

    } catch(e) {

        console.log()

    }

 

 * async 原理

    async === Generator + 自动执行器

    function spawn (genF) {

        return new Promise(resolve => {

            const gen = genF()

            function step (nextF) {

                let next = nextF()

                if (next.done) {

                    return resolve(next.value)

                }

                step(() => gen.next(next.value))

            }

            step(() => gen.next(undefined))

        })

     }

 

 * 类

    class Person {

        constructor(username, sex) {//构造器 constructor

            this.name = username

            this.sex = sex

        }

    }

 

    constructor 构造过程

    1. 创建一个空对象{ }

    2. 执行构造器

    3. 把所有的 this 替换成 { }

    4. 最终返回 空对象

 

    继承 

    class Animals {

        static eye = 'eye'//静态属性    (静态也可以继承)

        moues = 'moues'

    }

    class Person extends Animals {

        constructor() {

            super()//继承的子类是没有this的,需要通过super方法将父级的this拿过来

        }

    }

 

///////////////

///// git //////

///////////////

 

 * svn, git:版本管理工具  github:面向个人'

 

    * 配置git//新机器必备

        git config --global user.email"用户登录邮箱"

        git config --global user.name"用户名"

 

    1. 创建项目  

        git init//项目托管给git

        git add .

        git commit -m "说明性注释"//创建提交

 

    2. 提交项目

        git commit -m "说明性注释"//创建提交

        git push -u origin master//提交分支到gitHub(远程)

 

    3.配置公钥私钥

        ssh-keygen -t rsa -C '用户登录邮箱'//创建公钥

        cat ···/.ssh/id_rsa.pub//打开公钥(钥匙文件所在文件夹下打开)

        gitHUB页面中setting设置公钥//将文件中的密钥复制到gitHub

 

    4.查看修改与提交  (常用)

        git status//查看git那些文件修改

        git add (文件名/.)//保存文件修改到本地

        git commit -m "说明性注释"//创建提交

        git status//再次查看文件是否无修改

        git push origin master (master是分支名)//往远程提交分支文件

 

    * 常用分支指令

        git log//查看日志

        git checkout -b 本地分支名 origin/master//创建分支

        git checkout 分支名//切换分支

        git branch -v//查看本地分支

        git branch -a//查看远程分支

        git config --list//查看账号信息

 

    * 开发常用

        git stash / git stash save '说明性注释'//暂存修改(文件回复到修改前)

        git stash list//查看缓存列表

        git stash apply / apply stash@{0}//回到最近(或指定)存储

        git stash clear//清除缓存

        git diff <file>//查看当前修改文件

        git clone (gitHub地址)//复制拉取文件

        git pull origin master(远程分支)//同步远程项目

        git fetch//拉取远程分支同步到本地

        git reset --hard hash值//撤回提交

        git push -f origin master//强制提交

        git checkout .//撤销修改

 

    * 合并分支

        git add (文件名/.)//保存文件修改到本地

        git commit -m "说明性注释"//创建提交

        git checkout 分支名//切换分支

        git merge 需要合并的分支名//将其他分支合并到当前分支

        

///////////////////////

//react 项目创建流程//

///////////////////////

 

    1.npx create-react-app name

    2.配置文件夹,路由,页面,组件等

    3.配置router文件夹,包含 index.js(主路由文件) 与 assembly.js(抛出路由组件)

    4.删除不必要的文件,index.js中删除App相关,并引入主路由 router/index.js

    5.配置conifg-overrides.js(项目配置文件/webpack配置文件)

       替换package.json中的scripts配置,并安装配置相关依赖

       "scripts": {

           "start": "react-app-rewired start --open",

           "build": "react-app-rewired build",

           "test": "react-app-rewired test",

           "eject": "react-app-rewired eject"

       },"scripts": {

           "start": "react-app-rewired start --open",

           "build": "react-app-rewired build",

           "test": "react-app-rewired test",

           "eject": "react-app-rewired eject"

       },

    6.安装less@3.11.1 与 less-loader@5.0.0,更改index.js引入index.css为index.less

 

/////////////

//  Hook  //

////////////

 

 * class组件达到瓶颈,复用组件逻辑复杂(使用高阶函数),hook的主要用途就是复用状态逻辑

 

 * Hook(是函数、没有生命周期)

 

 * Hook常用钩子

    1.useState:

        const = [ val, setVal ] = useState(默认值)//定义useState

        setVal()//设置useState中的值(异步)

        setVal( pre => { return xxx }  )//拿到上一次的值

        const = [ val, setVal ] = useState( ( ) => {

            初始值有复杂逻辑时写法

            return xxx

        })

    2.useEffect:

        useEffect( () => {

 

            //逻辑代码

            return () => { 卸载阶段 }

 

        }, [ 依赖项 ] )//依赖项中为监听值,没有监听值只执行一次,相当于DidMount

//依赖多个值,只要一个改变,就触发,监听后相当于更新期

 

 * 注意事项:

    Hook 只能写在函数组件

    Hook 只能写在顶层,不能写在 if for中,hook按顺序解析;Hook的调用顺序在每次渲染中都是相同的

    Hook 自定义hook,以use开头或者以函数组件的形式

 

 * createRef 与 useRef

    const myRef = React.createRef( )//每次都返回一个新对象

    console.log( myRef.current )//不可以加属性,只有current属性

    <div ref={ myRef }></div>

 

    const ref = useRef ( 初始值 )//只执行一次,可记录上一次的值,始终返回同一个对象

    console.log( ref.current )//不一定只有current属性

 

 * memo//返回一个新组件  机制与PureComponent相似,执行时做比较优化

    const A = memo(function(){

        return(

            <div>AAA</div>

        )

    })

    <A />

    useMemo( 回调, [ 依赖 ]) => 返回值取决于return//多用于缓存,函数体立刻执行

    useCallback( 回调, [ 依赖 ]) => 返回新函数         //比较函数,相同就缓存通常与memo连用,函数体需要调用执行

 

    redux-react-hook//配合useReducer使用的插件

 

/////////

// vue //

/////////

 

 * 安装 npm i @vue-cli

    vue create hello-world 

 

 * 配置文件夹,路由,页面,组件等 

    npm i element-ui -S

    npm install babel-plugin-component -D//按需引入

 

 * data() {

        return {

            //项目中的数据

        }

    }

 

 * methods: {

        //项目函数

    }

 

 * watch: {

        data中的现有数据 : {

            监听触发的函数

        }

    }

 

 * computed: {//缓存,同时可以监听多个值

        data中的现有数据 : {

            监听触发的函数

        }

    }

 

 * filters: {//过滤值

        filter(price) {

            return `$${price}`

        }

    }

    {{ price | filter(price) }}

 

 * components: {

        引入的组件

    }

    父传子

    父:<A :price="price"/>

    子:props: [ 'price' ],

 

    子传父

    子:methods: {

        onclick(){

            this$emits('aaa(触发事件名)',{

                返回值

            })

        }

    }

    <div @click='onclick'></div>

    父:methods: {

        onAAA(obj){

            console.log(obj)

        }

    }

    <A @aaa(触发事件名)='onAAA'></div>

 

 * slot

    <A>aaa</A>//拿到在父组件中,子组件的公共部分

    子:

    <slot/>

 

 * keep-alive //缓存,避免加载浪费性能

    <keep-alive></keep-alive>

    activated(){}//激活

    deactivated(){}//暂停

 

 * router

    this.$router.push('/ ')//跳转

    this.$router.push({name: ''})

    const routes = [

      {

          path: '/',

          name: 'Home',

          component: Home,

      },

      {

          path: '/about',

          name: 'About',

          component: () => import('../views/about/About.vue')

      }

    ]

    const router = new VueRouter({

        mode: 'history',

        base: process.env.BASE_URL,

        routes

    })

    export default router

 

 * vuex

    store/index.js//配置store

    state: {//默认值

        code: 1,

        data: []

    },

    mutations: {//同步修改  只能在mutations中修改state  触发 commit

        //同步代码不能写异步

        setCode ( state, action ) {

            console.log()

            state = action

        }

        setDataList ( state, action ) {

            state.data = action

        }

    },

    actions: {//异步操作  触发 dispatch

        getDataList ({ commit }) {

            const data = axios.get('url')

            commit( 'setDataList', data )

            commit( 'home/setDataList', data, {root: true})//调用别的方法

        }

    },

    modules: {

        //引入拆出的模块

    }

 

    页面组件

    import { mapState, mapMutations, mapActions } from 'vuex'//引入store中的配置

    methods: {

        ...mapMutations([

            'setCode',//在Mutations中提取方执行方法

        ]),

        ...mapMutations('home',[

            'setCount',//在拆出部分中提取方执行方法actions同理

        ]),

        ...mapActions([

            'getDataList',//在Mutations中提取方执行方法

        ]),

        onclick() {

            this.setCode(传值)//使用提取出来的方法处理数据

        }

    }

    computed: {//在computed中取store的state值

        ...mapState(['code', 'data']),

        ...mapState('home',[ 'count' ]),//引入拆出模块的state

        ...mapState('home',{

            homeCount: 'count',//重名时,别名方法

        })

    }

 

///////////////

///溢出省略///

///////////////

 * 单行溢出省略

    overflow: hidden;

    white-space: nowrap;

    text-overflow: ellipsis;

 

 * 多行溢出省略

    overflow: hidden;

    display: -webkit-box;

    -webkit-line-clamp: 2;//行数

    -webkit-box-orient: vertical;

 

 * 中间截取省略

    overflow: hidden;

    display: -webkit-box;

    -webkit-box-orient: vertical;

    -webkit-line-clamp: 2;//行数

    text-indent: -40px;//缩进

 

/////////////

//面试常问//

/////////////

 

 * z-index//需要position才能生效

    0,0 点//相对于设置position最近的父元素

//如果没有position父元素,以document定位

//relative的0,0点相对于父元素计算

 

 * 粘性定位

    position: sticky;

 

 * 事件注册

    addEventListener( ' ', function( ){ }, false ) 

    //事件;触发函数;在哪个阶段触发( false,冒泡;true,捕获 )

 

 * 事件传递方式

    捕获阶段 -> 目标阶段 -> 冒泡阶段

 

 * 跨域

    (浏览器)同源策略:协议,域名,端口,只要一项不同就会跨域

    JSONP    CORS后台设置请求头    设置代理 http-proxy-middleware

    上线后项目不是node,使用nginx反向代理

    

 * 为什么请求要放在componentDidMoutn()

    this.setState() 需要在DOM渲染完之后才能执行

 

    // await 微任务 promise

    // 4 1 3 6 8 2 7 5//执行顺序

    async function async1() {

        console.log(1)

        await async2() // reoslve()

        console.log(2)

    }

    async function async2() {

        console.log(3)

    }

    console.log(4)

    setTimeout( function () {

        console.log(5)

    }, 0)

    async1();

    new Promise(function ( resolve ) {

        console.log(6)

        resolve();

    }).then( function () {

        console.log(7)

    })

    console.log(8)

 

 * viewport//主要用于移动设备

    width = device-width//宽度为设配屏幕的宽度

    initial-scale = 1.0//初始缩放比例

    minimum-scale = 0.5//最小缩放比例

    maximum-scale = 2.0//最大缩放比例

    user-scalable = yes//用户是否可以调整缩放

 

 * 浏览器内核

    chrome: Blink

    FireFox: Gecko

    Opera: Blink

    Safari: Webkit

 

 * 路由权限

    pt: 登录 首页

    vip : 登录 首页 详情

    sipv: 登录 首页 详情 用户列表

 

    1. 本地存 { pt: [], vip: [], sivp: [] }

    2. 登录后台返回权限 通过权限 拿到这个用户能访问的路由数组

    3. 全局路由拦截 [].includes(pathname)

 

 * HTML5

    canvas  svg  video  audio  localStorage  sessionStorage  webSocket  pushState  replaceState

 

 * 清除浮动的2中方法

    //内浮动

    :after 

    :before{ clear: both }

 

 * 新增伪类

    :after    :before    :checked    :focus    :nth-child    :last-child    :first-child

 

 * 手动动画最小间隔

    1/60*1000ms = 16.7ms

 

 * css3动画

    transform ( 通过事件触发 )

    animation ( 不通过事件触发 )

 

 * 如何使用CSS实现硬件加速, GPU渲染 

    transfrom: translate3D(100, 0, 0): 写上Z轴 会使用伪 GPU渲染

    will-change: 绝对的GPU渲染

 

 * websoket

    跟后台进行通信 创建长连接

    const ws = new Websocket(url)

    ws -> httpwss -> https

    # 四个事件

        open 连接建立时触发

        message客户端服务端数据时触发

        error通信发生错误时触发

        close 连接关闭时触发

    # 两个方法

        ws.send()

        ws.close()

 

 * js继承

    继承概念:通过某种方式让一个对象可以访问到另一个对象的属性和方法,把这种方式称之为继承

    作用:获取更多的拓展,减少代码的冗余等。

 

    ### 原型链继承

    function Person(){

            this.name = '邓紫棋'

        }

        Person.prototype.getName = function(){

            console.log(this.name)

        }

        function Child(){

            

        }

        Child.prototype = new Person()

        var child1 = new Child()

        child1.getName()// 邓紫棋

    缺点:

        通过原型来实现继承时,原型会变成另一个类型的实例,原先的实例属性变成了现在的原型属性,该原型的引

    用类型属性会被所有的实例共享。

        在创建子类型的实例时,没有办法在不影响所有对象实例的情 况下给超类型的构造函数中传递参数

 

    ###借用构造函数继承

     // 借用构造函数继承(经典继承)

    function Person(){

        this.colors = ['red', 'blue', 'green']

    }

    function Child(){

        Person.call(this)

    }

    var child1 = new Child()

    child1.colors.push('yellow')

    console.log(child1.colors)// ["red", "blue", "green", "yellow"]

    var child2 = new Child()

    console.log(child2.colors)// ["red", "blue", "green"]

    优点:

        可以向超类传递参数

        解决了原型中包含引用类型值被所有实例共享的问题

    缺点:

        方法都在构造函数中定义,函数复用无从谈起,超类型原型中定义的方法对于子类型而言都是不可见的。

 

    ###组合继承(借用构造函数继承+原型链继承)

    function Parent (name) {

        this.name = name

        this.colors = ['red', 'blue', 'green']

    }

    Parent.prototype.getName = function () {

        console.log(this.name)

    }

    function Child (name, age) {

        Parent.call(this, name)

        this.age = age

    }

    Child.prototype = new Parent()

    var child1 = new Child('kevin', '18')

    console.log(child1)//Parent { name: 'kevin', colors: [ 'red', 'blue', 'green' ], age: '18' }

    优点:

        可以向超类传递参数

        每个实例都有自己的属性

        实现了函数复用

    缺点:

        无论什么情况下,都会调用两次超类型构造函数:一次是在创建

        子类型原型的时候,另一次是在子类型构造函数内部

 

    ###原型式继承

    function Wonman(name){

        let instance = new People()

        instance.name = name || 'wangxiaoxia'

        return instance

    }

    let wonmanObj = new Wonman()

    缺点:同原型链实现继承一样,包含引用类型值的属性会被所有实例共享。

 

    ###寄生式继承

    function createAnother(original){

        var clone = Object.create(original)   //通过调用函数创建一个新对象

        clone.sayHi = function(){            //以某种方式来增强这个对象

        alert("Hello")

    } 

        return clone          //返回这个对象

    }

    var person = {

        name: "Bob",

        friends: ["Shelby", "Court", "Van"]

    }

    var anotherPerson = createAnother(person)

    anotherPerson.sayHi()

    缺点:

        使用寄生式继承来为对象添加函数,会由于不能做到函数复用而效率低下。同原型链实现继承一样,包含

    引用类型值的属性会被所有实例共享。

 

    ###寄生组合式继承

    function Parent(name,play){

        this.name=name;

        this.play=play;

    }

    function Child(name,play,age){

        Parent.call(this,name,play);

        this.age=age;

    }

    // 隔离了父类和子类的构造函数,父类的添加到了__proto__属性上

    Child.prototype=Object.create(Parent.prototype);

    Child.prototype.constructor=Child

    let child=new Child("张三","玩",20);

    let child2=new Child("李四","吃",10)

    console.log(child.constructor)

    优点:

        只调用了一次超类构造函数,效率更高。避免在 SuberType.prototype上面创建不必要的、多余的属

    性,与其同时,原型链还能保持不变。

 

 * web前端性能优化

    ## 页面内容 

        1.减少HTTP 

            · 通过 webpack 合并JS CSS文件

            · 使用 CSS Sprite 合并图片 

            · 使用 Base64 行内图片 

            · 用 icon 替换图标

        2. 避免重定向 

            · URL末尾添加 / 例如 http://www.baidu.com/ 

        3. 缓存Ajax请求 

            · 设置 Cache-Control (相对过期时间) 

        4. 减少页面元素数量 

    ## CSS 

        1. react vue 可以实现css样式按需加载, 减少每次加载CSS的大小 

        2. 压缩CSS 

        3. 使用CSS3属性 例如动画使用 transform transiton animtion 

    ## Javascript 

        1. JS代码尽量放在页面底部, 避免阻塞页面加载 

        2. 使用外部的CSS 可以缓存CSS

        3. webpack 压缩 js代码 

    ## 图片

        1. CSS Sprite 合并图片 

        2. Webp 图片 

        3. 不在HTML中缩放图片 

        4. 非 webp 图片都要压缩后再使用 

        5. 使用 Base64 内嵌图片

    ## react || vue 

        · 路由懒加载 

        · vue 组件异步加载 

    ## 服务器 

        1. 使用 CDN(内容分发网络CDN是一组分散在不同地理位置的web服务器) 

        2. 添加 Cache-Control 缓存头 

        3. 启用 Gzip 压缩 (图片不要gzip压缩) 

        4. Ajax 尽可能使用 get方法, post方法会多一次请求 

        5. 避免  空图片标签 

    ## 移动端 

        1. 保证所有组件都小于25K

 

 * 链表

    单向链表:单向链表包含两个域一个是信息域一个是指针域

    双向链表:每个节点有2个指针域一个是指向前一个节点另一个则指向后一个节点

    循环链表:循环链表就是首节点和末节点被连接在一起,循环链表中第一个节点之前就是最后一个节点

    数组和链表的区别:

        链表是链式的存储结构数组是顺序的存储结构

        链表通过指针来连接元素数组则是把所有元素按次序依次存储

        链表的插入删除元素相对数组较为简单但是寻找某个元素较为困难

        数组寻找某个元素较为简单但插入与删除比较复杂

    自我理解:

        数组便于查询和修改但是不方便新增和删除

        链表适合新增和删除但是不适合查询

 

 * 防抖 节流

    所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,

    则会重新计算函数执行时间。

    import _ from 'lodash'

    const id = useRef()

    const fn = () => {

        clearTimeout( id.current )

        id.current = setTimeout(( ) => {

console.log()

        }, 1000)

    }

    <input onKeyDown={ fn }/>

 

    import _ from 'lodash'

    const id = useRef()

    const fn = () => {

        console.log()

    }

    <input onKeyDown={_.debounce(fn, 1000)} />

 

    所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数

    import _ from 'lodash'

    const id = useRef()

    const fn = () => {

        if( !id.current ) {

            id.current = setTimeout(( ) => {

                id.current = null

                console.log()

            }, 1000)

        }

        console.log()

    }

    <input onKeyDown={_.debounce(fn, 1000)} />

 

    resize//窗口变化时触发(事件)

 

    window.addEventListener('scroll', _.throttle(evt => {

        document.querySelector('p').innerHTML =  

        document.querySelector('body').scrollTop || document.querySelector('html').scrollTop

    }, 200), false)

 

 * 判断引用数据类型

    Object. prototype. toString.call (对象)

 

 * 事件代理

    currentTarget(获取注册事件的节点)

 

 * http状态码

    200:表示客户端发来的请求在服务器端被正确处理

    201:请求成功并且服务器创建了新的资源。 

    202:接受请求但没创建资源

    203:返回另一资源的请求

 

    301:永久性重定向,表示资源已被分配了新的url

    302:临时重定向,表示资源临时分配了新的url

    303:表示资源存在着另一个url,应使用get方法获取资源

    304:表示服务器允许访问资源,但因发生请求未满足条件的情况

 

    400:请求报文存在语法错误

    401:表示发送的请求需要通过HTTP认证的认证信息

    403:表示对请求资源的访问被服务器拒绝

    404:表示在服务器上没有找到请求的资源

 

    500:表示服务器端在执行请求时发送了错误

    501:表示服务器不支持当前请求所需要的的某个功能

    503:表示服务器暂时除余超负载或正在停机维护

 

 * 从输入URL 到页面展现

    根据地址栏输入的地址向DNS(Domain Name System)查询IP

    通过IP向服务器发起TCP连接

    向服务器发起请求

    服务器返回请求内容

    浏览器开始解析渲染页面并显示

    关闭连接

     # 通过DNS解析获得对应的IP地址

        1. 浏览器缓存——浏览器会缓存DNS记录一段时间(2分钟到30分钟)

        2. 系统缓存——如何浏览器缓存中没有,浏览器会做一个系统系统调用,查找系统缓存中的记录,常

            见的hosts文件

        3. 路由缓存——如果系统缓存也没有需要的记录,会向本地路由器发送一条DNS查询请求,一般会有

            自己的dns缓存

        4. ISP DNS缓存——如果本地路由器没有再查看本地网络提供商(移动啦、电信啦)的DNS服务器,

            一般都能找到相应的缓存记录

     # 浏览器向服务器发送一个HTTP请求

        1. 首先通过三次握手建立TCP连接,

        2. 浏览器通过TCP连接向服务器发送一个http请求

     # 服务器发出重定向响应

    1. 在拿到ip地址后, 浏览器会向对应的web服务器(Nginx,Apache...)发起TCP连接请求,通过三次握手,建立

        TCP连接

    2. 建立TCP连接后, 浏览器向web服务器发送Http请求

     # 服务器返回请求内容

        服务器在接收到请求后,解析用户请求,知道了要调度那些资源文件,再通过相应的资源文件,处理用户的请

        求和参数,并调用数据库信息,最后讲结果通过web服务器返回给浏览器.

     # 浏览器开始解析渲染页面并显示

        html 渲染过程

     # 关闭连接

        在这次数据传输完成后,为了避免服务器与客户端双方的资源占用和损耗,会经过四次挥手,关闭TCP连接.

 

 * 浏览器缓存

    强缓存

    Expires: 2020.12.12 8.0 一个绝对时间的 GMT 格式的时间字符串,代表缓存资源的过期时间

    Cache-Control: 2小时 2小时之内你重新请求了一个接口 从你请求这个接口开始 重新计算2小时

                             判断缓存资源的最⼤⽣命周期,它的值单位为秒

    协商缓存  

    If-Modified-Since 过期 2020.12.12 8.0

    ajax('1.php') -> 后台可以拿到过期时间 后台判断 不给返回新数据 300, 有数据200 

    通过⽐较两个时间来判断资源在两次请求期间是否有过修改

    Last-Modified (值为资源最后更新时间,随服务器response返回)

 

 * RESF规范  实现一个接口执行多个操作

 

 * vip权限

    封装权限路由表(数组)

    跳转获取pathname,通过后台的权限,使用includes查看是否包含该pathname,

 

 * 数组合并4种方法

    arr.concat( [] )

    arr.push( ...[] )//返回长度,合成数组为arr

    [ ...arr, ...arr1 ]

    arr.push.apply(arr, [])//返回长度,合成数组为arr

 

 * jekenis 上线

    提交代码到 测试 featur/dev

    提交代码到 测试 featur/pre

    提交代码到 测试 featur/master

 

 * 打包 npm run build

    合并 js css

    react less 转译 js css

    build

        1.FTP

        2.给后台

 

 * 前端数据映射: //解决公共组件 渲染后台 不同接口 返回不同数据的问题

    1. 首先定义一套自己的数据格式 

    2. 把后台接口给的数据转化成我们自己定义的数据格式

    3. 公共组件都适用这套自己定义的数据格式渲染数据

 

////////////////

////问公司/////

////////////////

 

 * 技术栈--详细了解(包括状态管理工具,插件等)

 

 * 假如有幸加入公司,会负责哪些项目

 

 * 公司内部是否有技术分享

 

/////人事/////

 

 * 接下来找工作的想法:

    1. 北京的公司

    2. 稳定可以长期干下去的公司

    3. 技术氛围好的公司

 

 * 你找工作主要看中哪些东西

    1. 技术提升

    2. 薪资是否可以

    3. 公司氛围

 

////////////////////

//react插件、方法//

////////////////////

 

 * React传送门

    ReactDOM.createPortal( fn(), document.querySelector('') )//渲染到root外面

    { children }//通过 children 展示弹框内容

 

 * export const { Provider, Consumer } = createContext()

    <Provider value='wxh'></Provider>

 

 * react-router-config

    import { renderRoutes } from 'react-router-config'

    const Root = ({ route }) => (

        <div>

          <h1>Root</h1>

          {renderRoutes(route.routes)}

        </div>

    )

 

    const routes = [

        {

            component: Root,

            routes:[

                {

                    path: '/home/:id',//动态路由

                    component: Home,

                    routes:[

                        {

                            path: '/home/user',

                            component: Hook

                        }

                    ]

                },

                {

                    path: '/hook',

                    component: Hook

                },

                {

                    path: '/hook2',

                    component: Hook2

                },

            ]

        }

    ]

 

 * import { useHistory, useRouteMatch } from 'react-router-dom'

        子组件中引用

        let match = useRouteMatch('/home/:id')

        let history = useHistory()

 

 * import Masonry from 'masonry-layout'  // 瀑布流

 * import InfiniteScroll from 'react-infinite-scroller' //下拉加载

    state = {

        hasMore: true, // 是否开启下拉加载

        data: [

            { title: '小白' }, 

            { title: '小白' }, 

            { title: '小白' },

            { title: '小白' }, 

            { title: '小白' },

            { title: '小白' }, 

            { title: '小白' },

        ], // 接受我每次的数据

        count: 0,

        width: '',

    }

 

    advanceWidth = () => {//瀑布流配置

        new Masonry(document.querySelector('.content'), {// new Masonry(节点, 配置)

            itemSelector: '.d', // 要布局的网格元素

            fitWidth: true, // 设置网格容器宽度等于网格宽度

            gutter: 20,

            columnWidth: '.d', 

            originLeft: true,

        })

    }

 

    loadMoreData = page => {//下拉加载配置

        const { data, count } = this.state

        if (count && page > Math.ceil(count / 10)) return false

            axios.post('https://api.baxiaobu.com/index.php/home/v5/getuser', { data: { page, limit: 10 } })

            .then(res => {

                this.setState({

                data: [...data, ...data],

                count: res.count,

            })

            this.advanceWidth()

        })

        .catch(err => console.log(err))

    }

 

    <div className="box">

        <InfiniteScroll//下拉加载部分

            initialLoad={false} // 不让它进入直接加载

            pageStart={1} // 设置初始化请求的页数

            loadMore={this.loadMoreData}  // 监听的ajax请求

            hasMore={true} // 是否继续监听滚动事件 true 监听 | false 不再监听

            useWindow={true} // 不监听 window 滚动条 如果你要监听 window 外层不能有任何节点

        >

            <div className="content">

                {

                    this.state.data.map((value, key) => (//瀑布流部分

                        <div key={key} className="d xxx">

                            {value.title}

                        </div>

                    ))

                 }

             </div>

         </InfiniteScroll>

    </div>

 

    .box {

        box-sizing: border-box;

        margin: 0 auto;

        width: 100%;

        height: 100%;

        overflow-x: hidden;

        overflow-y: auto;

        box-sizing: border-box;

        border: 5px #0f0 solid;

        .content {

            width: 100%;

            margin: 0 auto;

            border: 5px #00F solid;

        }

        .xxx {

            width: 200px;

            margin: 0 0 20px 0;

            border: 5px #f00 solid;

        }

        .xxx:nth-child(2n-1) {

            height: 200px;

        }

        .xxx:nth-child(2n) {

            height: 300px;

        }

    }

 

    // columnWidth: 200,

    // itemSelector: '.grid-item'    // 要布局的网格元素

    // gutter: 10    // 网格间水平方向边距,垂直方向边距使用css的margin-bottom设置

    // percentPosition: true   // 使用columnWidth对应元素的百分比尺寸

    // stamp:'.grid-stamp'    // 网格中的固定元素,不会因重新布局改变位置,移动元素填充到固定元素下方

    // fitWidth: true    // 设置网格容器宽度等于网格宽度,这样配合css的auto margin实现居中显示

    // originLeft: true // 默认true网格左对齐,设为false变为右对齐

    // originTop: true // 默认true网格对齐顶部,设为false对齐底部

    // containerStyle: { position: 'relative' } // 设置容器样式

    // transitionDuration: '0.8s'    // 改变位置或变为显示后,重布局变换的持续时间,时间格式为css的时间格式

    // stagger: '0.03s'   // 重布局时网格并不是一起变换的,排在后面的网格比前一个延迟开始,该项设置延迟时间  

    // resize:  false // 改变窗口大小将不会影响布局

    // initLayout: true // 初始化布局,设未true可手动初试化布局

 

 * npm i imagesloaded -S//等图片加载

 

    imagesOnload = () => {//等待图片加载

        // 初始化你要监听哪个节点下的图片

        const elLoad = imagesLoaded('.content')

        // always 页面图片全部加载完 不管有没有加载失败的图片

        elLoad.on('always', (instance, image) => {

            // 图片加载后执行的方法

            // 拿第一次的数据

            this.advanceWidth() // 初始化瀑布流

        })

    }

 

 * 图片瀑布流

    1. 元素设置 absolute

    2. 获取浏览器宽度 和 卡片的宽度, 浏览器的宽度 / 卡片宽度 = 有几列

    const imglist = [img, img, img, img, ...]

    const arr = [

        [{ url: '图片路径', position: {top: 100px, left: 40px} }], // 100px

        [img, img], // 80 + 20 = 100

        [img, img], // 60 + 70 = 130

        [img], // 120

    ]

   

    arr.forEach(v => {

        v.forEach(v2 => {

            v2.img + v2.img

        })

    })

    // 2 80 + 20 = 100

    arr[1].push(imglist[5])

 

    arr.map(v => {

        v.map(v2 => {

            <img src={v2.url} style={{top: v2.position.top, left: v2.position.left}}

        })

    })

    3. onresize 

    获取浏览器宽度 和 卡片的宽度, 浏览器的宽度 / 卡片宽度 = 有几列

    const imglist = [img, img, img, img, ...]

    const arr = [

        [{ url: '图片路径', position: {top: 100px, left: 40px} }], // 100px

        [img, img], // 80 + 20 = 100

        [img, img], // 60 + 70 = 130

    ]

 

///////////////

////  dva  ////

//////////////

 

 * dva === redux-sage + roadhog

    npm i dva-cli -g//安装dva-cli

    dva new name//创建dva应用

 

 * .webpackrc.js//webpackrc改为js文件

    export default {//配置webpackrc.js文件

        publicPath: '/',

        extraBabelPlugins: [

            ['import', { 'libraryName': 'antd', 'libraryDirectory': 'es', 'style': 'css' }],

        ],

        alias: {

            '@': `${__dirname}/src`,

            '@@': `${__dirname}/src/components`

        },

        proxy: {

            '/aps': {

                target: 'https://api.baxiaobu.com',

                changeOrigin: true,

                pathRewrite: {

                    '^/aps': '',

                }

            },

            '/api': {

                target: 'https://blogs.zdldove.top',

                changeOrigin: true,

                pathRewrite: {

                    '^/api': '',

                }

            },

        }

    }

 

 * 在routes中创建assembly.js、router.js同react一样配置路由

    在router.js中引入异步加载路由

    import dynamic from 'dva/dynamic'

 

    function RouterConfig({ history, app }) {//注意引入app

        const Home = dynamic({

            app,

            models: () => [//引入model,数组形式

                import('@/models/home')

            ],

            component: () => import('@/pages/home'),//引入组件

        })

        return (

            <Router history={history}>

                <Switch>

                    <Route path="/" exact component={Home} />

                </Switch>

            </Router>

        )

    }

 

    export default RouterConfig

 

 * model

    export default {

        namespace: 'home',

 

        state: {

            data: []

        },

 

        subscriptions: {

            setup({ dispatch, history }) {  // eslint-disable-line

            },

        },

 

        effects: {//处理异步

             *fetch({ payload }, { call, put, select }) {  //select拿到上一次的数据,里面也是函数

                  const xx = yield call(() => {做请求})//call中是函数,相当于一个await

                  yield put({//put === dispatch

                      type: '',

                      payload: ''

                  })

              },

        },

 

        reducers: {//修改state

            home/setName (state, { payload }) {

                return { ...state, data: payload }

            },

        },

    }

    组件中使用connect连接组件

    connect(

        state => {

            return { dataName: state.home.data }

        }

    )(Home)

 

    this.props.dispatch({//通过props.dispatch调用

        type: 'home/setName',

        payload: 'xla'

    })

 

 * subscriptinos: {//订阅 初始化数据

        xxx ({ history, dispatch }) {

            history.listen(({ pathname }) => {

const regexp = pathToRegexp( '/home' ).test(pathname)

            })

        }

    }

    //pathToRegexp将路由自动转为正则

 

    model中路由跳转

    router from 'umi/router'

    put( routerRedux.push('/xxx') )

 

/////////////////

///typescript///

////////////////

 

 * npx create-react-app tsDemo --typescript//ts react项目搭建

    tsconfig.json 配置

    {

        "compilerOptions": {

        "target": "es5", // 指定 ECMAScript 版本

        "lib": [

            "dom",

            "dom.iterable",

            "esnext"

        ],

        "outDir": "lib",

        "allowJs": true, // 允许编译 JavaScript 文件

        "skipLibCheck": true,

    // 禁用命名空间引用 (import * as fs from "fs") 启用 CJS/AMD/UMD 风格引用 (import fs from "fs")

        "esModuleInterop": true,

        "allowSyntheticDefaultImports": true,

        "strict": true,

        "forceConsistentCasingInFileNames": true,

        "module": "esnext",

        "moduleResolution": "node",

        "resolveJsonModule": true,

        "isolatedModules": true,

        "noEmit": true,

        "jsx": "react",

        "declaration": true

    },

        "include": [

            "src/**/*"

        ],

        "exclude": ["node_modules", "build"] // *** 不进行类型检查的文件 ***

    }

 

 * 声明变量

    let/const/var xxx : 数据类型 = xxx

    let/const/var arr : 数据类型[ ] = [ ]//数组

    let/const/var arr : (number, string) [ ] = [ ]//数组联合类型

    let/const/var arr : any = xxx//任意类型

    let/const/var arr : number | boolean | null = xxx//联合类型(允许值为其中一种类型)

 

    let xxx: [number, boolean] = [1, true]

 

    enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat}//枚举 值只能为string或number

 

    function name (xxx: string, xxx:number ): void {

        //void: 表示一个函数没有任何一个返回值

    }

 

    function name (xxx: string, xxx:string ): string 

    function name (xxx: number, xxx:number ): number 

    function name (xxx: any, xxx:any ): any {//函数重载

 

    }

 

 * class类

    class Person {

        name: string

        age: number

        constructor(n: string, a: number){//需初始化

            this.name = n

            this.age = a

        }

    }

    Person('wxh', 20)

 

 * interface//接口不可实例化可继承(仅可继承一个, 接口可实现多个)

    interface A {

        可设置对象、函数等接口(规定接口中有哪些变量或属性)

    }

    implements//实现接口

    interface 可以继承类,但是constructor,静态方法、属性不会继承

 

    //接口只能定义规则,但抽象类可以设置公共的属性和方法

 

 * abstract//抽象类不可实例化

    abstract Person {

        name: string

        constructor(n: string){//需初始化

            this.name = n

        }

    }

 

 * 泛型

    泛型函数

    function fun<T> (opt: T): T {//传入什么类型,返回什么类型

        return opt

    }

    console.log(fun<string>('123'))

    console.log(fun('123'))

 

    function fun2<T> (opt: T[]): T[] {//传入什么类型,返回什么类型

        return opt

    }

    console.log(fun<string>(['1', '2', '3']))

    泛型类

    class Person<T> {

        private count: T[]

        constructor(arr: T[]) {

            this.count = arr

          }

        minRun(): T {

            let minValue = this.count[0]

            this.count.forEach(v => {

                if(v < minValue) {

                    minValue = v

                }

            })

            return minValue

        }

    }

    const person = new Person<number>([1, 2, 3])

    person.minRun()// 1

    泛型接口

    interface Kind<T> {

        (arg: T, n: T): T

    }

    const fn: Kind<number> = function<t> (arg: T, n: T): T{

        return arg

    }

    fn(123, 456)

 

 

////////////

// mobx //

///////////

 * npm i mobx -S//安装mobx插件

 

 * import { observable } from 'mobx'//可观察数据(监听)

    //4.0以前

    const num = observable.box(11)

    num.get()//获取值

    num.set()//修改值

 

    //引用数据类型

    const arr = observable([1, 2, 3])

    arr[2] = 4

    const obj = observable({name: 'wxh'})

    obj.name = 'wbl'

    //避免下标越界访问数组

 

 * import { computed, } from 'mobx'//监听数据变化

    class kuuga {

        observable str = 'wxh'

        @computed get com() {//使用数据时触发

            console.log('获取')

        }

        set com(){//更改数据时触发

            console.log('更改')

        }

    }

    const Kuuga = new kuuga()

    console.log(Kuuga.com)//触发get com()

    Kuuga.str = 'hdr'//触发set com()

 

 * autorun 当任意可观察数据修改时触发

 

 * when(() => {

        return boolean

    },() => {})

 

 * @action xxx() {}//能将多次autorun合并为一次

    @action.bound xxx() {}//效果相当于bind(),用于改变指向

 

/////////////

//设计模式//

/////////////

 

 * 发布-订阅模式

    var saleOffices = {//发布-订阅模式

        clientList: [],

 

        listen (fn){         //订阅函数

            this.clientList.push(fn)

        },

 

        trigger(price, square) {    //发布函数

            this.clientList.forEach(fn => {

                fn(price, square)

            })

        }

    }

 

    saleOffices.listen((price, square) => {

        console.log('王小红'+price, square)

    })

 

    saleOffices.listen((price, square) => {

        console.log('好多肉'+price, square)

    })

 

    saleOffices.listen((price, square) => {

        console.log('沈年年'+price, square)

    })

 

    saleOffices.trigger(8000, 120)       

 

 * 传参判断版

    var saleOffices = {

        clientList: {},

 

        listen (kind, fn){        //订阅函数    kind表示订阅分类,函数表示订阅后要做什么

            if(!this.clientList[kind]){

                this.clientList[kind] = []//判断是否存在该订阅类型

            }

            this.clientList[kind].push(fn)//存在就添加

        },

 

        trigger(kind, price, square) {    //发布函数

            this.clientList[kind].forEach(fn => {//遍历该类型的所有方法

                fn(price, square)

            })

        }

    }

 

    saleOffices.listen('square120' ,(price, square) => {//订阅时传入订阅类型和执行函数

        console.log('王小红'+price, square)

    })

 

    saleOffices.listen('square120', (price, square) => {

        console.log('好多肉'+price, square)

    })

 

    saleOffices.listen('square130', (price, square) => {

        console.log('沈年年'+price, square)

    })

 

    saleOffices.trigger('square120', 8000, 120)

 

 

/////////////////

// 函数柯里化 //

////////////////

 

    function fun() {

      const arr = []

 

      return opt => {

          if (opt) {

              arr.push(opt)

          } else {

              let sum = 0

              arr.forEach(v => {

              sum += v

          })

          return sum

      }

  }

}

 

const fn = fun()

 

fn(10)

fn(20)

fn(30)

fn(40)

console.log(fn())

 

////////////////////////////

//pushState replaceState//

////////////////////////////

    state: 可通过 history.state读取

    title: 可选参数,暂时没有用,建议传个短标题

    url: 改变后的 url 地址 /abc

 

    let { history } = window//window中的history

    export default function Home (props) {

        const onClick = () => {

            var _wr = function(type) {

            var orig = history[type]

            return function() {

                var rv = orig.apply(this, arguments)

                var e = new Event(type)

                e.arguments = arguments

                window.dispatchEvent(e)

                return rv

            }

        }

        history.pushState = _wr('pushState')

        history.replaceState = _wr('replaceState')

    

        // 监听 history.pushState

        window.addEventListener('pushState', function(e) {

            if ('page1') {

        

            }

            // history.state 直接拿 pushState 第一个参数

            console.log(history.state, 2)

        })

 

        history.pushState({ page: 1 }, 'title1', 'page1')

        history.replaceState({page: 2}, "title 3", 'page2')

    }

 

        return (

            <div className="pages-home">

                <Button onClick={onClick}>点我</Button>

            </div>

        )

    }

 

//////////////////////////

//redux - promise原理//

/////////////////////////

 

// 判断一个变量是不是 promise

import isPromise from 'is-promise'

// 是不是 FSA

// FSA: 定义 action 标准 { type, payload, error, meta }

// 必须有 type, 

// 可能有 payload, error, meta

import { isFSA } from 'flux-standard-action'

 

// redux-promise

export default function promiseMiddleware(_ref) {

    // next === 下一个中间件 或者 dispatch

    // 首先返回一个函数 接收一个参数 这个参数是下一个中间件 或者 dispatch

    return function (next) {

        return function (action) {

            // 判断是不是标准的 FSA 

            // 标准的 FSA 只包含4个属性 type payload error meta

            if (!isFSA(action)) {

                /**

                 * 判断是不是promise,

                 * 如果是则执行,只会处理resolve的值,

                 * 反之交给下一个中间件

                 */

                return isPromise(action) ? action.then(dispatch) : next(action);

            }

 

            // 是标准的FSA, 判断是不是一个promise

            return isPromise(action.payload)

                /**

                 * 1.promise的时候,执行then,同时捕获异常,

                 * 在处理这两种情况以后,会分别添加另外一个约束error

                 * 这我们需要在reducer里面还需要判断error的值,

                 * 做不同的处理

                 * 

                 * 2. 如果不是promise则交给下一个中间件

                 * */

                // promise

                // action.payload === axios.get('http://www.baidu.com')

                ? action.payload

                    // result 就是我们请求接口的数据

                    .then(result => {

                        _ref.dispatch({ ...action, payload: result })

                    })

                    .catch(error => {

                        _ref.dispatch({ ...action, payload: error, error: true });

                        return Promise.reject(error);

                    })

                : next(action);

        }

    };

}

 

///////////////////

/////  BFC  ///////

//////////////////

 

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8" />

<meta name="viewport" content="width=device-width, initial-scale=0.5" />

<meta name="description" content="Web site created using create-react-app" />

<title>React App</title>

<style>

.d0 {

  border: 10px #F00 solid;

  width: 200px;

  /* float: left; */

  /* position: absolute; */

  /* display: inline-block; */

  /* display: table-cell; */

  overflow: hidden;

}

.d1 {

  background: #9F9;

  height: 100px;

  width: 100%;

  float: left;

}

*{

  margin: 0;

  padding: 0;

}

p {

  color: #FFF;

  background: rgb(214, 125, 9);

  width: 200px;

  line-height: 100px;

  text-align:center;

  margin: 0 0 30px 0;

}

.div {

  overflow: hidden;

  border: 1px #F00 solid;

}

div p {

  margin: 30px 0 0 0;

}

</style>

 

</head>

<body>

<div id="root"></div>

<div class="d0">

  <div class="d1"></div>

</div>

 

<p>看看我的 margin是多少</p>

<div class="div">

  <p>看看我的 margin是多少</p>

</div>

</body>

</html>

 

BFC: 块格式化上下文

 

变成BFC:

  浮动元素 (元素的 float 不是 none)

  绝对定位元素 (元素具有 position 为 absolute 或 fixed)

  内联块 (元素具有 display: inline-block)

  表格单元格 (元素具有 display: table-cell,HTML表格单元格默认属性)

  具有overflow 且值不是 visible 的块元素

 

BFC特性:

  使 BFC 内部浮动元素不会到处乱跑;

  和浮动元素产生边界。

 

<script>

</script>

 

///////////////

/// 修饰器 ///

//////////////

 

//target === MyTestableClass

function testable(isTestable) {

  return function fun(target) {

    target.isTestable = isTestable

  }

}

 

//装饰class用

@testable('wxh')

class MyTestableClass {

 

}

 

console.log(MyTestableClass.isTestable)

// MyTestableClass.isTestable

 

@testable(false)

class Myclass {}

 

console.log(Myclass.isTestable)

// Myclass.isTestable

 

//////////////////

//postMessage//

//////////////////

    //跨域传值

 * 父路由

    <iframe src='http://localhost:3001' name='a1' />

    document.onclick = function() {

        window.frames['a1'].postMessage('狼来了', 'http://localhost:3001')

    }

    window.addEventListener('message', function(e) {

        console.log(e.origin, 1)

        console.log(e.data, 2)

    })

 

 * 子路由

    window.addEventListener('message', function (e) {

        console.log(e.origin, 1)

        console.log(e.data, 2)//传递的内容

        window.top.postMessage('没来', 'http://localhost:3000')

    })

 

/////////////

/// Umi ////

////////////

    npm create @umijs/umi-app

    npm i

 

    .umirc.ts//配置路由及其他

    pages//存放路由文件

 

 

 

 

 

 

 

 

 

    web(World Wide Web)           即全球广域网,也称为万维网,它是一种基于超文本和HTTP的、全球性的、动态交互的、跨平台的分    布式图形信息系统。是建立在Internet上的一种网络服务,为浏览者在Internet上查找和浏览信息提供了图    形化的、易于访问的直观界面,其中的文档及超级链接将Internet上的信息节点组织成一个互为关联的网状    结构。    //////////////////// this.setState ////////////////////异步:    1. react 本身的事件    2. 在 生命周期里 setState 都是异步的同步:    1. 原生事件    2. setTimetou setTimeInteval    3. axios 回调里
///////////////////////// index 可以当 key ///////////////////////// * 怎么解决这个问题: shortid 或者 唯一的 id * 怎么实现一个类似的 shortid     getId = () => Math.random()    shortId 封装: 数据中人为添加id: shortId
/////////////  路由  ///////////// * 文件拆出   所有路由拆出一个文件 * Switch组件,确保路由只匹配一个页面 * link 跳转   navlink 带class属性的跳转 * 路由传参  query 和 动态路由    query  直接拼接  使用 location.search获取,获取可以直接qs.parse()解析    动态路由  路由后设置动态变量  使用 this.props.match.params.动态变量 获取
////////////////////////////  redux状态管理  //////////////////////////// * 流程 view->action->reduce->渲染   (只有一个store,单一数据源)
 * redux 与 react-redux    redux(状态管理)  --  react-redux(react版本状态管理)
 * 使用流程:    { createStore (创建store) , combineReducers (合并reducer) } from redux    { Provider } from react-redux        cons defaultState = { } //state默认值    function list ( state = defaultState , action ){      //处理数据逻辑      switch ( ) {        case '处理逻辑名'://case值唯一,匹配时会全局查找          return { ...state( 用于备份state,防止冲突 ) , name: action.payload };        default :          break ;      }    }
    var myReducers = combineReducers ({ list })
    const action = {        type: '选择要操作的逻辑',        payload: '转递参数'    }
    var store = createStore ( myReducers )        store.dispatch (action)//调用action
    <Provider store = { store }>         包裹项目    </Provider>
 * 组件内使用redux    import { connect } from 'react-redux'    import { xxx } from '/action/xxx'    17之前             connect(  state => { value: state.reducer( .value ) },{ xxx (引入的action) }            )( 组件 )     17之后           @connect( state =>({              value: state.reducer( .value )            }), {              xxx ( 引入的reducer )            }          ) 组件
 * redux-promise 插件    action 中只能写同步代码    使action中,可以直接使用axios请求,并直接返回请求到的数据    const action = {      type: '选择要操作的逻辑',      payload: axios.get( url )    }    //先当于在action中,直接取到 axios.get( url ).then( res=> {}) 中的res                                                                                                                       
//////////////// flex 布局 ////////////////
 * 使用 flex: 1; 时,为防止溢出导致布局变化,在布局方向上添加     width: 1px 或 height: 1px
//////////////////////// 数据持久化 ////////////////////////
 *  import { persistStore } from 'redux-persist'     import { PersistGate } from 'redux-persist/lib/integration/react'     /////////  index.js配置  //////////
     ////////  reducer持久化需要配置   //////// * import { persistReducer } from 'redux-persist'    import  storage  from 'redux-persist/lib/storage'    import  sessionStorage  from 'redux-persist/lib/storage/session'    import  autoMergeLevel2  from 'redux-persist/lib/stateReconciler/autoMergeLevel2'        import  doData  from './reducers/doData'  // reducer
    //需要对哪些 state 持久化    const rootPersistConfig = {      key: 'root',      storage: sessionStorage,//storage 类型      stateReconciler:autoMergeLevel2,    // 层级      whiteList: ['doData']   //白名单 想让谁持久,就放谁    }
    //抽离一个需要持久化的公共 reducer    const myPersistReducer = persistReducer(      rootPersistConfig,      doData    )
    const store = createStore(      myPersistReducer,      composeEnhancers(        applyMiddleware(promise)      )    )
    <Provider store = { store }>        <PersistGate loading = { null } persistor={ PersistStore( store ) }>             包裹项目        </Provider>    </Provider>
 * redux-thunk -- 以函数的形式写action    import { redux-thunk } from 'redux-thunk'
    export function getxxx () {        return dispatch => {            dispatch({                type: ' getList ',payload: ' 参数 '            })        }    }
    applyMiddleware( redux-thunk )       //注意将中间件添入
/////////////////////node /////////////////////
 * npm view 插件 versions   //查看插件版本
////////////////////    antd     ////////////////////
 * Form 表单回填  ( antd 版本3 )
    Form.create({      mapPropsToFields( props ) {        return {          username: Form.createFormField({            value: '65464',          }),          password: Form.createFormField({            value: '98798797',          })        }      }    })( 组件名 )
/////////////////////////// React 生命周期 /////////////////////////// * 16.4    1. 加载阶段: constructor( ),render( ),componentDidMount( )    2. 更新阶段: componentWillReceiveProps( ),shouldComponentUpdate( ),render( ),                         componentWillUpdate( ),componentDidUpdate( )    3. 卸载阶段: componentWillUnmount( )
 * 16.4 之后:     加载阶段: consructor( ),getDerivedStateFromProps( ),render( ),componentDidMount( )    更新阶段: getDerivedStateFromProps( nextProps, prevState ),shouldComponentUpdate( ),render( ),                getSnapshotBeforeUpdate( prevProps, prevState ),componentDidUpdate( )    卸载阶段: componentWillUnmount( )
    注意: getSnapshotBeforeUpdate( prevProps, prevState ),             getDerivedStateFromProps( nextProps, prevState )    //两者都必须有返回值             state或者props改变就触发             比较props的值是否有改变             
//////////////////    es6    //////////////////
 * includes():返回布尔值,表示是否找到了参数字符串。    startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。    endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
 * this : 代表当前执行的对象
 *  constructor(){ }   //构造过程    new 的过程也是构造    // 创建一个空对象{ }    // 执行构造器    // 把所有的 this 替换成 { }    // 最终返回 空对象
 * var xxx = ( ) => { }     // 被定义之后,this产生并固定不变
 * 箭头函数 与 普通函数 -- 区别    //箭头函数 没有 arguments    //箭头函数 不能当构造器使用    //箭头函数 没有自己的this    //箭头函数 this 是在定义的时候就不变了
 * 数组扩展方法    map()    // 返回新数组,长度与原数组长度相同    filter()    // 返回新数组,返回符合条件的数据    reduce()    //两个参数,第一个参数是回调函数,第二个参数为默认第一项值    find()    //返回真 结束循环 并把当前值返回    findIndex()    //返回真 结束循环 并把当前值的下标返回    for of    // 数组中值的循环
 * 对象扩展方法    keys()    //遍历key值返回为一个数组    entries(){}    //将对象变为二维数组 每一对key和值变为一个数组     is    深浅拷贝    Object.assign() , { ...obj }     //浅拷贝    JSON.parse( JSON.stringify( obj ) )    //可以实现深拷贝存在bug    // 过滤undefined    // 如果对象中有function,拷贝后的对象会丢失这个function    // 如果对象中存在循环引用的情况也无法正确实现深拷贝    递归 , lodash    //深拷贝
 * Symbol 变量    // 具有唯一性  多用于object的key
 * Promise    //解决回调地狱    //三种状态: 进行中 已成功 已失败
    const promise = new Promise(( resolve, reject ) => {        resolve( '成功' )        reject( '失败' )    })    //resolve()    回调函数(成功)    //reject()    回调函数(失败)
    链式操作    // 等待上一个promise改变状态后再执行下一个    promise        .then(res => {            console.log( res )        // 打印resolve()中的 '成功'        })        .catch(err => {            console.log( err )        // 打印reject()中的 '成功'        })
    Promise.all ([promise, promise2]).then( res => {        console.log(res)// 所有promise返回resolve时,才执行//失败时,只返回失败项的状态    })    Promise.race ([promise, promise2]).then( res => {        console.log(res)// 此状态为最先改变的promise的状态    })
    Promise.resolve( 任意类型 )  快速创建一个成功的promise 参数为then打印的参数值    Promise.reject( 任意类型 )  快速创建一个失败的promise 参数为catch打印的参数值
 * Generator     const promise = new Promise(( resolve, reject ) => {        resolve( '成功' )        reject( '失败' )    })    function* fn() {        yield promise        yield 'hello'    }    const f = fn()    console.log( f.next() )//返回{ value:'xxx', done: false }    console.log( f.next() )//返回{ value:'xxx', done: false }    console.log( f.next() )//返回{ value:'undefined', done: true } done为true,结束    f.next(参数)//参数为上一个yield的返回值
 * 宏任务 - 微任务    宏任务: setTimeout setInterval    微任务: resolve reject await    同步任务
    同步任务 > 微任务 > 宏任务    //优先级
 * event loop 事件循环机制    1.先执行同步任务    2.微任务调用栈[resolve(1), resolve(2), resolve(3)] await    3.宏任务: setTimeout setInterval I/O(异步操作) DOM渲染
 * async    含义:相对于Promise链式操作与Generator的优化,使得异步操作更加方便,返回值为    Promise对象    内部与await联合使用,await后面的任务会等到await代码执行完之后再执行    await 接收任意类型 通常接收异步方法     const data = await promise()    //用变量接收值,等同于执行一个then,若状态为失败,    则需用.catch()接收返回,此时data接收失败的值,并且后面的await不会执行    推荐写法 try{        data = await promise()    } catch(e) {        console.log()    }
 * async 原理    async === Generator + 自动执行器    function spawn (genF) {        return new Promise(resolve => {            const gen = genF()            function step (nextF) {                let next = nextF()                if (next.done) {                    return resolve(next.value)                }                step(() => gen.next(next.value))            }            step(() => gen.next(undefined))        })     }
 * 类    class Person {        constructor(username, sex) {//构造器 constructor            this.name = username            this.sex = sex        }    }
    constructor 构造过程    1. 创建一个空对象{ }    2. 执行构造器    3. 把所有的 this 替换成 { }    4. 最终返回 空对象
    继承     class Animals {        static eye = 'eye'//静态属性    (静态也可以继承)        moues = 'moues'    }    class Person extends Animals {        constructor() {            super()//继承的子类是没有this的,需要通过super方法将父级的this拿过来        }    }
//////////////////// git /////////////////////
 * svn, git:版本管理工具  github:面向个人'
    * 配置git//新机器必备        git config --global user.email"用户登录邮箱"        git config --global user.name"用户名"
    1. 创建项目          git init//项目托管给git        git add .        git commit -m "说明性注释"//创建提交
    2. 提交项目        git commit -m "说明性注释"//创建提交        git push -u origin master//提交分支到gitHub(远程)
    3.配置公钥私钥        ssh-keygen -t rsa -C '用户登录邮箱'//创建公钥        cat ···/.ssh/id_rsa.pub//打开公钥(钥匙文件所在文件夹下打开)        gitHUB页面中setting设置公钥//将文件中的密钥复制到gitHub
    4.查看修改与提交  (常用)        git status//查看git那些文件修改        git add (文件名/.)//保存文件修改到本地        git commit -m "说明性注释"//创建提交        git status//再次查看文件是否无修改        git push origin master (master是分支名)//往远程提交分支文件
    * 常用分支指令        git log//查看日志        git checkout -b 本地分支名 origin/master//创建分支        git checkout 分支名//切换分支        git branch -v//查看本地分支        git branch -a//查看远程分支        git config --list//查看账号信息
    * 开发常用        git stash / git stash save '说明性注释'//暂存修改(文件回复到修改前)        git stash list//查看缓存列表        git stash apply / apply stash@{0}//回到最近(或指定)存储        git stash clear//清除缓存        git diff <file>//查看当前修改文件        git clone (gitHub地址)//复制拉取文件        git pull origin master(远程分支)//同步远程项目        git fetch//拉取远程分支同步到本地        git reset --hard hash值//撤回提交        git push -f origin master//强制提交        git checkout .//撤销修改
    * 合并分支        git add (文件名/.)//保存文件修改到本地        git commit -m "说明性注释"//创建提交        git checkout 分支名//切换分支        git merge 需要合并的分支名//将其他分支合并到当前分支        /////////////////////////react 项目创建流程/////////////////////////
    1.npx create-react-app name    2.配置文件夹,路由,页面,组件等    3.配置router文件夹,包含 index.js(主路由文件) 与 assembly.js(抛出路由组件)    4.删除不必要的文件,index.js中删除App相关,并引入主路由 router/index.js    5.配置conifg-overrides.js(项目配置文件/webpack配置文件)       替换package.json中的scripts配置,并安装配置相关依赖       "scripts": {           "start": "react-app-rewired start --open",           "build": "react-app-rewired build",           "test": "react-app-rewired test",           "eject": "react-app-rewired eject"       },"scripts": {           "start": "react-app-rewired start --open",           "build": "react-app-rewired build",           "test": "react-app-rewired test",           "eject": "react-app-rewired eject"       },    6.安装less@3.11.1 与 less-loader@5.0.0,更改index.js引入index.css为index.less
///////////////  Hook  //////////////
 * class组件达到瓶颈,复用组件逻辑复杂(使用高阶函数),hook的主要用途就是复用状态逻辑
 * Hook(是函数、没有生命周期)
 * Hook常用钩子    1.useState:        const = [ val, setVal ] = useState(默认值)//定义useState        setVal()//设置useState中的值(异步)        setVal( pre => { return xxx }  )//拿到上一次的值        const = [ val, setVal ] = useState( ( ) => {            初始值有复杂逻辑时写法            return xxx        })    2.useEffect:        useEffect( () => {
            //逻辑代码            return () => { 卸载阶段 }
        }, [ 依赖项 ] )//依赖项中为监听值,没有监听值只执行一次,相当于DidMount//依赖多个值,只要一个改变,就触发,监听后相当于更新期
 * 注意事项:    Hook 只能写在函数组件    Hook 只能写在顶层,不能写在 if for中,hook按顺序解析;Hook的调用顺序在每次渲染中都是相同的    Hook 自定义hook,以use开头或者以函数组件的形式
 * createRef 与 useRef    const myRef = React.createRef( )//每次都返回一个新对象    console.log( myRef.current )//不可以加属性,只有current属性    <div ref={ myRef }></div>
    const ref = useRef ( 初始值 )//只执行一次,可记录上一次的值,始终返回同一个对象    console.log( ref.current )//不一定只有current属性
 * memo//返回一个新组件  机制与PureComponent相似,执行时做比较优化    const A = memo(function(){        return(            <div>AAA</div>        )    })    <A />    useMemo( 回调, [ 依赖 ]) => 返回值取决于return//多用于缓存,函数体立刻执行    useCallback( 回调, [ 依赖 ]) => 返回新函数         //比较函数,相同就缓存通常与memo连用,函数体需要调用执行
    redux-react-hook//配合useReducer使用的插件
/////////// vue ///////////
 * 安装 npm i @vue-cli    vue create hello-world 
 * 配置文件夹,路由,页面,组件等     npm i element-ui -S    npm install babel-plugin-component -D//按需引入
 * data() {        return {            //项目中的数据        }    }
 * methods: {        //项目函数    }
 * watch: {        data中的现有数据 : {            监听触发的函数        }    }
 * computed: {//缓存,同时可以监听多个值        data中的现有数据 : {            监听触发的函数        }    }
 * filters: {//过滤值        filter(price) {            return `$${price}`        }    }    {{ price | filter(price) }}
 * components: {        引入的组件    }    父传子    父:<A :price="price"/>    子:props: [ 'price' ],
    子传父    子:methods: {        onclick(){            this$emits('aaa(触发事件名)',{                返回值            })        }    }    <div @click='onclick'></div>    父:methods: {        onAAA(obj){            console.log(obj)        }    }    <A @aaa(触发事件名)='onAAA'></div>
 * slot    <A>aaa</A>//拿到在父组件中,子组件的公共部分    子:    <slot/>
 * keep-alive //缓存,避免加载浪费性能    <keep-alive></keep-alive>    activated(){}//激活    deactivated(){}//暂停
 * router    this.$router.push('/ ')//跳转    this.$router.push({name: ''})    const routes = [      {          path: '/',          name: 'Home',          component: Home,      },      {          path: '/about',          name: 'About',          component: () => import('../views/about/About.vue')      }    ]    const router = new VueRouter({        mode: 'history',        base: process.env.BASE_URL,        routes    })    export default router
 * vuex    store/index.js//配置store    state: {//默认值        code: 1,        data: []    },    mutations: {//同步修改  只能在mutations中修改state  触发 commit        //同步代码不能写异步        setCode ( state, action ) {            console.log()            state = action        }        setDataList ( state, action ) {            state.data = action        }    },    actions: {//异步操作  触发 dispatch        getDataList ({ commit }) {            const data = axios.get('url')            commit( 'setDataList', data )            commit( 'home/setDataList', data, {root: true})//调用别的方法        }    },    modules: {        //引入拆出的模块    }
    页面组件    import { mapState, mapMutations, mapActions } from 'vuex'//引入store中的配置    methods: {        ...mapMutations([            'setCode',//在Mutations中提取方执行方法        ]),        ...mapMutations('home',[            'setCount',//在拆出部分中提取方执行方法actions同理        ]),        ...mapActions([            'getDataList',//在Mutations中提取方执行方法        ]),        onclick() {            this.setCode(传值)//使用提取出来的方法处理数据        }    }    computed: {//在computed中取store的state值        ...mapState(['code', 'data']),        ...mapState('home',[ 'count' ]),//引入拆出模块的state        ...mapState('home',{            homeCount: 'count',//重名时,别名方法        })    }
//////////////////溢出省略////////////////// * 单行溢出省略    overflow: hidden;    white-space: nowrap;    text-overflow: ellipsis;
 * 多行溢出省略    overflow: hidden;    display: -webkit-box;    -webkit-line-clamp: 2;//行数    -webkit-box-orient: vertical;
 * 中间截取省略    overflow: hidden;    display: -webkit-box;    -webkit-box-orient: vertical;    -webkit-line-clamp: 2;//行数    text-indent: -40px;//缩进
///////////////面试常问///////////////
 * z-index//需要position才能生效    0,0 点//相对于设置position最近的父元素//如果没有position父元素,以document定位//relative的0,0点相对于父元素计算
 * 粘性定位    position: sticky;
 * 事件注册    addEventListener( ' ', function( ){ }, false )     //事件;触发函数;在哪个阶段触发( false,冒泡;true,捕获 )
 * 事件传递方式    捕获阶段 -> 目标阶段 -> 冒泡阶段
 * 跨域    (浏览器)同源策略:协议,域名,端口,只要一项不同就会跨域    JSONP    CORS后台设置请求头    设置代理 http-proxy-middleware    上线后项目不是node,使用nginx反向代理     * 为什么请求要放在componentDidMoutn()    this.setState() 需要在DOM渲染完之后才能执行
    // await 微任务 promise    // 4 1 3 6 8 2 7 5//执行顺序    async function async1() {        console.log(1)        await async2() // reoslve()        console.log(2)    }    async function async2() {        console.log(3)    }    console.log(4)    setTimeout( function () {        console.log(5)    }, 0)    async1();    new Promise(function ( resolve ) {        console.log(6)        resolve();    }).then( function () {        console.log(7)    })    console.log(8)
 * viewport//主要用于移动设备    width = device-width//宽度为设配屏幕的宽度    initial-scale = 1.0//初始缩放比例    minimum-scale = 0.5//最小缩放比例    maximum-scale = 2.0//最大缩放比例    user-scalable = yes//用户是否可以调整缩放
 * 浏览器内核    chrome: Blink    FireFox: Gecko    Opera: Blink    Safari: Webkit
 * 路由权限    pt: 登录 首页    vip : 登录 首页 详情    sipv: 登录 首页 详情 用户列表
    1. 本地存 { pt: [], vip: [], sivp: [] }    2. 登录后台返回权限 通过权限 拿到这个用户能访问的路由数组    3. 全局路由拦截 [].includes(pathname)
 * HTML5    canvas  svg  video  audio  localStorage  sessionStorage  webSocket  pushState  replaceState
 * 清除浮动的2中方法    //内浮动    :after     :before{ clear: both }
 * 新增伪类    :after    :before    :checked    :focus    :nth-child    :last-child    :first-child
 * 手动动画最小间隔    1/60*1000ms = 16.7ms
 * css3动画    transform ( 通过事件触发 )    animation ( 不通过事件触发 )
 * 如何使用CSS实现硬件加速, GPU渲染     transfrom: translate3D(100, 0, 0): 写上Z轴 会使用伪 GPU渲染    will-change: 绝对的GPU渲染
 * websoket    跟后台进行通信 创建长连接    const ws = new Websocket(url)    ws -> httpwss -> https    # 四个事件        open 连接建立时触发        message客户端服务端数据时触发        error通信发生错误时触发        close 连接关闭时触发    # 两个方法        ws.send()        ws.close()
 * js继承    继承概念:通过某种方式让一个对象可以访问到另一个对象的属性和方法,把这种方式称之为继承    作用:获取更多的拓展,减少代码的冗余等。
    ### 原型链继承    function Person(){            this.name = '邓紫棋'        }        Person.prototype.getName = function(){            console.log(this.name)        }        function Child(){                    }        Child.prototype = new Person()        var child1 = new Child()        child1.getName()// 邓紫棋    缺点:        通过原型来实现继承时,原型会变成另一个类型的实例,原先的实例属性变成了现在的原型属性,该原型的引    用类型属性会被所有的实例共享。        在创建子类型的实例时,没有办法在不影响所有对象实例的情 况下给超类型的构造函数中传递参数
    ###借用构造函数继承     // 借用构造函数继承(经典继承)    function Person(){        this.colors = ['red', 'blue', 'green']    }    function Child(){        Person.call(this)    }    var child1 = new Child()    child1.colors.push('yellow')    console.log(child1.colors)// ["red", "blue", "green", "yellow"]    var child2 = new Child()    console.log(child2.colors)// ["red", "blue", "green"]    优点:        可以向超类传递参数        解决了原型中包含引用类型值被所有实例共享的问题    缺点:        方法都在构造函数中定义,函数复用无从谈起,超类型原型中定义的方法对于子类型而言都是不可见的。
    ###组合继承(借用构造函数继承+原型链继承)    function Parent (name) {        this.name = name        this.colors = ['red', 'blue', 'green']    }    Parent.prototype.getName = function () {        console.log(this.name)    }    function Child (name, age) {        Parent.call(this, name)        this.age = age    }    Child.prototype = new Parent()    var child1 = new Child('kevin', '18')    console.log(child1)//Parent { name: 'kevin', colors: [ 'red', 'blue', 'green' ], age: '18' }    优点:        可以向超类传递参数        每个实例都有自己的属性        实现了函数复用    缺点:        无论什么情况下,都会调用两次超类型构造函数:一次是在创建        子类型原型的时候,另一次是在子类型构造函数内部
    ###原型式继承    function Wonman(name){        let instance = new People()        instance.name = name || 'wangxiaoxia'        return instance    }    let wonmanObj = new Wonman()    缺点:同原型链实现继承一样,包含引用类型值的属性会被所有实例共享。
    ###寄生式继承    function createAnother(original){        var clone = Object.create(original)   //通过调用函数创建一个新对象        clone.sayHi = function(){            //以某种方式来增强这个对象        alert("Hello")    }         return clone          //返回这个对象    }    var person = {        name: "Bob",        friends: ["Shelby", "Court", "Van"]    }    var anotherPerson = createAnother(person)    anotherPerson.sayHi()    缺点:        使用寄生式继承来为对象添加函数,会由于不能做到函数复用而效率低下。同原型链实现继承一样,包含    引用类型值的属性会被所有实例共享。
    ###寄生组合式继承    function Parent(name,play){        this.name=name;        this.play=play;    }    function Child(name,play,age){        Parent.call(this,name,play);        this.age=age;    }    // 隔离了父类和子类的构造函数,父类的添加到了__proto__属性上    Child.prototype=Object.create(Parent.prototype);    Child.prototype.constructor=Child    let child=new Child("张三","玩",20);    let child2=new Child("李四","吃",10)    console.log(child.constructor)    优点:        只调用了一次超类构造函数,效率更高。避免在 SuberType.prototype上面创建不必要的、多余的属    性,与其同时,原型链还能保持不变。
 * web前端性能优化    ## 页面内容         1.减少HTTP             · 通过 webpack 合并JS CSS文件            · 使用 CSS Sprite 合并图片             · 使用 Base64 行内图片             · 用 icon 替换图标        2. 避免重定向             · URL末尾添加 / 例如 http://www.baidu.com/         3. 缓存Ajax请求             · 设置 Cache-Control (相对过期时间)         4. 减少页面元素数量     ## CSS         1. react vue 可以实现css样式按需加载, 减少每次加载CSS的大小         2. 压缩CSS         3. 使用CSS3属性 例如动画使用 transform transiton animtion     ## Javascript         1. JS代码尽量放在页面底部, 避免阻塞页面加载         2. 使用外部的CSS 可以缓存CSS        3. webpack 压缩 js代码     ## 图片        1. CSS Sprite 合并图片         2. Webp 图片         3. 不在HTML中缩放图片         4. 非 webp 图片都要压缩后再使用         5. 使用 Base64 内嵌图片    ## react || vue         · 路由懒加载         · vue 组件异步加载     ## 服务器         1. 使用 CDN(内容分发网络CDN是一组分散在不同地理位置的web服务器)         2. 添加 Cache-Control 缓存头         3. 启用 Gzip 压缩 (图片不要gzip压缩)         4. Ajax 尽可能使用 get方法, post方法会多一次请求         5. 避免  空图片标签     ## 移动端         1. 保证所有组件都小于25K
 * 链表    单向链表:单向链表包含两个域一个是信息域一个是指针域    双向链表:每个节点有2个指针域一个是指向前一个节点另一个则指向后一个节点    循环链表:循环链表就是首节点和末节点被连接在一起,循环链表中第一个节点之前就是最后一个节点    数组和链表的区别:        链表是链式的存储结构数组是顺序的存储结构        链表通过指针来连接元素数组则是把所有元素按次序依次存储        链表的插入删除元素相对数组较为简单但是寻找某个元素较为困难        数组寻找某个元素较为简单但插入与删除比较复杂    自我理解:        数组便于查询和修改但是不方便新增和删除        链表适合新增和删除但是不适合查询
 * 防抖 节流    所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,    则会重新计算函数执行时间。    import _ from 'lodash'    const id = useRef()    const fn = () => {        clearTimeout( id.current )        id.current = setTimeout(( ) => {console.log()        }, 1000)    }    <input onKeyDown={ fn }/>
    import _ from 'lodash'    const id = useRef()    const fn = () => {        console.log()    }    <input onKeyDown={_.debounce(fn, 1000)} />
    所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数    import _ from 'lodash'    const id = useRef()    const fn = () => {        if( !id.current ) {            id.current = setTimeout(( ) => {                id.current = null                console.log()            }, 1000)        }        console.log()    }    <input onKeyDown={_.debounce(fn, 1000)} />
    resize//窗口变化时触发(事件)
    window.addEventListener('scroll', _.throttle(evt => {        document.querySelector('p').innerHTML =          document.querySelector('body').scrollTop || document.querySelector('html').scrollTop    }, 200), false)
 * 判断引用数据类型    Object. prototype. toString.call (对象)
 * 事件代理    currentTarget(获取注册事件的节点)
 * http状态码    200:表示客户端发来的请求在服务器端被正确处理    201:请求成功并且服务器创建了新的资源。     202:接受请求但没创建资源    203:返回另一资源的请求
    301:永久性重定向,表示资源已被分配了新的url    302:临时重定向,表示资源临时分配了新的url    303:表示资源存在着另一个url,应使用get方法获取资源    304:表示服务器允许访问资源,但因发生请求未满足条件的情况
    400:请求报文存在语法错误    401:表示发送的请求需要通过HTTP认证的认证信息    403:表示对请求资源的访问被服务器拒绝    404:表示在服务器上没有找到请求的资源
    500:表示服务器端在执行请求时发送了错误    501:表示服务器不支持当前请求所需要的的某个功能    503:表示服务器暂时除余超负载或正在停机维护
 * 从输入URL 到页面展现    根据地址栏输入的地址向DNS(Domain Name System)查询IP    通过IP向服务器发起TCP连接    向服务器发起请求    服务器返回请求内容    浏览器开始解析渲染页面并显示    关闭连接     # 通过DNS解析获得对应的IP地址        1. 浏览器缓存——浏览器会缓存DNS记录一段时间(2分钟到30分钟)        2. 系统缓存——如何浏览器缓存中没有,浏览器会做一个系统系统调用,查找系统缓存中的记录,常            见的hosts文件        3. 路由缓存——如果系统缓存也没有需要的记录,会向本地路由器发送一条DNS查询请求,一般会有            自己的dns缓存        4. ISP DNS缓存——如果本地路由器没有再查看本地网络提供商(移动啦、电信啦)的DNS服务器,            一般都能找到相应的缓存记录     # 浏览器向服务器发送一个HTTP请求        1. 首先通过三次握手建立TCP连接,        2. 浏览器通过TCP连接向服务器发送一个http请求     # 服务器发出重定向响应    1. 在拿到ip地址后, 浏览器会向对应的web服务器(Nginx,Apache...)发起TCP连接请求,通过三次握手,建立        TCP连接    2. 建立TCP连接后, 浏览器向web服务器发送Http请求     # 服务器返回请求内容        服务器在接收到请求后,解析用户请求,知道了要调度那些资源文件,再通过相应的资源文件,处理用户的请        求和参数,并调用数据库信息,最后讲结果通过web服务器返回给浏览器.     # 浏览器开始解析渲染页面并显示        html 渲染过程     # 关闭连接        在这次数据传输完成后,为了避免服务器与客户端双方的资源占用和损耗,会经过四次挥手,关闭TCP连接.
 * 浏览器缓存    强缓存    Expires: 2020.12.12 8.0 一个绝对时间的 GMT 格式的时间字符串,代表缓存资源的过期时间    Cache-Control: 2小时 2小时之内你重新请求了一个接口 从你请求这个接口开始 重新计算2小时                             判断缓存资源的最⼤⽣命周期,它的值单位为秒    协商缓存      If-Modified-Since 过期 2020.12.12 8.0    ajax('1.php') -> 后台可以拿到过期时间 后台判断 不给返回新数据 300, 有数据200     通过⽐较两个时间来判断资源在两次请求期间是否有过修改    Last-Modified (值为资源最后更新时间,随服务器response返回)
 * RESF规范  实现一个接口执行多个操作
 * vip权限    封装权限路由表(数组)    跳转获取pathname,通过后台的权限,使用includes查看是否包含该pathname,
 * 数组合并4种方法    arr.concat( [] )    arr.push( ...[] )//返回长度,合成数组为arr    [ ...arr, ...arr1 ]    arr.push.apply(arr, [])//返回长度,合成数组为arr
 * jekenis 上线    提交代码到 测试 featur/dev    提交代码到 测试 featur/pre    提交代码到 测试 featur/master
 * 打包 npm run build    合并 js css    react less 转译 js css    build        1.FTP        2.给后台
 * 前端数据映射: //解决公共组件 渲染后台 不同接口 返回不同数据的问题    1. 首先定义一套自己的数据格式     2. 把后台接口给的数据转化成我们自己定义的数据格式    3. 公共组件都适用这套自己定义的数据格式渲染数据
////////////////////问公司/////////////////////
 * 技术栈--详细了解(包括状态管理工具,插件等)
 * 假如有幸加入公司,会负责哪些项目
 * 公司内部是否有技术分享
/////人事/////
 * 接下来找工作的想法:    1. 北京的公司    2. 稳定可以长期干下去的公司    3. 技术氛围好的公司
 * 你找工作主要看中哪些东西    1. 技术提升    2. 薪资是否可以    3. 公司氛围
//////////////////////react插件、方法//////////////////////
 * React传送门    ReactDOM.createPortal( fn(), document.querySelector('') )//渲染到root外面    { children }//通过 children 展示弹框内容
 * export const { Provider, Consumer } = createContext()    <Provider value='wxh'></Provider>
 * react-router-config    import { renderRoutes } from 'react-router-config'    const Root = ({ route }) => (        <div>          <h1>Root</h1>          {renderRoutes(route.routes)}        </div>    )
    const routes = [        {            component: Root,            routes:[                {                    path: '/home/:id',//动态路由                    component: Home,                    routes:[                        {                            path: '/home/user',                            component: Hook                        }                    ]                },                {                    path: '/hook',                    component: Hook                },                {                    path: '/hook2',                    component: Hook2                },            ]        }    ]
 * import { useHistory, useRouteMatch } from 'react-router-dom'        子组件中引用        let match = useRouteMatch('/home/:id')        let history = useHistory()
 * import Masonry from 'masonry-layout'  // 瀑布流 * import InfiniteScroll from 'react-infinite-scroller' //下拉加载    state = {        hasMore: true, // 是否开启下拉加载        data: [            { title: '小白' },             { title: '小白' },             { title: '小白' },            { title: '小白' },             { title: '小白' },            { title: '小白' },             { title: '小白' },        ], // 接受我每次的数据        count: 0,        width: '',    }
    advanceWidth = () => {//瀑布流配置        new Masonry(document.querySelector('.content'), {// new Masonry(节点, 配置)            itemSelector: '.d', // 要布局的网格元素            fitWidth: true, // 设置网格容器宽度等于网格宽度            gutter: 20,            columnWidth: '.d',             originLeft: true,        })    }
    loadMoreData = page => {//下拉加载配置        const { data, count } = this.state        if (count && page > Math.ceil(count / 10)) return false            axios.post('https://api.baxiaobu.com/index.php/home/v5/getuser', { data: { page, limit: 10 } })            .then(res => {                this.setState({                data: [...data, ...data],                count: res.count,            })            this.advanceWidth()        })        .catch(err => console.log(err))    }
    <div className="box">        <InfiniteScroll//下拉加载部分            initialLoad={false} // 不让它进入直接加载            pageStart={1} // 设置初始化请求的页数            loadMore={this.loadMoreData}  // 监听的ajax请求            hasMore={true} // 是否继续监听滚动事件 true 监听 | false 不再监听            useWindow={true} // 不监听 window 滚动条 如果你要监听 window 外层不能有任何节点        >            <div className="content">                {                    this.state.data.map((value, key) => (//瀑布流部分                        <div key={key} className="d xxx">                            {value.title}                        </div>                    ))                 }             </div>         </InfiniteScroll>    </div>
    .box {        box-sizing: border-box;        margin: 0 auto;        width: 100%;        height: 100%;        overflow-x: hidden;        overflow-y: auto;        box-sizing: border-box;        border: 5px #0f0 solid;        .content {            width: 100%;            margin: 0 auto;            border: 5px #00F solid;        }        .xxx {            width: 200px;            margin: 0 0 20px 0;            border: 5px #f00 solid;        }        .xxx:nth-child(2n-1) {            height: 200px;        }        .xxx:nth-child(2n) {            height: 300px;        }    }
    // columnWidth: 200,    // itemSelector: '.grid-item'    // 要布局的网格元素    // gutter: 10    // 网格间水平方向边距,垂直方向边距使用css的margin-bottom设置    // percentPosition: true   // 使用columnWidth对应元素的百分比尺寸    // stamp:'.grid-stamp'    // 网格中的固定元素,不会因重新布局改变位置,移动元素填充到固定元素下方    // fitWidth: true    // 设置网格容器宽度等于网格宽度,这样配合css的auto margin实现居中显示    // originLeft: true // 默认true网格左对齐,设为false变为右对齐    // originTop: true // 默认true网格对齐顶部,设为false对齐底部    // containerStyle: { position: 'relative' } // 设置容器样式    // transitionDuration: '0.8s'    // 改变位置或变为显示后,重布局变换的持续时间,时间格式为css的时间格式    // stagger: '0.03s'   // 重布局时网格并不是一起变换的,排在后面的网格比前一个延迟开始,该项设置延迟时间      // resize:  false // 改变窗口大小将不会影响布局    // initLayout: true // 初始化布局,设未true可手动初试化布局
 * npm i imagesloaded -S//等图片加载
    imagesOnload = () => {//等待图片加载        // 初始化你要监听哪个节点下的图片        const elLoad = imagesLoaded('.content')        // always 页面图片全部加载完 不管有没有加载失败的图片        elLoad.on('always', (instance, image) => {            // 图片加载后执行的方法            // 拿第一次的数据            this.advanceWidth() // 初始化瀑布流        })    }
 * 图片瀑布流    1. 元素设置 absolute    2. 获取浏览器宽度 和 卡片的宽度, 浏览器的宽度 / 卡片宽度 = 有几列    const imglist = [img, img, img, img, ...]    const arr = [        [{ url: '图片路径', position: {top: 100px, left: 40px} }], // 100px        [img, img], // 80 + 20 = 100        [img, img], // 60 + 70 = 130        [img], // 120    ]       arr.forEach(v => {        v.forEach(v2 => {            v2.img + v2.img        })    })    // 2 80 + 20 = 100    arr[1].push(imglist[5])
    arr.map(v => {        v.map(v2 => {            <img src={v2.url} style={{top: v2.position.top, left: v2.position.left}}        })    })    3. onresize     获取浏览器宽度 和 卡片的宽度, 浏览器的宽度 / 卡片宽度 = 有几列    const imglist = [img, img, img, img, ...]    const arr = [        [{ url: '图片路径', position: {top: 100px, left: 40px} }], // 100px        [img, img], // 80 + 20 = 100        [img, img], // 60 + 70 = 130    ]
///////////////////  dva  //////////////////
 * dva === redux-sage + roadhog    npm i dva-cli -g//安装dva-cli    dva new name//创建dva应用
 * .webpackrc.js//webpackrc改为js文件    export default {//配置webpackrc.js文件        publicPath: '/',        extraBabelPlugins: [            ['import', { 'libraryName': 'antd', 'libraryDirectory': 'es', 'style': 'css' }],        ],        alias: {            '@': `${__dirname}/src`,            '@@': `${__dirname}/src/components`        },        proxy: {            '/aps': {                target: 'https://api.baxiaobu.com',                changeOrigin: true,                pathRewrite: {                    '^/aps': '',                }            },            '/api': {                target: 'https://blogs.zdldove.top',                changeOrigin: true,                pathRewrite: {                    '^/api': '',                }            },        }    }
 * 在routes中创建assembly.js、router.js同react一样配置路由    在router.js中引入异步加载路由    import dynamic from 'dva/dynamic'
    function RouterConfig({ history, app }) {//注意引入app        const Home = dynamic({            app,            models: () => [//引入model,数组形式                import('@/models/home')            ],            component: () => import('@/pages/home'),//引入组件        })        return (            <Router history={history}>                <Switch>                    <Route path="/" exact component={Home} />                </Switch>            </Router>        )    }
    export default RouterConfig
 * model    export default {        namespace: 'home',
        state: {            data: []        },
        subscriptions: {            setup({ dispatch, history }) {  // eslint-disable-line            },        },
        effects: {//处理异步             *fetch({ payload }, { call, put, select }) {  //select拿到上一次的数据,里面也是函数                  const xx = yield call(() => {做请求})//call中是函数,相当于一个await                  yield put({//put === dispatch                      type: '',                      payload: ''                  })              },        },
        reducers: {//修改state            home/setName (state, { payload }) {                return { ...state, data: payload }            },        },    }    组件中使用connect连接组件    connect(        state => {            return { dataName: state.home.data }        }    )(Home)
    this.props.dispatch({//通过props.dispatch调用        type: 'home/setName',        payload: 'xla'    })
 * subscriptinos: {//订阅 初始化数据        xxx ({ history, dispatch }) {            history.listen(({ pathname }) => {const regexp = pathToRegexp( '/home' ).test(pathname)            })        }    }    //pathToRegexp将路由自动转为正则
    model中路由跳转    router from 'umi/router'    put( routerRedux.push('/xxx') )
////////////////////typescript///////////////////
 * npx create-react-app tsDemo --typescript//ts react项目搭建    tsconfig.json 配置    {        "compilerOptions": {        "target": "es5", // 指定 ECMAScript 版本        "lib": [            "dom",            "dom.iterable",            "esnext"        ],        "outDir": "lib",        "allowJs": true, // 允许编译 JavaScript 文件        "skipLibCheck": true,    // 禁用命名空间引用 (import * as fs from "fs") 启用 CJS/AMD/UMD 风格引用 (import fs from "fs")        "esModuleInterop": true,        "allowSyntheticDefaultImports": true,        "strict": true,        "forceConsistentCasingInFileNames": true,        "module": "esnext",        "moduleResolution": "node",        "resolveJsonModule": true,        "isolatedModules": true,        "noEmit": true,        "jsx": "react",        "declaration": true    },        "include": [            "src/**/*"        ],        "exclude": ["node_modules", "build"] // *** 不进行类型检查的文件 ***    }
 * 声明变量    let/const/var xxx : 数据类型 = xxx    let/const/var arr : 数据类型[ ] = [ ]//数组    let/const/var arr : (number, string) [ ] = [ ]//数组联合类型    let/const/var arr : any = xxx//任意类型    let/const/var arr : number | boolean | null = xxx//联合类型(允许值为其中一种类型)
    let xxx: [number, boolean] = [1, true]
    enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat}//枚举 值只能为string或number
    function name (xxx: string, xxx:number ): void {        //void: 表示一个函数没有任何一个返回值    }
    function name (xxx: string, xxx:string ): string     function name (xxx: number, xxx:number ): number     function name (xxx: any, xxx:any ): any {//函数重载
    }
 * class类    class Person {        name: string        age: number        constructor(n: string, a: number){//需初始化            this.name = n            this.age = a        }    }    Person('wxh', 20)
 * interface//接口不可实例化可继承(仅可继承一个, 接口可实现多个)    interface A {        可设置对象、函数等接口(规定接口中有哪些变量或属性)    }    implements//实现接口    interface 可以继承类,但是constructor,静态方法、属性不会继承
    //接口只能定义规则,但抽象类可以设置公共的属性和方法
 * abstract//抽象类不可实例化    abstract Person {        name: string        constructor(n: string){//需初始化            this.name = n        }    }
 * 泛型    泛型函数    function fun<T> (opt: T): T {//传入什么类型,返回什么类型        return opt    }    console.log(fun<string>('123'))    console.log(fun('123'))
    function fun2<T> (opt: T[]): T[] {//传入什么类型,返回什么类型        return opt    }    console.log(fun<string>(['1', '2', '3']))    泛型类    class Person<T> {        private count: T[]        constructor(arr: T[]) {            this.count = arr          }        minRun(): T {            let minValue = this.count[0]            this.count.forEach(v => {                if(v < minValue) {                    minValue = v                }            })            return minValue        }    }    const person = new Person<number>([1, 2, 3])    person.minRun()// 1    泛型接口    interface Kind<T> {        (arg: T, n: T): T    }    const fn: Kind<number> = function<t> (arg: T, n: T): T{        return arg    }    fn(123, 456)
////////////// mobx ///////////// * npm i mobx -S//安装mobx插件
 * import { observable } from 'mobx'//可观察数据(监听)    //4.0以前    const num = observable.box(11)    num.get()//获取值    num.set()//修改值
    //引用数据类型    const arr = observable([1, 2, 3])    arr[2] = 4    const obj = observable({name: 'wxh'})    obj.name = 'wbl'    //避免下标越界访问数组
 * import { computed, } from 'mobx'//监听数据变化    class kuuga {        observable str = 'wxh'        @computed get com() {//使用数据时触发            console.log('获取')        }        set com(){//更改数据时触发            console.log('更改')        }    }    const Kuuga = new kuuga()    console.log(Kuuga.com)//触发get com()    Kuuga.str = 'hdr'//触发set com()
 * autorun 当任意可观察数据修改时触发
 * when(() => {        return boolean    },() => {})
 * @action xxx() {}//能将多次autorun合并为一次    @action.bound xxx() {}//效果相当于bind(),用于改变指向
///////////////设计模式///////////////
 * 发布-订阅模式    var saleOffices = {//发布-订阅模式        clientList: [],
        listen (fn){         //订阅函数            this.clientList.push(fn)        },
        trigger(price, square) {    //发布函数            this.clientList.forEach(fn => {                fn(price, square)            })        }    }
    saleOffices.listen((price, square) => {        console.log('王小红'+price, square)    })
    saleOffices.listen((price, square) => {        console.log('好多肉'+price, square)    })
    saleOffices.listen((price, square) => {        console.log('沈年年'+price, square)    })
    saleOffices.trigger(8000, 120)       
 * 传参判断版    var saleOffices = {        clientList: {},
        listen (kind, fn){        //订阅函数    kind表示订阅分类,函数表示订阅后要做什么            if(!this.clientList[kind]){                this.clientList[kind] = []//判断是否存在该订阅类型            }            this.clientList[kind].push(fn)//存在就添加        },
        trigger(kind, price, square) {    //发布函数            this.clientList[kind].forEach(fn => {//遍历该类型的所有方法                fn(price, square)            })        }    }
    saleOffices.listen('square120' ,(price, square) => {//订阅时传入订阅类型和执行函数        console.log('王小红'+price, square)    })
    saleOffices.listen('square120', (price, square) => {        console.log('好多肉'+price, square)    })
    saleOffices.listen('square130', (price, square) => {        console.log('沈年年'+price, square)    })
    saleOffices.trigger('square120', 8000, 120)

/////////////////// 函数柯里化 //////////////////
    function fun() {      const arr = []
      return opt => {          if (opt) {              arr.push(opt)          } else {              let sum = 0              arr.forEach(v => {              sum += v          })          return sum      }  }}
const fn = fun()
fn(10)fn(20)fn(30)fn(40)console.log(fn())
//////////////////////////////pushState replaceState//////////////////////////////    state: 可通过 history.state读取    title: 可选参数,暂时没有用,建议传个短标题    url: 改变后的 url 地址 /abc
    let { history } = window//window中的history    export default function Home (props) {        const onClick = () => {            var _wr = function(type) {            var orig = history[type]            return function() {                var rv = orig.apply(this, arguments)                var e = new Event(type)                e.arguments = arguments                window.dispatchEvent(e)                return rv            }        }        history.pushState = _wr('pushState')        history.replaceState = _wr('replaceState')            // 监听 history.pushState        window.addEventListener('pushState', function(e) {            if ('page1') {                    }            // history.state 直接拿 pushState 第一个参数            console.log(history.state, 2)        })
        history.pushState({ page: 1 }, 'title1', 'page1')        history.replaceState({page: 2}, "title 3", 'page2')    }
        return (            <div className="pages-home">                <Button onClick={onClick}>点我</Button>            </div>        )    }
////////////////////////////redux - promise原理///////////////////////////
// 判断一个变量是不是 promiseimport isPromise from 'is-promise'// 是不是 FSA// FSA: 定义 action 标准 { type, payload, error, meta }// 必须有 type, // 可能有 payload, error, metaimport { isFSA } from 'flux-standard-action'
// redux-promiseexport default function promiseMiddleware(_ref) {    // next === 下一个中间件 或者 dispatch    // 首先返回一个函数 接收一个参数 这个参数是下一个中间件 或者 dispatch    return function (next) {        return function (action) {            // 判断是不是标准的 FSA             // 标准的 FSA 只包含4个属性 type payload error meta            if (!isFSA(action)) {                /**                 * 判断是不是promise,                 * 如果是则执行,只会处理resolve的值,                 * 反之交给下一个中间件                 */                return isPromise(action) ? action.then(dispatch) : next(action);            }
            // 是标准的FSA, 判断是不是一个promise            return isPromise(action.payload)                /**                 * 1.promise的时候,执行then,同时捕获异常,                 * 在处理这两种情况以后,会分别添加另外一个约束error                 * 这我们需要在reducer里面还需要判断error的值,                 * 做不同的处理                 *                  * 2. 如果不是promise则交给下一个中间件                 * */                // promise                // action.payload === axios.get('http://www.baidu.com')                ? action.payload                    // result 就是我们请求接口的数据                    .then(result => {                        _ref.dispatch({ ...action, payload: result })                    })                    .catch(error => {                        _ref.dispatch({ ...action, payload: error, error: true });                        return Promise.reject(error);                    })                : next(action);        }    };}
////////////////////////  BFC  /////////////////////////
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=0.5" /><meta name="description" content="Web site created using create-react-app" /><title>React App</title><style>.d0 {  border: 10px #F00 solid;  width: 200px;  /* float: left; */  /* position: absolute; */  /* display: inline-block; */  /* display: table-cell; */  overflow: hidden;}.d1 {  background: #9F9;  height: 100px;  width: 100%;  float: left;}*{  margin: 0;  padding: 0;}p {  color: #FFF;  background: rgb(214, 125, 9);  width: 200px;  line-height: 100px;  text-align:center;  margin: 0 0 30px 0;}.div {  overflow: hidden;  border: 1px #F00 solid;}div p {  margin: 30px 0 0 0;}</style>
</head><body><div id="root"></div><div class="d0">  <div class="d1"></div></div>
<p>看看我的 margin是多少</p><div class="div">  <p>看看我的 margin是多少</p></div></body></html>
BFC: 块格式化上下文
变成BFC:  浮动元素 (元素的 float 不是 none)  绝对定位元素 (元素具有 position 为 absolute 或 fixed)  内联块 (元素具有 display: inline-block)  表格单元格 (元素具有 display: table-cell,HTML表格单元格默认属性)  具有overflow 且值不是 visible 的块元素
BFC特性:  使 BFC 内部浮动元素不会到处乱跑;  和浮动元素产生边界。
<script></script>
////////////////// 修饰器 /////////////////
//target === MyTestableClassfunction testable(isTestable) {  return function fun(target) {    target.isTestable = isTestable  }}
//装饰class用@testable('wxh')class MyTestableClass {
}
console.log(MyTestableClass.isTestable)// MyTestableClass.isTestable
@testable(false)class Myclass {}
console.log(Myclass.isTestable)// Myclass.isTestable
////////////////////postMessage////////////////////    //跨域传值 * 父路由    <iframe src='http://localhost:3001' name='a1' />    document.onclick = function() {        window.frames['a1'].postMessage('狼来了', 'http://localhost:3001')    }    window.addEventListener('message', function(e) {        console.log(e.origin, 1)        console.log(e.data, 2)    })
 * 子路由    window.addEventListener('message', function (e) {        console.log(e.origin, 1)        console.log(e.data, 2)//传递的内容        window.top.postMessage('没来', 'http://localhost:3000')    })
//////////////// Umi ////////////////    npm create @umijs/umi-app    npm i
    .umirc.ts//配置路由及其他    pages//存放路由文件








posted on 2020-12-20 18:19  chenweiyang  阅读(240)  评论(0)    收藏  举报