JavaScript成长记(1)
对javascript的一些了解。下面都是读书笔记。
1.先说下function
function square(x){return x*x;}
这个定义将会创建一个新的function对象并且把它分配到一个square变量中去。square不是function的实质。它只是一个引用function的变量的名称.而这个function还可以分配给其它变量。
var a=square(4);
var b=square;
var c=b(5);
每一个Function都有一个length属性,它表示的是function本身申明的参数个数。与function隐含的arguments.length不同的是,argument.length是被调用时实际传递过来的参数个数。
每一个function都有一个prototype属性,它引用的是预先定义个prototype对象。当function作为构造器被new操作符使用时。prototype指向的是构造器。
当一个function被定义时,当前的作用域链(scope chain)就被保存为function的内部状态了。
当脚本解释器调用一个function时,首先会在作用域链中设置function的作用域。接着,会把这个对象设置在作用域链的最前面。然后用arguments所引用的Argument对象来初始化这个对象。被命名的
参数会被添加到紧挨着这个对象的下面。任何在function中申明的变量都在这个对象内。既然局部变量、function参数、和Argument对象都在function中。那么就意味着会有相同名称的属性。
需要注意的是arguments,this不是对象的属性,所以你就不能在一对象中访问他们,我想这个是实现私有成员的前提。
//function mutil(w,h)
//{
// this.getWidth=function(){return w;};
// this.getHeight=function(){return h;};
//}
//var m=new mutil(2,3);
//alert(m.getWidth());
//m.getWidth=function(){return mutil.arguments[0]=1;}//如果能访问arguments属性,那就能改变参数的值。在javascript中实现私有也就是不可能了。
//alert(m.getWidth());
当程序需要导入许多不同的js代码时,Namespace事实上是非常有用的,当使用一个已定义的function创建一个对象时,所定义的变量和创建的属性是放在一个临时的Namespace中。它不会破坏全局的Namespace。
当一个function被调用时,一个调用对象(call object)也就被创建了,并且被放到作用域链中,当function执行完时,调用对象也会从作用域链上移除不在引用它了,调用对象也就被垃圾收集掉。
JavaScript中的function是被执行代码的组合和执行时的作用域。代码的组合和作用域通常被成为闭包。所有的functions都是闭包。
function的创建有两种,一是Function()构造器,另一种是function文本。
var f=new Function("x","y","return x*y");这种最后一个参数就是function body.
function f(x,y){return x*y;} 这种是通常的做法。
非常值得注意的是Function()构造器它创建使用的是全局作用域。
var y='global';
function ctor()
{
y='local';
return new Function("return y;");
}
alert(ctor()())://这里输出的是global;
2.说下prototype.
用new创建对象时,它会设置对象的prototype。对象的prototype是对象的构造器function的prototype属性的值。所有的function有有一个prototype属性,当定义function时它被自动创建并初始化。
prototype属性的初始值是一个拥有单个属性的对象,这个对象有一个名为constructor的属性并引用这function的构造器。可以添加任意的属性到prototype上,它将会被构造器初始化。
一个构造器提供了对象的"类"的一个名称并且负责初始化。继承是自动发生的当查找一个属性的值。属性并没有从prototype对象拷贝到新对象中;它仅仅看起来是这些对象的属性。
两点非常重要:一使用prototype可以减少每一个对象对内存的需求。二即使对象被创建后才属性被prototype中,对象仍然继承了这些属性。继承的属性和对象的普通属性很相似,它们是可枚举的。
每一个类(function)都有一个prototype对象,但是有许多隐含的类的实例,每一个都继承了类的prototype属性。因为一个prototype属性被许多对象共享,所以在javascript中读取属性值和写入属性值
存在着不对称。当要访问一个对象的一个属性比如obj.pp。javascript首先会在对象obj中查找是否有名称为pp的属性,如果没有就去查找对象ob中的prototype对象中是否有名称为pp的属性,这就是prototype
继承的基本工作原理。当你写入一个属性值时,javascript不会去使用prototype对象。因此属性的继承仅仅是发生在你读取属性值的时候。当你设置属性pp的值时,事实上是创建了一个新的属性pp
这时对象obj有了自己属性pp,它就不在从prototype中继承pp的值了。当再次访问obj.pp是,使用的是对象obj自己的属性pp。
扩展内置类型。任何通过prototype添加到内置类型中的属性和方法,都是可枚举的,而且对每一个该类型的单个对象都是可见的。一个空对象比如:{}.本来它是没有可枚举属性的。但是任何添加
到Object.prototype的属性方法,这个空对象也会有。这种扩展只能对javascript本身的内置对象,而不能对宿主对象进行扩展。因为这些宿主对象没有构造器和prototype对象。
3.JavaScript中的“类”。
尽管javascript支持被调用对象的数据类型。但是它是没有正真意义上类的概念的。面向对象的语言是强类型的并且支持类的继承。javascript中使用了大量的对象,它通过prototype继承使得它
有自己的类型。从这个方面来说javascript使用prototype继承替代了类的继承,javascript又是一种面向对象的语言。尽管它不是类继承的面向对象的语言,但是也能很好地模拟了类继承的特性。
一个对象是一种数据结构,它包含了许多不同名称的数据和操作这些数据的许多方法,javascript中有对象许多属性,它们可能是动态添加到对象上去的,这与强类型的语言不同,强类型的语言
每个对象的属性是被预先定义好的。而且属性的类型也被预先定义好。
function Circle(radius)
{
this.r=radius;//实例属性
}
Circle.prototype.area=function(){return Math.PI*this.r*this.r;}//实例方法
Circle.PI=Math.PI;//类属性
Circle.max=function(a,b){return Math.max(a,b);}//类方法
var c=new Circle(3);
alert(c.r);
alert(c.area());
//alert(Circle.area());//不能访问实例方法。此时会抛出异常。
alert(Circle.r);//不能访问实例属性,但是不会抛出异常,因为此时会在查找Circle类属性中是否有r属性,没有值为undefined.
4.valueOf方法。
valueOf()方法很像toString()方法,许多对象都不是一个简单的值。Number,Boolean很明显是一个简单的值所以它们重写了
toString()方法类返回一个简单的值。有一点要注意:在某些情况下,valueOf()方法比toString()方法有更高的优先权。所以有时就需要显示的调用toString()方法。
当使用比较操作符是比如:<,>=时,这个对象不是Number,Boolean类型的对象,会调用该对象的valueOf()方法的返回值来比较。
Object.toString=function(){return 6;};
Object.prototype.toString=function(){return 5;};
Number.prototype.valueOf=function(){return 2;};
Number.prototype.toString=function(){return 4;};
var a=new Number();
//a=3;//注意这里a=3被注释的话,a就是一个对象,它的类型是object的,但是它是Number类的实例。
alert(typeof a);//为object
alert(a instanceof Number);//为true;
alert(a.toString());//因为a是Number的实例,它调用的是Number的实例方法,所以它输出的是4;
alert(a==2);//这里调用的是valueOf()实例方法