一. 什么是JavaScript?
概念
JavaScript简称JS. JS是世界上最流行的编程语言之一, 它是一个脚本语言, 通过解释器运行, 主要在客户端(浏览器)运行, 现在也可以基于node.js在服务器上运行.
JS是一种具有函数有限的轻量级, 解释型 或即时编译型的编程语言. 虽然他是作为开发web页面的脚本语言而出名, 但是他也被用到了许多非浏览器环境中, JS基于原型编程, 多凡事的动态脚本语言. 并且支持面向对象, 命令式, 声明式, 函数式编程范式.
JS是在1995年有NetScape公司的Brendan Eich, 在网景导航者留恋其上首次设计实现而成, 因为Netscape与Sun合作, NetScape管理层希望他看起来更像Java, 因为取名为JavaScript, 但实际上他和Java没有无任何关系, JS在实际上的语法风格和Self和Scheme较为接近.
JavaScript可以做的事情
- 网页开发
- 网页游戏开发
- 服务器开发(node.js)
- 桌面程序开发
- 手机App开发
JavaScript和HTML, CSS之间的关系
简单来说:
- HTML是一种超文本标记语言, 提供网页的结构, 提供网页中的内容, 是网页结构中的骨架
- CSS 用来美化页面, 变现为页面的外表
- JavaScript: 网页的行为, 用来控制网页的内容, 给网页增加动态效果.
JavaScript运行过程
- 编写的代码保存在文件当中, 也就是存储在硬盘(外存上)
- 双击.html文件, 浏览器就会读取文件, 把文件加载到内存当中去.
- 浏览器会解析用户编写的代码, 把代码翻译成二进制文件, 能够让计算机CPU识别,并解释工作
- 得到的二进制指令被CPU加载并执行.
二. 基础语法篇
第一个JavaScript程序
我们说HTML是网页的骨架, 我们在编写JavaScript代码的时候需要HTML的框架, 也就是说, 在HTML文件中来书写JavaScript语句, 通常会使用Html中的script标签, 来将JavaScript语句包含在script标签当中.:
<script> alert("hello world!") </script>
我们点击预设好的HTML文件:
显示如下:
alert是JS中的一个弹出警告窗口, 括号里面的内容为提示内容. 此处的提示内容为hello world
JS的书写形式
- 行内式
什么叫做行内式呢? 也就是直接将JS语句嵌套到HTML元素的内部, 这就称为行内式, 例如, 我们设计一个按钮, 点击这个按钮可以弹出hello world提示内容的弹窗< 首先可以想到的是input标签:
<input type="button" value="我是一个按钮" onclick="alert('hello world')">
- 随后代开html页面如下:
点击这个<我是一个按钮>, 将会显示如下弹窗内容:
注意 : 在JS中的字符串可以是单引号引起的, 也可以是双引号引起的字符串, 但是在配合THML使用的时候一定要注意避免使用引号而导致的截断. - 内嵌式
也就是我们上面所说的, 将JS语句写入到HTML的script标签中, 例如我们上面使用的alert弹窗:
<script> alert("hello world") </script>, 但是如果你直接使用alert("hello world"), 就不会被浏览器识别为JS语法, 例如:
<body> <script> alert("hello world") </script> </body>
- 将会在浏览器直接显示:
并不会将alert识别为一个JS弹窗 - 外部式
也就是通过外部引用的方式使用js代码, 使用外部的JS文件, 来导入js代码, 例如使用html的scrip标签中的src属性来指定js文件:
在js文件中就可以编写js代码, 例如我们在这个toos.js中直接写入一行js代码:alert("hello world"), 就会被识别, 然后成功弹出
JS的代码注释
- 单行注释//
直接要在被注释的一行前面使用双反斜杠//, 来表示这样一整行都被注释, 例如:
// alert("hello world")
- 多行注释/*被注释的多行内容*/
多行注释和单行注释的用法和java差不多, 例如:
<body> <script> var name = prompt("请输入您的名字") </script> </body>
- 但是不建议多行注释的嵌套使用, 例如
这样子使用就会直接报错
输入输出
- 输入框prompt
使用prompt可以弹出一个输入框, 例如, 我们编写如下代码
<body> <script> var name = prompt("请输入您的名字") </script> </body>
- 就会在html页面显示:
这个prompt哈数有一个返回值, 这个返回值就是用户输入的值. 我们可以使用的一个变量来接收这个值 - 警告窗alert
之前展示过, 使用alert函数, 可以触发一个弹出告示窗口, 函数的参数是一个字符串, 这个字符串被作为提示内容. - 控制台日志console.log
这个是在控制台打印一个日志, 供给程序员查看的, 例如:
console.log("这是一个日志!!")
日志是作为程序员调试程序的重要手段
变量的使用
JavaScript变量, 使用来存储信息的容器, 例如:
var x = 1;
var y = 2;
var z = x + y;
就像代数那样, 使用字母来保存值, 上述表达式中我们可以计算出z的值为3. 这些形如xyz的字母被成为变量名
变量命名
- 除了xyz之外, 我们可以使用更加具有标识性的名称, 例如平均数使用avg作为变量名
- 变量可以使用字母开头
- 变量名不能以数字开头
- 变量名也能使用$进而_符号开头, 但是不推荐这样子命名
- 变量名对大小写敏感
数据类型
除了整数之外, JavaScript还可以保存其他数据类型, 录入文本值(var name = "ZhangSan"), 在js中, 类似于"ZhangSan"这样的文本被称为字符串(除了双引号, 也可以使用单引号在js中), JS中除了文本和整形, 还有其他的很多种数据类型.
当你向变量分配文本值的时候, 应该使用双引号或者单引号包围这个值, 如果向变量赋值的是数值时, 不用使用引号, 如果被引号包围, 就会被当做文本处理, 例如var x = 1和var x = "1"是两个不同的处理方式
变量的声明和使用
1. 声明一个变量
我们声明一个name变量,来记录名字:
var name
对变量name进行赋值, 并输出到alert作为提示内容:
name = "ZhangSan"
alert(name)
2. 一条语句多个变量:
我们可以在一行语句中, 声明多个变量, 使用var做为开头 , 中间多个变量, 使用逗号作为分割:
var index1, index2, index3 .....
或者
var index1 = "case1", index2 = "case2", index3 = "case3" .....
如果这样赋值:
var index1, index2, index3 = "case3";
那么index1, 和index2是未被定义的, 而index3 = "case3"
3. 重新声明变量
例如, 我们定义一个变量name , 给其赋值之后, 然后再次定义这个变量name
var name = "ZhangSan"
var name
alert(name)
编写如上代码, 并执行:
此时任然可以正常显示, 也就是说, 在JS中, 重新生成变量不会导致该变量的值丢失.
理解动态类型
js中的关键字var有点类似于java中的关键字var, 可以自动识别数据类型, js中的变量是程序运行的过程中才能确定的, 这也就一位置, 相同的一个变量可以拥有不同的数据类型, 例如:
var x = 1;
var x = "hello world";
这个过程中, x的数据类型从数字类型转变为了字符串类型.
假如, 这里有一个变量, 但是你不知道他的类型, 那么你可以使用typeof操作符来查看, 例如:
var x = "hello world";
var ret = typeof x;
alert(ret);
输出:
JS变量类型
JS的变量类有以下几种:
- number: 数字类型, 小数和整数统称为数字类型
- boolean: true表示为真, false为假.
- string: 字符串类型
- undefined: 只有唯一的值undefined表示未定义的值
- null: 表示空值
1. number
JS中不区分整数和浮点数, JS中的整数和浮点数统称为数字类型. 例如:
var x = 1;
var y = 1.322;
上面这个x和y都表示数字类型
JS中的数字类型有几个表示方法:
- 十进制, 就是直接使用类似这种: var x = 1; 这种就是十进制的定义方法
- 八进制, 形如var x = 07这样的, 其中八进制的数以0开头
- 二进制, 形如var x = 0b1011, 0b表示二进制,后面的"1011"表示数据位.
- 十六进制: 形如var x = 0xabc, 0x表示16进制
对于2进制来说, 每四位表示一个16进制数, 每三位表示一个8进制数, 以此类推
除了这些之外, 还存在着一些特殊的数字类型的值:
- Infinity: 表示无穷大, 大于任何数字, 表示的数字已经超过了JS的能表示的范围
- -Infinity: 表示负无穷大, 小于任何数字, 表示数字已经超过了JS能表示的范围
- NaN: Not a Number, 表示当前的结果不是一个数字
我们在html页面进行输出查看者三个情况:
var MAX = Number.MAX_VALUE;//通过这个方法可以获取到Number的最大值, 也就是Infinity
// 然后使用控制台进行输出查看
console.log( max * 2)
console.log( -max * 2)
console.log('hello world' - 10)
运行结果依次为如上图
2. String
字符串的字面常量需要使用引号(单引号和双引号都可以, 但是需要注意不能发生截断等语法错误), 例如:
var str1 = "hello world"
var str2 = "hello java"
如果使用的字符串没有赋值将会报错, 例如:
var str3 = hello java and world; // 如果没有使用引号就会直接报错.
但是如果想要使用的字符串里面已经包含了引号, 这个时候为了避免发生截断该怎么办. 我们可以使用转义字符, 例如:
var str1 = "this is a "dog"" ; // 此种情况发生了截断, 会发生报错
var str2 = "this is a \"dog\""; // 对把dog包围的引号进行的转移, 让他来表示字符串内部的引号
var str3 = "this is a 'dog'"; // 如果单引号冲突, 那么可以使用双引号和单引号搭配使用,
var str4 = 'this is a "dog"';
求字符串的长度可以使用length属性来查看, 例如:
var str = "hello world"
var len = str.length
console.log(len);
结果如下:
JS中的字符串也有类似于java中String类的字符串拼接, 例如我们可以将两个字符串拼接在一起:
var str1 = "this is a ";
var str2 = "dog"
console.log(str1 + str2)
输出如下:
同时字符串也可以和数字类型的数据进行拼接:
var str = "my age is: "
var age = 18;
console.log(str + age)
运行结果如下:
我们在使用字符串加法的时候, 一定要看清相加的数据是否存在字符串, 例如:
console.log(100 + 100)
console.log('100' + 100)
console.log(100 + '100')
输出结果为:
可以发现, 和数字类型拼接的时候, 如果字符串存在, 那么最后的类型就会被直接拼接为一个字符串.
String和boolean类型的的拼接:
var boo = false;
var str = "this is "
console.log(str + boo)
如果一个数据命名了但是没有定义 此时拿来和字符串拼接:
var name;
var sentence = "my name is :" + name;
console.log(name)
console.log(sentence + name);
结果确实null? 这是为什么呢? 原因是, undefined派生自null, 可以通过相等和全等来判断. 例如:
console.log(undefined == null) // true;
console.log(undefined === null) // false;
结果如下:
3. null
null表示当前变量是一个空值, 例如:
var x = null;
console.log(x); // null值直接输出
console.log(x + 1); // 空值 + 1 然后输出
console.log(x + "1"); // 空值和字符串拼接
可以看到通过控制台直接输出null值, 会显示null, 如果空值 + 1 的话, 会直接显示1, 也就是null被当做了0, null值和字符串会直接进行拼接.
4.boolean
布尔逻辑只能有两个值, true或者false,
var x = true; var y = false;
布尔常用在条件测试中.
JS数组
下面是JS中数组的创建和使用相关:
var names= new Array(); names[0] = "ZhangSan"; names[1] = "LiSi"; names[2] = "WangWu"; // 或者 var names = new Array( "ZhangSan", "LiSi", "WangWu"); // 或者 var names = [ "ZhangSan", "LiSi", "WangWu"];
数组下表是基于0的, 所以第一个项目是0, 第二个下表是1, 以此类推.
对于new Array(); 其中A必须大写, 当然除了放一样的元素, 也可以存放不同的数据类型
访问数组的长度, 使用点号"."访问数组的length属性.
var arr = [1, 2, "ZhangSan"] // 也可以使用var arr = new Array(); // 当然也可以对数组增加内容, 使用push函数 arr.push(3) arr.push("LiSi") // for循环遍历数组 for(var i = 0; i < arr.length; i++) { console.log(arr[i]) }
对于数组的遍历, 还有下面这个方法. 也就是我们Java中常用的for-each增强for循环
for(var x of arr) { console.log( x ); }
效果是一样的(都是默认从0下标开始遍历)
但是如果访问元素超过了数组的限定下标, 例如现在一个数组arr里面存在4个元素, 如果你使用如下语句:
console.log(arr[-1]); // 或者 console.log(arr[4]); // 数组下标越界而产生错误 这两者产生的结果为undefined
修改数组元素, 直接使用下标访问然后修改即可:
var arr = new Array(); arr.push(1) arr.push(2) arr.push(3) arr[2] = 4
那么如何删除元素呢? 是否可以将数组的某个下标的值设置为null?
var arr = new Array(); arr.push(1) arr.push(2) arr.push(3) arr[0] = null for(var x of arr) { console.log( x ); }
可以看到并没有删除下标为0的元素, 只是简单的将这个下标为0的元素置为了null
对于删除, 我们可以使用arr的splice(var i, var len);
从下标为i 的元素开始, 往后删除len个元素, 如果删除的元素已经超过了数组的尾元素, 则会照常删除, 不会发生异常;
var arr = new Array(); arr.push(1) arr.push(2) arr.push(3) arr.splice(1,2) for(var x of arr) { console.log( x ); }
数组的截取slice(var i, var j), 截取的下标范围为: [ i , j ).
例如:
var arr = new Array(); arr.push(1) arr.push(2) arr.push(3) var ret = arr.slice(0,2) // 截取1和2 for(var x of ret) { console.log( x ); }
此外, 删除还可以使用数组的pop()方法, pop方法删除数组末尾元素:
var arr = new Array(); arr.push(1) arr.push(2) arr.push(3) arr.pop() // 删除数组[1,2,3]末尾的数字类型:3 for(var x of arr ) { console.log( x ); }
既然可以删除队尾元素, 也可以删除队首元素, 可以使用shift()方法来删除一个数组的队首元素
var arr = new Array(); arr.push(1) arr.push(2) arr.push(3) arr.shift() // 删除数组[1,2,3]末尾的数字类型:3 for(var x of arr ) { console.log( x ); }
运算符
算术运算符
- +
- -
- *
- /
- %
赋值运算符 & 复合赋值运算符
- =
- +=
- -=
- *=
- /=
- %=
自增自减运算符
- ++
- --
比较运算符
- <
- >
- <=
- >=
- == : 比较全等, 会进行隐式类型转化
- !=
- ===
- !== :: 比较相等, 不会进行隐式类型转化
例如我们所说的undefined是派生自null的, 如果直接使用==进行比较null和undefined:
var x = null; var y = undefined; console.log(x == y)
结果输出 true, 这是因为undefined会隐式转换为null.
再比如:
如果比较1和字符1两者, 使用== 和===分别进行比较并在控制台输出: console.log(1 == "1") // true console.log(1 === "1") // false
结果如下:
因为1会隐式转换为"1", 但是下面的===不会
逻辑运算符 & 位运算符 % 移位运算
- && 与
- || 或
- ! 非
- & 按位与
- | 按位或
- ~ 按位取反
- ^ 按位异或
- << 左移
- >> 有符号右移
- >>> 无符号右移
条件语句
类似于java中的条件语句, 条件表达式为true则执行{}中的代码块:
// 形式1 if (条件) { // code here } // 形式2 if (条件) { // code here } else { // code here } // 形式3 if (条件1) { // code here } else if (条件2) { // code } else if (条件....) { // code } else { // code }
代码练习:
输入一个数字, 判断这个数字是奇数还是偶数:
<body> <script> var num = prompt("请输入一个数字:->") if (num % 2 == 0) { alert("您输入的数字" + num + "是一个偶数") } else { alert("您输入的数字" + num + "是一个奇数") } </script> </body>
输入2:
输出:
三元表达式
三元表达式, 也称为三目运算符, 他是一种if - else 语句的简化写法:
条件 ? 表达式1 : 表达式2
如果条件为真, 返回表达式1的结果, 如果为假, 返回表达式2 的结果.
注意, 三元表达式的优先级是比较低的
switch-case语句
多分支语句, 和java语言里面的switch- case语句类似.
switch (value) { case value1: 语句1; break; case value2: 语句2; break; case value3: 语句3; break; ....... default: 语句N; }
例如. 用户输入一个数字, alert提示今天是星期几:
var day = prompt ( " 请输入今天星期几 : " ); switch ( parseInt ( day )) { case 1 : alert ( " 星期一 " ); break ; case 2 : alert ( " 星期二 " ); break ; case 3 : alert ( " 星期三 " ); break ; case 4 : alert ( " 星期四 " ); break ; case 5 : alert ( " 星期五 " ); break ; case 6 : alert ( " 星期六 " ); break ; case 7 : alert ( " 星期日 " ); break ; default : alert ( " 输入有误 " ); }
这里为什么使用了一个我们没有见过的函数parseInt(Stringx)?
类似于java, parseInt的作用是将一个字符串转化为对应的数字类型.
通过下面这个例子:
输入6:
输出:
发现结果是一个字符串类型
但是我们的case里面是数字类型, 这也就会造成不匹配, 直接跳转到default的情况, 所以此处需要使用parseInt来将其转化为对应的数字类型
循环语句
同java一样, JS也存在着while循环, 格式如下:
while (条件) { // code }
例如: 在控制台打印1 ~ 10:
var num = 1; while (num <= 10) { console.log(num); num ++; }
同Java语言一样, JS中的循环语句同样可以使用continue结束当前循环直接进入下一次循环,
例如上面的例子, 我们遇到5就跳过不打印:
var num = 1; while (num <= 10) { if(num == 5) { continue; } console.log(num); num ++; }
当然也存在着break语句, 将打断循环,
JS也存在着for循环, 其结构如下:
for (表达式1 ; 表达式2 ; 表达式3) { 循环体 }
其中:
- 表达式1用来初始化循环变量
- 表达式2 是循环的条件
- 表达式3更新循环变量
例如, 使用for循环打印1 ~ 5
for (var i = 1; i <= 5; i++) { console.log(num) }
运行结果如下:
当然如果你希望你的代码至少循环一次, 你也可以使用do-while循环:
函数
JS中也存在着函数, 也就是所谓的创建函数, 函数声明, 和其函数定义, 例如
创建函数
// 函数创建与声明和定义 function 函数名( 形参列表 ) { 函数体 // 如果有必要的话可以加上return语句; // return 返回值; } // 调用函数 函数名(参数列表) // 如果考虑返回值, 可以使用一个参数接收返回值 var ret = 函数名(参数列表)
注意: 函数在定义的时候并不会执行函数体和return部分, 只有显式地调用才会执行函数体, 调用几次函数就会执行几次函数体. 和定义变量不同的是, 定义变量是需要先定义变量, 然后才能使用的, 但是函数的定义和使用之间没有明确的顺序的
例如我们现在定义一个函数hello() 参数体为空, 此时调用hello的时候, 会在控制台输出hello:
function hello() { console.log("hello"); } hello(); // hello()也可以在定义function hello()之前 hello(); function hello() { console.log("hello"); }
关于函数参数
有参数的函数, 可以传入参数, 并使用这些参数做出对应的行为:
function 函数名(parameter1, parameter2 ....) { 函数体 // 有必要时使用return语句 }
例如: 假设我们输入一个字符串, 然后我们在控制台输出这个字符串.
function input(x) { console.log(x); } var ret = prompt("请输入一个内容:->"); input(ret);
输出如下:
关于参数的个数, 实参和形参之间的个数可以不匹配, 但是实际开发, 一般要求形参和实参个数要匹配:
- 如果实参比形参的个数多, 那么多出来的形参不参与函数运算
- 如果实参个数比形参个数少, 则此时多出来的形参值为undefined
举例说明:
// 定义一个函数, 具有一个形参
arguments
arguments用于函数体中, 用来接收函数中的形参, 我们说, 在JS中, 可以存在形参数量和实参数量不匹配的情况, 甚至出现, 没有形参, 但是传入了很多实参的情况, 这个时候 就可以使用arguments来接收这些传入的实参.
例如定义一个函数:
function func1() { var sum = 0; for(let i = 0; i < arguments.length; i++) { sum +=arguments[i]; } return sum; } console.log(func1(1,2,3,4));
arguments接收完全部参数之后, 将其放在一个数组里面, arguments本质上就是一个存放着这些参数数据的数组, 我们可以通过下标来解引用. 如上arguments[0]
函数表达式
此处有另外一种定义函数的方法, 叫做匿名函数, 也就是如下的形式:
var ret = function(1,2,"hello") { let sum = 0; for(let i = 0; i < arguments.length; i++) { sum +=arguments[i]; } return sum; } // 此处的ret作为函数名使用: console.log(ret(1,2,3)); console.log(ret(10, 20));
此时形如function() {函数体} 的写法就是定义了一个匿名函数, 然后这个匿名函数用一个变量来表示, 后面就可以通过这个变量ret来调用函数了.
作用域
作用域也就是说某个变量或者签名在代码中的有效范围
例如我们有如下例子:
// 全局变量 var num = 10 ; console . log ( num ); function test () { // 局部变量 var num = 20 ; console . log ( num ); } function test2 () { // 局部变量 var num = 30 ; console . log ( num ); } test (); test2 (); console . log ( num ); // 执行结果 10 20 30 10
首先我们定义了一个全局变量var num = 10, 然后在控制台输出num, 随后在方法体test中, 重新定义变量var num = 20, 此时调用test(), 结果输出为20.
其次定义了一个test2方法, 里面使用的是var num = 30, 调用test2()输出30, 随后再次在控制台输出num, 结果又变回了原来的10.
总结, 当方法的外部和方法的内部同时存在对同一个变量的赋值时候, 方法体内部的赋值并不会影响外部相同名的变量的值, 在方法体内使用这个变量名, 起作用的将会是方法体内的这个变量名. 但是对这个变量赋值不会影响外部同名变量
对象
概念
Java中, 我们有类和对象的概念, 类, 就是我们把身边的事务的抽象, 对象就是这个抽象的具体化实例. 对比于Java, JS中也存在着对象的概念. 在JS中, 字符串, 数字类型, 数组, 函数等都是对象. 每个对象都有很多属性和方法, 例如数组里面有length属性, 还有push()方法, 可以在数组末尾添加一个元素.
我们说JS中, 数组也可以保存数据, 例如:
var arr = ["蔡徐坤", 175, 170]
上面有一组数据, 里面有数据175和170, 对于填写这个数据的人来说, 或者一个真ikun来说, 他可能知道这个175是指的身高, 170指的是体重, 但是如果你让你一个不是ikun的人, 或者是不属于这个数据的设计者的人来说, 他无法分辨这个175到底是身高还是体重.
所以对象的重要性就不言而喻了.
使用字面量创建对象
创建一个空对象
var student = {}
创建一个对象, 并向这个对象中添加一些属性和方法
var sutdent = { name: '蔡徐坤', height:175, weight:170, sayHello: function() { console.log("hello world!"); } }
其中:
- 使用{} 来创建一个对象
- 属性, 方法使用键值对的形式来组织, 也就是, 变量名在左, 数据或者方法体在右, 中间使用冒号":"分割
- 键值对之间使用逗号","分割, 注意这里的逗号是英文逗号
- 方法是一个匿名函数体
- 对于方法的使用, 使用对象+.号(点号)的形式来访问对象的属性和方法
例如:
console.log(student.name); console.log(student.height); sutdent.sayHello(); // 同时还可以使用[]来访问属性, 例如 console.log(student['height']); // 此时的属性需要使用引号包围
使用new object()创建对象
var student = new object(); student.name = "蔡徐坤"; student.height = 175; student.weight = 170; // 也可以使用[]来创建属性 student['weight'] = 170 student.sayHello = function() { console.log("hello"); } console.log(student.name); console.log(student['weight']); student.sayHello();
如果使用{}来创建对象的话, 也可以使用student.属性名 = value的形式来增加属性
使用构造函数来创建对象
使用构造函数来创建对象, 可以很方便的对这个对象进行实例化. 如果一个对象具有很多个实例的话, 推荐使用构造函数来创建对象
function 对象名(para1, para2, para3 ....) { this.para1 = para1; this.para2 = para2; this.para3 = para3; ...... this.func = function() { // code here 方法体 } } // 实例化 var exm = new 对象名(para1, para2, para3 ....);
如何理解这样的new关键字? 首先new会在内存中创建一个空对象{}, 然后根据this指向刚才的空对象, 随后执行构造函数的代码, 给对象创建属性和方法. 返回构建完成的对象
JavaScript是一门很适合去学习的语言, 大家一定要好好学习这门语言