From 0bbb6c66dec066decb4791775787a8d77b41c06c Mon Sep 17 00:00:00 2001 From: qianguyihao Date: Tue, 10 Dec 2019 22:39:08 +0800 Subject: [PATCH] =?UTF-8?q?add:=20=E5=87=BD=E6=95=B0=E7=9A=84=E5=AE=9A?= =?UTF-8?q?=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 04-JavaScript基础/09-函数.md | 86 +++++++++++++++++--- 04-JavaScript基础/10-作用域.md | 34 ++++++-- 04-JavaScript基础/12-作用域链.md | 35 ++++++++ 04-JavaScript基础/{19-this.md => 13-this.md} | 0 04-JavaScript基础/14-闭包.md | 0 05-JavaScript进阶/JavaScript开发积累.md | 30 ++++++- 6 files changed, 163 insertions(+), 22 deletions(-) create mode 100644 04-JavaScript基础/12-作用域链.md rename 04-JavaScript基础/{19-this.md => 13-this.md} (100%) create mode 100644 04-JavaScript基础/14-闭包.md diff --git a/04-JavaScript基础/09-函数.md b/04-JavaScript基础/09-函数.md index 49db032..2d48eb6 100644 --- a/04-JavaScript基础/09-函数.md +++ b/04-JavaScript基础/09-函数.md @@ -1,4 +1,21 @@ +## 前言 + +关于函数的核心内容: + +- 函数有哪几种定义和调用方式 + +- this:函数内部的 this 指向、如何改变 this 的指向。 + +- 函数的严格模式 + +- 高阶函数:函数作为参数传递、函数作为返回值传递 + +- 闭包:闭包的作用 + +- 递归:递归的两个条件 + +- 深拷贝和浅拷贝的区别 ## 函数的介绍 @@ -27,13 +44,13 @@ function sayHello(){ } ``` +## 函数的定义 -## 函数的定义和调用 +### 方式一:函数声明(命名函数) -### 第一步:函数的定义 -**方式一**:使用`函数声明`来创建一个函数。语法: +使用`函数声明`来创建一个函数(也就是 function 关键字)。语法: ```javascript @@ -45,7 +62,7 @@ function 函数名([形参1,形参2...形参N]){ // 备注:语法中的中括 举例: ```javascript -function sum(a, b){ +function fun1(a, b){ return a+b; } ``` @@ -62,10 +79,12 @@ function sum(a, b){ PS:在有些编辑器中,方法写完之后,我们在方法的前面输入`/**`,然后回车,会发现,注释的格式会自动补齐。 -**方式二**:使用`函数表达式`来创建一个函数。语法: +### 方式二:函数表达式(匿名函数) + +使用`函数表达式`来创建一个函数。语法: ```javascript -var 函数名 = function([形参1,形参2...形参N]){ +var 变量名/函数名 = function([形参1,形参2...形参N]){ 语句.... } ``` @@ -73,17 +92,59 @@ var 函数名 = function([形参1,形参2...形参N]){ 举例: ```javascript -var fun3 = function() { +var fun2 = function() { console.log("我是匿名函数中封装的代码"); }; ``` - 从方式二的举例中可以看出:所谓的“函数表达式”,其实就是将匿名函数赋值给一个变量。 -当然,我们还有方式三:使用构造函数来创建一个对象。这种方式,用的少。 +### 方式三:使用构造函数 new Function() -### 第二步:函数的调用 +使用构造函数`new Function()`来创建一个对象。这种方式,用的少。 + +语法: + +```javascript +var 变量名/函数名 = new Function('形参1', '形参2', '函数体']); +``` + +注意,这里是直接将函数体放在**字符串**里包裹起来,放在 Function 的最后一个参数的位置;而且,形参也必须放在**字符串**里。 + +代码举例: + +```javascript +var fun3 = new Function('a', 'b', 'console.log("我是函数内部的内容"); console.log(a + b);'); + +fun3(1, 2); // 调用函数 +``` + +打印结果: + +``` +我是函数内部的内容 +3 +``` + +**分析**: + +方式3的写法很少用,原因如下: + +- 不方便书写:写法过于啰嗦和麻烦。 + +- 执行效率较低:首先需要把字符串转换为 js 代码,然后再执行。 + +### 总结 + +1、**所有的函数,都是 `Fuction` 的“实例”**(或者说是“实例对象”)。函数本质上都是通过 new Function 得到的。 + +2、函数既然是实例对象,那么,**函数也属于“对象”**。还可以通过如下特征,来佐证函数属于对象: + +- 我们直接打印某一个函数,比如 `console.log(fun2)`,发现它的里面有`__proto__`。(这个是属于原型的知识,后续再讲) + +- 我们还可以打印 `console.log(fun2 instanceof Object)`,发现打印结果为 `true`。这说明 fun2 函数就是属于 Object。 + +## 函数的调用 函数调用的语法: @@ -267,6 +328,11 @@ function fn(){ 我们可以这样说,如果直接是`fn()`,那就说明是函数调用。如果是`XX.fn()`的这种形式,那就说明是**方法**调用。 +## 构造函数、原型对象、对象实例之间的关系 + +暂略。 + + ## 我的公众号 想学习**代码之外的技能**?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。 diff --git a/04-JavaScript基础/10-作用域.md b/04-JavaScript基础/10-作用域.md index 71f516e..ee3371a 100644 --- a/04-JavaScript基础/10-作用域.md +++ b/04-JavaScript基础/10-作用域.md @@ -3,7 +3,8 @@ ## 作用域(Scope)的概念 -作用域是一个变量或函数的作用范围。作用域在**函数定义**时,就已经确定了。 +通俗来讲,作用域是一个变量或函数的作用范围。作用域在**函数定义**时,就已经确定了。 + ### 作用域的分类 @@ -13,7 +14,10 @@ - 函数作用域 -在函数作用域中可以访问到全局作用域的变量,在全局作用域中无法访问到函数作用域的变量。 +### js 是函数级别作用域 + + +js 是函数级别作用域:在内部作用域中可以访问到外部作用域的变量,在外部作用域中无法访问到内部作用域的变量。 代码举例: @@ -32,11 +36,7 @@ console.log(b); // 报错:Uncaught ReferenceError: b is not defined。说明 定义在函数作用域的变量,叫「局部变量」。 -### 执行上下文 - -当**函数执行**时,会创建一个执行期上下文的内部对象。每调用一次函数,就会创建一个新的上下文对象,他们之间是相互独立的。当函数执行完毕,它所产生的执行期上下文会被销毁。参考链接: - -**作用域的上下级关系:** +### 作用域的上下级关系 当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用(**就近原则**)。如果没有则向上一级作用域中寻找,直到找到全局作用域;如果全局作用域中依然没有找到,则会报错 ReferenceError。 @@ -84,6 +84,24 @@ console.log(b); // 报错:Uncaught ReferenceError: b is not defined。说明 ![](http://img.smyhvae.com/20180314_2136.png) + +举例3: + +```javascript +foo(); + +function foo() { + if (false) { + var i = 123; + } + console.log(i); +} +``` + +打印结果:undefined。注意,打印结果并没有报错,而是 undefined。这个例子,再次说明了:变量 i 在函数执行前,就被提前声明了,只是尚未被赋值。 +打印结果: + + ### 函数的声明提前 **函数声明**: @@ -136,7 +154,7 @@ console.log(b); // 报错:Uncaught ReferenceError: b is not defined。说明 ``` -上方代码中,foo()的打印结果是`1`。如果去掉第一行代码,打印结果是`Uncaught ReferenceError: a is not defined` +上方代码中,执行foo()后,打印结果是`1`。如果去掉第一行代码,打印结果是`Uncaught ReferenceError: a is not defined` **提醒2**:定义形参就相当于在函数作用域中声明了变量。 diff --git a/04-JavaScript基础/12-作用域链.md b/04-JavaScript基础/12-作用域链.md new file mode 100644 index 0000000..bfcb47b --- /dev/null +++ b/04-JavaScript基础/12-作用域链.md @@ -0,0 +1,35 @@ + +## 一些概念 + +### 作用域和作用域链 + +**作用域**: + +每个 JS 函数都是一个对象,对象中有些属性我们可以访问,有些属性我们不可以访问。无法访问的这些属性仅供 JS 引擎存取,[[scope]] 属性就是其中之一。 + +[[scope]]就是我们所说的作用域,其中存储了执行期上下文的集合。 + + + +**作用域链**: + +[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。 + + +### 执行期上下文 + +当**函数执行**时(准确来说,是在函数发生预编译的前一刻),会创建一个执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境。 + +每调用一次函数,就会创建一个新的上下文对象,他们之间是相互独立且独一无二的。当函数执行完毕,它所产生的执行期上下文会被销毁。 + +## 最后一段 + +备注:本文的内容还有待完善。 + + + +## 参考链接 + +- + + diff --git a/04-JavaScript基础/19-this.md b/04-JavaScript基础/13-this.md similarity index 100% rename from 04-JavaScript基础/19-this.md rename to 04-JavaScript基础/13-this.md diff --git a/04-JavaScript基础/14-闭包.md b/04-JavaScript基础/14-闭包.md new file mode 100644 index 0000000..e69de29 diff --git a/05-JavaScript进阶/JavaScript开发积累.md b/05-JavaScript进阶/JavaScript开发积累.md index c51ebc6..8794758 100644 --- a/05-JavaScript进阶/JavaScript开发积累.md +++ b/05-JavaScript进阶/JavaScript开发积累.md @@ -79,10 +79,32 @@ window.open('你所要跳转的新页面'); ``` - - - - +### 2019-12-10-JavaScript 新特性:Optional Chaining(可选链式调用)语法 + +以往写代码,我们一般都这么写: + +```javascript +if (result && result.user && result.user.name && result.user.name.length) { + console.log('qianguyihao'); +} +``` + +有了 Optinal Chain 语法之后,就简洁很多了,可以这么写: + + +```javascript +if (result?.user?.name?.length) { + console.log('qianguyihao'); +} +``` + + + +参考链接: + +- 了解 JavaScript 新特性:Optional Chaining: + +- 原文链接: https://v8.dev/features/optional-chaining