0.概述

  1. js是一门客户端脚本语言。js是一种弱类型的动态语言(比如Lua),而Java是一种强类型的语言。
强类型:在开辟变量存储空间时,定义了空间将来存储的数据的数据类型。只能存储固定数据类型的数据。
弱类型:在开辟变量存储空间时,不定义空间将来存储的数据的数据类型。可以存放任意数据类型的数据。

var a = 100;
alert(a);
a = "HelloWorld"; // 变量a可以存放任意数据类型的数据
alert(a);
  1. JS的标准命名为ECMAScript,不同的浏览器厂商对于该标准会有不同的实现。
1. FireFox:JS标准的实现方式是SpiderMonkey
2. Chrome:JS标准的实现方式是V8
3. Internet Explorer:JS标准的实现方式是JScript/Chakra

1.js的三种输出语句

<script type="text/javascript">
		//1.控制浏览器发出一个警告
		//alert("这是第一个js程序");
		
		//2.让计算机在页面中输出内容
		//document.write("这是第一个js程序");
		
		//3.向控制台输出内容
		console.log("这是第一个js程序");
</script>

2.js编写程序语句的位置:

<head>
	<meta charset = "utf-8">
	<title>helloJs</title>
	<!--
		2.方式二:可以将js代码编写在script标签中,script标签的位置随便放。
		定义的位置会影响执行顺序
		script标签可以定义多个
		script标签的type属性默认值为text/javascript
	-->
	<!--
	<script type = "text/javascript">
		alert("这是第二种编写js程序的第二种方式");
	</script>
	-->
	<!--
		3.方式三:将js语句编写在外部以后缀名为.js的文件中
		然后通过script标签的属性src将外部文件引入
	-->
	<script src = "js/ex.js" type = "text/javascript">
	</script>
	
</head>
<body>
	<!--
		1.方式一:可以将js代码编写在标签的属性中,比如说button的onclick
		属性中,a标签的href属性中
		这种方式不推荐使用,因为结构和行为耦合不利于维护
		<button onclick="alert('这是js编写代码的位置的方式之一')">我是一个按钮</button>
	-->
	
	<!-- 点击链接弹出alert()函数中的内容-->
	<a href = "javascript:alert('这是js编写代码的位置的方式之一')">我是一个链接</a>
	<!--
		点完链接后没有反应
	-->
	<a href = "javascript:;">我是一个链接</a>
</body>

3.js中的常量和变量

  1. 变量的声明使用var关键字,也可以不使用。用var定义的变量是局部变量,不用var定义的变量是全局变量(不建议使用全局变量)。
  2. 字面量:一些不可改变的值。比如12,23,"Hello"
<script type = "text/javascript">
	//js中常量变量的使用
	//1.使用var关键字声明局部变量
	var age = 20;
	var height = 175;
    //HelloWorld为常量
	console.log("HelloWorld");
	console.log(age);
	console.log(height);
	
	a = 100;    // 定义一个全局变量
    document.write(a); // 100
</script>

4.js中的数据类型

1.js中共有6种数据类型,js中的数据类型如下:
  1. 基础数据类型(原始数据类型):
1.Number
2.String
3.Null:一个对象为空的占位符,空值.该数据类型只有一个特殊的值null
4.Boolean
5.Undefined:未定义。如果一个变量没有给初始化值,则会被默认赋值为
只有一个特殊的值undefined

note:js中的所有数值都是number类型,比如说小数和整数,NAN。(NAN是一个特殊的数值,在JS中当对数值进行计算没有结果返回。)
2. 引用数据类型

1.Object:对象
  1. 示例
// 字符串使用单引号或者双引号引起来都可以
var str1 = "Hello";
var str2 = 'Hi';
var a = NAN;
var obj = null;
var o;
document.write(a);  // NAN
document.write(obj);// null
document.write(o);  // undefined
2.转义字符\的使用:对特定的字符进行转义
//转义字符\的使用
var str = "\\";	//打印一个字符\
console.log(str);
console.log("Hello\nWorld");

5.js中的typeof关键字

typeof关键字: 检查变量的数据类型

var a = "Hello";
document.writeln(typeof (a))  // string
a = undefined;
document.writeln(typeof (a))  // undefined
a = null;
document.writeln(typeof (a))  // object
a = NaN;
document.writeln(typeof (a))  //number 

6.Number数据类型

1.Number数据类型的最大值和最小值

Number:Number数据类型能表示的值是有范围的,如果超过所能表示的范围则为Infinity

//number类型能够表示的最大数值和最小数值
console.log(Number.MAX_VALUE);  
console.log(Number.MIN_VALUE);

var a = Infinity;
var b = -Infinity;  //表示负无穷
console.log(typeof(a));	//Number类型
console.log("\n");
console.log(typeof(b));	//Number类型
2.Number数据类型的整数的运算基本可以保证精确
var c = 1865789 + 7654321;
console.log(c); // 9520110
3.JS中进行浮点运算

JS进行浮点运算,可能得到一个不精确的结果,所以千万不要使用JS进行对精确度要求比较高的运算

var c = 0.1 + 0.2;
console.log(c); //0.30000000000000004

7.Object与Null数据类型

Null类型的值只有一个,就是null。它表示一个空对象。
当只给一个变量声明却不初始化时,它的值即为undefined

var c = null;
console.log(typeof(c));	//object

var d = undefined;
console.log(typeof(d));	//undefined

8.js中数据类型的转化方法:

1.其他数据类型转化为String类型
//数据类型转换
//方式一:调用被转换数据类型变量的tostring方法
var e = 123;
e = e.toString();	//将Number类型转化位String类型
console.log(typeof(e)); //string
//方式二:使用String()函数
var f = 123;
f = String(f);	////将Number类型转化位String类型
console.log("\n");
console.log(typeof(f)); //string
//方式三:任何NUmber类型和String类型相加,都会转化为字符串然后做拼接操作。
2.其他数据类型转化为Number类型
  1. 将字符串类型转化为Number类型:
1. 如果是纯数字的字符串,则直接将其转化为数字。例如`var b = +"123";    // b为number类型`
2. 如果字符串中包含有非数字的内容,则转化为NAN(一个不是数字的数字)
3. 如果字符串是一个空串或者是一个全是空格的字符串,则转化为0
  1. 将boolean类型转化为Number类型(直接使用一元运算符+)
1. true值转化为1
2. false值转化为0

var a = +true;
var b = +false;
document.write(typeof (a) + typeof (b) + "<br/>");  // nnumber
document.write(a + "<br/>");  // 1
document.write(b + "<br/>");  // 0
  1. null类型转化为Number类型,值为0
