序文
私は現在、Vueの高度なコンテンツを書いています。このプロセス中に、Vueソースコードを読むためにどのような準備が必要かと尋ねられる人がいました。したがって、この計画外の記事があります。
Vueのソースコードを学びたいときは、しっかりしたJavaScriptの基盤が必要です。以下のリストは、代表的な知識ポイントのほんの一部です。JavaScriptの基盤がない場合は、Vueのソースコードを急いで読まないことをお勧めします。そうすれば、簡単に諦めます。
私は次の7つのポイントから始めます:
-
フローの基本構文
-
公開/サブスクライブモデル
-
Object.defineProperty
-
ES6 +構文
-
プロトタイプチェーン、クロージャー
-
機能カレー
- イベントループ
必要な知識の予備
この記事の各ポイントについては特に詳しく説明しませんので、ここでいくつかの知識ポイントを要約します。それぞれの詳細なポイントは、学ぶためにまだ時間を費やす必要があります。
フローの基本構文
VueやVuexなどのソースコードを見たことがある人なら誰でも、Flow静的型チェックツールを使用していることを知っていると思います。
JavaScriptは型が弱い言語であることがわかっているため、コードを作成するときに予期しない問題が発生する傾向があります。静的型チェックツールであるFlowが登場したのは、まさにこの問題のためです。
このツールは、JavaScriptが弱く型付けされた言語であるという状況を変えることができ、型制限を追加してコードの品質を向上させることができます。
// 未使用 Flow 限制
function sum(a, b) {
return a + b;
}
// 使用 Flow 限制 a b 都是 number 类型。
function sum(a: number, b:number) {
return a + b;
}
基本的な検出タイプ
Flowは、次のプリミティブデータタイプをサポートします。
boolean
number
string
null
void( 对应 undefined )
変数を定義するときは、以下を使用して、重要な場所で型を宣言します。
let str:string = 'str';
// 重新赋值
str = 3 // 报错
複合型検出
Flowは、次のような複雑なタイプの検出をサポートしています。
Object
Array
Function
自定义的 Class
flow.jsを直接使用すると、JavaScriptをブラウザ側で実行できないことに注意してください。babelプラグインを使用する必要があります。babel-preset-flow-vueプラグインはvueソースコードで使用され、babelrcで構成されます。
詳細なフロー構文は、次の情報で確認できます。
ここでは2つの材料をお勧めします
-
公式文書:https://flow.org/en/
- フロー入門:https://zhuanlan.zhihu.com/p/26204569
公開/サブスクライブモデル
Vueは内部で双方向のバインディングメカニズムを実装しているため、以前のようにDOMを操作する必要はありません。
実際、Vueの双方向バインディングメカニズムは、公開/サブスクライブモデルと組み合わせたデータハイジャックを使用して、Object.defineProperty()を介して各プロパティのセッターとゲッターをハイジャックし、データが変更されたときにサブスクライバーにメッセージを公開し、対応するリスナーコールバックをトリガーします。
オブザーバーモデルと公開/サブスクライブモデルを混同している人がいることがわかりました。実際、サブスクリプションモデルには、サブスクリプションイベントを統合管理するためのディスパッチセンターがあります。オブザーバーモードでは、イベントを自由に登録および呼び出すことができます。
オブザーバーモデルと公開/サブスクライブモデルを説明するために、一般的なフローチャートを作成しました。次のように:
これについては次の記事で詳しく説明します。最初にコンセプトを示します。興味がある場合は、自分で情報を見つけるか、私の記事が公開されるのを待つことができます。
実際、私たちはこのパターンに精通していますが、自分で気付いていないかもしれません。
let div = document.getElementById('#div');
div.addEventListener('click', () => {
console.log("div 被点击了一下")
})
上記のイベントバインディング実行のプロセスについて考えることができます、あなたは共鳴を持っているべきです。
機能カレー
双方向データバインディングの基本:Object.defineProperty()
1つは、データ属性です
data属性には、データ値の場所が含まれます。この位置は、値の読み取りと書き込みが可能です。データプロパティには、その動作を説明する4つの特性があり
ます。上記の4つのデフォルトのデータプロパティを変更する場合は、ECMAScriptのObject.defineProperty()メソッドを使用する必要があります。
このメソッドには、属性が配置されているオブジェクト、属性名、および記述子オブジェクトの3つのパラメーターが含まれています。記述子オブジェクトの属性は、上記の4つの属性に含まれている必要があります。
var person = {
name: '',
};
// 不能修改属性的值
Object.defineProperty(person, "name",{
writable: false,
value: "小生方勤"
});
console.log(person.name); // "小生方勤"
person.name = "方勤";
console.log(person.name); // "小生方勤"
2、アクセサプロパティ
アクセサプロパティにはデータ値は含まれず、ゲッター関数とセッター関数のペアが含まれます(必須ではありません)。アクセサプロパティの値を読み書きするとき、対応するゲッター関数とセッター関数が呼び出され、vueは必要な操作をゲッター関数とセッター関数に追加します。
[値または書き込み可能]は[取得または設定]と共存してはならないことに注意してください。
アクセサプロパティには、次の4つの特性があります。
例を挙げましょう。
var person = {
_name : "小生方勤"
};
Object.defineProperty(person, "name", {
//注意 person 多定义了一个 name 属性
set: function(value){
this._name = "来自 setter : " + value;
},
get: function(){
return "来自 getter : " + this._name;
}
});
console.log( person.name ); // 来自 getter : 小生方勤
person.name = "XSFQ";
console.log( person._name ); // 来自 setter : XSFQ
console.log( person.name ); // 来自 getter : 来自 setter : XSFQ
以前にObject.defineProperty()メソッドを知らない場合は、「JavaScriptAdvancedProgramming」の139〜144ページを読むことをお勧めします。
Object.create(null)についての追加の話
ソースコードのどこにでもthis.set = Object.create(null)のような値を割り当てることができます。なぜこれをするのですか?この方法で作成する利点は、プロトタイプチェーンのプロパティを考慮する必要がなく、純粋なオブジェクトを実際に作成できることです。
まず、Object.createはオブジェクトを継承していると理解できます。これはES5の機能であり、古いブラウザと互換性がある必要があります。基本的なコードは次のとおりです。
if (!Object.create) {
Object.create = function (o) {
function F() {} // 定义了一个隐式的构造函数
F.prototype = o;
return new F(); // 其实还是通过new来实现的
};
}
ES6 +構文
実際、これはデフォルトで知っておく必要のあることですが、誰かが以前にいくつかの関連する質問をしてきたので、少し話させてください。
exportdefaultとexportの違い
-
ファイルまたはモジュールに複数のエクスポートが存在する可能性がありますが、exportdefaultは1つだけです。
-
エクスポートによるエクスポート、インポート時に{}を追加しますが、exportdefaultは必要ありません
1.エクスポート
//a.js
export const str = "Xiaosheng Fangqin";
//b.js
import {str} from'a '; //インポートするときは中括弧が必要です
2.デフォルトのエクスポート
//a.js
const str = "Xiaosheng Fang Qin";
デフォルトのstrをエクスポートします。
//b.js
import str from'a '; //インポート時に中括弧は必要ありません
exportdefaultconsta=1; 这样写是会报错的哟。
矢印機能
これは取った:
-
矢印関数でのこの方向は固定されています。つまり、関数が定義されているときの方向です。
- 通常の関数のこれは、それが指すとき、つまり関数が使用されるときのポイントを変更します
クラスの継承
クラスはextendsキーワードを介して継承できます。これは、プロトタイプチェーンを変更することにより、ES5の継承よりもはるかに明確で便利です。
class staff {
constructor(){
this.company = "ABC";
this.test = [1,2,3];
}
companyName(){
return this.company;
}
}
class employee extends staff {
constructor(name,profession){
super();
this.employeeName = name;
this.profession = profession;
}
}
// 将父类原型指向子类
let instanceOne = new employee("Andy", "A");
let instanceTwo = new employee("Rose", "B");
instanceOne.test.push(4);
// 测试
console.log(instanceTwo.test); // [1,2,3]
console.log(instanceOne.companyName()); // ABC
// 通过 Object.getPrototypeOf() 方法可以用来从子类上获取父类
console.log(Object.getPrototypeOf(employee) === staff)
// 通过 hasOwnProperty() 方法来确定自身属性与其原型属性
console.log(instanceOne.hasOwnProperty('test')) // true
// 通过 isPrototypeOf() 方法来确定原型和实例的关系
console.log(staff.prototype.isPrototypeOf(instanceOne)); // true
親クラスのコンストラクターを表すsuperキーワードは、親クラスのthisオブジェクトを作成するために使用されます。
サブクラスはコンストラクターメソッドのスーパーメソッドを呼び出す必要があります。そうしないと、インスタンスの作成時にエラーが報告されます。これは、サブクラスが独自のthisオブジェクトを持っていないが、親クラスのthisオブジェクトを継承し、それを処理するためです。
- このキーワードは、superを呼び出した後でのみ使用できます。そうしないと、エラーが報告されます。これは、サブクラスインスタンスの構築がスーパークラスインスタンスの処理に基づいており、スーパーメソッドのみがスーパークラスインスタンスを返すことができるためです。
`super` 虽然代表了父类 `A` 的构造函数,但是返回的是子类 `B` 的实例,即` super` 内部的 `this ` 指的是 `B`,因此 `super()` 在这里相当于 A.prototype.constructor.call(this)
ES5とES6の実装継承の違い
ES5継承の本質は、最初にサブクラスのインスタンスオブジェクトthisを作成し、次に親クラスのメソッドをこれに追加することです(Parent.apply(this))。
ES6の継承メカニズムは完全に異なります。本質は、最初に親クラスのインスタンスオブジェクトthisを作成し(したがって、super()メソッドを最初に呼び出す必要があります)、次にサブクラスのコンストラクターを使用してこれを変更することです。
プロキシ
最新の開発を知っている人は、Vueの次のバージョンでは、データの乗っ取りを完了するためにObject.definePropertyの代わりにプロキシが使用されることを知っているでしょう。
You Daは、この新しいソリューションにより、メモリ使用量が半分になりながら初期化速度が2倍になると述べました。
プロキシオブジェクトの使用法:
var proxy = new Proxy(target, handler);
new Proxy()はプロキシインスタンスを生成します。ターゲットパラメータは、インターセプトされるターゲットオブジェクトを示し、ハンドラパラメータは、インターセプト動作をカスタマイズするためのオブジェクトでもあります。
var proxy = new Proxy({}, {
get: function(obj, prop) {
console.log('get 操作')
return obj[prop];
},
set: function(obj, prop, value) {
console.log('set 操作')
obj[prop] = value;
}
});
proxy.num = 2; // 设置 set 操作
console.log(proxy.num); // 设置 get 操作 // 2
取得と設定に加えて、プロキシは最大13の操作を傍受できます。
注意,proxy 的最大问题在于浏览器支持度不够,IE 完全不兼容。
ES6を理解していない場合は、次のチュートリアルをお勧めします。
Ruan Yifeng ECMAScript 6の概要:http://es6.ruanyifeng.com/
プロトタイプチェーン、クロージャー
プロトタイプチェーン
以前にプロトタイプチェーンを説明する記事を意図的に書いたので、ここでは説明しません。
プロトタイプチェーン:https://juejin.im/post/5c335940f265da610e804097
閉鎖
ここでは、最初にVueソースコードにonce関数の一部を配置します。これはクロージャ呼び出しです-戻り値としての関数:
/**
* Ensure a function is called only once.
*/
export function once (fn: Function): Function {
let called = false
return function () {
if (!called) {
called = true
fn.apply(this, arguments)
}
}
}
この関数の目的は、関数が1回だけ呼び出されるようにすることです。
なぜ一度だけ呼び出されるのですか?関数呼び出しが完了した後、その実行コンテキストは破棄されないため、calledの値はまだそこにあります。
閉鎖とは正確には何ですか?「JavaScriptAdvancedProgramming」の説明は次のとおりです。
クロージャーは、別の関数のスコープ内の変数にアクセスできる関数です。クロージャーを作成する一般的な方法は、別の関数内に関数を作成することです。
简单讲,闭包就是指有权访问另一个函数作用域中的变量的函数。
2つのコードを入力します。その結果がわかっている場合は、クロージャーについて知っています。
// 第一段
var num = 20;
function fun(){
var num = 10;
return function con(){
console.log( this.num )
}
}
var funOne = fun();
funOne(); // 20
// 第二段
var num = 20;
function fun(){
var num = 10;
return function con(){
console.log( num )
}
}
var funOne = fun();
funOne(); // 10
機能カレー
所谓"柯里化",就是把一个多参数的函数,转化为单参数函数。
私が以前に遭遇したインタビューの質問について話させてください:
如何使 add(2)(3)(4)() 输出 9
インタビューの時はまだカレーの概念がわからなかったので答えませんでした。後で私はこれが関数カレーによって解決できることを学びました、すなわち:
function add(num){
var sum=0;
sum= sum+num;
return function tempFun(numB){
if(arguments.length===0){
return sum;
}else{
sum= sum+ numB;
return tempFun;
}
}
}
では、これはVueと何の関係があるのでしょうか。もちろん、それは関連しています:
私たちはしばしばこのような判断を書きますか?
if( A ){
// code
}else if( B ){
// code
}
この書き方には何の問題もありませんが、同じ判断を繰り返すと。これは少しインテリジェントではありません。現時点では、機能カレーが重宝します。
Vueはさまざまなプラットフォームで実行できるため、上記の判断も存在します。ここでは、カレーの特性を利用して、createPatchFunctionメソッドを介していくつかのパラメーターを事前に保存して再利用します。
// 这样不用每次调用 patch 的时候都传递 nodeOps 和 modules
export function createPatchFunction (backend) {
// 省略好多代码
return function patch (oldVnode, vnode, hydrating, removeOnly) {
// 省略好多代码
}
}
イベントループ
4つの概念:
-
同期タスク:メインスレッドで実行するためにキューに入れられているタスク次のタスクを実行する前に、前のタスクのみが完了します
-
非同期タスク:メインスレッドに入らずに実行できる特定の非同期タスクを指し、タスクは実行のためにメインスレッドに入ります
-
マクロタスク:主なシナリオには、メインコードブロック、setTimeout、setIntervalなどが含まれます。
- マイクロタスク:主なシナリオには、Promise、process.nextTickなどがあります。
この点についてはすでにオンラインチュートリアルがたくさんありますが、スペースの問題があるため、ここでは詳しく説明しません。
非常に詳細な記事をお勧めします。
JavaScript実行メカニズム:https://juejin.im/post/59e85eebf265da430d571f89#heading-4
総括する
この記事はここにあります。しかし、私が言わなければならないことが1つあります。この記事の位置付けは、あらゆる面ですべての知識を説明することではありません。これは非現実的であり、私にはそのような能力がありません。
この記事で要点をお伝えしたいと思います。ソースコードを見たい場合は、JavaScriptの基本的な知識がしっかりしている必要があります。そうしないと、苦労します。
毎日進歩していきますように。
Vue関連記事の出力計画
最近、友達からVue関連の質問が寄せられているので、次はVue関連の記事を9つ出力します。更新は7〜10日で行います。
-
[フロントエンド辞書] VuexがVueライフサイクルプロセスを注入します(完了)
-
[フロントエンド辞書] Vue応答原理の分析
-
[フロントエンド辞書]新旧のVNodeにパッチを適用するプロセス
-
[フロントエンド辞書]機能コンポーネントの開発方法とnpmのアップロード方法
-
[フロントエンド辞書]これらの側面からVueプロジェクトを最適化する
-
[フロントエンド辞書] Vue-Router設計からのフロントエンドルーティングの開発について話します
-
【フロントエンド辞書】プロジェクトでWebpackを正しく使う方法
-
【フロントエンド辞書】Vueサーバーレンダリング
- 【フロントエンド辞書】AxiosとFetchの選び方
私の公式アカウントに注意を払うことをお勧めします。できるだけ早く最新の記事を受け取ることができます。
グループ通信に参加したい場合は、スマートロボットを追加して、自動的にグループに参加させることもできます。
気軽に幸せに