点击在线浏览,体验更好 | 链接 |
---|---|
古代 JavaScript 高级小册 | 链接 |
深入浅出 Dart | 链接 |
古代 TypeScript 高级小册 | 链接 |
原型和原型链
JavaScript 是一门反对面向对象编程的语言,它的函数是第一公民,同时也领有类的概念。不同于传统的基于类的继承,JavaScript 的类和继承是基于原型链模型的。在 ES2015/ES6 中引入了 class
关键字,但其本质依然是基于原型链的语法糖。
原型(Prototype)
原型(Prototype)是 JavaScript 中对象的一个非凡属性,它用于实现属性和办法的继承。在 JavaScript 中,每个对象都有一个原型属性,它指向另一个对象,这个对象被称为原型对象。通过原型链,对象能够从原型对象继承属性和办法。
原型的概念能够用以下形式解释:每个 JavaScript 对象都是基于一个构造函数创立的,构造函数是对象的模板或蓝图。在创建对象时,构造函数会创立一个关联的原型对象,对象通过原型链继承原型对象上的属性和办法。原型对象是一个一般的 JavaScript 对象,它具备本人的属性和办法。
让咱们以一个示例来阐明原型的概念和作用:
// 构造函数
function Person(name) {this.name = name;}
// 在原型对象上增加办法
Person.prototype.sayHello = function() {console.log("Hello, my name is" + this.name);
};
// 创立实例
var person1 = new Person("John");
var person2 = new Person("Alice");
// 调用原型对象上的办法
person1.sayHello(); // 输入: "Hello, my name is John"
person2.sayHello(); // 输入: "Hello, my name is Alice"
在这个示例中,咱们定义了一个构造函数 Person
,它有一个name
属性。而后,咱们通过给原型对象 Person.prototype
增加一个 sayHello
办法,使得所有通过 Person
构造函数创立的实例都能够拜访该办法。咱们创立了两个实例 person1
和person2
,并别离调用了 sayHello
办法。
原型的重要性体现在以下几个方面:
- 继承:原型链容许对象继承其原型对象上的属性和办法。通过原型链,子对象能够拜访和复用父对象的属性和办法,实现了继承的概念。
- 代码复用和共享:通过将办法和属性定义在原型对象上,能够实现多个对象共享雷同的办法和属性。这样能够节俭内存空间,进步性能,同时也不便了代码的保护和扩大。
上面是一个简略的原型链示意图:
+----------------------+
| Object.prototype |
+----------------------+
^
|
+----------------------+
| Constructor.prototype |
+----------------------+
^
|
+----------------------+
| Object instance |
+----------------------+
在这个示意图中,Object.prototype
是所有对象的原型,Constructor.prototype
是构造函数的原型,Object instance
是基于构造函数创立的对象实例。
构造函数和原型对象
构造函数是用于创建对象的非凡函数。它通常以大写字母结尾,通过应用 new
关键字来调用构造函数,咱们能够创立一个新的对象实例。构造函数在创建对象时能够执行一些初始化操作,并为对象增加属性和办法。
原型对象是构造函数的一个属性,它是一个一般的 JavaScript 对象。原型对象上的属性和办法能够被通过构造函数创立的对象实例所继承。通过将属性和办法定义在原型对象上,咱们能够实现办法的共享和节俭内存空间。
让咱们通过一个示例来阐明构造函数和原型对象的概念以及如何应用它们来创建对象和共享方法:
// 构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
// 在原型对象上增加办法
Person.prototype.sayHello = function() {console.log("Hello, my name is" + this.name + "and I am" + this.age + "years old.");
};
// 创建对象实例
var person1 = new Person("John", 25);
var person2 = new Person("Alice", 30);
// 调用共享的办法
person1.sayHello(); // 输入: "Hello, my name is John and I am 25 years old."
person2.sayHello(); // 输入: "Hello, my name is Alice and I am 30 years old."
在这个示例中,咱们定义了一个构造函数 Person
,它承受 name
和 age
参数,并将它们赋值给对象的属性。而后,咱们通过在原型对象 Person.prototype
上增加一个办法 sayHello
,使得通过 Person
构造函数创立的对象实例能够拜访该办法。咱们创立了两个对象实例 person1
和 person2
,并别离调用了共享的办法 sayHello
。
以下是一个简略的构造函数和原型对象的流程图示意图:
+----------------------------------+
| Constructor |
| |
| +--------------------------+ |
| | Prototype Properties | |
| +--------------------------+ |
| |
| - Property: name |
| - Property: age |
| - Method: sayHello() |
| |
+----------------------------------+
^
|
|
+----------------------------------+
| Object Instance |
| |
| +--------------------------+ |
| | Instance Properties | |
| +--------------------------+ |
| |
| - Property: name |
| - Property: age |
| |
+----------------------------------+
在这个示意图中,构造函数和原型对象之间存在关联,构造函数领有原型对象的援用。通过构造函数,咱们能够创建对象实例,并且这些实例能够通过原型对象继承原型上的属性和办法。
原型链
原型链是 JavaScript 中对象之间通过原型链接起来的机制,用于实现属性和办法的继承。它是由一系列的原型对象组成,每个对象都有一个指向其原型对象的连贯,造成了一条链式构造。
原型链的概念能够通过以下形式解释:在 JavaScript 中,每个对象都有一个外部属性 [[Prototype]](__proto__)
,它指向该对象的原型。当咱们拜访一个对象的属性或办法时,如果该对象自身没有这个属性或办法,JavaScript 引擎会主动沿着原型链向上查找,直到找到匹配的属性或办法或者达到原型链的顶部(Object.prototype
)。
让咱们通过一个示例来阐明原型链的概念和工作原理:
// 父对象构造函数
function Parent() {this.name = "Parent";}
// 在父对象原型上增加办法
Parent.prototype.sayHello = function() {console.log("Hello, I am" + this.name);
};
// 子对象构造函数
function Child() {this.name = "Child";}
// 通过原型继承建设子对象和父对象的连贯
Child.prototype = Object.create(Parent.prototype);
// 创立子对象实例
var child = new Child();
// 调用父对象原型上的办法
child.sayHello(); // 输入: "Hello, I am Child"
在这个示例中,咱们定义了一个父对象构造函数 Parent
,它有一个属性 name
和一个原型办法 sayHello
。而后,咱们定义了一个子对象构造函数 Child
,它也有一个属性 name
。通过 Object.create()
办法,咱们将子对象的原型连贯到父对象的原型上,建设了子对象和父对象之间的原型链关系。最初,咱们创立了子对象实例 child
,并调用了父对象原型上的办法 sayHello
。
以下是一个简略的原型链示意图:
+----------------------+
| Object.prototype |
+----------------------+
^
|
+----------------------+
| Parent.prototype |
+----------------------+
^
|
+----------------------+
| Child.prototype |
+----------------------+
^
|
+----------------------+
| Child instance |
+----------------------+
<!– –>
在这个示意图中,Object.prototype
是所有对象的顶层原型,Parent.prototype
是父对象的原型,Child.prototype
是子对象的原型,Child instance
是基于子对象构造函数创立的对象实例。
原型链的重要性体现在以下几个方面:
- 继承:原型链容许对象通过继承获取其余对象的属性和办法。子对象能够继承父对象的属性和办法,而父对象又能够继承更下层对象的属性和办法,以此类推。
- 代码复用和共享:通过原型链,咱们能够在原型对象
上定义方法和属性,从而实现多个对象之间的办法共享和代码复用。这样能够节俭内存空间,进步性能,并缩小代码的冗余。
- 扩大和批改:通过在原型对象上增加新的办法和属性,咱们能够在整个原型链中的所有对象实例上拜访和应用这些扩大。这样能够不便地对现有对象进行性能扩大和批改。
原型继承
原型继承是一种通过继承原型对象来创立新对象的形式。在 JavaScript 中,咱们能够应用多种形式实现原型继承。原型继承的概念是通过将一个对象作为另一个对象的原型来实现继承,从而使新对象能够共享原型对象的属性和办法。
1. 对象字面量和 Object.create()
:能够应用字面量对象定义属性和办法,并应用 Object.create()
办法创立一个新对象,并将其原型设置为现有对象的原型。
var parent = {
name: "Parent",
sayHello: function() {console.log("Hello, I am" + this.name);
}
};
var child = Object.create(parent);
child.name = "Child";
2. 构造函数和 Object.create()
:能够应用构造函数定义对象,并通过 Object.create()
办法将新对象的原型连贯到现有对象的原型上。
function Parent(name) {this.name = name;}
Parent.prototype.sayHello = function() {console.log("Hello, I am" + this.name);
};
function Child(name) {Parent.call(this, name);
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
var child = new Child("Child");
3. 构造函数和 new
关键字:能够应用构造函数创建对象实例,并应用 new
关键字进行实例化。
function Parent(name) {this.name = name;}
Parent.prototype.sayHello = function() {console.log("Hello, I am" + this.name);
};
function Child(name) {Parent.call(this, name);
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
var child = new Child("Child");
4. 寄生组合继承
寄生组合继承是一种罕用的原型继承形式,联合了构造函数继承和原型链继承的长处,防止了原型链中不必要的属性复制和办法反复定义的问题。这种形式先通过构造函数继承属性,而后通过设置原型链继承办法。
function Parent(name) {this.name = name;}
Parent.prototype.sayHello = function() {console.log("Hello, I am" + this.name);
};
function Child(name, age) {Parent.call(this, name);
this.age = age;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
var child = new Child("Child", 10);
以上是罕用的原型继承实现形式,每种形式都有其特点和实用场景。依据具体的需要和代码构造,能够抉择最适宜的形式来实现原型继承。
参考资料
- MDN Web Docs – Object.create()
- MDN Web Docs – Inheritance and the prototype chain
- JavaScript.info – Prototypal Inheritance
- Eloquent JavaScript – Object-Oriented Programming