1.JS控制HTML元素的显示和隐藏
利用JS来控制页面控件的显示和隐藏有两种方法,两种方法分别利用HTML的style中的两个属性,两种方法的不同之处在于控件隐藏后是否还在页面上占空位。
方法一:
document.getElementById("EleId").style.visibility="hidden";
document.getElementById("EleId").style.visibility="visible";
利用上述方法实现隐藏后,页面的位置还被控件占用,显示空白。
方法二:
document.getElementById("EleId").style.display="none";
document.getElementById("EleId").style.display="inline";
利用上述方法实现隐藏后,页面的位置不被占用。
2.document.documentElement是什么,和document.body的区别?
document是HTML DOM中的文档对象,指代载入浏览器的 HTML文档。document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问。
注意:Document 对象是 BOM中Window 对象的一部分,可通过 window.document 属性对其进行访问。
documentElement 属性可返回文档的根节点。body是DOM中document对象里的body子节点,即 <body>
标签;
documentElement 是整个节点树的根节点root,即<html>
标签;
DOM把层次中的每一个对象都称之为节点,就是一个层次结构,你可以理解为一个树形结构,就像我们的目录一样,一个根目录,根目录下有子目录,子目录下还有子目录。
以HTML超文本标记语言为例:整个文档的一个根就是,在DOM中可以使用document.documentElement来访问它,它就是整个节点树的根节点。而body是子节点,要访问到body标签,在脚本中应该写:document.body。
3.为什么浮动元素可以撑开父级容器?
为什么浮动元素可以撑开父级容器,浮动的元素不是已经脱离文档流,不占用父容器的空间了吗?
原来,如果对父容器同时进行浮动,那么浮动的元素就可以撑开浮动的父容器了。已经在IE9+(包含IE9)和Chrome中得到验证。
参考如下验证的代码:
<!doctype html>
<html>
<head></head>
<body>
<div id="box">
<div id="box1">
<p>jsadfasdjfsjdflfakfaslfasjflkajdsklajfhkda;lklj;s</p>
</div>
</div>
</body>
<style type="text/css">
p{float:left;}
#box1{float:left;}
</style>
</html>
上面的#box1高度是由子元素<p>
的高度决定的,即浮动的<p>
撑开了浮动的父级元素#box1。
4.JS获取可视窗口、html文档、body的高度和宽度
高度的获取:
<!doctype html>
<html>
<head></head>
<body>
</body>
<style type="text/css">
*{margin:0;padding:0;}
html{border:1px solid red;height:1000px;}
body{border:1px solid red;height:500px;}
</style>
<script>
alert("window.innerHeight:"+window.innerHeight);
alert("document.documentElement:"+document.documentElement.offsetHeight);
alert("document.body.offsetHeight:"+document.body.offsetHeight);
</script>
</html>
宽度的获取:
window.innerWidth;//可视窗口宽度
document.documentElement.offsetWidth;//html文档宽度
document.body.offsetWidth;//body元素宽度
下面附上网友的总结,可以放到浏览器中试一下,加深理解。
jquery高度:
alert($(window).height()); //浏览器当前窗口可视区域高度
alert($(document).height()); //浏览器当前窗口文档的高度
alert($(document.body).height()); //浏览器当前窗口文档body的高度
alert($(document.body).outerHeight(true)); //浏览器当前窗口文档body的总高度 包括border padding margin
alert($(window).width()); //浏览器当前窗口可视区域宽度
alert($(document).width()); //浏览器当前窗口文档对象宽度
alert($(document.body).width()); //浏览器当前窗口文档body的宽度
alert($(document.body).outerWidth(true)); //浏览器当前窗口文档body的总宽度 包括border padding margin
javascript的各种高度:
网页可见区域宽[仅针对body]: document.body.clientWidth
网页可见区域高[仅针对body]: document.body.clientHeight
网页可见区域宽[仅针对body]: document.body.offsetWidth (包括滚动条和边框,若滚动条和边框为0,则和clientWidth相等)
网页可见区域高[仅针对body]: document.body.offsetHeight (包括滚动条和边框,若滚动条和边框为0,则和clientHeight相等)
可视窗口宽度(包括滚动轴宽度):window.innerWidth; //IE9+、Chrome、Firefox、Opera 以及 Safari
可视窗口高度,不包括浏览器顶部工具栏: window.innerHeight;//IE9+、Chrome、Firefox、Opera 以及 Safari
网页正文全文宽(不包括滚动轴的宽度): document.body.scrollWidth
网页正文全文高:document.body.scrollHeight
//假如网页中没有滚动轴,document.body.scrollWidth和window.innerWidth相等,document.body.scrollHeight和window.innerHeight相等。
网页被卷去的高: document.body.scrollTop
网页被卷去的左: document.body.scrollLeft
网页正文部分上: window.screenTop
网页正文部分左: window.screenLeft
屏幕分辨率的高(整个屏幕的高度): window.screen.height
屏幕分辨率的宽(整个屏幕的宽度): window.screen.width
屏幕可用工作区高度: window.screen.availHeight
屏幕可用工作区宽度: window.screen.availWidth
整个浏览器可用工作区高度: window.outerHeight
整个浏览器可用工作区宽度: window.outerWidth
5.如何使固定定位的元素(position:fixed)的元素垂直水平居中在浏览器可视窗口*?
使用固定定位时,元素的定位的参考对象是浏览器可视窗口,不是body,请切记。此时,使用margin:0 auto;已经没有效果。
此时,只能使用CSS的top和left属性进行定位。这里需要一点计算。计算公式如下:
top=n%;
n=(窗口高度-元素高度)/2);
left=n%;
n=(窗口宽度-元素宽度)/2);
6.html中如何键入两个汉字空格?
空格的替代符号有以下几种:
名称 编号 描述
  半角空格(1个ASCII码字符宽度)
    半角空格(当前字体的大写字母“N”的宽度)
    全角空格(当前字体的大写字母“M”的宽,相当于一个汉字宽度)
    窄空白(小于1个ASCII码字符宽度)