var c = +null;
document.write(typeof(c));	// number
  1. undefined类型转化为Number类型,值为NAN
//将其他数据类型转化为Number
var a = "123";

console.log(typeof(a));
console.log(a);
//方式一:使用Number函数
a = Number(a);	//将String类型转化为Number类型
console.log(typeof(a));
console.log(a);

var b = "123Hello";
b = Number(b);
console.log(typeof(b));	//Number
console.log(b);			//值为NAN:not a number 

var c = "";
c = Number(c);
console.log(typeof(c));//number
console.log(c);	//0

var d = "   ";
d = Number(d);
console.log(typeof(d));//number
console.log(d);//值为0

var e = null;
e = Number(e);
console.log(typeof(e));//number
console.log(e);//0

var f = undefined;
f = Number(f);
console.log(typeof(f));//number
console.log(f);	//值为NAN
  1. 注意:将字符串类型转化为Number类型的第二种方法:使用parseInt方法可以将字符串类型转化为整数类型;使用parseFloat方法可以将字符串转化为浮点数类型。
//注意:对于字符串类型转化为Number类型的第二种方式
//使用parseInt或者parseFloat方法
var a = "123Hello";
a = parseInt(a);
console.log(a);	//值为123
console.log(typeof(a));//number类型

a = parseInt(true);
console.log(a);	// NaN
a = parseInt("true");
console.log(a);	// NaN
3.将其他数据类型转化为Boolean类型

将其他数据类型转化为Boolean类型使用Boolean()函数

  1. 将Number类型转化为Boolean类型:除了0和NAN,其余的都是true
// while循环的编写可以这样的
while(1) {
}
  1. 将字符串转化为Boolean类型:除了空串其余的都是true
  2. null和undefined都会转化为false
  3. 对象也会转化为true。
// js中防止空指针异常,可以这样写
var object = null;
if(object) {
    
}
var str = "";   // 空串
console.log(Boolean(str));  // false
// 将判断str是否为空串
if(str) {
    
}

9.js中的算数运算符

1.对于加法运算,一个Number类型和String类型相加,Number类型将会转化为String类型然后进行加法运算。 任何值和字符串相加都会转换为字符串,并作拼串操作。

var result = NaN + "";
console.log(result);	// string类型的NaN
result = undefined + ""
console.log(result); 	// string类型的undefined
result = null + "";
console.log(result);	// string类型的null
result = 123 + "1";
console.log(result); // 1231
result = true + "hello";
console.log(result); // truehello

2.除了加法运算,一个Number类型和String类型进行运算,String类型将会转化为Number类型再进行运算。

var a = 12;
a = a * "12";	//将字符串"12"转化为Number12再进行乘法运算
console.log(a);	//144
console.log(typeof(a));	//number

var b = 12;
b = b + "12";	//将Number类型b转化为String类型再进行运算
console.log(b);	//1212
console.log(typeof(b));	//string

//任何值和NaN做运算都得NaN

10.js中的一元运算符

1.一元运算符
  1. 正号不会对数字产生影响,对于非Number类型的值使用该运算符可以将其转换为Number类型
  2. 负号可以对数字进行取反
var a = 12;
a = -a;
console.log(a);	//-12

//使用一元运算符可以将字符串类型转化为Number类型
//因为使用一元运算符可以将任意数据类型转化为Number类型
var b = "123";
b = +b;
console.log(b);	//123
console.log(typeof(b));//number

var c = "123";
c = -c;
console.log(c);	//-123
console.log(typeof(c));//number

var a = true;
a = +a;
console.log("a = "+a); // 1
console.log(typeof a); // number
  1. 前置加加与后置加加
  2. 前置减减与后置减减

11.js中的逻辑运算符

对于非布尔值进行与或运算时,会先将其转换为布尔值,然后再运算,并且返回原值。

  1. 逻辑与:&&
  2. 逻辑或:||
  3. 逻辑非:!
    注意:对于逻辑与运算,如果两个值都为true,则返回后边的。如果两个值都为false,则返回靠前的false;对于逻辑非运算符则相反。
    比如说:
var results = 12 && 24;	//24
console.log("results = "+ results);

var results0 = 24 && 12;	//12
console.log("results0 = "+ results0);

var results1 = NaN && 0;	//NaN
console.log("results1 = "+ results1);

var results2 = 0 && NaN	//0
console.log("results2 = "+ results2);

12.js中的赋值运算符和复合赋值运算符

13.js中的关系运算符

  1. 对于非数值和数值进行比较时,会将非数值转化为数值后进行比较
  2. 任何值和NaN比较都为false
  3. 对于比较的都是字符串,不会将其转化为数值后进行比较,而是比较字符串中的字符的Unicode编码。
//非数值比较,会将字符串"125"转化为125
console.log(123 < "125");	//true

//比较的都是字符串,则从第一个字符开始比较Unicode
console.log("abc" < "abcd");//true

//任何值和NaN比较值都为false
console.log(123 > NaN);	//false

14.unicode编码的使用

1.再字符串中使用Unicode:格式\u四位Unicode编码(十六进制的)
2.再网页中使用Unicode:格式&#编码(这里的编码使用十进制的)
//再字符串中使用转义字符输出Unicode编码
//使用方式:\u四位编码
console.log("\u0031");	//输出1,因为1的Unicode编码为0031
<!--
再网页中输出Unicode编码
-->
<h1>&#9760;</h1>

image.png

15.全等运算符与不全等运算符

1.全等运算符: 三个等号用来判断两个值是否相等,它和相等运算符类似,不同的是她不会做自动的类型转换。如果两个值的类型不同,直接返回false。

2.不全等运算符:!==用来判断两个值是否不全等,和不等运算符类似,不同的是它不会做自动的类型转换。如果两个值的类型不同,直接返回true。

// 在相等运算符中,null,undefined则不会转化为数字类型,
// 而是经过特殊处理后转化为false
console.log(null == 0); 	//false
console.log(Number(null));	//0

//全等运算符与不全等运算符

console.log(1 === "1");	//false
console.log(1 == "1");	//true,因为相等运算符比较时,将字符串类型转化为number
alert(undefined == null);   // true
alert(undefined === null);  //false

console.log(1 != "1");	//false
console.log(1 !== "1");	//true

注意:1.NaN不和任何值相等,包括它自身。所以判断一个值是否为NaN使用isNaN函数。

var a = NaN;
console.log(a == NaN);//false,因为NaN不和任何值相等,包括他本身
console.log(NaN == NaN);//false

