JS 基础

1. JavaScript 历史

  • 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中).后将其改名ScriptEase.(客户端执行的语言)。
  • Netscape(网景)接收Nombas的理念,(Brendan Eich)在其Netscape Navigator 2.0产品中开发出一套livescript的脚本语言.Sun和Netscape共同完成.后改名叫Javascript。
  • 微软随后模仿在其IE3.0的产品中搭载了一个JavaScript的克隆版叫Jscript。
  • 为了统一三家,ECMA(欧洲计算机制造协会)定义了ECMA-262规范.国际标准化组织及国际电工委员会(ISO/IEC)也采纳 ECMAScript 作为标准(ISO/IEC-16262)。从此,Web 浏览器就开始努力(虽然有着不同的程度的成功和失败)将 ECMAScript 作为 JavaScript 实现的基础。EcmaScript是规范。

JavaScript 基于对象,也面向对象,一个完整的 JavaScript 包括以下三部分:

  • 核心:ECMAScript(语法、类型、语句、关键字、保留字、运算符、对象(封装、继承、多肽)
  • 文档对象模型(DOM):Document Object Model(包含 js、html、css)
  • 浏览器对象模型(BOM):Broswer Object Model(整合 js 和浏览器)

2. JavaScript 基础

2.1 JavaScript 引入方式

直接在 HTML 中嵌入

js 代码写在 script 标签中,script 标签可以放在 head 中,也可以放在 body 后面(可以避免一些不必要的麻烦)

<script>
	alert('hello');
    console.log('javascript');
</script>

从外部引入 js 文件

<script src='xxx.js'></script>

2.2 变量

JavaScript 中使用 var 关键字声明一个变量,不需要指定数据类型,而且可以一行声明多个变量:

var x=123;
var name='rose', age=18, gender='female'
  • 不用 var 关键字声明的变量为全局变量
  • 变量名必须是(字母、下划线、$开头),且区分大小写

以下为几种常见的命名规则:

Camel 标记法
var myFirstName = 'li';
    
Pascal 标记法
var MyFirstName = 'li';

匈牙利类型标记法(前面的 s 为数据类型,s为字符串)
var sMyFirstName = 'li'

2.3 语法风格

基础规范

  • 每行结束需要有分号(;)结束,否则以换行符结束
  • 注释:单行(//),多行(/**/)
  • 代码块:{}

常量与标识符

  • 常量:即数值
  • 标识符:由不以数字开头的字母、数字、下划线及 $ 组成(如:_abc,a1bc)
    • 常用于函数、变量等名称
    • 不能使用关键字作为标识符

ECMA v3 标准保留的 JavaScript 关键字:

2.4 数据类型

  • 基本数据类型:Number(数字)、string、Boolean、Null、Undefined
  • 引用数据类型:object 对象

数据由栈和堆共同存储,基本数据类型存储在栈里面,引用数据类型只存储地址,通过指针找到堆中的数据:

2.4.1 Number 类型

数值类型,不区分整数和浮点数,全都采用 64位浮点格式存储,其范围是(±5 * 10 ^-324 到 ±1.7976931348623157 * 10308 )。

number 数字表示方法

0.1 + 0.2 = 0.30000000000000004	
0.1 + 0.2 == 0.3		// false

.9;   // 0.9
1E3   // 1000
2e6   // 2000000
0.1e2 // 10
1e-5  // 0.00001

不同进制表示方法

  • 二进制:以 0b(或 0B )开头,如:0b100000
  • 八进制:以 0 开头,加入 0 后面的数字不在 (0~7)中,那么将会被转换成十进制,如:0755
  • 十六进制:以 0 开头,后面接小写或大写字母(a~f 或 A~F),如:0xFFFFFFFFFFFFFFFFF

进制转换

不同进制之间转换主要用 Number 对象的 tosting() 方法 和 parseInt() 方法。

  • tostring() 方法将数字转换为字符串,可以接收一个(2~36之间的整数)作为基数,表示会转换为多少进制值表示的字符串(可选,默认按十进制转换)。
  • parseIn() 方法将字符串转换为数值,可以接收一个(2~36之间的整数)作为基数,表示会转换为多少进制值表示的数字(可选,默认按十进制转换)。
var n = 120;

console.log(n.toString());		// "120"
console.log(n.toString(2));		// "1111000"
console.log(n.toString(8));		// "170"
console.log(n.toString(16));	// "78"
console.log(n.toString(32));	// 3o

console.log(parseInt('100'));			// 100
console.log(parseInt('100.98'));		// 100	(小数直接被截断)
console.log(parseInt('100', 2));		// 4

2.4.2 String 类型

由 Unicode 字符、数字以及标点符号组成的序列,用单或双引号括起,特殊字符必须用反斜杠(\)转义。

常见转义字符:\n:换行,\':单引号,\“:双引号,\\:右划线

Unicode 插入方法:

var str="\u4f60\u597d\n欢迎来到\"JavaScript世界\"";
alert(str)

2.4.3 Boolean 类型

Boolean 类型只有两个值(true和false),也可以看作为(1 和 0,on 和 off 等)。

false:0、null、undefined、off
true:1、[] (new object)、on

2.4.4 Null 和 Undefined 类型

Null 类型

只有一个值,即 Null,表示一个特殊值,常用来表述 空值

表示不存在的对象,即不应该有值

console.log(document.getElementById('test'));		// null


Undefined 类型

只有一个值,即 Undefined,出现 Undefined 的几种情况:

  • 声明变量,但未赋值,那么它的默认值即为 Undefined(如:var n;)
  • 当函数无明确返回值时,返回的也是 Undefined
  • 获取对象不存在的属性
  • 函数的参数没有传入
  • void(expression)
var i;
console.log(i);		// undefined

var x = {};
console.log(x.p);	// undefined

function f(){}
console.log(f());	// undefined

function f(x){return x;}
console.log(f());		// undefined

console.log(void(0));	// undefined

2.4.5 类型转换

数值类型转换

  • 数字+字符串:数字转换为字符串
  • 数字+布尔值:true 为 1,false 为 0
  • 字符串+布尔值:布尔值转换为 true 或 false
console.log(1+'ab');	// '1ab'
console.log(1+true);	// '2'
console.log(true +'ab');	// 'trueab'


强制类型转换

  • parseInt 函数:强制转换为整数
  • parseFloat 函数:强制转换为浮点数
  • eval 函数:将字符串转换为表达式并返回
console.log(parseInt('6.12'));		// 6
console.log(parseInt('a'));			// NAN
console.log(parseInt('1a2'));		// 1

console.log(parseFloat('a'));		// NAN
console.log(parseFloat('12.1'));		// 12.1

console.log(eval('1+2'));			// 3
console.log(eval('2<3'));			// true

Tips:NAN(not a number),属于 number 的一种,在转换为数值类型失败时会出现这种情况。


类型查询 typeof

console.log(typeof('12'));		// string
console.log(typeof(true));		// Boolean
console.log(typeof(null));		// object

2.5 运算符

2.5.1 算术运算符

加(+)、减(-)、乘(*)、除(/)、余数(%),与数学中一样。

递增(++)、递减(--)

  • ++i:先加后打印
  • i++:先打印后加
var n = 1;
console.log(n++);		// 1

var m = 1;
console.log(++m);		// 2

var x = 1;
console.log(x--);		// 1

var y = 1;
console.log(--y);		// 0

2.5.2 比较运算符与逻辑运算符

比较运算符

等于()、不等于(!=)、大于(>)、小于(<)、大于等于(>)、小于等于(<),绝对等于(=)。

等于与绝对等于的区别:

  • 等于是只要值相等就为 true
  • 绝对等于值和类型必须都相等
console.log(2==2);		// true
console.log('2'==2);	// true
console.log('2'===2);	// false
console.log(2===2);		// true

// NAN 只要参与比较,都为 false,除非为不等于
console.log(n==NaN) ;	// false
console.log(n!=NaN) ;	// true


逻辑运算符

运算符 描述 例子(var m = 6, n = 3;)
&& and m<10 && n>1,为 true
|| or m>20 || n>2,为 true
not !(m<10),为 false
  • 如果某个运算数是 null,返回 null。
  • 如果某个运算数是 NaN,返回 NaN。
  • 如果某个运算数是 undefined,返回undefined。

2.5.3 等性运算符

类型转换规则

  • 若一个运算数是 Boolean,在检查相等性之前,会把它转换为数字
  • 若一个运算数是 string,另一个是 number,会尝试将 string 转换为 number
  • 若一个运算数是 object,另一个是 string,会尝试将 object 转换为 string
  • 若一个运算数是 object,另一个是 number,会尝试将 object 转换为 number

比较运算规则

  • null 和 undefined 相等
  • 在检查相等性时,不能把 null 和 undefined 转换为其他值
  • 两个数比较时,如其中一个是 NaN,那么将返回 false,除非是 不等于才返回 true
  • 若两个运算数都是对象,则比较它们的引用值。若两个运算数指向同一对象,那么等号返回 true,否则两个运算数不等。

2.5.4 关系运算符

字符串比较

字符串比较,比较的是最高位字母在 ASCII 码表中所对应的字符代码,若最高位相等则比较第二位,一直到比较出大小为止。

console.log('ba' < 'ab');		// false
console.log('20' < '3');		// true


数字和字符串比较

数字和字符串比较,会尝试将字符串转换为数字再比较

console.log('20' < 3);		// false

3. 控制语句

3.1 if 控制语句

if 语句可以单独使用,也可以配合 if -else,if - else if - else 使用。

语法结构:

if (表达式){
    语句1;
}
else if{
    语句2;
}
else{
    语句3;
}

var name = 'rose';
if (name=='rose'){
    alert('hello '+ name);
}
else{
    alert('hello');
}

3.2 switch 语句

switch 语句表达式的值与 case 值想比较,相等则执行该条语句,如果都没有匹配上,则执行 default 语句。

语法结构:

switch (表达式) {
    case 值1:语句1;break;
    case 值2:语句2;break;
    case 值3:语句3;break;
    default:语句4;

var week = 3;
switch (week){
    case 1: alert('星期一');break;
    case 2: alert('星期二');break;
    case 3: alert('星期三');break;
    case 4: alert('星期四');break;
    case 5: alert('星期五');break;
    default:alert('周末');
}

3.3 for 循序语句

语法结构:

for (初始化; 条件; 增量;){
    语句;
}

计算 0-100 所有数的和:

var sum = 0;
for (var i=0; i<101; i++){
	sum += i;	
}
console.log(sum)

使用 for 循环遍历数组中的值:

var attr = [1, 2, 3];
for (var i=0; i<attr.length; i++){
    console.log(i);		// 0、1 、2 ,这里的 i 是数组的下标
    console.log(attr[i]);		// 要获得数组的值,还需要通过下标取出
}

3.4 while 循环语句

语法结构:

while (条件){
    语句;
}

计算 1-100 所有数的和:

var sum = 0;
var i = 0;
while (i<=100){
    sum += i;
    i++;
}
console.log(sum);

4. 异常处理

语法结构:

try{
    //该段代码从上往下执行,其中任何一个语句抛出异常,该代码就结束运行
}
catch(e){
    // try 抛出异常,则执行该条语句
    // e 为局部变量,用来指向 Error 对象或其他抛出异常的对象
}
finally{
    // 无论 try 中是否有异常,都会执行
}

try {
    console.log('hello rose');
    throw Error('define error');		// 主动抛出异常
}
catch (e){
    console.log(e);
}
finally {
    console.log('javascript');
}

Tips: 可以使用 throw Error('xxx') 主动抛出异常

5. ECMA对象

JavaScript 中没有类的概念,对象就相当于其他语言中的类,所有的对象都由 object 这个对象继承而来。

11 中内置对象:Arrya、String、Date、Math、Boolean、Number、Function、Global、Error、RexExp、Object。

内置对象分类:

  • 数据对象:Number、String、Boolean
  • 组合对象:Array、Math、Date
  • 高级对象:Object、Error、Function、RegExp、Global

valueOf() 方法和 toString() 方法,是所有对象共享的方法,每个对象都有:

  • toSting():返回对象的原始字符串表示
  • valueOf():返回最适合对象的原始值,对于许多对象,该方法返回的值都与 toSting 返回的值相同。

5.1 String 对象

String 对象,字符串对象,JavaScript 中比较常见的对象。

创建 String 对象

var str1 = 'hello';			// 方式 1
var str2 = new String('hello');		// 方法2


String 对象属性

String 对象只有一个属性 length,用于获取对象长度。

var str1='hello';
alert(str1.length);


String 对象方法:格式编排方法

String 对象提供了一组针对 HTML 格式的方法,常见的有:

  • str.anchor():返回锚定义字符串
  • str.bold():返回粗体字符串
  • str.italics():返回斜体字符串
var str1 = 'hello';
console.log(str1.anchor());		//  <a name='undefined'>hello</a>


String 对象方法:大小写转换

  • toLowerCase():转换为小写
  • toUpperCase():转换为大写

String 对象方法:获得指定字符

  • charAt(index):按照索引获取指定字符,搜索从 0 开始
  • charCodeAt(index):按照索引获取指定字符的 Unicode 编码
var str1='hello';
console.log(str1.charAt(3));			// l
console.log(str1.charCodeAt(3)); 		// 108


String 对象方法:查询字符串

  • indexOf(findstr,index):返回第一个符合的字符的下标
  • lastIndexOf(findstr):返回最后一个符合的字符的下标
var str1 = 'hello javascript';
console.log(str1.indexOf('a'));		// 7
console.log(str1.lastIndexOf('a'));		// 9


String 对象方法:截取字符串

  • substr(start, length):从 start 位置截取 length 长度的字符
  • substring(start, end):从 start 位置截取到 end 位置的字符
  • slice(start, end):字符串切片
var str1 = 'hello';
console.log(str1.substr(1, 2));			// el
console.log(str1.substring(1, 2));		// e,  [1, 2):左取右不取
console.log(str1.slice(1, 2)); 			// e


String 对象方法:替换、分割与连接字符串

  • replace(findstr, tostr):替换字符串
  • split(sub):以 sub 为分割符
  • concat(substr):连接 substr 字符串
var str1 = 'hello';
console.log(str1.replace('e', 'b'));		// hbllo
console.log(str1.split('e'));			// Array['h', 'llo']
console.log(str1.concat('na'));			// hellona

5.2 Array 对象

Array 对象,数组对象,可以存储任何数据类型,属性(length:数组长度)。

创建数组对象

一维数组:

var a = [1, '2', 3];
var a = new Array();	
var a = new Array(3);		// 数组长度为 3
a[0] = 1;				// 数组赋值
a[1] = 2;
a[2] = 3;
console.log(a);		// [1, 2, 3]

二维数组:

var a = new Array(3);
for (var i=0; i<3; i++){
    a[i] = new Array(2);
}
a[0][0] = 'a';
a[0][1] = 'b';
a[1][0] = 'c';
a[1][1] = 'd';
a[2][0] = 'e';
a[2][1] = 'f';
console.log(a)			// [['a', 'b'], ['c', 'd'], ['e', 'f']]


连接数组:join、concat 方法

var a = [1, 2, 3];
console.log(a.join('-'));		// 1-2-3
console.log(a.concat(4, 5));	// [1,2,3,4,5]
console.log(a.concat([4, 5]));	// [1,2,3,4,5]


数组排序:reverse、sort 方法

var a = [10, 2, 3, 40];
console.log(a.reverse());		// 反转数组 [40,3,2,10]
console.log(a.sort());			// 比较高位在ASCII 码表中位置比较  [10,2,3,40],默认从小到大

// 按照数值大小排序
function f(x, y){
    return x-y;
}
console.log(a.sort(f))			// [ 2, 3, 10, 40 ]


数组切片:slice

var a = [10, 2, 3, 40];
console.log(a.slice(1,2));		// 2


删除子数组:splice

对数组指定位置进行删除操作:

splice(start, deleteCount, value,...)	// deleteCount:删除个数,value:要增加的值
      
var a = [1, 2, 3, 4, 5, 6];
a.splice(1, 2);     // [1, 4, 5, 6]		从位置 1 开始删除 2 个值
a.splice(1, 0, 10);     // [1, 10, 4, 5, 6]		从位置 1 开始删除 0 个,插入一个 10


数组进出栈

push(压栈)、pop(弹栈)方法模拟的是一个栈操作,栈(先进后出):

// 压栈的数在数组后面
var a = [1,2,3];
console.log(a.push([5, 6]));        // a:[1, 2, 3, [5,6]]
console.log(a.push('js', 'array'));     // a: [1, 2, 3, [5, 6], 'js', 'array']

// 'array' 后进先出
console.log(a.pop());           // a: [1, 2, 3, [5,6], 'js']

shift(出栈)、unshift(入栈):

// 入栈的数在数组前面
var a = [1,2,3];
console.log(a.unshift([5, 6]));		// a:[[5,6], 1, 2, 3]
console.log(a.unshift('js', 'array'));      // a:['js', 'array', [5,6], 1, 2, 3]
console.log(a.shift());     // a:['array', [5,6], 1, 2, 3]

5.3 Function 对象

JavaScript 使用 function 关键字创建一个函数,参数可以是变量、常量或表达式。

定义函数

// 第一种
function 函数名(参数){
	函数体;
    return 返回值;
}
函数名()		// 调用函数

// 第二种(不推荐)
var 函数名 = new Function('参数1', '参数2', '函数体')

JavaScript 的函数执行,要等全部加载完毕后,才会执行,因此调用函数在函数上火函数下面都可以。


Function 对象属性

函数对象属于引用类型,所以也有属性和方法。函数的 length 属性声明了函数期望的参数个数:

function f(a, b){
    return a + b;
}

console.log(f(2, 3));		// 5
console.log(f.length);		// 2


调用带参数的函数

JavaScript 只要调用的函数名对,不管传入的实参比形参少还是多,都可以执行。

// 实参比形参多时,只会取前面几个与形参个数相等的参数
function f(a, b){
    return a + b;
}
console.log(f(2, 3, 5, 6));		// 5

// 实参比形参少时,返回 NaN
console.log(f(2));		// NaN

一个 JavaScript 面试题:

function func(a, b) {
    return a+b;
}

var func=1;			// 变量 func 被重新赋值
var b = 2;
console.log(func(func, b));			// TypeError: func is not a function


内置对象 arguments

arguments 可以接收任意个参数,并通过索引取的参数值:

// 传入的参数都以键值对的方法,存储在 arguments 中,通过索引可以取得参数
function f(a, b){
    console.log(arguments);			// Arguments { 0: 2, 1: 3, 2: 5, 3: 6, … }
    console.log(arguments.length);		// 4
    console.log(arguments[1]);			// 3
    return a + b;		
}
console.log(f(2, 3, 5, 6));		// 5

求所有参数的和:

function add(a, b ) {
	var sum = 0;
	for (var i=0; i<arguments.length; i++){
		sum += arguments[i];
	}
	return sum;
}
console.log(add(1, 2, 3, 4, 5, 6));		// 21


匿名函数

// 创建一个匿名函数
var func = function(args){
    return args;
};
console.log(func(1));		// 1

// 匿名函数应用
(function (args) {
    alert(args);
})(1)			// 1

5.4 Date 对象

创建 Date 对象

var CurrentTime = new Date();	// 不指定参数
var CurrentTime = new Date('2018/12/31 22:05');		// 参数为字符串形式
var CurrentTime = new Date(6000);		// 参数为毫秒数
var CurrentTime = new Date(2018, 12, 31, 22, 05, 20, 200);	// 参数为年月日时分钟秒毫秒,毫秒不直接显示


获取日期和时间方法

toLocaleString()		// 获取当前时间的字符串形式,如:2018/12/31 下午10:11:35
toDateString()			// 格式:Mon Dec 31 2018
toUTCString()			// 获取当前UTC时间,如: Mon, 31 Dec 2018 14:11:35 GMT
getDate()			// 获取日
getDay()			// 获取星期
getMonth()			// 获取月(0-11)
getFullYear()		// 获取完整年份(2018)
getYear()			// 获取年
getHours()			// 获取小时
getMinutes()		// 获取分钟
getSeconds()		// 获取秒
getMilliseconds()	// 获取毫秒
getTime()			// 返回累积毫秒数(从1970/1/1 00:00:00开始累积)

6. 函数作用域

与绝大多数编程语言类似,JS 函数也有自己的作用域,而 if,while 并没有。

function f() {
    var x = 2;
}
f();
console.log(x);		// ReferenceError: x is not define

变量 x 是函数 f 内部定义的,在函数外部无法调用。

嵌套函数作用域

当多个函数嵌套时,若变量名相同,那么先从自己作用域中找,没有再往上找:

var x = 10;
function f1() {
	var x = 9;
	function f2() {
		x = 8;
		console.log(x);				// 8
	}
	f2();
}
f1();

var x = 10;
function f1() {
    console.log(x);			// 10
}
function f2() {
    var x = 8;
    return f1;
}

var res = f2();
res()


闭包

在一个内部函数里,对在外部作用域(但不是全局作用域)的变量进行引用,那么这个内部函数就是闭包。

var x = 10;
function f1() {
    var x = 9;
    function f2() {
//        var x = 8;
        console.log(x);			// 9 
    }
    return f2;
}

res = f1();
res();	

7. BOM 对象

BOM 对象(浏览器对象模型),通过 BOM 对象可以对浏览器窗口进行访问和操作,使得 JS 有了与浏览器 “对话”的能力。

7.1 window 对象

所有浏览器都支持 window 对象,不需要创建,可直接使用。

方法

  • alert():弹出一个带有一段消息和一个确认按钮的警告框
  • confirm():弹出一个带有一段消息和确认、取消按钮的对话框
  • prompt():弹出一个用户可输入的对话框,第一个参数为提示信息,第二个为输入框默认值,返回值为输入的值
  • open():打开一个新的浏览器窗口或查找一个已命名的窗口
  • close():关闭浏览器窗口
  • setInterval():按照指定周期(单位:毫秒)来调用函数或计算表达式
  • clearInterval():取消由 setInterval() 设置的 timeout
  • setTimeout():在指定的毫秒数后调用函数或计算表达式
  • clearTimeout():取消由 setTimeout() 方法设置的 timeout
  • scrollTo():把内容滚动到指定坐标
  window.alert('123');
  var res = window.prompt('你真的确定要关闭我?');
  console.log(res);

创建一个计时器,每隔 1000 ms 实时显示当前时间,当点击停止按钮时,停止时间:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>js 对象</title>
    <style type="text/css">
      #test{
            width: 200px;
            height: 50px;
      }
    </style>
</head>
<body>
    <input type="text" id="test" onclick="begin()">
    <button onclick="end()">停止</button>

	<script>

        // 显示时间

        function showtime() {
            var CurrentTime = new Date();
            var res = document.getElementById('test');      // 获取 input 标签对象
            res.value = CurrentTime.toLocaleString();   // 给 input 标签 value 赋值(当前时间)
        }

        var clock1;     // 全局
        function begin() {
            if (clock1==undefined){
                showtime();
                clock1 = setInterval(showtime, 1000);       // 创建一个闹钟,1000毫秒后,执行 showtime 函数
            }

        }

        function end() {
            clearInterval(clock1);
            clock1 = undefined;
        }	
    </script>
    </body>
</html>

setTimeout() ,在载入后延迟指定时间去执行一次表达式,**仅执行一次

setTimeout(OpenWindow, 3000);		// 3s 后打开一个窗口,定位到百度首页
function OpenWindow() {
    window.open('https://www.baidu.com');
}	

7.2 history 对象

history 对象包含浏览器窗口中访问过的 URL,是 window 对象的一部分,通过 length 属性可以获得浏览器历史记录 URL 数量。

history 对象方法:

  • back():加载 history 列表中前一个 URL
  • forward():加载 history 列表中下一个 URL
  • go():加载 history 列表中某个具体的页面

利用 history 对象制作浏览器前进后退功能:

<!--page1.html-->
<a href="page2.html">前进</a>
<button onclick="history.forward()">>>></button>
<!--<button onclick="history.go(1)">>>></button>-->

<!--page2.html-->
<a href="page1.html" onclick="f2()">后退</a>
<button onclick="history.back()"><<<</button>
<!--<button onclick="history.go(-1)">>>></button>-->

7.2 Location 对象

Location 对象包含当前 URL 的信息,也是 window 对象的一部分,可以通过 window.location 属性来访问。

Location 对象方法

  • assign(url):跳转到某个 URL,可回退
  • reload():刷新
  • replace(newURL):替换原有 URL,不可回退
<button onclick="f1()">点击我</button>
<script>
    function f1() {
//        location.reload();      // 刷新
//        location.assign('https://www.baidu.com');   // 跳转,可返回
          location.replace('https://www.baidu.com');    // 替换 url,不可返回
    }
</script>

8. DOM 对象

DOM 对象是 W3C 的标准,定义了访问 HTML 和 XML 文档的标准,分为 3 个部分:

  • 核心 DOM:对任何结构化文档的标准模型
  • XML DOM:对 XML 文档的标准模型
  • HTML DOM:对 HTML 文档的标准模型

8.1 DOM 节点

w3c 的 HTML DOM 标准,HTML 文档中所有内容都是节点(node)。

  • 整个 HTML 文档是一个文档节点(document 对象)
  • 每个 HTML 元素是一个元素节点(element 对象)
  • HTML 元素内的文本是文本节点(text 对象)
  • 每个 HTML 元素属性是属性节点(attribute 对象)
  • 注释是注释节点(comment 对象)

获取节点对象的方法

访问 HTML 元素就是访问节点,通过以下方法可以获得节点对象:

  • getElementById():通过元素 id 访问节点对象,唯一
  • getElementsByName():通过元素 name 属性访问节点对象
  • getElementsByClassName():通过元素 class属性访问节点对象,获得是节点对象数组(可用索引获取)
  • getElementsByTagName():通过元素名字访问节点对象

Tips: 通过节点的 name、class 属性,以及节点名字获取节点对象,获得是节点对象数组(可用索引获取)。


导航属性

很多时候 HTML 文档都是层层嵌套的,我们并不能直接获取到元素节点对象,这时就需要用到 导航属性

所谓的导航属性就是先获取节点对象的父节点或子节点或兄弟节点,从而获得我们需要的结点对象:

  • parentNode:父节点,唯一
  • firstChild:节点下的第一个子节点
  • lastChild:节点下最后一个子节点
  • childNodes:节点下所有子节点
  • nextSibling:节点下一个兄弟节点
  • previousSibling:节点上一个兄弟节点

需要注意的是,每个元素节点的兄弟节点不是元素节点,而是空白文本节点:

<div class="box1">
    <p class="p1"></p>
    <div class="box2"></div>
</div>

var p = document.getElementsByClassName('p1')[0];
var box2 = p.nextSibling;
console.log(box2);

上面我们获得 p 节点,再通过 p 节点获取它的下一个节点,发现获得不是 box2,而是 #text。这是因为 p 节点的下一个兄弟节点是空白文本节点,要想获得 box2,就需要用到 nextElementSibling 属性:

var box2 = p.nextElemntSibling;

类似的属性还有:

  • parentElement:父节点标签元素
  • children:所有子标签
  • firstElementChild:第一个子标签元素
  • lastElementChild:最后一个子标签元素
  • nextElementSibling:下一个兄弟标签元素
  • previousElementSibling:上一个兄弟标签元素

节点自身属性

获得节点对象后,通过以下属性可以获得节点的属性、名字以及文本等:

  • attributes:节点的属性节点
  • nodeType:节点类型
  • nodeValue:节点值
  • nodeName:节点名称
  • innerHTML:节点文本值(包括标签中文本和其他子标签)
  • innerText:节点文本值

8.2 DOM Event 事件

通过 操作 DOM 对象可以使触发浏览器中的动作(action),这些动作就是事件,以下为事件列表:

onclick			// 鼠标点击事件
ondblclick		// 鼠标双击事件

onfocus			// 元素获得鼠标焦点	应用场景:输入框
onblur			// 元素失去鼠标焦点	应用场景:表单验证,当鼠标离开输入框时,表示输入完成,就可以验证了
onchange		// 域的内容被改变		应用场景:用于表单元素,当元素内容被改变时触发(三级联动)

onkeydown		// 键盘按键被按下		应用场景:在最后一个输入框按下回车键时,表单提交
onkeypress		// 键盘按键按下并松开
onkeyup			// 键盘按键被松开
onload			// 一个页面或图像完成加载		当把 js 放在 head 中,时可以使用它来先让整个 HTML 文档加载完毕,再执行 js 文件
onmousedown		// 鼠标按钮被按下
onmousemove		// 鼠标被移动
onmouseout		// 鼠标从某个元素移开
onmouseover		// 鼠标移到某元素之上
onmouseleave	// 鼠标从元素离开

onselect		// 文本被选中
onsubmit		// 确认按钮被点击

事件绑定

给节点对象绑定事件,有两种方法:

  • 在元素节点中直接绑定
  • 先找到节点对象,然后在 JS 代码中绑定事件,完美的实现了 HTML与JS的解耦
<input type='text' class='t1' onclick='f()'>		// 方法一
    
// 方法二
<script>
    var input = document.getElementsByClassName('t1');
	input.onclick = function{
    	alert('hello');
	}
</script>

方法二可以给多给对象绑定事件,但是先遍历(for 循环)。

示例1:输入框

鼠标点击输入框,输入框中原有内容消失,可输入内容,退出内容不消失。

<input type="text" class="t1" value="请输入用户名" onfocus="f1()" onblur="f2()">

var input = document.getElementsByClassName('t1')[0];   // 获取 input 节点
    function f1() {
 // 当鼠标点击 input 节点的输入框时,输入框获得鼠标焦点,可输入内容,输入框中原有内容"请输入用户名"消失
        // 只有当 value == '请输入用户名'时,才把 value 赋值为空,这样可以保留用户输入的内容
        if (input.value == '请输入用户名'){
            input.value = '';
        }

    }

    function f2() {
// 鼠标移开,输入框失去焦点,若输入的内容为空,则输入框中内容依然为"请输入用户名"; 否则为输入内容
    // trim() 去掉空格
        if (!input.value.trim()){
            input.value = "请输入用户名";
        }
    }

示例2:onload 事件

有时我们希望页面加载完毕立刻执行,就可以使用该事件属性,只能给 body 元素加。

<head>
    <script>
        function f() {
            var div = document.getElementsByClassName('box')[0];
            console.log(div);
        }
    </script>
</head>
<body onload="f()">
	<div class="box">hello</div>
</body>

JS 文件放在 head 标签中,会找到节点对象。这是因为 HTML 文档从上至下加载,当加载到 JS 文件时,因为body,所以找不到相关的节点对象。

我们可以给 body 标签加一个 onload 事件,这样只有等整个 HTML 加载完毕后,才会执行 JS 文件,就不存在找不到节点对象了。


JavaScript中的 this 作用

this 是函数在运行时,自动生成的一个内部对象,只能在函数内部使用,总是指向调用它所在的方法对象。

<body>
	<span onclick="f(this)"></span>

	<script>
    	function f(n) {
        	console.log(n);		// <span onclick="f(this)">
    	}
	</script>
</body>

上面代码中,this 是 span 节点对象的一个引用,把它传递给函数 f 的参数 n,打印 n 发现是 span 节点对象


onsumbit 事件

该事件应用在表单提交时,只能给 form 属性使用。在用户提交前验证是否输入正确,如果验证失败,则阻止表单的提交。(验证:前端验证,后代数据库验证)

<form id="fo" action="">
    <input type="text">
    <input type="submit" value="提交">
</form>

<script>
    var ele = document.getElementById('fo');
    ele.onsubmit = function (event) {
        alert('验证错误,阻止提交');
//        return false;			// 方式一,返回 false 阻止表单的提交
        event.preventDefault()		// 方式二,通知浏览器不执行与事件关联的默认动作
    }

Event 对象

Event 对象表示事件的状态,如事件在其中发生的元素、键盘按键的状态、鼠标的位置以及鼠标按钮状态。

通常与函数结合使用,函数不会再事件发生前被执行。事件发生时 event 对象就被创建好了,在函数调用时传给事件函数,我们仅需要接收即可使用。


事件传播

现在有两个盒子,div2 在 div1 里面,给每个盒子绑定一个 onclick 事件,当我们当即 div2 的时候,div1 的事件也被触发,这是因为事件传播。我们可以通过 event 对象调用 stopPropagation() 方法阻止事件传播:

<html>
    <head>
        <style type='text/css'>
            .box1{
                width: 200px;
                height: 200px;
                background-color: red;
            }
            
            box2{
                width: 100px;
                height: 100px;
                background-color: pink;
            }
        </style>
    </head>
    <body>
        <div class='box1'></div>
        <div class='box2'></div>
            
        <script>
        	var ele1 = document.getElementByClassName('box1')[0];
            ele1.onclick = function(event){
                alert('box1');
                // event.stopPropagation() 	// 阻止事件传播
            }
            
            var ele2 = document.getElementByClassName('box1')[0];
            ele2.onclick = function(event){
                alert('box2');
            }
        </script>
    </body>
</html>

8.3 节点对象增删改查

  • createElement(name):创建一个元素节点
  • appendChild():添加元素节点
  • replaceChild(newnode,oldnode):替换元素节点

  • removeChild():删除元素节点

ele.innerHTML	  // 修改元素节点和文本
ele.innerText	// 修改节点文本

// 修改 css 样式
ele.style.color			
ele.style.fontSize
...

// 修改 HTML 属性
ele.setAttribute(name, value)	// 修改节点属性
ele.getAttribute(name)		// 获取节点属性


查找节点对象就是通过节点的(class、id 、name属性,标签名字)查找。


元素节点 class 属性的相关操作

  • className:获取 class 值
  • classList:获取 class 属性值集合
  • classList.add:增加 class 属性值
  • classList.remove:删除 class 属性值
<div class="box box2"></div>

var div = document.getElementsByClassName('box')[0];
console.log(div.className);			// box box2
console.log(div.classList);			// DOMTokenList [ "box", "box2" ]


示例1:点击 add 按钮添加 h1 标签,点击 del 按钮删除 p 标签:

<div class="box">
    <p>你好</p>
    <button onclick="add()">add</button>
    <button onclick="del()">del</button>
</div>

var div = document.getElementsByClassName('box')[0];

function add() {
    var h1 = document.createElement('h1');
    h1.innerHTML = '一级标题';
    div.appendChild(h1);
}

function del() {
    // 删除
    var p = document.getElementsByTagName('p')[0];
    div.removeChild(p);
}

Tips: 给元素添加、删除元素节点,需要先找到其父节点,才能添加删除

示例2:模态对话框

是指在用户想要对对话框以外的应用程序进行操作时,必须首先对该对话框进行响应。如单击【确定】或【取消】按钮等将该对话框关闭。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模态对话框</title>
    <style>
        .box1{
            height: 1800px;
            background-color: pink;
        }

        .box2{
            position: fixed;
            background-color: #777777;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            opacity: 0.7;

        }

        .box3{
            width: 100px;
            height: 100px;
            background-color: red;
            position: absolute;
            top: 50%;
            left: 50%;
        }

        .hidden{
            display: none;
        }
    </style>
</head>
<body>

<div class="box1">
    一级
    <button onclick="show()">显示</button>
</div>

<div class="box2 hidden">

</div>


<div class="box3 hidden">
    <button onclick="hide()">隐藏</button>
</div>


<script>
    var box2 = document.getElementsByClassName('box2')[0];
    var box3 = document.getElementsByClassName('box3')[0];
    
    // 显示
    function show() {
        box2.classList.remove('hidden');
        box3.classList.remove('hidden');
    }
    
    // 隐藏
    function hide() {
        box2.classList.add('hidden');
        box3.classList.add('hidden');
    }
</script>
</body>
</html>

示例3:全选取消反选

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>page1</title>
</head>
<body>

<button onclick="selectAll()">全选</button>
<button onclick="cancel()">取消</button>
<button onclick="reverse()">反选</button>

<table border="1px solid black">
    <tr>
        <td><input type="checkbox"></td>
        <td>111</td>
        <td>222</td>
        <td>333</td>
    </tr>

    <tr>
        <td><input type="checkbox"></td>
        <td>111</td>
        <td>222</td>
        <td>333</td>
    </tr>

    <tr>
        <td><input type="checkbox"></td>
        <td>111</td>
        <td>222</td>
        <td>333</td>
    </tr>
</table>

<script>
    var inputs = document.getElementsByTagName('input');

    // 全选
    function selectAll() {
        for (var i=0; i<inputs.length; i++){
            var input = inputs[i];
            input.checked = true;
        }

    }

    // 取消
    function cancel() {
        for (var i=0; i<inputs.length; i++){
            var input = inputs[i];
            input.checked = false;
        }

    }

    // 反选
    function reverse() {
        for (var i=0; i<inputs.length; i++){
            var input = inputs[i];

            if (input.checked){
                input.checked = false;
            }
            else{
                input.checked = true;
            }

        }

    }
</script>
</body>
</html>

示例4:二级联动

知识点:

  • select 标签的 selectedIndex 属性(获取option 标签的索引)
  • options数组:selected 标签下的 option 标签集合
  • onchange:域的内容改变触发事件

参考:HTML DOM options 集合

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <select id="provience">
        <option value="">选择省份</option>
    </select>


    <select id="citys">
        <option value="">选择城市</option>
    </select>

<script>
    data = {'湖南省': ['长沙', '湘潭', '株洲'], '广东省': ['深圳', '广州', '湛江'], '广西省': ['玉林', '南宁', '河池']};
    var pro_ele = document.getElementById('provience');
    var citys_ele = document.getElementById('citys');

    for (var i in data){
        var opt_ele = document.createElement('option');

        opt_ele.innerHTML = i;

        pro_ele.appendChild(opt_ele);
    }

    pro_ele.onchange = function () {
        // options 为 select 标签中所有 option 集合,数组
        
        var pro = this.options[this.selectedIndex].innerHTML;   // 省份

        var citys = data[pro];       // 取出城市
        
        citys_ele.options.length = 1;   // 设置每个 options 的长度为 1,这样就不会累加

        for (var j in citys){
            var ele = document.createElement('option');
            ele.innerHTML = citys[j];

            citys_ele.appendChild(ele);
        }
    }
</script>
</body>
</html>

posted @ 2019-05-10 23:41  Hubery_Jun  阅读(240)  评论(0编辑  收藏  举报