javascript 列では、フロントエンド コードの能力を向上させるいくつかの方法を紹介します。
#無料のおすすめ:JavaScript(ビデオ)
これまでの開発経験の中で、さまざまな奇妙なバグに対処してきた中で、コードの堅牢性(堅牢性)が作業効率や生活の質を向上させるための重要な指標であることに気づき、この記事では主にコードの堅牢性を向上させるためのいくつかの考えをまとめます。- JavaScript 単体テストを真剣に書く
- コードのログイン方法
api/xxx/list のインターフェイスは、ドキュメント
{ code: 0, msg: "", data: [ // ... 具体数据 ], };复制代码の規則に従って、フロントエンド コードは次のようになります。バックグラウンドから返されるデータは配列であると想定しているため、
const {code, msg, data} = await fetchList() data.forEach(()=>{})复制代码として記述されます。そのため、
data.forEach が直接使用されます。共同デバッグ中にいくつかの例外が見つからなかった場合、
- は、データがない場合にデータが
- []
を返すことが期待されています。空の配列ですが、バックグラウンドの実装は
dataフィールド
を返しませんその後のインターフェイスの更新、データが配列から辞書に変更され、フロントエンドとの同期が適時に行われませんでした
data.forEach# を使用するとエラーが報告されます。 ##,
したがって、バックエンド インターフェイスの戻り値が直接使用される場所に、次のコードを追加するのが最善です型検出
Array.isArray(data) && data.forEach(()=>{})复制代码
同様に、バックエンドもフロントエンドのリクエストパラメータを処理するときに、関連する型検出を実行する必要があります。
Null 値結合演算子
JavaScript の動的な性質により、
x.y.z などのオブジェクトの特定の属性をクエリするときは、## を検出するのが最善です。 #x と
y 存在しますか?
let z = x && x.y && x.y.z复制代码
このように頻繁に書くのは非常に面倒です。dart でオブジェクトのプロパティに安全にアクセスする方がはるかに簡単です
var z = a?.y?.z;复制代码ES2020 では、
null
?? 演算子と ?. 演算子を含むドラフト値結合演算子 は、Dart と同じようにオブジェクト プロパティに安全にアクセスできます。現時点では、最新バージョンの Chrome を開いてテストできます
その前に、オブジェクトのプロパティを安全に取得するメソッドをカプセル化できます
function getObjectValueByKeyStr(obj, key, defaultVal = undefined) { if (!key) return defaultVal; let namespace = key.toString().split("."); let value, i = 0, len = namespace.length; for (; i フロントエンドは避けられません さまざまなブラウザやデバイスを扱う場合、非常に重要な問題は <p>互換性 </p> です。特に ES2015 の機能を使用してコードを開発することに慣れているので、<p>polyfill<strong>は役立ちます私たちの問題のほとんどを解決します。 </strong><code>例外処理を覚えておいてください</code></p>参考:<h2 data-id="heading-3"></h2><p>JS エラー処理 MDN</p>
- JS は UI 用の統合例外処理ソリューションを構築します。このシリーズの記事非常に良い
- 例外処理は、コードの堅牢性の主な保証です。例外処理には 2 つの側面があります。
適切なエラー処理により、ユーザー エクスペリエンスが向上します。コードが間違っている場合、ユーザーに適切なプロンプトを表示します。
- エラー処理をカプセル化します。これにより、開発量が削減され、コードからエラー処理が切り離されます。
- エラー オブジェクト
// Create an object type UserExceptionfunction UserException (message){ // 包含message和name两个属性
this.message=message; this.name="UserException";
}// 覆盖默认[object Object]的toStringUserException.prototype.toString = function (){ return this.name + ': "' + this.message + '"';
}// 抛出自定义错误function f(){ try { throw new UserException("Value too high");
}catch(e){ if(e instanceof UserException){ console.log('catch UserException') console.log(e)
}else{ console.log('unknown error') throw e
}
}finally{ // 可以做一些退出操作,如关闭文件、关闭loading等状态重置
console.log('done') return 1000 // 如果finally中return了值,那么会覆盖前面try或catch中的返回值或异常
}
}
f()复制代码
同期コード 同期コードの場合、を使用して、責任連鎖パターン
を通じてエラーをカプセル化できます。つまり、現在の関数がエラーを処理できる場合は、catch で処理します。対応するエラーを処理できない場合は、catch を前の層に再度スローします。function a(){ throw 'error b'}// 当b能够处理异常时,则不再向上抛出function b(){ try{ a() }catch(e){ if(e === 'error b'){ console.log('由b处理') }else { throw e } } }function main(){ try { b() }catch(e){ console.log('顶层catch') } }复制代码非同期コードSince catch非同期コードでスローされた例外を取得できません。責任の連鎖を実現するには、例外処理をコールバック関数
function a(errorHandler) { let error = new Error("error a"); if (errorHandler) {
errorHandler(error);
} else { throw error;
}
}function b(errorHandler) { let handler = e => { if (e === "error b") { console.log("由b处理");
} else {
errorHandler(e);
}
}; setTimeout(() => {
a(handler);
});
}let globalHandler = e => { console.log(e);
};
b(globalHandler);复制代码
Prmise の例外処理を通じて非同期タスクに渡す必要があります。 Promise には 3 つの状態のみが含まれます: pending
、rejected、
fulfilled
let promise2 = promise1.then(onFulfilled, onRejected)复制代码
Promise が例外をスローするためのいくつかのルール
function case1(){ // 如果promise1是rejected态的,但是onRejected返回了一个值(包括undifined),那么promise2还是fulfilled态的,这个过程相当于catch到异常,并将它处理掉,所以不需要向上抛出。 var p1 = new Promise((resolve, reject)=>{ throw 'p1 error' }) p1.then((res)=>{ return 1 }, (e)=>{ console.log(e) return 2 }).then((a)=>{ // 如果注册了onReject,则不会影响后面Promise执行 console.log(a) // 收到的是2 }) }function case2(){ // 在promise1的onRejected中处理了p1的异常,但是又抛出了一个新异常,,那么promise2的onRejected会抛出这个异常 var p1 = new Promise((resolve, reject)=>{ throw 'p1 error' }) p1.then((res)=>{ return 1 }, (e)=>{ console.log(e) throw 'error in p1 onReject' }).then((a)=>{}, (e)=>{ // 如果p1的 onReject 抛出了异常 console.log(e) }) }function case3(){ // 如果promise1是rejected态的,并且没有定义onRejected,则promise2也会是rejected态的。 var p1 = new Promise((resolve, reject)=>{ throw 'p1 error' }) p1.then((res)=>{ return 1 }).then((a)=>{ console.log('not run:', a) }, (e)=>{ // 如果p1的 onReject 抛出了异常 console.log('handle p2:', e) }) }function case4(){ // // 如果promise1是fulfilled态但是onFulfilled和onRejected出现了异常,promise2也会是rejected态的,并且会获得promise1的被拒绝原因或异常。 var p1 = new Promise((resolve, reject)=>{ resolve(1) }) p1.then((res)=>{ console.log(res) throw 'p1 onFull error' }).then(()=>{}, (e)=>{ console.log('handle p2:', e) return 123 }) }复制代码したがって、
onRejected
現在の Promise のエラーを処理できます。それができない場合は、次のpromiseasync
## にスローします。
本質的にはプロミス構文の糖衣であるため、
promise.catch同様のキャプチャメカニズム<pre class="brush:php;toolbar:false">function sleep(cb, cb2 =()=>{},ms = 100) {
cb2() return new Promise((resolve, reject) => { setTimeout(() => { try {
cb();
resolve();
}catch(e){
reject(e)
}
}, ms);
});
}// 通过promise.catch来捕获async function case1() { await sleep(() => { throw "sleep reject error";
}).catch(e => { console.log(e);
});
}// 通过try...catch捕获async function case2() { try { await sleep(() => { throw "sleep reject error";
})
} catch (e) { console.log("catch:", e);
}
}// 如果是未被reject抛出的错误,则无法被捕获async function case3() { try { await sleep(()=>{}, () => { // 抛出一个未被promise reject的错误
throw 'no reject error'
}).catch((e)=>{ console.log('cannot catch:', e)
})
} catch (e) { console.log("catch:", e);
}
}复制代码</pre>
より安定したサードパーティモジュール##を使用することもできます#日付の書式設定などの比較的小さな関数を実装する場合、npm から成熟したライブラリを見つけることに慣れていない場合がありますが、開発時間やテスト ケースが不十分なため、代わりに関数パッケージを自分で作成します。考慮されていない境界条件に遭遇すると、バグが発生しやすくなります。
这也是npm上往往会出现一些很小的模块,比如这个判断是否为奇数的包:isOdd,周下载量居然是60来万。
使用一些比较成熟的库,一个很重要原因是,这些库往往经过了大量的测试用例和社区的考验,肯定比我们顺手些的工具代码更安全。
一个亲身经历的例子是:根据UA判断用户当前访问设备,正常思路是通过正则进行匹配,当时为了省事就自己写了一个
export function getOSType() { const ua = navigator.userAgent const isWindowsPhone = /(?:Windows Phone)/.test(ua) const isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone const isAndroid = /(?:Android)/.test(ua) // 判断是否是平板 const isTablet = /(?:iPad|PlayBook)/.test(ua) || (isAndroid && !/(?:Mobile)/.test(ua)) || (/(?:Firefox)/.test(ua) && /(?:Tablet)/.test(ua)) // 是否是iphone const isIPhone = /(?:iPhone)/.test(ua) && !isTablet // 是否是pc const isPc = !isIPhone && !isAndroid && !isSymbian && !isTablet return { isIPhone, isAndroid, isSymbian, isTablet, isPc } }复制代码
上线后发现某些小米平板用户的逻辑判断出现异常,调日志看见UA为
"Mozilla/5.0 (Linux; U; Android 8.1.0; zh-CN; MI PAD 4 Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 Quark/3.8.5.129 Mobile Safari/537.36复制代码
即使把MI PAD
添加到正则判断中临时修复一下,万一后面又出现其他设备的特殊UA呢?所以,凭借自己经验写的很难把所有问题都考虑到,后面替换成mobile-detect这个库。
使用模块的缺点在于
- 可能会增加文件依赖体积,增加打包时间等,这个问题可以通过打包配置解决,将不会经常变更的第三方模块打包到vendor文件中配置缓存
- 在某些项目可能会由于安全考虑需要减少第三方模块的使用,或者要求先进行源码code review
当然在进行模块选择的时候也要进行各种考虑,包括稳定性、旧版本兼容、未解决issue等问题。当选择了一个比较好的工具模块之后,我们就可以将更多的精力放在业务逻辑中。
本地配置文件
在开发环境下,我们可能需要一些本地的开关配置文件,这些配置只在本地开发时存在,不进入代码库,也不会跟其他同事的配置起冲突。
我推崇将mock模板托管到git仓库中,这样可以方便其他同事开发和调试接口,带来的一个问题时本地可能需要一个引入mock文件的开关
下面是一个常见的做法:新建一个本地的配置文件config.local.js
,然后导出相关配置信息
// config.local.jsmodule.exports = { needMock: true}复制代码
记得在.gitignore中忽略该文件
config.local.js复制代码
然后通过try...catch...
加载该模块,由于文件未进入代码库,在其他地方拉代码更新时会进入catch流程,本地开发则进入正常模块引入流程
// mock/entry.jstry { const { needMock } = require('./config.local') if (needMock) { require('./index') // 对应的mock入口 console.log('====start mock api===') } } catch (e) { console.log('未引入mock,如需要,请创建/mock/config.local并导出 {needMock: true}') }复制代码
最后在整个应用的入口文件判断开发环境并引入
if (process.env.NODE_ENV === 'development') { require('../mock/entry') }复制代码
通过这种方式,就可以在本地开发时愉快地进行各种配置,而不必担心忘记在提交代码前注释对应的配置修改~
Code Review
参考:
- Code Review 是苦涩但有意思的修行
Code Review应该是是上线前一个必经的步骤,我认为CR主要的作用有
能够确认需求理解是否出现偏差,避免扯皮
优化代码质量,包括冗余代码、变量命名和过分封装等,起码除了写代码的人之外还得保证审核的人能看懂相关逻辑
对于一个需要长期维护迭代的项目而言,每一次commit和merge都是至关重要的,因此在合并代码之前,最好从头检查一遍改动的代码。即使是在比较小的团队或者找不到审核人员,也要把合并认真对待。
小结
本文主要整理了提高JavaScript代码健壮性的一些方法,主要整理了
- 安全地访问对象属性,避免数据异常导致代码报错
- 捕获异常,通过责任链的方式进行异常处理或上报
- 使用更稳定更安全的第三方模块,
- 认真对待每一次合并,上线前先检查代码
此外,还需要要养成良好的编程习惯,尽可能考虑各种边界情况。
以上がJavaScript を使用してフロントエンド コードの能力を向上させるいくつかの方法は素晴らしいです。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

現実世界でのJavaScriptのアプリケーションには、フロントエンドとバックエンドの開発が含まれます。 1)DOM操作とイベント処理を含むTODOリストアプリケーションを構築して、フロントエンドアプリケーションを表示します。 2)node.jsを介してRestfulapiを構築し、バックエンドアプリケーションをデモンストレーションします。

