js高级程序设计第三版---1~3章
DOM并不只是会对js的,很多其它语言也实现了DOM,但DOM已经是js的一个重要组成部分。
BOM是js实现的一部分,但是没有相关的标准,所以每个浏览器都有自己的实现,这个问题在HTML5中得到了解决。
1、<script>的属性:
async(异步加载):表示立即下载脚本,不会影响页面中的其它操作,只对外部脚本有效。<script async="async" type="text/javascript"</script>
charset:通过src属性指定代码的字符集,大部分浏览器会忽视这个值。
defer:脚本可以延迟到完全被解析和显示之后再执行,只对外部脚本有效。<script defer="defer" type="text/javascript"</script>
type:language的替代属性,表示编写代码使用的脚本语言的内容类型(通常称为MIME类型。)服务器上传送的MIME类型通常是application/x-javascript,但在type中设置这个值却可能导致脚本被忽略,在非IE浏览器下可以使用这个值application/javascript和application/ecmascript,这个属性不是必须的。
defer和async的区别:async一旦下载就开始执行,是在window.onload之前,这就是说带async的<script>不会按在页面中出现的先后顺序来执行,如果脚本互相依赖且和执行顺序有关(解决方法:AMD),则会出现问题,而带有defer的是按页面中出现的先后顺序来执行的在DOMContentLoaded事件之前)。
建议:异步脚本不要在加载期间修改DOM,异步脚本会在load事件之前执行,但可能会在DOMContentLoaded事件触发之前或触发之后执行。
注意:如果在页面中嵌套<script>标签,那么在代码中就不能出现<script>,如果要用的话用"\"来转义,否则浏览器中的js解释器会把代码中出现的</script>当作结束标记来处理。
function a(){console.log("<\/script>");}
a();
如果代码中不包含defer 和async两个属性,这浏览器都会按照<script>出现的先后顺序进行解析的,如果把<script>标签放在<head>中就意味着所有的js代码都被下载、解析和执行完才能呈现页面的内容,则浏览器会出现延迟,那么浏览器窗口就是空白,为了解决这个问题,一般都放在<body>标签页面内容的后面,如:
<body>
<p>十年树木,百年树人</p>
<img src="1.jpg"/>
<script type="text/javascript" src="1.js"></script>
<script type="text/javascript" src="2.js"></script>
</body>
2、延迟:
<head>
<title>无标题文档</title>
<script type="text/javascript" defer="defer" src="1.js"></script>
<script type="text/javascript" defer="defer" src="2.js"></script>
</head>
添加defer是告诉浏览器,立即下载,延迟执行。延迟到</html>标签后再执行,一个页面中最好只包含一个延迟脚本,而且把延迟脚本放在页面底部是一个最佳选择。
保证相同代码在XHTML中也能执行的方法:在代码中加入CDATA片段,大部分浏览器不支持CDATA片段,可以使用注释来解决,如下代码
在将页面的MIME类型指定为"application/xhtml+xml"的情况下会触发XHTML模式,并不是所有浏览器都支持这种方式提供XHTML文档。
<script type="text/javascript">
//<![CDATA[
function compare(a,b)
{
if(a<b)
{
document.write("a小于b");
}
else if(a>b)
{document.write("a大于b");}
else
{
document.write("a等于b");
}
}
//]]>
compare(4,2);
</script>
使用外部js文件的好处:
1)可维护
2)可缓存:浏览器能根据具体的设置缓存链接的所有外部js文件。
3)适应XHTML:XHTML和HTML包含外部文件的方式是相同的。
<noscript>--------------------------------当浏览器不支持js脚本或者支持js脚本但没有被启用时出现,脚本无效的情况下用。
<p>浏览器不支持或者没有启用JAVASCRIPT</p>
</noscript>
3、js严格区分大小写:如typeof是关键字,而typeOf就可以是变量。
ECMAScript切换到严格模式:
在代码的顶部添加use strict
function a(){
"use strict";//这段代码是一个编译指示,告诉js引擎切换到严格模式下执行。
}
保留字:
4、变量:
function test(){
message="hi"; //全局变量,message有值,只要test()被调用过一次,变量message就有了意义,但是不易维护
}
test();
console.log(message);
下面这个是局部变量
function test(){
var message="hi"; //局部变量,message是未定义
}-------局部变量已经被销毁了
test();
console.log(message);
typeof:是一个操作符而不是函数,检测变量的数据类型
函数是一种对象,并不是一种数据类型。
对于没有声明过的变量只能进行typeof操作,如果再做其它操作是会报错的。
对未初始化和未声明的变量使用typeof操作都是返回undefined。
null值是一个空对象指针,如果定义一个变量要保存对象,那就要将变量初始化为null。
Number类型:八进制字面量值的第一位必须是0,如果字面量值的数值超过了范围,这前导0就被忽略,十六位的字面量值必须是0x。
保存浮点数值所需要的内存空间是保存整数值的两倍。
isFinite()函数来测试是否在最大值和最小值之间。
isNaN():接受一个参数,来判断这个参数是否是“不是数值”,这个也适合对象。
有3个函数可以把非数值转换为数值,Number()--可以用于任何数据类型(包括对象),parseInt(),parseFloat(),后面两个专用于把字符串转换为数值。
console.log(Number("dfasfdsa"));---------------NaN,如果字符串中包含数字,浮点数,十六进制的转换为相应的数值
console.log(Number(false));----------------------0
console.log(Number(true));-----------------------1
console.log(Number(4545));----------------------4545
console.log(Number());----------------------------0
console.log(Number(undefined));-----------------NaN
var num1=parseInt("54dfdsa");console.log(num1);--------------------54
var num1=parseInt("");console.log(num1);------------------------------NaN
var num2=parseInt("0xaf",16);console.log(num2);----------------------175
parseInt()和ParseFloat()是从字符解析,字符中的第一个小数点是有效的,但是第二个小数点就无效了。
ecmascript中的字符串一旦被创建是不能被改变的,如果要改变就要将原来的字符串销毁,然后再用新值来填充变量。
在js的数据类型中只有null和undefined没有toString()方法,toString()可以传递一个基数,如:
var num=10;console.log(num.toString(16));------------------------------输出为a
String()遵循以下转换原则:
如果值有toString()方法,则调用该方法(没有参数),并返回相应的结果。
如果值是null,则返回*null*。
如果值是undefined,则返回*undefined*。
object:是一组数据加功能的集合。
object的每个实例都有下列属性和方法:
constructor:保存着用于创建当前对象的函数,对于var ob=new Objec()来构造函数constructor就是Object()。
hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而不是实例的原型中)是否存在。其中作为参数的属性名(propertyName)必须以字符串的形式指定。
propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用for-in语句来枚举。作为参数的属性名必须以字符串的形式指定。
toLocationString():返回对象的字符串表示,该字符串与执行环境的地区对应。
toString():返回对象的字符串表示。
valueOf():返回对象的字符串、数值或布尔值表示,通常与toString()方法的返回值相同。
所有对象都有这些基本的方法和属性。
前置操作符:先加减再赋值,++age等价于age=age+1
后置操作符:递增和递减操作是在包含它们的语句被求值之后才执行的。
例如:var num1=2;var num2=20;console.log(num1--+num2);console.log(num1+num2);输出结果为22和21,因为第一个num1是使用的原始值(2),而第二个num1是使用的递减后的值(1)
在应用于不同的值时,递增和递减操作符遵循以下规则:
1)包含一个有效数字字符串时,先转换为数字,再加减,字符串变量变成数字变量。
2)应用于一个不包含数字的字符串时,将变量的值设为NaN,字符串变量变成数值变量。
3)应用于布尔值(false)时先转换为0再进行加减操作。
4)应用于true时先转换为1再进行加减操作。
5)应用于浮点数时直接进行加减操作。
6)应用于对象时先调用对象的valueOf()方法以取得一个可操作的值,如果结果是NaN,在调用toString()方法之后再用前面的规则。
位操作:
1)按位非~(NOT):返回数值的反码,按位非的本质是操作数和负数减1,优点是速度快
2)按位与&(AND):只有两个操作数的对应位都是1时才返回1,任何一位是0的话结果都是0
3)按位或|(OR):有一个是1的情况下返回1,只有两个位都为0时才返回0
4)按位异或^(XOR):只有一个为1时才返回1,如果两位都是1或者0则返回0
5)左移<<:向左移动指定的位数,左移不会影响操作数的符号位。
6)有符号的右移>>:保留符号位,与左移操作刚好相反。
7)无符号的右移>>>:对于正数来说,无符号的右移与有符号的右移相同;无符号右移是以0位来填充空位,有符号的右移是以符号位来填充。无符号右移操作符会把负数的二进制当成正数的二进制码,由于负数以其绝对值的二进制补码形式表示,因此无符号右移的结果非常大。
8)布尔操作符:非、与、或
逻辑非操作符遵循以下规则:
如果操作数是一个对象,则返回false
如果操作数是一个空字符串,则返回true
如果操作数是一个非空字符串,则返回false
如果操作数是0,返回true
如果操作数非0,返回false
如果操作数是Null、NaN、undefined返回true
逻辑与操作属于短路操作,如果第一个操作数能够决定结果,那么就不会对第二个操作数求值。
逻辑与操作的操作规则:
如果第一个操作数是对象,则返回第二个操作数
如果第二个操作数是对象,则只有在第一个操作数的结果为true的情况下才会返回该对象。
如果两个操作数都是对象,则返回第二个操作数。
如果有一个操作数是Null、undefined、NaN其中的一个,则返回Null、undefined、NaN中的本身。
逻辑或也是短路操作
逻辑或的操作规则:
如果第一个操作数是对象,则返回第一个操作数
如果第一个操作数的求值结果为false,则返回第二个操作数。
如果有一个操作数是Null、undefined、NaN其中的一个,则返回Null、undefined、NaN中的本身。
如果两个操作数都是对象,则返回第一个操作数。
乘法操作符的规则:
除法操作符处理特殊值的情况下的规则:
如果有一个操作数不是数值,则在后台调用Number()将其转换为数值,然后再用上面的规则。
求模:
加法操作符:
减法操作符:
关系操作符(<,<=,>,>=):
相等操作符:
console.log(undefined==null);-----------------------------------------true
console.log(undefined===null);----------------------------------------false
推荐使用全等和不全等
条件操作符:var num=(8>0)?"8大于0":"8小于0";console.log(num);
语句:
1)if.......else if......else if......else
2)do-while:在表达式求值之前,循环体内的代码至少被执行一次。
3)while:在循环体内的代码执行之前就对出口条件求值。
4)for
5)for-in
for(var propName in window){console.log(propName);}
如果变量的值为Null或undefined时for-in语句会抛出错误。所以在循环前要先判断变量的值是否为null或undefined。
6)break和continue语句:立即退出循环,不同的是break执行循环体后面的,当前循环体内的就不执行了;而continue会从循环的顶部继续执行。
var num=0;
for(var i=1;i<10;i++)
{
if(i%5==0){
break;
}
num++;
}
console.log(num);-----------------------结果是4
如果把break换成continue结果就是8。
7)with语句:是将代码的作用域放到一个特定的对象中。严格模式下用with语句会报语法错误。
8)switch语句:
加个break可以避免同时执行多个case代码的情况
switch("hello world")----------------在此是使用的全等操作符,因此不会发生类型转换。
{
case "hello"+" world":
console.log("恭喜找到了");
break;
case "lili":
console.log("没找到");
break;
default:
console.log("继续努力哦");
}
7)函数:一个函数可以包含多个return语句,return语句也可以有不带返回值的。
function sum(a,b)
{
return a+b;
console.log("你好啊");
}
sum(52,34);----这个函数执行完return后就退出,后面的代码永远都不会执行。
有多个return语句的函数:
function sub(a,b)
{
if(a<b)
return -(b-a);
else
return a-b;
}
sub(2,8);
下列代码返回undefined值,这种情况用在需要提前终止函数又不需要返回值的情况。
function say(name,message){
return;
console.log(name+message);
}
say("marry","hello world");
函数的参数:ecmascript不在乎传递的是几个参数,即使定义的函数接收两个参数,调用时也未必要传递两个参数,因为ecmascript在内部是把参数作为一个数组来表示的。函数接收的始终是这个数组。可以使用arguments对象来访问参数数组,从而获取传递给函数的每一个参数。用arguments[0]、argument[1]来表示和访问参数。
例如:
function add()
{
return arguments[0]+arguments[1];
}
add(3,8);
arguments对象的长度是由传入的参数来决定的。不是由定义函数时命名参数的个数来决定的,没有传递值的命名参数将自动被赋予undefined值,这就和定义了没有初始化一样。ecmascript中所有参数传递的都是值,不是引用传递参数。
重载:由于不存在函数签名的特性,ecmascript中没有真正的重载,通过检查传入参数的类型和数量并作出不同的反应来模仿方法的重载。
不需要为函数来指定函数值,因为任何函数会在任何时候返回任何值。