JavaScript项目优化总结(1)(2)
实例类
JavaScript实现经典的类,总结有三种方法:
构造函数方式;
原型方式;
构造函数+原型的混合方式
构造函数方式
构造函数用来初始化实例对象的属性和值。任何JavaScript函数都可以用作构造函数,构造函数必须使用new运算符作为前缀来创建新的实例。
- var Person = function (name) {
- this.name = name;
- this.sayName = function(){
- alert(this.name);
- };
- }
- //实例化
- var tyler = new Person("tylerzhu");
- var saylor = new Person("saylorzhu");
- tyler.sayName();
- saylor.sayName();
- //检查实例
- alert(tyler instanceof Person);
构造函数方式跟传统的面向对象语言是不是很相识!只不过是class关键字用function替换了。
注意:不要省略new否则Person(“tylerzhu”) //==>undefined。当使用new关键字来调用构造函数时,执行上下文(context)从全局对象(window)变成一个空的上下文,这个上下文代表了新生成的实例。因此,this关键子指向当前创建的实例。所以省略new时,没有进行上下文切换会在全局对象中查找name,没有找到而创建一个全局变量name返回undefined。
原型方式
构造函数方式简单,但是存在一个浪费内存的问题。如上面的例子中实例化了两个对象tyler、saylor,表面上好像没什么问题,但是实际上对于每一个实例对象,sayName()方法都是一模一样的内容,每一次生成一个实例,都必须为重复的内容申请内容。
alert(tyler. sayName == saylor. sayName) 输出false!!!
Javascript中每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例共享。
- var Person = function (name) {
- Person.prototype = name;
- Person.prototype.sayName = function(){
- alert(this.name);
- }
- }
- //实例化
- var tyler = new Person("tylerzhu");
- var saylor = new Person("saylorzhu");
- tyler.sayName();
- saylor.sayName();
- //检查实例
- alert(tyler instanceof Person);
这时tyler、saylor实例的sayName方法,都是同一个内存地址(指向prototype对象),因此原型方法更节省内存。
但是看tyler.sayName();saylor.sayName();两者输出,会看出问题 —— 它们都输出“saylorzhu”。因为原型所有属性都共享,只要一个实例改变其他的都会跟着改变,所以实例化对象saylor覆盖了tyler。
构造函数+原型的混合方式
构造函数方式可以为同一个类的每一个对象分配不同的内存,这很适合写类的时候设置属性;但是设置方法的时候我们就需要让同一个类的不同对象共享同一个内存了,写方法用原型的方式最好。所以写类的时候需要把构造方法和原型两种方式混合着用(很多类库提供的创建类的方法或框架的写类方式本质上都是:构造函数+原型)。
- var Person = function (name) {
- Person.prototype = name;
- Person.prototype.sayName = function(){
- alert(this.name);
- }
- }
- //实例化
- var tyler = new Person("tylerzhu");
- var saylor = new Person("saylorzhu");
- tyler.sayName();
- saylor.sayName();
- //检查实例
- alert(tyler instanceof Person);
这样即可通过构造函数构造不同name的人,对象实例也都共享sayName方法,不会造成内存浪费。