Web開発におけるJavaScriptの主な用途には、クライアントの相互作用、フォーム検証、非同期通信が含まれます。 1)DOM操作による動的なコンテンツの更新とユーザーインタラクション。 2)ユーザーエクスペリエンスを改善するためにデータを提出する前に、クライアントの検証が実行されます。 3)サーバーとのリフレッシュレス通信は、AJAXテクノロジーを通じて達成されます。

JavaScriptエンジンが内部的にどのように機能するかを理解することは、開発者にとってより効率的なコードの作成とパフォーマンスのボトルネックと最適化戦略の理解に役立つためです。 1)エンジンのワークフローには、3つの段階が含まれます。解析、コンパイル、実行。 2)実行プロセス中、エンジンはインラインキャッシュや非表示クラスなどの動的最適化を実行します。 3)ベストプラクティスには、グローバル変数の避け、ループの最適化、constとletsの使用、閉鎖の過度の使用の回避が含まれます。

Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

C/CからJavaScriptへのシフトには、動的なタイピング、ゴミ収集、非同期プログラミングへの適応が必要です。 1)C/Cは、手動メモリ管理を必要とする静的に型付けられた言語であり、JavaScriptは動的に型付けされ、ごみ収集が自動的に処理されます。 2)C/Cはマシンコードにコンパイルする必要がありますが、JavaScriptは解釈言語です。 3)JavaScriptは、閉鎖、プロトタイプチェーン、約束などの概念を導入します。これにより、柔軟性と非同期プログラミング機能が向上します。

