复习


// 节流  每过一段时间执行一次

// 定时器实现
function throttle(fn, wait) {
  var timer = null
  var args, that
  if (typeof fn !== 'function') {
    throw new TypeError('Expected a function')
  }
  wait = +wait || 0
  return function(){
    args = arguments, that = this
    if(!timer){      
      timer = setTimeout(function(){
        timer = null
      },wait)
      return fn.apply(that, args)      
    }
  }
}
var f = throttle(function(a){
  console.log(a)
},1000)
f(1);f(2);f(3);f(4);f(5);

// 时间戳实现
function _throttle(fn, wait) {
  var preTime = 0
  var args, that
  if (typeof fn !== 'function') {
    throw new TypeError('Expected a function')
  }
  wait = +wait || 0
  return function(){
    var dif = new Date().getTime()-preTime    
    if(preTime === 0 || dif >= wait){
      args = arguments;
      that = this
      preTime = new Date().getTime()
      return fn.apply(that, args)
    }
  }
}
var f = _throttle(function(a){
  console.log(a)
  console.log(this)
},1000)
f(1);f(2);f(3);f(4);f(5);

// 防抖  指定时间内没有新的触发才执行

function debounce(fn, time){
  var timer = null
  var args = arguments, that = this
  return function(){
    args = arguments;
    that = this
    clearTimeout(timer)
    timer = setTimeout(function(){
      fn.apply(that, args)
    }, time)   
  }
}

function debounce(fn, wait, leading = false){
  var preTime = 0,timer = null,result
  var args , that ;
  if (typeof fn !== 'function') {
    throw new TypeError('Expected a function')
  }
  wait = +wait || 0
  var invokeFunc = function(){    
    // 防止同一触发执行在 lead 为 true 时执行2次
    if(args && that){
      const a = args, t = args
      args = that = null
      result =  fn.apply(a, t)
    }
    return result
  }
  var run = function(interval){
    timer = setTimeout(function(){
      var difTime = new Date().getTime()-preTime
      if(difTime>=wait){
        clearTimeout(timer)
        timer = null   
        return invokeFunc()
      }else {        
        run(wait-difTime)
      }
    }, interval)
  }
  return function(){
    args = arguments
    that = this    
    preTime = new Date().getTime()
    if(!timer){
      run(wait)
      if(leading) {
        return invokeFunc()
      }      
    }
    return result    
  }
}

var f = debounce(function(a){
  console.log(a)
},1000,true)
f(1);f(2)


// 
function sort(arr){
  if(arr.length<=1){
    return arr
  }
  for (let i = 0; i < arr.length-1; i++) {
    for (let j = i+1; j < arr.length; j++) {
      if(arr[i]>arr[j]){
        [arr[i],arr[j]] = [arr[j],arr[i]]
      }      
    }    
  }
  return arr
}

function sort(arr){
  if(arr.length<=1){
    return arr
  }
  for (let i = 0; i < arr.length-1; i++) {
    var minIndex = i;
    for (let j = i+1; j < arr.length; j++) {
      if(arr[j]<arr[minIndex]){
        minIndex = j
      }      
    }    
    [arr[i],arr[minIndex]] = [arr[minIndex],arr[i]]
  }
  return arr
}
sort([2,1,2323,22,22,323,4])

function quickSort(arr){
  if(arr.length<2){
    return arr
  }
  var left = [],
  right = [],
  middle = arr.splice(Math.floor(arr.length/2),1)[0]
  for (let index = 0; index < arr.length; index++) {
    const element = arr[index];
    if(element >= middle){
      right.push(element)
    }else {
      left.push(element)
    }    
  }
  return [...quickSort(left),middle, ...quickSort(right)]
}
quickSort([2,1,2323,22,22,323,4])

// 深拷贝 递归
var deepCopy = (function (){
  let arr = []
  const that = {}
  function copy(target) {
    if(this !== that){
      arr = []
      console.log('外部调用时清空arr,防止arr无限大')
    }
    if(Array.isArray(target)) {
      return target.map(item=>{
        const findItem = arr.find(i=>{return i.item === item})
        if(findItem){
          return findItem.itemCopy
        }else {
          const value = copy.call(that, item)
          arr.push({
            item: item,
            itemCopy: value
          })
          return value
        }        
      })
    }
    if(Object.prototype.toString.call(target) === '[object Object]'){
      const re = {}
      Object.keys(target).forEach(key => {
        const ele = target[key]
        const findItem = arr.find(i=>{return i.item === ele})
        if(findItem){
          re[key] = findItem.itemCopy
          return
        }
        debugger
        const value = copy.call(that,ele)
        re[key] = value
        arr.push({
          item: ele,
          itemCopy: value
        })
        console.log(arr.length)
      })
      return re
    }
    return target
  }
  return copy
})()