//a的值为NaN,可以通过isNaN函数来判断
console.log(isNaN(a));//true

流程控制语句

1.选择结构
  1. if...else
var age = 35;
if (age < 18) {
	alert("您还未成年!");
}	else if (age <= 30) {
	alert("您处于青少年!");
} else {
	alert("您处于老年!");
}
  1. switch...case:在Java中,switch语句可以接受的数据类型:byte,int,short,char,枚举,String
    在js中,switch语句可以接受任意的原始数据类型。
2.循环结构
  1. while
  2. do...while
  3. for
3.label语句的使用

使用label语句可以在代码中添加标签,以便将来使用。语法为:label:statement

js中的对象

1.js中的对象分类:

  1. 内建对象:由ES标准定义的对象,在任何的ES的实现中都可以使用。比如说:Math,String,Number,Boolean,Function,Object,Date,RegExp,Global
  2. 宿主对象:由js运行环境提供的对象,目前来讲主要是指由浏览器提供的对象:比如说:BOM,DOM.(两个中都有一堆对象)
  3. 用户自定义对象

自定义一个对象举例:

<script type = "text/javascript">
    // 创建对象有两种方式,方式一使用new Object()
    //new一个对象,对象名叫做student
    var student = new Object();
    //给对象添加属性
    student.name = "李华";
    student.age = 20;
    student.gender = "男";
    
    console.log("name:"+student.name);
    console.log("age:"+student.age);
    console.log("gender:"+student.gender);
    
    console.log(typeof(student.name));
    console.log(typeof(student.age));
    console.log(typeof(student.gender));
    
    //删除对象的属性
    delete student.gender;
    console.log("gender:"+student.gender);	//值为undefined
	
	// 创建对象的第二种方式:
	var person = {
		name:"张三",
		age:23,
		toString:function() {
			alert("name:" + this.name + "age:" + this.age);
		}
	}
	alert(person);
</script>

2.访问属性的两种方式:

1. 对象名.属性名
2. 对象名["属性名"]
var student = new Object();
student["name"] = "李华";
console.log(student["name"]);	//李华
student.name = "李华";
console.log(student.name);		//李华

3.in运算符

in运算符:通过该运算符可以检查一个对象是否含有指定的属性,如果返回true则表示存在,返回false表示不存在。

in运算符使用举例:

var student = new Object();
student.name = "李华";
console.log("gender" in student);//false
console.log("name" in student);//true
console.log(name in student);//false

4.使用对象字面量创建对象

//这样再创建对象的同时添加属性并且设置值
//对象字面量的属性名可以加引号也可以不加
var student = {name:"李华",gender:"男",age:20};
console.log("name:"+student.name);
console.log("age:"+student.age);
console.log("gender:"+student.gender);

js中的函数(Function类型的对象)

1.函数:函数也是一个对象,所以函数也是在堆内存中保存的。,函数中可以封装一些代码,需要时可以调用函数执行这些代码。方法或者函数定义时,形参的类型不用写,返回值类型也不写。

2.创建函数对象的几种方式:

  1. 使用构造函数创建函数对象(了解即可)。语法:
// 可以将要封装的代码以字符串的形式传递给构造函数
var objName = new Function(形式参数列表,方法体);//这样调用函数的时候使用objName();.

// 示例
var fun = new Function("a","b","alert(a)");
fun(3,4); 
  1. 使用函数声明来创建一个函数。语法:
function funcName([形参1,形参2,...,形参N]){函数体中的可执行语句}

示例:
function func(a, b) {
    var c = a * b;
    alert(c);
}
func("200", 100);   // 20000
  1. 创建匿名函数对象,语法:推荐使用
var obj = function([形参1,形参2,...,形参N]){函数体中的可执行语句};//创建匿名函数对象将其赋值给一个变量
//调用可以通过obj();

示例:

//方式一:通过构造函数创建函数对象
var printHello = new Function("console.log('Hello');");
printHello();

//方式二:通过函数声明来创建函数对象
function printWorld() {
	console.log("World");
}
printWorld();

//方式三:创建匿名函数对象
var printHelloWorld = function() {
	console.log("HelloWorld");
}
printHelloWorld();
		

3.函数中的参数: 可以在函数的()中指定一个或者多个或者0个形参,在多个形参之间使用逗号隔开。调用函数时可以在()中指定实参。
注意:

  1. 调用函数时解析器不会检查实参的类型,所以要注意,是否可能接受到非法的参数,如果有可能则需要对参数进行类型的检查。
  2. 调用函数时,解析器也不会检查实参的数量,多余实参不会被赋值;如果实参的数量少于形参的数量,则没有对应实参的形参的值将为undefined.
    在js中,函数的调用只与函数的名称有关,和参数列表无关。在函数的声明中,有一个隐藏的内置对象(arguments类数组对象),封装所有的实际参数;还有一个函数的上下文对象this。

示例:

function sum(a,b){
	console.log("b="+b);
	console.log(a + b);
}
//实参的个数多于形参的个数,第三个实参则忽略
sum(100,200,300);	//300
//实参的个数少于形参的个数,则形参b的值为undefined
sum(100);	//100和undefined相加值为NaN(not a number)

// 求未知个数的数的和,利用内置对象arguments类数组对象
function add() {
    var sum = 0;
    for (var i = 0; i < arguments.length; i++) {
      sum += arguments[i];
    }
	console.log(Array.isArray(arguments));	// false
    return sum;
}
var sum = add(100,200,300,400,500);
alert(sum); // 1500

4.函数返回值:使用return关键字;函数返回值可以是任意的数据类型包括对象或者函数 return后的值将会作为函数的执行结果返回,可以定义一个变量,来接收该结果。如果return语句后不跟任何值就相当于返回一个undefined,如果函数中不写return,则也会返回undefined。
比如说:

function printHello(){
	console.log("HelloWorld");
}
//函数内部返回一个函数
function example(){
	return printHello;
}

//var funObj = example();
//funObj();	//HelloWorld

example()();//HelloWorld

5.调用函数的实参: 实参可以是任意数据类型包括对象(函数)。
比如说:

//计算圆的面积函数
function calcu(object){
	return object.r * object.r * 3.14;
}
//定义一个对象,属性r表示半径
var obj = {
	r:10
};
//对象作为参数
var results = calcu(obj);
console.log("results:"+results);	//314

function printMess(funcName){
	console.log("results:"+funcName(obj));//314
}
//函数对象作为参数
printMess(calcu);

6.匿名函数的直接调用(立即执行函数)

//匿名函数的使用
(function(){
	alert("我是一个匿名函数");
})();

