title:关于JavaScript原型链的一些小结
文章的美感部分源于工整的排版,也就是结构。完整合理的结构保证了文章组织脉络的清晰和行文的流畅,而不合理的结构好似乱用goto和break的封装类,破坏整个系统的封装性和模块化。
原型链
在js没有类的情况下,可以采用下列三种模式创建对象。
1.工厂模式
通过新建一个对象,为其添加特定属性和方法并返回的模式来创建对象。它解决了一次创建多个对象的问题,但是无法解决对象类型匹配的问题。
2.构造器模式
没有显示的创建一个新对象。在new执行过程中,先自建一个新对象,将函数作用域传递给新对象,然后将属性方法添加到新对象中并返回。构造器模式相对工厂模式的优势在于:它可以通过实例检测到类型,它的不足在于(additional:每一个sayname函数式本质上就是创建了一个新的对象:this.sayName = new Function(“alert(this.name)”);
),所以不同实例上的同名函数是不相等的。
alert(person1.sayName == person2.sayName); //false
3.原型模式
所有的实例都会根据作用域链来查找匹配的属性和方法,查找的顺序为对象指向函数的属性和方法,然后再查找原型函数中的属性和方法。所有的对象的构造器都有一个指向函数原型的指针,也就说每一个对象都有一个对象原型,如果实例指向同一个对象原型,然后统一的操作对象原型中的代码,就可以为所有的对象赋值统一的属性和方法。
但是往往我们在构造函数时,都希望一个对象拥有相同的方法和独立的属性,所以一般使用构造函数与原型模式相结合,构造函数创建属性,原型模式创建方法的方式来创建对象。
js主要通过原型链来实现继承,原型链主要是解决多个对象复用同一个方法导致的复用困难和置方法于全局导致的封装性不足之间的矛盾。具体而言即:通过让超类的实例赋值给另一个构造函数的原型实现。但是这样的方式会带来一个问题,对象实例共享所有的继承和方法。解决这个衍生问题的技术是:借用构造器函数,在子类构造器内部调用超类构造器,这样就能保证在继承超类属性和方法的同时,保留自己的属性和方法。使用最多的继承模式是组合继承,此外还存在下列的继承模式
1.原型继承
本质:将超类型的实例赋值给子类型的原型(SubType.prototype = new SuperType();
)
additional:所有对象都拥有的诸如:toString(),equals(),toLocalString()等方法都是因为,所有的对象最终都是Object对象的子类实例,故而object对象包含的toString(),equals(),toLocalString()等方法也就是所有其他对象的原型所包含的方法。
原型继承的劣势也就是原型模式的劣势:它导致所有的对象都包含相同的属性值,然后这一点在实际使用时往往相反,没有特殊情况,我们希望不同对象的属性值尽量都不同。解决的办法也与原型模式类似,借用构造函数,使用构造函数来继承属性(同时还可以传递参数),使用原型模式继承方法。
2.寄生继承
与原型式继承非常相似,也是基于某个对象或某些信息创建一个对象,然后增强
对象,最后返回对象。为了解决组合继承模式由于多次调用超类型构造函数而导致的低效率问
题,可以将这个模式与组合继承一起使用
3.寄生组合继承·
集寄生式继承和组合继承的优点与一身,是实现基于类型继承的最有效方式。
闭包
函数表达式是js中一种强大的技术,不同于函数声明,它无须对函数命名的特性使他便于进行动态编程。匿名函数,也称拉姆达函数,是js函数中的一种强大技术
1.函数表达式不同于声明函数不需要命名,也称匿名函数
2.在递归函数中,使用声明函数容易导致引用错乱,故常用arguments.callee调用函数自身来实行递归
当函数内部定义了其他函数时,就创建了闭包。闭包有权访问创建函数的所有属性和对象。
1.闭包的作用链包括:它自己的作用域,包含函数的作用域和全局作用域
2.通常函数的作用域及所有变量会在函数执行结束返回时被销毁,但是如果函数包含闭包函数,则要等到闭包不存在时才会销毁作用域及变量。
函数表达式可以用于模仿块级作用域,方法是:创建并立即调用一个函数,这样当这个函数执行结束时,其变量就会被立即销毁
闭包还可以用于创建私有变量并为其增加访问方法
1.有权访问访问私有变量的方法叫特权方法
2.可以使用函数原型模式,构造器模式来实现自定义类型的特权方法;也可以使用模块模式和增强模块模式来实现单例的特权方法。
模块模式返回了一个访问私有变量的方法,增强模块模式返回了一个包含访问私有变量方法的对象。
闭包需要维护额外的作用域,会造成额外的开销,谨慎使用