什么是JavaScript?它跟Java有什么关系?
答:JavaScript是一门编程语言,它跟Java之间的关系不大。就像“雷锋”和"雷锋塔",“周杰”和"周杰伦"他们之间关系并不大。
- JavaScript诞生于1995年,它的出现主要用于处理网页中的前端验证。
- 所谓的前端认证,就是指检查用户输入的内容是否符合一定的规则。
- 但是到今天JavaScript已经不仅仅用来处理前端验证了,网页中所有的动态效果都离不开JavaScript
- JavaScript 是由网景公司发明,起初命名为LiveScript,后来由于SUN公司的介入更名为了JavaScript。
- 1996 年微软在其最新的IE3浏览器中引入了自己对JavaScript的实现JScript。
- 于是市面上就存在了两个版本的JavaScript,一个网景公司的JavaScript和微软的JScript。
- 为了确保不同的浏览器上运行的JavaScript标准一致,所以几个公司共同定制了JS的标准命名为ECMAScript。
- ECMAScript 是一个标准,而这个标准需要由各个厂商去实现。例如:就比如说我现在规定“世界上所有的杯子高度都是20厘米”那么我说的这个就是一个标准。至于如何实现肯定由各个杯子的制造商来决定。
- 不同浏览器厂商对该标准会有不同的实现。
- 我们已经知道ECMAScript 是 JavaScript 标准,所以一般情况下这两个词我们认为是一个意思。
- 概括的说就是 ECMAScript 是标准,JavaScript 是实现。
- 一个完整的JavaScript 实现应该由以下三个部分构成:
- ECMAScript
- DOM
- BOM
HelloWorld程序
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript">
alert("helloWorld"); //弹框
//向body中输出一个内容
document.write("hello,你真帅");
//向控制台输出一个内容
console.log("你猜我出现在哪里");
</script>
</head>
<body>
</body>
</html>
JS代码编写位置
- 方式一:可以把js写在标签的属性中,但是这样结构和行为耦合,不方便维护,不推荐使用
- 方式二:就是将js代码编写到script标签中
- 方式三:可以将js代码编写到外部js文件中,然后通过script标签引入。写到外部文件中可以在不同的页面中同时引用,也可以利用到浏览器的缓存机制。这是我们推荐使用的方式。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!--
方式三:可以将js代码编写到外部js文件中,然后通过script标签引入
-->
<script type="text/javascript" src="js/script.js">
alert("无效代码") //这个script已经用于引用外部文件了,再写内部代码,内部代码也不会起作用
</script>
<script type="text/javascript">
//方式二:就是将js代码编写到script标签中
alert("hello");
</script>
</head>
<body>
<!--可以将js代码编写到标签的onclick属性中,当我们点击按钮时,js代码才会执行-->
<button onclick="alert('弹出咯')"></button>
<!--可以将js代码写在超链接的href属性中,这样当点击超链接时,会执行js代码-->
<a href="javascript:alert('点我吧')">点我一下</a> <!--格式就是要在js代码前面写上javascript: -->
<a href="javascript:;">超链接点上去后没有反应</a> <!--这种写法我们也会经常遇到 -->
<!--
方式一:
虽然可以把js写在标签的属性中,但是这样结构和行为耦合,不方便维护,不推荐使用
-->
</body>
</html>
注意:script标签一旦用于引用外部文件了,就不能在里面编写代码了,即使编写了浏览器也会忽略,如果需要可以再创建一个script标签用于编写内部代码
JS基本语法
- JS中严格区分大小写 。
- JS中每一条语句都以分号结尾。如果你不写分号,浏览器会自动帮你添加,但是会消耗一些系统资源,而且有时候浏览器会加错分号,所以在开发中分号必须写。
- JS中会忽略多个空格和换行,所以我们可以利用空格和换行对代码进行格式化。
字面量和变量
字面量:都是一些不可改变的值。比如 1 2 3 4 5 字面量都是可以直接使用,但是我们一般都不会直接使用字面量
变量:变量可以用来保存字面量,而且变量的值是可以任意改变的,变量更加方便我们使用,所以在开发中都是通过变量去保存。一个字面量,而很少直接使用字面量。
标识符
- 在JS中所有的可以由我们自主命名的都可以称为是标识符。如:变量名、函数名、属性名都属于标识符
- 命名一个标识符时需要遵守如下的规则:
- 标识符中可以含有字母、数字、下划线、美元符
- 标识符不能以数字开头
- 标识符不能是JS中的关键字或保留字
- 标识符一般采用驼峰命令法
- JS底层保存标识符时实际上是采用的Unicode编码。所以理论上讲,所有的utf-8中含有的内容都可以作为标识符。(意思就是我变量名用中文也可以)
在JS中一共有六种数据类型
- String 字符串
- Number 数值
- Boolean 布尔值
- Null 空值
- Undefined 未定义
- Object 对象
其中String Number Boolean Null Undefined 属于基本数据类型,而Object 属于引用数据类型
字符串(String)
- 在JS中字符串需要使用引号引起来
- 使用双引号或单引号都可以
<script type="text/javascript">
/**
* 在字符串中我们可以使用\作为转义字符,当表示一些特殊符号时可以使用\进行转义
*/
var str = "我说:\"今天天气很不错\"";
console.log(str);
</script>
数值类型(Number)
- 在JS中所有的数值都是Number类型,包括整数和浮点数
- JS中可以表示的数字的最大值
- Number.MAX_VALUE 值为1.7976931348623157e+308
- 如果使用Number表示的数字超过了最大值,则会返回一个Infinity表示正无穷
- 使用typeof 检查Infinity也会返回Number
- Infinity 表示正无穷,-Infinity表示负无穷
- NaN 是一个特殊的数字,表示Not A Number
- 使用typeof检查一个 NaN 也会返回 number
- JS中大于0的最小值
- Number.MIN_VALUE 值为5e-324
<script type="text/javascript">
var a = 123;
var b = "123";
/**
* 可以使用一个运算符 typeof,来检查一个变量的类型
* 语法:typeof 变量
*/
console.log(a);
console.log(b);
console.log(typeof b); //打印string
console.log(Number.MAX_VALUE); //打印1.7976931348623157e+308
var c = Infinity; //Infinity本身就是一个字面量
console.log(c); //打印Infinity
console.log(typeof Infinity); //打印一个number
var d = "ab" * "bc";
console.log(d); //打印NaN
console.log(typeof d); //打印number
console.log(Number.MIN_VALUE) //打印5e-324
/**
* 在JS中整数的运算基本可以保证精确
*/
var e = 12345 + 23432;
console.log(d);
/**
* 在JS中对浮点数进行运算,可能得到一个不精确的结果
* 所以千万不要使用JS进行对精确度要求比较高的运算
*/
var f = 0.1 + 0.2; //打印0.30000000000000004 结果不精确
console.log(f);
</script>
布尔值(boolean)
- 布尔值只有两个,主要用来做逻辑判断
- true 表示真
- false 表示假
<script type="text/javascript">
var bool = true;
console.log(bool);
console.log(typeof bool); //打印boolean
</script>
Null 和 Undefined
- null 这个值专门用来表示一个为空的对象
- 使用typeof 检查一个null 值时,会返回一个Object
- 当声明一个变量,但并不给变量赋值时,它的值就是 undefined
- 使用typeof 检查一个 undefined 时也会返回 undefined
<script type="text/javascript">
var a = null;
console.log(a); //打印null
console.log(typeof a); //打印Object
var b;
console.log(b); //打印出undefined,表示这个变量声明了但是没有赋值
</script>
强制类型转换
- 指将一个数据类型强制转换为其他数据类型
- 类型转换主要指,将其他的数据类型转换为 String Number Boolean
其他数据类型转换为 String
- 方式一
- 调用被转换数据类型的toString() 方法,它会将转换结果返回
- 但是注意,null 和 undefined 这两个值没有 toString() 方法,调用就会报错
- 方式二
- 调用String() 函数,并将被转换的数据作为参数传递给函数
- 使用String()函数做强制类型转换时,对于Number 和 Boolean 实际上就是调用他们的toString()方法,但是对于null 和 undefined 就不会调用toString()方法,它会将 null 直接转换为 “null” 将 undefined 直接转换为 “undefined”
其他数据类型转换为 Number
- 方式一
- 使用Number()函数
- 字符串 ----> 数字
- 如果是纯数字的字符串,则直接将其转换为数字
- 如果字符串中有非数字的内容,则转换为NaN
- 如果字符串是一个空串或是是一个全是空格的字符串,则转换为0
- 布尔值 -----> 数字
- true 转成 1
- false 转成 0
- null ------> 数字
- 结果就是0
- undefined ------> 数字
- 结果就是NaN
- 方式二
- 这种方式专门用来对付字符串
- parseInt() 把一个字符串转换成一个整数
- parseFloat() 把一个字符串转换为一个浮点数
<script type="text/javascript">
var a = "123";
console.log(typeof a);
console.log(a);
//调用Number()函数来将a转换为Number类型
a = Number(a);
console.log(typeof a); //打印string
var b = "";
console.log(Number(b)); //空字符串转换成0
var c = true;
console.log(Number(c)) //true转成1,false转成0
var d = undefined;
console.log(Number(d)); //undefined 转成 NaN
/**
* parseInt()可以将一个字符串中的有效整数内容取出来,然后转换为Number
* 它是从左往右解析,遇到非数字就停止解析
*/
var e = "123abc";
console.log(parseInt(e)); //打印123
e = "12s3abc";
console.log(parseInt(e)); //打印12
/**
* parseFloat()作用和parseInt()类似,不同的是它可以获得有效的小数位
*/
var f = "123.11dd";
console.log(parseFloat(f)); //打印的是123.11
/**
* 注:
* 如果对非String 使用parseInt()或parseFloat()
* 它会先将其转换为String,然后再操作
*/
var h = true;
console.log(parseInt(h)); //打印的是NaN 相当与console.log(parseInt("true")) 这个打印的肯定是NaN
</script>
其他数据类型转换为 Boolean
- 使用Boolean函数
- 数字 ------> 布尔 除了 0 和 NaN,其余的都是 true
- 字符串 -------> 布尔 除了空串,其余的都是true
- null 和 undefined -------> 结果都为false
- 对象也会转换为true
<script type="text/javascript">
var a = 123; //打印true
a = -123; //打印true
a = Infinity; //打印true
a = "abc"; //打印true
a = 0; //打印false
a = null; //打印false
a = undefined; //打印false
a = NaN; //打印false
a = ""; //打印false
a = " "; //打印true
console.log(Boolean(a));
</script>
运算符
- 运算符也叫操作符,通过运算符可以对一个或多个值进行运算,并获取运算结果。
比如typeof就是运算符,可以来获得一个值的类型,他会将该值的类型以字符串的形式返回
算术运算符
当对非Number类型的值进行运算时,会将这些值转换为Number然后进行运算
任何值和NaN做运算都得NaN
任何值和字符串做加法操作,都会先转换为字符串,然后再和i字符串做拼接操作
我们可以利用这一特点,来将一个任意的数据类型转换为String ,只需要为任意的数据类型后面加上一个空串即可将其转换为String ,这是一种隐式的类型转换,由浏览器自动完成,实际上也是调用的String()函数
任何值做减法"-" 乘法 "*" 除法 "/" 运算时都会自动转换为Number
我们可以利用这一特点做隐式类型转换,可以通过为一个值减0乘1除1将其转换为Number 原理和Number()函数一样,只是使用起来会更加简单(了解下就行了)
<script type="text/javascript">
var num = 123;
var result = typeof num;
console.log(result); //打印number,这里是使用typeof来获取一个值的类型,会以字符串的形式返回这个类型
console.log(typeof result); //打印String
//算术运算符
var a = 234;
a = a + 1;
console.log(a); //打印235
a = true + 1;
console.log(a); //打印2 true转换为数字是1
a = false + 1;
console.log(a); //打印1 fasle转换为数字是0
a = null + 1;
console.log(a); //打印1 null 转换为数字是0
a = 1 + NaN;
console.log(a); //打印NaN 任何值和NaN做运算都得NaN
var c = 123;
c = c + ""; //本质上和 c = String(c)一样
console.log(typeof c); //打印String
//减法
var d = 100 - "1"; //这里会先把字符串1转换为number 1然后再做运算
console.log(d); //打印99
//乘法
var e = 2 * "3"; //这里会先把字符串3转换为number 3然后再做运算
console.log(e); //打印6
e = 2 * undefined; //这里会先把undefined转换为Number类型,结果是NaN然后再做运算
console.log(e); //打印NaN 因为我们说任何数和NaN做运算,结果都是NaN
//除法
var f = 4 / 2;
console.log(f); //打印2
</script>
一元运算符
一元运算符,只需要一个操作数
正号("+")
正号不会对数字产生任何影响
负号("-")
负号可以对数字进行负号的取反
对于非Number类型的值,它会先转换为Number,然后在运算
可以对一个其他的数据类型使用+,来将其转换为number,它的原理和Number()函数一样
<script type="text/javascript">
var a = "12";
a = +a;
console.log(a); //打印12
console.log(typeof a); //打印number
var result = 1 + + "2" + 3; //这里+"2"就把字符串2转换为了number 2
console.log(result); //打印结果是6
</script>
逻辑运算符
- JS中为我们提供了三种逻辑运算符
- ! 非
- 可以用来对一个值进行非运算
- 所谓非运算就是指对一个布尔值进行取反操作,true 变 false,false 变 true
- 如果对一个值进行两次取反,它不会变化
- 如果对非布尔值进行运算,则会先将其转换为布尔值,然后再取反
- 所以我们可以利用该特点,来将一个其他数据类型转换为布尔值,我们可以为一个任意数据类型取两次反,来将其转换为布尔值。原理和Bollean()函数类似
- && 与
- && 可以对符号两侧的值进行与运算并返回结果
- 运算规则:
- 两个值中只要有一个值为false 就返回 false ,只有两个值都为true时,才会返回true
- JS 中的 “与” 属于短路 “与”,如果第一个值为false 第二个值就不会再去看了
- || 或
- || 可以对符号两侧的值进行或运算并返回结果
- 运算规则:
- 两个值中只要有一个true,就返回true,如果两个值都为false 就返回false
- JS中的 "或" 属于短路 "或",如果第一个值为true 就不会去看第二个值了
<script type="text/javascript">
var a = true;
a = !a;
console.log(a); //打印false
var b = 10;
b = !!b //如果是一个非布尔值的元素就先把它转换为布尔值然后再做运算
console.log(b); //打印true
var c = "hello";
c = !!c; //把其他类型元素转换为Boolean(直接取两次反原值不变)
console.log(typeof c);
//只要有一个false,结果就是false
var d = true && false;
console.log(d);
var e = false || true; //只要有一个为true结果就是true
console.log(e);
</script>
非布尔值的与或运算
- 对于非布尔值进行运算时,会先将其转换为布尔值,然后再运算,并且返回原值
- 与运算(短路)
- 如果第一个值为true,则必然返回第二个值
- 如果第一个值为 false,则直接返回第一个值
- 或运算(短路)
- 如果第一个值为true,则直接返回第一个值
- 如果第一个值为false,则直接返回第二个值
<script type="text/javascript">
//相当于true && true 如果两个值都为true,则返回后面的
var result = 1 && 2; //会把这两个值都转换为boolean类型然后再做运算
console.log(result); //打印2
result = 2 && 1;
console.log(result); //打印1
//相当于false && true 如果有一个值为false,则返回false对应的值
result = 0 && 2;
console.log(result); //打印0
result = 2 && 0;
console.log(result); //打印0
//相当于false && false 如果两个值都为false,则返回靠前的
result = NaN && 0;
console.log(result); //打印NaN
result = 0 && NaN;
console.log(result); //打印0
//相当于 true || true
result = 2 || 1;
console.log(result); //打印2
result = "" || "hello"; //相当于false || true
console.log(result); //打印"hello"
</script>
关系运算符
- 非数值的情况
- 对于非数值进行比较时,会将其转换为数字然后在比较
- 如果符号两侧的值都是字符串时,不会将其转换为数字进行比较,而会分别比较字符串中字符的Unicode编码
<script type="text/javascript">
console.log(1 > true); //打印false,true转换成数字是1
console.log(1 >= true); //打印true
console.log(1 > "0"); //打印true,字符串"0"转换为数字就是0
console.log(10 > null); //打印true,null转换成数字就是0
//注意任何值和NaN做比较都是false
console.log(10 >= "hello"); //打印false,字符串"hello"转换成数字是NaN
console.log(true > false); //打印true, true转换为数字是1,false转换为数字是0
//比较两个字符串时,比较的是两个字符编码(ASCII码)
console.log("a" < "b"); //true
//比较字符编码是一位一位比较,如果两位一样,则比较下一位(如果第一位就比较出结果了,后面就不比了),所以借用它来对英文进行排序
console.log("abc" < "bcd"); //打印true
//如果比较的是两个字符串类型的数字,可能会得到不可预期的结果
console.log("1223213" > "2"); //打印false
//注意:在比较两个字符串类型的数字时,一定要记得强转
console.log("1223213" > +"2"); //打印true,这里把字符串2强转成了数字2
</script>
Unicode编码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Unicode编码</title>
<script type="text/javascript">
//下面是JS中的使用方法
//在字符串中使用转义字符输入Unicode编码:\u四位编码
console.log("\u2620"); //2620是一个骷髅图案的unicode编码
</script>
</head>
<body>
<!--
在网页中使用Unicode编码 ,方式:
&#编码; 这里的编码需要的是10进制
-->
<h1>☠</h1> <!--输出骷髅头图案 -->
</body>
</html>
相等运算符
- 相等运算符用来比较两个值是否相等,如果相等会返回true,否则返回fasle
- 使用 == 来做相等运算
- 当使用 == 来比较两个值时,如果值的类型不同,则会自动进行类型转换,将其转换为相同的类型然后再比较。
- 使用 != 来做不相等运算
- 不相等两个值是否不相等,如果不相等返回true,否则返回false
- 不相等也会对变量进行自动的类型转换,如果转换后相等它也会返回false
- 全等(===)
- 用来判断两个值是否全等,它和相等类似,不同的是它不会做自动类型转换。如果两个值的类型不同,直接返回false
- 不全等(!==)
- 用来判断两个值是否不全等,它和不等类似,不同的是它不会做自动类型转换。如果两个值的类型不同,直接返回true
<script type="text/javascript">
console.log(1 == 1); //打印true
console.log("1" == 1); //打印true
console.log(true == "1"); //打印true
console.log(null == 0); //这是个特例不会做自动类型转换,打印false
//undefined 衍生自null所以这两个值做相等判断时,会返回true
console.log(undefined == null); //打印true
//NaN不和任何值相等,包括他本身
console.log(NaN == undefined) //打印false
console.log(NaN == NaN); //打印false
var b = NaN;
//判断b的值是否是NaN
console.log(b == NaN); //很显然这种方式是行不同的
//可以通过isNaN()函数来判断一个值是否是NaN,如果该值是NaN则返回true,否则返回false
console.log(isNaN(b)); //打印true
//全等
console.log("123" === 123); //打印false 全等,类型不一样直接返回false
console.log(null === undefined)//打印false 上面我们用这两个判断相等是true,这里全等因为类型不一样直接返回false
//不全等
console.log("1" == 1) //打印true 类型转换后相等
console.log("1" !== 1) //打印true 不全等,类型不一样
</script>
运算符优先级
- 和数学中的一样,在JS中运算符也有优先级,比如先乘除,后加减
- 在JS中有一个运算符优先级的表,在表中越靠上优先级越高,优先级越高越优先计算。如果优先级一样,则从左往右计算。
- 这个运算符优先级的表我们并不需要记忆,如果遇到优先级不清楚,可以使用 () 来改变优先级
<script type="text/javascript">
/**
* 逗号运算符
* 使用逗号可以分割多个语句,一般可以在声明多个变量时使用
*/
var a,b,c; //可以使用逗号运算符同时声明多个变量
var a = 1,b = 2,c = 3; //可以同时声明多个变量并赋值
alert(a);
//运算符优先级
/**
* 如果||的优先级高,或者两个一样高(从左往右算),则应该返回3
* 如果&&的优先级高,则应该返回1
*/
var result = 1 || 2 && 3;
console.log(result); // 打印1, 所以说明&&的优先级比较高
//假设我现在不知道||和&&的优先级谁高,我们可以通过()来改变优先级
result = (1 || 2) && 3; //这里我想让1 和 2 先做运算
console.log(result); //打印3
</script>
代码块
- 我们的程序是由一条一条的语句构成的,语句是按照自上而下的属性一条一条的执行的
- 在JS中使用 {} 来为语句进行分组,同一个 {} 中的语句我们称为是一组语句,他们要么都执行,要么都不执行。一个 {} 中的语句我们也称为一个代码块。
- JS中的代码块,只具有分组的作用,没有其他的用途。代码块内部的内容,在外部是完全可见的
<script type="text/javascript">
{
var a = "hello";
console.log("你好")
}
//JS中的代码块,只具有分组的作用,没有其他用途,代码块中的内容在外部是完全可见的
console.log(a); //打印hello
</script>
条件判断语句
- 使用条件判断语句可以在执行某个语句之前进行判断。如果条件成立才会执行,条件不成立则语句不执行
<script type="text/javascript">
/**
* if语句
* 语法一:
* if (条件表达式){
* 语句...
* }
* if语句在执行时,会先对条件表达式进行求值判断,如果条件表达式的值为true,则执行if
* 后的语句,如果条件表达式的值为false,则不会执行if后的语句
* if语句只能控制紧随其后的那个语句,如果希望if语句可以控制多条语句
* 可以将这些语句统一放到大括号中,if语句后的大括号不是必须的,但是在开发中尽量写上
* 大括号,即使if后只有一条语句
*/
var a = 10;
if (a < 12){
console.log(a);
}
</script>
prompt()函数
- prompt()可以弹出一个提示框,该提示框中会带有一个文本框,用户可以在文本框中输入一段内容,该函数需要一个字符串作为参数,该字符串将作为提示框的提示文字。
- 用户输入的内容将作为函数的返回值返回,可以定义一个变量来接收该内容
- prompt()这个函数的返回值是 String 类型的
<script type="text/javascript">
var score = prompt("请输入一个数");
console.log(score); //控制台打印你输入的数
</script>
条件分支语句
- 条件分支语句也叫switch语句
- 执行流程
- switch...case....语句在执行时会依次将 case 后表达式的值和 switch 后的条件表达式的值进行全等比较,如果比较结果为 true ,则从当前 case 处开始执行代码,当前 case 后的所有代码都会执行,我们可以在 case 的后边跟着一个 break 这样就确保只会执行当前 case 后的语句而不会执行其它的case语句,如果比较结果为 fasle,则继续往下比较。如果所有的比较结果都为 false,则只执行 default 后的语句。
<script type="text/javascript">
/**
* 语法:
* switch(条件表达式){
* case 表达式:
* 语句...
* break;
* case 表达式:
* 语句...
* break;
* default:
* 语句...
* break;
* }
*/
var num = 1;
switch (num) {
case 1:
console.log("1");
break;
case 2:
console.log("2");
break;
default:
console.log("哈哈");
break;
}
//JS里面独有的一种使用switch方式,其他语言都不能像下面这么用
var score = 70;
switch (true) {
case score > 60:
console.log("及格");
break;
default:
console.log("不及格");
break;
}
</script>
for循环
- for 循环中,为我们提供了专门位置用来放三个表达式
- 初始化表达式
- 条件表达式
- 更新表达式
<script type="text/javascript">
/**
* for循环语法:
* for(①初始化表达式 ;②条件表达式; ④更新表达式) {
* ③语句...
* }
* for循环的执行流程:
* ①执行初始化表达式,初始化变量
* ②执行条件表达式,判断是否执行循环
* 如果为true,则执行循环③
* 如果为false,终止循环
* ④执行更新表达式,更新表达式执行完毕继续重复②
*/
for (var i = 0; i < 10; i++) {
alert(i);
}
//因为for循环初始化表达式只会执行一次,所以我在for循环括号里面去初始化多个变量也是可以的
for (var i = 0,sum = 0; i < 10; i++) {
alert(i);
}
/**
* for 循环中的三个部分都可以省略,也可以写在外部
* 如果for循环中不写任何表达式,只写两个分号,这个循环就是一个死循环
*/
for (;;) {
alert(i);
}
</script>
break关键字
<script type="text/javascript">
/**
* break关键字,会立即终止离他最近的那个循环语句
*/
for (var i = 0; i < 5; i++) {
console.log(i);
if (i == 2) {
break;
}
}
/**
* 可以为循环语句创建一个label,来标识当前的循环
* label:循环语句 (lable表示一个标识字段)
* 使用break语句时,可以在break后跟一个label,这样break将会结束指定的循环,而不是离它最近的循环
* continue使用同上
*/
hello:for (var i = 0; i < 5; i++) { //加了一个hello以后,表示我这个循环的名字叫hello
console.log("我是外层循环");
for (var j = 0; j < 5; i++) {
console.log("我是内层循环");
break hello; //在这里直接终止外层循环
}
}
</script>
计时器
- console.time("")可以用来开启一个计时器。它需要一个字符串作为参数,这个字符串将会作为计时器的标识
- console.timeEnd("") 用来停止计时器,需要一个计时器的名字作为参数
<script type="text/javascript">
/**
* console.time("")可以用来开启一个计时器
* 它需要一个字符串作为参数,这个字符串将会作为计时器的标识
*/
console.time("test"); //传一个参数作为这个计时器的名字
for (var i = 0; i < 100; i++) {
console.log("--------" + i);
}
//终止计时器
console.timeEnd("test"); //用来停止计时器,需要一个计时器的名字作为参数
</script>
对象
- JS种一共有六种数据类型,5种基本数据类型,如果我们看到的值不是5中基本数据类型,就一定是对象
- 基本数据类型都是单一的值如 "hello" 123 true 值和值之间没有任何联系。如果使用基本数据类型的数据,我们所创建的变量都是独立的,不能成为一个整体。
- 对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性。
- 对象的分类
- 内建对象
- 由ES标准中定义的对象,在任何的ES实现中都可以使用
- 比如:Math String Number Boolean
- 宿主对象
- 由JS运行环境提供的对象,目前来讲主要是由浏览器提供的对象
- 比如 BOM DOM
- 自定义对象
- 由开发人员自己创建的对象
<script type="text/javascript">
//创建对象
var obj = new Object();
console.log(typeof obj); //使用typeof 检查一个对象时,会返回object
/**
* 向对象添加属性
* 语法: 对象.属性名 = 属性值
*/
//向obj中添加一个name属性
obj.name = "Jimmy";
//向obj中添加一个gender属性
obj.gender = "man";
//向obj中添加一个age属性
obj.age = 18;
console.log(obj); //打印{name: "Jimmy", gender: "man", age: 18}
/**
* 读取对象属性
* 语法:对象.属性名
* 如果读取对象中没有的属性,不会报错而是会返回undefined
*/
console.log(obj.name);
/**
* 修改对象的属性值
* 语法:对象.属性名 = 新值
*/
obj.name = "kimi";
/**
* 删除对象的属性
* 语法: delete 对象.属性名
*/
//删除name属性
delete obj.name;
console.log(obj); //打印{gender: "man", age: 18}
</script>
对象的属性名和属性值
- 属性名
- 对象的属性名不强制要求遵守标识符的规范,什么乱七八糟的名字都可以使用
- 但是我们尽量还是要按照规范去命名
- 属性值
- JS对象的属性值,可以是任意的数据类型。甚至也可以是一个对象。
<script type="text/javascript">
var obj = new Object();
obj.name = "Jimmy";
//属性名
obj.var = "aa"; //我属性名时一个关键字也可以
console.log(obj.var); //打印aa
/**
* 如果要使用特殊的属性名,不能采用点"."的方式来操作
* 需要使用另一种方式:
* 语法: 对象["属性名"] = 属性值
* 读取时也需要采用这种方式
*
* 使用[]这种形式去操作属性,更加的灵活
* 在[]中可以直接传递一个变量,这样变量值是多少就会读取那个属性
*/
// obj.123 = "bb";
// console.log(obj.123); //这样是会报错的
obj["123"] = "bb";
obj["nihao"] = "你好";
console.log(obj["123"]); //打印bb
var n = "123";
console.log(obj[n]); //这里打印的是bb,但是如果我把n的值换成"nihao"打印的就是你好,更加灵活
//属性值 可以是任意数据类型,甚至是一个对象
obj.test = true;
obj.test = null;
obj.test = undefined;
console.log(obj);
var obj2 = new Object();
obj2.name = "kelly";
obj.test = obj2;
console.log(obj.test); //打印obj2这个对象
/**
* in 运算符
* 通过该运算符可以检查一个对象中是否含有指定的属性,如果有则返回true ,没有则返回 false
* 语法:
* "属性名" in 对象
*/
//检查 obj 中是否含有 test 属性
console.log("test" in obj); //打印true
</script>
in 运算符
- 通过该运算符可以检查一个对象中是否含有指定的属性,如果有则返回true ,没有则返回 false
- 语法
- "属性名" in 对象
对象字面量
- 使用对象字面量,可以在创建对象时,直接指定对象中的属性
- 语法:
- {属性名:属性值,属性名:属性值....}
- 对象字面量的属性名可以加引号也可以不加,建议不加
- 如果要使用一些特殊的名字,则必须加引号
- 属性名和属性值是一组一组的key-value结构,key和value之间使用冒号":"连接,多个key-value对之间使用逗号","隔开
<script type="text/javascript">
//创建一个对象
var obje = new Object();
/**
* 使用对象字面量来创建一个对象,使用这种方式和上面的方式本质上是一样
*/
var obj = {};
console.log(obj); //打印[object Object]
obj.name = "Jimmy";
console.log(obj.name); //打印Jimmy
/**
* 使用对象字面量,可以在创建对象时,直接指定对象中的属性
* 语法:
* {属性名:属性值,属性名:属性值....}
* 对象字面量的属性名可以加引号也可以不加,建议不加
* 如果要使用一些特殊的名字,则必须加引号
*
* 属性名和属性值是一组一组的key-value结构
* key和value之间使用冒号":"连接,多个key-value对之间使用逗号","隔开
*/
var obj2 = {
name:"kimi",
"age":"12",
sex:"male",
test:{name:"kelly"} //test的属性值是一个对象
};
console.log(obj2);
</script>
函数
- 函数也是一个对象
- 函数中可以封装一些功能(代码),在需要时可以执行这些功能(代码)
- 使用 typeof 检查一个函数对象时,会返回function
- 我们可以使用函数声明来创建一个函数
- 我们可以是会用函数表达式来创建一个函数
<script type="text/javascript">
//创建一个函数对象
var fun = new Function();
console.log(typeof fun); //打印function
//可以将要封装的代码以字符串的形式传递给构造函数(这种方式了解下即可)
var fun1 = new Function("console.log('这是第一个函数')")
/**
* 封装到函数中的代码不会立即执行
* 函数中的代码会在函数调用的时候执行
* 调用函数语法:
* 函数对象()
* 当调用函数时,函数中封装的代码会按照顺序执行
*/
fun1();
//我们说函数也是一个对象,它具有所有普通的对象的功能,只不过它比普通对象更强大,在函数里面封装的是一些可执行的代码
fun1.hello = "你好";
console.log(fun1.hello); //打印你好
/*
* 在开发中我们一般都使用函数声明来创建一个函数
* 语法:
* function 函数名 ([形参1,形参2...形参N]) { 中括号表示这些形参可选
* 语句....
* }
*/
function fun2() {
console.log("这是我的第二个函数");
}
console.log(fun2); //会把整个函数都给它打出来
//调用fun2()
fun2();
/*
* 使用函数表达式来创建一个函数
* var 函数名 = function([形参1,形参2...形参N]) {
* 语句....
* }
* 所谓的函数表达式就是创建一个匿名函数,然后将这个匿名函数的对象赋值给一个变量
*/
var fun3 = function() {
console.log("我是匿名函数中的语句");
};
</script>
函数参数
<script type="text/javascript">
function add(a,b) {
console.log(a + b);
}
/*
* 调用函数时,解析器不会检查实参的类型,所以要注意是否可能会接收到非法的参数,如果有可能则需要对参数进行类型的检查
* 函数的实参可以是任意的数据类型
*/
add(2,3); //打印5
/**
* 调用函数时,解析器也不会检查实参的数量
* 多余的实参不会被赋值
* 如果实参的数量少于形参的数量,则没有对应实参的形参将是undefined
*/
add(3,2,1,"hello"); //打印5,后面的参数不会被赋值
add(1); //打印NaN,就相当于a=1,b=undefined a+b即为NaN
</script>
函数返回值
<script type="text/javascript">
/*
* 创建一个函数,用来计算三个数的和
* 可以使用 return 来设置函数的返回值
* 语法:
* return 值
* return 后的值将会作为函数的执行结果返回,可以定义一个变量,来接收该结果
* 在函数中return 后的语句都不会执行
* 如果 return 语句后不跟任何值就相当于返回一个undefined
* 如果函数不写 return(即没有返回值),则也会返回 undefined
*/
function sum (a,b,c) {
var d = a + b + c;
return d;
}
var result = sum(1,2,3);
console.log(result); //打印6 假设sum函数中我没有写return,这里打印的就是undefined
</script>
函数的实参可以是任何值
<script type="text/javascript">
function isou(num) {
/*if (num % 2 == 0) {
return true;
} else {
return false;
}*/
//上面这样写有点多余了,直接返回就可以了
return num % 2 == 0;
}
var result = isou(6);
console.log(result)
var obj = {
name : "孙悟空",
age : "18",
gender : "男",
address : "花果山"
};
function myFun(fun) {
console.log(fun);
}
//函数的实参也可以是一个函数
myFun(isou); //这里我可以传一个函数对象过去
myFun(function () { //我也可以传一个匿名函数
console.log("匿名函数作为一个实参传递给一个函数");
});
</script>
返回值类型
- 返回值可以是任意的数据类型
- 返回值可以是一个对象,也可以是一个函数(强调)
<script type="text/javascript">
function fun2() {
return {name:"Jimmy"}; //返回值类型可以是一个对象
}
function fun3() {
//在函数内部再声明一个函数
function fun4() {
console.log("我是fun4");
}
//fun4(); 在函数里面调用fun4
return fun4; //返回fun4这个函数对象
}
var resu = fun3();
console.log(resu); //打印的就是fun4这个函数
</script>
立即执行函数
- 函数定义完,立即被调用,这种函数叫做立即执行函数
- 立即执行函数往往只会执行一次(因为没有变量去接收它,执行完以后你就找不到了)
<script type="text/javascript">
/*
* 1、如果我直接声明一个匿名函数,它是会报错的。因为它把大括号当成一个代码块,大括号前面的东西它就不认识了
* 所以我们应该在匿名函数上加一个括号,来表示这个函数是一个整体,这样它就不会报错了
* 2、如果我要是想去调用匿名函数应该怎么去调用呢?
* 答:我们说调用一个函数,直接用 函数对象()
*/
/*(function() {
console.log("我是一个匿名函数");
})*/
//调用匿名函数
/*
* 这就是一个立即执行函数,函数定义完,立即被调用
* 立即执行函数往往只会执行一次,因为这个函数没有变量去接收它,执行完以后你就找不到它了
*/
/*(function() {
console.log("我是一个匿名函数,啦啦啦");
})()*/
//也可以这么写
(function(a,b) {
console.log("a = " + a);
console.log("b = " + b);
})(2,3) //这也是一个立即执行函数,带参数的
</script>
方法
- 函数也可以成为对象的属性,如果一个函数作为一个对象的属性保存,那么我们称这个函数是这个对象的方法
- 调用函数就说调用对象的方法
- 调函数和调方法本质上是一样的,只是叫法,名称不同而已
<script type="text/javascript">
var obj = new Object();
//像对象中添加属性
obj.name = "Jimmy";
obj.age = 18;
//对象的属性值可以是任何数据类型,也可以是个函数
obj.sayName = function() {
console.log(obj.name);
}
console.log(obj.sayName) //打印sayName这个函数
obj.sayName(); //调用方法
function fun() {
console.log("aa");
}
fun(); //调用函数
/*
* 函数也可以成为对象的属性,
* 如果一个函数作为一个对象的属性保存,那么我们称这个函数是这个对象的方法
* 调用函数就说调用对象的方法
*
* 调函数和调方法本质上是一样的,只是叫法,名称不同而已。
*/
var obj2 = {
name : "kelly",
age : 18,
sayName : function() {
console.log(obj2.name);
}
}
obj2.sayName(); //这种方式也可以
</script>
枚举对象中的属性
<script type="text/javascript">
var obj = {
name : "kimi",
age : 18,
gender : "男",
address : "Taibei"
}
//枚举对象中的属性
//使用 for ... in 语句
/*
* 语法:
* for(var 变量 in 对象) {
*
* }
* for...in语句 对象中有几个属性,循环体就会执行几次
* 每次执行会将对象中的一个属性的名字赋值给变量
*/
for (var n in obj) {
console.log(n + ":" + obj[n]);
}
</script>
作用域
- 作用域指一个变量的作用范围
- 在JS中一共有两种作用域
- 全局作用域
- 直接编写在script标签中的JS代码,都在全局作用域
- 全局作用域在页面打开时创建,在页面关闭时销毁
- 在全局作用域中有一个全局对象window,它代表的是浏览器窗口,它由浏览器创建我们可以直接使用
- 在全局作用域中,创建的变量都会作为window对象的属性保存,创建的函数都会作为window对象的方法保存
- 全局作用域中的变量都是全局变量,在页面的任意部分都可以访问的到
- 函数作用域
- 调用函数时创建函数作用域,函数执行完毕后,函数作用域销毁
- 每调用一次函数就会创建一个新的函数作用域,它们之间是互相独立的
- 在函数作用域中可以访问到全局作用域的变量,在全局作用域中无法访问到函数作用域中的变量
- 当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用,如果没有则向上一级作用域中寻找,直到找到全局作用域,如果全局作用域中依然没有找到,则会报错
- 在函数中要访问全局变量可以使用window对象
<script type="text/javascript">
//直接写在script标签中的JS代码,都在全局作用域,在全局作用域中,创建的变量都会作为window对象的属性保存
var a = 10;
console.log(window.a); //创建的a变量,会作为window对象的属性
function fun() { //创建的这个fun函数,会作为window对象的方法
console.log("我是一个方法");
}
//全局作用域中的函数会作为window对象的方法保存
window.fun(); //我们所谓的函数其实就是window对象的方法
</script>
变量/函数的声明提前
- 变量的声明提前
- 使用var关键字声明的变量,会在所有的代码执行之前被声明(但是不会被赋值)
- 但是如果声明变量时不使用var关键字,则变量不会被声明提前
- 函数的声明提前
- 使用函数声明形式创建的函数 function 函数名(){} 它会在所有代码执行之前就被创建,所以我们可以在函数声明前来调用函数
- 使用函数表达式创建的函数,不会被声明提前,所以不能在声明前调用
<script type="text/javascript">
var a = 10;
console.log(a);
b = 15; //这里我定义变量的时候不写var,发现也没有报错。不写var就相当于是window.b=15,b作为window对象的一个属性
console.log(b); //打印15
console.log(c); //打印undefined
var c = 11; //这行代码就相当于,我在最开始声明一个var c;然后在这行给c赋值c=11
// console.log(d);
d = 13; //这样的话就会报错,因为我声明变量的时候没有使用var关键字,变量就不会被声明提前,变量还没声明,我在上一行就打印肯定就报错了
fun(); //我在函数声明之前调用函数,是不会报错的
function fun() { //它会在所有代码执行之前被调用
console.log("我是fun函数");
}
fun2(); //在用函数表达式创建的函数之前调用会报错,用var声明的变量会被声明提前,所以就相当于在最前面声明一个var fun2; 因为没有赋值所以这个fun2肯定是undefined,所以你在这行就相当于调用undefined(),肯定报错
var fun2 = function() {
console.log("我是fun2函数");
}
</script>
函数作用域小案例
<script type="text/javascript">
var a = 10;
function fun() {
var a = 3;
console.log(window.a); //打印10,在函数里面我如果想访问全局变量,可以借助window对象
}
/*
* 在函数作用域中也有声明提前的特性
* 使用var关键字声明的变量,会在函数中所有的代码执行之前被声明
*/
function fun2() {
console.log(b); //打印undefined,这行代码它会现在fun2函数作用域里面找b,看有没有b,发现是有b的,因为b这个变量用var声明了,它会被声明提前,找到了但是没有被赋值,所以打印undefined
var b = 1; //这行代码就相当于我在fun2函数里面的第一行代码声明一个变量var b; 然后在这行给b赋值b=1
}
// fun2();
var c = 33;
function fun3() {
console.log(c); //打印33,这行代码它会现在fun3函数作用域里面找看有没有c,发现没有,因为下面的c没有用var关键字声明,就不会被声明提前,所以去它上一级作用域找,找到了就打印
c = 10; //这个c实际上是个全局变量
//这个d没有使用var关键字,则会设置为全局变量
d = 100; //这个d也是全局变量
}
fun3();
/*
* 在函数中,不使用var声明的变量都会成为全局变量
*/
//在全局输出c
console.log(c); //打印10
console.log(d); //打印100
/*
* 定义形参就相当于在函数作用域中声明了变量
*/
function fun4(e) {
console.log(e); //打印undefined,我实参没有传值,但是函数定义了形参,就相当于在函数作用域中声明了变量,声明了变量但是没有赋值,所以打印undefined
}
fun4();
</script>
工厂方法创建对象
<script type="text/javascript">
var obj = {
name : "Jimmy",
age : 18,
gender : "男",
sayName: function() {
console.log(this.name)
}
}
var obj2 = {
name : "kimi",
age : 8,
gender : "男",
sayName: function() {
console.log(this.name)
}
}
/*
* 使用工厂方法创建对象
*/
function createPerson(name, age, gender) {
//创建新的对象
var obj = new Object();
//向对象中添加属性
obj.name = name;
obj.age = age;
obj.gender = gender;
obj.sayName = function() {
console.log(this.name);
};
return obj;
}
var p1 = createPerson("cc",18,"男");
console.log(p1);
function createDog(name, age) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sayHello = function() {
console.log("汪汪");
}
return obj;
}
/*
* 工厂方法创建的对象,使用的构造函数都是Object
* 所以创建的对象都是Object这个类型,就导致我们无法区分出多种不同类型的对象
*/
var dog = createDog("旺财",12);
</script>
构造函数
- 构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写。
- 构造函数和普通函数的区别就是调用方式的不同,普通函数是直接调用,而构造函数需要使用 new 关键字来调用
- 构造函数的执行流程
- 立刻创建一个新的对象
- 将新建的对象设置为函数中的this,在构造函数中可以使用 this 来引用新建的对象
- 逐行执行函数中的代码
- 将新建的对象作为返回值返回
- 使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类。我们通过一个构造函数创建的对象,称为是该类的实例。
<script type="text/javascript">
/*
* 构造函数习惯首字母大写
*/
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
var per = new Person("Jimmy",12,"男");
console.log(per); //打印Person {name: "Jimmy", age: 12, gender: "男"}
/*
* 使用instanceof 可以检查一个对象是否是一个类的实例
*/
console.log(per instanceof Person); //打印true
//所有对象都是Object的后代
console.log(per instanceof Object); //打印true
</script>
关于构造函数里面的方法
<script type="text/javascript">
//声明一个构造函数
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
//向对象中添加一个方法
this.sayName = fun; //为了不是每调用一次构造函数,我就要新调用一次这个方法,我把方法拿到外面去写
}
/*
* 将函数拿到外面来写又会带来一个问题:
* 将函数定义在全局作用域,污染了全局作用域的命名空间(如果有两个名字一样的函数,后一个会覆盖前面的)
* 而且定义在全局作用域中也很不安全(别人定义的函数名和你定义的函数名可能会重掉,这样就会出问题)
*/
function fun() {
console.log(this.name);
}
//js中可以定义两个函数名相同的函数,后一个函数会把前一个函数给覆盖掉
function fun() {
console.log(this.age);
}
//这样我不同对象调用sayName方法,调用的都是同一个方法。要是在构造函数里面写,每创建一个对象,就会创建一个方法造成资源浪费
var p1 = new Person("Jimmy",44,"男");
p1.sayName();
</script>
原型对象
- 我们所创建的每一个函数,解析器都会向函数中添加一个属性 prototype
- 如果函数作为普通函数调用,这个 prototype 属性没有任何作用
- 当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,我们可以通过 _ proto _ _来访问该属性
- 原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中
- 当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用
- 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样就不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了
<script type="text/javascript">
/*
* 原型 prototype
* 我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype
* 如果函数作为普通函数调用,这个prototype属性没有任何作用
* 当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,
* 指向该构造函数的原型对象,我们可以通过__proto__来访问该属性
*/
function Person() {
}
function MyClass() {
}
var mv = new MyClass();
console.log(MyClass.prototype); //这个prototype属性值是一个对象
//同一个类的实例都指向这个原型对象
console.log(mv.__proto__ == MyClass.prototype); //打印true
//向MyClass的原型中添加属性a
MyClass.prototype.a = 123; //MyClass的prototype属性的属性值是一个对象,现在我给这个对象添加一个属性a
console.log(mv.a); //打印123,因为同一类的实例都指向这个原型对象
mv.a = 456;
console.log(mv.a); //打印456,找的时候是先在对象实例中找,找不到后再去原型里面找
//向MyClass原型中添加一个方法
MyClass.prototype.sayHello = function() {
console.log("我是原型对象中的方法");
}
mv.sayHello(); //在mv对象中我并没有写sayHello方法,在原型对象中写了,所以我这里可以调
</script>
//像上面关于构造函数里面的方法,我们就可以把它写到原型对象里面去
<script type="text/javascript">
//声明一个构造函数
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
Person.prototype.sayName = function() {
console.log(this.name);
}
var p1 = new Person("Jimmy",44,"男");
p1.sayName(); //在原型对象里面写方法,我这个对象的实例都可以访问到
</script>
<script type="text/javascript">
//创建一个构造函数
function MyClass() {
}
//向MyClass的原型中添加一个name属性
MyClass.prototype.name = "我是原型中的名字";
var mv = new MyClass();
console.log(mv.name); //打印"我是原型中的名字"
//使用 in 检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true
console.log("name" in MyClass) //打印true
//可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性
console.log(mv.hasOwnProperty("name")); //打印false
/*
* 原型对象也是对象,所以它也有原型
* 当我们使用一个对象的属性或方法时,会现在自身中寻找,自身中如果有,则直接使用
* 如果没有则去原型对象中寻找,如果原型对象中有,则使用
* 如果没有则去原型的原型中寻找,直到找到Object对象的原型
* Object对象的原型没有原型,如果在Object 中依然没有找到,则返回undefined
*/
console.log(mv.__proto__.hasOwnProperty("hasOwnProperty")) //看下原型里面有没有hasOwnProperty这个属性,发现打印fasle
console.log(mv.__proto__.__proto__.hasOwnProperty("hasOwnProperty")); //打印true,发现这个属性是在原型的原型里面
</script>
//关于原型
/*当系统为Person构造器创建原型对象的时候,会执行这样的一条语句:Person.prototype = new Object();也就是说,这个原型对象是Object的一个实例,那么,Object类下面的所有属性和方法会被这个原型对象所拥有,Person下的实例就可以通过这个原型对象使用这些属性和方法。所以说Object是所有类的父类*/
toString()方法
<script type="text/javascript">
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
var per = new Person("Jimmy",12,"男");
//当我们直接在页面中打印一个对象时,实际上是输出这个对象的toString()方法的返回值
//如果我们希望在输出对象时不输出[Object,Object],可以为对象添加一个toString()方法
Person.prototype.toString = function() {
return this.name + "," + this.age + "," + this.gender
}
console.log(per.toString());
</script>
垃圾回收
- 就像人生活时间长了会产生垃圾一样,程序运行过程也会产生垃圾,这些垃圾积攒过多以后,会导致程序运行的速度过慢,所以我们需要一个垃圾回收机制,来处理程序运行过程中的垃圾。
- 当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,所以这种垃圾必须进行清理。
- 在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,我们不需要也不能进行垃圾回收操作
- 我们需要做的就是将不再使用的对象设置为 null 即可
数组
- 数组也是一个对象
- 它是用来存储一些值的
<script type="text/javascript">
//创建一个数组对象
var arr = new Array();
//使用typeof检查一个数组时,会返回object
console.log(typeof arr);
/*
* 向数组中添加元素
* 语法:
* 数组[索引] = 值
*/
arr[0] = 1;
arr[1] = 2;
/*
* 读取数组中的元素
* 语法:
* 数组[索引]
* 如果读取不存在的索引,它不会报错而是返回undefined
*/
console.log(arr[1]); //如果读取不存在的索引,返回undefined
/**
* 获取数组的长度
* 可以使用length属性来获取数组长度
* 语法: 数组.length
* 对于连续的数组,使用length可以获取到数组的长度(元素的个数)
* 对于非连续的数组,使用length会获取到数组的最大索引+1
*/
console.log(arr.length); //打印2
/*
* 修改length
* 如果修改的length大于原长度,则多出部分会空出来
* 如果修改的length小于原长度,则多出的元素会被删除(所以我们可以通过修改length来删除一些元素)
*/
arr.length = 5; //原来length长度是2,现在我给它改成5
console.log(arr.length); //打印5
</script>
数组字面量
<script type="text/javascript">
//创建一个数组
var arr = new Array();
/*
* 使用字面量来创建数组
* 语法:[]
*/
var arr1 = [];
console.log(arr1);
//使用字面量创建数组时,可以在创建时就指定数组中的元素
var arr2 = [1,2,3,4];
console.log(arr2.length); //打印4
//使用构造函数创建数组时,也可以同时添加元素,将要添加的元素作为构造函数的参数传递,元素之间使用逗号隔开
var arr3 = new Array(3,4,5,6);
console.log(arr3.length); //打印4
//创建一个数组数组中只有一个元素10
var arr4 = [10];
console.log(arr4.length); //打印1
//创建一个长度为10的数组
var arr5 = new Array(10);
console.log(arr5.length); //打印10
//数组中的元素可以是任意的数据类型
var arr6 = ["hello",1,true,null,undefined];
//可以是对象
var arr7 = [{name:"Jimmy"},{name:"kimi"},{name:"kelly"}]
console.log(arr7.length); //打印3
//也可以是函数
var arr8 = [function(){console.log(1)},function(){console.log(2)}];
console.log(arr8.length); //打印2
//调用
arr8[0]();
//数组中也可以放数组,如下这种数组我们称为二维数组
var arr9 = [[1,2,3],[2,3,4],[1,3,8]];
console.log(arr9.length); //打印3
</script>
数组的四个方法
- push()方法
- 该方法可以向数组的末尾添加一个或多个元素,并返回数组的新长度
- 可以将要添加的元素作为方法的参数传递,这样这些元素将会自动添加到数组的末尾
- 该方法会将数组新的长度作为返回值返回
- pop()方法
- 该方法可以删除数组的最后一个元素,并将被删除的元素作为返回值返回
- unshift()方法
- 向数组开头添加一个或多个元素,并返回新的数组长度
- 向前边插入元素以后,其他元素的索引会依次调整
- shift()方法
- 可以删除数组的第一个元素,并将删除的元素作为返回值返回
<script type="text/javascript">
//创建一个数组
var arr = ["Jimmy","kelly","kimi"];
/*
* push()
* 该方法可以向数组的末尾添加一个或多个元素,并返回数组的新的长度
* 可以将要添加的元素作为方法的参数传递,这样这些元素将会自动添加到数组的末尾
*/
arr.push("kyson"); //添加一个
console.log(arr); //打印"Jimmy,kelly,kimi,kyson"
var len = arr.push("shp","heping"); //添加多个
console.log(len); //打印len,返回值是数组的长度
/*
* pop()
* 该方法可以删除数组的最后一个元素,并将被删除的元素作为返回值返回
*/
console.log(arr); //打印"Jimmy,kelly,kimi,kyson,shp,heping"
var result = arr.pop();
console.log(arr); //打印"Jimmy,kelly,kimi,kyson,shp"
console.log(result); //打印heping
/*
* unshift()
* 向数组开头添加一个或多个元素,并返回新的数组长度
* 向前边插入元素以后,其他元素的索引会依次调整
*/
var len2 = arr.unshift("hi","hello");
console.log(arr); //打印"hi,hello,Jimmy,kelly,kimi,kyson,shp"
console.log(len2); //打印7
/*
* shift()
* 可以删除数组的第一个元素,并将删除的元素作为返回值返回
*/
result = arr.shift();
console.log(arr); //打印"hello,Jimmy,kelly,kimi,kyson,shp"
console.log(result); //打印"hi",这个为删除的第一个元素
</script>
数组小练习
<script type="text/javascript">
function Person(name,age,gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
//修改Person原型的toString方法
Person.prototype.toString = function() {
return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"]";
}
//创建Person对象
var per1 = new Person("Jimmy",43,"男");
var per2 = new Person("kelly",33,"女");
var per3 = new Person("kimi",11,"男");
//将这些Person放到一个数组里
var perArr = [per1,per2,per3];
/*
* 创建一个函数,可以将perArr中大于18岁的Person提取出来,
* 然后封装到一个新的数组中并返回
*/
function getAdult(arr) {
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i].age > 18) {
newArr.push(arr[i]);
}
}
return newArr;
}
console.log(getAdult(perArr)); //打印Jimmy和kelly两个数组对象
</script>
forEach()方法
- 一般我们都是使用for循环去遍历数组,JS中还为我们提供了一个方法,用来遍历数组
- forEach()方法
- 这个方法只支持IE8以上浏览器,IE8及以下的浏览器均不支持该方法
- forEach()方法需要一个函数作为参数
- 像这种,由我们创建但是不由我们调用的,我们称为回调函数
- 数组中有几个元素,函数就执行几次,每次执行时浏览器会将遍历到的元素,以实参的形式传递进来,我们可以定义形参来读取这些内容
- 浏览器会在回调函数中传递三个参数
- 第一个参数,就是当前正在遍历的元素
- 第二个参数,就是当前正在遍历元素的索引
- 第三个参数,就是正在遍历的数组
<script type="text/javascript">
//创建一个数组
var arr = ["Jimmy","kelly","kimi","kyson","jkson"];
/*
* forEach()方法需要一个函数作为参数
* 像这种函数,由我们创建但是不由我们调用的,我们称为回调函数
* 数组中有几个元素函数执行几次,每次执行时,浏览器会将遍历到的元素以实参的形式传递进来,我们可以定义形参,来读取这些内容
*/
arr.forEach(function(value,index,obj) {
console.log(value); //打印数组中的各个元素
console.log(index); //打印正在遍历元素的索引
console.log(arr); //打印这个数组对象
})
</script>
数组的方法
- slice()方法
- 可以从数组中提取指定的元素
- 该方法不会改变数组,而是将截取到的元素封装到一个新数组中返回
- 参数
- start 从何处开始选取(包含开始)
- end 从何处结束选取(不包含结束)
- 参数可以传一个负数,如果传的是负数,那么就从数组尾部开始算起。即,-1指最后一个元素,-2指倒数第二个元素
- splice()方法
- 可以用于删除数组中的元素
- 使用splice()会影响到原数组,会将指定元素从原数组中删除,并将被删除的元素作为返回值返回
- 参数
- 第一个参数,表示开始位置的索引
- 第二个参数,表示删除的数量
- 第三个及以后,可以传递一些新的元素,这些元素将会自动插入到开始位置的索引前边
<script type="text/javascript">
//创建一个数组
var arr = ["Jimmy","kelly","kimi","kyson","jkson"];
//使用slice截取数组中的元素
var newArr = arr.slice(0,2); //截取是前包括后不包括截取
console.log(newArr); //打印Jimmy,kelly
/*
* splice()
* 可以用于删除数组中的元素
* 使用splice()会影响到原数组,会将指定元素从原数组中删除,并将被删除的元素作为返回值返回
* 参数
* 第一个参数,表示开始位置的索引
* 第二个参数,表示删除的数量
* 第三个及以后,可以传递一些新的元素,这些元素将会自动插入到开始位置的索引前边
*/
var result = arr.splice(0,2);
console.log(result); //打印"Jimmy,kelly"
</script>
数组剩余方法
- concat()方法
- 可以连接两个或多个数组,并将新的数组返回
- 该方法不会对原数组产生影响
- join()方法
- 该方法可以将数组转换为一个字符串
- 该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
- 在join()中可以指定一个字符串作为参数,这个字符串将会成为数组中元素的连接符。如果不指定连接符,则默认使用逗号“,”作为连接符
- reverse()方法
- 该方法用来反转数组
- 该方法会直接修改原数组
- sort()方法
- 可以用来对数组进行排序
- 会影响原数组,默认会按照Unicode编码进行排序
<script type="text/javascript">
var arr = ["Jimmy","kimi","kelly"];
var arr2 = ["durant","kobe","James"];
var arr3 = ["aa","bb","cc"];
/**
* concat()可以连接两个或多个数组,并将新的数组返回
*/
var newArr = arr.concat(arr2,arr3);
console.log(newArr); //打印三个数组所有的元素
/*
* join方法
*/
var result = arr.join();
console.log(result); //打印Jimmy,kimi,kelly
console.log(typeof result); //打印string
//在join()中指定一个字符串作为参数,这个字符串会成为数组中元素的连接符
result = arr.join("-");
console.log(result); //打印Jimmy-kimi-kelly
/*
* reverse()
*/
newArr = arr.reverse();
console.log(newArr); //打印kelly,kimi,Jimmy
/**
* sort()
*/
var arr3 = ["a","c","d","b"];
console.log(arr3.sort()); //打印a,b,c,d
/*
* 对于纯数字的数组,使用sort()排序时,也会按照unicode编码来排序
* 所以对数字进行排序可能会得到错误的结果
*
* 所以我们可以自己指定排序的规则,我们可以在sort()中添加一个回调函数,来指定排序规则
* 回调函数中需要定义两个形参,浏览器将会分别使用数组中的元素作为实参去调用回调函数
* 使用哪个元素不确定,但是肯定的是在数组中a一定在b的前边
* 浏览器会根据回调函数的返回值来决定元素的顺序,
* 如果返回一个大于0的值,则元素会交换位置
* 如果返回一个小于0的值,则元素位置不变
* 如果返回一个0,则认为两个元素相等,也不交换位置
*
* 结论:
* 如果需要升序排列,则返回a-b
* 如果需要降序排列,则返回b-a
*/
var arr4 = [3,4,6,5,11];
console.log(arr4.sort()); //打印11,3,4,5,6, 是按照unicode编码来排序的
var arr5 = [5,3];
arr5.sort(function(a,b) {
//前面的大
if (a > b) {
return 1; //如果前面的比后面的大就换位置
} else if (a < b) { //说明小的数在前面
return -1; //如果前面的比后面的小就不换位置
} else {
return 0;
}
//比较简单一点可以这么写,直接return 两个值相减
// return a-b;
})
console.log(arr5); //如果返回一个正数,这里打印3,5。如果返回一个负数,这里打印5,3
</script>
函数的方法
- call()和apply()方法
- 这两个方法都是函数对象的方法,需要通过函数对象来调用
- 当函数对象调用call()和apply()都会调用函数执行
- call()方法可以将实参在对象之后依次传递
- apply()方法需要将实参封装到一个数组中统一传递
<script type="text/javascript">
function fun() {
console.log("我是fun函数");
}
fun.call(); //打印我是fun函数
fun.apply(); //打印我是fun函数
fun(); //打印我是fun函数
function fun2() {
console.log(this);
}
fun2(); //打印[object Window],this代表当前window对象
var obj = {};
fun2.call(obj); //打印[object Object],this代表当前对象,你传过来哪个对象,this就代表哪个对象
function fun3(a,b) {
console.log(a);
console.log(b);
}
var obj2 = {};
fun3.call(obj2,5,6); //打印a是5,b是6
fun3.apply(obj2,[2,3]); //打印a是2,b是3
//这两个方法不同的是,call()方法实参需要一个一个的传,apply()方法实参需要封装到一个数组中一起传
</script>
函数的arguments对象
在调用函数时,浏览器每次都会传递进两个隐含的参数:
- this
- 封装实参的对象 arguments
- arguments是一个类数组对象,它也可以通过索引来操作数据,也可以获取长度
- 在调用函数时,我们所传的实参都会封装到arguments中
- arguments.length可以用来获取实参的长度
- 我们即使不定义形参,也可以通过arguments来使用实参,只不过比较麻烦
- arguments[0] 表示第一个实参 arguments[1] 表示第二个实参
- 它里面有一个属性叫做callee,这个属性的值对应一个函数对象,就是当前正在执行的函数对象
<script type="text/javascript">
function fun() {
console.log(Array.isArray(arguments)); //打印false,判断这个arguments对象是不是一个数组对象
console.log(arguments.length); //打印3
console.log(arguments[0]); //打印2
console.log(arguments.callee == fun); //打印true
}
fun(2,"hello",true); //这里的三个参数都会封装到arguments对象中
</script>
Date对象
<script type="text/javascript">
/*
* Date对象
* 在JS中使用Date对象来表示一个时间
*/
//创建一个Date对象
var d = new Date();
/*
* 创建一个指定的时间对象
* 需要在构造函数中传递一个表示时间的字符串作为参数
* 日期格式 月份/日/年 时:分:秒
*/
var d2 = new Date("12/4/2017 12:30:10");
console.log(d2);
/*
* getDate()
* 获取当前日期对象是几日
*/
var date = d2.getDate();
console.log(date); //打印3,表示当前日期对象是3日
/*
* 获取当前日期对象是周几
* 0表示周日
* 1表示周一
*/
var day = d2.getDay();
console.log(day); //打印1,表示当前日期对象是周一
/*
* 获取当前对象的月份,返回一个0-11的值
* 0表示1月
* 1表示2月
* 11表示12月
*
*/
var month = d2.getMonth();
console.log(month); //打印11
/*
* 获取当前日期对象的年份
*/
var year = d2.getFullYear();
console.log(year);
/*
* 获取当前日期对象的时间戳
* 计算机底层在保存时间时,使用的都是时间戳
*/
var time = d2.getTime();
console.log(time); //打印1512361810000
/*
* 获取当前时间的时间戳
*/
var timeNow = Date.now();
console.log(timeNow); //打印1511441225359
</script>
Math对象
- Math和其他对象不同,它不是一个构造函数,它属于一个工具类不用创建对象,它里面封装了数学运算相关的属性和方法
<script type="text/javascript">
console.log(Math.PI); //打印圆周率
//abs()可以用来计算一个数的绝对值
console.log(Math.abs(-1));
/*
* Math.ceil()
* 可以对一个数进行向上取整,小数位只要有值就自动进1
* Math.floor()
* 可以对一个数进行向下取整,小数部分会被舍掉
* Math.round()
* 可以对数进行四舍五入取整
*/
console.log(Math.ceil(1.4)); //打印2
console.log(Math.floor(1.9)); //打印1
console.log(Math.round(2.4)); //打印2
/*
* Math.random()
* 可以用来生成一个0-1之间的随机数
* 生成一个0-x之间的随机数
* Math.round(Math.random() * x)
* 生成一个x-y之间的随机数
* Math.round(Math.random() * (y-x) + x)
*/
console.log(Math.random()); //打印0.07515802048146725
console.log(Math.round(Math.random() * 10)); //生成一个0-10之间的随机数
/*
* Math.random() 是0-1之间的随机数,乘以9就是0-9之间的随机数,加1就是1-10之间的随机数
*/
console.log(Math.round(Math.random() * 9) + 1); //生成一个1-10之间的随机数
/*
* max() 可以获取多个数中的最大值
* min() 可以获取多个数中的最小值
*/
console.log(Math.max(12,23,56,34,18)); //打印56
console.log(Math.min(12,56,22,34,9)); //打印9
/*
* Math.pow(x,y)
* 返回x的y次幂
*/
console.log(Math.pow(2,3)); //打印8,即2的3次方
/*
* Math.sqrt()
* 用于对一个数进行开方运算
*/
console.log(Math.sqrt(4)); //打印2
</script>
包装类
- 基本数据类型
- String Number Boolean Null Undefined
- 引用数据类型
- Object
- 在 JS 中为我们提供了三个包装类,通过这三个包装类可以将基本数据类型转换为对象
- String()
- 可以将基本数据类型字符串转换为 String 对象
- Number()
- 可以将基本数据类型的数字转换为 Number 对象
- Boolean()
- 可以将基本数据类型的布尔值转换为 Boolean 对象
- 注意:我们在实际开发中不会使用基本数据类型的对象,如果使用基本数据类型的对象,在做一些比较时可能会带来一些不可预期的结果
<script type="text/javascript">
//创建一个Number类型的对象
var num = new Number(3);
console.log(num); //打印3
console.log(typeof num); //打印object
//创建一个String 类型的对象
var str = new String("aa");
console.log(str); //打印aa
console.log(typeof str); //打印object
//创建一个Boolean类型的对象
var bol = new Boolean(true);
console.log(bol); //打印true
console.log(typeof bol); //打印object
/*
* 开发中我们不会使用基本数据类型的对象
*/
var b = new Boolean(false);
if (b) { //因为这个b是一个对象,你把一个对象放在这,它会把这个对象转换成一个布尔值然后在判断,我们知道对象转换成布尔值都是true
console.log("你好呀");
}
/*
* 方法和属性只能添加给对象,不能添加给基本数据类型
* 当我们对一些基本数据类型的值去调用属性和方法时,
* 浏览器会临时使用包装类将其转换为对象,然后调用对象的属性和方法
* 调用完以后,再将其转换为基本数据类型
*/
var s = 123;
s = s.toString(); //这里其实调用的是String类的toString方法,代码执行到这一步的时候,浏览器发现这个s是这个基本数据类型,基本数据类型是没有属性和方法的,所以浏览器会临时把这个基本数据类型转换成包装类,然后调用包装类的方法,调用完之后销毁
console.log(s); //打印123
console.log(typeof s); //打印string
var s1 = 345;
s1.name = "hello"; //这个s1是个基本数据类型,我给基本数据类型设置一个属性,保存之后没有报错
console.log(s1.name); //打印undefined
/*
* 原因:
* 我给s1设置一个name属性,但是这个s1是个基本数据类型,所以浏览器会临时把s1转成包装类,然后给这个包装类设置name属性
* 当我在下面打印s1.name的时候,浏览器发现这个s1是个基本数据类型,所以临时把这个s1转成一个包装类,这个包装类是一个新的类,所以你在里面找name属性,肯定找不到undefined(重点就在这两个包装类不是同一个类)
*/
</script>
字符串相关的方法
<script type="text/javascript">
//创建一个字符串
var str = "hello Jimmy";
/*
* 字符串在底层是以字符数组的形式保存的
*/
//获取字符串的长度
console.log(str.length); //打印11
console.log(str[0]); //打印h
/*
* charAt()
* 返回字符串中指定位置的字符
*/
var result = str.charAt(1);
console.log(result); //打印e
/*
* charCodeAt()
* 获取指定位置字符的字符编码(Unicode编码)
*/
result = str.charCodeAt(1);
console.log(result); //打印101
/*
* String.fromCharCode()
* 可以根据字符编码去获取字符
*/
result = String.fromCharCode(74); //打印J
console.log(result);
/*
* concat()
* 可以用来连接两个或多个字符串
*/
result = str.concat("love","you");
console.log(result); //打印hello Jimmyloveyou
/*
* indexOf()
* 返回字符串中字符的索引位置
* 如果该字符串中含有该内容,则会返回其第一次出现的索引位置
* 如果没有找到指定的内容,则返回-1
* 可以指定一个第二个参数,指定开始查找的位置
*/
result = str.indexOf("e");
console.log(result); //打印1
result = str.indexOf("m",2); //打印8,表示从索引为2开始查找,返回"m"第一次出现的索引位置
console.log(result);
/*
* slice()
* 可以从字符串中截取指定的内容
* 不会影响原字符串,而是将截取到的内容返回
* 参数
* 第一个,开始位置的索引
* 第二个,结束位置的索引(前包括,后不包括)
* 也可以传递一个负数作为参数,负数的话将会从后边开始计算
*/
result = str.slice(0,2);
console.log(result); //打印he
/*
* substring()
* 可以用来截取一个字符串,和slice()类似
* 参数
* 第一个,开始截取位置的索引
* 第二个,结束位置的索引(前包括后不包括)
* 和slice()不同的是,这个方法不能接受负值作为参数,如果传递一个负值,则默认使用0
* 而且它还能自动调整参数位置,如果第二个参数小于第一个,则自动交换
*
*/
str = "abcde";
result = str.substring(3,0);
console.log(result); //打印abc 第二个参数小于第一个,自动交换位置
/*
* substr()
* 用来截取字符串
* 参数
* 第一个,截取开始位置的索引
* 第二个,截取的长度
*/
result = str.substr(3,2);
console.log(result); //打印de
</script>
正则表达式
- 正则表达式用于定义一些字符串的规则,计算机可以根据正则表达式来检查一个字符串是否符合规则,或者将字符串中符合规则的内容提取出来
<script type="text/javascript">
/*
* 创建正则表达式的对象
* 语法:
* var 变量 = new RegExp("正则表达式","匹配模式")
* 使用typeof检查正则对象,会返回object
* var reg = new RegExp("a") 这个正则表达式可以检查一个字符中是否含有a
* 在构造函数中可以传递一个匹配模式作为第二个参数
* 这个参数可以是
* i 忽略大小写
* g 全局匹配模式
*/
var reg = new RegExp("a");
console.log(typeof reg);
var str = "a";
//现在我想用reg这个正则来检查str这个字符串是否符合规则
/*
* 正则表达式的方法:
* test()
* 使用这个方法可以用来检查一个字符串是否符合正则表达式的规则,如果符合返回true,否则返回false
*/
var result = reg.test(str);
console.log(result); //打印true
console.log(reg.test("dfdadd")); //打印true
console.log(reg.test("A")); //打印false
reg = new RegExp("a","i"); //忽略大小写
console.log(reg.test("Ab")); //打印true
</script>
正则语法
<script type="text/javascript">
/*
* 使用字面量来创建正则表达式
* 语法:
* var 变量 = /正则表达式/匹配模式
* 使用字面量的方式创建更加简单
* 使用构造函数创建更加灵活
*/
//创建一个正则表达式对象
var reg = new RegExp("a","i"); //构造函数方式,我可以传一个正则表达式变量进来
console.log(reg.test("A")); //打印true
//使用字面量的方式来创建
var reg2 = /a/i;
console.log(reg2.test("A")); //打印true
//创建一个正则表达式,检查一个字符串中是否含有a或b
/*
* 使用 | 表示或者的意思
*/
var reg3 = /a|b/;
console.log(reg3.test("anc")); //打印true
//创建一个正则表达式检查一个字符串中是否有字母
/*
* []里的内容也是或的关系
* [ab] == a|b
* [a-z] 任意小写字母
* [A-Z] 任意大写字母
* [A-z] 任意字母
* [0-9] 任意数字
*/
var reg4 = /[a-z]/;
console.log(reg4.test("t")); //打印true
reg4 = /[A-z]/;
console.log(reg4.test("R")); //打印true
//检查一个字符串中是否含有abc 或 adc 或 aec
var reg5 = /a[bde]c/;
console.log(reg5.test("aec")); //打印true
/*
*[^ ]除了
*/
var reg6 = /[^ab]/;
console.log(reg6.test("ab")); //打印fasle,找除了ab以外的
</script>
字符串和正则相关方法
<script type="text/javascript">
var str = "1a2b3c4d5e6f";
/*
* split()方法
* 可以传递一个正则表达式作为参数,这样方法会根据正则表达式去拆分字符串
*/
var result = str.split(/[a-z]/);
console.log(result[6]); //打印[1,2,3,4,5,6,]
/*
* search()方法
* 可以搜索字符串中是否含有指定内容
* 如果搜索到指定内容,则会返回第一次出现的索引,如果没有搜索到返回-1
* 它可以接收一个正则表达式作为参数,然后会根据正则表达式去检索字符串
* search()只会查找第一个,即使设置全局配置也没用
*/
str = "hello abc hello aec afc";
result = str.search("abc");
console.log(result); //打印6,第一次出现abc时的索引位置
/*
* 搜索字符串中是否含有abc 或 aec 或afc
*/
result = str.search(/a[bef]c/);
console.log(result); //打印6
/*
* match()
* 可以根据正则表达式,从一个字符串中将符合条件的内容提取出来
* 默认情况下我们match只会找到第一个符合要求的内容,找到以后就停止检索
* 我们可以设置正则表达式为全局匹配模式,这样就会匹配到所有的内容
* 可以为一个正则表达式设置多个匹配模式,且顺序无所谓
* match()会将匹配到的内容封装到一个数组中返回,即使只查询到一个结果
*/
str = "1a2b3c4d5e6f";
result = str.match(/[A-z]/); //这里我想把str中所有的字母都提取出来(却发现只提取出了一个a)
console.log(result); //打印一个a
result = str.match(/[A-z]/g); //设置正则表达式为全局匹配模式
console.log(result); //打印a,b,c,d,e,f
result = str.match(/[a-z]/gi); //设置正则表达式为全局匹配加忽略大小写
console.log(result); //打印a,b,c,d,e,f 如果有大写字母,大写字母也会被提前出来
console.log(Array.isArray(result)); //打印true 发现这个结果是一个数组
/*
* replace()
* 可以将字符串中指定内容替换为新的内容
* 参数:
* 第一个,被替换的内容,可以接受一个正则表达式作为参数
* 第二个,新的内容
*/
str = "1a2b3c4d5e6f";
result = str.replace("a","@"); //我想把字符串中的a替换为@,如果字符串中有多个a,那么默认只会替换第一个位置的a
console.log(result); //打印1@2b3c4d5e6f
str = "1a2a3a4b";
result = str.replace(/a/g,"@"); //第一个参数传正则表达式,指定匹配模式为全局
console.log(result); //打印1@2@3@4b
</script>
正则表达式语法2
<script type="text/javascript">
//创建一个正则表达式检查一个字符串中是否含有aaa
var reg = /aaa/;
var str = "aaa";
console.log(reg.test(str)); //打印true
/*
* 量词
* 通过量词可以设置一个内容出现的次数
* 量词只对它前面的一个内容起作用
* {n} 正好出现n次
* {m,n} 出现m-n次
* {m,} 出现m次以上
* + 至少出现1次,相当于{1,}
* * 出现0次或多次,相当于{0,}
* ? 出现0次或1次,相当于{0,1}
*/
var reg1 = /a{3}/;
console.log(reg1.test("aaab")); //打印true
reg1 = /ab{3}/;
console.log(reg1.test("abbb")); //打印true
console.log(reg1.test("ababab")) //打印false
reg1 = /(ab){3}/; //加个小括号表示ab是一个整体,一起出现3次
console.log(reg1.test("ababab")); //打印true
reg1 = /ab{1,3}c/; //表示匹配ab(出现1-3次都行)c
console.log(reg1.test("abc")); //打印true,中间的b出现1次
console.log(reg1.test("abbc")); //打印true,中间的b出现2次,中间的b出现3次也是true,出现4次就是false了
reg1 = /ab{2,}c/; //表示中间的b需要出现2次以上
console.log(reg1.test("abbbbbc")); //打印true
reg1 = /ab+c/;
console.log(reg1.test("abc")); //打印true
console.log(reg1.test("ac")); //打印fasle, b至少需要出现一次
reg1 = /ab*c/;
console.log(reg1.test("ac")); //打印true
console.log(reg1.test("abbbc")); //打印true, b出现0次或多次
reg1 = /ab?c/;
console.log(reg1.test("abc")); //打印true
console.log(reg1.test("ac")); //打印true b可以出现0次或1次
/*
* 检查一个字符串中是否以a开头
* ^ 表示开头
* $ 表示结尾
*/
reg1 = /^a/;
console.log(reg1.test("bcd")); //打印fasle,这个字符串不是以a开头的
console.log(reg1.test("abc")); //打印true
reg1 = /a$/;
console.log(reg1.test("ab")); //打印fasle,不是以a结尾的
console.log(reg1.test("ba")); //打印true
/*
* 如果在正则表达式中同时使用^ $则要求字符串必须完全符合正则表达式
* 如果想用以a开头或以a结尾,可以使用 /^a|a$/
*/
reg1 = /^a$/;
console.log(reg1.test("a")) //打印true
console.log(reg1.test("aaa")); //打印fasle
/*
* 创建一个正则表达式,用来检查一个字符串是否是一个合法的手机号
* 手机号规则:
* 1 3 345678899
* 1.以1开头
* 2.第二位3-9任意数字
* 3.第三位以后任意数字9个
*/
var phoneRegx = /^1[3-9][0-9]{9}/;
console.log(phoneRegx.test("a18375320276")); //打印false
console.log(phoneRegx.test("18375320276")); //打印true
</script>
正则表达式语法3
<script type="text/javascript">
/*
* 现在我想检查一个字符串中是否含有点"."
* 正则表达式中"."表示任意字符
* 在正则表达式中使用\作为转义字符
*
* 注意:使用构造函数时,由于它的参数是一个字符串,而"\"是字符串中转义字符,
* 所以在字符串中如果要使用\则需要使用\\来代替
*/
//按照我们之前的正则表达式应该这么写
var reg = /./;
console.log(reg.test("abc.ss")); //打印true
console.log(reg.test("abc")) //发现没有点也打印true,其实这个"."在正则里面有特殊含义
reg = /\./;
console.log(reg.test("abc.bcd")) //打印true
console.log(reg.test("abc")); //打印false
//我想检查字符串里面是否包含"\"
reg = /\\/;
// console.log(reg.test("ab\")); //这样写会报错,因为你在字符串里面写"\"也表示转义,斜杠把它后面的引号给转义了,所以报错
console.log(reg.test("abc\\")); //所以在字符里面写"\"要写两个,不然它就表示转义符号
var reg1 = new RegExp("\.");
console.log(reg1.test("aa")); //打印true
console.log(reg1); //打印/./ 这个正则表示匹配任意字符,所以上面打印true就不奇怪了
reg1 = new RegExp("\\.");
console.log(reg1.test("aa")); //打印fasle
console.log(reg1); //打印/\./
/*
* \w 表示任意字母、数字、下划线 相当于=>[A-z0-9_]
* \W 除了字母、数字、下划线 相当于=>[^A-z0-9_]
* \d 表示任意数字 相当于=>[0-9]
* \D 表示除了数字 相当于=>[^0-9]
* \s 表示空格
* \S 表示除了空格
* \b 表示单词边界
* \B 表示除了单词边界
*/
reg = /\w/;
console.log(reg.test("a")); //打印true
console.log(reg.test("1313")); //打印true
console.log(reg.test("_")); //打印true
console.log(reg.test("@##")); //打印false
reg = /\W/;
console.log(reg.test("a")); //打印false
console.log(reg.test("@#$")); //打印true
reg = /\d/;
console.log(reg.test("123")); //打印true
console.log(reg.test("abc")); //打印false
reg = /\D/;
console.log(reg.test("123")) //打印false
console.log(reg.test("abc")); //打印true;
console.log(reg.test("@#$%")); //打印true
reg = /\s/;
console.log(reg.test("a b")); //打印true
reg = /\S/;
console.log(reg.test("fs#%$f")); //打印true
console.log(reg.test(" ")); //打印false
/*
* 创建一个正则表达式检查一个字符串中是否含有单词child
*/
//平常我们可能会这么写
reg = /child/;
console.log(reg.test("hello child")); //打印true
console.log(reg.test("hello children")); //打印true,这样就有问题了,这个字符串中的单词是children而不是child
//所以我们应该这么写
reg = /\bchild\b/; //这个就表示child前面是一个单词边界后面也是一个单词边界
console.log(reg.test("hello children")); //打印false
console.log(reg.test("hello child ren")); //打印true
/*
* 去掉字符串中的空格
* 去掉空格就是使用""来替换空格
*/
var str = " he llo ";
str = str.replace(/\s/g,""); //注意这里一定加一个匹配模式g,不然它只会给你替换一个空格,而不是所有空格
console.log(str); //打印hello
//使用正则表达式去除开头的空格
str = " he llo ";
str = str.replace(/^\s/g,""); //就是把开头的空格替换为空串
console.log(str); //打印" he llo ",你会发现明明我已经加了g全局匹配模式,但它还是只给我去了一个空格,因为我们只去除开头的空格,在h前面所有的空格中,只有第一个空格表示开头的空格,所有就只有这个空格被去除了
//如果我们想去除h前面的所有空格可以这么写
str = " he llo ";
str = str.replace(/^\s*/,""); //表示开头0个或多个空格给替换成空串
console.log(str); //打印"he llo "
//去除o后面的所有空格
str = " he llo ";
str = str.replace(/\s*$/,""); //*表示0个或多个,末尾0个或多个空格替换为空串
console.log(str); //打印" he llo"
//使用正则表达式去除前后空格
str = " he llo ";
str = str.replace(/^\s*|\s*$/g,""); //两个结合起来,中间加个或者
console.log(str); //打印he llo
</script>
- DOM,全称Document Object Model 文档对象模型
- DOM是干嘛的?说白了就是可以让我们可以通过JS随心所欲的操控网页
- 文档
- 文档表示的就是整个HTML网页文档
- 对象
- 对象表示将网页中的每一个部分都转换为了一个对象
- 模型
- 使用模型来表示对象之间的关系,这样方便我们获取对象
- 节点:Node-------构成HTML文档最基本的单元
- 常用节点分为四类
- 文档节点:整个HTML文档
- 元素节点:HTML文档中的HTML标签
- 属性节点:元素的属性
- 文本节点:HTML标签中的文本内容
nodeName | nodeType | nodeValue | |
---|---|---|---|
文档节点 | #document | 9 | null |
元素节点 | 标签名 | 1 | null |
属性节点 | 属性名 | 2 | 属性值 |
文本节点 | #text | 3 | 文本内容 |
这三个属性 『nodeName』 『nodeType』『nodeValue』每个节点都有
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button id="btn">我是一个按钮</button>
<script type="text/javascript">
/*
* 浏览器已经为我们提供了文档节点对象,这个对象是window对象的属性
* 可以在页面中直接使用,文档节点代表的是整个网页
*/
//获取到button对象
var btn = document.getElementById("btn");
console.log(btn.innerHTML); // innerHTML表示内部的HTML代码,这句话的意思就是我打印一下btn这个对象内部的HTML代码,这个btn对象内部的HTML代码就是"我是一个按钮"
</script>
<!--innerHTML用于获取元素内部的HTML代码,对于自结束标签这个属性没有意义(获取不到) -->
</body>
</html>
- 事件,就是用户和浏览器之间的交互行为
- JavaScript 与 HTML 之间的交互是通过事件实现的
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button id="btn">我是一个按钮</button>
<script type="text/javascript">
//获取按钮对象
var btn = document.getElementById("btn");
/*
* 可以为按钮的对应事件绑定处理函数的形式来响应事件
* 这样当事件被触发时,其对应的函数将会被调用
*/
//绑定一个单击事件
btn.onclick = function() { //可以理解成btn对象的onclick属性,属性值是一个函数
alert("点击啦");
}
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
/*
* onload事件会在整个页面加载完成之后触发
* 为window对象绑定一个onload事件
* 该事件对应的响应函数会在整个页面加载完成之后执行,这样可以确保我们的代码执行时所有的DOM对象已经加载完毕了
*/
window.onload = function() {
var btn = document.getElementById("btn");
btn.onclick = function() {
alert("点击啦");
};
};
</script>
</head>
<body>
<button id="btn">我是按钮</button>
</body>
</html>
- 通过 document 对象调用
- getElementById() 通过id属性获取一个元素节点对象
- getElementsByTagName() 通过标签名获取一组元素节点对象
- getElementsByName() 通过name 属性获取一组元素节点的对象
- 通过具体的元素节点调用
- getElementsByTagName() 方法,返回当前节点的指定标签名后代节点
- childNodes 属性,表示当前节点的所有子节点。这个属性会获取包括文本节点在内的所有节点,根据DOM标准,标签间空白也会当成文本节点。注意,在IE8及以下浏览器中,不会将空白文本当成子节点。
- firstChild 属性,表示当前节点的第一个子节点
- lastChild 属性,表示当前节点的最后一个子节点
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
window.onload = function() {
var city = document.getElementById("city");
alert(city.childNodes.length); //获取包括文本节点在内的所有子节点
/*
* children属性可以获取当前元素的所有子元素
*/
var eles = city.children;
alert(eles.length); //打印4
var text = city.firstChild;
alert(text); //拿到的是一个空白文本节点,因为ul标签和li标签之间有空格
/*
* firstElementChild 不支持IE8及以下浏览器
*/
var elementNode = city.firstElementChild;
alert(elementNode.innerHTML); //获取到的是<li id="bj">北京</li>这个节点,打印"北京"
}
</script>
</head>
<body>
<div class="inner">
<p>
你喜欢哪个城市?
</p>
<ul id="city">
<li id="bj">北京</li>
<li>上海</li>
<li>东京</li>
<li>首尔</li>
</ul>
</div>
</body>
</html>
- 通过具体的节点调用
- parentNode 属性,表示当前节点的父节点
- previousSibling 属性,表示当前节点的前一个兄弟节点
- nextSibling 属性,表示当前节点的后一个兄弟节点
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
window.onload = function() {
//定义一个函数,专门用来为指定元素绑定单击响应函数
/*
* 参数:
* idStr 要绑定单击响应函数的对象的id属性值
* fun 事件的回调函数,当单击该元素时,该函数将会被触发
*/
function myclick(idStr,fun) {
var btn = document.getElementById(idStr);
btn.onclick = fun;
}
var bj = document.getElementById("bj");
alert(bj.parentNode.innerHTML); //获取"北京"节点的父节点,它的innerHTML内容就是ul里面的几个li节点
/*
* innerText
* 该属性可以获取到元素内部的文本内容
* 它和innerHTML类似,不同的是它会自动将html代码去除
*/
// alert(bj.parentNode.innerText); //打印"city"节点里面的文本内容,"北京 上海 东京 首尔"
//获取id为dj节点的前一个兄弟节点
var dj = document.getElementById("dj");
alert(dj.previousSibling); //打印[object Text],"dj"节点前一个节点是一个空白文本节点
alert(dj.previousElementSibling.innerHTML); //获取"dj"节点前一个元素兄弟节点,(previousElementSibling这个属性IE8及以下不支持)
alert(dj.nextSibling); //获取下一个兄弟节点,可以是文本节点
//读取id为username元素的value属性值
var username = document.getElementById("username");
alert(username.value); //打印Jimmy
//为id为username元素设置value属性值
username.value="hello";
alert(username.value);
//返回#bj的文本值
/*
* 第一种方法,获取到#bj这个节点,然后直接innerHTML,因为它里面只有"北京"这个两个字
*/
var bj = document.getElementById("bj");
alert(bj.innerHTML); //打印"北京"
/*
* 第二种方法
* "北京"是一个文本节点,而且是#bj这个元素节点的子节点,而且是第一个子节点
* 所以我可以先获取到这个文本节点,然后再获取这个文本节点的文本内容
*/
var textNode = bj.firstChild; //获取到这个文本节点
alert(textNode.nodeValue); //获取这个文本节点的文本内容
}
</script>
</head>
<body>
<div class="inner">
<p>
你喜欢哪个城市?
</p>
<ul id="city">
<li id="bj">北京</li>
<li>上海</li>
<li id="dj">东京</li>
<li>首尔</li>
</ul>
<input type="text" id="username" value="Jimmy" />
</div>
</body>
</html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>全选练习</title>
<script type="text/javascript">
window.onload = function(){
//获取全选按钮对象
var checkedAllBtn = document.getElementById("checkedAllBtn");
checkedAllBtn.onclick = function() {
//获取四个多选框的items
var items = document.getElementsByName("items");
//遍历items
for (var i = 0; i < items.length; i++) {
//通过多选框的checked属性可以来获取或设置多选框的选中状态
items[i].checked = true; //设置四个多选框变成选中状态
}
}
//获取全不选按钮对象
var checkedNoBtn = document.getElementById("checkedNoBtn");
checkedNoBtn.onclick = function() {
//获取四个多选框的items
var items = document.getElementsByName("items");
//遍历items
for (var i = 0; i < items.length; i++) {
//通过多选框的checked属性可以来获取或设置多选框的选中状态
items[i].checked = false; //设置四个多选框变成全不选状态
}
}
//获取反选按钮对象
var checkedRevBtn = document.getElementById("checkedRevBtn");
checkedRevBtn.onclick = function() {
//获取四个多选框的items
var items = document.getElementsByName("items");
for (var i = 0; i < items.length; i++) {
/*//判断多选框状态
if (items[i].checked) {
//证明多选框已选中,则设置为没选中
items[i].checked = false;
} else {
//证明多选框没选中,则设置为选中状态
items[i].checked = true;
}*/
//上面代码的意思就是,如果是true,我就给它设置成false。如果是false,我就给它设置成true
//所以可以直接这么写
items[i].checked = !items[i].checked; //一行代码搞定
}
}
//获取提交按钮对象,将所有选中的多选框的value属性值弹出
var sendBtn = document.getElementById("sendBtn");
sendBtn.onclick = function() {
var items = document.getElementsByName("items");
for (var i = 0; i < items.length; i++) {
if (items[i].checked) {
alert(items[i].value);
}
}
}
//获取 全选/全不选 按钮对象
var checkedAllBox = document.getElementById("checkedAllBox");
checkedAllBox.onclick = function() {
var items = document.getElementsByName("items");
for (var i = 0; i < items.length; i++) {
//全选/全不选 这个多选框,当它选中时,其余也选中,当它取消时,其余的也取消
items[i].checked = this.checked;
}
}
/*
* 如果四个多选框全都选中,则checkedAllBox也应该选中
* 如果四个多选框没都选中,则checkedAllBox也不应该选中
*/
//为四个多选框分别绑定响应函数
var itemsInput = document.getElementsByName("items");
for (var i = 0; i < itemsInput.length; i++) {
itemsInput[i].onclick = function() { //只要我一点击四个多选框中的一个我就把checkedAllBox设置为选中状态
//将checkedAllBox设置为选中状态
checkedAllBox.checked = true;
for (var j = 0; j < itemsInput.length; j++) { //再遍历四个多选框
if (!itemsInput[j].checked) { //如果有一个没选中,我就让checkedAllBox设置为没选中状态
checkedAllBox.checked = false;
//一旦进入判断,就得出结果证明不是全选状态,就不用再继续循环下去了,所以为了提升效率,加个break
break;
}
}
}
}
}
</script>
</head>
<body>
<form method="post" action="">
你爱好的运动是?<input type="checkbox" id="checkedAllBox" />全选/全不选
<br />
<input type="checkbox" name="items" value="足球" />足球
<input type="checkbox" name="items" value="篮球" />篮球
<input type="checkbox" name="items" value="羽毛球" />羽毛球
<input type="checkbox" name="items" value="乒乓球" />乒乓球
<br />
<input type="button" id="checkedAllBtn" value="全 选" />
<input type="button" id="checkedNoBtn" value="全不选" />
<input type="button" id="checkedRevBtn" value="反 选" />
<input type="button" id="sendBtn" value="提 交" />
</form>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
window.onload = function() {
//获取body标签
// var body = document.getElementsByTagName("body")[0];
console.log(body); //打印[object HTMLBodyElement]
//上面这种获取body标签比较麻烦
/*
* 在document中有一个属性body,它保存的是body的引用
*/
var body = document.body;
console.log(body); //打印[object HTMLBodyElement]
/*
* document.documentElement 保存的是html根标签
*/
var html = document.documentElement;
console.log(html); //打印[object HTMLHtmlElement]
/*
* document.all 代表页面中所有的元素
*/
var all = document.all;
console.log(all); //为什么打印undefind?可能是个bug
console.log(all.length); //打印6,这里我可以获取到它的长度,代表页面中有6个元素
for (var i = 0; i < all.length; i++) {
console.log(all[i]); //打印[object HTMLHtmlElement] [object HTMLHeadElement] [object HTMLMetaElement] [object HTMLTitleElement] [object HTMLScriptElement] [object HTMLBodyElement]
}
/*
* 获取页面中所有的元素,也可以用另一种方法,跟 document.all 效果一样
*/
all = document.getElementsByTagName("*");
console.log(all.length); //打印6
/*
* 根据元素的 class 属性值查询一组元素节点对象
* document.getElementsByClassName()可以根据class属性值获取一组元素节点对象
* 但是该方法不支持IE8及以下的浏览器
*/
var box1 = document.getElementsByClassName("box1")
console.log(box1.length) //打印2
//获取页面中所有的div
var divs = document.getElementsByTagName("div");
console.log(divs.length); //打印3
//获取 class 为box1中的所有的 div
/*
* document.querySelector()
* 需要一个选择器的字符串作为参数,可以根据CSS选择器来查询一个元素节点对象
* 使用该方法总会返回唯一的一个元素,如果满足条件的元素有多个,那么它只会返回第一个元素
*/
var divChild = document.querySelector(".box1 div");
console.log(divChild.innerHTML); //打印"我是box1中的div"
/*
* 虽然 IE8 中没有getElementsByClassName()但是可以使用querySelector()代替
*/
var box1div = document.querySelector(".box1");
//这里我虽然查询 class 属性值为box1的,但是这个方法只会给我返回第一个元素
console.log(box1div.innerHTML); //打印 我是第一个div中的元素 <div>我是box1中的div</div>
/*
* document.querySelectorAll()
* 该方法和querySelector()用法类似,不同的是它会将符合条件的元素封装到一个数组里面返回
* 即使符合条件的元素只有一个,它也会返回数组
*/
box1 = document.querySelectorAll(".box1");
console.log(box1.length); //打印2,有两个class属性值为box1的元素
var box3 = document.querySelectorAll("#box3");
console.log(box3); //打印[object NodeList]
}
</script>
</head>
<body>
<div id="box3"></div>
<div class="box1">
我是第一个div中的元素
<div>我是box1中的div</div>
</div>
<div class="box1"></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Untitled Document</title>
<link rel="stylesheet" type="text/css" href="style/css.css" />
<script type="text/javascript">
window.onload = function() {
//创建一个"广州"节点,添加到#city下
myclick("btn01",function() {
//创建 "广州"节点 <li>广州</li>
//先创建li元素节点
/*
* document.createElement()
* 可以用于创建一个元素节点对象,它需要一个标签名作为参数,将会根据标签名创建元素节点对象
* 并将创建好的对象作为返回值返回
*/
var li = document.createElement("li");
//然后创建广州文本节点
/*
* document.createTextNode()
* 可以用来创建一个文本节点对象
* 需要一个文本内容作为参数,将会根据该内容创建文本节点,并将新的节点返回
*/
var gzText = document.createTextNode("广州");
//将gzText节点设置为li的子节点
/*
* appendChild()
* 向一个父节点中添加一个新的子节点
* 用法:
* 父节点.appendChild(子节点);
*/
li.appendChild(gzText);
//将li节点添加到city下
var city = document.getElementById("city");
city.appendChild(gzText);
});
//将 "广州" 节点插入到#bj节点的前面
myclick("btn02",function() {
//创建一个广州节点
var li = document.createElement("li");
var gzText = document.createTextNode("广州");
li.appendChild(gzText);
var bj = document.getElementById("bj");
var city = document.getElementById("city");
/*
* insertBefore()
* 可以在指定的子节点前插入新的子节点
* 语法:
* 父节点.insertBefore(新节点,旧节点)
*/
city.insertBefore(li,bj);
});
//使用"广州"节点替换#bj节点
myclick("btn03",function() {
//创建一个广州节点
var li = document.createElement("li");
var gzText = document.createTextNode("广州");
li.appendChild(gzText);
//获取bj节点
var bj = document.getElementById("bj");
//获取city节点
var city = document.getElementById("city");
/*
* replaceChild()
* 可以使用指定的子节点替换已有的子节点
* 语法:
* 父节点.replaceChild(新节点,旧节点)
*/
city.replaceChild(li,bj);
});
//删除#bj节点
myclick("btn04",function() {
var bj = document.getElementById("bj");
var city = document.getElementById("city");
/*
* removeChild()
* 可以删除一个子节点
* 语法:
* 父节点.removeChild(子节点 )
*/
city.removeChild(bj);
//但是我们更常用这种方法
bj.parentNode.removeChild(bj); //获取到bj节点的父节点,然后通过父节点来删
});
//读取#city内的HTML代码
myclick("btn05",function() {
var city = document.getElementById("city");
var htmls = city.innerHTML;
alert(htmls);
});
//设置#bj内的HTML代码
myclick("btn06",function() {
var bj = document.getElementById("bj");
bj.innerHTML = "bj";
});
//通过innerHTML属性,创建一个"广州"节点,添加到#city下
myclick("btn07",function() {
var city = document.getElementById("city");
/*
* 使用innerHTML也可以完成DOM的增删改的相关操作
* 但是使用这种方式操作动静可能会有点大,相当于把city下面的节点先删了,然后再把新节点给它设置进去
* 要是你原来city下面的节点绑定了事件,使用这种方式新增节点,绑定的事件可能就没了
* 所以一般我们会和上面新增节点的方式,两种方式结合使用
*/
// city.innerHTML += "<li>广州</li>";
//两种方式结合使用
var li = document.createElement("li"); //创建li节点
li.innerHTML = "广州";
city.appendChild(li); //将li节点加到city节点后面
});
}
function myclick(idStr, fun) {
var btn = document.getElementById(idStr);
btn.onclick = fun;
}
</script>
</head>
<body>
<div id="total">
<div class="inner">
<p>
你喜欢哪个城市?
</p>
<ul id="city">
<li id="bj">北京</li>
<li>上海</li>
<li>东京</li>
<li>首尔</li>
</ul>
</div>
</div>
<div id="btnList">
<div><button id="btn01">创建一个"广州"节点,添加到#city下</button></div>
<div><button id="btn02">将"广州"节点插入到#bj前面</button></div>
<div><button id="btn03">使用"广州"节点替换#bj节点</button></div>
<div><button id="btn04">删除#bj节点</button></div>
<div><button id="btn05">读取#city内的HTML代码</button></div>
<div><button id="btn06">设置#bj内的HTML代码</button></div>
<div><button id="btn07">创建一个"广州"节点,添加到#city下</button></div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
window.onload = function() {
var aAll = document.getElementsByTagName("a");
//为每个超链接都绑定一个单击响应函数
for (var i = 0; i < aAll.length; i++) {
aAll[i].onclick = function() {
/**
* 点击超链接以后,超链接会跳转页面,这个是超链接的默认行为
* 但是此时我们不希望出现默认行为,可以通过在响应函数的最后 return false来取消默认行为
*/
//获取当前tr
var tr = this.parentNode.parentNode;
//删除之前弹出一个提示框
/*
* confirm()用于弹出一个带有确认和取消按钮的提示框
* 需要一个字符串作为参数,该字符串将会作为提示文字显示出来
*/
var flag = confirm("是否确认删除?");
if (flag) {
//删除tr
tr.parentNode.removeChild(tr);
}
return false;
}
}
}
</script>
</head>
<body>
<table id="employeeTable">
<tr>
<th>Name</th>
<th>Email</th>
<th>Salary</th>
<th> </th>
</tr>
<tr>
<td>Tom</td>
<td>[email protected]</td>
<td>5000</td>
<td>
<a href="javascript:;">Delete</a>
</td>
</tr>
<tr>
<td>Jerry</td>
<td>[email protected]</td>
<td>8000</td>
<td>
<a href="deleteEmp?id=002">Delete</a>
</td>
</tr>
<tr>
<td>Bob</td>
<td>[email protected]</td>
<td>10000</td>
<td>
<a href="deleteEmp?id=003">Delete</a>
</td>
</tr>
</table>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
window.onload = function() {
var aAll = document.getElementsByTagName("a");
//为每个超链接都绑定一个单击响应函数
for (var i = 0; i < aAll.length; i++) {
alert("for循环开始执行" + i); //会弹出0 1 2 然后for循环执行完毕
/*
* for循环会在页面加载完成后立即执行
* 而响应函数会在超链接被点击时才执行
* 当响应函数执行时,for循环早已执行完毕
*/
aAll[i].onclick = function() {
alert("响应函数开始执行" + i); //这里会永远弹出3, for循环执行完成之后,i=3,这里只有当点击的时候才会执行,而当你点击的时候for循环已经执行完了
}
}
}
</script>
</head>
<body>
<a href="javascript:;">第一个超链接</a>
<a href="javascript:;">第二个超链接</a>
<a href="javascript:;">第三个超链接</a>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>DOM操作CSS</title>
<style type="text/css">
#box1{
width: 100px;
height: 100px;
background-color: red;
}
</style>
<script type="text/javascript">
window.onload = function() {
//获取box1对象
var box1 = document.getElementById("box1");
//为按钮绑定单击响应函数
var btn1 = document.getElementById("btn1");
btn1.onclick = function() {
//修改box1的宽度
/*
* 通过 JS 修改元素的样式
* 语法: 元素.style.样式名 = 样式值
*
* 注意:
* 如果 CSS 的样式名中含有 "-",这种名称在 JS 中是不合法的,比如 background-color
* 所以需要将这种样式名修改为驼峰命名法,去掉"-",然后将"-"后的字母大写
* 像上面background-color 应该改成 backgroundColor
*
* 我们通过style属性设置的样式都是内联样式
* 而内联样式有较高的优先级,所以通过 JS 修改的样式往往会立即显示
* 但是如果在样式中写了!important,则此时样式会有最高的优先级,即使通过 JS 也不能覆盖该样式,此时将会
* 导致 JS 修改样式失效
*/
box1.style.width="200px";
box1.style.height="200px";
// box1.style.background-color="yello"; 这种写法会报错
box1.style.backgroundColor="yellow";
}
//点击按钮2以后,读取元素的样式
var btn2 = document.getElementById("btn2");
btn2.onclick = function() {
//读取box1样式
/*
* 语法:元素.style.样式名
*
* 注意:
* 通过 style 属性设置和读取的都是内联样式
* 无法读取样式表中的样式
*/
alert(box1.style.width); //发现这个弹出来一个空,因为这里的样式是样式表中的样式不是内联样式
}
}
</script>
</head>
<body>
<button id="btn1">点我</button>
<button id="btn2">点我</button>
<div id="box1"></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#box1{
width: 100px;
height: 100px;
background-color: red;
}
</style>
<script type="text/javascript">
window.onload = function() {
//点击按钮后读取box1的样式
var box1 = document.getElementById("box1");
var btn1 = document.getElementById("btn1");
btn1.onclick = function() {
/*
* 获取元素当前显示的样式
* 语法: 元素.currentStyle.样式名
* 它可以用来读取当前元素正在显示的样式(并不是一定读的就是样式表的样式)
* 如果当前元素没有设置该样式,则获取它的默认值
* currentStyle 只有IE浏览器支持,其他浏览器都不支持
*/
// alert(box1.currentStyle.width); //在chrome或者火狐里面没反应,因为这个属性只支持IE
// alert(box1.currentStyle.backgroundColor);
/*
* 在其他浏览器中可以使用getComputedStyle()这个方法来获取元素当前的样式
* 这个方法是 window 的方法,可以直接使用
* 这个方法需要两个参数
* 第一个参数:要获取样式的元素
* 第二个参数:可以传递一个伪元素,但是我们一般都传null
* 该方法会返回一个对象,对象中封装了当前元素对应的样式
* 可以通过 "对象.样式名"来读取样式
* 如果获取的样式没有设置,则会获取到真实的值,而不是默认值
*
* 但是该方法不支持 IE8 及以下浏览器
*/
var obj = getComputedStyle(box1,null); //这个对象中封装了元素对应的样式
alert(obj.width); //假如我div没有设置width,currentStyle会获取样式的默认值,宽度的默认值是auto,而使用该方法会获取当前窗口真实值,当前窗口多大,值就为多少,而不是auto
}
/* ---------------------------------------解决兼容性问题 ------------------------------------*/
/*
* 定义一个函数,用来获取指定元素的当前样式
* 参数:
* obj 要获取样式的元素
* name 要获取的样式名
*/
function getStyle(obj, name) {
if (window.getComputedStyle) { //这里你如果直接写getComputedStyle,在IE8里面它会直接报错,就不走下面的else里面的内容。因为你在这里直接写getComputedStyle,它就是一个变量,这个变量它会先在函数作用域里面找,找不到会去全局作用域里面找,全局作用域要是也找不到就报错。但是如果你写window.getComputedStyle这就表示getComputedStyle是window对象的一个属性,这个属性值要是没有,会报一个undefined而不是报错
//正常浏览器的方式(具有getComputedStyle()方法)
return getComputedStyle(obj,null)[name];
} else {
//IE8的方式(没有getComputedStyle()方法)
return obj.currentStyle[name];
}
}
}
</script>
</head>
<body>
<button id="btn1">点我一下</button>
<div id="box1"></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>其他样式相关的属性</title>
<style type="text/css">
#box1{
width: 100px;
height: 100px;
background-color: red;
padding: 10px;
border: 10px yellow solid;
}
#box2{
padding: 20px;
background-color: greenyellow;
}
#box4{
width: 200px;
height: 300px;
background-color: #bfa;
overflow: auto;
}
#box5{
width: 150px;
height: 500px;
background-color: yellow;
}
</style>
<script type="text/javascript">
window.onload = function() {
var box1 = document.getElementById("box1");
var btn = document.getElementById("btn");
var box4 = document.getElementById("box4");
btn.onclick = function() {
/*
* clientWidth
* clientHeight
* 这两个属性可以获取元素的可见宽度和高度
* 这些属性都是不带px的,返回的都是一个数字,可以直接进行计算
* 会获取元素宽度和高度,包括内容区和内边距
* 这些属性都是只读的,不可修改
*/
alert(box1.clientHeight); //弹出120,高是100px上下各10px的内边距,并不包括边框长度
// box1.clientHeight = 300; //你会发现不起作用,因为这个属性它不仅仅代表一个值,它包括内容区和内边距,你要是修改值它肯定不知道要改哪个值
/*
* offsetHeight
* offsetWidth
* 获取元素的整个宽度和高度,包括内容区、内边距和边框
*/
alert(box1.offsetWidth); //弹出140,包括宽100px,左右内边距各10px,左右边框各10px
/*
* offsetParent
* 可以用来获取当前元素的定位父元素
* 会获取到离当期元素最近的开启了定位的祖先元素,如果所有的祖先元素都没有开启定位,则返回body
*/
var op = box1.offsetParent;
alert(op.id); //弹出box2
/*
* offsetLeft 当前元素相对于其定位元素的水平偏移量
* offsetTop 当前元素相对于其定位元素的垂直偏移量
*/
alert(box1.offsetLeft); //弹出20,box2开启了定位,box1相对于box2的水平偏移量
/*
* scrollHeight
* scrollWidth
* 可以获取元素整个滚动区域的高度和宽度
*/
alert(box4.scrollHeight); //弹出500,box5的高度溢出的父元素,我给box4设置了overflow:auto,它会出现滚动条,这个属性就是获取元素整个滚动区域的高度
/*
* scrollLeft 可以获取水平滚动条滚动的距离
* scrollTop 可以获取垂直滚动条滚动的距离
*/
alert(box4.scrollTop); //现在我滚动条在最上面,弹出的就是0.我要是把滚动条往下拉,这个值也会增大
/*
* 当满足scrollHeight - scrollTop == clientHeight 说明垂直滚动条滚动到底了
* 当满足scrollWidth - scrollLeft == clientWidth 说明水平滚动条滚动到底了
* 这里可以应用于注册的时候的那些细则,只有我读完这些细则,才让你点击"我已阅读内容"的那个单选框
* 那怎么判断它有没有读完?就是当它把滚动条拖到底的时候我就认为你读完了这些细则
*/
alert(box4.clientHeight); //打印300
alert(box4.scrollHeight - box4.scrollTop) //当我把垂直滚动条拖到最底面的时候,这里弹出300
}
}
</script>
</head>
<body>
<button id="btn">按钮</button>
<br />
<div id="box4">
<div id="box5"></div>
</div>
<div id="box2" style="position: relative;">
<div id="box1"></div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#areaDiv {
border: 1px solid black;
width: 300px;
height: 50px;
margin-bottom: 10px;
}
#showMsg {
border: 1px solid black;
width: 300px;
height: 20px;
}
</style>
<script type="text/javascript">
window.onload = function() {
/*
* 当鼠标在areaDiv中移动时,在showMsg中来显示鼠标的坐标
*/
//获取两个div
var areaDiv = document.getElementById("areaDiv");
var showMsg = document.getElementById("showMsg");
/*
* onmousemove 该事件将会在鼠标在元素中移动时被触发
*
* 事件对象
* 当事件的响应函数被触发时(事件的响应函数都是由浏览器去调用的),浏览器每次都会将一个事件对象作为实参传递进响应函数
* 那我想用这个实参怎么办呢?我可以在函括号里面定义一个形参
* 在事件对象中封装了当前事件相关的一切信息,比如:鼠标的坐标,键盘哪个按键被按下,鼠标滚轮滚动的方向
*/
areaDiv.onmousemove = function(event) { //假设这里我没有定义形参,浏览器也会传一个事件对象,不是说你定义形参了浏览器就给你传递事件对象,你要是没有定义形参浏览器就不给你传递事件对象,不是这样的!
/*
* 在IE8中,响应函数被触发时,浏览器不会传递事件对象,
* 在IE8及以下浏览器中,是将事件对象作为window对象的属性保存的
*/
if (!event) { //解决兼容性问题
event = window.event;
}
//或者更简单的写法:
event = event || window.event; //我们说或者是找true,如果传了event对象,就直接返回第一个后面就不看了,如果要是没传event,那event就是undefined转换成布尔就是fasle,那么直接返回第二个
/*
* clientX 可以获取鼠标指针的水平坐标
* clientY 可以获取鼠标指针的垂直坐标
*/
var x = event.clientX; //IE8中应该这么写:var x = window.event.clientX
var y = event.clientY; //IE8中应该这么写:var y = window.event.clientY
showMsg.innerHTML = "x="+ x +"y=" + y;
}
}
</script>
</head>
<body>
<div id="areaDiv"></div>
<div id="showMsg"></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#box1{
width: 100px;
height: 100px;
background-color: red;
}
</style>
<script type="text/javascript">
window.onload = function() {
/*
* 使div可以跟随鼠标移动
*/
// var box1 = document.getElementById("box1");
document.onmousemove = function(event) { //把这个onmousemove事件加给doucument
//解决兼容性问题
event = event || window.event;
/*
* 获取滚动条滚动的距离
* chrome认为浏览器的滚动条是body的,可以通过body.scrollTop来获取
* 火狐等浏览器认为浏览器的滚动条是html的
*/
// var st = document.body.scrollTop; //chrome的方式
// var st = document.documentElement.scrollTop; //火狐或者IE的方式
var st = document.body.scrollTop || document.documentElement.scrollTop; //可以合起来这么写,如果前面可以获取到不是undefined转换成布尔直接就是true,后面就不看可,如果前面是false直接返回后面的
var sl = document.body.scrollLeft || document.documentElement.scrollLeft;
//获取到鼠标坐标
/*
* clientX和clientY
* 用于获取鼠标在当前的可见窗口的坐标
* div的偏移量,是相对于整个页面的
*
* pageX和pageY可以获取鼠标相对于当前页面的坐标
* 但是这两个属性在IE8中不支持,所以如果需要兼容IE8,则不要使用
*/
var left = event.clientX; //这里我们要做的功能是div跟随鼠标移动,当页面出现滚动条时,如果你用clientX或clientY来获取鼠标坐标,你就会发现会出问题,因为这两个属性是获取当前可见窗口坐标,而div是相对于整个页面所以鼠标和div之间就会有段距离
var top = event.clientY; //改成event.pageY就不会有这个问题了,都是相对于当前页面获取坐标
box1.style.position="relative";
box1.style.left = left + sl + "px";
box1.style.top = top + st + "px";
}
};
</script>
</head>
<body>
<div id="box1"></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#box1{
width: 200px;
height: 200px;
background-color: yellowgreen;
}
#s1{
background-color: yellow;
}
</style>
<script type="text/javascript">
window.onload = function() {
/*
* 事件冒泡(Bubble)
* 1.所谓的事件冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
* 2.在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡
*/
var s1 = document.getElementById("s1");
s1.onclick = function(event) { //为span绑定单击响应函数
event = event || window.event;
alert("我是span单击响应函数");
//取消冒泡
//可以将事件对象的cancelBubble设置为true,即可取消冒泡
event.cancelBubble = true; //现在所有浏览器都支持cancelBubble这个属性了,没有兼容性问题
}
var box1 = document.getElementById("box1");
box1.onclick = function() { //为box1绑定单击响应函数
alert("我是div单击响应函数");
}
var body = document.body;
body.onclick = function() { //为body绑定单击响应函数
alert("我是body的单击响应函数");
}
}
</script>
</head>
<body>
<div id="box1">
我是box1
<span id="s1">我是span</span>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
window.onload = function() {
//点击按钮以后添加超链接
var button = document.getElementById("btn01");
var u1 = document.getElementById("u1");
button.onclick = function() {
//创建一个li
var li = document.createElement("li");
li.innerHTML = "<a href='javascript:;' class='link'>新超链接</a>";
u1.appendChild(li);
}
/*
* 为每一个超链接都绑定一个单击响应函数
* 这里我们为每一个超链接都绑定了一个单击响应函数,这种操作比较麻烦
* 而且这些操作只能为已有的超链接设置事件,而新添加的超链接必须重新绑定(因为我页面刚加载的时候,你还没新建超链接所以肯定没绑上)
*/
/*var allA = document.getElementsByTagName("a");
for (var i = 0; i < allA.length; i++) {
allA[i].onclick = function() { //这种方式不推荐使用,一方面麻烦,一方面性能也不好,假设我有1000个超链接那这里就要绑定1000次
alert("aa");
}
}*/
/*
* 我们希望,只绑定一次事件,即可应用到多个事件上,即使元素是后添加的
* 我们可以尝试将其绑定给元素的共同的祖先元素
*
* 事件的委派:
* 1.指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件被触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件
* 2.事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
*/
u1.onclick = function(event) { //但是这样会有一个问题,因为我事件是绑定给ul的,所以在ul的范围内,我点击都会触发这个事件
event = event || window.event;
/*
* target
* event中的target表示的是触发事件的对象
*/
// alert(event.target);//(比如说这个onclick事件是由li触发的那么这个target就是li,要是这个onclick的事件是由a触发的,那么这个target就是a)
//如果触发事件的对象是我们期望的元素,则执行否则不执行
if (event.target.className == 'link') {
alert("点击啦");
}
}
}
</script>
</head>
<body>
<button id="btn01">添加超链接</button>
<ul id="u1">
<li><a href="javascript:;" class="link">超链接一</a></li>
<li><a href="javascript:;" class="link">超链接二</a></li>
<li><a href="javascript:;" class="link">超链接三</a></li>
</ul>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>事件的绑定</title>
<script type="text/javascript">
window.onload = function() {
/*var obj = {"dd":function(){
alert("aa");
}};
alert("***" + obj.dd);*/ //判断obj这个对象里面有没有dd这个方法,这里会弹出dd的属性值
var btn01 = document.getElementById("btn01");
/*
* 使用 对象.事件=函数 的形式绑定响应函数,它只能同时为一个元素的一个事件绑定一个响应函数,
* 不能绑定多个,如果绑定了多个,则后边的会覆盖前边的
*/
//为btn01绑定第一个响应函数
/*btn01.onclick = function() {
alert("1");
};
//为btn01绑定第二响应函数
btn01.onclick = function() { //再一次绑定就会把前面那个给覆盖掉
alert("2");
};*/
/*
* addEventListener()
* --通过这个方法也可以为元素绑定响应函数
* --参数:
* 1.事件的字符串,不要on
* 2.回调函数,当事件触发时该函数会被调用
* 3.是否在捕获阶段触发事件,需要一个布尔值,一般都传false
* 使用addEventListener()可以同时为一个元素的相同事件同时绑定多个响应函数,
* 这样当事件被触发时,响应函数将会按照函数的绑定顺序执行
* 这个方法不支持IE8及以下的浏览器
*/
/*btn01.addEventListener("click",function(){
alert("1");
alert(this); //弹出[object HTMLButtonElement]
},false);
btn01.addEventListener("click",function(){ //会按照顺序弹出1,2
alert("2");
},false);*/
/*
* attachEvent()
* --在IE8中可以使用attachEvent()来绑定事件
* --参数:
* 1.事件的字符串,要on
* 2.回调函数
* --这个方法也可以同时为一个事件绑定多个处理函数,不同的是它是后绑定先执行,执行顺序和addEventListener()相反
*/
btn01.attachEvent("onclick",function() {
alert(this); //弹出[object window]
alert("1");
});
btn01.attachEvent("onclick",function() {
alert("2");
});
btn01.attachEvent("onclick",function() { //会弹出3,2,1
alert("3");
});
//****************定义一个函数,用来为指定元素绑定响应函数**************************
/*
* addEventListener() 中的this 指的是绑定事件的对象
* attachEvent() 中的this 是window对象
* 需要统一两个方法this
*/
/*
* 参数:
* obj 要绑定事件的对象
* eventStr 事件的字符串(要绑定哪个事件)
* callback 回调函数
*/
function bind(obj, eventStr, callback) {
//判断obj这个对象里面是否有addEventListener()这个方法
if (obj.addEventListener) {
//大部分浏览器兼容的方式
obj.addEventListener(eventStr,callback,false);
} else {
/*
* 解决一下this不统一问题,在attachEvent()中 this 是表示window对象
* callback.call(obj) 这个call()方法可以修改函数this,之前有说过
*/
//IE8及以下浏览器
// obj.attachEvent("on"+eventStr,callback); //现在这里callback这个回调函数是由浏览器调用的,现在我不想让浏览器调用,想把调用回调函数的权利给拿回来
//怎么拿回来呢?
obj.attachEvent("on"+eventStr,function() { //这里我不传callback了,传一个匿名函数,到时候浏览器调用就调用我这个匿名函数
callback.call(obj); //我在匿名函数里面再调用callback
//上面那个callback是浏览器调用的,这里的这个callback就变成我们自己调用的了,浏览器调用的是
//匿名函数,我们自己调用,想怎么调用就怎么调用,所以就可以使用call()方法修改函数的this
});
}
}
};
</script>
</head>
<body>
<button id="btn01">我是按钮</button>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#box1{
width: 300px;
height: 300px;
background-color: yellowgreen;
}
#box2{
width: 200px;
height: 200px;
background-color: yellow;
}
#box3{
width: 150px;
height: 150px;
background-color: skyblue;
}
</style>
<script type="text/javascript">
window.onload = function() {
var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");
var box3 = document.getElementById("box3");
//为三个div分别绑定单击响应函数
bind(box1,"click",function() { //点击box1会先弹出box1再弹出box2再弹出box3
alert("box1");
});
bind(box2,"click",function() {
alert("box2");
});
bind(box3,"click",function() {
alert("box3");
});
};
/*
* 事件的传播
* -关于事件的传播网景公司和微软公司有这不同的理解
* -微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,然后再向当前元素的祖先元素上传播,
* 也就是说事件应该在冒泡阶段执行
* -网景公司认为事件应该是由外向内传播的,也就是当事件触发时,应该先触发当前元素的最外层的祖先元素的事件,然后再向内传播给后代元素
* -W3C综合了两个公司的方案,将事件传播分成了三个阶段
* 1.捕获阶段
* 在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
* 2.目标阶段
* 事件捕获到目标元素,捕获结束开始在目标元素上触发事件
* 3.冒泡阶段
* 事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件
* -如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true.一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false
* -对于IE8及以下浏览器来说,是没有捕获阶段的,只有冒泡阶段
*/
function bind(obj, eventStr, callback) {
if (obj.addEventListener) {
obj.addEventListener(eventStr,callback,false);
} else {
obj.attachEvent("on"+eventStr,function() {
callback.call(obj);
});
}
};
</script>
</head>
<body>
<div id="box1">
<div id="box2">
<div id="box3"></div>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>鼠标滚轮事件</title>
<style type="text/css">
#box1{
width: 100px;
height: 100px;
background-color: red;
}
</style>
<script type="text/javascript">
window.onload = function() {
/*
* 当鼠标滚轮向下滚动时,box1变长
* 当鼠标滚轮向上滚动时,box1变短
*/
var box1 = document.getElementById("box1");
/*
* onmousewheel 鼠标滚轮滚动事件,会在滚轮滚动时触发,但是火狐不支持该属性
* 在火狐中需要使用DOMMouseScroll 来绑定滚动事件
*/
box1.onmousewheel = function(event) {
event = event || window.event;
//鼠标滚轮向上滚wheelDelta值为120,向下滚wheelDelta值为-120
//wheelDelta这个值我们不看大小,只看正负
// alert(event.wheelDelta);
//wheelDelta这个属性火狐中不支持,在火狐中使用event.detail来获取滚动的方向
//滚轮向上滚值为-3,滚轮向下滚值为3
// alert(event.detail);
//判断鼠标滚轮滚动的方向
if (event.wheelDelta > 0 || event.detail < 0) {
box1.style.height = box1.clientHeight + 10 + "px";
} else {
box1.style.height = box1.clientHeight -10 + "px";
}
/*
* 使用addEventListener()方法绑定响应函数,取消默认行为时不能使用 return false(不起作用),
* 需要使用event.preventDefault()来取消默认行为
* 但是IE8不支持event.preventDefault(),如果你直接调用的话会报错
*/
// event.preventDefault(); 所以可以这么写
event.preventDefault && event.preventDefault(); //如果event有preventDefault这个属性,那么我就直接用"&"后面的,没有就不用
/*
* 说明:
* 当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动,这是浏览器的默认行为,
* 如果不希望发生,则可以取消默认行为
*/
return false;
};
//为火狐绑定鼠标滚轮事件
bind(box1,"DOMMouseScroll",box1.onmousewheel);
function bind(obj, eventStr, callback) {
if (obj.addEventListener) {
obj.addEventListener(eventStr,callback,false);
} else {
obj.attachEvent("on"+eventStr,function() {
callback.call(obj);
});
}
};
}
</script>
</head>
<body>
<div id="box1"></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>键盘事件</title>
<script type="text/javascript">
window.onload = function() {
/*
* 键盘事件
* onkeydown
* 1.按键被按下事件
* 2.对于onkeydown来说如果一直按着某个键不松手,则事件会一直触发
* 3.当onkeydown连续触发时,第一次和第二次之间会间隔稍微长一点,其它的会非常快,这种设计是为了防止误操作的发生
* onkeyup
* 1.按键被松开事件
* 键盘事件一般都会绑定给一些可以获取到焦点的对象或者是document
*/
document.onkeydown = function(event) {
event = event || window.event;
/*
* 可以通过keyCode来获取按键的编码
* 通过它可以判断哪个按键被按下
* 除了keyCode,事件对象中还提供了几个属性
* altKey
* ctrlKey
* shiftKey
* 这三个用来判断 alt ctrl 和 shift 是否被按下,如果按下则返回 true,否则返回 false
*/
//比如我现在想知道ctrl的keyCode值是多少,那我就可以这样:
// console.log(event.keyCode); //然后你按一下ctrl就会出来它的编码
if (event.keyCode === 89) { //y的unicode编码是89(其实就是unicode码)
console.log("y键被按下了");
}
}
var input = document.getElementsByTagName("input")[0];
input.onkeydown = function(event) {
event = event || window.event;
/*
* 在文本框中输入内容,属于onkeydown的默认行为
* 如果在onkeydown中取消了默认行为,则输入的内容,不会出现在文本框中
*/
//利用这个特性我们可以做一个小功能,比如我们让文本框中不能输入数字
//数字的keyCode是 48-57 (0-9)
if (event.keyCode >= 48 && event.keyCode <= 57) {
return false; //这样你会发现在文本框中输入数字是没有反应的
}
}
}
</script>
</head>
<body>
<input type="text" />
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#box1{
width: 100px;
height: 100px;
background-color: red;
position: absolute;
}
</style>
<script type="text/javascript">
window.onload = function() {
var box1 = document.getElementById("box1");
var speed = 10;
document.onkeydown = function(event) {
switch (event.keyCode){
case 37:
box1.style.left = box1.offsetLeft - speed + "px";
break;
case 39:
box1.style.left = box1.offsetLeft + speed + "px";
case 38:
box1.style.top = box1.offsetTop - speed + "px";
case 40:
box1.style.top = box1.offsetTop + speed + "px";
}
}
}
</script>
</head>
<body>
<div id="box1"></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
/*
* BOM
* 1.浏览器对象模型
* 2.BOM可以使我们通过JS来操作浏览器
* 3.在BOM中为我们提供了一组对象,用来完成对浏览器的操作
* BOM对象
* 1.Window
* 代表的是整个浏览器窗口,同时window也是网页中的全局对象
* 2.Navigator
* 代表的是当前浏览器的信息,通过该对象可以来识别不同的浏览器
* 3.Location
* 代表的是当前浏览器的地址栏信息,通过Location可以获取地址栏信息,或者操作浏览器跳转页面
* 4.History
* 代表浏览器的历史记录,可以通过该对象来操作浏览器的历史记录。由于隐式原因,该对象不能获取到具体的历史记录,
* 只能操作浏览器向前或向后翻页。而且该操作只在当次访问时有效(也就是说你浏览器关了,再次打开,就无效了)
*
* 这些BOM对象在浏览器中都是作为window对象的属性保存的,可以通过window对象来使用,也可以直接使用
*/
console.log(window.navigator); //或者直接写console.log(navigator);
console.log(location);
</script>
</head>
<body>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript">
/*
* Navigator
* - 代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器
* - 由于历史原因,Navigator对象中的大部分属性都已经不能帮助我们识别浏览器了
* - 一般我们只会使用userAgent来判断浏览器的信息,
* userAgent是一个字符串,这个字符串中包含有用来描述浏览器信息的内容,
* 不同的浏览器会有不同的userAgent
*
* 火狐的userAgent
* Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
*
* Chrome的userAgent
* Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36
*
* IE8
* Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
*
* IE9
* Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
*
* IE10
* Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
*
* IE11
* Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; rv:11.0) like Gecko
* - 在IE11中已经将微软和IE相关的标识都已经去除了,所以我们基本已经不能通过UserAgent来识别一个浏览器是否是IE了
*/
//alert(navigator.appName);
var ua = navigator.userAgent;
console.log(ua);
if(/firefox/i.test(ua)){
alert("你是火狐!!!");
}else if(/chrome/i.test(ua)){
alert("你是Chrome");
}else if(/msie/i.test(ua)){
alert("你是IE浏览器~~~");
}else if("ActiveXObject" in window){
alert("你是IE11,枪毙了你~~~");
}
/*
* 如果通过UserAgent不能判断,还可以通过一些浏览器中特有的对象,来判断浏览器的信息
* 比如:ActiveXObject
*/
/*if("ActiveXObject" in window){
alert("你是IE,我已经抓住你了~~~");
}else{
alert("你不是IE~~~");
}*/
/*alert("ActiveXObject" in window);*/
</script>
</head>
<body>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>history</title>
<script type="text/javascript">
/*
* History
* 对象可以用来操作浏览器向前或向后翻页
*/
/*
* length
* 属性,可以获取到当次访问的链接数量(你页面一关它就又重新计数了)
*/
alert(history.length);
window.onload = function() {
var btn = document.getElementById("btn");
btn.onclick = function() {
/**
* back()
* 可以用来回退到上一个页面,作用和浏览器的回退按钮一样
*/
history.back(); //现在只要我一点击按钮,页面就会回退到上一个页面
/**
* forward()
* 可以跳转到下一个页面,作用和浏览器的前进按钮一样
*/
history.forward();
/**
* go()
* 可以用来跳转到指定页面
* 它需要一个整数作为参数
* 1:表示向前跳转一个页面,相当于forward()
* ` 2:表示向前跳转两个页面
* -1:表示向后跳转一个页面
* -2:表示向后跳转两个页面
*/
history.go(2);
};
};
</script>
</head>
<body>
<button id="btn">我是按钮</button>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
/*
* Location
* 该对象封装了浏览器地址栏信息
*/
window.onload = function() {
var btn = document.getElementById("btn");
btn.onclick = function() {
//如果直接打印location,则可以获取到地址栏的信息(当前页面的完整路径)
alert(location); //弹出http://127.0.0.1:8020/jsfour/location.html
//如果直接将location属性修改为一个完整的路径或相对路径,则页面会自动跳转到该路径
location = "http://www.baidu.com";
/**
* assign()
* 用来跳转到其他页面,作用和直接修改location一样
* 会生成历史记录,你可以点击回退按钮回退到上一个连接的页面
*/
location.assign("http://www.baidu.com");
/**
* reload()
* 用于重新加载当前页面,作用和刷新按钮一样
* 如果在方法中传递一个true作为参数,则会强制清空缓存刷新
*/
location.reload(true); //强制情况缓存刷新
/*
* replace()
* 可以使用一个新的页面替换当前页面,调用完毕也会跳转页面
* 但是它不会生成历史记录(即不能使用回退按钮进行回退)
*/
location.replace("http://www.baidu.com");
}
};
</script>
</head>
<body>
<button id="btn">我是按钮</button>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
window.onload = function() {
var count = document.getElementById("count");
for (var i = 0; i < 10; i ++) {
count.innerHTML = i;
}
/**
* 定时调用,可以将一个函数,每隔一段时间执行一次
* 参数:
* 第一个参数:回调函数,该函数会每隔一段时间被调用一次
* 第二个参数:每次调用间隔的时间,单位是毫秒
* 返回值:
* 返回一个Number类型的数据,这个数字用来作为定时器的唯一标识
*/
var num = 1;
var timer = setInterval(function(){
count.innerHTML = num++;
if (num == 11) {
/*
* clearInterval()可以接收任何类型的参数,如果参数是一个有效的定时器标识,则停止对应的定时器;如果参数是一个无效的标识,则什么也不做
*/
clearInterval(timer); //用来关闭一个定时器,需要一个定时器标识作为参数,这样将3关闭标识对应定时器
}
},1000); //让这个函数每隔1秒执行一次
};
</script>
</head>
<body>
<h1 id="count"></h1>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
window.onload = function() {
var img1 = document.getElementById("img1");
var imgArray = ["img/1.jpg","img/2.jpg","img/3.jpg","img/4.jpg"];
var index = 0;
var btn01 = document.getElementById("btn01");
var btn02 = document.getElementById("btn02");
/**
* 目前我每点一次按钮,就会开启一个定时器,点击多次就会开启多个定时器,就会导致图片切换速度过快
*/
var timer;
//在开启定时器之前需要将当前元素上的其它定时器关闭(如果不关的话我点很多次,就会开启很多个定时器)
clearInterval(timer);
btn01.onclick = function() {
timer = setInterval(function(){ //因为这里返回的都是同一个timer,所以如果我点击很多次,这个time的值就是最后一次点击的值,导致你关闭定时器的时候也只能关最后一个定时器
index++;
if (index == imgArray.length) {
index = 0;
}
img1.src = imgArray[index];
},1000);
};
btn02.onclick = function() {
clearInterval(timer);
}
}
</script>
</head>
<body>
<img id="img1" src="img/1.jpg"/>
<br />
<button id="btn01">开始</button>
<button id="btn02">关闭</button>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>延时调用</title>
<script type="text/javascript">
window.onload = function() {
var num = 1;
//开启一个定时器
/*setInterval(function(){
console.log(num++);
},3000);*/
/*
* 延时调用
* 延时调用一个函数不马上执行,而是隔一段时间以后再执行,而且只会执行一次。
* 延时调用和定时调用的区别就是,定时调用会执行多次,而定时调用只会执行一次
*
* 延时调用和定时调用实际上可以互相代替的(意思就是我一个定时调用,我只让它调用一次然后就给它关了,它不就变成延时调用了嘛;一个延时调用我让它调用多次,它不就变成定时调用了嘛)
* 在开发中可以根据自己的需要去选择
*/
var timer = setTimeout(function(){
console.log(num++);
},3000);
//使用 clearTimeout() 来关闭一个延时调用
clearTimeout(timer);
}
</script>
</head>
<body>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>类的操作</title>
<style type="text/css">
.b1{
width: 100px;
height: 100px;
background-color: red;
}
.b2{
width: 200px;
height: 200px;
background-color: yellow;
}
</style>
<script type="text/javascript">
window.onload = function() {
var box = document.getElementById("box");
var btn01 = document.getElementById("btn01");
btn01.onclick = function() {
//修改box的样式
/*
* 通过 style 属性来修改元素的样式,每修改一个样式,浏览器就需要重新渲染一次页面
* 这样执行的性能是比较差的,而且这种形式修改多个样式时,也是不方便的(比如我有30个样式要修改,你就要修改30行)
*/
/*box.style.width="200px";
box.style.height="200px";
box.style.backgroundColor="yellow";*/
//现在我希望一行代码,可以同时修改多个样式
//采取方法:修改box的class属性(我把要修改的样式写在一个class名为b2的css样式表中)
/*
* 我们可以通过修改元素的class属性来间接修改样式,这样的话我们只需要修改一次,就可以同时修改多个样式
* 此时浏览器也只需渲染一次页面,性能比较高
* 并且这种方式,可以使js和css进一步分离(原来我是直接通过js去改具体的css样式,现在js只去改class属性名)
*/
box.className="b2";
//如果想在原来class基础上添加,可以这么写
box.className += " b2"; //注意这里要有个空格,不然到时候你两个class会连在一起
};
};
//定义一个函数,用来向一个元素中添加指定的 class 属性值
/*
* 参数:
* obj:要添加class 属性的元素
* cn: 要添加的class值
*/
function addClass(obj,cn){
//检查obj中是否含有cn
if (!hasClass(obj,cn)) {
obj.className += " " + cn; //加个空格是因为防止你新添加的class值和之前的class值连在一起
}
};
/*
* 判断一个元素中是否含有指定的 class 属性值
* 如果有该 class 则返回true,没有返回 false
*/
function hasClass(obj,cn) {
var reg = new RegExp("\\b" + cn + "\\b");
return reg.test(obj.className);
};
/*
* 移除class属性值
*/
function removeClass(obj,cn) {
//创建一个正则表达式
var reg = new RegExp("\\b" + cn + "\\b"); // \b表示单词边界,加这个就是防止我想匹配b2的时候把b2016给匹配到了
//删除class
obj.className = obj.className.replace(reg,""); //用空串去替换正则表达式匹配到的内容
};
/*
* 可以用来切换一个类
* 如果元素中有该类,则删除
* 如果元素中没有该类,则添加
*/
function toggleClass(obj,cn) {
if (hasClass(obj,cn)) {
removeClass(obj,cn);
} else {
addClass(obj,cn);
}
}
</script>
</head>
<body>
<button id="btn01">点击修改box的样式</button>
<br /><br />
<div id="box" class="b1">
</div>
</body>
</html>