var obj = {
	name:"李华",
	age:20
};
(function(obj){
	console.log("name:"+obj.name+"age:"+obj.age);//name:李华age:20
})(obj);
		

7.Function对象的属性length

  1. length属性表示方法或者函数中的形参个数
  2. 函数名或者方法名.length进行访问

8.函数对象的方法

每个函数对象都有两个方法call和apply,需要通过函数对象来调用,可以用来指定一个函数的运行环境对象,就是设置函数执行时的this值。

使用方式:
函数对象.apply(this对象,参数数组)
函数对象.call(this对象,参数1,参数2,参数N)

function func() {
	alert(this.name);
}
var obj1 = {name:"张三"};
var obj2 = {name:"李四"};
func.apply(obj2);
func.call(obj2);

js中的方法

方法: 当函数作为对象的属性值时,我们称这个函数为这个对象的方法。

var student = {
	//属性
	name:"李华",
	age:20,
	gender:"男",
	
	//方法
	printMess:function(){
		console.log("name:"+student.name+"age:"+student.age+"gender:"+student.gender);//name:李华age:20
	}
};
//调用student对象中的方法
student.printMess();

for....in语句

1.for...in语句: for...in语句,对象中有几个属性,循环体就会执行几次;每次执行时,会将对象中的属性的名字赋值给变量。语法如下:

for(var 变量 in 对象){
}

比如说:

var student = {
	//属性
	name:"李华",
	age:20,
	gender:"男",
	
	//方法
	printMess:function(){
		console.log("name:"+student.name+"age:"+student.age+"gender:"+student.gender);//name:李华age:20
	}
};

for(var pros in student){
	console.log("属性名:"+pros);
	console.log("属性值:"+student[pros]);
}

运行如下:
image.png

js中的作用域

1.全局作用域: 编写在script标签中的js代码都在全局作用域。全局作用域再页面打开时创建,再页面关闭时销毁。再全局作用域中有一个全局对象window,他代表的是一个浏览器窗口,它由浏览器创建我们可以直接使用。 再全局作用域中,创建的变量都会作为window对象的属性保存;创建的函数作为window的方法保存。
比如说:

var a = 100;
console.log(window.a);//100

function printHello(){
	console.log("HelloWorld");
}
window.printHello();//HelloWorld
window.alert("HelloWorld");

2.函数作用域(局部作用域)

js中的this关键字

this关键字: 解析器在调用函数或者对象的方法时会向其内部传递一个隐含的参数,这个隐含的参数就是this,this指向的是一个对象的引用。根据调用的方式不同,this会指向不同的对象:

  1. 以函数的形式调用时,this指向的是window对象的引用。
  2. 以方法的形式调用时,this指向调用方法的那个对象的引用。
  3. 当以构造函数的形式调用时,this就是新创建的那个对象。
  4. 使用函数对象的call和apply调用时,this是指定的那个对象。

比如说:

function printHello(){
	console.log("this:"+this);
}
window.printHello();
console.log("\n");

var obj = {
	name:"李华",
	age:20,
	gender:"男",
	
	//对象的方法
	printWorld:function(){
		console.log("this:"+this);
	}
};
obj.printWorld();

运行结果如下:

image.png

js中使用工厂方法创建对象

1.工厂方法可以创建大量对象,比如说:

function createObject(name,age,gender){
	var object = new Object();
	object.name = name;
	object.age = age;
	object.gender = gender;
	
	object.printMess = function(){
		console.log("name:"+this.name+"age:"+this.age+"gender:"+this.gender);
	}
	return object;
}

//创建学生对象
var student = createObject("李华",20,"男");
student.printMess();//name:李华age:20gender:男

//创建老师对象
var teacher = createObject("刘老师",32,"女");
teacher.printMess();//name:刘老师age:32gender:女

使用工厂方法创建的对象,使用的构造函数都是Object,所以创建的对象都是Object类型,导致无法区分多种不同类型的对象。

使用js中的构造函数创建对象

构造函数也称为类,将通过一个构造函数创建的对象,称为是该类的实例

1.构造函数与普通函数的区别: 调用的方式不同。

1. 普通函数直接通过函数名调用,而构造函数通过new关键字调用.
2. 任何函数都可以通过new关键字调用,所以函数都可以是构造函数
3. 构造函数的首字母要大写,来区分用于执行的函数和构造函数

2.构造函数的执行过程:

  1. 立刻创建一个新的对象
  2. 将新创建的对象初始化this,在构造函数体中可以使用this来引用新创建的对象
  3. 执行函数体中的代码
  4. 将新创建的对象返回

举例:

//定义一个构造函数
function Student(name,age,gender) {
	this.name = name;
	this.age = age;
	this.gender = gender;
	console.log(this);	//this即为调用此构造函数返回的新建对象的引用
	
	this.printMess = function() {
		console.log("name:"+this.name+"age:"+this.age+"gender:"+this.gender);
		
	}
}

//通过构造函数创建Student类对象
var student1 = new Student("李华",20,"男");
student1.printMess();//name:李华age:20gender:男

var student2 = new Student("张三",18,"男");
student2.printMess();//name:张三age:18gender:男

2instanceof关键字的应用: 可以检验一个引用变量是否属于某个类
比如说:

console.log(student1 instanceof Student);//true
console.log(student2 instanceof Student);//true
console.log(window instanceof Student);	//false

js中的原型对象

1.原型对象的概念: 创建的每一个函数名或者类名,解析器都会向其添加一个属性prototype(显示原型属性),这个属性对应着一个实例对象,这个实例对象就是原型对象。

function fun1() {
			
}
function fun2() {
	
}
console.log(fun1.prototype);
console.log(fun2.prototype);
console.log(fun1.prototype == fun2.prototype);//false

var obj = new Object();
console.log(obj.prototype);	//undefined
console.log(obj.__proto__)
console.log(Object.prototype);
// 实例对象的隐式原型等于构造函数的显示原型
console.log(obj.__proto__ == Object.prototype); // true

var person = {
    name:'Nrv',
    age:23,
}
console.log(person.__proto__)
console.log(person.prototype) //undefined

2.当函数以构造函数的形式调用时,它所创建的引用变量中都有一个隐含的属性指向该构造函数的原型对象,我们可以通过__proto__(隐式原型属性)来访问这个属性

function Student(name,age,gender) {
	this.name = name;
	this.age = age;
	this.gender = gender;

}
var student1 = new Student("李华",20,"男");
var student2 = new Student("张三",18,"男");

// 原型对象相当于一个公共的区域,所以输出true
console.log(student1.__proto__ == student2.__proto__);//true

