【前端】JavaScript
一、JavaScript概述
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是规范.
2.ECMAScript
尽管 ECMAScript 是一个重要的标准,但它并不是 JavaScript 唯一的部分,当然,也不是唯一被标准化的部分。实际上,一个完整的 JavaScript 实现是由以下 3 个不同部分组成的:
- 核心(ECMAScript)
- 文档对象模型(DOM) Document object model (整合js,css,html)
- 浏览器对象模型(BOM) Broswer object model(整合js和浏览器)
- Javascript 在开发中绝大多数情况是基于对象的.也是面向对象的.
简单地说,ECMAScript 描述了以下内容:
- 语法
- 类型
- 语句
- 关键字
- 保留字
- 运算符
- 对象 (封装 继承 多态) 基于对象的语言.使用对象.
二、JavaScript的基础
1.JS的引入方式
1 直接编写 <script> alert('hello yuan') </script> 2 导入文件 <script src="hello.js"></script>
2.JS的变量、常量和标识符
2.1:JS的变量
(1)声明变量时不用声明变量类型,全都使用var关键字;
var a;<br>a=3;
(2)一行可以声明多个变量,并且可以是不同类型
var name="yuan", age=20, job="lecturer";
(3)声明变量时,可以不用var,如果不用var,那么它是全局变量
(4)变量命名,首字符只能是字母,下划线,$美元符 三选一,余下的字符可以是下划线、美元符号或任何字母或数字字符且区分大小写,x与X是两个变量
Camel 标记法 首字母是小写的,接下来的字母都以大写字符开头。例如: var myTestValue = 0, mySecondValue = "hi"; Pascal 标记法 首字母是大写的,接下来的字母都以大写字符开头。例如: Var MyTestValue = 0, MySecondValue = "hi"; 匈牙利类型标记法 在以 Pascal 标记法命名的变量前附加一个小写字母(或小写字母序列),说明该变量的类型。例如,i 表示整数,s 表示字符串,如下所示“ Var iMyTestValue = 0, sMySecondValue = "hi";
2.2:常量和标识符
常量:直接在程序中出现的数据值
标识符:
- 由不以数字开头的字母、数字、下划线(_)、美元符号($)组成
- 常用于表示函数、变量等的名称
- 例如:_abc,$abc,abc,abc123是标识符,而1abc不是
- JavaScript语言中代表特定含义的词称为保留字,不允许程序再定义为标识符
3.JS的数据类型
number ----- 数值 boolean ----- 布尔值 string ----- 字符串 undefined ----- undefined null ----- null
3.1:数字类型(number)
- 不区分整型数值和浮点型数值;
- 所有数字都采用64位浮点格式存储,相当于Java和C语言中的double格式
- 能表示的最大值是±1.7976931348623157 x 10308
- 能表示的最小值是±5 x 10 -324
整数:
在JavaScript中10进制的整数由数字的序列组成
精确表达的范围是
-9007199254740992 (-253) 到 9007199254740992 (253)
超出范围的整数,精确度将受影响
浮点数:
使用小数点记录数据
例如:3.4,5.6
使用指数记录数据
例如:4.3e23 = 4.3 x 1023
16进制和8进制数的表达:
16进制数据前面加上0x,八进制前面加0;16进制数是由0-9,A-F等16个字符组成;8进制数由0-7等8个数字组成
3.2:字符串类型(string)
是由Unicode字符、数字、标点符号组成的序列;字符串常量首尾由单引号或双引号括起;JavaScript中没有字符类型;常用特殊字符在字符串中的表达
字符串中部分特殊字符必须加上右斜杠\;常用的转义字符:
\n:换行 \':单引号 \":双引号 \\:右斜杠
3.3:布尔类型(boolean)
Boolean类型仅有两个值:true和false,也代表1和0,实际运算中true=1,false=0
布尔值也可以看作on/off、yes/no、1/0对应true/false
Boolean值主要用于JavaScript的控制语句,例如:
f (x==1){ y=y+1; }else{ y=y-1; }
3.4:Null & Undefined类型
Undefined类型
Undefined 只有一个值,即undefined。当生命的变量未初始化时,该变量的默认值是undefined。当函数无明确返回值时,返回的也是值“undefined”;
Null类型
另一种只有一个值的类型是Null,它只有一个专用值null,即它的字面量。值undefined实际上是从值null派生来的,因此ECMAScript把他们定义为相等的。
尽管这两个值相等,但它们的含义不同。undefined是声明了变量但未对其初始化时赋予该变量的值,null则用于表示尚未存在的对象(在讨论typeof运算符时,简单的介绍过这一点)。如果函数或方法要返回的是对象,name找不到该对象时,返回的通常是null。
4.运算符
算术运算符: + - * / % ++(自加一) -- 比较运算符: > >= < <= != == === !== 逻辑运算符: && || ! (逻辑与或非) 赋值运算符: = += -= *= /= 字符串运算符: + 连接,两边操作数有一个或两个是字符串就做连接运算
4.1:算术运算符
(1)自加自减
假如x=2,那么x++表达式执行后的值为3,x--表达式执行后的值为1;i++相当于i=i+1,i--相当于i=i-1;
递增和递减运算符可以放在变量前也可以放在变量后:--i
x++(先赋值再计算) var ret=x++:ret=10 ++x(先计算后赋值) var ret=++x:ret=11
(2)单元运算符
- 除了可以表示减号还可以表示负号 例如:x=-y + 除了可以表示加法运算还可以用于字符串的连接 例如:"abc"+"def"="abcdef"
JS不同于python,是一门弱类型语言
静态类型语言 一种在编译期间就确定数据类型的语言。大多数静态类型语言是通过要求在使用任一变量之前声明其数据类型来保证这一点的。Java 和 C 是静态类型语言。 动态类型语言 一种在运行期间才去确定数据类型的语言,与静态类型相反。VBScript 和 Python 是动态类型的,因为它们确定一个变量的类型是在您第一次给它赋值的时候。 强类型语言 一种总是强制类型定义的语言。Java 和 Python 是强制类型定义的。您有一个整数,如果不明确地进行转换 ,不能将把它当成一个字符串去应用。 弱类型语言 一种类型可以被忽略的语言,与强类型相反。JS 是弱类型的。在JS中,可以将字符串 '12' 和整数 3 进行连接得到字符串'123',然后可以把它看成整数 123 ,所有这些都不需要任何的显示转换。 所以说 Python 既是动态类型语言 (因为它不使用显示数据类型声明),又是强类型语言 (因为只要一个变量获得了一个数据类型,它实际上就一直是这个类型了)。
(3)NaN
var d="yuan"; d=+d; alert(d);//NaN:属于Number类型的一个特殊值,当遇到将字符串转成数字无效时,就会得到一个NaN数据 alert(typeof(d));//Number //NaN特点: var n=NaN; alert(n>3); alert(n<3); alert(n==3); alert(n==NaN); alert(n!=NaN);//NaN参与的所有的运算都是false,除了!=
4.2:比较运算符
> >= < <= != == === !==
用于控制语句时:
if (2>1){ // 3 0 false null undefined [] console.log("条件成立!") }
等号和非等号的同类运算符是全等号和非全等号。这两个运算符所做的与等号和非等号相同,只是它们在检查相等性前,不执行类型转换。
console.log(2==2); console.log(2=="2"); #自动执行类型转换 console.log(2==="2"); #不执行类型转换 console.log(2!=="2"); #不执行类型转换
注意1:
比较运算符两侧如果一个是数字类型,一个是其他类型,会将其类型转换成数字类型.
比较运算符两侧如果都是字符串类型,比较的是最高位的asc码,如果最高位相等,继续取第二位比较.
注意2:
等性运算符:执行类型转换的规则如下: 如果一个运算数是 Boolean 值,在检查相等性之前,把它转换成数字值。false 转换成 0,true 为 1。 如果一个运算数是字符串,另一个是数字,在检查相等性之前,要尝试把字符串转换成数字。 如果一个运算数是对象,另一个是字符串,在检查相等性之前,要尝试把对象转换成字符串。 如果一个运算数是对象,另一个是数字,在检查相等性之前,要尝试把对象转换成数字。 在比较时,该运算符还遵守下列规则: 值 null 和 undefined 相等。 在检查相等性时,不能把 null 和 undefined 转换成其他值。 如果某个运算数是 NaN,等号将返回 false,非等号将返回 true。 如果两个运算数都是对象,那么比较的是它们的引用值。如果两个运算数指向同一对象,那么等号返回 true,否则两个运算数不等。
5.流程控制
5.1:顺序结构
<script> console.log(“星期一”); console.log(“星期二”); console.log(“星期三”); </script>
5.2:分支结构
if-else结构:
if (表达式){ 语句1; ...... }
else{ 语句2; ..... }
如果表达式的值为true则执行语句1,否则执行语句2
if-elif-else结构:
if (表达式1) { 语句1; }
else if (表达式2){ 语句2; }
else if (表达式3){ 语句3; }
else{ 语句4; }
seitch-case结构
switch比else if结构更加简洁清晰,使程序可读性更强,效率更高。
switch基本格式 switch (表达式) { case 值1:语句1;break; case 值2:语句2;break; case 值3:语句3;break; default:语句4; }
var week=3; switch (week){ case 1:console.log("礼拜一");break; case 2:console.log("礼拜2");break; case 3:console.log("礼拜3");break; case 4:console.log("礼拜4");break; case 5:console.log("礼拜5");break; case 6:console.log("礼拜6");break; case 7:console.log("礼拜7");break; default:console.log("输入错误") }
5.2:循环结构
for循环:条件循环
语法规则: for(初始表达式;条件表达式;自增或自减) { 执行语句 …… }
功能说明:实现条件循环,当条件成立时,执行语句1,否则跳出循环体
for循环的另一种形式:遍历循环
for( 变量 in 数组或对象) { 执行语句 …… }
white循环:
语法规则: while (条件){ 语句1; ... }
功能说明:运行功能和for类似,当条件成立循环执行语句花括号{}内的语句,否则跳出循环;同样支持continue与break语句。
5.3:异常处理
try { //这段代码从上往下运行,其中任何一个语句抛出异常该代码块就结束运行 } catch (e) { // 如果try代码块中抛出了异常,catch代码块中的代码就会被执行。 //e是一个局部变量,用来指向Error对象或者其他抛出的对象 } finally { //无论try中代码是否有异常抛出(甚至是try代码块中有return语句),finally代码块中始终会被执行。 } 注:主动抛出异常 throw Error('xxxx')
三、JavaScript的对象
简介:
在JavaScript中除了null和undefined以外其他的数据类型都被定义成了对象,也可以用创建对象的方法定义变量,String、Math、Array、Date、RegExp都是JavaScript中重要的内置对象,在JavaScript程序大多数功能都是基于对象实现的。
<script language="javascript"> var aa=Number.MAX_VALUE; //利用数字对象获取可表示最大数 var bb=new String("hello JavaScript"); //创建字符串对象 var cc=new Date(); //创建日期对象 var dd=new Array("星期一","星期二","星期三","星期四"); //数组对象 </script>
3.1:string对象
3.1.1:字符串对象创建
字符串对象创建(两种方式)
(1)变量=“字符串”
(2)字符串对象名称=newstring(字符串)
var str1="hello world"; var str1= new String("hello word");
3.1.2:字符串对象的属性和函数
x.length ----获取字符串的长度 x.toLowerCase() ----转为小写 x.toUpperCase() ----转为大写 x.trim() ----去除字符串两边空格 ----字符串查询方法 x.charAt(index) ----str1.charAt(index);----获取指定位置字符,其中index为要获取的字符索引 x.indexOf(findstr,index)----查询字符串位置 x.lastIndexOf(findstr) x.match(regexp) ----match返回匹配字符串的数组,如果没有匹配则返回null x.search(regexp) ----search返回匹配字符串的首字符位置索引 示例: var str1="welcome to the world of JS!"; var str2=str1.match("world"); var str3=str1.search("world"); alert(str2[0]); // 结果为"world" alert(str3); // 结果为15 ----子字符串处理方法 x.substr(start, length) ----start表示开始位置,length表示截取长度 x.substring(start, end) ----end是结束位置 x.slice(start, end) ----切片操作字符串 示例: var str1="abcdefgh"; var str2=str1.slice(2,4); var str3=str1.slice(4); var str4=str1.slice(2,-1); var str5=str1.slice(-3,-1); alert(str2); //结果为"cd" alert(str3); //结果为"efgh" alert(str4); //结果为"cdefg" alert(str5); //结果为"fg" x.replace(findstr,tostr) ---- 字符串替换 x.split(); ----分割字符串 var str1="一,二,三,四,五,六,日"; var strArray=str1.split(","); alert(strArray[1]);//结果为"二" x.concat(addstr) ---- 拼接字符串
3.2:Array对象
3.2.1:数组创建
创建数组的三种方式:
创建方式1: var arrname = [元素0,元素1,….]; // var arr=[1,2,3]; 创建方式2: var arrname = new Array(元素0,元素1,….); // var test=new Array(100,"a",true); 创建方式3: var arrname = new Array(长度); // 初始化数组对象: var cnweek=new Array(7); cnweek[0]="星期日"; cnweek[1]="星期一"; ... cnweek[6]="星期六";
var cnweek=new Array(7); for (var i=0;i<=6;i++){ cnweek[i]=new Array(2); } cnweek[0][0]="星期日"; cnweek[0][1]="Sunday"; cnweek[1][0]="星期一"; cnweek[1][1]="Monday"; ... cnweek[6][0]="星期六"; cnweek[6][1]="Saturday";
3.2.2:数组对象的属性和方法
(1)join方法:将数组元素拼接成字符串
x.join(bystr) ----将数组元素拼接成字符串 var arr1=[1, 2, 3, 4, 5, 6, 7]; var str1=arr1.join("-"); alert(str1); //结果为"1-2-3-4-5-6-7"
(2)concat方法:连接两个字符串
toString方法(原生类方法):将对象转换成字符串
x.concat(value,...) ---- var a = [1,2,3]; var b=a.concat(4,5) ; alert(a.toString()); //返回结果为1,2,3 alert(b.toString()); //返回结果为1,2,3,4,5
(3)数组排序-reverse(反转) sort:
//x.reverse() //x.sort() var arr1=[32, 12, 111, 444]; //var arr1=["a","d","f","c"]; arr1.reverse(); //颠倒数组元素 alert(arr1.toString()); //结果为444,111,12,32 arr1.sort(); //排序数组元素 alert(arr1.toString()); //结果为111,12,32,444,sort排序默认会以最高位的asc码来排
(4)数组切片操作:slice
//x.slice(start, end) // //使用注解 // //x代表数组对象 //start表示开始位置索引 //end是结束位置下一数组元素索引编号 //第一个数组元素索引为0 //start、end可为负数,-1代表最后一个数组元素 //end省略则相当于从start位置截取以后所有数组元素 var arr1=['a','b','c','d','e','f','g','h']; var arr2=arr1.slice(2,4); var arr3=arr1.slice(4); var arr4=arr1.slice(2,-1); alert(arr2.toString()); //结果为"c,d" alert(arr3.toString()); //结果为"e,f,g,h" alert(arr4.toString()); //结果为"c,d,e,f,g"
(5)删除子数组:splice
//x. splice(start, deleteCount, value, ...) //使用注解 //x代表数组对象 //splice的主要用途是对数组指定位置进行删除和插入 //start表示开始位置索引 //deleteCount删除数组元素的个数 //value表示在删除位置插入的数组元素 //value参数可以省略 var a = [1,2,3,4,5,6,7,8]; a.splice(1,2); alert(a.toString());//a变为 [1,4,5,6,7,8] a.splice(1,1); alert(a.toString());//a变为[1,5,6,7,8] a.splice(1,0,2,3); alert(a.toString());//a变为[1,2,3,5,6,7,8]
(6)数组的push和pop
//push pop这两个方法模拟的是一个栈操作 //x.push(value, ...) 压栈 //x.pop() 弹栈 //使用注解 // //x代表数组对象 //value可以为字符串、数字、数组等任何值 //push是将value值添加到数组x的结尾 //pop是将数组x的最后一个元素删除 var arr1=[1,2,3]; arr1.push(4,5); alert(arr1); //结果为"1,2,3,4,5" arr1.push([6,7]); alert(arr1) //结果为"1,2,3,4,5,6,7" arr1.pop(); alert(arr1); //结果为"1,2,3,4,5"
(7)数组的shift和unshift
//x.unshift(value,...) //x.shift() //使用注解 //x代表数组对象 //value可以为字符串、数字、数组等任何值 //unshift是将value值插入到数组x的开始 //shift是将数组x的第一个元素删除 var arr1=[1,2,3]; arr1.unshift(4,5); alert(arr1); //结果为"4,5,1,2,3" arr1. unshift([6,7]); alert(arr1); //结果为"6,7,4,5,1,2,3" arr1.shift(); alert(arr1); //结果为"4,5,1,2,3"
3.3:Date对象
3.3.1:创建date对象
//方法1:不指定参数 var nowd1=new Date(); alert(nowd1.toLocaleString( )); //方法2:参数为日期字符串 var nowd2=new Date("2004/3/20 11:12"); alert(nowd2.toLocaleString( )); var nowd3=new Date("04/03/20 11:12"); alert(nowd3.toLocaleString( )); //方法3:参数为毫秒数 var nowd3=new Date(5000); alert(nowd3.toLocaleString( )); alert(nowd3.toUTCString()); //方法4:参数为年月日小时分钟秒毫秒 var nowd4=new Date(2004,2,20,11,12,0,300); alert(nowd4.toLocaleString( ));//毫秒并不直接显示
3.3.2:Date对象的方法--获取日期和时间
获取日期和时间 getDate() 获取日 getDay () 获取星期 getMonth () 获取月(0-11) getFullYear () 获取完整年份 getYear () 获取年 getHours () 获取小时 getMinutes () 获取分钟 getSeconds () 获取秒 getMilliseconds () 获取毫秒 getTime () 返回累计毫秒数(从1970/1/1午夜)
3.3.3:Date对象的方法—设置日期和时间
//设置日期和时间 //setDate(day_of_month) 设置日 //setMonth (month) 设置月 //setFullYear (year) 设置年 //setHours (hour) 设置小时 //setMinutes (minute) 设置分钟 //setSeconds (second) 设置秒 //setMillliseconds (ms) 设置毫秒(0-999) //setTime (allms) 设置累计毫秒(从1970/1/1午夜) var x=new Date(); x.setFullYear (1997); //设置年1997 x.setMonth(7); //设置月7 x.setDate(1); //设置日1 x.setHours(5); //设置小时5 x.setMinutes(12); //设置分钟12 x.setSeconds(54); //设置秒54 x.setMilliseconds(230); //设置毫秒230 document.write(x.toLocaleString( )+"<br>"); //返回1997年8月1日5点12分54秒 x.setTime(870409430000); //设置累计毫秒数 document.write(x.toLocaleString( )+"<br>"); //返回1997年8月1日12点23分50秒
3.4:Math对象
//该对象中的属性方法 和数学有关. abs(x) 返回数的绝对值。 exp(x) 返回 e 的指数。 floor(x)对数进行下舍入。 log(x) 返回数的自然对数(底为e)。 max(x,y) 返回 x 和 y 中的最高值。 min(x,y) 返回 x 和 y 中的最低值。 pow(x,y) 返回 x 的 y 次幂。 random() 返回 0 ~ 1 之间的随机数。 round(x) 把数四舍五入为最接近的整数。 sin(x) 返回数的正弦。 sqrt(x) 返回数的平方根。 tan(x) 返回角的正切。 //方法练习: //alert(Math.random()); // 获得随机数 0~1 不包括1. //alert(Math.round(1.5)); // 四舍五入 //练习:获取1-100的随机整数,包括1和100 //var num=Math.random(); //num=num*10; //num=Math.round(num); //alert(num) //============max min========================= /* alert(Math.max(1,2));// 2 alert(Math.min(1,2));// 1 */ //-------------pow-------------------------------- alert(Math.pow(2,4));// pow 计算参数1 的参数2 次方.
3.5:Function对象(重点)
3.5.1:函数的定义
function 函数名 (参数){ <br> 函数体; return 返回值; }
功能说明:
可以使用变量、常量或表达式作为函数调用的参数,
函数由关键字function定义,
函数名的定义规则与标识符一致,大小写是敏感的,
返回值必须使用return,
function类可以表示开发者定义的任何函数。
用Function类直接创建函数的语法如下:
var 函数名 = new Function("参数1","参数n","function_body");
虽然由于字符串的关系,第二种形式写起来有些困难,但有助于理解函数只不过是一种引用类型,它们的行为与用Function类明确创建的函数行为是相同的
function func1(name){ alert('hello'+name); return 8 } ret=func1("alex"); alert(ret);
var func2=new Function("name","alert(\"hello\"+name);") func2("amos")
注意:js的函数加载执行与python不同,它是整体加载完才会执行,所以执行函数放在函数声明上面或下面都可以
3.5.2:函数的内置对象arguments
arguments:可以接收任何参数,相当于python的*args
function add(a,b){ console.log(a+b);//3 console.log(arguments.length);//2 console.log(arguments);//[1,2] } add(1,2) ------------------arguments的用处1 ------------------ function nxAdd(){ var result=0; for (var num in arguments){ result+=arguments[num] } alert(result) } nxAdd(1,2,3,4,5) // ------------------arguments的用处2 ------------------ function f(a,b,c){ if (arguments.length!=3){ throw new Error("function f called with "+arguments.length+" arguments,but it just need 3 arguments") } else { alert("success!") } } f(1,2,3,4,5)
3.5.3:匿名函数
// 匿名函数 var func = function(arg){ return "tony"; } // 匿名函数的应用 (function(){ alert("tony"); } )() (function(arg){ console.log(arg); })('123')
四、BOM对象
window(窗口)对象
所有浏览器都支持 window 对象。
概念上讲.一个html文档对应一个window对象.
功能上讲: 控制浏览器窗口的.
使用上讲: window对象不需要创建对象,直接使用即可.
4.1:window对象方法
alert() 显示带有一段消息和一个确认按钮的警告框。 confirm() 显示带有一段消息以及确认按钮和取消按钮的对话框。 prompt() 显示可提示用户输入的对话框。 open() 打开一个新的浏览器窗口或查找一个已命名的窗口。 close() 关闭浏览器窗口。 setInterval() 按照指定的周期(以毫秒计)来调用函数或计算表达式。 clearInterval() 取消由 setInterval() 设置的 timeout。 setTimeout() 在指定的毫秒数后调用函数或计算表达式。 clearTimeout() 取消由 setTimeout() 方法设置的 timeout。 scrollTo() 把内容滚动到指定的坐标。
方法使用
setInterval,clearInterval
setinterval()方法会不停地调用函数,直到clearInterval()被调用或者窗口被关闭。由setinterval()返回的ID值可作clearinterval()方法的参数。
语法:setInterval(code,millisec) 其中,code为要调用的函数或要执行的代码串。millisec周期性执行或调用 code 之间的时间间隔,以毫秒计。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> <script> var ID; function start() { if (ID==undefined){ foo(); ID=setInterval(foo,1000) } } function foo() { var timer=new Date().toString(); //获取当前时间字符串 var ele=document.getElementById("time"); // 获取操作标签对象 ele.value=timer; // 对操作标签对象进行赋值 } function end() { clearInterval(ID); ID=undefined } </script> </head> <body> <input type="text" id="time"> <button onclick="start()">start</button> <button onclick="end()">end</button> </body> </html>
五、DOM对象
5.1:什么是HTML DOM
- HTML Document Object Model(文档对象模型)
- HTML DOM 定义了访问和操作HTML文档的标准方法
- HTML DOM 把 HTML 文档呈现为带有元素、属性和文本的树结构(节点树)
5.2:DOM树
5.3:DOM节点
5.3.1:节点类型
HTML文档中的每个成分都是一个节点。
DOM是这样规定的:
- 整个文档是一个文档节点
- 每个HTML标签是一个元素节点
- 包含在HTML元素中的文本是文本节点
- 每一个HTML属性是一个属性节点
其中,document与element节点是重点。
5.3.2:节点关系
节点树中的节点彼此拥有层级关系。
父(parent),子(child)和同胞(sibling)等术语用于描述这些关系。父节点拥有子节点。同级的子节点被称为同胞(兄弟或姐妹)。
- 在节点树中,顶端节点被称为根(root)
- 每个节点都有父节点、除了根(它没有父节点)
- 一个节点可拥有任意数量的子
- 同胞是拥有相同父节点的节点
5.3.3:节点查找
直接查找节点
document.getElementById(“idname”) #通过ID查找 下面的取出来是多个标签,以数组的形式显示 document.getElementsByTagName(“tagname”) #通过标签名查找 document.getElementsByName(“name”) #通过name查找 document.getElementsByClassName(“name”) #通过class查找
导航节点属性
parentElement // 父节点标签元素 children // 所有子标签 firstElementChild // 第一个子标签元素 lastElementChild // 最后一个子标签元素 nextElementtSibling // 下一个兄弟标签元素 previousElementSibling // 上一个兄弟标签元素 注意,js中没有办法找到所有的兄弟标签! 可以找到所有父标签的子标签,然后排除自己
5.3.4:节点操作
(1)创建节点
createElement(标签名) :创建一个指定名称的元素。 例:var tag=document.createElement(“input") tag.setAttribute('type','text');
(2)添加节点:父节点添加子节点
追加一个子节点(作为最后的子节点) 父标签.appendChild(添加标签) 把增加的节点放到某个节点的前边 #兄弟之间的添加 somenode.insertBefore(newnode,某个节点);
(3)删除节点:父节点删除子节点
父标签.removeChild(要删除的标签):获得要删除的元素,通过父元素调用删除
(4)替换节点
父标签.replaceChild(新节点, 父标签中的某个节点);
(5)拷贝节点
cloneNode():浅拷贝,只拷贝标签 cloneNode(true):深拷贝,连同标签内的标签也一起拷贝过去 注意:拷贝会把ID也拷贝过去
(6)节点属性操作
1.获取文本节点的值:
innerText(不认标签,只认文本):赋值时都会赋成纯文本 innerHTML(标签文本都可以识别):赋值时可以赋标签, 都会删除原来的内容然后添加内容
2.取值操作:
方式一:
element.getAttribute(属性名)(可以取到自定义属性)
方式二: element.属性名(推荐,只能取到固有属性,取不到自定义属性)
方式一:
element.setAttribute(属性名,属性值)
方式二:
element.属性名="属性值"
4.select标签操作
this.selectedIndex 拿到和用户选中标签索引 this.options 相当于拿到子标签 this.options[this.selectedIndex].innerText 拿到选中标签的值 ele_select.options.length=0 清空select标签的集合,可以设定保留几个值
5.4:DOM Event(事件)
5.4.1:事件类型:事件都是由操作系统监听的
onclick 当用户点击某个对象时调用的事件句柄。 ondblclick 当用户双击某个对象时调用的事件句柄。 onfocus 元素获得焦点。 练习:输入框 onblur 元素失去焦点。 应用场景:用于表单验证,用户离开某个输入框时,代表已经输入完了,我们可以对它进行验证. onchange 域的内容被改变(主要应用于select标签)。 应用场景:通常用于表单元素,当元素内容被改变时触发.(三级联动) onkeydown 某个键盘按键被按下。 应用场景: 当用户在最后一个输入框按下回车按键时,表单提交. onkeypress 某个键盘按键被按下并松开。 onkeyup 某个键盘按键被松开。 window.onload 一张页面或一幅图像完成加载。 onmousedown 鼠标按钮被按下。和onclick不同的是他里面还可以配合onmousemove使用 onmousemove 鼠标被移动。 onmouseout 鼠标从某元素移开。 onmouseover 鼠标移到某元素之上。 onmouseleave 鼠标从元素离开 //onmouseout和onmouseleave的区别 // 1.不论鼠标指针离开被选元素还是任何子元素,都会触发 mouseout 事件。 // 2.只有在鼠标指针离开被选元素时,才会触发 mouseleave 事件。 onselect 文本被选中。 onsubmit 确认按钮被点击(用于form表单)。
5.4.2:绑定事件方式
方式一:
<div id="div" onclick="foo(this)">点我呀</div> <script> function foo(self){ // 形参不能是this; console.log("点你大爷!"); console.log(self); } </script>
方式二
<p id="abc">试一试!</p> <script> var ele=document.getElementById("abc"); ele.onclick=function(){ console.log("ok"); console.log(this); // this直接用 }; </script>
5.4.3:事件介绍
1.onload:
onload属性在开发中只给body元素加,这个属性的触发标志着页面内容被加载完成,应用场景:当有些事情我们希望页面加载完立刻执行,那么可以使用该事件属性。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script> window.onload=function () { var ele=document.getElementById("c1"); ele.style.color="green"; }; </script> </head> <body> <div id="c1">div</div> </body> </html>
2.onsubmit:
当表单在提交时触发,该属性也只能给form元素使用,应用场景:在表单提交验证用户输入是否正确,如果验证失败,在该方法中我们应该阻止表单的提交
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <form action="" id="form"> <p>姓名 <input type="text" id="name"></p> <p>密码 <input type="password" id="psw"></p> <input type="submit"> </form> <script> var ele_form=document.getElementById("form"); var ele_name=document.getElementById("name"); var ele_psw=document.getElementById("psw"); ele_form.onsubmit=function () { if (ele_name.value.length < 5){ var ele_err=document.createElement("span"); ele_err.innerHTML="输入字符必须大于5"; ele_err.style.color="red"; ele_form.appendChild(ele_err); return false } } </script> </body> </html>
3.事件传播:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> <style> .outer{ width: 400px; height: 400px; background-color: #396bb3; } .inner{ width: 200px; height: 200px; background-color: #e59373; } </style> </head> <body> <div class="outer"> <div class="inner"></div> </div> </body> <script> var ele_outer=document.getElementsByClassName("outer")[0]; var ele_inner=document.getElementsByClassName("inner")[0]; ele_outer.onclick=function () { alert(123) }; ele_inner.onclick=function (e) { alert(456); e.stopPropagation() //阻止事件传播 } </script> </html>
4.onselect:文本被选中时
<input type="text"> <script> var ele=document.getElementsByTagName("input")[0]; ele.onselect=function(){ alert(123); } </script>
5.onchange
<select name="" id=""> <option value="">111</option> <option value="">222</option> <option value="">333</option> </select> <script> var ele=document.getElementsByTagName("select")[0]; ele.onchange=function(){ alert(123); } </script>
6.onkeydown:
Event对象:Event对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。
事件通常与函数结合使用,函数不会在事件发生前被执行!event对象在事件发生时系统已经创建好了,并且会在事件函数被调用时传给事件函数,我们获得仅仅需要接收一下即可,比如onkeydown,我们想知道哪个键被按下了,需要问下event对象的属性,这里就是keyCode。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <input type="text" id="user"> </body> <script> var ele=document.getElementById("user"); // event对象是保存事件触发状态的对象,由操作系统发送 ele.onkeydown=function (e) { e=e||window.event; console.log(String.fromCharCode(e.keyCode)); //e.keyCode拿到的是按下键的asc码,然后用String.fromCharCode方法拿到用户按下的键 } </script> </html>
7.onmouseout与onmouseleave事件的区别:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> #container{ width: 300px; } #title{ cursor: pointer; background: #ccc; } #list{ display: none; background:#fff; } #list div{ line-height: 50px; } #list .item1{ background-color: green; } #list .item2{ background-color: rebeccapurple; } #list .item3{ background-color: lemonchiffon; } </style> </head> <body> <p>先看下使用mouseout的效果:</p> <div id="container"> <div id="title">使用了mouseout事件↓</div> <div id="list"> <div class="item1">第一行</div> <div class="item2">第二行</div> <div class="item3">第三行</div> </div> </div> <script> // 1.不论鼠标指针离开被选元素还是任何子元素,都会触发 mouseout 事件。 // 2.只有在鼠标指针离开被选元素时,才会触发 mouseleave 事件。 var container=document.getElementById("container"); var title=document.getElementById("title"); var list=document.getElementById("list"); title.onmouseover=function(){ list.style.display="block"; }; container.onmouseleave=function(){ // 改为mouseout试一下 list.style.display="none"; }; /* 因为mouseout事件是会冒泡的,也就是onmouseout事件可能被同时绑定到了container的子元素title和list 上,所以鼠标移出每个子元素时也都会触发我们的list.style.display="none"; */ /* 思考: if: list.onmouseout=function(){ list.style.display="none"; }; 为什么移出第一行时,整个list会被隐藏? 其实是同样的道理,onmouseout事件被同时绑定到list和它的三个子元素item上,所以离开任何一个 子元素同样会触发list.style.display="none"; */ </script> </body> </html>
六、实例练习
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <select name="" id="s1"> <option value="">请选择省份</option> <option value="">山西</option> <option value="">河北</option> </select> <select name="" id="s2"> <option value="">请选择城市</option> </select> </body> <script> data={"山西":["太原","阳泉","大同"],"河北":["石家庄","邯郸"]}; var ele=document.getElementById("s1"); var ele2=document.getElementById("s2"); ele.onchange=function () { ele2.options.length=0; var ele_pro=this.children[this.selectedIndex].innerText; for (var i in data){ if (i==ele_pro){ for (var j in data[i]){ var city= document.createElement("option"); city.innerHTML=data[i][j]; ele2.appendChild(city) } } } } </script> </html>
2.模态对话框
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .back{ background-color: white; height: 2000px; } .shade{ position: fixed; top: 0; bottom: 0; left:0; right: 0; background-color: grey; opacity: 0.4; } .hide{ display: none; } .models{ position: fixed; top: 50%; left: 50%; margin-left: -100px; margin-top: -100px; height: 200px; width: 200px; background-color: wheat; } </style> </head> <body> <div class="back"> <input class="c" type="button" value="click"> </div> <div class="shade hide handles"></div> <div class="models hide handles"> <input class="c" type="button" value="cancel"> </div> <script> var eles=document.getElementsByClassName("c"); var handles=document.getElementsByClassName("handles"); for(var i=0;i<eles.length;i++){ eles[i].onclick=function(){ if(this.value=="click"){ for(var j=0;j<handles.length;j++){ handles[j].classList.remove("hide"); } } else { for(var j=0;j<handles.length;j++){ handles[j].classList.add("hide"); } } } } </script> </body> </html>
3.悬浮下拉菜单
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> <style> .container{ width: 300px; } .title{ background-color: gray; line-height: 44px; text-align: center; } .list{ display: none; } .list div{ line-height: 40px; } .item1{ background-color: #396bb3; } .item2{ background-color: #ffc392; } .item3{ background-color: #ff487f; } </style> </head> <body> <div class="container"> <div class="title">text</div> <div class="list"> <div class="item1">111</div> <div class="item2">222</div> <div class="item3">333</div> </div> </div> <script> var ele=document.getElementsByClassName("title")[0]; var ele_list=document.getElementsByClassName("list")[0]; var ele_box=document.getElementsByClassName("container")[0]; ele.onmouseover=function () { ele_list.style.display="block"; }; ele_box.onmouseleave=function () { ele_list.style.display="none" } </script> </body> </html>
4.图书管理系统
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> <style> *{ margin: 0; padding: 0; } .navbar{ float: left; width: 100%; height: 50px; background-color: #272425; } .left_menu{ float: left; width: 20%; margin-left: -1px; height: 500px; border-right: 1px solid; } .right_content{ position: relative; top: 0; left: 0; float: left; width: 77%; height: 500px; padding-left: 40px; margin-right: -1px; } .operation{ margin-top: 20px; color: white; width: 100%; height: 30px; text-align: center; line-height: 30px; background-color: #396bb3; } .operation_list{ list-style: none; } .operation_list li{ margin: 10px; font-size: 14px; } .operation_list li a{ color: #396bb3; text-decoration: none; } .book_info{ width: 100%; font-size: 14px; } td{ width: 50px; height: 40px; border-top: 1px solid #e1e1e1; } .search_box{ width: 100%; height: 100px; } #search_bar{ padding: 10px; position: absolute; right: 144px; top: 36px; width: 200px; border-radius: 7px; border: 1px solid #e1e1e1; } .search_btn{ color: white; border-radius: 5px; padding: 9px; background-color: #396bb3; position: absolute; right: 93px; top: 34px; } .hide{ display: none; } .shade{ position: fixed; top: 0; bottom: 0; left: 0; right: 0; background-color: black; opacity: 0.4; } .model,.model2{ width: 500px; height: 400px; background-color:white; position: fixed; top: 50%; left:50%; margin-top: -200px; margin-left: -250px; } .btn{ width: 50px; height: 30px; border-radius: 5px; color: white; } .btn1{ background-color: #ff1732; } .btn2{ background-color: #396bb3; } .btn3{ background-color: #4cff82; } .btn4{ background-color: #ffdd3f; } .input_field,.input_field2{ height: 30px; border-radius: 5px; margin: 10px; } .model,.model2{ padding-left: 150px; } #put,#update{ margin-left: 100px; } #cancle,#quit{ margin-left: 50px; } .head{ width: 80%; height: 100%; margin: 0 auto; } .title{ float: left; color: white; font-size: 28px; line-height: 100%; margin-top: 8px; } .index_link{ float: left; color: #e1e1e1; font-size: 15px; margin-top: 15px; margin-left: 80px; text-decoration: none; } .copyright{ line-height: 30px; text-align: center; font-size: 14px; } </style> </head> <body> <div class="outer"> <div class="navbar"> <div class="head"> <div class="title">图书管理系统</div> <div ><a href="" class="index_link">首页</a></div> </div> </div> <div class="left_menu"> <div class="operation">操作</div> <ul class="operation_list"> <!--<li><a href="" >>>>添加书籍</a></li>--> <li><a href="" >>>>草稿箱</a></li> <li><a href="" >>>>设置默认编辑器</a></li> <li><a href="" >>>>备份书籍</a></li> </ul> </div> <div class="right_content"> <div class="search_box"> <form action=""> <input type="text" placeholder="Title" id="search_bar"> </form> <button class="search_btn">查找</button> </div> <button class="btn2 btn">添加</button> <table class="book_info"> <tr> <td>图书编号</td> <td>书名</td> <td>作者</td> <td>价格</td> <td>分类</td> <td>上架时间</td> <td>操作</td> </tr> <tr> <td>1</td> <td>囚徒健身</td> <td>保罗·威德(美)</td> <td>79¥</td> <td>健身</td> <td>2013年10月</td> <td> <button class="btn4 btn">编辑</button> <button class="btn1 btn">删除</button> </td> </tr> <tr> <td>2</td> <td>万历十五年</td> <td>黄仁宇</td> <td>18¥</td> <td>历史</td> <td>1990年1月1日</td> <td> <button class="btn4 btn">编辑</button> <button class="btn1 btn">删除</button> </td> </tr> </table> </div> <div class="shade hide"></div> <div class="model hide"> <div>图书编号:<input type="text" class="input_field" value=""></div> <div> 书名:<input type="text" class="input_field" value=""></div> <div> 作者:<input type="text" class="input_field" value=""></div> <div> 价格:<input type="text" class="input_field" value=""></div> <div> 分类:<input type="text" class="input_field" value=""></div> <div>上架时间:<input type="text" class="input_field" value=""></div> <button class="btn3 btn" id="put">提交</button> <button class="btn1 btn" id="cancle">取消</button> </div> <div class="model2 hide"> <div>图书编号:<input type="text" class="input_field2" value=""></div> <div> 书名:<input type="text" class="input_field2" value=""></div> <div> 作者:<input type="text" class="input_field2" value=""></div> <div> 价格:<input type="text" class="input_field2" value=""></div> <div> 分类:<input type="text" class="input_field2" value=""></div> <div>上架时间:<input type="text" class="input_field2" value=""></div> <button class="btn3 btn" id="update">更新</button> <button class="btn1 btn" id="quit">退出</button> </div> <div class="copyright"> <p>©All rights reserved</p> <p><b>Powered by</b> Amos</p> </div> </div> <script> //拿到所有的button标签 var eles_btn=document.getElementsByTagName("button"); //删除表格一行的函数 function cancel() { var ele_grand=this.parentElement.parentElement.parentElement; var ele_father=this.parentElement.parentElement; ele_grand.removeChild(ele_father); } //编辑函数 function compile() { var ele_shade=this.parentElement.parentElement.parentElement.parentElement.nextElementSibling; var ele_model2=ele_shade.nextElementSibling.nextElementSibling; ele_shade.classList.remove("hide"); ele_model2.classList.remove("hide"); var eles_info=this.parentElement.parentElement.children; var eles_value=document.getElementsByClassName("input_field2"); edit_obj=this.parentElement.parentElement; for (var i=0;i<eles_info.length-1;i++){ eles_value[i].value=eles_info[i].innerText; } } //循环每个按钮,对应按钮进行操作 for (var i=0;i<eles_btn.length;i++){ //按钮被点击的时候 eles_btn[i].onclick=function () { //如果被点击的是添加按钮:弹出对话框 if (this.innerText=="添加"){ var eles_val=document.getElementsByClassName("input_field"); for (var i in eles_val){ eles_val[i].value=''; } var ele_shade=this.parentElement.nextElementSibling; var ele_model=ele_shade.nextElementSibling; ele_shade.classList.remove("hide"); ele_model.classList.remove("hide"); } //如果被点击的是提交按钮: // 1.拿到用户输入的值 // 2.添加一行表格 // 3.把用户输入的值添加到本行 // 4.添加删除按钮 // 5.关闭对话框 else if(this.innerText=="提交"){ var eles_val=document.getElementsByClassName("input_field"); var eles_book_info=document.getElementsByClassName("book_info"); var ele_tr=document.createElement("tr"); eles_book_info[0].appendChild(ele_tr); for (i=0;i<eles_val.length;i++){ var ele_td=document.createElement("td"); ele_td.innerText=eles_val[i].value; ele_tr.appendChild(ele_td); } //创建删除,编辑按钮 var ele_td2=document.createElement("td"); ele_tr.appendChild(ele_td2); var ele_cancel_btn = document.createElement('button'); ele_cancel_btn.innerText="删除"; ele_cancel_btn.classList.add("btn1"); ele_cancel_btn.classList.add("btn"); ele_cancel_btn.onclick=cancel; var ele_edit_btn=document.createElement("button"); ele_edit_btn.innerText="编辑"; ele_edit_btn.onclick=compile; ele_edit_btn.classList.add("btn4"); ele_edit_btn.classList.add("btn"); ele_td2.appendChild(ele_edit_btn); ele_td2.appendChild(ele_cancel_btn); //隐藏对话框 var ele_model=this.parentElement; var ele_shade=ele_model.previousElementSibling; ele_shade.classList.add("hide"); ele_model.classList.add("hide"); } else if(this.innerText=="取消"){ //隐藏对话框 var ele_model=this.parentElement; var ele_shade=ele_model.previousElementSibling; ele_shade.classList.add("hide"); ele_model.classList.add("hide"); } else if(this.innerText=="删除"){ var ele_grand=this.parentElement.parentElement.parentElement; var ele_father=this.parentElement.parentElement; ele_grand.removeChild(ele_father); } else if(this.innerText=="编辑"){ //把表格中的数据显示到对话框中 var eles_info=this.parentElement.parentElement.children; var eles_value=document.getElementsByClassName("input_field2"); var ele_table=this.parentElement.parentElement.parentElement.parentElement; edit_obj=this.parentElement.parentElement; for (var i=0;i<eles_info.length-1;i++){ eles_value[i].value=eles_info[i].innerText; } //显示对话框 var ele_shade=ele_table.parentElement.nextElementSibling; var ele_model2=ele_shade.nextElementSibling.nextElementSibling; ele_shade.classList.remove("hide"); ele_model2.classList.remove("hide"); } else if(this.innerText=="更新"){ // 1.拿到用户输入的值, // 2.循环创建td标签,并赋值 // 3.创建tr标签,添加td标签, // 4.找到目标标签替换 // 5.隐藏对话框 var eles_value=document.getElementsByClassName("input_field2"); var new_tr=document.createElement("tr"); for (var i=0;i<eles_value.length;i++){ var new_td=document.createElement("td"); new_td.innerText=eles_value[i].value; new_tr.appendChild(new_td); } //拿到新tr标签中的每一个td标签 //然后用新td的值替换旧td的值 var new_tr_child=new_tr.children; var old_tr_child=edit_obj.children; for (var i=0;i<new_tr_child.length;i++){ old_tr_child[i].innerText=new_tr_child[i].innerText; } //隐藏对话框 var ele_model2=this.parentElement; var ele_shade=ele_model2.previousElementSibling.previousElementSibling; ele_shade.classList.add("hide"); ele_model2.classList.add("hide"); } else if(this.innerText=="退出"){ //隐藏对话框 var ele_model2=this.parentElement; var ele_shade=ele_model2.previousElementSibling.previousElementSibling; ele_shade.classList.add("hide"); ele_model2.classList.add("hide"); } }; } </script> </body> </html>
七、JS扩展
1.JS的作用域
作用域是JavaScript最重要的概念之一,在JavaScript中,变量的作用域有全局作用域和局部作用域两种。
1.1:全局作用域(global scope)
在代码中任何地方都能访问到的对象拥有全局作用域,一般来说以下几种情况拥有全局作用域:
(1)最外层函数和在最外层函数外面定义的变量拥有全局作用域
var name="amos"; function foo(){ var age=23; function inner(){ console.log(age); } inner(); } console.log(name); // amos //console.log(age); // Uncaught ReferenceError: age is not defined foo(); // 23 inner(); // Uncaught ReferenceError: inner is not defined
(2)所有未定义直接复制的变量自动声明为拥有全局作用域,例如:
var name="amos"; function foo(){ age=23; var sex="male" } foo(); console.log(age); // 23 console.log(sex); // sex is not defined
变量age拥有全局作用域,而sex在函数外部无法访问到。
(3)所有window对象的属性拥有全局作用域
一般情况下,window对象的内置属性都拥有全局作用域,例如window.alert()、window.location、window.top等等。
1.2:局部作用域(Local Scope)
和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部,所有在一些地方也会看到有人把这种作用域称为函数作用域。
js中if/for没有自己的作用域。
2.作用域链(Scope chain)
在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。
2.1:示例演示
//-----**********************例1********************************* var s=12; function f(){ console.log(s); var s=12; // if s=12 console.log(s) } f(); //-----**********************例2********************************* var s=10; function foo(){ console.log(s); var s=5; console.log(s); function s(){console.log("ok")}// 函数的定于或声明是在词法分析时完成的,执行时已不再有任何操作 console.log(s); } foo(); //-----***********************例3******************************** function bar(age) { console.log(age); var age = 99; var sex= 'male'; console.log(age); function age() { alert(123) }; console.log(age); return 100; } result=bar(5); //-----********************************************************
2.2:结果分析
我相信大家一定会有想不到的结果,接下来我们就以最复杂的例3来分析整个过程。
当一个函数创建后,它的作用域链会被创建此函数的作用域中可访问的数据对象填充。在函数bar创建时,它的作用域链中会填入一个全局对象,该全局对象包含了所有全局变量,如下图所示:
解析到函数调用时,即bar(5),会生成一个active object的对象,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。新的作用域链如下图所示:
过程解析:
function bar(age) { console.log(age); var age = 99; var sex="male"; console.log(age); function age(){ alert(123); } ; console.log(age); return 100; } result=bar(5); 一 词法分析过程(涉及参数,局部变量声明,函数声明表达式): 1-1 、分析参数,有一个参数,形成一个 AO.age=undefine; 1-2 、接收参数 AO.age=5; 1-3 、分析变量声明,有一个 var age, 发现 AO 上面有一个 AO.age ,则不做任何处理 1-4 、分析变量声明,有一个 var sex,形成一个 AO.sex=undefine; 1-5 、分析函数声明,有一个 function age(){} 声明, 则把原有的 age 覆盖成 AO.age=function(){}; 二 执行过程: 2-1 、执行第一个 console.log(age) 时,当前的 AO.age 是一个函数,所以输出的一个函数 2-2 、这句 var age=99; 是对不 AO.age 的属性赋值, AO.age=99 ,所以在第二个输出的age是 99; 2-3 、同理第三个输出的是 99, 因为中间没有改变 age 值的语句了。 注意:执行阶段: function age(){ alert(123) } ; 不进行任何操作,将执行语句复制给age这部操作是在词法分析时,即运行前完成的。