学习笔记(9)

学习笔记(9)

文章目录

  • 学习笔记(9)
    • 高阶组件
      • 作用
      • 是什么
        • 高阶函数
        • 类的装饰器(decorator)
          • 做什么的?
          • 语法
          • 特点
      • 高阶组件
      • 应用点
      • 高阶组件的两种形式
      • 函数curry
    • demo
      • FormProvider
    • setTimeout的第一个参数
      • mdn上的解释
      • 总结
    • 进阶算法
      • 贪心算法
        • 贪心算法总结
      • 动态规划(dynamic programming)
      • 对时间复杂度的思考
    • 关于== ===(冷门知识点)
      • 含义
          • 例子:

高阶组件

references:
React 精要面试题讲解(五) 高阶组件真解

作用

对于复用的ui、数据逻辑的一个封装

是什么

是一个函数,接收一个组件作为参数,返回一个处理后的组件或者新的组件

高阶函数

是一个函数,接收一个函数作为参数,返回一个经过处理后的函数或者新函数

        function testedFunc() {
            this.a=1;
        }
        function hof(func){
            func.prototype.aaa=3;
            return func;
        }
        const newfunc=hof(testedFunc);
        const func0=new newfunc();
        console.info(newfunc.prototype.aaa,func0.aaa,func0.a);
        // 3 3 1
类的装饰器(decorator)

这部分可以参考阮一峰的博客
es6 decorator

做什么的?

用来注释或修改类和类方法。

语法
@decorator
class A {}

// 等同于

class A {}
A = decorator(A) || A;

特点

装饰器本质就是编译时执行的函数。不是运行时哦~

高阶组件

// 下面写一个简单的高阶组件
const wrapedComponent=(component)=>{
    class newComponent extends React.Component{
        render(){
            return <component info="xxx" />
        }
    }
    return newComponent;
}

应用点

  • redux:
class MyReactComponent extends React.Component {}

export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);

可以这样写

@connect(mapStateToProps, mapDispatchToProps)
class MyReactComponent extends React.Compone
nt {}

高阶组件的两种形式

  • 组合(代理)类型的高阶组件
    • 特点:返回的新组件继承的还是React.Component,只是把参数组件作为新组件的子组件去使用;
  • 继承类型的高阶组件
    • 特点:返回的新组建继承的是参数组件,从而实现以参数组件为模板,改写参数组件的功能。

函数curry

函数柯里化其实就是将输入的多个参数变成只使用第一个参数并且返回以剩余参数为参数且有返回结果的函数。

demo

hoc form组件我更新在了github上面:
https://github.com/LynnWonder/dva-router-demo

FormProvider

接收fields作为初始state,handleInputChange用value来更新state,其实这里有点类似于父子组件传值。

setTimeout的第一个参数

  • 为什么重新提setTimeout这个老掉牙的函数呢,因为最近重新看this的指向的时候发现了一个以前没有明确的问题,第一个参数写函数名还是函数执行?

mdn上的解释

function
A function to be executed after the timer expires.
code
An alternative syntax that allows you to include a string instead of a function, which is compiled and executed when the timer expires. This syntax is not recommended for the same reasons that make using eval() a security risk.

再参考这篇博文:关于setTimeout 第一个参数的问题解析

  1. 当我们传入的是一个函数执行的时候,它总是立即执行,而不是延迟执行,也就是说setTimeout失去了它的价值
  2. 当我们传入的是一个函数的时候,此时传入的是引用函数地址,会延迟执行
  3. 至于可以传字符串的问题,建议不用,因为此时this指向的是全局window,eval()执行动态脚本的时候,在全局作用域找字符串中的内容,具有很大的不可预知性不建议使用(毕竟字符串是传值,下次调用的时候有可能找不到内存在哪里(我也不懂为什么要下次调用))
  4. 具体怎么延迟就是宏任务,微任务等的问题了,本期不讲

总结

第一个参数只能放函数指针,如果想传参就直接用匿名函数包裹起来即可

进阶算法

贪心算法

  1. 基本概念
  • 贪婪算法或者说贪心算法:对问题求解时,总是作出在当前看来最好的选择。也就是说不从整体最优上加以考虑,它所作出的是在某种意义上的局部最优解。
  • 关键点:贪心攻略的选择必须具备无后效性,某个状态以前的过程不会影响以后的状态,只与当前状态有关
  1. 股票买卖问题,柠檬水找零问题
贪心算法总结

当你在做一个题目找不到什么规律的时候,可以考虑贪心算法,先去解决局部的最优问题,然后逐步的改进提升。
注意:

  • 贪心算法只是一种思想,它不局限于你去用什么样的数据结构去实现。
  • 你可以用栈可以用队列或者其他

