gpt4 book ai didi

javascript - Javascript原型(prototype)构造函数说明

转载 作者:行者123 更新时间:2023-11-29 17:51:35 25 4
gpt4 key购买 nike

我有以下代码片段代表了此问题的答案:

您正在创建一个必须从Employee类继承的名为Consultant的类。 Consultant类必须修改继承的PayEmployee方法。将来的顾问实例必须使用重写的方法创建。

function Employee() {}

Employee.prototype.PayEmployee = function ( ){
alert(‘Hi there!’);
}

function Consultant () {
Employee.call(this); // X
}
Consultant.prototype = new Employee();
Consultant.prototype.constructor = Consultant; // X

Consultant.prototype.PayEmployee = function ()
{
alert(‘Pay Consultant’);
}


我真的无法解决这个问题。为什么标有“ X”的行是必需的?我不能只编写没有这些行的代码,它会完全一样吗?根据我的测试,这没有什么区别:


https://jsfiddle.net/yk84g8f4/1/
https://jsfiddle.net/66jxp9p9/


有人可以向我解释这两个代码之间的区别是什么,为什么我应该在另一个上使用它?

提前致谢

最佳答案

我不能只编写没有这些行的代码,它会完全一样吗?


不,在一般情况下,您确实需要两者。是的,在某些特定情况下,您可能没有一个或两个都逃脱了。

首先,请注意该代码中有一个常见错误。这是不正确的:

Consultant.prototype = new Employee(); // INCORRECT


它应该是:

Consultant.prototype = Object.create(Employee.prototype);


new Employee做两件事:


它创建一个使用 Employee.prototype作为其原型的对象
它在 Employee中运行代码,其作用是通过设置 Employee等属性来初始化 this实例。


但是我们还不想要第二部分。 Consultant.prototype不是 Employee实例,它是一个对象,它将成为通过 new Consultant创建的对象的原型(将是 Employee的实例,也是 Consultant的实例)。 (这是JavaScript的构造函数和 prototype属性偏离标准原型继承的地方。您可以在JavaScript中进行标准原型继承,但是这样做时,您将不使用构造函数, prototype属性或 new

Object.create只是完成这两个任务中的第一个:使用 Employee.prototype作为其原型创建一个对象。因此,我们最终在 Consultant.prototype上使用了一个对象,该对象使用 Employee.prototype作为其原型,但没有调用 Employee并让它运行其按实例的初始化代码。 (我们稍后在第二行中用X标记。)

但是,为什么我们不希望 Employee进行每个实例的初始化呢?同样,由于 Consultant.prototype不是 Employee实例,因此将其初始化为一个实例没有任何意义。一方面:如果 Employee需要用于初始化返回的对象的参数,该怎么办?构造 Consultant.prototype时我们将通过什么?在这一点上,我们没有任何特定于实例的信息来传递它。

因此,相反,我们只是在上面执行了#1(通过 Object.create),然后离开了#2(调用 Employee),直到构造实例为止,方法是从 Employee.call(this)调用 Consultant(在下面进行更多介绍)。



标记行:

Employee.call(this);


这行对于使 Employee有机会对正在创建的实例进行初始化至关重要。没有它, Employee就没有机会做它的工作:初始化实例的 Employee部分。例如,假设 Employee看起来像这样:

function Employee() {
this.paySchedule = "biweekly";
}


如果在 Employee.call(this);中没有 Consultant行,则通过 new Consultant创建的实例将缺少该属性。

您的第二条标记行:

Consultant.prototype.constructor = Consultant;


我们需要这样做,因为 Consultant.prototypeconstructor属性应指向 Consultant,但是如果我们不这样做,它将指向 Employee

它过去没什么大不了的,因为尽管 constructor在规范中定义为默认情况下是通过这种方式设置的,但在使用它的规范中没有任何内容。在ES2015(又称为“ ES6”)中发生了变化:现在,有时会使用 constructor属性(例如,在promise中)。



这是一个示例,说明 Employee具有参数的情况。我也将 PayEmployee切换为 payEmployee以符合JavaScript中压倒性的约定,即最初仅对构造函数进行了上限:



function Employee(name, title) {
this.name = name;
this.title = title;
}

Employee.prototype.payEmployee = function() {
console.log("Time to pay " + this.name + " (" + this.title + ")");
};

function Consultant(name) {
Employee.call(this, name, "Consultant");
}
Consultant.prototype = Object.create(Employee.prototype);
Consultant.prototype.constructor = Consultant;

Consultant.prototype.payEmployee = function() {
console.log("Time to pay " + this.name + " (" + this.title + ") -- remember, you're paying the gross, consultants handle their own tax.");
};

var e = new Employee("Joe Bloggs", "Engineer");
e.payEmployee();

var c = new Consultant("John Smith");
c.payEmployee();







最后,如果我没有指出从ES2015开始,我会对此感到不知所措,因为我们拥有 class语法,可以在较旧的环境中进行必要的转换:



class Employee {
constructor(name, title) {
this.name = name;
this.title = title;
}
payEmployee() {
console.log("Time to pay " + this.name + " (" + this.title + ")");
}
}

class Consultant extends Employee {
constructor(name) {
super(name, "Consultant");
}
payEmployee() {
console.log("Time to pay " + this.name + " (" + this.title + ") -- remember, you're paying the gross, consultants handle their own tax.");
}
}

const e = new Employee("Joe Bloggs", "Engineer");
e.payEmployee();

const c = new Consultant("John Smith");
c.payEmployee();







您询问 Consultant.prottype = new Employee();是否总是错误。让我们使用 new Employee来获取代码版本,并删除用X标记的两行,然后向Employee添加一个看起来应该可以使用的功能,但最终会导致各种混乱:



function Employee() {
this.staff = [];
}

Employee.prototype.payEmployee = function() {
console.log("Paying employee");
};

function Consultant(name) {
}
Consultant.prototype = new Employee();

Consultant.prototype.payEmployee = function() {
console.log("Time to pay " + this.name + " (" + this.title + ") -- remember, you're paying the gross, consultants handle their own tax.");
};

var jill1 = new Employee();
jill1.staff.push("Bob");
jill1.staff.push("Jane");

var john1 = new Employee();
john1.staff.push("Russell");
john1.staff.push("Mohammed");

console.log("Jill's staff (1): " + jill1.staff.join(", "));
console.log("John's staff (1): " + john1.staff.join(", "));

// so far so good, but what if we use Consultant instead?

var jill2 = new Consultant();
jill2.staff.push("Bob");
jill2.staff.push("Jane");

var john2 = new Consultant();
john2.staff.push("Russell");
john2.staff.push("Mohammed");

console.log("Jill's staff (2): " + jill2.staff.join(", "));
console.log("John's staff (2): " + john2.staff.join(", "));

// ??? how is it they both have all four staff?!





问题在于 staff数组位于 Consultant.prototype上,而不是每个实例上,因此无论我们使用哪个实例,我们总是在访问同一数组。

这就是为什么我们不使用旨在初始化实例的函数(例如,构造函数)来初始化构造函数的 prototype属性的对象的原因。

我应该注意,在标准的原型继承中,实际创建一个实例作为另一个实例的原型是正常的。但是JavaScript的构造函数及其 prototype属性不是标准的原型继承,它们是基于类的OOP和原型OOP的混合体。您可以使用JavaScript进行纯原型OOP(很多可以这样做),但是当您这样做时,就不必使用构造函数,其 prototype属性或 new。您通常使用工厂功能和 Object.create

关于javascript - Javascript原型(prototype)构造函数说明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43062766/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com