事前解析されたの概念
事前に解析されたどのようなものです
実行前JSコード、コードの解釈翻訳、コードが実行時に異常減らすことができます
なぜ事前に解析し
コンパイル言語
コンパイルされた言語:C、C ++、C#、Javaが...その後、コンピュータが事前に翻訳します保存されている実行可能ファイルに読み込むことができるバイナリデータにソースコードを変換する「翻訳者」プログラム(コマンド)が必要です。結果を得るために、直接実行ランタイム
インタプリタ言語
(スクリプトタイプ)解釈:JavaScriptを、SQLは、...コードの実装では、コードを実行するためのコードを読むための翻訳プログラムがあり、コードを読んで、そしてコードを実行します。
なぜ事前に解析し
コードの実行、迅速な「プレビュー」を再度、露出の間違った部分の前に、あなたは、可能な限り執行の効率性を向上させることができます。
事前分析機能
事前解決された設定変数のスコープで標識された肯定処理完了コード部分
どのような記載されています
利用可能なもの識別子のマークを見ると、現在の環境JS実行エンジンのノウハウ
宣言された変数
语法: var 变量名;
目的: 告诉解释器, 有一个名字是一个变量, 在当前环境中可以被使用.
var a; // 申明变量a 值是undefined
var b = 123; // 申明变量b 同时在执行时赋值123;
肯定アップグレード
if('a' in window){
var a = 123;
}
console.log(a);
// 分析:
// 1.读取所有的代码( 字符串 ). 包含每一个字节, 每一个数据. 但是 "只留意" var
// 2.判断 var 后面紧跟的名字是否被标记. 如果没有, 则标记上.
// 如果已标记, 则忽略. 表示在当前环境中已经有该变量了.
// 3.读取完毕后, 代码再从头开始, 从上往下, 从左至右一句一句的执行代码.
// 执行 'a' in window. 很显然当前环境中已有变量 a, 所以结果为真.
関数を宣言
フォームの定義された関数
宣言型:
function func () { console.log( '使用声明式定义' ); }
式のタイプ(匿名関数、関数リテラル、ラムダ関数):
var func = function () { console.log( '使用表达式式定义' ); }; /*也可以带有名字*/ var func = function fn(){ console.log('表达式式函数'); };
定義された関数の二つの形式の特徴
コードに埋め込まれていない関数宣言文の独立していません。セミコロンを追加する必要が。表現。 実行部は、文のステージ前の解析プロセスで完了している場合、機能の宣言は、コードの実行。コードから独立している。したがって、最初のを肯定する呼び出すことができます。
式のスタイルは、基本的に変数に関数式(リテラル)を割り当てた値であるので、文です。
なお、ポイントを定義する関数式
var f1 = function f2 () {
console.log( '带有名字的 函数表达式' );
console.log( f2 );
};
// 当函数声明语法嵌入表达式环境中, 会自动进行转换, 将转换成函数表达式.
// 1> 引用函数的规则还是使用变量赋值, 所以外部可以使用该名字调用函数.即可以使用f1调用函数
// 2> 函数表达式带有名字, 该名字只允许在函数内部使用. 属于局部作用域. ( IE8 除外 )即f2只能在f2函数内部使用
// 3> 带有名字的函数表达式, 函数的 name 属性即为该名字,即函数的name为f2
どのような表現
1.オペレータ発現が接続オペランド。
2.(ステートメントを含まない)コード手段の存在の結果。
var a; // 声明, 不是语句, 也没有结果
123 // 字面量, 有值, 是表达式. 是常量表达式
a = 123 // 赋值, 有值, 就是被赋值的那个值. 是赋值表达式.
表示され、そのポイントに同時に注意を払うで宣言された関数と変数の宣言
変数を宣言し、現在の環境は、その名前を使用することができますインタプリタを伝えることです。
文関数は、名前の使用に加えて、名前も関数本体を表し、インタプリタを伝えることです。
最初のVAR関数の後
var num;
function num(){
}
console.log(num); // 打印函数体
// 先 var num; 后 function num ...
// 首先告知解释器有 名字 num 了
// 后面是函数声明. 由于已经有 num 名字可以使用了, 所以就不再告诉解释器可以使用 num
// 而是直接将 num 与函数结合在起义.
最初の関数VAR後
function num(){};
var num;
console.log(num); // 打印函数体
// 先 function num ... 后 var num;
// 一开始已经有 num 了, 而且是函数. 所以后面的 var num; 属于重复声明.
特例
if ( true ) {
function foo() {
console.log( true );
}
} else {
function foo() {
console.log( false );
}
}
foo();
// 在早期的浏览器中( 2015 年前) 所有的浏览器( 除了火狐 )都是将其解释为声明 : false
// 但是现在的运行结果, 得到: true. 表示 if 起到了作用
/******************************/
if ( true ) {
function foo1() {
console.log( true );
}
} else {
function foo2() {
console.log( false );
}
}
foo1();
// foo2(); 大专栏 i5ting_ztree_toc:scopeChain // error: foo2 is not function. 已定义, 但是函数为被指向
// 好比: var foo1 = function foo1 () { ... }
// 虽然这两个函数不是声明, 但是也不能解释成函数表达式. 如果是函数表达式 foo1 与 foo2 只能在函数内部使用.
字句スコープ
スコープとは何ですか
スコープに使用できる変数を使用することはできません
JSレキシカルスコープ
字句範囲は事前解析ルールの使用に基づいているJSは、変数を定義し、のみスコープJSを制限するように機能することができる。他のアクセス範囲を定義することができない。実際には、字句スコープ関数スコープと呼ぶことができます。
レキシカルスコープの特長
コード機能は、範囲を定義することができる。機能外部変数ではないその逆へのアクセスを可能にします。
内部変数への優先アクセスは、外部アクセスが発生しない場合にのみ、関数内で宣言しました。
すべての変数のアクセスルール、アクセスにルールを事前に解析するために従っ
jsはスコープチェーン内の変数と環境の実行とは何の関係の定義。
ケース
ケース01
var num = 123;
function f1 () {
console.log( num );
}
function f2 () {
console.log( num );
var num = 456;
f1();
console.log( num );
}
f2();
1> 读取代码预解析. 得到 num, f1, f2
2> 逐步的执行代码
1) 赋值 num = 123; 注意 f1 和 f2 由于是函数, 所以也有数据.
2) 调用 f2.
进入到函数体内. 相当于做一次预解析. 得到 num. 注意, 此时有内外两个 num
执行每一句代码
-> 打印 num. 因为函数内部有声明 num. 所以此时访问的是函数内部的 num. 未赋值, 得到 undefined
-> 赋值 num = 456
-> 调用 f1(). 调用函数的规则也是一样. 首先看当前环境中是否有函数的声明. 如果有直接使用. 如果没有, 则在函数外面找, 看是否有函数. 此时在函数 f2 中没有 f1 的声明. 故访问的就是外面的 f1 函数
-> 跳入 f1 函数中. 又要解析一次. 没有得到任何声明.
-> 执行打印 num. 当前环境没有声明 num. 故在外面找. 外面的是 123. 所以打印 123.
函数调用结束, 回到 f2 中.
-> 继续执行 f2, 打印 num. 在 f2 的环境中找 num. 打印 456.
ケース02
(function ( a ) {
console.log( a );
var a = 10;
console.log( a );
})( 100 );
拆解
( 函数 ) ( 100 )
第一个圆括号就是将函数变成表达式
后面一个圆括号就是调用该函数
注意: 函数定义参数, 实际上就是在函数最开始的时候, 有一个变量的声明
function ( a ) { ... }
其含义就是, 在已进入函数体, 在所有操作开始之前( 预解析之前 )就有了该变量的声明.
由于已经有了 a 参数的声明. 所以在代码中 var a = 10 是重复声明. 其声明无效.
所以上面的代码, 等价于
var func = function ( a ) {
console.log( a ); // => 100
a = 10;
console.log( a ); // => 10
}
func( 100 );
ケース03
(function ( a ) {
console.log( a );
var a = 10;
console.log( a );
function a () {
console.log( a );
}
a();
})( 100 );
1> 直接调用
2> 进入到函数中, 已有声明 a 并且其值为 100
3> 在函数内部预解析. 得到 一个结论. 函数声明是两个步骤.
1) 让当前环境中, 有变量名 a 可以使用. 但是不需要. 因为已经有 a 的声明了
2) 让 a 指向函数. 相当于
var a;
function a () {}
...
4> 开始逐步执行每一句代码
1) 打印 a. 所以打印函数体
2) 赋值 a = 10
3) 打印 a, 打印出 10
4) 调用 a, a已经被赋值为10,不在是函数体, 所以报错 error: a is not function
スコープチェーン
実際には、チェーンは、アクセスルールを指し、スコープチェーンは、アクセスルールのスコープを指し
スコープチェーンのルールを描画
1. 将所有的 script 标签作为一条链结构. 标记为 0 级别的链.
2. 将全局范围内, 所有的声明变量名和声明函数名按照代码的顺序标注在 0 级链中.
3. 由于每一个函数都可以构成一个新的作用域链. 所以每一个 0 级链上的函数都延展出 1 级链.
4. 分别在每一个函数中进行上述操作. 将函数中的每一个名字标注在 1 级链中.
5. 每一条 1 级链中如果有函数, 可以再次的延展出 2 级链. 以此类推...
解析コードの実行
1. 根据代码的执行顺序( 从上往下, 从左至右 )在图中标记每一步的变量数据的变化
2. 如果需要访问某个变量. 直接在当前 n 级链上查找变量. 查找无序.
3. 如果找到变量, 直接使用. 如果没有找到变量 在上一级, n - 1 级中查找.
4. 一直找下去, 直至到 0 级链. 如果 0 级链还没有就报错. xxx is not defined.
クラシック顔の質問
var arr = [ { name: '张三1' },
{ name: '张三2' },
{ name: '张三3' },
{ name: '张三4' } ];
// 利用循环, 添加方法, 在方法中打印 name
for ( var i = 0; i < arr.length; i++) {
// arr[ i ] 绑定方法
arr[ i ].sayHello = function () {
// 打印名字
console.log( 'name = ' + arr[ i ].name );
};
}
for ( var i = 0; i < arr.length; i++ ) {
arr[ i ].sayHello();
}
// 打印结果?