国内网页设计师个人网站,奎屯网站建设,长春网站制作wang,免费下载百度seoJavaScript 中的原型和原型链也是一个相对较难理解透彻的知识点#xff0c;下面结合详细例子来进行说明#xff1a;
一、原型的概念
在 JavaScript 中#xff0c;每个函数都有一个 prototype 属性#xff0c;这个属性指向一个对象#xff0c;这个对象就是所谓的 “原型对…JavaScript 中的原型和原型链也是一个相对较难理解透彻的知识点下面结合详细例子来进行说明
一、原型的概念
在 JavaScript 中每个函数都有一个 prototype 属性这个属性指向一个对象这个对象就是所谓的 “原型对象”。当通过构造函数创建一个新的实例对象时该实例对象会自动拥有一个指向构造函数原型对象的内部属性在大多数浏览器中可以通过 proto 来访问这个内部属性虽然它并非标准属性但方便理解。 例如
function Person(name, age) {this.name name;this.age age;
}Person.prototype.sayHello function () {console.log(Hello, my name is ${this.name} and Im ${this.age} years old.);
};let john new Person(John, 30);
john.sayHello();
// 输出Hello, my name is John and Im 30 years old.在这个例子中 首先定义了一个 Person 函数作为构造函数用来创建 Person 类型的实例。 然后给 Person 函数的 prototype 属性添加了一个 sayHello 方法。 当通过 new Person(‘John’, 30) 创建了 john 这个实例后john 本身并没有 sayHello 这个方法的定义但是它可以通过内部的 proto 属性指向 Person.prototype找到并调用 sayHello 方法。
二、原型链的形成
当在一个对象上访问某个属性或方法时如果该对象本身没有这个属性或方法JavaScript 就会自动沿着它的原型链去查找。原型链就是由对象的 proto 属性连接起来的一系列对象。 继续上面的例子假设我们有这样一个情况
function Employee(name, age, department) {Person.call(this, name, age);this.department department;
}Employee.prototype Object.create(Person.prototype);
Employee.prototype.constructor Employee;Employee.prototype.sayDepartment function () {console.log(I work in the ${this.department} department.);
};let jane new Employee(Jane, 25, Engineering);
jane.sayHello();
// 输出Hello, my name is Jane and Im 25 years old.
jane.sayDepartment();
// 输出I work in the Engineering department.在这个例子中 首先定义了 Employee 函数作为构造函数来创建 Employee 类型的实例并且在构造函数内部通过 Person.call(this, name, age) 调用了 Person 构造函数以便让 Employee 实例继承 Person 实例的 name 和 age 属性。 然后通过 Employee.prototype Object.create(Person.prototype) 让 Employee 的原型对象继承自 Person 的原型对象这样 Employee 实例就可以沿着原型链找到 Person 原型对象上的方法如 sayHello。同时重新设置了 Employee.prototype.constructor 为 Employee以保证构造函数的正确性。 最后给 Employee 原型对象添加了 sayDepartment 方法。 当我们在 janeEmployee 实例上调用 sayHello 方法时jane 本身没有 sayHello 方法它会通过自己的 proto 属性此时指向 Employee.prototype找不到就继续沿着 Employee.prototype 的 proto因为 Employee.prototype Object.create(Person.prototype)所以 Employee.prototype.proto 指向 Person.prototype找到 Person.prototype 上的 sayHello 方法并调用。
三、原型链的查找顺序
为了更清楚地展示原型链的查找顺序我们再看一个例子
function Animal() {}
Animal.prototype.eat function () {console.log(Eating...);
};function Dog() {}
Dog.prototype Object.create(Animal.prototype);
Dog.prototype.bark function () {console.log(Woof!);
};let myDog new Dog();
myDog.eat();
// 输出Eating...
myDog.bark();
// 输出Woof!// 查看原型链
console.log(myDog.__proto__ Dog.prototype);
// 输出true
console.log(myDog.__proto__.__proto__ Animal.prototype);
// 输出true
console.log(myDog.__proto__.__proto__.__proto__ Object.prototype);
// 输出true
console.log(myDog.__proto__.__proto__.__proto__.__proto__ null);
// 输出true在这个例子中 定义了 Animal 函数和其原型对象上的 eat 方法。 定义了 Dog 函数并让其原型对象继承自 Animal 原型对象同时在 Dog 原型对象上添加了 bark 方法。 当创建了 myDog 这个 Dog 实例后在 myDog 上调用 eat 方法时首先 myDog 本身没有 eat 方法它会沿着原型链查找。先通过 myDog.proto指向 Dog.prototype找不到再通过 myDog.proto.proto指向 Animal.prototype找到并调用 eat 方法。同样调用 bark 方法时在 myDog 本身找不到通过 myDog.proto 就能找到并调用。 从 myDog 的原型链可以看出查找顺序是先在实例本身查找然后沿着 proto 指向的对象依次查找一直到 Object.prototype最后 Object.prototype.proto 为 null表示原型链的尽头。
四、原型和原型链的难点
概念的抽象性原型和原型链涉及到对象、函数、构造函数、原型对象等多个概念的相互关系理解起来比较抽象。例如要清楚地区分函数的 prototype 属性和实例对象的 proto 属性以及它们之间是如何相互作用来实现属性和方法的继承的这对于初学者来说并不容易。 复杂的继承关系当涉及到多层继承时如上面例子中的 Employee 继承自 Person再加上可能还有更多层的继承关系要准确把握每个实例沿着原型链查找属性和方法的路径以及如何正确设置继承关系比如通过 Object.create 等方式这需要对原型链的机制有深入的理解。 与其他语言的差异对于有其他编程语言背景的开发者来说JavaScript 的原型继承方式与基于类的继承如 Java、C 等有很大的不同。在基于类的继承中继承关系通常是通过类的定义和关键字如 extends来明确规定的而 JavaScript 是通过原型和原型链这种相对更灵活但也更抽象的方式来实现继承的所以习惯了类继承的开发者可能会觉得难以适应。 原型和原型链在 JavaScript 中是非常重要的概念虽然理解起来有一定难度但掌握它们对于深入理解 JavaScript 的对象系统以及编写高效、灵活的代码至关重要。