本文共 5576 字,大约阅读时间需要 18 分钟。
经常使用 Javascript 的人会琢磨其垃圾收集机制,Javascript 并不像 C,C++ 那样需要开发者手动去清除垃圾,在编写 Javascript 程序是,开发者无需关心内存使用问题,所需内存分配以及无用内存(垃圾)的回收完全实现了自动管理。究其根源,主要是程序收集那些不再使用的变量,并且释放其占用的内存。因此,垃圾收集机制会按照固定时间间隔,周期性反复的执行这一操作。
Javascript 中的原型函数(prototype)的工作原理,在 javascript 中每次声明新函数的过程中,就会为其创建一个 prototype 的属性。在未加其他附带条件情况下,所有的 prototype 属性都会自动获取 constractor 属性,constructor 内包含一个指向 prototype 属性所属函数的指针(就是说 constructor 回指构造函数本身)。
举个例子来说,Fruit.prototype.constructor 指向 Fruit。并且可以通过这个构造函数,为其添加更多的属性和方法。 当调用构造函数创建一个新实例后,该实例内部包含一个指针指向构造函数的原型函数。此时我们不用去关心内部的这个指针到底是什么(这个指针还的确有个名字:__proto__ 估计是为了对应 prototype 而起的名字吧 ~\(≧▽≦)/~ ),只需记住它的指向即可(指向构造函数的原型函数)。需要注意的是,这个 __proto__ 只存在于函数实例与构造函数的原型函数之间,而非实例与构造函数之间。 下面画个图,来精心诠释一下。如上图所示,Fruit_1, Fruit_2 与构造函数没有直接的联系,只是这两个实例的 __proto__ 属性指向了 Fruit.prototype。虽然这两个实例都不包含属性和方法,但却可以通过 fruit_1.showPrice() 来调用。其理论依据是通过查找对象属性的过程来实现的。
举个例子来说:function Fruit(){ } Fruit.prototype.category = "apple"; Fruit.prototype.price = 19.9; Fruit.prototype.showPrice = function(){ alert(this.price); } var fruit_1 = new Fruit(); var fruit_2 = new Fruit(); alert(fruit_1.constructor == fruit_2.constructor); // 输出 true fruit_1.showPrice(); // 19.9此时,Fruit()构造函数变成了一个空函数,但却可以通过调用 prototype 往构造函数内直接增加属性和方法。并且在此时,仍然可以调用构造函数来 new 新对象,并且新对象具有通过原型函数向构造函数直接增加的属性和方法(有点拗口啊,就是说,通过原型函数直接向构造函数增加属性和方法,增加的这些属性和方法,在通过构造函数 new 出来新实例中也具有)。 并且通过上面的例子可以看出,通过构造函数 new 出来的不同对象,具有与构造函数相同的属性和方法。并且这些都是共有的。 这一切的一切表明,在构造函数外部可以通过原型函数为其增加属性和方法,并且与在构造函数内部声明具有相同的效果。
在 Javascript 中,是没有重载的概念的。我们可以通过将函数名想像为指针的方法对其加以深入的理解(很好理解)。
下面的一个例子可以让大家很容易的明白 Javascript 中无重载的概念。
在大多数面向对象语言中,基本上的都支持继承,首先来宽泛的谈谈大多数 OO 语言的继承方式,之后具体到 javascript 来看看其继承有什么不同之处。 1. 实现继承:实现继承是指派生类(子类)继承了基类(父类)的所有属性和方法,并且有且只有一个基类。 优点是可以直接使用基类的所有属性和方法,缺点不言而喻,基类的一些不必要的方法也会被子类所继承。 比如:基类定义了果树类,里面有开花,结果等方法。派生类继承基类,但如果派生类的中的果树不会开花,只会结果(如:无花果),那么开花对子类就没用,但子类确实继承了基类开花的方法。 在设计模式中,我们更多强调的是面向接口的继承。上面的例子中,果树有两个接口,一个是开花,一个是结果。如果我的果树只能结果,不会开花的话,那么只要我的果树实现结果的接口就行了。与此同时不会把开花带入到我的派生类(子类)中。 2. 接口继承:派生类继承了接口的方法签名,它不同于实现继承的是,接口继承允许多继承,同时派生类只继承了方法签名而没有方法实现。具体的实现必须在派生类中完成。这种继承又称为“接口实现”。 谈完了 OO 语言继承的分类,下面对比上述两种方式来看看 javascript 是怎么来完成它独有的继承的。 先看第二点——接口继承,接口继承要求派生类继承基类的方法签名。 方法签名:返回值类型+方法名+参数列表 而在 javascript 中,任何的函数,方法,究其本质都会转变成变量来解析,如下:
如上所示,便完成了 javascript 通过原型对象的方式的继承。
原型链表明实例化的对象首先会在构造函数的实例中搜索该属性,如果没有找到,则会继续搜索实例的原型。通过原型链实现继承,搜索过程会沿着原型链向上搜索,拿上面的例子来说,调用 dog.isFruit() 会经历三个搜索步骤:1)搜索实例(未找到) --> 2)搜索 NotFruit.prototype (未找到) --> 3) 搜索 Fruit.prototype,上面这个例子在调用 dog.isFruit() 时,在第三步才找到其对应的方法。如果在搜索到原型末端还未找到属性或方法时,则会报错,如上 dog.notFoundFruit() 所示。 当然,在 javascript 中,还存在“对象冒充”的方式的继承,在这里就不详细论述了。
转载地址:http://zqtci.baihongyu.com/