一、理解变量的基本类型和引用类型
前者是按值访问的,可以操作到保存的实际的值,而后者的值是保存在内存中的对象,JavaScript中不允许直接访问内存中的位置,即不能直接操作对象的内存空间。在操作对象时,实际是在操作对象的引用。我们通过对这两种类型的复制操作来理解。
JavaScript中所有的函数传参都是按值传递的。如果传递的是数字字符串之类的应该很容易理解,但是当传递的值是对象时,就有点不一样了。为什么局部环境里面修改的能够影响外部环境的呢?
首先我们理解一下这几个短语:按值访问、按引用访问、按值传递、按指针传递、按引用传递。前两者和后三者完全不一样,一个是访问方式,一个是传递方式。我们谈谈后面三种:
1.相当于右图中的num1复制为num2
2.按指针传递:指针?就是存放某个变量地址的变量,在逻辑上是独立的,是可以改变的。按指针传递实质是按值传递,只不过传递的值是某个变量的地址而已。
3.按引用传递:引用?就是类似别名的东西,好比,我儿子叫我爸爸,我孙子叫我爷爷,而我就是那个人。它在逻辑上不是独立的它具有依附性,所以引用在一开始就要被初始化,被引用对象在它的整个生命周期中不可以改变。
引用传递和指针传递是不同的,虽然它们都是在被调用函数栈空间中的一个局部变量,但是对于任何引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而指针传递的参数,如果它的值被修改了,就影响不到主调函数的相关变量。
下面的例子,我们用反证法:假设它就是引用传递,那么当我在函数中改变了对它的引用之后,为什么输出的还是Jhon?这也恰恰证明了这是按值传递中的按指针传递。
function setName(obj){
obj.name = "Jhon";
obj = new Object();
obj.name = "Greg"
}
var person = new Object();
setName(person);
alert(person.name);
二、块级作用域?
块级作用域:在类C语言中 用花括号括起来的区域。不同块级作用域中就算变量具有相同的标识符,它们也是不一样的。但是在JavaScript中并没有块级作用域,所以下面的color还是blue
if(true){
var color = blue;
}
alert(color); //blue
for(var i=0; i<10; i++){
alert(i)
}
alert(i); //i=10
对于for循环就更烦了,如果我们想要实现一些效果,类似banner这种,那该怎么办呢?我们要么用闭包,要么用自定义属性。
(1) 使用自定义属性
for(var i=0; i<10; i++){
a[i].index = i;
a[i].onclick = function(){
//这里如果要引用i的话i=10,不理解可以学习一下作用域的相关内容哦
a[this.index].....
}
}
(2) 使用闭包
<ul id="list">
<li>haha</li>
<li>haha</li>
<li>haha</li>
<li>haha</li>
<li>haha</li>
</ul>
<script>
window.onload = function() {
getIndex();
}
function getIndex() {
var aLi = document.getElementById('list').getElementsByTagName('li');
for(var i = 0; i < aLi.length; i++){
(function (i) {
// body...
aLi[i].onclick = function () {
console.log(i);
}
})(i);
}
}
</script>
闭包是什么?
从语法的角度讲,闭包是一个能够读取其他函数内部变量的函数;
从JS作用域链的角度来讲,它是一个定义在函数内的函数。
闭包,包括它本身的的函数解构和他所处的环境。这个环境决定了它能够引用的变量。当然,函数所引用的变量的值是这个函数在运行时而不是定义时的值。所以才有了上面的在for循环里定义并立即运行的用法,因为click句柄所引用的i就是当时的i了。这是一种体现引用函数内部变量的方法。但这并不能说明所有的闭包都是这个形式。
而从用户的角度来讲,闭包可以将一些复杂的技术细节放在它的上下文中,而自己实现对外交互的友好的接口。可以将它当成一块语法糖,一种设计原则。
三、垃圾收集和内存管理
JavaScript中具有自动垃圾收集机制,原来就是找出那些不再需要使用的变量加以区别,然后释放其内存。有两种找出不需要变量的方式:
1.标记清除(mark-and-sweep)
通过对标记某个状态对“进入环境”(比如 声明一个变量)的和“离开环境”变量的不同状态加以区别,对“离开环境”的进行回收处理。
2.引用计数(reference counting)
记录对某个对象的引用次数,如果引用次数为0则回收。但是这个有可能引发循环引用,数量很多时要爆炸。
funtion(){
var oA = new Object();
var oB = new Object();
oA.b = oB;
oB.a = oA;
}
如此的引用次数为2,永远都不为0.
尽管IE中使用的是标记清除,但是当引用COM(组件对象模型)对象时也会引发这个问题。
如何进行内存管理?对不需要了的变量,为它赋值null。这样自动垃圾收集机制将会对它进行处理。其实因为安全原因,为了不让运行JavaScript的网页耗尽所以的内存导致崩溃,电脑分配了相对少于桌面应用内存的内存给web浏览器。及时清理有助于提高性能。
四、 Asynchronous JavaScript and XML
所谓的ajax其实是基于一个js原生对象XMLHttpRequest所实现的更新部分网页的实现动态网页的一种方法
如果单从前端这个方面去学习是很肤浅的,只能学习到一个对象以及它的属性方法,但这是基础。我们还需要了解后端的一些东东,比如XML、PHP或者JSP,通过这些,我们可以了解到我们所写的方法,是怎样触发一些条件进而使得后端返回我们所需要的东西的。后端中可以做的可以是简单的返回文本、xml数据,也可以封装一些方法实现一些功能(很重要一部分是它可以和数据库对接,可以执行很多操作),返回一些服务。就像《神奇宝贝xy》中所说的“心合为一,而景色有两种”一样,我们才能理解得更加透彻。
1.简单的流程,当然你可以进行更多的封装,将操作callback、路径url等作为参数进行封装也是很实用的。
2.XMLHttpRequest的属性方法
http://www.w3school.com.cn/xmldom/dom_http.asp
五、对象创建
1.工厂模式
最大的缺点就是无法实现对象识别
2.构造函数模式
注意跟上面的差别
使用new时,实际上经过了这些步骤:1.创建一个对象,2.将构造函数的作用域赋给新对象,
3.执行函数中的代码,4.返回新对象
缺点就是,每个方法都要在每个实例上重新创建一遍,方法的创建其实相当于new Function(),也即是说,这种方法创建的对象上的同名方法是不等价的,尽管它们事项相同的功能
3.原型模式
缺点就是如果在原型中定义了像数组这类通过引用共享的东东,就很容易破坏原有的模型
所以我们经常使用的是构造函数和原型模式混合的方式创建对象,实例属性在构造函数中定义,共享属性constructor等和方法在原型中定义
4动态原型
经常使用的模式
六、继承
未完待续......