diff --git a/04-JavaScript基础/17-函数.md b/04-JavaScript基础/13-函数.md similarity index 93% rename from 04-JavaScript基础/17-函数.md rename to 04-JavaScript基础/13-函数.md index b01a3d7..ae46480 100644 --- a/04-JavaScript基础/17-函数.md +++ b/04-JavaScript基础/13-函数.md @@ -44,15 +44,12 @@ function sayHello(){ } ``` -## 函数的定义 - - -### 方式一:函数声明(命名函数) +## 函数的定义/声明 +### 方式一:利用函数关键字自定义函数(命名函数) 使用`函数声明`来创建一个函数(也就是 function 关键字)。语法: - ```javascript function 函数名([形参1,形参2...形参N]){ // 备注:语法中的中括号,表示“可选” 语句... @@ -84,7 +81,7 @@ PS:在有些编辑器中,方法写完之后,我们在方法的前面输入 使用`函数表达式`来创建一个函数。语法: ```javascript -var 变量名/函数名 = function([形参1,形参2...形参N]){ +var 变量名 = function([形参1,形参2...形参N]){ 语句.... } ``` @@ -97,6 +94,15 @@ var fun2 = function() { }; ``` +解释如下: + + +- 上面的 fun2 是变量名,不是函数名。 + +- 函数表达式的声明方式跟声明变量类似,只不过变量里面存的是值,而函数表达式里面存的是函数。 + +- 函数表达式也可以传递参数。 + 从方式二的举例中可以看出:所谓的“函数表达式”,其实就是将匿名函数赋值给一个变量。 ### 方式三:使用构造函数 new Function() @@ -111,7 +117,6 @@ var 变量名/函数名 = new Function('形参1', '形参2', '函数体'); 注意,Function 里面的参数都必须是**字符串**格式。也就是说,形参也必须放在**字符串**里;函数体也是放在**字符串**里包裹起来,放在 Function 的最后一个参数的位置。 - 代码举例: ```javascript @@ -147,7 +152,6 @@ fun3(1, 2); // 调用函数 ## 函数的调用 - ### 方式1:普通函数的调用 函数调用的语法: @@ -281,7 +285,6 @@ new Fun3(); - **形参:** - 概念:形式上的参数。定义函数时传递的参数,当时并不知道是什么值。 @@ -332,7 +335,7 @@ helloworld - 如果实参的数量多余形参的数量,多余实参不会被赋值。 -- 如果实参的数量少于形参的数量,多余的形参会被定义为 undefined。表达式的运行结果为 NaN +- 如果实参的数量少于形参的数量,多余的形参会被定义为 undefined。表达式的运行结果为 NaN。 代码举例: @@ -377,7 +380,7 @@ return 的作用是结束方法。 - return 的值将会作为函数的执行结果返回,可以定义一个变量,来接收该结果。 -- 在函数中,return后的语句都不会执行(函数在执行完 return 语句之后停止并立即退出) +- 在函数中,return后的语句都不会执行(函数在执行完 return 语句之后停止并立即退出函数) - 如果return语句后不跟任何值,就相当于返回一个undefined @@ -387,7 +390,6 @@ return 的作用是结束方法。 - return 只能返回一个值。如果用逗号隔开多个值,则以最后一个为准。 - ## 函数名、函数体和函数加载问题(重要,请记住) 我们要记住:**函数名 == 整个函数**。举例: @@ -420,7 +422,6 @@ function fn(){ - return :1、退出循环。2、返回 return 语句中的值,同时结束当前的函数体内的代码,退出当前函数。 - ## 立即执行函数 现有匿名函数如下: @@ -469,15 +470,15 @@ function fn(){ ## arguments 的使用 -当我们不确定有多少个参数传递的时候,可以用 **arguments** 来获取。在 JavaScript 中,arguments 实际上是当前函数的一个**内置对象**。所有函数都内置了一个 arguments 对象,arguments 对象中存储了**传递的所有实参**. +当我们不确定有多少个参数传递的时候,可以用 **arguments** 来获取。在 JavaScript 中,arguments 实际上是当前函数的一个**内置对象**。所有函数都内置了一个 arguments 对象(只有函数才有 arguments 对象),arguments 对象中存储了**传递的所有实参**. arguments的展示形式是一个**伪数组**。伪数组具有以下特点: -- 可以进行遍历;length 属性。 +- 可以进行遍历;具有数组的 length 属性。 - 按索引方式存储数据。 -- 不具有数组的 push、pop 等方法。 +- 不具有数组的 push()、pop() 等方法。 **代码举例**:利用 arguments 求函数实参中的最大值 @@ -486,6 +487,7 @@ arguments的展示形式是一个**伪数组**。伪数组具有以下特点: ```javascript function getMaxValue() { var max = arguments[0]; + // 通过 arguments 遍历实参 for (var i = 0; i < arguments.length; i++) { if (max < arguments[i]) { max = arguments[i]; diff --git a/04-JavaScript基础/18-作用域.md b/04-JavaScript基础/14-作用域.md similarity index 56% rename from 04-JavaScript基础/18-作用域.md rename to 04-JavaScript基础/14-作用域.md index ee3371a..66d2da8 100644 --- a/04-JavaScript基础/18-作用域.md +++ b/04-JavaScript基础/14-作用域.md @@ -3,21 +3,21 @@ ## 作用域(Scope)的概念 -通俗来讲,作用域是一个变量或函数的作用范围。作用域在**函数定义**时,就已经确定了。 +- **概念**:通俗来讲,作用域是一个变量或函数的作用范围。作用域在**函数定义**时,就已经确定了。 +- **目的**:为了提高程序的可靠性,同时减少命名冲突。 ### 作用域的分类 -在js中,一共有两种作用域: +在 JS 中,一共有两种作用域:(ES6 之前) -- 全局作用域 +- 全局作用域:作用于整个 script 标签内部,或者作用域一个独立的 JS 文件。 -- 函数作用域 +- 函数作用域(局部作用域):作用于函数内的代码环境。 -### js 是函数级别作用域 +### 作用域的访问关系 - -js 是函数级别作用域:在内部作用域中可以访问到外部作用域的变量,在外部作用域中无法访问到内部作用域的变量。 +在内部作用域中可以访问到外部作用域的变量,在外部作用域中无法访问到内部作用域的变量。 代码举例: @@ -32,9 +32,31 @@ foo(); console.log(b); // 报错:Uncaught ReferenceError: b is not defined。说明 外层作用域 无法访问 内层作用域 里的变量 ``` -定义在全局作用域的变量,叫「全局变量」。 +### 变量的作用域 -定义在函数作用域的变量,叫「局部变量」。 +根据作用域的不同,变量可以分为两类:全局变量、布局变量。 + +**全局变量**: + +- 在全局作用域下声明的变量,叫「全局变量」。在全局作用域的任何一地方,都可以访问这个变量。 + +- 在全局作用域下,使用 var 声明的变量是全局变量。 + +- 特殊情况:在函数内不使用 var 声明的变量也是全局变量(不建议这么用)。 + +**局部变量**: + +- 定义在函数作用域的变量,叫「局部变量」。 + +- 在函数内部,使用 var 声明的变量是局部变量。 + +- 函数的**形参**也是属于局部变量。 + +从执行效率来看全局变量和局部变量: + +- 全局变量:只有浏览器关闭时才会被销毁,比较占内存。 + +- 局部变量:当其所在的代码块运行结束后,就会被销毁,比较节约内存空间。 ### 作用域的上下级关系 @@ -56,36 +78,39 @@ console.log(b); // 报错:Uncaught ReferenceError: b is not defined。说明 - 创建的**函数**都会作为window对象的方法保存。 -全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问的到。 ### 变量的声明提前(变量提升) 使用var关键字声明的变量( 比如 `var a = 1`),**会在所有的代码执行之前被声明**(但是不会赋值),但是如果声明变量时不是用var关键字(比如直接写`a = 1`),则变量不会被声明提前。 -举例1: +**举例1**: ```javascript console.log(a); var a = 123; ``` - 打印结果:undefined。注意,打印结果并没有报错,而是 undefined,说明变量 a 被提前声明了,只是尚未被赋值。 - -举例2: +**举例2**: ```javascript console.log(a); a = 123; //此时a相当于window.a ``` -程序会报错: +程序会报错:`Uncaught ReferenceError: a is not defined`。 -![](http://img.smyhvae.com/20180314_2136.png) +**举例3**: +```javascript + a = 123; //此时a相当于window.a + console.log(a); +``` -举例3: +打印结果:123。 + +**举例4**: ```javascript foo(); @@ -99,7 +124,7 @@ function foo() { ``` 打印结果:undefined。注意,打印结果并没有报错,而是 undefined。这个例子,再次说明了:变量 i 在函数执行前,就被提前声明了,只是尚未被赋值。 -打印结果: + ### 函数的声明提前 @@ -125,7 +150,7 @@ function foo() { 使用`函数表达式`创建的函数`var foo = function(){}`,**不会被声明提前**,所以不能在声明前调用。 -很好理解,因为此时foo被声明了(这里是变量声明),且为undefined,并没有把 `function(){}` 赋值给 foo。 +很好理解,因为此时foo被声明了(这里只是变量声明),且为undefined,并没有把 `function(){}` 赋值给 foo。 所以说,下面的例子,会报错: @@ -135,11 +160,11 @@ function foo() { **提醒1**:在函数作用域中,也有声明提前的特性: -- 函数中,使用var关键字声明的变量,会在函数中所有的代码执行之前被声明 +- 函数中,使用var关键字声明的变量,会在函数中所有的代码执行之前被声明。 - 函数中,没有var声明的变量都是**全局变量**,而且并不会提前声明。 -举例1: +举例: ```javascript var a = 1; @@ -154,7 +179,7 @@ function foo() { ``` -上方代码中,执行foo()后,打印结果是`1`。如果去掉第一行代码,打印结果是`Uncaught ReferenceError: a is not defined` +上方代码中,执行foo()后,函数里面的打印结果是`1`。如果去掉第一行代码,执行foo()后,函数里面的打印结果是`Uncaught ReferenceError: a is not defined`。 **提醒2**:定义形参就相当于在函数作用域中声明了变量。 @@ -167,6 +192,72 @@ function foo() { fun6(123);//打印结果为123 ``` +## JavaScript 没有块级作用域(ES6之前) + +在其他编程语言中(如 Java、C#等),存在块级作用域,由`{}`包括起来。比如在 Java 语言中,if 语句里创建的变量,只能在if语句内部使用: + +```java +if(true){ + int num = 123; + system.out.print(num); // 123 +} +system.out.print(num); // 报错 +``` + +但是,在 JS 中没有块级作用域(ES6之前)。举例如下: + +```javascript +if(true){ +var num = 123; + console.log(123); //123 +} + +console.log(123); //123(可以正常打印) + +``` + +## 作用域链 + +引入: + +- 只要是代码,就至少有一个作用域 + +- 写在函数内部的局部作用域 + +- 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域 + +基于上面几条内容,我们可以得出作用域链的概念。 + +**作用域链**:内部函数访问外部函数的变量,采用的是链式查找的方式来决定取哪个值,这种结构称之为作用域链。查找时,采用的是**就近原则**。 + +代码举例: + +```javascript +var num = 10; + +function fn() { + // 外部函数 + var num = 20; + + function fun() { + // 内部函数 + console.log(num); + } + fun(); +} +fn(); + +``` + +打印结果:20。 + + + + + + + + ## 我的公众号 想学习**代码之外的技能**?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。 diff --git a/04-JavaScript基础/20-作用域链.md b/04-JavaScript基础/20-作用域链.md deleted file mode 100644 index bfcb47b..0000000 --- a/04-JavaScript基础/20-作用域链.md +++ /dev/null @@ -1,35 +0,0 @@ - -## 一些概念 - -### 作用域和作用域链 - -**作用域**: - -每个 JS 函数都是一个对象,对象中有些属性我们可以访问,有些属性我们不可以访问。无法访问的这些属性仅供 JS 引擎存取,[[scope]] 属性就是其中之一。 - -[[scope]]就是我们所说的作用域,其中存储了执行期上下文的集合。 - - - -**作用域链**: - -[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。 - - -### 执行期上下文 - -当**函数执行**时(准确来说,是在函数发生预编译的前一刻),会创建一个执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境。 - -每调用一次函数,就会创建一个新的上下文对象,他们之间是相互独立且独一无二的。当函数执行完毕,它所产生的执行期上下文会被销毁。 - -## 最后一段 - -备注:本文的内容还有待完善。 - - - -## 参考链接 - -- - - diff --git a/04-JavaScript基础/20-执行期上下文.md b/04-JavaScript基础/20-执行期上下文.md new file mode 100644 index 0000000..48b9341 --- /dev/null +++ b/04-JavaScript基础/20-执行期上下文.md @@ -0,0 +1,15 @@ + + +## 执行期上下文 + +当**函数执行**时(准确来说,是在函数发生预编译的前一刻),会创建一个执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境。 + +每调用一次函数,就会创建一个新的上下文对象,他们之间是相互独立且独一无二的。当函数执行完毕,它所产生的执行期上下文会被销毁。 + + + +## 参考链接 + +- + + diff --git a/04-JavaScript基础/25-数组简介.md b/04-JavaScript基础/25-数组简介.md index 13b37a0..faf02d3 100644 --- a/04-JavaScript基础/25-数组简介.md +++ b/04-JavaScript基础/25-数组简介.md @@ -143,6 +143,8 @@ console.log(JSON.stringify(arr)); 可以使用`length`属性来获取数组的长度(即“元素的个数”)。 +数组的长度是元素个数,不要跟索引号混淆。 + 语法: ```javascript