var obj = new Object();
console.log(obj.__proto__ == Object.prototype);//true

3.原型对象的应用: 原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问这个原型对象我们创建构造函数时,可以将对象中共有的属性或者方法添加到构造函数的原型对象中。 这个应用类似于C++中类中的静态方法或者静态成员变量。添加静态成员变量或者静态方法就可以为同一个类中的对象所共享。

举例:上诉例子中的printMess方法是为同一个类中的方法共享的,我们可以将其添加到原型对象中

function MyClass() {
				
}
//向MyClass函数对象的原型对象中添加公共方法或者添加公共属性
MyClass.prototype.a = 100;
MyClass.prototype.pringA = function() {
	console.log(this.a);
}
//通过构造函数创建MyClass类对象
var mc = new MyClass();
mc.a = 200;		// 对象自身上有a
mc.pringA();	// 200
var mc2 = new MyClass();
mc2.pringA();	// 100
console.log(mc.pringA == mc2.pringA); //true
console.log(MyClass.prototype == mc.__proto__); // true

function Person(name, age) {
	this.name = name;
	this.age = age;
	this.__proto__.address = "北京大学";
}
var p1 = new Person("张三", 23);
var p2 = new Person("李四", 24);
console.log(p1.address);	// 北京大学
console.log(p2.address);	// 北京大学

访问对象的一个属性或者方法时,他会先在对象自身中寻找,如果有则直接使用;如果没有就会去原型对象中寻找,如果找到就直接使用。
image.png
4.原型链

原型对象也是一个对象,所以它也有原型。 当我们使用一个对象的属性或者方法时,会先在自身中寻找,自身中如果有,则直接使用。如果没有则去该对象的原型对象中寻找,如果原型对象中有,则使用。如果没有则去原型的原型中寻找。直到找到Object这个构造函数对象的原型对象,Object对象的原型没有原型,如果在Object对象的原型中依然没有找到,则返回undefined。

function MyClass() {
				
}
// 向函数对象的原型对象中添加公共属性
MyClass.prototype.name = 100;
var mc = new MyClass();
console.log(mc.__proto__);
// hasOwnProperty可以用来检查对象自身中是否有该属性
// mc对象自身中没有name属性,而是在mc对象的原型对象中
console.log(mc.hasOwnProperty("name"));	// false
console.log(mc.__proto__.hasOwnProperty("name")); //true
console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));// true
// Object对象的原型对象的原型对象为null
console.log(mc.__proto__.__proto__.__proto__);// null 

image.png

5.Function

  1. 所有函数对象的隐式原型属性都相等
function func1() {

}
function func2() {

}
// 每一个函数对象(包括Object对象)都有__proto__属性,其值都指向Function函数对象的原型对象
// 函数对象也是一个实例对象,它是Function的实例
// function func1(){}相当于var func1 = new Function()


console.log(Object.__proto__)   // ƒ () { [native code] }
console.log(typeof Object, typeof Object.__proto__) // function,function
console.log(Object) //ƒ Object() { [native code] }
console.log(func1.__proto__)    // ƒ () { [native code] }
console.log(func2.__proto__)    // ƒ () { [native code] }
console.log(func1.__proto__ === func2.__proto__) //true
console.log(Function.__proto__) //ƒ () { [native code] }
  1. 所有函数都是Function的实例,包括Function
// Function函数对象的隐式原型链属性__proto__
// 和显示原型链属性prototype相等,都指向Function函数对象的原型对象
// 相当于var Function = new Function()
console.log(Function.__proto__) //ƒ () { [native code] }
console.log(Function.prototype) //ƒ () { [native code] }
console.log(Function.__proto__ === Function.prototype) //true
  1. 函数对象的显示原型属性指向的原型对象默认是Object实例对象(但是Object不满足)。
function func() {

}

console.log(func.prototype)
console.log(func.prototype instanceof Object) //true
console.log(Function.prototype) // ƒ () { [native code] }
console.log(Function.prototype instanceof Object) //true

console.log(Object.prototype instanceof Object) //false
  1. Object的原型对象是原型链尽头,Object.prototype 是浏览器底层根据 ECMAScript 规范创造的一个对象。
console.log(Object.prototype.__proto__) //null
  1. 函数对象的原型对象的原型对象和Object的原型对象相等
console.log(Object.prototype === Function.prototype.__proto__) //true

function func() {

}
// 实例对象的隐式原型等于构造函数的显示原型
console.log(func.prototype.__proto__ === Object.prototype) //true

image
6. instanceof关键字
1. 表达式:A(实例对象) instanceof B(构造函数)
2. 如果B的显示原型对象在A对象的原型链上,返回true,否则返回false。

function func() {

}
var f = new func()
console.log(f instanceof func) //true
console.log(f instanceof Object) //true

js中的toString方法(了解即可):

1.当我们在页面中打印一个对象时,实际上输出的是对象的toString方法的返回值。如果我们希望输出对象时不输出[object object],可以为对象添加一个toString方法。这个类似于JAVA中的重写toString方法达到定制的打印对象值的功能的目的。

function Student(name,age,gender) {
  this.name = name;
  this.age = age;
  this.gender = gender;
}
// 向原型中添加公共方法
Student.prototype.toString = function() {
  return "++name:"+this.name+"age:"+this.age+"gender:"+this.gender;
}
var student1 = new Student("李华",20,"男");
console.log(student1);

js中的数组(Array对象):表示一个有序的数组

1.数组对象的创建方式

// 方式1 
var arr = new Array(元素列表);
例如 var arr = new Array(1,2,3,4,5);
// 方式2
var arr = new Array(数组长度);
var arr = new Array();//表示创建一个空的数组
// 方式3
var arr = [元素列表];
var arr = [];

2.js中的数组也是对象类型,通过索引值访问数组元素。

//创建一个空的数组对象
var arr = new Array();

arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
console.log(typeof(arr));//object
//[object Array]: [10, 20, 30]
console.log(arr);

3.数组的特点

  1. js中,数组元素的类型可变。JS的数组中可以保存任意数据类型的数据。
var arr = [1,"abc",true,null,undefined];
  1. js中数组的长度可变:数组对象的属性length可以获取数组的长度
 var arr = [1,"abc",true,null,undefined];
// 索引越界,会进行自动扩容。未初始化的元素的值为undefined
document.write(arr[10]);  // ubdefined
arr[10] = 100;
document.write(arr.length); // 11

4.数组对象中的方法

  1. join方法:将数组中的元素按照指定的分隔符拼接为字符串,如果不指定连接符,则默认使用逗号作为连接符。该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回。
  2. push方法:向数组的尾部添加一个或者更多元素,并返回新的长度
