2020前端面試系列之JSX是什麼

前言

衆所周知React Native開發中,頁面View書寫佈局採用了React 的JSX語法,而在ReactNative面試中可能會遇到有關JSX相關的面試題,今天和大家分享有關JSX的知識,爲你的面試助一臂之力。

JSX的定義

JSX到底是什麼?我們先看看[React官網](https://reactjs.org/docs/glossary.html#jsx)的定義。

JSX is a syntax extension to JavaScript. It is similar to a template

language, but it has full power of JavaScript. JSX gets compiled to

React.createElement() calls which return plain JavaScript objects

called “React elements”.

JSX是JavaScript的一種語法擴展,類似一種模板語言,但是它擁有JavaScript的全部能力。JSX被編譯成React.createElement(), React.createElement()返回一個名爲“React element”的JavaScript對象。


從以上定義可以看到JSX是作爲一種擴展存在的,那就會出現在低版本的瀏覽器或者其他開發環境中的兼容性問題。怎麼解決這個問題呢?上面定義中也提到了, JSX被編譯成React.createElement()並返回一個js對象。

JSX編譯工具-Babel

將JSX編譯成js對象就是由Babel完成的。

[Babel官網](https://babeljs.io/docs/en/)的定義:


Babel是一個工具鏈,主要用於將ECMAScript 2015+代碼轉換爲當前和舊版本瀏覽器或環境中向後兼容的JavaScript版本。


比如在ES2015中出現的箭頭函數,轉成ES5環境的支持

// Babel Input: ES2015 arrow function[1, 2, 3].map((n) => n + 1);

// Babel Output: ES5 equivalent[1, 2, 3].map(function(n) { return n + 1;});


類似的,Babel也可以編譯JSX語法。


Babel can convert JSX syntax! Check out our React preset to get

started. Use it together with the babel-sublime package to bring

syntax highlighting to a whole new level.


如下一段代碼是ReactNative經典的入門Hello World.

import React from 'react';import { Text, View } from 'react-native';

const HelloWorldApp = () => { return ( <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> <Text>Hello, world!</Text> </View> )}export default HelloWorldApp;

我們將佈局文件使用[Babel工具]編譯一下,看看編譯後的代碼是什麼樣子的

從編譯結果可以看到,所有的JSX標籤都被編譯成了React.createElement調用了,所以我們書寫JSX其實就是在寫React.createElement()函數調用。

JSX描述小結

JSX的正確描述應該是它是JavaScript調用函數React.createElement()的語法糖。


爲什麼React使用JSX

在上面分析中我們看到通過Babel轉換JSX後其實就是React.createElement的調用,爲什麼我們不直接使用React.createElement,而要使用JSX語法糖呢?

其實從上面Babel編譯截圖上可以看到,佈局中只有兩個元素View,Text,直接寫React.createElement的代碼就很多了,如果是很多元素的嵌套,那畫面沒法想象了,首先代碼閱讀體驗不好,佈局的嵌套也非常的混亂。相比較而言JSX就顯得層次分明,嵌套關係清晰。


結論:使用JSX語法糖可以使用開發人員使用類Html的標籤創建虛擬DOM進行佈局,既提高了開發效率和體驗,也降低了學習成本。


JSX是如何映射爲虛擬DOM的

我們已經知道了JSX會通過Babel編譯成React.createElement()調用,我們看一下這個方法的源碼實現:

function createElement(type, config, children) {  var propName = void 0;

// Reserved names are extracted var props = {};

var key = null; var ref = null; var self = null; var source = null;

if (config != null) { if (hasValidRef(config)) { ref = config.ref; } if (hasValidKey(config)) { key = '' + config.key; }

self = config.__self === undefined ? null : config.__self; source = config.__source === undefined ? null : config.__source; // Remaining properties are added to a new props object for (propName in config) { if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) { props[propName] = config[propName]; } } }

// Children can be more than one argument, and those are transferred onto // the newly allocated props object. var childrenLength = arguments.length - 2; if (childrenLength === 1) { props.children = children; } else if (childrenLength > 1) { var childArray = Array(childrenLength); for (var i = 0; i < childrenLength; i++) { childArray[i] = arguments[i + 2]; } { if (Object.freeze) { Object.freeze(childArray); } } props.children = childArray; }

// Resolve default props if (type && type.defaultProps) { var defaultProps = type.defaultProps; for (propName in defaultProps) { if (props[propName] === undefined) { props[propName] = defaultProps[propName]; } } } { if (key || ref) { var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type; if (key) { defineKeyPropWarningGetter(props, displayName); } if (ref) { defineRefPropWarningGetter(props, displayName); } } } return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);}

通過以上源碼我們可以看到createElement函數接受三個參數,分別是type, config, childen。

  • type:標識節點的類型。可以是標記名字符串(例如'div'或'span')、React組件類型(類或函數)或React片段類型。

  • config: 組件的所有屬性以鍵值對的形式存儲在config中,以對象的形式傳遞。

  • childen: 組件的嵌套內容,也就是子元素,子節點,也是以對象的形式進行傳遞。


createElement函數主要做了如下工作:

  1. 根據config,處理key, ref, self, source的賦值工作

  2. 遍歷config,刷選適合的屬性放入到props中

  3. 獲取子元素放入到children中

  4. 處理defaultProps

  5. 最終調用ReactElement來創建元素。

如何渲染到DOM

ReactElement是通過React.render()方法渲染到DOM。

下面是一個示例

const element = <h1>Hello, world</h1>;ReactDOM.render(element, document.getElementById('root'));

render()

ReactDOM.render(element, container[, callback])

ReactDOM.render函數接受三個參數,第一個是代表元素或者節點,第二個container是一個真是的DOM節點,作爲一個DOM容器,用於包含渲染的元素內容。


總結

JSX只是一種語法糖,你也可以不使用JSX進行書寫頁面佈局,但是使用JSX會使頁面佈局層次分明,嵌套邏輯清晰,方便前端開發人員使用熟悉的類Html標籤進行開發,調高了開發體驗和效率,並且也提供了更多有用錯誤和警告信息。

通過以上內容,相信面試的時候遇到此類問題,一定可以回答的比較深入了。


--- END ---

君偉說


本文分享自微信公衆號 - 君偉說(wayne90214)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章