React和redux,ES6等前端开发经验记录总结(都是干货,看到是你的运气)

React和redux,ES6等前端开发经验记录总结(都是干货,看到是你的运气)

    • React和redux,ES6等前端开发经验记录总结(都是干货,看到是你的运气)
  • 前言
  • 箭头函数this指向
  • 有趣的reduce函数
    • 形成函数调用链
    • 计算和
    • redux里compose函数
  • 箭头函数的返回值
    • 不使用大括号,则箭头后面的代码就是返回值
    • 使用大括号,必需显示使用return,否则返回undefined
    • 使用箭头函数返回对象:必须在对象外面加上括号,否则就只是个代码块,返回undefined
  • js里特殊的函数,行参和实参
  • 怎么理解js预编译阶段和执行阶段(重要)
  • js的闭包,scope(域)
    • scope(域)
    • this变量
    • 闭包
  • redux里combineReducers函数
  • bindActionCreators函数
  • applyMiddleware(…middlewares)函数
  • dispatch(action)函数
  • createStore
  • react、redux、react-redux结合起来的流程

前言

毫不夸张,你能看到这篇文章,是你的运气,里面都是干货,在理解js的道路上容易误解的和关键点的知识。牛逼先不吹….看内容

箭头函数this指向

ES6 将箭头函数纳入标准,很多人都知道一些基本的特性,比如下面的:

  • 没有this、super、arguments 和 new.target 绑定
  • 不能通过 new 关键字调用
  • 没有 prototype
  • 不可改变 this 的绑定
  • 不支持 arguments
  • 不支持重复命名参数(无论是严格模式还是非严格模式)

理解箭头函数this指向只要记住箭头函数 this 的指向(不仅仅是this,其实super,new.target等)由外围最近一层非箭头函数决定。当然这里面有些细节,什么叫最近一层非箭头函数
比如函数里包裹箭头函数

var Animal = function() {
    this.name = "Animal";
    this.speak = (words) => {
        console.log(this.name + ' is saying ' + words + '.');
    }
}
var cat = new Animal();
cat.speak("miao ~");

输出:Animal is saying miao ~.。箭头函数里this指向的是函数本身。
再比如

var lastName = 'postbird';
const person = {
    lastName:"ptbird",
    getLastName:()=>{
        console.log(this.lastName)
    }
};
person.getLastName();

输出: postbird.箭头函数this指向windows。
注意最近一层非箭头函数。person本身是对象,不是函数,this指向person定义时的上下文环境,也就是window,同时lastName属于person的内部且与getLastName函数是等价的。

再比如下面的,箭头函数所在的非箭头函数在对象里。

var adder = {
  base : 1,

  add : function(a) {
    var f = v => v + this.base;
    return f(a);
  },
};

console.log(adder.add(1)); 

输出 2
箭头函数在add方法里,add虽然定义在对象adder里,但箭头函数 this 的指向(不仅仅是this,其实super,new.target等)由外围最近一层非箭头函数决定,所以箭头函数里this其实是adder.

总之,一般我们只会遇到在在函数里使用箭头函数和对象里使用箭头函数,3者情况见上面即可。
参考ES6对象方法声明时箭头函数this的指向
[非箭头函数this指向](this 指向详细解析(箭头函数))

有趣的reduce函数

它是js里的一个方法,reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

形成函数调用链

var test1 = function(){
    console.log("方法一:test1");
}
var test2 = function(str){
    console.log("方法二:test2" + str);
}
var test3 = function(str){
    console.log("方法三:test3."+str);
    return "方法三被执行"
}
var arr = [test1,test2, test3]
var all = arr.reduce(function(a,b){
    return function(){
        return a(b.apply(undefined, arguments)) 
    }
})
all("ss");

结果

方法三:test3.ss
方法二:test2方法三被执行
方法一:test1

计算和