var arr = [1,2,3];
document.write(arr.join("--")); // 1--2--3
arr.push("HelloWorld");
document.write(arr);// 1,2,3,HelloWorld
  1. pop():该方法可以删除数组的最后一个元素,并将被删除的元素作为返回值返回。
  2. unshift():向数组开头添加一个或多个元素,并返回新的数组长度。
  3. shift():可以删除数组的第一个元素,并将被删除的元素作为返回值返回。
  4. slice():可以用来从数组提取指定元素,该方法不会改变元素数组,而是将截取到的元素封装到一个新数组中返回。 参数:
    1. 截取开始的位置的索引,包含开始索引
    2. 截取结束的位置的索引,不包含结束索引,第二个参数可以省略不写,此时会截取从开始索引往后的所有元素,索引可以传递一个负值,如果传递一个负值,则从后往前计算,-1表示 倒数第一个,-2 倒数第二个。
  5. splice():可以用于删除数组中的指定元素,使用splice()会影响到原数组,会将指定元素从原数组中删除,并将被删除的元素作为返回值返回。参数:
    1. 第一个,表示开始位置的索引
    2. 第二个,表示删除的数量
    3. 第三个及以后,可以传递一些新的元素,这些元素将会自动插入到开始位置索引前边。
  6. concat()可以连接两个或多个数组,并将新的数组返回。该方法不会对原数组产生影响
  7. reverse():该方法用来反转数组(前边的去后边,后边的去前边)该方法会直接修改原数组
  8. sort():可以用来对数组中的元素进行排序,也会影响原数组,默认会按照Unicode编码进行排序。sort函数的形参中可以指定一个表示排序规则的回调函数。

5.数组的遍历

  1. 使用for循环
var array = ["hello", null, undefined, true, 23, {name:"张三"}];
for (var i = 0; i < array.length; i++) {
	console.log(array[i]);
}
  1. 使用forEach()方法:该方法需要一个回调函数作为参数,该回调函数中需要传递三个参数。
    1. 第一个参数,就是当前正在遍历的元素
    2. 第二个参数,就是当前正在遍历的元素的索引
    3. 第三个参数,就是正在遍历的数组
var arr = ["hello", null, undefined, 23, true];
arr.forEach(function(value, index, obj) {
	console.log(obj[index]);
	console.log(value);
})

Date对象

  1. 日期对象的创建
// 不传参数默认创建当前时间
var date = new Date();
// 可以传递一个毫秒数用来创建具体的时间。

// 可以传递一个表示时间的字符串作为参数
// 日期的格式  月份/日/年 时:分:秒
var d2 = new Date("2/22/2022 13:38:30");
// 2022/2/22 下午1:38:30
console.log(d2.toLocaleString()); 
  1. Date对象的方法
1. toLocaleString:返回当前Date对象对应的时间本地字符串格式

var date = new Date();
document.write(date + "<br>") //Sat Oct 02 2021 12:24:38 GMT+0800
document.write(date.toLocaleString());//2021/10/2 下午12:25:52
2. getDate():获取当前日期对象是几日
3. getDay():获取当前日期对象时周几。会返回一个0-6的值。0 表示周日,1表示周一等等。
4. getMonth():获取当前时间对象的月份,会返回一个0-11的值
	1. 0 表示1月
	2. 1 表示2月
	3. 11 表示12月
5. getFullYear():获取当前日期对象的年份
6. getTime():获取当前日期对象的时间戳。
时间戳,指的是从格林威治标准时间的1970年1月1日,
0时0分0秒,到当前日期所花费的毫秒数(1秒 = 1000毫秒)
			 

Boolean对象

String对象

  1. String类型是字符串的对象包装类型,其length属性用于获取字符串的长度
// 使用String对象的构造函数
var str = new String("HelloWorld");
alert(str.length);	// 10
  1. String对象的方法
    1. charAt():可以返回字符串中指定位置的字符,根据索引获取指定的字符
    2. charCodeAt():获取指定位置字符的字符编码(Unicode编码)
    3. formCharCode():可以根据字符编码去获取字符
    4. concat():可以用来连接两个或多个字符串,作用和+一样
    5. indexof():该方法可以检索一个字符串中是否含有指定内容。如果字符串中含有该内容,则会返回其第一次出现的索引。如果没有找到指定的内容,则返回-1 可以指定一个第二个参数,指定开始查找的位置
    6. lastIndexOf():该方法的用法和indexOf()一样,不同的是indexOf是从前往后找,而lastIndexOf是从后往前找,也可以指定开始查找的位置。
    7. slice():可以从字符串中截取指定的内容,不会影响原字符串,而是将截取到内容返回。
    第一个,开始位置的索引(包括开始位置)	  
    第二个,结束位置的索引(不包括结束位置)如果
    省略第二个参数,则会截取到后边所有的,也可以传
    递一个负数作为参数,负数的话将会从后边计算
    
    1. substring():可以用来截取一个字符串,和slice()类似
    参数:
    第一个:开始截取位置的索引(包括开始位置)
    第二个:结束位置的索引(不包括结束位置)
    不同的是这个方法不能接受负值作为参数,
    如果传递了一个负值,则默认使用0
    而且他还自动调整参数的位置,如果第二个参数小于第一个,则自动交换
    
    1. substr():用来截取字符串
    参数:
    1.截取开始位置的索引
    2.截取的长度
    
    1. split():可以将一个字符串拆分为一个数组
    参数:
    需要一个字符串作为参数,将会根据该字符串去拆分数组
    示例:
    str = "abcbcdefghij";
    result = str.split("d");
    // ["abcbc", "efghij"]
    console.log(result);
    //如果传递一个空串作为参数,则会将每个字符都拆分为数组中的一个元素
    result = str.split("");
    console.log(result);
    console.log(result[0]); //a
    
    1. toUpperCase():将一个字符串转换为大写并返回
    2. toLowerCase():将一个字符串转换为小写并返回

Math对象

  1. 特点:不用创建Math对象,直接使用方法和属性
  2. Math对象的属性
    1. Math.PI:表示的圆周率
  3. Math对象的方法
    1. abs()可以用来计算一个数的绝对值
    2. Math.ceil():可以对一个数进行向上取整,小数位只要有值就自动进1
    3. Math.floor():可以对一个数进行向下取整,小数部分会被舍掉
    4. Math.round():可以对一个数进行四舍五入取整
    5. Math.random():生成一个0-x之间的随机数
    6. max() 可以获取多个数中的最大值
    7. min() 可以获取多个数中的最小值
    8. Math.pow(x,y):返回x的y次幂
    9. Math.sqrt(x):用于对一个数进行开平方根运算

