李莎_20210118李莎
知识点总结
JavaScript的学习
1 json数据格式
1.1 什么是json
JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于ECMAScript的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
1.2 json的语法格式
json对象有三种数据格式,分别如下:
类型 | 语法 | 解释 |
---|---|---|
对象类型 | {name:value,name:value...} | 其中name是字符串类型,而value是任意类型 |
数组/集合类型 | [value,value,value...] | 其中value是任意类型 |
混合类型 | [{},{}... ...] 或 {name:[]... ...} | 合理包裹嵌套对象类型和数组类型 |
JSON是存储和交换文本信息的语法,类似 XML。
JSON 比 XML 更小、更快,更易解析。
//如下java代码分别用xml、json传输
User user = new User();
user.setName("jack");
user.setAge(24);
user.setGender("男");
//xml格式
<user>
<name>jack</name>
<age>24<age>
<gender>男</gender>
</user>
//json
{"name":"jack","age":24,"gender":"男"}
2 JavaScript的基础语法
2.2 JavaScript中的几个概念
2.2.3 直接量
直接量(Literal)就是具体的值,即能够直接参与运算或显示的值,如字符串、数值、布尔值、正则表达式、对象直接量、数组直接量、函数直接量等
//空字符串直接量
1 //数值直接量
true //布尔值直接量
/a/g //正则表达式直接量
null //特殊值直接量
{} //空对象直接量
[] //空数组直接量
function(){} //空函数直接量,也就是函数表达式
2.2.4 转义序列
转义序列就是字符的一种表示方式(映射)。由于各种原因,很多字符无法直接在代码中输入或输出,只能通过转义序列间接表示
- Unicode 转义序列方法:\u + 4位十六进制数字。
- Latin-1 转义序列方法:\x + 2位十六进制数字。
javascript
//对于字符“©” , Unicode 转义为 \u00A9,ASCII 转义为 \xA9
document.write("\xa9"); //Latin-1 显示字符©
document.write("\u00a9"); //Unicode 显示字符©
##### 2.2.5 标识符
标识符(Identifier) 就是名称的专业术语。JavaScript 标识符包括变量名、函数名、参数名和属性名
合法的标识符应该注意以下强制规则: - 第一个字符必须是字母、下划线(_)或美元符号($)。
- 除了第一个字符外,其他位置可以使用 Unicode 字符。一般建议仅使用 ASCII 编码的字母,不建议使用双字节的字符。
- 不能与 JavaScript 关键字、保留字重名。
- 可以使用 Unicode 转义序列。例如,字符 a 可以使用“\u0061”表示 (不推荐)。
javascript
var \u0061 = "字符 a 的 Unicode 转义序列是 \u0061";
var a = "a";
使用转义序列不是很方便,一般常用转义序列表示特殊字符或名称,如 JavaScript 关键字、程序脚本等
##### 2.2.6 关键字
关键字就是 ECMA-262 规定的 JavaScript 语言内部使用的一组名称(或称为命令)。这些名称具有特定的用途,用户不能自定义同名的标识符。具体说明如表所示
| break | delete| if | this | while |
|--|--|--|--|--|
| case | do | in | throw | with |
| catch | else | instanceof | try |
| continue | finally | new | typeof |
| debugger | for | return | var |
| default | function | switch | void |
##### 2.2.7 保留字
保留字就是 ECMA-262 规定的 JavaScript 语言内部预备使用的一组名称(或称为命令)。这些名称目前还没有具体的用途,是为 JavaScript 升级版本预留备用的,建议用户不要使用。具体说明如表所示
| abstract | double | goto | native | static |
|--|--|--|--|--|
| boolean | enum | implements | package | super |
| byte | export | import | private | synchronized |
| char | extends | int | protected | throws |
| class | final | interface | public | transient |
|const | float | long | short | volatile |
> 补充:ECMAScript 3 将 Java 所有关键字都列为保留字,而 ECMAScript 5 规定较为灵活例如,在非严格模式下,仅规定 class、const、enums、export、extends、import、super 为保留字,其他 ECMAScript 3 保留字可以自由使用;在严格模式下,ECMAScript 5 变得更加谨慎,严格限制 implements、interface、let、package、private、protected、public、static、yield、eval(非保留字)、arguments(非保留字)的使用
##### 2.2.8 对象、属性和方法
JavaScript 预定义了很多全局变量和函数,用户也应该避免使用它们。具体说明如表所示
| arguments | encodeURL | Infinity | Number | RegExp |
|--|--|--|--|--|
| Array | encodeURLComponent | isFinite | Object | String |
| Boolean | Error | isNaN | parseFloat | SyntaxError |
| Date | eval | JSON | parseInt | TypeError |
| decodeURL | EvalError | Math | RangeError | undefined |
| decodeURLComponent | Function | NaN | ReferenceError | URLError |
> 不同的 JavaScript 运行环境都会预定义一些全局变量和函数,上表列出的仅针对 Web 浏览器运行环境
无论是在严格模式下还是在非严格模式下,都不要在定义变量名、函数名或者属性名时使用上面列举出的保留字,以免同学们入坑
2.2.9 空白符(分隔符)
分隔符(空白符)就是各种不可见字符的集合,如空格(\u0020)、水平制表符(\u0009)、垂直制表符(\u000B)、换页符(\u000C)、不中断空白(\u00A0)、字节序标记(\uFEFF)、换行符(\u000A)、 回车符(\u000D)、行分隔符(\u2028)、段分隔符(\u2029)等.
在 JavaScript 中,分隔符不被解析,主要用来分隔各种记号,如标识符、关键字、直接量等信息。 在JavaScript 脚本中,常用分隔符来格式化代码,以方便阅读.
function toStr(a){return a.toString();}
可以使用分隔符格式化显示:
function toStr(a){
return a.toString();
}
一般 JavaScript 编辑器都会提供代码格式化的功能。
分隔符使用时需要注意以下几点:
- 分隔符虽然无实际意义,但是在脚本中却不能缺少。如果在标识符与关键字之间不使用分隔符分隔,JavaScript 就会抛出异常
javascript
functiontoStr(a){returna.toString();} //错误写法
function toStr(a){return a.toString();} //正确写法
-
JavaScript 解析器一般采用最长行匹配原则,不恰当地换行显示一句代码,容易引发异常或错误
function toStr(a){ return
a.toString(); //错误的换行
}
document.write(toStr("abc")); //实际返回 undefined,应该返回"abc"解析:这是因为 return 作为一条独立语句,JavaScript 解析器可以正确解析它,虽然它后面没有分号,解析器在正确解析的前提下会自动为其补加一个分号,以表示该句已经结束。这样换行显示的 a.toString();就是下一句待执行的命令,而不是被返回的值
-
不能在标识符、关键字等内部使用分隔符
function toStr(a){ return a.to String(); //错误分隔符
} -
在字符串或者正则表达式内,分隔符是有意义的,不能够随意省略或替换
var a = "空格"; var b = "空格 ";
document.write((a==b)); //返回 false,说明不相同2.2.10 注释
| 语言 | 注释 |
|--|--|
| HTML |
| CSS | /* 注释 / |
| javaScript | // 单行注释 /多行注释 */ |//程序描述 function toStr(a){ //块描述
//代码段描述
return a.toString(); //语句描述
}
/*
* jQuery JavaScript Library v3.3.1
* https://jquery.com/
* Includes Sizzle.js
* https://sizzlejs.com/
* Copyright JS Foundation and other contributors
* Released under the MIT license
* https://jquery.org/license
* Date: 2019-08-21 T 17:24 Z
*/2.2.11 转义字符
转义字符是字符的一种间接表示方式。在特殊语境中,无法直接使用字符自身。例如,在字符串中包含说话内容。
alert(""子曰:"学而不思则罔,思而不学则殆。""");
由于 JavaScript 已经赋予了双引号为字符串直接量的标识符,如果在字符串中包含双引号,就必须使用转义字符表示
alert("子曰:\"学而不思则罔,思而不学则殆。\"");
JavaScript 定义反斜杠加上字符可以表示字符自身。注意,一些字符加上反斜杠后会表示特殊字符,而不是原字符本身,这些特殊转义字符被称为转义序列,具体说明如表所示
| 序列 | 代表字符 |
|--|--|
| \0 | Null字符(\u0000) |
| \b | 退格符(\u0008) |
| \t | 水平制表符(\u0009) |
| \n | 换行符(\u000A) |
| \v | 垂直制表符(\u000B) |
| \f | 换页符(\u000C) |
| \r | 回车符(\u000D) |
| \"
| 双引号(\u0022) |
| \'
| 撇号或单引号(\u0027) |
| \\
| 反斜杠(\u005C) |
| \xXX | 由 2 位十六进制数值 XX 指定的 Latin-1 字符 |
| \uXXXX | 由 4 位十六进制数值 XXXX 指定的 Unicode 字符 |
| \XXX | 由 1~3 位八进制数值(000 到 377)指定的 Latin-1 字符,可表示 256个 字符。如 \251 表示版本符号。注意,ECMAScript 3.0 不支持,考虑到兼容性不建议使用。 |
提示:
如果在一个正常字符前添加反斜杠,JavaScript 会忽略该反斜杠
alert("子曰:\"学\而\不\思\则\罔\, \思\而\不\学\则\殆\。\"");
//等价于
alert("子曰:\"学而不思则罔,思而不学则殆。\"");
2.3 变量
变量相当于容器,值相当于容器内装的东西,而变量名就是容器上贴着的标签,通过标签可以找到 变量,以便读、写它存储的值
2.3.1 声明变量
常用的方式为:
var 变量名 = 初始化值;
在一个 var 语句中,可以声明一个或多个变量,也可以为变量赋值,未赋值的变量初始化为undefined(未定义)值。当声明多个变量时,应使用逗号运算符分隔
var a; //声明一个变量
var a,b,c; //声明多个变量
var b = 1; //声明并赋值
alert(a); //返回 undefined
alert(b); //返回 1
可以重复声明同一个变量,也可以反复初始化变量的值
var a = 1;
var a = 2;
var a = 3;
alert(a); //返回 3
注意:
在非严格模式下,JavaScript 允许不声明变量就直接为其赋值,这是因为 JavaScript 解释器能够自动隐式声明变量。隐式声明的变量总是作为全局变量使用。在严格模式下,变量必须先声明,然后才能使用。
"use strict";// 严格模式
a = 3; // 报错 (a 未定义)
2.3.2 关于JS的弱类型(动态类型)
JavaScript 是弱类型语言,对于变量类型的规范比较松散。具体表现如下:
- 变量的类型分类不严谨、不明确,带来使用的随意性。
- 声明变量时,不要求指定类型。
- 使用过程不严格,可以根据需要自动转换变量类型。
- 变量的转换和类型检查没有一套统一、规范的方法,导致开发效率低下。
由此带来的优缺点如下:
- 优点:使用灵活,简化了代码编写。
- 缺点:执行效率低,在开发大型应用时,程序性能会受到影响。
简单说就是,同一变量可以接受不同的数据类型。
var a = 1; //数值类型
a = "1"; //字符串类型
2.3.3 字符和字符串类型的说明
JavaScript中只有字符串类型,没有字符类型,字符串既可以使用双引号,也可以使用单引号。
var a = "1";
var a = '1';
2.3.4 变量定义的特点
- var关键字不是必须的,可以省略,但不建议省略
- 变量名可以重复定义
##### 2.3.5 变量作用域
在 JavaScript 中, 对象和函数同样也是变量,变量作用域为可访问变量,对象,函数的集合。
> 变量作用域(Scope)是指变量在程序中可以访问的有效范围,也称为变量的可见性。
JavaScript 变量可以分为全局变量和局部变量:
- 全局变量:不是声明在函数体内部的变量,变量在整个页面脚本中都是可见的,可以被自由访问。
- 局部变量:变量仅能在声明的函数内部可见,函数外是不允许访问的。只要函数运行完毕,变量就会被删除
###### 2.3.5.1 局部变量
只能在函数内部访问
javascript
// 此处不能调用 carName 变量
function myFunction() {
var carName = "Volvo";
// 函数内可调用 carName 变量
}
alert(carName); //error: carName is not defined
因为局部变量只作用于函数内,所以不同的函数可以使用相同名称的变量。
局部变量在函数开始执行时创建,函数执行完后局部变量会自动销毁
###### 2.3.5.2 全局变量
网页中所有脚本和函数均可使用
javascript
var carName = " Volvo";
// 此处可调用 carName 变量
function myFunction() {
// 函数内可调用 carName 变量
}
向未声明的 javascript 变量来分配值
如果您把值赋给尚未声明的变量,该变量将被自动作为全局变量声明。如:
javascript
ycdl = "云创动力"; //注:前面没有var
这样声明一个全局变量,哪怕这个变量是声明在函数内部它也是一个全局变量。
全局变量是 window 对象,所有数据变量都属于 window 对象
javascript
myFunction();
// 此处可以使用 windwo.carName
document.getElementById("demo").innerHTML =
"我可以显示 " + window.carName;
function myFunction()
{
carName = "Volvo"; //全局变量
}
##### 2.3.6 生命周期
JavaScript 变量生命周期在它声明时初始化。
局部变量在函数执行完毕后销毁。
全局变量在页面关闭后销毁。
##### 2.3.7 变量污染
javaScript 可以随意定义保存所有应用资源的全局变量。但全局变量可以削弱程序灵活性,增大了模块之间的耦合性。在多人协作时,如果定义过多的全局变量有可能造成全局变量冲突。
javascript
var x = 10;
// 这里输出 x 为 10
{
var x = 2;
// 这里输出 x 为 2
}
// 这里输出 x 为 2
解决方式: - 定义全局变量命名空间
只创建一个全局变量,并定义该变量为当前应用容器,把其他全局变量追加在该命名空间下
javascript
var MyAPP = {}; //定义 APP 访问接口
MyAPP.name = { //定义APP配置变量
"id" : "应用程序的ID编号"
};
MyAPP.work = {
num : 123, //APP计数器等内部属性
sub : { name : "sub_id"}, //APP应用分支
doing : function(){ //具体方法
//执行代码
}
};
- 使用函数体封装应用程序,这是最常用的一种方法
javascript
(function(){
var MyAPP = {}; //定义 APP 访问接口
MyAPP.name = { //定义APP配置变量
"id" : "应用程序的ID编号"
};
MyAPP.work = {
num : 123, //APP计数器等内部属性
sub : { name : "sub_id"}, //APP 应用分支
doing : function(){ //具体方法
//执行代码
}
};
window.MyAPP = MyAPP; //对外开放应用程序接口
})();
window.MyAPP; //外部调用
##### 2.3.8 let&const
ES2015(ES6) 新增加了两个重要的 JavaScript 关键字: let 和 const。
let 声明的变量只在 let 命令所在的代码块内有效。
const 声明一个只读的常量,一旦声明,常量的值就不能改变。
在 ES6 之前,JavaScript 只有两种作用域: 全局变量 与 函数内的局部变量
```javascript
var name = "张三"; //全局变量
function myFun(){
var age = 11; // 局部变量
}
###### 2.3.8.1 JavaScript 块级作用域(Block Scope)
使用 var 关键字声明的变量不具备块级作用域的特性,它在 {} 外依然能被访问到。
```javascript
{
var a = 10;
}
// 可以访问到 a
在 ES6 之前,是没有块级作用域的概念的。
ES6 可以使用 let 关键字来实现块级作用域。
let 声明的变量只在 let 命令所在的代码块 {} 内有效,在 {} 之外不能访问
{
let x = 2;
}
// 这里不能使用 x 变量
使用let定义变量也可以解决变量污染问题
注意:
- 在函数体外或代码块外使用 var 和 let 关键字声明的变量,它们的作用域都是 全局的
- 在函数体内使用 var 和 let 关键字声明的变量,它们的作用域都是 局部的
- 使用let声明的变量不能再次被声明
###### 2.3.8.2 const 关键字
const 用于声明一个或多个常量,声明时必须进行初始化,且初始化后值不可再修改
javascript
const PI = 3.141592653589793;
PI = 3.14; // 报错
PI = PI + 10; // 报错
const
定义常量与使用let
定义的变量相似: - 二者都是块级作用域
- 都不能和它所在作用域内的其他变量或函数拥有相同的名称
两者还有以下两点区别:
- const 声明的常量必须初始化,而 let 声明的变量不用
- const 定义常量的值不能通过再赋值修改,也不能再次声明。而 let 定义的变量值可以修改。
#### 2.4 数据类型
在JavaScript中,数据类型可以分为原始类型和引用类型。
##### 2.4.1 五种原始数据类型:
| 类型 | 说明 |
|--|--|
| Number | 数值型:整数和浮点数 |
| Boolean | 布尔类型:true/false |
| String | 字符串类型:包含字符和字符串 |
| Null | 只有一个值null |
| Undefined | 未定义/变量未初始化时的类型,只有一个值undefined |
> 注: Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值
##### 2.4.2 typeof操作符 - 作用:判断指定的变量数据类型
- 写法:
javascript
typeof(变量名) 或 typeof 变量名
- null 与 undefined 的区别:
null: 是一个object类型,但没有值,可以认为是引用类型的占位符
undefined:未初始化的类型,不知道是什么类型
##### 2.4.3 示例
javascript
<script type="text/javascript">
var i = 5;
document.write("整数:" + typeof(i) + "<br/>");
var f = 3.14;
document.write("浮点数:" + typeof(f) + "<br/>");
var str = "abc";
document.write("字符串:" + typeof(str) + "<br/>");
var c = 'a';
document.write("字符:" + typeof(c) + "<br/>");
var b = true;
document.write("布尔类型:" + typeof(b) + "<br/>");
var u;
document.write("未定义的类型:" + typeof(u) + "<br/>");
var n = null;
document.write("null:" + typeof(n) + "<br/>");
</script>
2.4.4 引用类型
引用类型有:对象(Object)、数组(Array)、函数(Function)
2.5 常用运算符
2.5.1 算术运算符
算术运算符用于执行两个变量或值的运算。
以下表格将向你说明算术运算符的使用: y = 5
| 运算符 | 描述 | 例子 | y值 | x值 |
|--|--|--|--|--|
| + | 加法 | x = y + 2 | 5 | 7 |
| - | 减法 | x = y - 2 | 5 | 3 |
| * | 乘法 | x = y * 2 | 5 | 10 |
| / | 除法 | x = y / 2 | 5 | 2.5 |
| % | 余数 | x = y % 2 | 5 | 1 |
| ++ | 自增 |x = ++ y | 6 | 6 |
| | | x = y ++ | 6 | 5 |
| -- | 自减 | x = - - y | 4 | 4 |
| | | x = y - - | 4 | 5 |
任何类型的数据都可以使用算数运算符参与运算
var a = 10; var b = false; document.write(a + b);
2.5.2 赋值运算符
赋值运算符用于给 javascript 变量赋值。
下面的表格解释了赋值运算符: x = 10; y = 5
| 运算符 | 例子 | 类似于 | x值 |
|--|--|--|--|
| = | x = y | x = y | 5 |
| += | x += y | x = x + y | 15 |
| -= | x -= y | x = x - y | 5 |
| *= | x *= y | x = x * y | 50 |
| /= | x /= y | x = x / y | 2 |
| %= | x %= y | x = x % y | 0 |2.5.3 比较运算符
比较运算符用于逻辑语句的判断,从而确定给定的两个值或变量是否相等。
下表展示了比较运算符的使用: x = 5
| 运算符 | 描述 | 例子 | 结果 |
|--|--|--|--|
| == | 等于 | x == 8 | false |
| | | x == 5 | true |
| === | 值及类型均相等(恒等于) | x === "5" | false |
| | |x === 5 | true |
| != | 不等于 | x != 8 | true |
| !== | 值与类型均不等(不恒等于) | x !== "5" | true |
| | |x !== 5 | false |
| > | 大于 | x > 8 | false |
| < | 小于 | x < 8 | true |
| >= | 大于或等于 | x >= 8 | false |
| <= | 小于或等于 | x <= 8 | true |
数字可以与字符串进行比较,字符串可以与字符串进行比较。字符串与数字进行比较的时候会先把字符串转换成数字然后再进行比较var a = 125; var b = "123"; document.write("字符串与数字比较的结果:"+ (a>b)+"<br/>");
2.5.4 逻辑运算符
逻辑运算符用来确定变量或值之间的逻辑关系。
下表展示了逻辑运算符的使用: x = 6 , y = 3
| 运算符 | 描述 | 例子 |
|--|--|--|
|&&
| 与 |(x < 10 && y > 1)
为 true |
|||
| 或 |(x == 5 | | y == 5)
为 false |
|!
| 非 |!(x == y)
为 true |逻辑运算符不存在单与&、单或|
2.5.5 三目(元)运算符
var age = 24; document.write("是成年人吗?"+ (age >= 18 ? "是":"不是")+"\<br/>");
2.6 流程控制语句
高级语言中的三种基本结构:顺序、分支、循环
2.6.1 if 判断
if 语句
在一个指定的条件成立时执行代码。if(条件表达式) { //代码块; }
if...else 语句
在指定的条件成立时执行代码,当条件不成立时执行另外的代码。if(条件表达式) { //代码块; }else { //代码块; }
if...else if....else 语句
使用这个语句可以选择执行若干块代码中的一个。if (条件表达式) { //代码块; }else if(条件表达式) { //代码块; }else { //代码块; }
条件判断可以使用非逻辑运算符
| 数据类型 | true | false |
|--|--|--|
| number | 非0 | 0 |
| string | 非空串 | 空串 |
| undefined | | false |
| NaN(Not a Number) | | false |
| object | 非null | null |2.6.2 循环
for 语句
循环指定次数for (var i=0; i<10; i++) { //需要执行的代码; }
while语句:
当指定的条件为 true 时循环执行代码while (条件表达式) { // 需要执行的代码; }
do-while语句:
最少执行1次循环do { // 需要执行的代码; } while (条件表达式)
break和continue
2.7.2 语法错误
如果有语法错误,浏览器会出现提示,出现错误后,下面代码将不会被执行
练习:
使用js输出乘法口诀表
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
span{
margin: 10px;
}
</style>
</head>
<body>
<script type="text/javascript">
for(var i=1;i<=9;i++){
for(var j=1;j<=i;j++){
document.write("<span>"+i+" * "+j+" = "+i*j+" </span>");
}
document.write("<br />")
}
</script>
</body>
</html>
2.8 函数
JavaScript 使用关键字 function 定义函数。
函数可以通过声明定义,也可以是一个表达式。
通俗的讲,可以将函数理解为 用一堆JavaScript代码,来完成某个功能
2.8.1 函数的声明
一个函数的声明(或者说是函数的定义)包含:
- 关键字function
- 函数名称
- 参数列表,包围在括号中并由逗号分隔
- 定义函数的 JavaScript 语句,用大括号 {} 括起来
javascript
function functionName(parameters){
// 执行的代码
}
例如:定义一个square
函数:
javascript
function square(number) {
return number * number;
}
函数square
使用了一个参数,叫作number
。这个函数只有一个语句,它说明该函数将函数的参数(即number
)自乘后返回。函数的return
语句确定了函数的返回值。
函数声明后不会立即执行,会在我们需要的时候调用。
原始参数(比如一个具体的数字)被作为值传递给函数;值被传递给函数,如果被调用函数改变了这个参数的值,这样的改变不会影响到全局或调用函数。
javascript
var num = 10;
var r1 = square(10); // 调用函数
num = 11;
如果你传递一个对象(即一个非原始值,例如Array
或用户自定义的对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示:
```javascript
function myFunc(theObject) {
theObject.make = "Toyota";
}
var mycar = {make: "Honda", model: "Accord", year: 1998};
var x, y;
x = mycar.make; // x获取的值为 "Honda"
myFunc(mycar);
y = mycar.make; // y获取的值为 "Toyota"
// (make属性被函数改变了)
> 分号是用来分隔可执行JavaScript语句。
由于函数声明不是一个可执行语句,所以不以分号结束
##### 2.8.2 函数表达式
JavaScript 函数可以通过一个表达式定义。
函数表达式可以存储在变量中:
```javascript
var square = function (number){ return number * number };
在函数表达式存储在变量后,变量也可作为一个函数使用:
var s = square(2);
以上函数实际上是一个 匿名函数 (函数没有名称)。
函数存储在变量中,不需要函数名称,通常通过变量名来调用。
上述函数以分号结尾,因为它是一个执行语句
2.8.3 Function() 构造函数
通过前边的内容我们学习了函数通过关键字 function 来定义。
函数同样可以通过内置的 JavaScript 函数构造器(Function())定义new Function ([arg1[, arg2[, ...argN]],] functionBody)
- arg1, arg2, ... argN
参数名称是一个有效的JavaScript标识符的字符串,或者一个用逗号分隔的有效字符串的列表;例如“×
”,“theValue
”,或“a,b
”- functionBody
一个含有包括函数定义的 JavaScript 语句的字符串
javascript
var sum = new Function("square", "return number * number");
上面的声明方式和我们之前函数表达式中声明的函数是一样的。
实际上,很多时候你不用使用构造函数来声明函数。而且要避免使用 new 关键字
使用Function
构造器生成的Function
对象是在函数创建时解析的。这比你使用函数声明或者函数表达式并在你的代码中调用更为低效,因为使用后者创建的函数是跟其他代码一起解析的当一个函数是一个对象的属性时,称之为方法
2.8.4 调用函数
定义一个函数并不会自动的执行它。定义了函数仅仅是赋予函数以名称并明确函数被调用时该做些什么。调用函数才会以给定的参数真正执行这些动作。例如,一旦你定义了函数 square ,你可以如下这样调用它:
square(2)
上述语句通过提供参数 2 来调用函数。函数执行完它的语句会返回值 4
函数一定要处于调用它们的域(范围)中,但是函数的声明可以被提升(出现在调用语句之后)
提升(Hoisting)是 JavaScript 默认将当前作用域提升到前面去的的行为console.log(square(5)); // 调用
function square(n) { return n*n } // 声明
函数域是指函数声明时的所在的地方,或者函数在顶层被声明时指整个程序
> 注意只有使用如上的语法形式(即 `function funcName(){}` )才可以。而下面的代码是无效的。就是说,函数提升仅适用于函数声明,而不适用于函数表达式。
```javascript
console.log(square); // square is hoisted with an initial value undefined.
console.log(square(2)); // TypeError: square is not a function
var square = function (n) {
return n * n;
}
函数可以被递归,就是说函数可以调用其本身。例如,下面这个函数就是用递归计算阶乘:
function factorial(n){
if ((n == 0) || (n == 1))
return 1;
else
return (n * factorial(n - 1));
}
2.8.5 函数作用域
在函数内定义的变量不能在函数之外的任何地方访问,因为变量仅仅在该函数的域的内部有定义。相对应的,一个函数可以访问定义在其范围内的任何变量和函数。换言之,定义在全局域中的函数可以访问所有定义在全局域中的变量。在另一个函数中定义的函数也可以访问在其父函数中定义的所有变量和父函数有权访问的任何其他变量。
// 下面的变量定义在全局作用域(global scope)中
var num1 = 20,
num2 = 3,
name = "Chamahk";
// 本函数定义在全局作用域
function multiply() {
return num1 * num2;
}
multiply(); // 返回 60
// 嵌套函数的例子
function getScore() {
var num1 = 2,
num2 = 3;
function add() {
return name + " scored " + (num1 + num2);
}
return add();
}
getScore(); // 返回 "Chamahk scored 5"
2.8.6 嵌套函数和闭包
你可以在一个函数里面嵌套另外一个函数。嵌套(内部)函数对其容器(外部)函数是私有的。它自身也形成了一个闭包。一个闭包是一个可以自己拥有独立的环境与变量的表达式(通常是函数)。
既然嵌套函数是一个闭包,就意味着一个嵌套函数可以”继承“容器函数的参数和变量。换句话说,内部函数包含外部函数的作用域。
可以总结如下:
- 内部函数只可以在外部函数中访问。
- 内部函数形成了一个闭包:它可以访问外部函数的参数和变量,但是外部函数却不能使用它的参数
和变量。
javascript
function addSquares(a, b) {
function square(x) {
return x * x;
}
return square(a) + square(b);
}
a = addSquares(2, 3); // returns 13
b = addSquares(3, 4); // returns 25
c = addSquares(4, 5); // returns 41
由于内部函数形成了闭包,因此你可以调用外部函数并为外部函数和内部函数指定参数:
```javascript
function outside(x) {
function inside(y) {
return x + y;
}
return inside;
}
fn_inside = outside(3); // 可以这样想:给一个函数,使它的值加3
result = fn_inside(5); // returns 8
result1 = outside(3)(5); // returns 8
###### 2.8.6.1 闭包
闭包是 JavaScript 中最强大的特性之一。JavaScript 允许函数嵌套,并且内部函数可以访问定义在外部函数中的所有变量和函数,以及外部函数能访问的所有变量和函数。
但是,外部函数却不能够访问定义在内部函数中的变量和函数。这给内部函数的变量提供了一定的安全性。
##### 2.8.7 函数参数
从ECMAScript 6开始,有两个新的类型的参数:默认参数,剩余参数
###### 2.8.7.1 默认参数
在JavaScript中,函数参数的默认值是 `undefined` 。然而,在某些情况下设置不同的默认值是有用的。这时默认参数可以提供帮助。
在过去,用于设定默认参数的一般策略是在函数的主体中测试参数值是否为 `undefined` ,如果是则赋予这个参数一个默认值。如果在下面的例子中,调用函数时没有实参传递给 `b` ,那么它的值就是`undefined` ,于是计算 `a*b` 得到、函数返回的是 `NaN` 。但是,在下面的例子中,这个已经被第二行获取处理:
```javascript
function multiply(a, b) {
b = (typeof b !== 'undefined') ? b : 1;
return a*b;
}
multiply(5); // 5
使用默认参数,在函数体的检查就不再需要了。现在,你可以在函数头简单地把1设定为 b
的默认值:
function multiply(a, b = 1) {
return a*b;
}
multiply(5); // 5
2.8.7.2 剩余参数
剩余参数语法允许将不确定数量的参数表示为数组。在下面的例子中,使用剩余参数收集从第二个到最后参数。然后,我们将这个数组的每一个数与第一个参数相乘。这个例子是使用了一个箭头函数。
function multiply(multiplier, ...theArgs) {
return theArgs.map(x => multiplier * x);
}
var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]
注意的事项
- 形参的类型:在函数定义的时候不用指定类型,因为是可变类型
- 函数的返回值:如果一个函数中需要返回值,直接使用return返回,如果没有返回值,不写return。
- 关于函数的重载:在JS中没有函数的重载,同名的函数会覆盖原来的函数,调用的时候,只会调用最后声明的函数,而且实参的个数与形参数的个数没有关系。
- 所有函数的内部都有一个类数组对象,名字叫:arguments,用来接收调用时提交的所有的参数。
演示:定义一个函数,在函数的内部输出arguments的长度和其中的每个元素。
<script type="text/JavaScript">
function sum (a,b) {
//在函数的内部输出arguments的长度和其中的每个元素
document.write("arguments数组的长度:" + arguments.length + "<hr/>");
//输出每个元素
for (var i = 0; i < arguments.length; i++) {
document.write(arguments[i] + "<br/>");
}
document.write("a=" + a + "<br />");
document.write("b=" + b + "<br />");
}
//调用
sum(3,10,8);
//sum(3);
</script>
心得体会
今天我们主要学习了JavaScript的剩余部分,包括JavaScript中的直接量、转义序列、标识符、关键字等各种概念,以及JavaScript中的各种变量的用法、作用域等等,还学习了JavaScript中的数据类型、运算符、函数等等。
在解决变量污染的时候还学习了一些Json的知识,总的来说,今天学习的东西比较多,在课堂上不能全部掌握,需要在课后多加练习才可以,今天的知识也相当重要,是学习JavaScript的重要时刻。学习了JavaScript的这些知识,就可以做成更加完美的前端界面,并且能够使自己的前端界面实现更多的功能。
评论留言