var numbers = [65, 44, 12, 4];
var total = numbers.reduce(function(a,b){
    return a+b;
})
console.log(total);

结果125

reduce的语法
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

redux里compose函数

function compose() {
  for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) {
    funcs[_key] = arguments[_key];
  }

  if (funcs.length === 0) {
    return function (arg) {
      return arg;
    };
  }

  if (funcs.length === 1) {
    return funcs[0];
  }

  return funcs.reduce(function (a, b) {
    return function () {
      return a(b.apply(undefined, arguments));
    };
  });
}

使用方法

compose.apply(undefined, 数组)(参数);

箭头函数的返回值

不使用大括号,则箭头后面的代码就是返回值

var sum = (num1, num2) => num1 + num2 

使用大括号,必需显示使用return,否则返回undefined

var sum = (num1, num2) => { return num1 + num2 }
var sum = (n1, n2) => {
  console.log(n1);
  return n1 + n2
}

使用箭头函数返回对象:必须在对象外面加上括号,否则就只是个代码块,返回undefined

var sum = () => ({name: 'a'})
等同于
var sum = function sum() {
  return { name: 'a' };
};

js里特殊的函数,行参和实参

我发现js里行参和实参完全可以理解为2条并行的线,比如

function t1(){
    console.log("打印参数: " + arguments.length);
    return "t1";
}
console.log(t1("1"));

t1函数在定义时没有指明可接收参数,但我们依然可以传入参数,这个传入的参数就是实参,可以通过arguments获取实参。
使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们,用 arguments[0],即第一个参数的值(第一个参数位于位置 0,第二个参数位于位置 1,依此类推)。

argumentsparameters经常被混为一谈,为了这个教程我们还是做一个2者的区分。在大多数标准中,parameters 是我们定义函数时设置的名字(形参),arguments (或者是实参)是我们传入函数的参数,看下如下的函数

function foo(param1, param2) {
    // do something
}
foo(10, 20);

这个函数里,param1 和 param2 是函数的形参,而我们传入函数的值10,20是实参。

怎么理解js预编译阶段和执行阶段(重要)

3个示例

var a = 2;
var b = 3;

//例子1
function test1(){
    if(b==3){
        //使用var声音变量
        var c = 3;
    }
    console.log("c=" + c);
}
test1()
console.log("分隔线")

//例子2
function test2(){
    console.log("b:" + b);
    var b = 3;
    console.log(b);
}
test2();

//例子3
function test3(){
    if(b==3){
    //注意使用的是es6里的let声明变量
        let c = 3;
    }
    console.log("c=" + c);
}
test3()
console.log("分隔线")

结果如下

c=3
分隔线
b:undefined
3
D:\gitSource\dy\dongli\testScope.js:24
        console.log("c=" + c);
                           ^

ReferenceError: c is not defined
    at test2 (D:\gitSource\dy\dongli\testScope.js:24:21)
    at Object. (D:\gitSource\dy\dongli\testScope.js:26:1)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:191:16)
    at bootstrap_node.js:612:3

为什么会有这个结果呢?
js解析代码按如下阶段执行的
1. 语法分析(分析语法)
2. 预编译(预处理js文件)
3. 解释执行(边解释边执行)3

js是单线程执行,es5之前(注意es6之后加入了let和const声明变量,但javascript是不认的,预编译时会把它当成普通代码)javascript中的两种声明方式,var和function,前者声明的是变量,后者声明的是方法。对应的预编译阶段也有两种处理方案
使用var定义的变量在内存中开辟一块内存空间并指向变量名,且赋值为undefined,使用function声明的函数,则同样会进行开辟内存空间,但赋值的对象会将声明的函数赋值给函数名。
预编译阶段会先声明变量名,再声明函数名,不管代码中声明变量和声明函数的顺序如何。
以上面例子为便解释过来
js引擎扫描js代码块(js里以

你可能感兴趣的:(技术工具,ES6,React,前端框架,redux)