11-原型对象
我们在学习构造函数那一节的时候遇到了一个问题。
1 <script type="text/javascript"> 2 function Person(age, name, sex){ 3 this.name = name; 4 this.sex = sex; 5 this.age = age; 6 this.sayName = SayName; 7 } 8 function SayName(){ 9 alert("大家好!" + "我是" + this.name + ",我" + this.age + "岁," + "我是" + this.sex + "生"); 10 } 11 12 p1 = new Person(18, "沙僧", "男"); 13 p2 = new Person(18, "孙悟空", "男"); 14 p3 = new Person(18, "白骨精", "女"); 15 p1.sayName(); 16 p2.sayName(); 17 p3.sayName(); 18 </script>
大家看这个,咱们可以发现虽然可以达到创建多个对象,只调用一次函数的效果,但是也有许多弊端。
将函数定义在全局作用域,污染全局作用域的命名空间,而且定义在全局作用域中也很不安全。因为一个程序一般都是多个人参与开发的,另外一个开发人员可能会用到和你一样的函数名,这样就会污染变量。
下面就为大家介绍另外一种方法:原型对象法
首先为大家解释什么是原型对象?
在每一个构造函数对象中都有一个隐藏的属性prototype,而这个属性是一个对象,我们把这个对象称作原型对象。
大家可以看下面这段代码:
1 function Dog(){ 2 console.log("一只小狗"); 3 } 4 console.log(Dog.prototype);
这段代码运行效果如下:
既然prototype是一个对象那他就可以拥有自己的属性和方法,大家可以看下面这张图:
另外,这个属性在同一个构造函数中创建的对象中是一样的:
1 function Dog(){ 2 console.log("一只小狗"); 3 } 4 // console.log(Dog.prototype); 5 d1 = new Dog(); 6 d2 = new Dog(); 7 console.log(d1.__proto__ === d2.__proto__); 8 console.log(d1.__proto__ === Dog.prototype);
这段代码运行效果如下:
基于以上特性我们可以将需要在构造函数中使用的属性、方法,全部放到原型属性里面:
(原型对象就像是一个公共的区域,所有同一类的实例都可以访问到这个原型对象。)
1 function Person(name, age, sex){ 2 this.name = name; 3 this.age = age; 4 this.sex = sex; 5 } 6 Person.prototype.sayName = function(){ 7 console.log(`大家好,我是${this.name},我是${this.sex}生,我${this.age}岁`); 8 } 9 obj1 = new Person("孙悟空", 10000, "男"); 10 obj1.sayName();
下图是上面代码执行效果:
在JS中当我们访问对象的一个属性或者方法时,他会现在对象自身中寻找,如果有则直接使用,如果没有就向原型对象中找。
另外原型对象也是一个对象,是一个对象就有原型对象,那么是不是没有尽头呢?我们来看下面的代码:
1 console.log(d1.__proto__); 2 console.log(d1.__proto__.__proto__); 3 console.log(d1.__proto__.__proto__.__proto__); // 返回空
下图是代码执行效果:
通过上面代码我们发现并不是所有对象都有原型对象,那么哪一类对象没有原型对象呢?
Object对象没有原型对象,如果在Object中依然没有找到,则返回null或undefined