美文网首页taro
和taro一起做SPA 1.基础知识

和taro一起做SPA 1.基础知识

作者: shtonyteng | 来源:发表于2019-01-09 12:35 被阅读0次

    这一章的主要目的是和大家一起复习一下taro涉及的基础知识,为后面的学习做好基础

    1. 基础知识

    1.1 this指针

    this指针大概是javascript中最令初学者困惑的语法了,简单说,this指针就是指向函数或方法运行的上下文环境。既然叫上下文环境,肯定和运行的环境相关。
    在浏览器环境下:

    • 当this出现在函数调用中,指向的是他运行的上下文:window对象;
    • 当this出现在对象方法调用时,则指向了他运行的上下文:对象本身;
      让我们举个例子说明一下:
        function fn(){
            console.log(this);
        }
        var obj={
            fn:fn
        }
        fn();
        obj.fn();
    

    通过运行代码,你会发现,fn返回的是window对象,而obj.fn返回的则是obj对象
    为了加深理解,我们看一个有点迷惑的问题

    <!DOCTYPE html>
    <html>
        <div id="root"></div>
    </html>
    <script type="text/javascript"/>
        var e1=document.getElementById("root");
        var getId=document.getElementById
        var e2=getId("root");
    </script>
    

    这是一个常见的场景,每次使用document.getElementById方法很麻烦,所以重新定义一个函数 getId,指向document.getElementById方法.
    但是你发现,在chrome浏览器中调用getId方法居然系统会抛一个异常:

    test.htm:9 Uncaught TypeError: Illegal invocation 
    

    发生异常的原因就在于,getElementById内部实现使用了this指针指向document对象.但是,当你用自己定义的getId方法时,getElementById已经由对象调用变成了方法调用,this指针被指向了window对象.

    既然this指针有这样的不确定性,那么,自然就可以想到如何根据需要变更他的指向。
    变更this指针指向有两种方法,定义时绑定和运行时绑定。

    • 定义时绑定 bind
    • 运行时绑定 apply/call
      还是让我们看个例子:
      对于我们上个getId的例子,你只要这样调用就可以了
      定义时通过bind方法绑定
        const getId=document.getElementById.bind(document);
        const e=getId("root");
    

    运行时通过call方法绑定

        const e=getId.call(document,"root")
    

    运行时通过apply方法绑定

         const e=getId.apply(document,["root"])
    

    通过上面的例子也可以看到call和apply两者的区别是:apply绑定时,传入的参数为数组形式,而call绑定则是采用枚举的方式。所以如果getId方法需要使用apply方法时,必须将参数包装成数组的形式.

    1.2 高阶函数

    在javascript语言中,函数是一类成员,函数可以作为变量,也可以作为输入参数和返回参数.将函数作为输入参数或输出参数的函数称之为高阶函数.后面我将会带大家一起了解一下高阶函数.

    1.2.1 闭包

    让我们看一下第一个高阶函数,闭包.
    闭包利用了javascript函数作用域内变量被引用不会消除的特性.闭包被应用的场景非常多.
    让我们先看一个获取递增ID的例子,首先,让我们看一下传统的方法,传统的方法获取递增ID,你需要先做一个全局变量.

    let globalID=0
    function getID(){
        return globalID++;
    }
    console.log(getID(),getID(),getID())
    

    这种方法由于使用了全局变量,任何一个人都有可能不经意的修改globalID的值导致你的方法失效.
    采用闭包的写法,你先创建一个crGetID方法通过闭包保存ID,并返回getID函数.然后通过getID方法获取ID

    function crGetID(){
        let id=0;
        return function(){
            return id++;
        }
    }
    var getID=crGetID();
    console.log(getID(),getID(),getID())
    

    这样,没有人可以直接修改你的ID值.

    1.2.2 currying

    让我们再看一个闭包的应用:currying,currying解决的问题是把一个函数的多个参数转换为单参数函数.
    举个例子,假设我们需要累计一个用户7天的数据:

    function add(d1,d2,d3,d4,d5,d6,d7){
        return d1+d2+d3+d4+d5+d6+d7
    }
    

    如果是30天,可能需要30个输入参数,如果不定天数呢?
    采用currying则可以解决这个问题:

    function curryAdd(){
        let s=[];
        return function(...arg){
            if (arg.length==0){
                return s.reduce(function(p,v){return p+v},0)
            }else{
                s.push(...arg)
                console.log("s",s);
            }
        }
    }
    var ca=curryAdd();
    ca(1);
    ca(2);
    ca(3);
    ca(4);
    console.log(ca());
    

    通过将一个函数currying后,函数可以随时被调用,直到输入参数为空时才进行计算.
    闭包的特性使之成为javascript中运用最广的特性.后续在代码中,我们还会继续看到大量的闭包用法.

    1.3 es6语法

    react 大量使用了es6的语法,如果你对javsascript的印象还停留在原始的印象里,你可能根本没法看懂react的代码。所以在这里我们简单对用到的es6语法做一些介绍,并尽可能以react实际使用作为学习的例子。详细的es6语法介绍,可以参考相关的技术文档。

    1.3.1变量解析

    • 数组变量解析
      es6 支持对数组直接进行解析,举个例子,如果需要对变量x,y互换值,传统的做法是:
    function(x,y){
        var t;
        t=x;
        x=y;
        y=t;
    }
    

    如果用数组解析,就容易多了:

    let [x,y]=[y,x]
    

    数组解析可以用到输入参数传递

        function test ([x,y,z]){
            return x+y+z;
        }
        console.log(test([1,2,3]))
    

    上面的例子,打印出来的结果是6.
    还可以用到一次返回多个参数:

        function retMult(){
            return [1,2,3]
        }
        let [x,y,z]=retMult();
        console.log(x,y,z)
    

    函数会打印出 1,2,3

    • 对象变量解析
      对象解析用的更广泛,让我们举个简单的例子:
        let {x:x,y:y}={x:2,y:3}
        console.log(x,y);
    

    函数打印结果 2,3
    还可以简写为:

        let {x,y}={x:2,y:3}
        console.log(x,y);
    

    让我们看一下下面的例子,如果对象属性名称和变量名称可以更进一步进行简写:

        let x=1;
        let obj={x};  //相当于 obj={x:x}
        console.log(obj.x);
    

    和数组解析一样,对象解析大量应用在输入参数的传值上,让我们举一个redux的实际应用的例子(这个例子里,假设state对象仅包含一个value属性):

    function  reducer({value},{type,payLoader}){
        switch(type){
            case "calc":
                return  {value:value+payLoader}
            default:
                return {value}
        }
    }
    

    这个例子里,使用了对象的解析,代码更加简洁和异动.如果不使用对象解析,你的代码是这样的:

    function reducer(state,action){
        switch(action.type){
            case "calc":
                return {value:state.value+action.payLoader}
            default:
                return state;
        }
    }
    

    1.3.2箭头函数

    箭头函数可以让代码更加简洁和直观,另外,由于箭头函数对this指针的特殊处理,因此,被大量的运用。
    让我们还是以数组提供的map函数为例子说明:

    let arr=[1,2,3,4];
    let m=arr.map(v=>v*2);
    

    使用箭头函数,即简洁又直观,对数组中的每个元素直接乘以2.
    如果使用传统的方式,你需要这样写:

    let n=arr.map(function(v){
        return v*2;
    })
    console.log(n);
    

    使用箭头函数需要注意以下几点:

    • 如果是一个参数,可以省略(),如果多个参数或没有参数,则必须使用()
    • 如果函数直接返回箭头后的表达式,可以不加{},否则,需要在箭头后使用{}
      让我们再举个数组提供的reduce方法的实际例子:
    var r=[1,2,3,4].reduce((p,n)=>p+n);
    console.log(r);
    

    这个例子通过reduce函数计算数字元素的累加和,reduce函数的输入参数是一个函数,函数的输入参数分别为累加之和p以及下一个元素n.
    如果用传统的方法,你需要这样写:

    var r=[1,2,3,4].reduce(function(p,n){
        return p+n;
    })
    console.log(r);
    

    1.3.3类

    ES6提供了类,类实际上就是一个语法糖.让我们还是通过一个具体的例子来看一下类的实现:

    class Counter extends Component{
        constructor(props){
            super(props)
        }
        sub(){
            let value=this.state.value-1;
            this.setState({value})
        }
        add(){
            let value=this.state.value+1;
            this.setState({value})
        }
        render(){
            return (
                <div>
                    <button onClick={this.add.bind(this)}>+</button>
                    <button onClick={this.desc.bind(this)}>-</button>
                </div>
            )
        }
    }
    

    这个例子说明了ES6的类的用法.
    首先,类的定义语法是:

    class  Name{
    }
    

    你的类可以继承自另一个类,在刚才的例子里我们的类Counter继承自React的Component类

    class Counter extends Component{
    }
    

    你可以根据需要实现类的构建器,构建器可以通过super方法引用父类的构建器:

        constructor(props){
            super(props)
        }
    

    类的方法可以缩写为methodName(){}的形式

        sub(){
            let value=this.state.value-1;
            this.setState({value})
        }
    

    相关文章

      网友评论

        本文标题:和taro一起做SPA 1.基础知识

        本文链接:https://www.haomeiwen.com/subject/nvwwrqtx.html