function deepCopy(source){
  const copy = []
  const _copy = function(target){
    const findItem = arr.find(i=>{return i.item === target})
    if(findItem){
      return findItem.itemCopy
    }
    if(isObject(target)){
      const re = {}
      for(let [k,v] of Object.entries(target)){
        copy.push({
          item: v,
          itemCopy: 
        })
        re[k] = _copy(v)

      }
      return re
    }else if(Array.isArray(target)){}
  }
  return _copy(source)
}


function isObject(target){
  return Object.prototype.toString.call(target) === '[object Object]'
}
deepCopy({a:{a:1}})
function deepCopy(target){  
  const copy = function(source){
    const re = {}
    const stack = [{value:source, parent: re, key:'value'}]    
    while (stack.length>0){ 
      const ele = stack.pop()
      if(isObject(ele.value)){
        ele.parent[ele.key] = {}
        for(let [k,v] of Object.entries(ele.value)){
          if(isObject(v)){
            ele.parent[ele.key][k] = {}
            stack.push({
              value: v,
              parent: ele.parent[ele.key][k],
              key: k
            })
          }else if(Array.isArray(v)){
            ele.parent[ele.key][k] = []
            v.forEach((i,index)=>{
              stack.push({
                value: i,
                parent: ele.parent[ele.key][k],
                key: index
              })
            })
          }else {
            ele.parent[ele.key][k] = v
          }
        }
      }else if(Array.isArray(ele.value)) {       

        ele.parent[ele.key] = []
        for(let i=0;i<ele.value.length;i++){
          let v = ele.value[i]
          if(isObject(v)){
            ele.parent[ele.key][i] = {}
            stack.push({
              value: v,
              parent: ele.parent[ele.key][i],
              key: i
            })
          }else if(Array.isArray(v)){
            ele.parent[ele.key][i] = []
            v.forEach((i,index)=>{
              stack.push({
                value: i,
                parent: ele.parent[ele.key][i],
                key: index
              })
            })
          }else {
            ele.parent[ele.key][i] = v
          }
        }
      }else {
        ele.parent[ele.key] = ele.value
      }      
    }
    return re['value']
  }
  if(isObject(target)){
    return copy(target)
  }else if(Array.isArray(target)){
    return target.map(i=>{
      return copy(i)
    })
  }else {
    return target
  }
}

function deepCopy(target){
  let stack = []
  let re =[] // copy结果存储
  // 初始化栈
  if(isObject(target)){
    stack.push({
      value: target,
      parent: re,
      key: 0
    })
  }else if(Array.isArray(target)){
    target.forEach((v,index)=>{
      stack.push({
        value: v,
        parent: re,
        key: index
      })
    })
  }else {
    return target
  }
  // 解决循环引用
  const copyed = []
  while (stack.length>0){ 
    const ele = stack.pop()
    const exits = copyed.find(i=>i.source === ele.value)
    if(exits){
      ele.parent[ele.key] = exits.target
      continue
    }
    if(isObject(ele.value)){
      ele.parent[ele.key] = {}
      copyed.push({
        source: ele.value,
        target: ele.parent[ele.key]
      })
      for(let [k,v] of Object.entries(ele.value)){
        stack.push({
          value: v,
          parent: ele.parent[ele.key],
          key: k
        })
      }
    }else if(Array.isArray(ele.value)) { 
      ele.parent[ele.key] = []
      copyed.push({
        source: ele.value,
        target: ele.parent[ele.key]
      })
      ele.value.forEach((v,k)=>{
        stack.push({
          value: v,
          parent: ele.parent[ele.key],
          key: k
        })
      })      
    }else {
      ele.parent[ele.key] = ele.value
    }      
  }
  return isObject(target)? re[0] : re
}