さまざまなJavaScriptエンジンは、各エンジンの実装原則と最適化戦略が異なるため、JavaScriptコードを解析および実行するときに異なる効果をもたらします。 1。語彙分析:ソースコードを語彙ユニットに変換します。 2。文法分析:抽象的な構文ツリーを生成します。 3。最適化とコンパイル:JITコンパイラを介してマシンコードを生成します。 4。実行:マシンコードを実行します。 V8エンジンはインスタントコンピレーションと非表示クラスを通じて最適化され、Spidermonkeyはタイプ推論システムを使用して、同じコードで異なるパフォーマンスパフォーマンスをもたらします。

現実世界におけるJavaScriptのアプリケーションには、サーバー側のプログラミング、モバイルアプリケーション開発、モノのインターネット制御が含まれます。 2。モバイルアプリケーションの開発は、ReactNativeを通じて実行され、クロスプラットフォームの展開をサポートします。 3.ハードウェアの相互作用に適したJohnny-Fiveライブラリを介したIoTデバイス制御に使用されます。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

SublimeText3 中国語版
中国語版、とても使いやすい

Dreamweaver Mac版
ビジュアル Web 開発ツール

AtomエディタMac版ダウンロード
最も人気のあるオープンソースエディター

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

MinGW - Minimalist GNU for Windows
このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。
