一、概念
javascript是一门客户端脚本语言。
* 运行在客户端浏览器中的。每一个浏览器都有JavaScript的解析引擎。
* 脚本语言:不需要编译,直接就可以被浏览器解析执行了。
浏览器执行JS简介:
浏览器分为两部分:渲染引擎和JS引擎
渲染引擎:用来解析HTML和CSS,俗称内核,比如chrome浏览器的blink,老版本的webkit。
JS引擎:也称为JS解释器,用来读取网页中的JavaScript代码,对其处理后运行,比如chome浏览器的V8。
浏览器本身并不会执行JS代码,而是通过内置 JavaScript 引擎(解释器) 来执行 JS 代码 。JS 引擎执行代码时逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以 JavaScript 语言归为脚本语言,会逐行解释执行。
解释型语言和编译型语言
计算机不能直接理解任何除机器语言以外的语言,所以必须要把程序员所写的程序语言翻译成机器语言才能执行程序。程序语言翻译成机器语言的工具,被称为翻译器。
-
-
编译器是在代码执行之前进行编译,生成中间代码文件;
-
执行过程
二、功能
* 可以来增强用户和html页面的交互过程,可以来控制html元素,让页面有一些动态的效果,增强用户的体验。
三、JavaScript发展史
1997年,ECMA(欧洲计算机制造商协会),制定出客户端脚本语言的标准:ECMAScript,就是统一了所有客户端脚本语言的编码方式。
ECMAScript:规定了JS的编程语法和基础核心知识。
* JavaScript = ECMAScript + JavaScript自己特有的东西(BOM+DOM)
JS的组成:
四、ECMAScript基本语法
1、JS 有3种书写位置
分别为行内、内嵌和外部。
1)、行内式
<input type="button" value="点我试试" onclick="alert('Hello World')" />
-
-
注意单双引号的使用:在HTML中我们推荐使用双引号, JS 中我们推荐使用单引号。
-
可读性差, 在html中编写JS大量代码时,不方便阅读;
-
引号易错,引号多层嵌套匹配时,非常容易弄混;
-
2)、内嵌式
<script> alert('Hello World~!'); </script>
3)、外部JS文件
<script src="my.js"></script>
-
-
引用外部 JS文件的 script 标签中间不可以写代码;
-
说明 | 归属 | |
---|---|---|
alert(msg) | 浏览器弹出警示框 | 浏览器 |
console.log(msg) | 浏览器控制台打印输出信息 | 浏览器 |
prompt(info) | 浏览器弹出输入框,用户可以输入 |
<script> /*alert('我是编程语言,来控制电脑网页弹出你好'); alert('我是编程语言,来控制电脑网页弹出你好');*/ prompt("请输入你的年龄!") </script>
效果如下:
3、与html结合方式
1)、内部JS:
* 定义<script>,标签体内容就是js代码。
2)、外部JS:
* 定义<script>,通过src属性引入外部的js文件。如下所示:
<script type="text/javascript" src="${ctx}/static/js/plugins/layui/layui.all.js"></script>
* 注意:
1)、<script>可以定义在html页面的任何地方。但是定义的位置会影响执行顺序。
2)、<script>可以定义多个。
4、注释
1)、单行注释://注释内容,快捷键 ctrl + /
2)、多行注释:/*注释内容*/,快捷键修改为: ctrl + shift + /
5、数据类型
JS 把数据类型分为两类:
1)、原始数据类型(基本数据类型):
• number:数字。 整数/小数/NaN(not a number 一个不是数字的数字类型);
• string:字符串。 字符串 "abc" "a" 'abc'。注意:JS中字符串都带引号;
• boolean: true和false,等价于1和0;
• null:一个对象为空的占位符;
• undefined:未定义。如果一个变量没有给初始化值,则会被默认赋值为undefined。
数字型
数字型范围:JavaScript中数值的最大和最小值
数字型三个特殊值:
-
-
-Infinity ,代表无穷小,小于任何数值
-
isNaN:用来判断一个变量是否为非数字的类型,返回 true 或者 false
var usrAge = 21; var isOk = isNaN(userAge); console.log(isNum); // false ,21 不是一个非数字 var usrName = "andy"; console.log(isNaN(userName));// true ,"andy"是一个非数字
字符串型 String
因为 HTML 标签里面的属性使用的是双引号,JS 这里我们更推荐使用单引号。
字符串引号嵌套:
JS 可以用单引号嵌套双引号 ,或者用双引号嵌套单引号 (外双内单,外单内双)
var strMsg = '我是"高帅富"程序猿'; // 可以用''包含"" var strMsg2 = "我是'高帅富'程序猿"; // 也可以用"" 包含''
字符串转义符:
转义符都是 \ 开头的,常用的转义符及其说明如下:
解释说明 | |
---|---|
\n | 换行符,n 是 newline 的意思 |
\ \ | 斜杠 \ |
' | ' 单引号 |
" | ”双引号 |
\t | tab 缩进 |
\b |
length 属性可以获取整个字符串的长度:
var strMsg = "我是帅气多金的程序猿!"; alert(strMsg.length); // 显示 11
字符串拼接:
多个字符串之间可以使用 + 进行拼接,其拼接方式为 字符串 + 任何类型 = 拼接之后的新字符串。
拼接前会把与字符串相加的任何类型转成字符串,再拼接成一个新的字符串。
console.log(true + 1); // 2 console.log(false + 1); // 1
Undefined
一个声明后没有被赋值的变量会有一个默认值undefined ( 如果进行相连或者相加时,注意结果)
var variable; console.log(variable); // undefined console.log('你好' + variable); // 你好undefined console.log(11 + variable); // NaN console.log(true + variable); // NaN
一个声明变量给 null 值,里面存的值为空
var vari = null; console.log('你好' + vari); // 你好null console.log(11 + vari); // 11 console.log(true + vari); // 1
2)、引用数据类型:对象
6、变量
变量:一小块存储数据的内存空间。
1)、声明变量:
// 声明变量 var age; // 声明一个 名称为age 的变量 ,但是没有赋值,此时age = undefined
var age = 10; // 这是一个数字型 var areYouOk = '是的'; // 这是一个字符串
var x = 6; // x 为数字 var x = "Bill"; // x 为字符串
var age = 10, name = 'zs', sex = 2;
声明变量特殊情况:
说明 | 结果 | |
---|---|---|
var age ; console.log (age); | 只声明 不赋值 | undefined |
console.log(age) | 不声明 不赋值 直接使用 | 报错 |
age = 10; console.log (age); | 不声明 只赋值 |
2)、赋值:
age = 10; // 给 age 这个变量赋值为 10
3)、变量的初始化:
语法:var 变量名 = 初始化值;
var age = 18; // 声明变量同时赋值为 18 // 声明一个变量并赋值, 我们称之为变量的初始化。
4)、变量命名规范:
-
-
严格区分大小写。var app; 和 var App; 是两个变量
-
不能以数字开头。 18age 是错误的
-
不能是关键字、保留字。例如:var、for、while
-
变量名必须有意义。 MMD BBD nl → age
-
Java语言是强类型语言,而JavaScript是弱类型语言。
强类型:在开辟变量存储空间时,定义了空间将来存储的数据的数据类型。只能存储固定类型的数据
弱类型:在开辟变量存储空间时,不定义空间将来的存储数据类型,可以存放任意类型的数据。
5)、获取变量的数据类型
var num = 18; console.log(typeof num) // 结果 number
不同类型的返回值
注:null运算后得到的是object。
7、运算符
1)、一元运算符:只有一个运算数的运算符
(1)、++ --: 自增(自减)
++(--) 在前,先自增(自减),再运算
var num = 10; alert(++num + 10); // 21
++(--) 在后,先运算,再自增(自减)
var num = 10; alert(10 + num++); // 20
(2)、+(-):正负号
注意:在JS中,如果运算数不是运算符所要求的类型,那么js引擎会自动的将运算数进行类型转换
其他类型转number:Number()
string转number:按照字面值转换。如果字面值不是数字,则转为NaN(不是数字的数字)。
boolean转number:true转为1,false转为0。
2)、算数运算符:+ - * / %
3)、赋值运算符:= += -=
4)、比较运算符:> < >= <= == ===(全等于)
console.log(18 == '18'); // true console.log(18 === '18'); // false
比较方式:
(1)、类型相同:直接比较
字符串:按照字典顺序比较。按位逐一比较,直到得出大小为止。
(2)、类型不同:先进行类型转换,再比较
===:全等于。在比较之前,先判断类型,如果类型不一样,则直接返回false。
5)、逻辑运算符:&& || !
短路运算(逻辑中断)
短路运算的原理:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值;
逻辑与:
语法: 表达式1 && 表达式2
- 如果第一个表达式的值为真,则返回表达式2
- 如果第一个表达式的值为假,则返回表达式1
例子
console.log( 123 && 456 ); // 456 console.log( 0 && 456 ); // 0 console.log( 123 && 456&& 789 ); // 789
逻辑或:
语法: 表达式1 || 表达式2
- 如果第一个表达式的值为真,则返回表达式1
- 如果第一个表达式的值为假,则返回表达式2
例子:
console.log( 123 || 456 ); // 123 console.log( 0 || 456 ); // 456 console.log( 123 || 456 || 789 ); // 123
其他类型转boolean:
(1)、number:0或NaN为假,其他为真。
(2)、 string:除了空字符串(""),其他都是true。
(3)、null&undefined:都是false。
(4)、对象:所有对象都为true。
6)、三元运算符 ? : 表达式
语法:
* 表达式? 值1:值2;
* 判断表达式的值,如果是true则取值1,如果是false则取值2;
例子:
var a = 3; var b = 4; var c = a > b ? 1:0;
(7)、运算符优先级
8、流程控制语句
(1)、if...else...
// 条件成立 执行 if 里面代码,否则执行else 里面的代码 if (条件表达式) { // [如果] 条件成立执行的代码 } else { // [否则] 执行的代码 }
(2)、switch:
switch 语句也是多分支语句,它用于基于不同的条件来执行不同的代码。当要针对变量设置一系列的特定值的选项时,就可以使用 switch。
在java中,switch语句可以接受的数据类型: byte int shor char,枚举(1.5) ,String(1.7)
switch( 表达式 ){ case value1: // 表达式 等于 value1 时要执行的代码 break; case value2: // 表达式 等于 value2 时要执行的代码 break; default: // 表达式 不等于任何一个 value 时要执行的代码 }
执行case 里面的语句时,如果没有break,则继续执行下一个case里面的语句。
在JS中,switch语句可以接受任意的原始数据类型
(3)、while
while (条件表达式) { // 循环体代码 }
(4)、do...while
do { // 循环体代码 - 条件表达式为 true 时重复执行循环体代码 } while(条件表达式);
(5)、for
for(初始化变量; 条件表达式; 操作表达式 ){ //循环体 }
continue 关键字用于立即跳出本次循环,继续下一次循环,break 关键字用于立即跳出整个循环(循环结束)。
9、JS特殊语法
(1)、语句以;结尾,如果一行只有一条语句则 ;可以省略 (不建议)
(2)、变量的定义使用var关键字,也可以不使用
* 用: 定义的变量是局部变量
* 不用:定义的变量是全局变量(不建议)
10、数据类型转换
使用表单、prompt 获取过来的数据默认是字符串类型的,此时就不能直接简单的进行加法运算,而需要转换变量的数据类型。通俗来说,就是把一种数据类型的变量转换成另一种数据类型,通常会实现3种方式的转换:
1)、转换为字符串
2)、转换为数字型(重点)
3)、转换为布尔型
console.log(Boolean('')); // false console.log(Boolean(0)); // false console.log(Boolean(NaN)); // false console.log(Boolean(null)); // false console.log(Boolean(undefined)); // false console.log(Boolean('小白')); // true console.log(Boolean(12)); // true
11、标识符、关键字、保留字
标识(zhi)符:就是指开发人员为变量、属性、函数、参数取的名字。标识符不能是关键字或保留字。
关键字:是指 JS本身已经使用了的字,不能再用它们充当变量名、方法名。包括:break、case、catch、continue、default、delete、do、else、finally、for、function、if、in、instanceof、new、return、switch、this、throw、try、typeof、var、void、while、with 等。
保留字:实际上就是预留的“关键字”,意思是现在虽然还不是关键字,但是未来可能会成为关键字,同样不能使用它们当变量名或方法名。包括:boolean、byte、char、class、const、debugger、double、enum、export、extends、fimal、float、goto、implements、import、int、interface、long、mative、package、private、protected、public、short、static、super、synchronized、throws、transient、volatile 等。
注意:如果将保留字用作变量名或函数名,那么除非将来的浏览器实现了该保留字,否则很可能收不到任何错误消息。当浏览器将其实现后,该单词将被看做关键字,如此将出现关键字错误。
五、ECMAScript基本对象
1、Function:函数(方法)对象
1)、创建
第一种:
var fun = new Function(形式参数列表,方法体); //忘掉吧
第二种:自定义函数方式(命名函数)
function 方法名称(形式参数列表){
方法体
}
例子:
function showViewById(id, w, h) { layer_full(" ", ctx + menuUri + "/show?id=" + id, w, h); }
第三种:函数表达式方式(匿名函数)
var 方法名 = function(形式参数列表){ 方法体 }
-
-
这个fn 里面存储的是一个函数;
-
函数表达式方式原理跟声明变量方式是一致的;
-
2)、特点
(1)、方法定义是,形参的类型不用写,返回值类型也不写。
(2)、方法是一个对象,如果定义名称相同的方法,会覆盖。
(3)、在JS中,方法的调用只与方法的名称有关,和参数列表无关。
(4)、在方法声明中有一个隐藏的内置对象(数组),arguments,封装所有的实际参数。
3)、调用
方法名称(实际参数列表);
// 带参数的函数声明 function 函数名(形参1, 形参2 , 形参3...) { // 可以定义任意多的参数,用逗号分隔 // 函数体 } // 带参数的函数调用 函数名(实参1, 实参2, 实参3...);
注意:在JavaScript中,形参的默认值是undefined。
2、内置对象Array:数组对象
1)、创建
创建空数组
var arr = new Array();
如果需要使用构造函数Array创建非空数组,可以在创建数组时传入参数
(1)、var arr = new Array(元素列表);
(2)、var arr = new Array(默认长度);
(3)、var arr = [元素列表];
var arr = [1,"test",true];
2)、方法
join(参数):将数组中的元素按照指定的分隔符拼接为字符串。
push() 向数组的末尾添加一个或更多元素,并返回新的长度。
3)、属性
length:数组的长度,使用“数组名.length”可以访问数组元素的数量(数组长度)。
4)、特点
(1)、JS中,数组元素的类型可变的。
数组元素的类型:
数组中可以存放任意类型的数据,例如字符串,数字,布尔值等。
var arrStus = ['小白',12,true,28.9];
(2)、JS中,数组长度可变的。
数组的length属性可以被修改:
数组[ 数组.length ] = 新数据;
6)、检测是否为数组
方法一:instanceof 运算符:
instanceof 可以判断一个对象是否是某个构造函数的实例
var arr = [1, 23]; var obj = {}; console.log(arr instanceof Array); // true console.log(obj instanceof Array); // false
方法二:Array.isArray()
Array.isArray()用于判断一个对象是否为数组,isArray() 是 HTML5 中提供的方法
var arr = [1, 23]; var obj = {}; console.log(Array.isArray(arr)); // true console.log(Array.isArray(obj)); // false
7)、添加删除数组元素的方法
数组中有进行增加、删除元素的方法,部分方法如下表
注意:push、unshift为增加元素方法;pop、shift为删除元素的方法
8)、数组排序
数组中有对数组本身排序的方法,部分方法如下表
注意:sort方法需要传入参数来设置升序、降序排序
数组中有获取数组指定元素索引值的方法,部分方法如下表
10)、数组转成字符串
数组中有把数组转化为字符串的方法,部分方法如下表
注意:join方法如果不传入参数,则按照 “ , ”拼接元素。
11)、其他方法
数组中还有其他操作方法
3、Boolean
4、内置对象Date:日期对象
Date 对象和 Math 对象不一样,Date是一个构造函数,所以使用时需要实例化后才能使用其中具体方法和属性。Date 实例用来处理日期和时间。
1)、创建,获取当前时间
var date = new Date();
获取指定时间的日期对象
var future = new Date('2019/5/1');
注意:如果创建实例时并未传入参数,则得到的日期对象是当前时间对应的日期对象。
2)、方法
toLocaleString():返回当前date对象对应的时间本地字符串格式。
getTime():获取毫秒值。返回当前如期对象描述的时间到1970年1月1日零点的毫秒值差。
通过Date实例获取总毫秒数
// 实例化Date对象 var now = new Date(); // 1. 用于获取对象的原始值 console.log(date.valueOf()) console.log(date.getTime()) // 2. 简单写可以这么做 var now = + new Date(); // 3. HTML5中提供的方法,有兼容性问题 var now = Date.now();
5、内置对象Math:数学对象
Math 对象不是构造函数,它具有数学常数和函数的属性和方法。跟数学相关的运算(求绝对值,取整、最大值等)可以使用 Math 中的成员。
1)、创建
特点:Math对象不用创建,直接使用。 Math.方法名();
2)、方法
random():返回 0 ~ 1 之间的随机数。 含0不含1
ceil(x):对数进行上舍入。
floor(x):对数进行下舍入。
round(x):把数四舍五入为最接近的整数。
功能 | |
---|---|
Math.PI | 圆周率 |
Math.floor() | 向下取整 |
Math.ceil() | 向上取整 |
Math.round() | 四舍五入版 就近取整 注意 -3.5 结果是 -3 |
Math.abs() | 绝对值 |
Math.max()/Math.min() | 求最大和最小值 |
Math.random() |
注意:上面的方法使用时必须带括号。
6、Number
7、内置对象String
为了方便操作基本数据类型,JavaScript 还提供了三个特殊的引用类型:String、Number和 Boolean。
基本包装类型就是把简单数据类型包装成为复杂数据类型,这样基本数据类型就有了属性和方法。
// 下面代码有什么问题? var str = 'andy'; console.log(str.length);
按道理基本数据类型是没有属性和方法的,而对象才有属性和方法,但上面代码却可以执行,这是因为js 会把基本数据类型包装为复杂数据类型,其执行过程如下 :
// 1. 生成临时变量,把简单类型包装为复杂数据类型 var temp = new String('andy'); // 2. 赋值给我们声明的字符变量 str = temp; // 3. 销毁临时变量 temp = null;
1)、字符串不可变
指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中新开辟了一个内存空间。
当重新给字符串变量赋值的时候,变量之前保存的字符串不会被修改,依然在内存中重新给字符串赋值,会重新在内存中开辟空间,这个特点就是字符串的不可变。
2)、根据字符返回位置
案例:查找字符串"abcoefoxyozzopp"中所有o出现的位置以及次数
先查找第一个o出现的位置,因为indexOf 只能查找到第一个,所以后面的查找,利用第二个参数,当前索引加1,从而继续查找。
在上述方法中,charCodeAt方法返回的是指定位置上字符对应的ASCII码
4)、字符串操作方法
字符串通过基本包装类型可以调用部分方法来操作字符串,以下是部分操作方法:
5)、replace方法
replace() 方法用于在字符串中用一些字符替换另一些字符,其使用格式如下:
字符串.replace(被替换的字符串, 要替换为的字符串);
6)、split方法
split()方法用于切分字符串,它可以将字符串切分为数组。在切分完毕之后,返回的是一个新数组。
字符串.split("分割字符")
8、RegExp:正则表达式对象
1)、正则表达式:定义字符串的组成规则
(1)、单个字符:[]
如: [a] [ab] [a-zA-Z0-9_]
特殊符号代表特殊含义的单个字符:
\d:单个数字字符 [0-9]
\w:单个单词字符[a-zA-Z0-9_]
(2)、量词符号
?:表示出现0次或1次
*:表示出现0次或多次
+:出现1次或多次
{m,n}:表示 m<= 数量 <= n
* m如果缺省: {0,n}:最多n次
* n如果缺省:{m,} 最少m次
(3)、开始结束符号
^:开始
$:结束
2)、正则对象
(1)、创建
var reg = new RegExp("正则表达式");
或
var reg = /^正则表达式$/;
(2)、方法
test(参数):验证指定的字符串是否符合正则定义的规范。
9、Global
1)、特点
全局对象,这个Global中封装的方法不需要对象就可以直接调用。 方法名();
2)、方法
encodeURI():url编码
decodeURI():url解码
encodeURIComponent():url编码,编码的字符更多
decodeURIComponent():url解码
parseInt():将字符串转为数字。逐一判断每一个字符是否是数字,直到不是数字为止,将前边数字部分转为number
isNaN():判断一个值是否是NaN。NaN六亲不认,连自己都不认。NaN参与的==比较全部问false。
eval():讲 JavaScript 字符串,并把它作为脚本代码来执行。
3)、URL编码
六、预解析
JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行。
预解析会把变量和函数的声明在代码执行之前执行完成。
1、变量预解析
预解析也叫做变量、函数提升。
变量提升(变量预解析): 变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升。
console.log(num); // 结果是多少? var num = 10; // ?
结果:undefined
注意:**变量提升只提升声明,不提升赋值**
2、函数预解析
函数提升: 函数的声明会被提升到当前作用域的最上面,但是不会调用函数。
fn(); function fn() { console.log('打印'); }
结果:控制台打印字符串 --- ”打印“
注意:函数声明代表函数整体,所以函数提升后,函数名代表整个函数,但是函数并没有被调用!
3、函数表达式声明函数问题
函数表达式创建函数,会执行变量提升,此时接收函数的变量名无法正确的调用:
fn(); var fn = function() { console.log('想不到吧'); }
结果:报错提示 ”fn is not a function"
解释:该段代码执行之前,会做变量声明提升,fn在提升之后的值是undefined;而fn调用是在fn被赋值为函数体之前,此时fn的值是undefined,所以无法正确调用
七、简单数据类型和复杂数据类型
1)、堆栈空间分配区别
栈:由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;
堆:存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。
复杂数据类型的存储方式:引用类型变量(栈空间)里存放的是地址,真正的对象实例存放在堆空间中。
2)、简单类型传参
函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到的外部变量。
function fn(a) { a++; console.log(a); } var x = 10; fn(x); console.log(x);
结果为:11和10
3)、
函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。
function Person(name) { this.name = name; } function f1(x) { // x = p console.log(x.name); // 2. 这个输出什么 ? x.name = "张学友"; console.log(x.name); // 3. 这个输出什么 ? } var p = new Person("刘德华"); console.log(p.name); // 1. 这个输出什么 ? f1(p); console.log(p.name); // 4. 这个输出什么 ?
结果:刘德华 刘德华 张学友 张学友