JavaScript-原型对象、原型链
在构造函数的例子中,我们想要为Person类构造函数内部创建一个sayName方法是通过外部定义全局函数,内部引用来防止多次创建占用空间,损耗性能。
// 创建一个Person构造函数
function Person(name, age) {
this.name = name;
this.age = age;
/*
* 在构造函数内部创建的sayName方法
* -每执行一次就会创建一个新的方法
* -这样对于同样的方法多次创建占用空间,损耗性能
*/
// this.sayName = function () {
// console.log("我的名字:", this.name);
// }
// 将sayName放在全局作用域中定义就不会多次创建
this.sayName = fun;
}
function fun() {
console.log("我的名字:", this.name);
}
但这也并不是最好的方法,因为方法定义在全局中定义会污染命名空间,不利于复杂功能开发和不利于协同开发。那通过prototype就可以很好的解决这个问题。
一、原型对象
我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,这个对象就是我们所谓的原型对象。 如果函数作为普通函数调用prototype没有任何作用。当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性__proto__指向该构造函数的原型对象,我们可以通过__proto__来访问。
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象。我们可以将对象中共有的内容,统一设置到原型对象中。
构造函数、实例对象、原型对象三者关系如何?以上的文字描述并不直观,通过关系图的加持会让我们的认识更加清晰,看一下吧!
到这里想必已经对原型有所了解了,那尝试一下解决解决开头所说的问题,其实不难想到把公共方法添加在原型上就得以解决了,如下:
function Person(name, age) {
this.name = name;
this.age = age;
}
// 原型上添加一个公共方法sayName
Person.prototype.sayName = function(){
console.log("我的名字:", this.name);
};
通过以上示例是可以的,那更深一层思考,它又是如何查找某个属性或是方法的呢?那这就涉及到原型链的问题了。
二、原型链
访问对象的一个属性或方法便是在原型链上的查找流程如下:
- 它会先在对象自身中寻找,如果有则直接使用
- 如果没有则会去原型对象中寻找,如果找到则直接使用
- 如果还没有就去原型的原型中寻找,直到找到Object对象的原型。
- Object对象的原型没有原型,如果在Object的原型中依然没有则返回undefined。
原型链解析视图如下:
三、完整示例
运行一下以下例子理解更清晰。
1、原型示例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>原型对象示例一</title>
<script>
function Person(name, age) {
this.name = name;
this.age = age;
}
// 原型上添加一个公共属性
Person.prototype.type = '人类';
// 原型上添加一个公共方法
Person.prototype.sayName = function(){
console.log("我的名字:", this.name);
};
let shier = new Person('shier', 12);
// 判断实例对象和构造函数访问到的是否是同一个原型对象
console.log(shier.__proto__ == Person.prototype);
console.log(shier.type);
shier.sayName();
</script>
</head>
<body>
</body>
</html>
2、关于原型链示例
这个示例中涉及检查对象中是否有某个属性的两种方法,简单介绍一下:
- in:如果对象自身没有该属性,原型链中有也会返回true,否则返回false。
- hasOwnProperty():只会检查对象自身是否有该属性,如果有返回true,否则返回false。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>原型对象示例二</title>
<script>
// 创建一个构造函数
function Person() {
}
Person.prototype.type = '人类';
let shier = new Person();
// in检查对象中是否有某个属性,如果对象中没有原型中有也会返回true
console.log("type" in shier);
// hasOwnProperty()
console.log(shier.hasOwnProperty('type'));
// 原型对象也是对象,所以它也有原型
console.log(Person.prototype)
console.log(shier.__proto__.__proto__);
</script>
</head>
<body>
</body>
</html>