[英]JavaScript prototype inheritance with defineProperty
說我有這個“班級”:
function Car()
{
}
Object.defineProperty(Car.prototype, "Make",
{
get:function() { return this._make; },
set:function(value) { this._make = value; }
});
Object.prototype.Drive = function Drive() { console.log("Car.Drive"); }
現在,我想使用原型繼承創建一個“子類”:
function Sedan()
{
}
Sedan.prototype = new Car();
Sedan.prototype.constructor = Sedan;
Sedan.prototype.Drive = function Drive() { Car.prototype.Drive.call(this); console.log("Sedan.Drive"); }
然后,我可以實例化汽車或轎車,並同時開車。 請注意,對於轎車,Drive還如何調用基類(Car)Drive:
var car = new Car(); car.Drive(); var carMake = car.Make;
var sedan = new Sedan(); sedan.Drive(); var sedanMake = sedan.Make;
是否可以實現與屬性相似的東西?
Object.defineProperty(Sedan.prototype, "Make",
{
get: function() { return Car.prototype.Make.<<CALL_GETTER>>(this) + " - Sedan"; },
set: function(value) { Car.prototype.Make.<<CALL_SETTER>>(this, value.replace(" - Sedan", "")); }
});
我唯一能想到的想法是這樣的:
Car.prototype.get_Make = function get_Make() { return this._make; }
Car.prototype.set_Make = function set_Make(value) { this._make = value; }
Object.defineProperty(Car.prototype, "Make",
{
get:function() { return this.get_Make(); },
set:function(value) { this.set_Make(value); }
});
然后,類似於Drive,可以覆蓋顯式的get_Make和set_Make。 但是,這很笨拙。 當然,可以將樣板提取到一個幫助函數中,該函數一次定義get_和set_方法以及該屬性。
function DefineVirtualProperty(obj, name, getter, setter)
{
obj["get_" + name] = getter;
obj["set_" + name] = setter;
Object.defineProperty(obj, name,
{
get:function() { return this["get_" + name](); },
set: function(value) { this["set_" + name](value); }
});
}
DefineVirtualProperty(Car.prototype, "Make", function() { return this._make; }, function(value) { this._make = value; });
但是,最重要的問題仍然是丑陋的。
您可以使用Object.getOwnPropertyDescriptor
來獲取父屬性的屬性描述符。
然后,您可以使用.call()
來調用它,例如:
function Car() {} Object.defineProperty(Car.prototype, "Make", { get() { return this._make; }, set(value) { this._make = value; } }); function Sedan() {} Sedan.prototype = Object.create(Car); Sedan.prototype.constructor = Sedan; Object.defineProperty(Sedan.prototype, "Make", { get() { console.log("Sedan Make get"); let desc = Object.getOwnPropertyDescriptor(Car.prototype, "Make"); return desc.get.call(this); }, set(value) { console.log("Sedan Make set"); let desc = Object.getOwnPropertyDescriptor(Car.prototype, "Make"); return desc.set.call(this, value); } }); let sedan = new Sedan(); sedan.Make = 12; console.log(sedan.Make);
一些小技巧:
Object.create
進行原型創建,因為在創建對象時它不會調用構造函數 Object.defineProperty
而不是直接在原型上創建屬性(因此您可以將enumerable
設置為false) 如果可以使用ES6類,它將變得更好。
您可以將super
與它們一起使用以訪問父屬性:
class Car { get Make() { return this._make; } set Make(value) { this._make = value; } } class Sedan extends Car { get Make() { console.log("Sedan Make get"); return super.Make; } set Make(value) { console.log("Sedan Make set"); super.Make = value; } } let sedan = new Sedan(); sedan.Make = 12; console.log(sedan.Make);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.