动态规划(dynamic programming)

  1. 基本概念:分阶段求解决策
    比如说课堂中是通过一个问题来引入的:你的面前有10级阶梯,每次只能走一步或者两步,问你一共有多少种走法,当然我们可以通过暴力枚举的方式得到所有答案,但是动态规划就容易多了。首先只考虑最后一步,只存在最后一步走两个台阶和一个台阶的两种情况,所以
F(10)=F(9)+F(8);
F(9)=F(8)+F(7);
···
- 状态转移方程:F(n)=F(n-1)+F(n-2) n>=3
- 最优子结构:F(9) F(8)
- 边界:F(1)=1 F(2)=2
  1. 不同路径问题,最短路径问题

对时间复杂度的思考

【C语言】求取第n个斐波那契数的时间复杂度、空间复杂度分析,用三种方式实现(普通递归,循环,优化递归)

    //递归写法
    const fib=(n)=>{
        if (n===1) return 1;
        if(n===2) return 1;
        return fib(n-1)+fib(n-2);
    }

时间复杂度分析:参考等比数列求和公式

T= 2^0+2^1+...+2^(n-2)=2^(n-2)-1

空间复杂度分析:
fib(n)=fib(n-1)+fib(n-2)=… 创建了n-1个空间

  • 时间复杂度:O(2^n)
  • 空间复杂度:O(n)
      const fib=(n)=>{
          let res=new Array(n);
          for(let i=0;i<n;i++){
              if (i===1) res[0]=1;
              if(i===2) res[1]=1;
              res[i]=res[i-1]+res[i-2];
          }
          return res[n-1];
      }
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
    同理,在贪心算法中使用递归也应该尽量用循环去实现。

关于== ===(冷门知识点)

真的心累,又又又记录这个问题了。。。
是因为今天看到一个

    []===[]; //false

从这篇文章做笔记而来:
探究 == 本质

含义

  1. == 比较的就是值:允许类型转换
  • 值类型 == 值类型 //相当于 Number(值类型) == Number(值类型)
  • 引用类型 == 值类型 // 对象转化成原始类型的值,再进行比较
    • 比较规则:数组与数值进行比较,会先转成数值,再进行比较;与字符串进行比较,会先转成字符串,再进行比较;与布尔值进行比较,两个运算子都会先转成数值,然后再进行比较。(存在异议)

详解 javascript 中的比较(==和 ===)
参考上面的文章可以发现:如果是两个基本类型的变量相比较一般都会化成number类型对比。
如果其中有一方是对象就要先将其变成原始类型
转换原始类型:Symbol.toPrimitive

在Symbol.toPrimitive 属性(用作函数值)的帮助下,一个对象可被转换为原始值。该函数被调用时,会被传递一个字符串参数 hint ,表示要转换到的原始值的预期类型。 hint 参数的取值是 “number”、“string” 和 “default” 中的任意一个。

    var obj = {
        [Symbol.toPrimitive](hint) {
            if (hint == "number") {
                return 10;
            }
            if (hint == "string") {
                return "hello";
            }
            return '10';
        }
    };
   console.info(obj=='10');//true 
例子:
  • []==![]//true 怎么来的呢?
ans
首先我们知道,!的优先级要大于==的,所以先运算右边,![]---->结果为false
此时两边数据类型已经不一样了,先转换数据类型 []空数组转换为false
相当于,Number([])为0,Number(false)为0
  1. === 比较的是值+类型:不允许类型转换
    javaScript里面(等于==与全等的区别)(值类型与引用类型的存储方式)
    我们都知道基本数据类型(javascript五种基本数据类型:number,boolean,string,null,undefined)和引用类型(比如Object,Array,RegExp,Function等)的区别:
基本数据类型 引用类型
值存放在栈中 地址放在栈里,值放在堆里
复制的时候传值 一般来讲,浅复制就是传址

因而如果比较两个空数组,虽然值一样,但是指向的地址不一样,所以不相等也不全等。

另:

		console.info('null===null',null===null); //true
        console.info('undefined===undefined',undefined===undefined); //true
        console.info('[]===[]',[]===[]); //false
        // Object.is 的polyfill
        if (!Object.is) {
		  Object.is = function(x, y) {
			    // SameValue algorithm
			    if (x === y) { // Steps 1-5, 7-10
			      // Steps 6.b-6.e: +0 != -0
			      return x !== 0 || 1 / x === 1 / y;
			    } else {
			      // Step 6.a: NaN == NaN
			      return x !== x && y !== y;
			    }
			  };
		}
		console.info(Object.is(null,null)); // true
        console.info(Object.is(NaN,NaN)); // true

你可能感兴趣的:(note,学习笔记,贪心算法,动态规划)