RegExp对象

1.正则表达式的定义规则
  1. 正则表达式(Regular Expression):描述字符模式的对象,它用于对字符串模式匹配及检索替换,是对字符串执行模式匹配的强大工具。
  2. 单个字符
[a],[ab],[a-zA-Z0-9]
  1. 量词符号
?:表示出现0次或者1次
*:表示出现0次数或者多次数
+:表示出现1次数或者多次数
{m,n}:表示m<=数量<=n,如果m缺省({,n}),
则表示最多n次;如果n缺省({m, }),则表示最少m次数
  1. 元字符:
\d:单个数字字符[0-9]
\w:单个单词字符[a-zA-Z0-9]
  1. 开始结束符号:^表示开始,$表示结束符号
2.正则表达式对象的创建
  1. 正则表达式的语法为:/正则表达式主体/修饰符(可选)
    1. 修饰符比如说i,表示匹配时不区分大小写
    2. g:表示执行全局匹配,查找所有匹配而不是找到第一个匹配就停止
1.方式1
// 在构造函数中可以传递一个匹配模式作为第二个参数,可以是: 
	1. i 忽略大小写 
	2. g 全局匹配模式
var reg = new RegExp(正则表达式,匹配模式);
2.方式2:使用字面量创建正则表达式
var reg = /正则表达式/匹配模式;

var reg0 = new RegExp("^\\w{6,12}$");
var reg1 = /^\w{6,12}$/;
3.正则表达式对象的方法
  1. test方法:可以用来检查一个字符串是否符合正则表达式的规则
var userName = "NrvCer";
alert(reg1.test(userName)); // true
  1. exec方法:根据给定的正则表达式检索字符串,返回一个存放匹配结果的数组。
3.正则表达式通常使用在字符串的方法中
  1. search方法
  2. replace方法

Global对象

1.Global对象的特点
  1. 全局对象,这个Global对象封装的方法不需要对象就可以直接调用,方法名();
2.Global对象的方法
  1. encodeURI:URL编码
  2. encodeURIComponent:URL编码,编码的字符更多
  3. decodeURI:URL解码
  4. decodeURIComponent:URL解码
// 编码
var encode_code = encodeURI("中国");
document.write(encode_code); // %E4%B8%AD%E5%9B%BD,UTF-8中一个汉字三个字节
// 解码
var decode = decodeURI(encode_code)
document.write(decode); // 中国
  1. parseInt:将字符串转为number
  2. isNAN:判断一个值是否为NAN
  3. eval:将JS字符串把它作为脚本代码来执行
var jscode = "alert(123);"
eval(jscode);

DOM

DOM,全称为Document Object Model,文档对象模型。JS中通过DOM对HTML文档进行操作。

文档:整个的HTML网页文档
对象:将网页中的每一个部分都转换为了一个对象
模型:使用模型来表示对象之间的关系,这样方便我们获取对象

1.模型

DOM树

2.节点

1.节点的相关概念
  1. 节点Node的概念:构成HTML文档最基本的单元。比如说html标签、属性、文本、注释、整个文档等都是一个节点。
  2. 常用节点的类型:
1. 文档节点:整个HTML文档
2. 元素节点:HTML文档中的HTML标签
3. 属性节点:元素的属性
4. 文本节点:HTML标签中的文本内容
  1. 节点的属性
2.文档节点(document)
  1. 文档节点document,代表的是整个HTML文档,网页中的所有节点都是它的子节点。文档节点的节点名为#document
  2. document对象作为window对象的属性存在的,我们不用获取可以直接使用。
  3. 通过该对象我们可以在整个文档访问内查找节点对象,并可以通过该对象创建各种节点对象。
3.元素节点(Element)
  1. HTML中的各种标签都是元素节点,这也是我们最常用
    的一个节点。
  2. 浏览器会将页面中所有的标签都转换为一个元素节点,我们可以通过document对象的方法来获取元素节点。
通过document对象的方法获取元素节点
1. getElementById():通过id属性获取一个元素节点对象
2. getElementsByTagName():通过标签名获取一组元素节点对象
3. getElementsByName():通过name属性获取一组元素节点对象
  1. 获取元素节点的子节点
通过具体的元素节点调用
1. getElementsByTagName()方法,返回当前节点的指定
标签名后代节点
2. childNodes属性,表示当前节点的所有子节点
3. firstChild属性,表示当前节点的第一个子节点
4. lastChild属性,表示当前节点的最后一个子节点
  1. 父节点和兄弟节点的获取
通过具体的节点调用
1. parentNode属性,表示当前节点的父节点
2. previousSibling属性,表示当前节点的前一个兄弟节点
3. nextSibling属性,表示当前节点的后一个兄弟节点
  1. 元素节点的属性
1. 获取元素节点的属性:元素对象.属性名
    例如element.value
    element.id
    # 读取class属性时需要使用:
    element.className(class是保留字,比较特殊)
2. 设置元素节点的属性:元素对象.属性名=新的值    
  1. 元素节点的操作
