一时兴起,写一遍博客吧。
“函数是函数,函数也是对象” 相信学过js 的同学看到这句话很熟悉。我表示耳朵都听出茧子了。
我们都知道,在JavaScript中是没有类的概念的,那么怎么来new 一个对象呢?首先,来看一下我们写一个普通的 构造函数。
1 function Person(name, age, gender) { 2 this.user_name = name; 3 this.user_age = age; 4 this.user_gender = gender; 5 6 this.sayHi = function () { 7 alert("我叫"+this.user_name+",我年芳"+this.user_age+"我是一个分流倜傥的"+this.user_age+"生"); 8 } 9 } 10 11 //创建两个对象; 12 var p1 = new Person('李寻欢', 18, '男'); 13 p1.sayHi(); 14 15 var p2 = new Person('张无忌', 20, '男'); 16 p2.sayHi();
很好 代码像我们想象的原样输出了。谁打印谁的互不相干。
从上面的代码我们可以看出来, p1 跟p2 之间是没有任何联系的,这很像C#里面的对象,每个对象保存自己的属性。这是js的优点。
但是,其中有 一个匿名函数赋值给了 sayHi ,匿名函数也是对象,我们都知道 对象是占内存的然而 这就变成了一个缺点。 因为当我们new 500个对象的时候,在内存中就会有500个sayHi 这是没必要的,因为都是那个函数,而属性是必须每个对象都要有自己的一份的。
如果你们说,属性都是自己独一份,你怎么知道他们调用的不是一个方法呢? 你可以打开编辑器试着改改代码吗? 我很懒的。
1 p1.user_name = '花无缺'; 2 p1.user_age = '19'; 3 p1.user_gender = '男'; 4 5 p1.sayHi = null; // 把p1的函数赋值 为null; 6 7 p1.sayHi(); // F12 一下 报错了 8 p2.sayHi(); //原样输出、
这下你们信了吧
那么怎么解决这个问题呢? 就要用到了 ProtoType了。
我们把函数放到prototype原型对象里面去,调用的时候都从原型对象里面调用。
OK啊 这样就解决了。那么怎么写代码呢?
1 function Person(name, age, gender) { 2 this.user_name = name; 3 this.user_age = age; 4 this.user_gender = gender; 5 6 } 7 Person.prototype.sayHi = function () { 8 alert("我叫" + this.user_name + ",我年芳" + this.user_age + "我是一个分流倜傥的" + this.user_gender + "生"); 9 } 10 11 //创建两个对象; 12 var p1 = new Person('李寻欢', 18, '男'); 13 p1.sayHi(); 14 15 var p2 = new Person('张无忌', 20, '男'); 16 p2.sayHi();
嗨呀!皮呦 怎么回事,我把 sayHi的函数给了 prototype 这个原型对象怎么跟p1 p2 关联起来的?
先说一下你们认为 user_name,user_age....等等属性是谁的? 是Person函数对象的?通过Person创建的p1 p2中能点出来 prototype?
完全不是,user_name,user_age 属性是创建的对象的而不是Person的。prototype是函数对象才有的 ,普通对象是没有的。
举个例子: 就像一个妈妈肚子里怀着一个宝宝,宝宝头嘴角有颗美人痣,那么这个痣是宝宝自己的,不是他妈妈的。
具体到代码里面就是 Person.constructor 有个这个构造函数,当创建对象的时候,内部调用构造函数执行 user_age user_name ..这个段代码,p1 p2 里面才会有。
先看下面这幅图,我再具体说一下;
在创建的每一个对象中,都有一个 __proto__ 这么一个属性,在我们使用p1.sayHi的时候他会首先在自己里面找这个方法,找不到就会通过__proto__这个属性找到原型对象,
去调用原型对象里面的方法。 如果在原型对象里面没找到的话,没关系,原型对象中也有一个__proto__属性,相信大家也猜到了 ,这是不是非常像C#中的继承?
对的。 js是通过原型对象来实现继承的。
总算写完了。
转载请说明出处