语法和数据类型
本章节复习的是JS中的基本语法,变量声明,数据类型和字面量。
首先要记住:JavaScript 对大小写敏感,即 varatt;
和 varAtt
是两个不同变量。
入门
一. js是什么?
(js即javascript,它是一种轻量级的脚本语言。运行在浏览器客户端.)
二. js引入方式
- a.内嵌式
所有js代码写到一个<script></script>,
此script标签可以放到html的任何地方
<script type="text/javascript">
js代码
</script>
- b.外链式
所有的js代码写到一个外部js文件内(该文件后缀名为.js),
在html内通过script上的src属性引入过来。
<script src="xxx.js"></script>
//导入外部js文件
- c.事件引入
在开始标签上通过加事件引入js代码
<button onclick="js代码">按钮</button>
<script>元素有下列 8 个属性。
async:可选。表示应该立即开始下载脚本,但不能阻止其他页面动作,比如下载资源或等待其
他脚本加载。只对外部脚本文件有效。
charset:可选。使用 src 属性指定的代码字符集。这个属性很少使用,因为大多数浏览器不
在乎它的值。
crossorigin:可选。配置相关请求的CORS(跨源资源共享)设置。默认不使用CORS。crossorigin= "anonymous"配置文件请求不必设置凭据标志。crossorigin="use-credentials"设置凭据
标志,意味着出站请求会包含凭据。
defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。只对外部脚本文件有效。
在 IE7 及更早的版本中,对行内脚本也可以指定这个属性。
integrity:可选。允许比对接收到的资源和指定的加密签名以验证子资源完整性(SRI,
Subresource Integrity)。如果接收到的资源的签名与这个属性指定的签名不匹配,则页面会报错,
脚本不会执行。这个属性可以用于确保内容分发网络(CDN,Content Delivery Network)不会提
供恶意内容。
language:废弃。最初用于表示代码块中的脚本语言(如"JavaScript"、"JavaScript 1.2"
或"VBScript")。大多数浏览器都会忽略这个属性,不应该再使用它。
src:可选。表示包含要执行的代码的外部文件。
三. 输出方式
alert()//警告框
document.write(内容)//向文档内部写入内容
console.log()//控制台日志输出
window对象的方法
- alert
alert() 警告框
无返回值 - confirm
confirm() 确认对话框
有返回值
返回值:布尔值
点击【确认】按钮,返回true,点击【取消】按钮,返回false - prompt
prompt(提醒文本,【默认】) 提示输入对话框
返回值:字符串 / null
点击【确认】按钮,返回输入框中的值(字符串类型),点击【取消】按钮,返回null
注:
console.log();控制台输出
document.write();页面输出
四. 注释
// 单行注释
/*
多行注释
*/
五. 变量 常量(声明)
a. 变量命名规范
1. 变量的名字又叫做“标识符”,必须以字母、下划线、美元符号$开头,后面可以是字母、下划线、美元符号或数字。
2.变量区分大小写
3.变量名不能使用关键字和保留字
b. 声明变量
JavaScript有三种声明方式:
-
var
声明一个变量(函数作用域),可赋一个初始值。 -
let
声明一个块作用域的局部变量,可赋一个初始值。 -
const
声明一个块作用域的只读命名的常量。
c. 初始化变量
- 如
var a=1
,声明局部变量和全局变量。 - 如
a=1
,声明一个全局变量,且在严格模式报错,不应该使用。 - 如
let a=1
,声明一个块作用域的局部变量。
1. var 声明
a. 函数作用域
关键的问题在于,使用 var 操作符定义的变量会成为包含它的函数的局部变量。比如,使用 var
在一个函数内部定义一个变量,就意味着该变量将在函数退出时被销毁:
function test() {
var message = "hi"; // 局部变量
}
test();
console.log(message); // 出错!
b.var在全局作用域中声明的变量会成为 window 对象,let不会
与 var 关键字不同,使用 let 在全局作用域中声明的变量不会成为 window 对象的属性(var 声明的变量则会)。
var name = 'Matt';
console.log(window.name); // 'Matt'
let age = 26;
console.log(window.age); // undefined
不过,let 声明仍然是在全局作用域中发生的,相应变量会在页面的生命周期内存续。因此,为了避免 SyntaxError,必须确保页面不会重复声明同一个变量。
若想将var定义的变量成为全局变量,则可以这样:
function txt(){
a =1;//全局变量
}
txt();
console.log(a)//1
c. var 声明提升
使用 var 时,下面的代码不会报错。这是因为使用这个关键字声明的变量会自动提升到函数作用域顶部:
function foo() {
console.log(age);
var age = 26;
}
foo(); // undefined
之所以不会报错,是因为 ECMAScript 运行时把它看成等价于如下代码:
function foo() {
var age;
console.log(age);
age = 26;
}
foo(); // undefined
这就是所谓的“提升”(hoist),也就是把所有变量声明都拉到函数作用域的顶部。此外,反复多次
使用 var 声明同一个变量也没有问题:
function foo() {
var age = 16;
var age = 26;
var age = 36;
console.log(age);
}
foo(); // 36
1. let 声明
a. 块作用域
let 跟 var 的作用差不多,但有着非常重要的区别。最明显的区别是,let 声明的范围是块作用域,而 var 声明的范围是函数作用域。
if (true) {
var name = 'Matt';
console.log(name); // Matt
}
console.log(name); // Matt
if (true) {
let age = 26;
console.log(age); // 26
}
console.log(age); // ReferenceError: age 没有定义
在这里,age 变量之所以不能在 if 块外部被引用,是因为它的作用域仅限于该块内部。块作用域
是函数作用域的子集,因此适用于 var 的作用域限制同样也适用于 let。
let 也不允许同一个块作用域中出现冗余声明。这样会导致报错:
var name;
var name;
let age;
let age; // SyntaxError;标识符 age 已经声明过了
当然,JavaScript 引擎会记录用于变量声明的标识符及其所在的块作用域,因此嵌套使用相同的标
识符不会报错,而这是因为同一个块中没有重复声明:
var name = 'Nicholas';
console.log(name); // 'Nicholas'
if (true) {
var name = 'Matt';
console.log(name); // 'Matt'
}
let age = 30;
console.log(age); // 30
if (true) {
let age = 26;
console.log(age); // 26
}
对声明冗余报错不会因混用 let 和 var 而受影响。这两个关键字声明的并不是不同类型的变量,
它们只是指出变量在相关作用域如何存在。
var name;
let name; // SyntaxError
let age;
var age; // SyntaxError
注意:
- 若没有为变量赋初始值,则值默认为
undefined
;
let a;
console.log(a); // undefined
- 若没有声明变量而直接使用,会抛出
ReferenceError
错误;
console.log(b); // Uncaught ReferenceError: b is not defined
- 当变量值为
undefined
时,布尔值环境会当做false
,数值环境会当做NaN
;
var a;
if(!a){
console.log('a为undefined'); // a为undefined
}
a + 1; // NaN
- 当变量值为
null
时,布尔值环境会当做false
,数值环境会当做0
;
let a = null;
if(!a){
console.log('a为unll'); // a为unll`
}
a + 1; // 1
d. 变量作用域
全局变量:即声明在函数之外,当前文档所有地方都可以访问;
局部遍历:即声明在函数内部,仅在当前函数内可以访问;
(在ES5之前没有语句块作用域的概念,并只能使用 var
进行声明,用 var
声明的变量,在函数内和全局都可以访问,而在ES6开始,将只能在声明的作用域中使用.)
if(true){
var a = 1;
}
a; // 1
if(true){
let b = 2;
}
b; // ReferenceError: b is not defined
变量声明提前(ES5 之前)
即将变量的声明提升到函数或语句的顶部,并返回 undefined
直到变量被初始化操作。
千万注意:ES5 以及之前,才有变量声明提前,在ES6开始就不存在变量提升。
// ES5及之前
console.log(a); // undefined
var a = 1;
console.log(a); // 1
// ES6开始`
console.log(b); // Uncaught ReferenceError: b1 is not defined
let b = 2;
console.log(b); // 2
函数提升
函数声明有两种方式:函数声明和函数表达式两种方式:
// 函数声明
f(); // hi leo
function(){
console.log('hi leo');
};
// 函数表达式
g(); // Uncaught TypeError: g is not a function
var g = function(){ // 换成 let 声明也一样
console.log('hi leo');
}
暂时性死区
上面说了var会有变量提升,而let却没有。如:
// name 会被提升
console.log(name); // undefined
var name = '伍叁';
//------------------
// age 不会被提升
console.log(age); // ReferenceError:age 没有定义
let age = 18;
全局变量
全局变量默认是全局对象( window
)的属性,常常使用 window.variable
语法来设置和访问全局变量。
这边还需要记住:
ES5之中,顶层对象的属性等价于全局变量(浏览器环境中顶层对象是
window
,Node中是global
对象);ES6之中,
var
/function
声明的全局变量,依然是顶层对象的属性,但是let
/const
/class
声明的全局变量不属于顶层对象的属性,即ES6开始,全局变量和顶层对象的属性是分开的。
// ES5
var a = 'leo';
window.a; // 'leo'
// ES6
let b = 'leo';
window.b; // undefined
常量和 const
ES6之后我们可以使用 const
来声明一个只读的常量,并且在声明时必须赋值,之后在相同作用域中不能赋值也不能重新声明,否则报错。
const a;
// Uncaught SyntaxError: Missing initializer in const declaration
const b = 'leo';
b = 'hi';
// Uncaught TypeError: Assignment to constant variable.
function f(){
const a1 = 'hi';
console.log(a1);
}
f(); // 'hi'
const a1 = 'hi leo';
a1; // "hi leo"
尽管 const
声明的变量不能直接修改值,但是对于对象和数组,却是不受保护可以修改的:
const a = {name:'leo',age:25};
a.name = 'pingan'; // a => {name: "pingan", age: 25}
const b = ['hi', 'leo'];
b[1] = 'pingan'; // b => ["hi", "pingan"]
六. 数据结构和数据类型
数据类型
JavaScript中一共分为7种不同类型:
- 六种原型数据类型:
- 1.Boolean : 布尔值,true和false;
- 2.null : 对大小写敏感(即
null
/Null
/NULL
完全不同); - 3.undefined : 空类型,变量未定义时候的值;
- 4.Number : 数字类型,如
100
; - 5.String : 字符串类型,如'hi pingan';
- 6.Symbol(ES6新增) : 表示一种唯一且不可变的数据;
- 以及Object对象类型
数据类型转换
由于JavaScript是门动态类型语言,因此在开发过程可以不需要指定数据类型,在执行时会自动转换:
var a = 100;
a = 'hi leo'; // 这样不报错
另外还有:
let a1 = '10';
let b1 = 20;
a1 + b1; // 30
let a2 = 'leo ' + 10 + ' age'; // leo 10 age
'10' - 5; // 5
'10' + 5; // 105
转换字符串为数字小技巧(连接符+)
小技巧很多,这里说个最简单的:
// 这样不会使两个数字计算总和:
'1.1' + '1.2'; // '1.11.2'
// 实际上要这样:
+'1.1' + +'1.2'; // 2.3
七. 字面量
字面量是用来表示如何表达这个值,简单理解就是变量赋值时右边的都是字面量。比如:
let a = 'hi leo';
hi leo
为字符串字面量, a
为变量名。
字面量分为七种:
- 1.数组字面量
- 2.布尔字面量
- 3.浮点数字面量
- 4.整数字面量
- 5.对象字面量
- 6.正则字面量
- 7.字符串字面量
1. 数组字面量
使用数组字面量创建数组的时,指定元素的值,并作为数组的初始化,从而确定数组长度。
let a = ['hi','leo','hello','pingan'];
a[1]; // 'leo'
a.length; // 4
若使用多余逗号,作为数组字面量,则值为 undefined
,并且数组长度也会正常计算:
let a = ['hi', ,'leo'];
a[0]; // 'hi'
a[1]; // undefined
a.length; // 3
2. 布尔字面量
只有 true
和 false
:
let a = true;
3. 整数字面量
整数可以用十进制(基数为10)、十六进制(基数为16)、八进制(基数为8)以及二进制(基数为2)表示。
4. 浮点数字面量
浮点数字面量组成:
- 一个十进制的整数,可以带正负号;
- 小数点
- 小数部分(只能十进制)
- 指数部分
let a = 3.14; // 3.14
let b = -.001; // -0.001
let c = -3.14e+12; // -3.14*1012
let d = .1e-23;// 0.1*10 - 23 = 10-24 = 1e-24
5. 对象字面量
对象字面量是由 {}
包含一个或多个 键:值
对的列表:
let a1 = 'hi leo';
let a2 = function(){ return 'my name is pingan' };
let obj = {
n1 : 'pingan',
n2 : a1,
n3 : a2()
}
obj; // {n1: "pingan", n2: "hi leo", n3: "my name is pingan"}
也可以使用任意数字或字符串作为对象属性的名字,但必须用 ''
引号包裹:
let obj = {
"" : "hi leo",
"!" : "hi pingan",
2 : 'hi number'
}
obj; // {2: "hi number", "": "hi leo", !: "hi pingan"}
obj[""]; // "hi leo"
obj[2]; // "hi number"
6. 正则字面量
使用字符被正斜杠“ /
”围起来的表达式:
var a = /ab+c/;
7. 字符串字面量
使用单引号( ''
)或者双引号( ""
)括起来的字符串:
let a = 'leo';
a.length; // 3
ES6中新增了模板字符串,作用于:
方便拼接字符串
有效实现字符串换行
防止注入攻击
建立基于字符串的高级数据抽象
// 拼接字符串
let name = 'leo';
let a = `
hi ${name}
`;
a; // hi leo
// 换行`
let b = `
hi
leo
`;
b;
// "
// hi
// leo
// "
常用特殊字符:
字符 | 含义 |
---|---|
\b | 退格符 |
\f | 换页符 |
\n | 换行符 |
\r | 回车符 |
\t | Tab (制表符) |
\v | 垂直制表符 |
' | 单引号 |
" | 双引号 |
\ | 反斜杠字符(\) |