一 javascript 数据类型
javascript属于弱类型语言 ,声明变量一概采用var关键字,变量的类型根据值类型自动匹配。 根据值类型可以javascript数据类型分为2类: 原始类型和引用类型。
原始类型指变量在栈上分配空间,可以自动释放,不需要进行垃圾回收.它有5种类型:
1. undefined 2. null 3. string 4. number 5. boolean
可以用typeof运算符来判断它们的基本类型如:
var a; alert(typeof a); //undefinded a = 1; alert(typeof a); //number a = '1'; alert(typeof a); //string a = true; alert(typeof a); //boolean a = null; alert(typeof a); //object
这里typeodf null 返回object, 可以把null理解成一个引用类型,只不过这个引用类型没有引用的对象而已,所以把它归为
原始类型。typeodf运算符对于引用类型都返回object. 当然typeof 还有一种类型就是function.
引用类型指这个类型的变量在栈上分配但是它的值是一个地址,这个地址指向堆上的一个对象实例。所以引用类型所指向的都是一个对象。在javascript有一个Object类,它是所有类的父类。同时,javascript为string,number,boolean都提供了相应的包装类。
可以用instanceof 判断变量的类类型如:
var a = new Object(); alert(a instanceof Object); //true a = new String("1"); alert(typeof a); //object alert(a instanceof Object); //true alert(a instanceof String); //true
二 函数
javascript中的函数灵活多变,但是它们终究都是一个对象。我们定义了一个函数,也就是生成了一个Function对象的实例。并把该对象.name设置为函数名,且把自己绑定倒当前环境下,在浏览器中为window对象,这也是为什么我们没有用引用变量指向它却可以调用它的原因。如:
function Car(){ } alert(typeof Car); //function alert(Car instanceof Object); //true alert(Car instanceof Function); //true alert(Car.name); //Car alert(window.Car === Car); //true
既然函数是一个对象,那么就可以将该对象赋值给一个变量。如果有一个变量指向了一个函数,我们就可以自己用该变量调用函数,而不需要函数名了,这样也就可以定义一个匿名函数了。如:
var Car = function(){alert("Car function...")}
alert(typeof Car); //function;
alert(Car instanceof Function); //true
alert(Car.name); //""
Car();
三 自执行函数
一般的函数总是先定义,后调用。但是自执行函数是那种在定义跟调用合并的一种方式。如:
(function Car(){alert("Car function...")})(); alert(typeof Car); //undefinded
注意的是这里一定要()把函数定义包括起来,否则将出现错误。可以看到函数执行后,该函数并没有绑定到window下,所以这里的函数名没有任何意义,所以下面这种写法会更直观一点:
(function(){ alert("Car function...") }());
那么这种写法有什么用呢:
1. 方便,定义完之后直接就用了,这个可能是其中一个原因把,不过可能性不太大。
2. 不影响全局对象如window,这里单指这个被()包括的函数,函数里面的代码实质上 仍然会影响window下的属性,因为内部 是可以访问全局变量的。
3. 提供一种命名空间的功能,使多库共存代码冲突降为最小。
四 作为对象方法的函数与this指针
在javascript中除了构造函数,所有的函数都是作为一个对象的方法。也就是说,要么用new调用一个函数,要么用obj.method()来调用函数。那么this指针指的就是调用该方法的对象。
那么alert方法为什么没有指明调用它的对象呢,因为alert属于window对象,window对象在浏览器中作为所有全局变量的绑定对象所以可以省略。
function funcA(){ alert(this.name_for_test); } funcA(); //undefined window.name_for_test = "window"; funcA(); //window var obj = {name_for_test : "obj"}; funcA.call(obj); //obj
五 构造函数与new
其实任何一个函数都可以作为一个构造函数,只要它前面跟了一个new操作符。而new的目的是创建一个对象实例。但是javascript中没有类的概念,除了原始类型,一切都是对象。所以new的过程像是在申请内存然后copy原始对象属性的过程。
通过一个实例来说明可能会更好点:
function ClassA(){
alert(this.type);
this.name = "ClassA";
var _name = "_ClassA";
this.exist = "ClassA_exist";
}
/* 输出 ClassA,undefinded
*
* 1. ClassA本身作为一个对象,已经在堆上分配到了内存。
* 2. 有了ClassA对象后,函数体里面的this就指ClassA对象,那么对this.xxx的赋值就像是对象属性的晚绑定。
* 3. var _name 作为一个局部变量在栈上分配,函数退出即释放空间,所以没有绑定到ClassA对象
*/
alert(ClassA.name); //ClassA
alert(ClassA._name); //undefinded
ClassA._type = "_base";
ClassA.prototype.type = "base";
ClassA.prototype.exist = "ClassA_prototype_exist";
/*
* new操作过程:
* 1. 生成空对象o
* 2. o.__proto__= ClassA.prototype,alert(this.type);用于测试2,3步哪步先执行
* 3. 执行构造函数,this指针指向生成的对象o
* 4. 如果构造函数没return 对象,则new运算的值为此生成对象o,否则为return的对象
*/
var objA = new ClassA();
alert(objA.name); //ClassA
alert(objA._name); //undefinded
alert(objA.type); //base
alert(objA._type); //undefinded, 因为属于构造函数之外的晚绑定,生成新对象时不执行此晚绑定
alert(objA.exist); //ClassA_exist 因为查this下面的属性,找到了则不查__proto__下面的属性
alert(objA.constructor.name); //ClassA
可以看到创建一个对象实例基本在执行Copy操作,在java中有深浅拷贝,这里也一样。所以对于引用类型作为属性时,是需要注意的。
六 原型与原型链
对于obj.name这么条语句,将会怎么查找这个name属性呢
1. 查找obj下面是否有name属性,有则返回,没有则tObj = obj.__proto__执行2
2. 如果tObj不为null,查找tObj下面是否有是否有name属性,有则返回,没有则tObj = tObj.__proto__执行2
可以看到没有找到name属性会一直遍历__proto__.__proto__.__proto__....的查下去,直倒查到或遇到一个__proto__=null
而Object.prototype.__proto__正好为null.这个查找链就是原型链。
这里要区分类的原型跟对象实例的 原型。
类的原型即prototype属性,只有类有这个属性,它是作为对象的模板,相当于与java中的静态属性。所有同类型对象共享此数据。对其修改将会影响到所有对象。
对象实例的 原型即__proto__,在new的第2步操作中看到它会被赋值为类的prototype.这个属性一般不公开,但firefox下可以访问。
例1:对prototype或__proto__操作影响到所有对象:
function ClassA(){}
ClassA.prototype._name = "_classA";
var objA = new ClassA();
var objB = new ClassA();
alert(objA._name); //_classA
alert(objB._name); //_classA
ClassA.prototype._name = "_classB";
alert(objA._name); //_classB
alert(objB._name); //_classB
objA.__proto__._name = "_classA";
alert(objA._name); //_classA
alert(ClassA.prototype._name); //_classA
alert(objB._name); //_classA
alert(objB.__proto__._name); //_classA
例2: 原型链
function ClassA(){}
var objA = new ClassA();
alert(Object.prototype.__proto__); //null
//all true
alert(objA.__proto__ === ClassA.prototype);
alert(objA.__proto__.__proto__ === Object.prototype);
alert(objA.__proto__.__proto__ .__proto__=== null);