02-JSX核心语法一

02-JSX核心语法一

前言

本节课以两个案例展开,主要还是对React有一个具体的认识,具体讲解JSX的一些知识点,并且在讲这些知识点的同时有对ES6中类的定义、类的继承以及高阶函数的使用做了补充。文章的相关代码放在GitHub仓库,有需要的小伙伴看这里(https://github.com/hqchqc/FrontendLearningIntegration/tree/master/React%E5%AD%A6%E4%B9%A0) ,多多 star 哦! 另外博客也会同步更新的,感兴趣的小伙伴可以多多留言哦! ( https://www.bagbean.cn/ )

语法补充

类的定义

  • 在ES5中定义类

    • ES5中我们是使用函数的方式来定义一个类的,并且把类的方法定义在原型上,这样就不会每次创建一个对象都要重新生成类中的方法,占用空间
    • 但其实读了小黄书(你不知道的JacaScript)之后,会认识到JS中本就没有类的概念,因为本质上来说,父类与子类的联系在面向对象中是有一种复制的关系,但是JS中并不是采用复制的方式,而是采用了原型将父类和子类联系起来,并没有复制,所以我们把JavaScript中的类称为一种“鸭子类型”(看起来像鸭子,走起路来像鸭子,那么就是鸭子)
    // ES5中类的定义
    function Person(name,age){
        this.name = name;
        this.age = age;
    }
    Person.prototype.running = function(){
        console.log(this.name ,this.age ,'running');
    }
    let p = new Person('zxy',18);
    p.running();
    
  • 在ES6中定义类

    • 在ES6中JavaScript引入了class关键字,用于定义一个类
    //ES6中类的定义
    class Person{
        // 构造方法
        constructor(name,age){
            this.name = name;
            this.age = age;
        }
        // 定义方法
        running(){
            console.log(this.name,this.age,'running');
        }
    }
    let p = new Person('zxy',3)
    p.running();
    
  • this的指向问题

    • 默认绑定(独立函数调用):可以把这条规则看作是无法应用其它规则时的默认规则,this指向全局对象,但是在严格模式下,指向undefined
    • 隐式绑定(作为对象中的方法):这条规则要看调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含,隐式绑定规则会把函数调用中的this绑定到这个上下文对象
    • 显示绑定(call、apply、bind):它会把你指定的参数设置为this的上下文并调用原始函数
    • new绑定(new操作符):我们会构造一个新对象并把this绑定到new操作符创造的那个对象上
    • 优先级:new绑定 > 显示绑定 > 隐式绑定 > 默认绑定

类的继承

  • 这里我们讲的是ES6中的继承方式,面向对象有三大特性:封装、继承和多态

  • 继承的优点:

    • 减少重复代码
    • 多态的前提(但是JavaScript是弱类型语言,所以多态是鸭子类型)
    • ES6中的继承其实是ES5中继承的语法糖,采用的是寄生式组合继承
    • 要注意,如果一个类继承自另一个类,那么在这个类的构造器中必须调用super(),用来调用一次父类的构造函数,也就是说子类必须初始化父类对象
    class Person{
        constructor(name,age){
            this.name = name;
            this.age = age;
        }
        running(){
            console.log(this.name,this.age,'running');
        }
    }
    
    class Stu extends Person{
        constructor(name,age,sno){
            // 如果是继承的话 super是必须要调用的 否则会报错哦
            // 子类中必须初始化父类对象
            super(name,age);
            this.sno = sno;
        }
    }
    
    let stu = new Stu('zxy',3,520);
    console.log(stu.name,stu.age,stu.sno);
    stu.running();
    

高阶函数map

  • 这个函数在之后遍历的时候会经常用到,所以讲了一下
  • 首先要明白map它是对原来数组的一个映射,那么自然它是会返回一个新的数组
  • map不会对空的数组进行检测,若数组为空,返回的也是一个空数组,这里和forEach有一点不同,forEach会对数组进行检测,如果数组为空,就不执行回调函数
let names = ['zxy','hqc','cmm','zt'];
/**
 * map里的回调函数有三个参数
 *  第一个参数: 遍历到的那个数据项
 *  第二个参数: 下标值
 *  第三个参数: 数组本身
 * map会返回一个新的数组 是原本数组的一个映射
 */
let newNames = names.map((item,index,array) => {
    return item + '000'
})
console.log(newNames);	// [ 'zxy000', 'hqc000', 'cmm000', 'zt000' ]

案例练习

案例一 电影列表

  • 在实际开发过程中,数据是通过发出网络请求来获取的,再渲染到页面上,这里我们先将发出网络请求的这一步骤省略,在state中定义一个数组,用来存放需要渲染的电影列表
  • 这里我们有两种方式来进行渲染
    • for-of的方式
    • map的方式
  • 本质上都是采用循环,将其拼接成<li>{电影名称}</li>这种形式,即可渲染到页面上,要注意不是字符串的拼接哦,而是直接将两者混在一起的方式,后面会讲到这是JSX的语法
<body>
  <div id="app"></div>
  <!-- 引入依赖 -->
  <script src="../react/react.development.js"></script>
  <script src="../react/react-dom.development.js"></script>
  <script src="../react/babel.min.js"></script>

  <script type="text/babel">
    class App extends React.Component{
      constructor(){
        super();
        this.state = {
          message: '电影列表',
          movies: ["大话西游","星际穿越","盗梦空间","小谢尔顿"]
        }
      }

      render(){
        const newMovie = [];
        for(let movie of this.state.movies){
          newMovie.push(<li>{movie}</li>)
        }

        return(
          <div>
            <h2>{this.state.message}1</h2>
            <ul>
              {newMovie}
            </ul>

            <h2>{this.state.message}2</h2>
              <ul>
                {
                  this.state.movies.map((item) => {
                    return <li>{item}</li>
                  })
                }
              </ul>
          </div>
        )
      }
    }

    ReactDOM.render(<App/>,document.getElementById('app'))
  </script>
</body>

案例二 计数器

  • 这个案例我们在学Vue的时候也写过,比较简单,这里只要注意在react中调用函数时的this指向问题即可
<body>
  <div id="app"></div>

  <script src="../react//react.development.js"></script>
  <script src="../react//react-dom.development.js"></script>
  <script src="../react/babel.min.js"></script>

  <script type="text/babel">
    class App extends React.Component{
      constructor(){
        super();
        this.state = {
          counter: 0
        }
      }

      render(){
        return(
          <div>
            <h2>计数器{this.state.counter}</h2>
            <button onClick={this.increment.bind(this)}>+1</button>
            <button onClick={this.decrement.bind(this)}>-1</button>
          </div>
        )
      }

      increment(){
        this.setState({
          counter: ++this.state.counter
        })
      }

      decrement(){
        this.setState({
          counter: --this.state.counter
        })
      }
    }

    ReactDOM.render(<App/>,document.getElementById('app'))
  </script>
</body>

小结

上面两个案例主要是对上一节内容的一个回顾,让你熟悉在React中的开发方式,注意一些细节问题,比如列表的渲染、this的指向,这两个案例做下来,个人感觉react比vue更加灵活,对JavaScript的要求也更高,并没有像vue中存在v-for、v-if这样的指令,而是通过JSX这种方式再借助循环来实现的,非常灵活。

认识JSX

  • 首先来看一段代码
const element = <h2>Hello React</h2>
ReactDOM.render(element,document.getElementById('app'))
  • 相信做了上面两个案例后,对这段代码并不陌生,那么这段element变量申明右侧赋值的标签语法是什么呢?
    • 它不是一段字符串(因为没有使用引号包裹),它看起来像是一段HTML原生代码,但是我们能在Js中直接给一个变量赋值HTML吗?
    • 其实是不可以的,如果我们将type = " text/babel "去掉就会出现语法错误的情况出现
    • 那么它到底是什么呢? 没错,这就是 JSX 语法
  • JSX是什么?
    • JSX是一种JavaScript的语法扩展(eXtension),也在很多地方称之为JavaScript XML,因为看起来就是一段 XML 语法
    • 它用于描述我们的 UI 界面,并且完全可以和 JavaScript 融合在一起
    • 它不同于 Vue 中的模板语法,你不需要专门学习模板语法中的一些指令(v-for、v-if、v-else)
    • 其实 Vue 也是支持 JSX 的,只是很多人不愿意写罢了

为什么React选择JSX

  • React认为渲染逻辑本质上与其它 UI 逻辑存在内在耦合
    • 比如 UI 需要绑定事件( button 、a 等等)
    • 比如 UI 中需要展示数据状态,再某些状态发生改变时,又需要改变 UI
  • 它们之间是密不可分的,所以 React 没有将标记分离到不同的文件中,而是把他们组合到了一起,这个地方就是组件(Component)
  • JSX 是嵌入到JavaScript中的一种结构语法
  • JSX 的书写规范(部分)
    • JSX 的顶层只能有一个根元素,所以我们很多时候会在外层包裹一个 div 原生(或者使用后面我们学习的 Fragment);
    • 为了方便阅读,我们通常在 JSX 的外层包裹一个小括号,这样可以方便阅读,并且 JSX 可以换行书写(render 函数中return 后面)
    • JSX 中的标签可以是单标签,也可以是双标签
      • 如果是但标签,必须以 />结尾

JSX的使用

JSX 中的注释

  • 注释有两种形式,但是都要在大括号中{}
class App extends React.Component{
  constructor(){
    super();
  }
  render(){
    return (
      <div>
        // 我是注释
        {/* 我是真的注释 */}
        {
          //我也是注释
        }
     </div>
	)
  }
}

JSX 嵌入变量

  • 情况一:当变量是 Number、String、Array类型时,可以直接显示
  • 情况二:当变量是 Null、Undefined、Boolean类型时,内容为空
    • 如果希望可以显示 null、undefined、boolean,那么需要转成字符串
    • 转换的方式有很多,比如 toString 方法 和 空字符串拼接, String(变量)等方式
  • 情况三:对象类型不能作为子元素(会报错)
class App extends React.Component {
  constructor() {
    super();
      this.state = {
        // 1. 在{}可以正常显示的内容
        name: 'why',
        age: 18,
        fav: ['run','swim','football'],
          
        // 2. 在{}中不能显示(忽略)
        test1: null,
        test2: undefined,
        test3: true,

         // 3. 对象不能作为jsx的子类
         item: {
           name: 'zxy',
           age:18,
           like: 'eat'
          }
      }
 }

 render() {
   return ( 
     <div>
       <h2>{this.state.name}</h2>
       <h2>{this.state.age}</h2>
       <h2>{this.state.fav}</h2>
       <h2>--------------本身不显示-------------</h2>
       <h2>---------但是可以转换成String类型显示-------------</h2>
       <h2>{this.state.test1 + ''}</h2>
       <h2>{String(this.state.test2)}</h2>
       <h2>{this.state.test3.toString()}</h2>
	   <h2>--------------对象类型的数据不显示会报错-------------</h2>
       {/*<h2>{this.state.item}</h2>*/}
	</div>
   )
  }
}

JSX 嵌入表达式

  • 运算符表达式
  • 三元表达式
  • 函数调用
class App extends React.Component{
    constructor(){
        super();
        this.state = {
            firstName: 'bag',
            lastName: 'bean',
            flag: true
        }
    }

    render(){
      // 对象的解构
      const {firstName,lastName} = this.state;
      return (
        <div>
            {/* 1. 插入运算符表达式 */}
            <h2>{firstName + lastName}</h2>

            {/* 2. 插入三元表达式*/}
            <h2>{this.state.flag ? this.state.firstName : this.state.lastName}</h2>

            {/* 3. 插入函数表达式*/}
            <h2>{this.callMe()}</h2>
        </div>
      )
	}

    callMe(){
        return this.state.firstName + ' ' + this.state.lastName;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值