/*
http:连接过程:
3次握手
  客户端  SYN=1 seq=j
  服务端  ACK=1 ack=j+1 seq=k
  客户端  ACK=1 ack=k+1
4次挥手
  客户端  FIN=j
  服务端  ACK=j+1
  服务端  FIN=k
  客户端  ACK=k+1


http2
 头部压缩
 多路复用,同个域名只需要一个连接,省去了tcp连接时间
  
https
 传输加密,需要配置ssl证书 

vue
 双向绑定: Object.defineProperties
 生命周期: beforeCreate created mounted beforUpdate updated beforeDestory destoryed errorCaptured activated deactivated
 透传:provide inject
 指令:Vue.directive 全局指令。选项: 
    bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
    inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
    update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前
    componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
    unbind:只调用一次,指令与元素解绑时调用。
    // 注册
    Vue.directive('my-directive', {
      bind: function () {},
      inserted: function () {},
      update: function () {},
      componentUpdated: function () {},
      unbind: function () {}
    })

    // 注册 (指令函数)
    Vue.directive('my-directive', function () {
      // 这里将会被 `bind` 和 `update` 调用
    })
 vue router 生命周期: beforeEach afterEach beforeEnter beforeRouterEnter beforeRouterLeave beforeRouterUpdate

 vue3 组合式API
 双向绑定: 使用Proxy,对于ie还是使用 Object.defineProperties  const a = reactive({title: '22'})  const a = ref(22)
 生命周期: setup(props, context) return 值将会在其他生命周期和模板中使用,ref值在模板中是展开的,不需要使用.value访问。 使用其他生命周期时为 on+原周期钩子 如 onMounted = (()=>{}) 这些钩子只能在setup中同步使用。另外 原beforeCreate created钩子没有,对应的逻辑应该直接写在 setup 钩子函数里面
 透传: 直接在setup中 使用 provide(name, ref(value)) 在子组件中 接受 const name = inject('name', 可选默认值)   provide值必须是ref、reactive的才能是响应式的
 指令: createApp().directives 或者组件中使用directives选项
    // 注册
    app.directive('my-directive', {
      // 指令是具有一组生命周期的钩子:
      // 在绑定元素的父组件挂载之前调用
      beforeMount() {},
      // 绑定元素的父组件挂载时调用
      mounted() {},
      // 在包含组件的 VNode 更新之前调用
      beforeUpdate() {},
      // 在包含组件的 VNode 及其子组件的 VNode 更新之后调用
      updated() {},
      // 在绑定元素的父组件卸载之前调用
      beforeUnmount() {},
      // 卸载绑定元素的父组件时调用
      unmounted() {}
    })

    // 注册 (功能指令)
    app.directive('my-directive', () => {
      // 这将被作为 `mounted` 和 `updated` 调用
    })
  
  组件注册: app.component(name, Component)    局部注册:组件的components:{name:Component}选项
  新增内置组件: Teleport 组件 用于将组件渲染到指定的container,如body
      <teleport to="body">
        <div>A</div>
      </teleport>  
  新增插件:插件是自包含的代码,通常向 Vue 添加全局级功能。它可以是公开 install() 方法的 object,也可以是 function
    // plugins/i18n.js
    export default {
      install: (app, options) => {
        app.config.globalProperties.$translate = (key) => {
          return key.split('.')
            .reduce((o, i) => { if (o) return o[i] }, options)
        }
        app.provide('i18n', options)
      }
    }
    // 使用方式    
    const app = createApp(Root)
    const i18nStrings = {
      greetings: {
        hi: 'Hallo!'
      }
    }
    app.use(i18nPlugin, i18nStrings)



    React
      生命周期:
        初始化: constructor getDerivedStateFromProps render(必须实现) componentDidMount 
        更新: getDerivedStateFromProps shoudComponentUpdate render getSnapshotBeforeUpdate(在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()) componentDidUpdate
        销毁: componentWillUnmount
        错误处理: getDerivedStateFromError componentDidCatch
          static getDerivedStateFromError(error) {
            // 更新 state 使下一次渲染可以显示降级 UI
            return { hasError: true };
          }

          componentDidCatch(error, info) {
            // "组件堆栈" 例子:
            //   in ComponentThatThrows (created by App)
            //   in ErrorBoundary (created by App)
            //   in div (created by App)
            //   in App
            logComponentStackToMyService(info.componentStack);
          }
      渲染组件到指定元素: ReactDOM.createPortal(child, container)    类似vue3中Teleport组件
      Fragments  用于返回多个元素
        render() {
          return (
            <React.Fragment>
              <ChildA />
              <ChildB />
              <ChildC />
            </React.Fragment>
          );
        }
    React Hook 16.8版本的新增特性,Hook 不能在 class 组件中使用,只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用
      useState  const [count, setCount] = useState(0);
      useEffect
        // 相当于 componentDidMount 和 componentDidUpdate componentWillUnmount
        useEffect(() => {
          ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
          // 副作用函数还可以通过返回一个函数来指定如何“清除”副作用
          return () => {
            ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
          };
        },[count]); // 仅仅在count更新时执行
      useContext: 
        接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。useContext(MyContext) 相当于 class 组件中的 static contextType = MyContext 或者 <MyContext.Consumer>。
      useReducer:
        useState 的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。
          const initialState = {count: 0};
          function reducer(state, action) {
            switch (action.type) {
              case 'increment':
                return {count: state.count + 1};
              case 'decrement':
                return {count: state.count - 1};
              default:
                throw new Error();
            }
          }

          function Counter() {
            const [state, dispatch] = useReducer(reducer, initialState);
            return (
              <>
                Count: {state.count}
                <button onClick={() => dispatch({type: 'decrement'})}>-</button>
                <button onClick={() => dispatch({type: 'increment'})}>+</button>
              </>
            );
          }
      useCallback:
        把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新
      useMemo:
        useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。    
      useRef:useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数
          const inputEl = useRef(null); 类似:const inputEl = React.createRef();
      自定义Hook:如果函数的名字以 “use” 开头并调用其他 Hook,我们就说这是一个自定义 Hook  
          function useFriendStatus(friendID) {
            const [isOnline, setIsOnline] = useState(null);
            return isOnline;
          }
          // 使用
          const isOnline = useFriendStatus(props.friend.id);


*/ 


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容