所以,要想键入一个汉字宽的空格使用 
字符实体,段落开头的缩进也是采用em作为长度单位。缩进的方式是设置CSS属性”text-indent:2em;”。
关于长度单位em的描述见:CSS中常见的长度单位。
7.js在函数中申明变量可以不用var吗?
(1)在函数内部申明变量
是可以不用var来申明变量,但是有很大的区别。有var和没var声明的变量是不一样的。有var声明的是局部变量,没var的,声明的全局变量,所以可以借此向外暴露接口东东。 参考如下代码:
<script type="text/javascript">
//函数内部申明全局变量
function test(){
lvlv=1;
}
test(); //需要执行函数来申明全部变量lvlv
alert(lvlv); //输出1
//函数内部申明局部变量
function test1(){
var local=1;
}
test1();
alert(local); //报错,local is not defined
</script>
(2)在全局作用域内申明变量
有var和没var声明的变量看一起是一样,但是也是不一样的。我们知道,声明的全局变量,就是window的属性,究竟是否一样,我们通过ECMAScrpit5提供的属性的特性查询方法,来发现之间的区别。
var fff = 2;
window.ffa = 3;
ffb = 4;
this.ffc = 4;
var ffftx = Object.getOwnPropertyDescriptor(window, 'fff'); //configurable:false,enumerable:true,value:2,writable:true
var ffatx = Object.getOwnPropertyDescriptor(window, 'ffa'); //configurable:true,enumerable:true,value:2,writable:true
var ffbtx = Object.getOwnPropertyDescriptor(window, 'ffb'); //configurable:true,enumerable:true,value:2,writable:true
var ffctx = Object.getOwnPropertyDescriptor(window, 'ffc'); //configurable:true,enumerable:true,value:2,writable:true
我们可以分别通过alert(ffftx.configurable);等来查看上面的属性值。通过上面,我们发现原来还是有差别的,我们再用delete删除属性来验证下,配置性为false的属性无法删除。也就是通过变量var声明全局对象的属性无法删除,我们还会发现和函数声明创建的全局对象属性也无法删除。
delete fff; // 无法删除
delete ffa; // 可删除
delete ffb; // 可删除
delete ffc; // 可删除
(3)JS可以重复申明变量吗?JS申明和定义变量的区别?
使用var语句重复声明语句是合法且无害的。如果重复声明且带有赋值,那么就和一般的赋值语句没差别。如果尝试读取没有声明过的变量,JS会报错。参考如下代码:
function test(){
lvlv=1;
}
test(); //需要执行函数来申明全部变量lvlv
var lvlv; //再申明
alert(lvlv); //输出1
var lvlv=6; //再申明
了解到这些,我真的不得不感叹js这个脚本语言真的是太强大了!语法太灵活了,以至于让我感到有点松散。如果让学Web前端跨到CC++的话,我觉得会很痛苦。在CC++中,变量的申明和定义是有着本质的区别,而在JS中,申明并没有什么作用,如果使用变量时没有定义,那么依然会输出undefined。比如下面的代码:
var lvlv; //申明(申明在JS中是没有太大的作用,因为即使变量在使用的地方的后面定义了,也无法识别到变量的定义,输出undefined)
alert(lvlv); //输出undefined
var lvlv=6; //再申明(按我的理解是定义)
var lvlv=7; //再申明(按我的理解是定义,CC++中不能再次定义)
但是,出去最后一行,上面的代码结构在CC++中是完全合法的。变量可以在使用时先申明,后定义。之所以会有这样的差异,因为CC++是编译型语言,在编译时如果发现变量只申明,而没有定义在会编译时报错。因为JS是解释性脚本语言,不存在编译时报错,解释运行时就会输出undefined。
我在上面已经定义了变量lvlv,在下面还可以重复定义,JS强大吧,在CC++中绝对不会允许这么做的。这个JS的语法太松散,感觉JS又有点缺憾,竟然不去检查我在下面定义的变量,这是为什么呢?请看我第8小节——JS代码的执行流程是怎样的?
说了这么多,这里给JS中变量的申明和定义下一个定义,以免大家听的糊涂。JS中变量的申明和变量定义有什么区别呢?
JS变量的申明:使用var关键字只申明,不初始化;
JS变量的定义:使用var关键字或不使用var申明时并初始化。
JS中变量的使用规范:使用时先定义。
在学习CC++的时候,我比较讨厌将申明和定义弄混淆,在学习JS时也是。所以,严格的来说JS变量的申明必须用var,不然的话,那叫做变量的定义。因为我们不能按照如下方式申明变量:
lvlv; //浏览器解析时报错
定义时却可以:
lvlv =4;
lvlv="lvlv";
alert(lvlv); //输出lvlv
JS真是各种随意啊。
8.JS代码的执行流程是怎样的?
这里要说明一个概念——JS的代码块。JS的代码块是由<script>
标签包围的JS代码,即标记对<script>
和</script>
之间的代码。下面就是两个JS代码块。
//代码块1
<script type="text/javascript">
var lvlv=666;
alert(lvlv);
</script>
//代码块2
<script type="text/javascript">
var dable=666;
alert(dable);
</script>
JS的加载顺序:页面上的JavaScript代码是HTML文档的一部分,所以JavaScript在页面装载的顺序就是其引入标记<script/>
标签的出现顺序。
JS的执行流程: JS在加载之后,解析时分为两个阶段,一个是预处理阶段,一个是执行阶段。一个HTML页面中的JS总的执行顺序是和JS的加载顺序一致。只不过JS执行的基本单元是JS代码块。当JS的一个代码块加载完之后,便对它进行预处理,预处理的内容有:语法分析等。当预处理结束之后就开始执行该代码块。
解析完当前的代码块,就是下一个JS代码块的解析了。当然,HTML文档内容的加载(包括JS的加载)和JS解析是同时进行且同步的。即JS一边解析的时候,其他的JS代码可以同时加载,但JS解析时,要保证一个完整的JS代码块已经加载完成。
考察下面的代码,来加深对JS代码的边加载边解析的过程理解。
<script type="text/javascript">
Fn(); //浏览器报错:"undefined"
</script>
<script type="text/javascript">
function Fn(){ //函数1
alert("执行了函数1");
}
</script>
为什么运行上面的代码浏览器会报错呢?声明函数不是会在预处理期就会被处理了吗,怎么还会找不到Fn()函数呢?其实这是一个理解误点,我们上面说了JS引擎是按照代码块来顺序解析的,其实完整的说应该是按照代码块来进行预处理和执行的,也就是说预处理的只是执行到的代码块的声明函数和变量,而对于还未加载的代码块,是没法进行预处理的,这也是边加载边解析的核心所在。
小结: JS并不是等待所有的JS代码加载完成之后才开始解析的,而是加载完一个JS代码块之后便对该代码块进行解析。
根据HTML文档流的执行顺序,需要在页面元素渲染前执行的js代码应该放在前面的<script>
代码块中,比如放在<head>
标签内。而需要在页面元素加载完后的js放在后面,比如放在<body>
标签后面。此外,body标签的onload事件是在最后执行的。
这里还是有个疑问,为什么在同一个JS代码块中在后面定义的函数可以调用,而在后面定义的变量却报not undefined的错误呢?考察如下代码:
<script type="text/javascript">
test(); //在同一个JS代码块中,函数可以先调用,后定义
alert(lvlv); //解析错误:
var lvlv=1; //在后面定义,报Uncaught ReferenceError: lvlv is not defined
function test(){
alert("right");
}
</script>
有知道的网友请告知,谢谢。
注:上面对JS代码的执行流程的讲解是参考这篇文章:javascript运行机制之执行顺序详解
。由于其没有权威的参考资料,所以我们要保持怀疑的态度接受它。
在理解JS代码的执行流程我们可能会想到以下几个问题:
(1)JS代码的加载顺序。
答:按照<script>
标签在HTML文件中的出现的顺序由上到下顺序加载。
(2)JS代码是等到HTML文档加载完之后,或者是等到所有的JS代码加载完之后才开始解析的吗?
答:不是,JS代码是等到一个JS代码块加载完成之后便开始预处理,预处理完之后开始解析。如果预处理出错,则该代码块不会被执行。出错的代码块不会影响其他JS代码块的解析。
(3)JS解析时,HTML文档或者说JS代码可以同时加载吗?
答:可以同时加载,一个是JS引擎在工作,一个是http超文本传输协议在工作,二者可以同时进行。但是JS引擎在解析JS代码时,需要等待一个完整的JS代码块加载完成。
(4)JS代码块加载完成之后JS引擎才开始预处理吗,可以加载完一句JS代码就预处理一句呢?
答:这个目前还没有查阅到可信的资料,在这里我们姑且简单的认为是JS代码块加载完成之后JS引擎才开始预处理与执行。我上面也是按照这个观点讲解的。如果有知道的网友请留言告知,万分感谢。
9.JS的作用域和作用域链
(1)原来JS只有两个作用域(scope),函数作用域和全局作用域。
JS中没有像C/C++中有块级作用域。在C/C++中,for、while、if语句块花括号内中的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的。而Javascript压根没有块级作用域,只有函数作用域和全局作用域。并且全局作用域中定义的所有 JavaScript 全局对象、函数以及变量均自动成为浏览器模型(BOM)中的window 对象的成员。
考察如下代码片段:
<script>
var scope="global";
function t(){
alert(scope);
var scope="local"
alert(scope);
}
t();
</script>
你觉得输出情况会是什么?是global和local吗?错了!输出的是undefined和local。为什么呢?因为我们在函数作用域中定义了与全局变量scope同名的局部变量,导致全局作用域中的变量被隐藏,在函数体内不可见,如果想使用全局作用域中的变量,使用window.var的形式来显示调用。但在函数体内使用局部变量scope时,又因为使用时没有先定义,所以输出undefined。
将代码改写成如下形式:
<script>
var scope="global";
function t(){
alert(scope);
scope="local" //未使用var定义变量scope
alert(scope);
}
t();
</script>
在函数体内定义变量时不适用var关键字,表明定义的是全局变量,如果与其它全局变量同名,那么就是重定义,JS中允许重定义,以最后定义的为准,CC++是绝对不允许重定义的。所以修改后的代码实际上是没有在函数作用域内定义新的变量,所以输出结果就是global local。
(2)JS中没有代码块作用域
为什么说Js没有块级作用域呢,有以下代码为证:
<script>
var name="global";
if(true){
var name="local";
console.log(name)
}
console.log(name);
</script>
都输出“local”。如果有块级作用域,明显if语句将创建局部变量name,并不会修改全局name,可是没有这样,所以Js没有块级作用域。
现在很好理解为什么会得出那样的结果了。
(3)JS的作用域链表与JS中函数竟然可以嵌套定义
CC++中是绝对不允许函数嵌套定义的,即在函数体内定义新的函数,但是强大的JS却是允许的。本来JS的作用域是很简单的,只用两个,即全局作用域和函数作用域,但是JS中如此做法,也就带来了一个问题,即作用域的嵌套,形象的说法就是JS的作用域链表。
函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。
参考如下代码:
<script type="text/javascript">
name="lvlv";
function t(){
var name="tlvlv";
function s(){
var name="slvlv";
console.log(name);
}
function ss(){
console.log(name);
}
s();
ss();
}
t();
</script>
当执行函数s时,将创建由函数s开始的作用域链,首先将函数s作用域置于链表头,然后函数s的执行环境(调用对象)形成的作用域置于链表的下一个位置,然后将函数t的调用对象链接在后面,也就是全局对象window。最后生成的作用域链表就是s()->t()->window。然后从链表开头寻找变量name,很明显函数s()作用域内有name,找到了,于是输出slvlv。
同样的道理,在执行ss()函数时,生成的作用域链表就是ss()->t()->window。还是从链表头ss()中开始寻找,发现没有变量name的定义,然后在t()中找到了name的定义,于是输出”tlvlv”。
(4)一个因作用域链表常犯的错误
下面看一个很容易犯错的例子:
<html>
<head>
<script type="text/javascript">
function buttonInit(){
for(var i=1;i<4;i++){
var b=document.getElementById("button"+i);
b.addEventListener("click",function(){ alert("Button"+i);},false);
}
}
window.onload=buttonInit;
</script>
</head>
<body>
<button id="button1">Button1</button>
<button id="button2">Button2</button>
<button id="button3">Button3</button>
</body>
</html>
当文档加载完毕,给几个按钮注册点击事件,当我们点击按钮时,会弹出什么提示框呢?
这个很容易犯错,真的,三个按钮都是弹出:”Button4”,你答对了吗?
当注册事件结束后,i的值为4,当点击按钮时,事件函数即function(){ alert(“Button”+i);}这个匿名函数中没有i,根据作用域链,所以到buttonInit函数中找,此时i的值为4,所以弹出”button4“。
这里也说明了一个问题,函数体内的局部变量var i; 在函数执行完毕后并没有被销毁,依然保持着上次离开函数体时的值。
(5)JS变量的销毁
为什么没有被销毁,那么JS中变量什么时候才会被销毁呢?js变量分为两种,一种是全局变量,一种是局部变量。
全局变量,在js文件的任意地方都可以使用,它的生命周期就是js文件使用的周期。
局部变量,它在所属的方法,或者说是它在自己属于的对象里面才存在,这个对象或者方法被使用过了,如果变量不再被引用,那么它离开作用域时会被JS引擎来销毁。
事实上,JavaScript 不需要程序员控制销毁变量,当一个变量脱离作用域并且不被引用的时候,JS引擎会去把它销毁掉的。
在JS中通过 var/function声明的对象因含有DontDelete属性,所以不可以使用delete来删除,即不可被删除。
var x = 1;
delete x; // false
typeof x; // 1
function x(){}
delete x; // false
typeof x; // "function"
但是对象的属性、数组成员却是可以删除的:
var o = { x: 1 };
delete o.x; // true
typeof o.x; // undefined
num = 123; //因为num前面没有var,所有等价于: this.num = 123, 即当前对象的一个属性。
delete num;
因此如果我们要回收某个对象可以使用Object来封装一下。
10.js 把一个函数赋给一个变量时带括号与不带括号的区别
首先看一段代码:
<script type="text/javascript">
function hi(){
var a = 1;
return function(){
console.log(a++);
};
};
var aaa = hi();
var bbb = hi;
aaa();
aaa();
bbb();
</script>
上面的代码中,将函数hi带上括号和不带括号赋给变量aaa和bbb的区别是什么呢?其实很简单,带上括号就是将hi函数执行的结果返回给变量aaa,不带括号,就是将函数hi赋给变量bbb,这个有点类似于CC++中的函数指针。
那为什么函数hi可以将匿名函数 function(){console.log(a++)}作为返回值呢?这种做法是函数式编程的一部分。
(1)函数式编程
函数式编程是种编程典范,它将电脑运算视为函数的计算。函数编程语言最重要的基础是 λ 演算(lambda calculus)。而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值)。和指令式编程相比,函数式编程强调函数的计算比指令的执行重要。和过程化编程相比,函数式编程里,函数可随时被调用。
因为JS支持函数式编程,所以函数的返回值可以是函数表达式。
(2)JS闭包
此外,aaa 的值是 function(){console.log(a++)},而aaa再次运行的话就会打印出来a的值,这个地方可以看下上面那个hi函数,其中包含一个闭包,也就是说hi函数返回的function(){console.log(a++)}这个函数会一直保持着对局部变量a的引用,也就是说每调用一次 aaa ,那么打印的值都会加上1。
那么,什么是JS的闭包呢?
一些关于闭包的定义:
a.闭包是指有权访问另一个函数作用域中变量的函数 –《JS高级程序设计第三版》 p178;
b.函数对象可以通过作用域链相关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性称为 ‘闭包’ 。 –《JS权威指南》 p183;
c.内部函数可以访问定义它们的外部函数的参数和变量(除了this和arguments)。 –《JS语言精粹》 p36。
来个定义总结:
a.可以访问外部函数作用域中变量的函数;
b.被内部函数访问的外部函数的变量可以保存在外部函数作用域内而不被回收—这是核心,后面我们遇到闭包都要想到,我们要重点关注被闭包引用的这个变量。
参考文献
[1]http://www.cnblogs.com/ckmouse/archive/2012/01/30/2332070.html
[2]HTML DOM Document 对象
[3]jquery和JavaScript获取网页相关元素的高度和宽度
[4]如何在HTML文档中显示空格
[5]JavaScript中变量声明有var和没var的区别示例介绍:http://www.jb51.net/article/55200.htm
[6]window对象.W3CSchool
[7]在JavaScript中释放变量
[8]Js作用域与作用域链详解
[9]js 把一个函数赋给一个变量时带括号与不带括号的区别
[10][ JS 进阶 ] 闭包,作用域链,垃圾回收,内存泄露
[11]Javascript 进阶 作用域 作用域链