创建节点:document.createElement(标签名)
删除节点:父节点.removeChild(子节点)
替换节点:父节点.replaceChild(新节点 , 旧节点)
插入节点:父节点.appendChild(子节点)
        父节点.insertBefore(新节点 , 旧节点
4.文本节点
  1. 文本节点表示的是HTML标签以外的文本内容,任意非HTML的文本都是文本节点。文本节点的节点名为#text
  2. 它包括可以字面解释的纯文本内容。
  3. 文本节点一般是作为元素节点的子节点存在的。
  4. 获取文本节点时,一般先要获取元素节点。在通过元素节点获取文本节点。
5.属性节点
  1. 属性节点表示的是标签中的一个一个的属性,这里要注意的是属性节点并非是元素节点的子节点,而是元素节点的一部分。
  2. 可以通过元素节点来获取指定的属性节点。
  3. 常用属性
1. nodeValue文本节点可以通过nodeValue属性获取和设置文本节点的内容
2. innerHTML元素节点通过该属性获取和设置标签内部的html代码

3.事件

  1. 事件:就是文档或浏览器窗口中发生的一些特定的交互瞬间。
  2. JavaScript 与 HTML之间的交互是通过事件实现的。
  3. 对于 Web 应用来说,有下面这些代表性的事件:点击某个元素、将鼠标移动至某个元素上方、按下键盘上某个键,等等。
<!--事件示例-->
<head>
	<meta charset="utf-8">
	<title>JS学习</title>
	<script type="text/javascript">
		// 为window对象绑定一个onload事件
		// onload事件会在整个页面加载完成之后才触发
		window.onload = function() {
			var button = document.getElementById("btn");
			// 为按钮绑定单击事件
			button.onclick = function() {
				alert("关闭窗口");
			};
		}
	</script>
</head>
<body>
	<button id="btn">点击按钮</button>
</body>
1.事件处理程序的绑定

为一个元素绑定事件处理程序有以下三种方式:

  1. 通过HTML元素指定事件属性来绑定
<button onclick="alert('确定提交吗?');">提交</button>
<script type="text/javascript">
    function execute() {
		alert("确定提交吗?");
	}
</script>
<button onclick="execute()">提交</button>
  1. 通过DOM对象指定的属性来绑定(推荐使用)
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>JS学习</title>
		<script type="text/javascript">
			window.onload = function() {
				var button = document.getElementById("btn");
				button.onclick = function() {
					alert("确认提交吗?");
				}
			}
		</script>
	</head>
	<body>
		<button id="btn">提交</button>
	</body>
</html>
  1. 12方式的缺陷是不能为一个元素的相同事件绑定多个事件处理程序。 设置事件监听器:元素对象.addEventListener()
设置事件监听器:addEventListener
移除事件:removeEventListener()和detachEvent()

<!--addEventListener方法需要三个参数:-->
<!--一个是事件字符串,一个是响应函数,
三是是否在捕获阶段触发事件,一般传递false,true表示在捕获阶段执行事件处理函数-->
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>JS学习</title>
		<script type="text/javascript">
			window.onload = function() {
				var button = document.getElementById("btn");
				button.addEventListener("click", function(){
					alert("确认提交吗?");
				});
				button.addEventListener("click", function() {
					alert("你确认吗?");
				});
				
			}
		</script>
	</head>
	<body>
		<button id="btn">提交</button>
	</body>
</html>

2.事件对象

在DOM对象上的某个事件被触发时,会产生一个事件对象XxxEvent,这个对象中包含着所有事件有关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数,在事件对象中封装了当前事件相关的一切信息。

areaDiv.onmousemove = function(event){
	/*
	 * 在IE8中,响应函数被触发时,浏览器不会传递事件对象,
	 * 	在IE8及以下的浏览器中,是将事件对象作为window对象的属性保存的
	 */
	
	//解决事件对象的兼容性问题
	event = event || window.event;
	console.log(event.type);	//mousemove
	/*
	 * clientX可以获取鼠标指针的水平坐标
	 * cilentY可以获取鼠标指针的垂直坐标
	 */
	var x = event.clientX;
	var y = event.clientY;
	
	//在showMsg中显示鼠标的坐标
	showMsg.innerHTML = "x = "+x + " , y = "+y;
};
3.事件的冒泡

冒泡指的是事件的向上传导,当后代元素的事件被触发时,其祖先元素的相同事件也会被触发。在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡。

<!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(){
				//为s1绑定一个单击响应函数
				var s1 = document.getElementById("s1");
				s1.onclick = function(event){
					event = event || window.event;
					alert("我是span的单击响应函数");
					
					//取消冒泡
					//可以将事件对象的cancelBubble设置为true,即可取消冒泡
					event.cancelBubble = true;
				};
				
				//为box1绑定一个单击响应函数
				var box1 = document.getElementById("box1");
				box1.onclick = function(event){
					event = event || window.event;
					alert("我是div的单击响应函数");
					
					event.cancelBubble = true;
				};		
				//为body元素绑定一个单击响应函数
				document.body.onclick = function(){
					alert("我是body的单击响应函数");
				};			
			};
		</script>
	</head>
	<body>
		
		<div id="box1">
			我是box1
			<span id="s1">我是span</span>
		</div>
		
	</body>
</html>
4.事件的委派

指的是将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数处理事件。事件委派利用了冒泡,通过委派可以减少事件的绑定次数,提高程序的性能。

<head>
	<meta charset="utf-8" />
	<title></title>
	<script type="text/javascript">
		
		window.onload = function(){
			
			var u1 = document.getElementById("u1");
			
			//点击按钮以后添加超链接
			var btn01 = document.getElementById("btn01");
			btn01.onclick = function(){
				//创建一个li
				var li = document.createElement("li");
				li.innerHTML = "<a href='javascript:;' class='link'>新建的超链接</a>";
				
				//将li添加到ul中
				u1.appendChild(li);
			};
			
			
			/*
			 * 为每一个超链接都绑定一个单击响应函数
			 * 这里我们为每一个超链接都绑定了一个单击响应函数,这种操作比较麻烦,
			 * 	而且这些操作只能为已有的超链接设置事件,而新添加的超链接必须重新绑定
			 */
			//获取所有的a
			var allA = document.getElementsByTagName("a");
			//为ul绑定一个单击响应函数
			u1.onclick = function(event){
				event = event || window.event;
				
				/*
				 * target
				 * 	- event中的target表示的触发事件的对象
				 */
				// alert(event.target);
				
				
				//如果触发事件的对象是我们期望的元素,则执行否则不执行
				if(event.target.className == "link"){
					alert("我是ul的单击响应函数");
				}	
			};	
		};
		
	</script>
</head>
<body>
	<button id="btn01">添加超链接</button>
	
	<ul id="u1" style="background-color: #bfa;">
		<li>
			<p>我是p元素</p>
		</li>
		<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>
5.事件的传播
  1. 捕获阶段:这一阶段会从window对象开始向下一直遍历到目标对象,如果发现有对象绑定了响应事件则做相应的处理。
  2. 目标阶段:这一阶段已经遍历结束,则会执行目标对象上绑定的响应函数。
  3. 事件冒泡阶段:这一阶段,事件的传播方式和捕获阶段正好相反,会从事件目标一直向上遍历,直至window对象结束,这时对象上绑定的响应函数也会执行。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>JS学习</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");
				// addEventListener的第三参数为true表示在事件
				// 的捕获阶段执行事件处理函数
				box1.addEventListener("click", function() {
					alert("box1中的单击响应函数");
				}, true);
				box2.addEventListener("click", function() {
					alert("box2中的单击响应函数");
				}, true);
				box3.addEventListener("click", function() {
					alert("box3中的单击响应函数");
				}, true);
			}
		</script>
	</head>
	<body>
		<div id="box1">
			<div id="box2">
				<div id="box3"></div>
			</div>
		</div>
	</body>
</html>

上述案例中,单击box3,先执行box1的单击响应函数,然后2,最后3.