讲解还是以示例代码搭配注释的形式,这里做个小目录:
JS代码预解析原理(包括三个段落);
函数相关(包括 函数传参,带参数函数的调用方式,闭包);
面向对象(包括 对象创建、原型链,数据类型的检测,继承)。
JS代码预解析原理
复制代码 代码如下:
/****************** JS代码预解析原理 ******************/
/*
JS代码预解析、变量作用域、作用域链等 应该能作为学习JS语言的入门必备知识。
下边给出些简要解释和一些典型的代码段,若要了解更多,能从网上搜索到更多相关示例。
引用网上的一段有关 “JS的执行顺序” 的解释:
如果一个文档流中包含多个script代码段(用script标签分隔的js代码或引入的js文件),它们的运行顺序是:
步骤1. 读入第一个代码段(js执行引擎并非一行一行地执行程序,而是一段一段地分析执行的)
步骤2. 做语法分析,有错则报语法错误(比如括号不匹配等),并跳转到步骤5
步骤3. 对var变量和function定义做“预解析”(永远不会报错的,因为只解析正确的声明)
步骤4. 执行代码段,有错则报错(比如变量未定义)
步骤5. 如果还有下一个代码段,则读入下一个代码段,重复步骤2
步骤6. 结束
*/
// 下边给出 三段觉得比较典型的代码示例:
/********** 一:基本的几条语句 **********/
alert(num); // undefined
var num = 0;
alert(str); // 错误:str未定义
str = "string";
alert(func); // undefined
var func = function (){ alert('exec func'); }
test(); // exec test
alert(test()); // 先exec test 后undefined
function test(){ alert('exec test'); }
/********** 二:函数名与变量名相同 **********/
//var mark = 1;
function mark(x) {
return x * 2;
}
var mark;
alert(mark); // function mark(x) { return x * 2; }
// 去掉前边的var mark = 1;则会返回1
/********** 三:把第二段包括在语句块中 **********/
// 当有条件时候(代码包含在条件语句块里)
if (false) {
var mark1 = 1;
function mark1() {
alert("exec mark1");
}
//var mark1;
alert(mark1);
}
alert(mark1);
mark1();
// 由于解析浏览器解析不同,这段代码在不同浏览器里执行的结果不一致,具体原因可从网上查找答案
函数相关(包括 函数传参,带参数函数的调用方式,闭包)
复制代码 代码如下:
/****************** 函数相关 ******************/
/********** 一:函数传参 **********/
/*
编程语言大概都有 值类型与引用类型 的区别,JS也不例外。
原始类型:undefined null number boolean 均为值类型。
string比较特殊,因为它是不可改变的,String类定义的方法都不能改变字符串的内容。
function object array 这三种为引用类型。
*/
/* JavaScript 函数传递参数时,是值传递。
ECMAScript 中,所有函数的参数都是按值来传递的。
基本类型值的传递和基本类型变量复制一致(采用在栈内新建值),
引用类型值的传递和引用类型变量的复制一致(栈内存放的是指针,指向堆中同一对象)。
具体参考:
*/
function setName(obj){
//obj拷贝了person的值(person是一个对象的引用地址),所以obj也指向了person所指向的对象。
obj.name = "xiaoxiaozi";
obj = {}; // 让obj 指向了另一个对象
obj.name = "admin";
}
var person = {};
setName(person);
alert(person.name); // xiaoxiaozi
/********** 二:带参数函数的调用方式 **********/
/* 在DOM不同版本中,函数调用方式不太一样。标准推荐的是addEventListener和attachEvent
这两种方式有很多资料可查。但是有些已经不被推荐的函数调用仍旧有实际应用,相关资料发现的不多。
这里主要讨论这些函数调用方式
*/
var g = "全局变量";
function show(str) {
alert("my site: " + str);
}
setTimeout("show(g);",100); // g是全局变量,函数正确执行
function t() {
var url = "www.xujiwei.cn";
var num = 2;
//setTimeout("alert("+url+")", 3000); // 解析错误,www未定义
//setTimeout("alert("+num+")", 3000); // 解析正确,注意与上句对比
//setTimeout("show('url');", 2000); // url
//setTimeout("show("+ url +");", 2000); // 解析错误,www未定义
//setTimeout("show(url);", 2000); // 解析错误,url未定义
//setTimeout('"show("+ url +");"', 2000); // 解析错误,url未定义
//setTimeout("show('"+ url +"');", 2000); // 正确
//setTimeout(function(){show(url);},1000); // 正确
}
t();
/* 结论:
诸如onclick="xx();"等函数调用方式,在双引号内的内容直接解析为js语句执行。
若调用的函数带有参数,注意对比以上各种写法,保证传递进去的参数为正确的。
*/
/********** 三:闭包 **********/
/*
闭包,几乎是每个学习JS的朋友都要讨论的问题,因此各种相关资料应有尽有。
它的作用很大,但也有弊端,例如如果使用不当,容易引起内存泄漏等问题,因此有不少人
提倡少用闭包。
这里列出闭包的一种经典应用,一个有争议的应用。
*/
function test1() { //通过闭包,每次能传入不同的j值。
for (var j = 0; j < 3; j++) {
(function (j) {
setTimeout(function () { alert(j) }, 3000);
})(j);
}
}
test1();
/* 这个是闭包的典型应用 */
(function tt() {
for (var i = 1; i < 4; i++) {
document.getElementById("b" + i).attachEvent("onclick",
new Function('alert("This is button' + i + '");')); // 在IE中测试
}
})() // 立即执行函数,一个文件是否只能有一个?把上边函数写成立即执行出问题,怎么回事?
/* 这个问题出现在论坛里,有很多争议
有说是new Function动态生成个闭包结构的函数,所以能保存外部变量。
有说是跟闭包无关,new Function,就是新定义了一个function,
i的值也作为这个新的function的参数固化在其内部了。
*/
面向对象(包括 对象创建、原型链,数据类型的检测,继承)
复制代码 代码如下: