fillText 方法作用是繪制一行文字。語法:void ctx.fillText(text, x, y [, maxWidth]);變量說明變量名類型是否必須說明textString是要繪制的文本。xNumber是文本起始點的 x 軸坐標(biāo)。yNumber是文本起始點的 y 軸坐標(biāo)。maxWidthNumber是可選,需要繪制的最大寬度。如果指定了值,并且經(jīng)過計算字符串的寬度比最大寬度還要寬,字體為了適應(yīng)會使用一個水平縮小的字體或者小號的字體。
包含從 0 到 10 之間所有整數(shù)的集合 >>> {i for i in range(10)}{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}將集合中的元素乘以 10>>> set = {1, 2, 3}>>> {i*10 for i in set}{10, 20, 30}將列表中所有的字符串變成大寫 >>> set = {'www', 'imooc', 'com'}>>> {i.upper() for i in set}{'WWW', 'IMOOC', 'COM'}包含所有的正整數(shù)的集合 >>> set = {-1, 1, -2, 2, -3, 3}>>> {i for i in list if i > 0}{1, 2, 3}包含兩個字符的字符串集合 >>> {x + y for x in 'ABC' for y in 'XYZ'}{'AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ'}
通過在父級元素設(shè)置這兩個屬性,可以簡單的理解為設(shè)置一個觀察者的位置,也就是我們的眼睛 perspective 的大小代表眼睛距離元素的位置。perspective-origin,代表眼睛所在的坐標(biāo)點,我們可以設(shè)置 x 軸和 y 軸,這兩個屬性其實就間接的組成了 (x,y,z)空間坐標(biāo)組,要注意的是,這是設(shè)置都是在父元素上進(jìn)行的。
畫布左上角(0,0)默認(rèn)原點,x 坐標(biāo)向右方增長,y 坐標(biāo)則向下方延伸:但是,Canvas 的坐標(biāo)體系并不是一成不變的,原點是可改變的。坐標(biāo)變換:可以對 Canvas 坐標(biāo)系統(tǒng)進(jìn)行移動 translate、旋轉(zhuǎn) rotate 和縮放等操作。坐標(biāo)變換之后繪制的圖形 x,y 偏移量都以新原點為準(zhǔn), 旋轉(zhuǎn)角度,縮放比,以新坐標(biāo)系角度為準(zhǔn)。
使用 circle 表示圓形:1088其中包含 3 個屬性r 圓的半徑;cx 圓心坐標(biāo) x 值;cy 圓心坐標(biāo) y 值。
面試官提問:給定兩個字符串,求解最長公共子序列。題目解析:求解最長公共子序列問題是來源于算法網(wǎng)站LeetCode的經(jīng)典題目,題目鏈接:https://leetcode.com/problems/longest-common-subsequence/。首先是明確子序列的定義,例如對于字符串imooc,那么im、imo、imc都是它的子序列,子序列可以連續(xù)也可以不連續(xù),如果是連續(xù)出現(xiàn)的,例如字符串imoo,一般被叫做子序列串。其次是明確公共子序列的定義,對于兩個字符串,如果包含相同的子序列,那么這個子序列就是兩個字符串的公共子序列,例如imooc和moocer的公共子序列就有m和mo等,所有公共子序列中最長的子序列就是最長公共子序列(Longest Common Subsequence)。首先從定性的角度來看,如果兩個字符串中,一個字符串的長度為零,那么最長公共子序列長度一定為零。其次從定量的角度分析這個問題,例如給定的兩個字符串分別是X={x1,x2,x3 ... xm} 和Y={y1,y2,y3 ... ym},表示X字符串是通過x1、x2一直到xm個連續(xù)字符組成,Y字符串同理。求解動態(tài)規(guī)劃的通用方案是找到子問題的共性,字符串的子問題就是子字符串,我們假設(shè)X'={x1,x2,x3 ... xi} 和 Y'={y1,y2,y3 ... yi} 的最長公共子序列是L,其中i<m。那么按照遞歸就有兩種狀態(tài)轉(zhuǎn)移流程:(1)如果xi=yi,也就是兩個字符串的子字符串的最后一個字符剛好相等,那么{L,x(i+1)}或者{L,y{i+1}}就是新的最長公共子序列;(2)如果xi≠yi,也就是兩個字符串的子字符串的最后一個字符并不相等,那么問題就可以轉(zhuǎn)換為求下面兩種情況的最長公共子序列:第一種情況:X'={x1,x2,x3 ... x(i-1)} ,Y'={y1,y2,y3 ... yi}的最長公共子序列,假設(shè)為L1;第二種情況:X'={x1,x2,x3 ... xi} ,Y'={y1,y2,y3 ... y(i-1)}的最長公共子序列,假設(shè)為L2。最終需要的結(jié)果就是L = max(L1,L2)。我們用 Java 語言實現(xiàn)上面描述的算法,示例:class Solution { public int longestCommonSubsequence(String text1, String text2) { int n = text1.length(); int m = text2.length(); int[][] dp = new int[n+1][m+1]; //設(shè)置dp方程初始值 for(int i = 0; i < n+1; i++){ for(int j = 0; j < m+1; j++){ if(i == 0 || j == 0){ dp[i][j] = 0; } } } //循環(huán)更新狀態(tài) for(int i = 1; i < n+1; i++){ for(int j = 1; j < m+1; j++){ if(text1.charAt(i-1) == text2.charAt(j-1)){ //如果這個位置的字符相同,說明相對于dp[i-1][j-1]剛好長一個字符 dp[i][j] = 1 + dp[i-1][j-1]; } else{ // 否則采用公共長度最長的 dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]); } } } //返回結(jié)果 return dp[n][m]; }}
在實際的應(yīng)用過程之中,有很多的情況下,我們需要使用 tf.function 來加速模型的速度并自定義訓(xùn)練過程。那么這個時候我們要如何才能查看網(wǎng)絡(luò)的模型結(jié)構(gòu)圖呢?其實也很簡單,我們只需經(jīng)過如下幾個步驟:確保 tf.function 函數(shù)修飾了我們需要進(jìn)行可視化的操作,這邊就是模型的過程;創(chuàng)建一個 TensorBoard 的日志寫入器 tf.summary.create_file_writer() ;通過 tf.summary.trace_on() API 進(jìn)行變量路徑的追蹤;執(zhí)行我們需要可視化的操作;使用 tf.summary.trace_export() API 將圖寫入日志。在這里,我們可以使用一個很簡單的例子來查看操作的結(jié)構(gòu):# 定義網(wǎng)絡(luò)的操作@tf.functiondef test_func(x, y): z = tf.matmul(x, y) z = z * 5.0 z = tf.nn.relu(z) return z# 創(chuàng)建寫入器writer = tf.summary.create_file_writer('./logs/3')# 創(chuàng)建初試數(shù)據(jù)x = tf.random.uniform((5, 5))y = tf.random.uniform((5, 5))# 開啟變量追蹤tf.summary.trace_on(graph=True, profiler=True)# 運(yùn)行程序z = test_func(x, y)# 將日志輸出with writer.as_default(): tf.summary.trace_export( name="test_func_graph", step=1, profiler_outdir='./logs/3')在這里,我們首先定義了一個基本的模型操作,該模型操作由一個矩陣乘法、一個常量乘法、外加一個 Relu 激活層組成。在運(yùn)行完操作之后,我們便使用 tf.summary.trace_export() API 來將模型圖輸入道日志之中。然后我們便可以在瀏覽器之中查看到相應(yīng)的模型圖:可以看到,該模型圖完整的反映了我們的操作。
使用 yum 命令安裝 emacs 編輯器命令如下:yum -y install emacs執(zhí)行結(jié)果如下圖:等待安裝完成輸入 emacs -v 即可在 CentOs 8 操作界面打開 emacs 編輯器:
使用 yum 命令安裝 nano 編輯器命令如下:yum -y install nano執(zhí)行結(jié)果如下圖:等待安裝完成輸入 nano -v 即可查看到 nano 編輯器的相關(guān)信息:
createRadialGradient() 方法會依照參數(shù)確定兩個圓的坐標(biāo),繪制放射性漸變,該方法返回 CanvasGradient 對象。語法:CanvasGradient ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);變量說明:變量名類型是否必須說明x0Number是開始圓形的 x 軸坐標(biāo)。y0Number是開始圓形的 y 軸坐標(biāo)。r0Number是開始圓形的半徑。x1Number是結(jié)束圓形的 x 軸坐標(biāo)。y1Number是結(jié)束圓形的 y 軸坐標(biāo)。r1Number是結(jié)束圓形的半徑。返回值:CanvasGradient一個根據(jù)指定線路初始化的徑向漸變對象。
createBitmap(int width, int height, Bitmap.Config config):根據(jù)傳入的寬高、創(chuàng)建一個可修改的 Bitmap 對象createBitmap(DisplayMetrics display, int width, int height, Bitmap.Config config):相比上一個接口,這個可以在創(chuàng)建的時候傳入一些參數(shù)createBitmap(Bitmap src):根據(jù)傳入的 Bitamp 創(chuàng)建一個新的 Bitampcopy(Bitmap.Config config, boolean isMutable):將 Bitamp 對象的所有像素復(fù)制到一個新的 Bitmap 當(dāng)中extractAlpha():提取原始 Bitmap 的透明度并返回一個新的 BitampgetConfig():獲取 Bitamp 的配置信息getDensity():返回 Bitamp 的圖片像素密度getRowBytes():返回 Bitamp 圖片的像素字節(jié)數(shù)組setPixel(int x, int y, int color):設(shè)置圖片的(x, y)坐標(biāo)點上的色值setDensity(int density):設(shè)置圖片像素密度
既然了解了 tf.function 的用法,那么我們便來測試一下 tf.function 的性能,我們采用一個簡單的卷積神經(jīng)網(wǎng)絡(luò)來進(jìn)行測試:import tensorflow as tfimport timeitdef f1(layer, image): y = layer(image) return y@tf.functiondef f2(layer, image): y = layer(image) return ylayer = tf.keras.layers.Conv2D(300, 3)image = tf.zeros([64, 32, 32, 3])model = tf.keras.models.Sequential([ tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)), tf.keras.layers.MaxPooling2D((2, 2)), tf.keras.layers.Conv2D(64, (3, 3), activation='relu'), tf.keras.layers.MaxPooling2D((2, 2)), tf.keras.layers.Conv2D(128, (3, 3), activation='relu'), tf.keras.layers.Flatten(), tf.keras.layers.Dense(128, activation='relu'), tf.keras.layers.Dense(64, activation='relu'), tf.keras.layers.Dense(10, activation='softmax')])print(timeit.timeit(lambda: f1(model, image), number=500))print(timeit.timeit(lambda: f2(model, image), number=500))在這里,我們定義了兩個相同的函數(shù),其中一個使用了 tf.function 進(jìn)行修飾,而另外一個沒有。在這里我們使用 lambda 函數(shù)來讓函數(shù)重復(fù)執(zhí)行 500 次,并且使用 timeit 來進(jìn)行時間的統(tǒng)計,得到兩個函數(shù)的執(zhí)行時間,從而進(jìn)行比較。最終,我們可以得到結(jié)果:17.2040366439998712.07886406200032由此可以看出,我們的 tf.function 已經(jīng)提升了一定的速度,但是提升的速度有限,目前大概提升了 25 % 的速度。這是因為我們的計算仍然還是太簡單了,當(dāng)我們計算非常大的時候,性能會有很大的提升。
const a: number = 1const add = (x: number, y:number) => x + y interface User { nickname: string, department: string}class Employee implements User { public nickname!: string public department!: string}type used = true | falseexport { add }export { a as level, used as status, Employee }解釋: 在導(dǎo)出時,可以用 as 關(guān)鍵字將聲明重命名。
ellipse 方法作用是繪制一個中點在 (x, y) 的橢圓。變量說明:變量名類型是否必須說明xNumber是指定橢圓中心位置的X坐標(biāo)。yNumber是指定橢圓中心位置的Y坐標(biāo)。radiusXNumber是橢圓長半軸。radiusYNumber是橢圓短半軸。rotationNumber是橢圓的旋轉(zhuǎn)角度,以弧度表示(非角度度數(shù))。sAngleNumber是起始角,以弧度計,(弧的圓形的三點鐘位置是 0 度)。eAngleNumber是結(jié)束角,以弧度計。counterclockwiseBoolean否規(guī)定應(yīng)該逆時針還是順時針繪圖,false = 順時針,true = 逆時針。
基礎(chǔ)的類型推斷發(fā)生在 初始化變量,設(shè)置默認(rèn)參數(shù)和決定返回值時。初始化變量例子:let x = 3 // let x: numberlet y = 'hello world' // let y: stringlet z // let z: any代碼解釋:變量 x 的類型被推斷為數(shù)字,變量 y 的類型被推斷為字符串。如果定義時沒有賦值,將被推斷為 any 類型。設(shè)置默認(rèn)參數(shù)和決定返回值時的例子:// 返回值推斷為 numberfunction add(a:number, b:10) { return a + b}const obj = { a: 10, b: 'hello world'}obj.b = 15 // Error,Type '15' is not assignable to type 'string'代碼解釋:第 1 行,參數(shù) b 有默認(rèn)值 10,被推斷為 number 類型。第 2 行,兩個 number 類型相加,函數(shù) add() 返回值被推斷為 number 類型。最后一行,obj 的類型被推斷為 {a: number, b: string},所以屬性 b 不能被賦值為數(shù)字。const obj = { protagonist: 'Sherlock', gender: 'male'}let { protagonist } = obj代碼解釋: 通過解構(gòu)賦值也可以完成正確的類型推斷:let protagonist: string。
在 Scientific mode 模式,可以將代碼格式化為一組可執(zhí)行代碼片斷,每個片斷都可以單獨運(yùn)行。要將代碼拆分為獨立運(yùn)行的部分,只需在適當(dāng)?shù)奈恢锰砑? #%% 行。在 main.py 中加入以下代碼:主要功能是生成一個散點圖。import numpy as npN = 50x = np.random.rand(N)y = np.random.rand(N)colors = np.random.rand(N)area = np.pi * (15 * np.random.rand(N))**2 # 0 to 15 point radiiplt.scatter(x, y, s=area, c=colors, alpha=0.5)plt.show()加了上面代碼后,main.py 除了生成上面的折線圖,還會再生成散點圖。為了使這兩張圖的生成分段執(zhí)行,如下圖所示,加兩行 # %% 行,然后分別點擊邊框中綠色箭頭執(zhí)行不同代碼。
text-shadow 一共接受 4 個參數(shù),前兩個是陰影的位置通過 x,y坐標(biāo)系來設(shè)定,第三個參數(shù)設(shè)定模糊的大小,最后一個參數(shù)設(shè)定陰影的顏色。
這個標(biāo)簽用于繪制分?jǐn)?shù),它的子元素必須是2個,不然的話會出現(xiàn)報錯,例如:(請使用 Firefox 運(yùn)行下面代碼)1073以上示例中的分母是 10,分子是 y。
不同于上一節(jié)所示上標(biāo)、下標(biāo),在數(shù)學(xué)公式中有一種更為簡單的定義方式。實例 6:上標(biāo)符號:$x^2$ 下標(biāo)符號:$y_1$ 組合符號:$a^{x^{2}+y^{2}}$ 其渲染效果如下:
在我們開始的我們的可視化的之旅之前,需要簡單的介紹一些數(shù)據(jù)分析工具,我們的數(shù)據(jù)可視化的任務(wù)也是建立在數(shù)據(jù)分析的基礎(chǔ)之上。Python 的主要數(shù)據(jù)分析工具如下所示:Numpy:這個是數(shù)據(jù)計算的工具,主要用來進(jìn)行矩陣的運(yùn)算,矢量運(yùn)算等等。Scipy:科學(xué)計算函數(shù)庫,主要用在學(xué)術(shù)領(lǐng)域,主要包含線性代數(shù)模塊,信號與圖像處理模塊,統(tǒng)計學(xué)模塊等等。Sympy:數(shù)學(xué)符號計算庫Pandas:包含了 numpy 的各種功能,并提供了更加強(qiáng)大的函數(shù),以及更加豐富的數(shù)據(jù)模型。Pandas的主要數(shù)據(jù)結(jié)構(gòu)為 Series 和 DataFrame。Series 可以當(dāng)作是一般的數(shù)組,區(qū)別就是Series數(shù)組有索引的性質(zhì),這個和普通的數(shù)組十分不同。我們可以通過series.index來獲取index的值。DataFrame 可以把它想像成數(shù)據(jù)的表格的概念,它是把一個或者多個Series按照邏輯合并后的二維數(shù)據(jù)結(jié)構(gòu)。接下來讓我們開始我們數(shù)據(jù)可視化之旅吧。首選,我們來畫一張最基本的直方圖。from matplotlib import pyplot //引入matplotlib庫進(jìn)行繪制圖形import numpy as np //引入numpy,來生成隨機(jī)數(shù)x = np.arage(12)y = np.random.rand(12)labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec]pyplot.bar(x,y, color='red', tick_label=labels) //繪制條形圖pyplot.title('first chart')plot.show()上面這幅是條形圖,我們可以看到 x 軸是月份,總共分為 12 個月,縱軸則是每個月的數(shù)值在 0-1 之間的值。x = np.random.randn(800)pyplot.hist(x,150) //繪制直方圖pyplot.title('second chart')pyplot.show()上面這幅是直方圖,默認(rèn)的為藍(lán)色,數(shù)據(jù)在我們?nèi)‰S機(jī)數(shù)之后,基本上是呈現(xiàn)一個對稱分布的情況。from mpl_toolkits.mplot3d import Axes3D //引入三維圖形包pic = pyplot.figure()ax = Axes3D(pic)x = np.arange(-1, 3, 0.3) //x軸取值范圍y = np.arange(-1, 3, 0.3 //y軸取值范圍a, b = np.meshgrid(x,y) //繪制二維圖形c = a**2 + b **2ax.plot_surface(a,b,c, cmap= pyplot.get_cmap('rainbow')) //繪制三維圖ax.set_zlim(-1, 10)pyplot.title('last chart')pyplot.show()除了簡單的二維圖形,同樣,matplotlib 也可以很輕松的繪制三維圖形,上面的代碼就是我們繪制三位圖形的簡單版本,效果如下所示:
在接收到各個狀態(tài)的事件之后,我們需要從中獲取當(dāng)前的觸摸/滑動坐標(biāo),如下:float x = ev.getX();float y = ev.getY();
首先我們和之前一樣,進(jìn)行數(shù)據(jù)的獲?。篿mport numpy as npimport pandas as pdimport tensorflow as tfx_train = pd.read_csv('https://storage.googleapis.com/tf-datasets/titanic/train.csv')x_test = pd.read_csv('https://storage.googleapis.com/tf-datasets/titanic/eval.csv')y_train = x_train.pop('survived')y_test = x_test.pop('survived')然后我們要定義連序列以及離散列:categories = ['sex', 'n_siblings_spouses', 'parch', 'class', 'deck', 'embark_town', 'alone']numeric = ['age', 'fare']然后我們就要定義特征列了:def one_hot_cat_column(feature_name, vocab): return tf.feature_column.indicator_column(tf.feature_column.categorical_column_with_vocabulary_list(feature_name, vocab))feature_columns = []for feature_name in categories: feature_columns.append(one_hot_cat_column(feature_name, x_train[feature_name].unique()))for feature_name in numeric: feature_columns.append(tf.feature_column.numeric_column(feature_name,dtype=tf.float32))在第一個 one_hot_cat_column 函數(shù)之中,我們對于特征列進(jìn)行了獨熱編碼。并且我們對于離散列與連續(xù)列進(jìn)行了不同的處理。然后我們定義輸入函數(shù),這里我們?nèi)匀欢x了兩個輸入函數(shù),一個為訓(xùn)練使用,另一個為測試使用:def train_input_fn(x, y): dataset = tf.data.Dataset.from_tensor_slices((dict(x), y)) dataset = dataset.shuffle(len(y_train)).repeat().batch(32) return datasetdef test_input_fn(x, y): dataset = tf.data.Dataset.from_tensor_slices((dict(x), y)).batch(32) return datasettrain_input = lambda: train_input_fn(x_train, y_train)test_input = lambda: test_input_fn(x_test, y_eval)在這之后,我們便需要定義我們的提升樹模型了:estimator = tf.estimator.BoostedTreesClassifier(feature_columns, n_batches_per_layer=len(y_train) // 32)這里的第一個參數(shù) feature_columns 就是特征列,這個很好理解;關(guān)鍵是第二個參數(shù),大家要記住的是, n_batches_per_layer 這個參數(shù)需要是樣本的數(shù)量與批次大小的商,因為這里我們的批次大小為 32 ,因此我們設(shè)置其為 (y_train) // 32 。最后便是模型的訓(xùn)練了:estimator.train(train_input, max_steps=100)result = estimator.evaluate(test_input)print(pd.Series(result))于是我們可以的得到輸出:accuracy 0.787879accuracy_baseline 0.625000auc 0.835384auc_precision_recall 0.825271average_loss 0.554901label/mean 0.375000loss 0.552625precision 0.747126prediction/mean 0.454899recall 0.656566global_step 100.000000dtype: float64于是我們可以得到了我們訓(xùn)練結(jié)果: 78% 的準(zhǔn)確率。為了做對比,大家可以采用一個簡單的線性分類器來做對比,也就是:tf.estimator.LinearClassifier(feature_columns)通過對比,大家就可以看到集成學(xué)習(xí)的優(yōu)勢。
字符串類型的數(shù)據(jù)表示一段文本,使用單引號或者雙引號創(chuàng)建:單引號字符串 ‘hello’雙引號字符串 “world”在 python 中使用字符串的例子如下:>>> x = 'hello'>>> x'hello'>>> y = "world">>> y'world'在第 1 行,創(chuàng)建了使用單引號字符串 hello,并將值賦給變量 x 在第 2 行,顯示變量 x 的值為 ‘hello’在第 3 行,創(chuàng)建了使用雙引號字符串 world,并將值賦給變量 y 在第 4 行,顯示變量 y 的值為 ‘world’使用單引號或者雙引號創(chuàng)建的字符串只能在一行,而使用三引號允許一個跨多行的字符串。使用 3 個單引號創(chuàng)建的多行字符串示例如下:s = '''line 1line 2line 3'''print(s)使用 3 個雙引號創(chuàng)建的多行字符串示例如下:s = """line 1line 2line 3"""print(s)以上程序的輸出如下:line 1line 2line 3
shadowOffsetY 屬性作用是設(shè)置垂直偏移量,可以為負(fù)數(shù),負(fù)數(shù)值向上偏移。變量說明:屬性名類型說明shadowOffsetYNumber設(shè)置陰影在 Y 軸方向的偏移量,負(fù)值表示向上偏移,正值表示向下偏移,默認(rèn)為0。
const a: number = 1const add = (x: number, y:number) => x + y interface User { nickname: string, department: string}class Employee implements User { public nickname!: string public department!: string}type used = true | falseexport { a, add, Employee }解釋: 先進(jìn)行聲明操作,最終統(tǒng)一使用 export 關(guān)鍵字導(dǎo)出。
通常無論是控件還是布局我們會先介紹屬性,但是 ScrollView 本質(zhì)是一個 FrameLayout,作用也只是增加一個滾動效果,并沒有什么很特別的屬性,這里主要介紹一下幾個控制滾動的 API:fullScroll():將列表滾動到頂部或者底部:ScrollView.FOCUS_DOWN 表示滾動到底部;ScrollView.FOCUS_UP 表示滾動到頂部。scrollTo():將列表滾動到指定位置,參數(shù)為 x/y,分別表示橫縱坐標(biāo)的坐標(biāo)值。這里要注意如果是縱向的 ScrollView,那么橫坐標(biāo)(x)是無效的;相反橫向的 ScrollView,縱向(y)是無效的。
export 是導(dǎo)出語法,import 是導(dǎo)入語法。看下面的實例:// a.jsexport let x = 1;export let y = 2;// main.jsimport {x, y} from './a.js';console.log(x, y)上面代碼中,a.js 文件中使用 export 導(dǎo)出 x 和 y 兩個變量,在 mian.js 文件中使用 import 進(jìn)行導(dǎo)入。a.js 中還可以使用對象的方式導(dǎo)出:let a = 1;let b = 2;export { a, b,}從上面的 main.js 文件中可以看出,export 使用的是引用方式進(jìn)行導(dǎo)出的,導(dǎo)出的是一個接口,所以不能直接導(dǎo)出一個值。我們?nèi)缦聦嵗簂et a = 1;export a; // 編譯報錯// 正確的方式如下Export let a = 1;雖然使用 export 不能直接導(dǎo)出一個值,但是可以使用 export default 導(dǎo)出一個特定的值:export default 100;export 模塊導(dǎo)出的是一個接口,在模塊內(nèi)如果數(shù)據(jù)更新,則所依賴的地方的值都是最新的。// a.jslet a = 1;setInterval(() => { a++})export { a}// main.jsimport { a } from './a.js';setInterval(() => { consolog.log(a)})import 有聲明的特點,類似 var 的特點,可以實現(xiàn)變量提升,但是不能修改變量對應(yīng)的值。// main.jsconsole.log(a)import { a } from './a.js';a = 100; // 這樣賦值是錯誤的使用 export + from 命令的方式,提供了一種便捷的方式在當(dāng)前的模塊導(dǎo)出其他模塊的內(nèi)容,不能在當(dāng)前模塊下使用導(dǎo)出的變量。// b.jslet a = 1;let b = 2;export { a, b,}// a.jsexport {a,b} from './b.js';export c = () => {}// 等價于使用import 先導(dǎo)入,然后再使用 export 導(dǎo)出import { a, b } from './b';export { a, b,}// main.jsimport {a, b, c} from './a.js'export 和 import 命令規(guī)定要處于模塊頂層,一旦出現(xiàn)在塊級作用域內(nèi),就會報錯。// a.js{ export let a = 1;}// main.js{ import { a } from './a';}//控制臺答應(yīng)錯誤內(nèi)容: 'import' and 'export' may only appear at the top level上面的代碼中 export 和 import 都放在塊級作用域中的,執(zhí)行時會報錯,提升你 export 和 import 只能在頂級出現(xiàn)。
可索引類型接口讀起來有些拗口,直接看例子:// 正常的js代碼let arr = [1, 2, 3, 4, 5]let obj = { brand: 'imooc', type: 'education'}arr[0]obj['brand']再來看定義可索引類型接口:interface ScenicInterface { [index: number]: string}let arr: ScenicInterface = ['西湖', '華山', '故宮']let favorite: string = arr[0]示例中索引簽名是 number類型,返回值是字符串類型。另外還有一種索引簽名是 字符串類型。我們可以同時使用兩種類型的索引,但是數(shù)字索引的返回值必須是字符串索引返回值類型的子類型。通過下面的例子理解這句話:// 正確interface Foo { [index: string]: number; x: number; y: number;}// 錯誤interface Bar { [index: string]: number; x: number; y: string; // Error: y 屬性必須為 number 類型}代碼解釋:第 12 行,語法錯誤是因為當(dāng)使用 number 來索引時,JavaScript 會將它轉(zhuǎn)換成 string 然后再去索引對象。也就是說用 100(一個number)去索引等同于使用"100"(一個string)去索引,因此兩者需要保持一致。
這里一定要記住這幾個要點:上欄和下欄的寬度加起來要剛好是屏幕的高度下欄一定要寫overflow-y: auto下欄的背景什么的最好寫在子元素上,除非你就是想要這種背景不動的效果
可以在 StudentModel 中創(chuàng)建如下方法處理追加字段值: public function getCreatedAtTextAttr() { return date('Y-m-d H:i',$this->created_at); }如下圖所示:Tips: 追加字段處理的方法命名格式為 getAaaBbbAttr() 這種格式,其中 AaaBbb 是追加字段按照大駝峰命名書寫的。