gpt4 book ai didi

javascript - 改进简单的 JavaScript 继承

转载 作者:可可西里 更新时间:2023-11-01 01:42:47 24 4
gpt4 key购买 nike

John Resig(以 jQuery 闻名)提供了 Simple JavaScript Inheritance 的简洁实现。 .他的方法激发了我进一步改进的尝试。我重写了 Resig 的原始 Class.extend 函数以包含以下优点:

  • 性能 – 类定义、对象构造和基类方法调用期间的开销更少

  • 灵 active – 针对较新的 ECMAScript 5 兼容浏览器(例如 Chrome)进行了优化,但为较旧的浏览器(例如 IE6)提供等效的“垫片”

  • 兼容性 – 在严格模式下验证并提供更好的工具兼容性(例如 VSDoc/JSDoc 注释、Visual Studio IntelliSense 等)

  • 简单 – 您不必成为“忍者”也能理解源代码(如果您失去了 ECMAScript 5 功能,它甚至会更简单)

    <
  • 健壮性 – 通过更多“极端情况”单元测试(例如在 IE 中重写 toString)

因为它好得令人难以置信,所以我想确保我的逻辑没有任何基本缺陷或错误,看看是否有人可以提出改进建议或反驳代码。有了这个,我展示了 classify 函数:

function classify(base, properties)
{
/// <summary>Creates a type (i.e. class) that supports prototype-chaining (i.e. inheritance).</summary>
/// <param name="base" type="Function" optional="true">The base class to extend.</param>
/// <param name="properties" type="Object" optional="true">The properties of the class, including its constructor and members.</param>
/// <returns type="Function">The class.</returns>

// quick-and-dirty method overloading
properties = (typeof(base) === "object") ? base : properties || {};
base = (typeof(base) === "function") ? base : Object;

var basePrototype = base.prototype;
var derivedPrototype;

if (Object.create)
{
// allow newer browsers to leverage ECMAScript 5 features
var propertyNames = Object.getOwnPropertyNames(properties);
var propertyDescriptors = {};

for (var i = 0, p; p = propertyNames[i]; i++)
propertyDescriptors[p] = Object.getOwnPropertyDescriptor(properties, p);

derivedPrototype = Object.create(basePrototype, propertyDescriptors);
}
else
{
// provide "shim" for older browsers
var baseType = function() {};
baseType.prototype = basePrototype;
derivedPrototype = new baseType;

// add enumerable properties
for (var p in properties)
if (properties.hasOwnProperty(p))
derivedPrototype[p] = properties[p];

// add non-enumerable properties (see https://developer.mozilla.org/en/ECMAScript_DontEnum_attribute)
if (!{ constructor: true }.propertyIsEnumerable("constructor"))
for (var i = 0, a = [ "constructor", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "toLocaleString", "toString", "valueOf" ], p; p = a[i]; i++)
if (properties.hasOwnProperty(p))
derivedPrototype[p] = properties[p];
}

// build the class
var derived = properties.hasOwnProperty("constructor") ? properties.constructor : function() { base.apply(this, arguments); };
derived.prototype = derivedPrototype;
derived.prototype.constructor = derived;
derived.prototype.base = derived.base = basePrototype;

return derived;
}

除了构造函数名称(constructor vs. init)和基类方法调用的语法外,用法几乎与 Resig 相同。

/* Example 1: Define a minimal class */
var Minimal = classify();

/* Example 2a: Define a "plain old" class (without using the classify function) */
var Class = function()
{
this.name = "John";
};

Class.prototype.count = function()
{
return this.name + ": One. Two. Three.";
};

/* Example 2b: Define a derived class that extends a "plain old" base class */
var SpanishClass = classify(Class,
{
constructor: function()
{
this.name = "Juan";
},
count: function()
{
return this.name + ": Uno. Dos. Tres.";
}
});

/* Example 3: Define a Person class that extends Object by default */
var Person = classify(
{
constructor: function(name, isQuiet)
{
this.name = name;
this.isQuiet = isQuiet;
},
canSing: function()
{
return !this.isQuiet;
},
sing: function()
{
return this.canSing() ? "Figaro!" : "Shh!";
},
toString: function()
{
return "Hello, " + this.name + "!";
}
});

/* Example 4: Define a Ninja class that extends Person */
var Ninja = classify(Person,
{
constructor: function(name, skillLevel)
{
Ninja.base.constructor.call(this, name, true);
this.skillLevel = skillLevel;
},
canSing: function()
{
return Ninja.base.canSing.call(this) || this.skillLevel > 200;
},
attack: function()
{
return "Chop!";
}
});

/* Example 4: Define an ExtremeNinja class that extends Ninja that extends Person */
var ExtremeNinja = classify(Ninja,
{
attack: function()
{
return "Chop! Chop!";
},
backflip: function()
{
this.skillLevel++;
return "Woosh!";
}
});

var m = new Minimal();
var c = new Class();
var s = new SpanishClass();
var p = new Person("Mary", false);
var n = new Ninja("John", 100);
var e = new ExtremeNinja("World", 200);

这是我的全部通过的 QUnit 测试:

equals(m instanceof Object && m instanceof Minimal && m.constructor === Minimal, true);
equals(c instanceof Object && c instanceof Class && c.constructor === Class, true);
equals(s instanceof Object && s instanceof Class && s instanceof SpanishClass && s.constructor === SpanishClass, true);
equals(p instanceof Object && p instanceof Person && p.constructor === Person, true);
equals(n instanceof Object && n instanceof Person && n instanceof Ninja && n.constructor === Ninja, true);
equals(e instanceof Object && e instanceof Person && e instanceof Ninja && e instanceof ExtremeNinja && e.constructor === ExtremeNinja, true);

equals(c.count(), "John: One. Two. Three.");
equals(s.count(), "Juan: Uno. Dos. Tres.");

equals(p.isQuiet, false);
equals(p.canSing(), true);
equals(p.sing(), "Figaro!");

equals(n.isQuiet, true);
equals(n.skillLevel, 100);
equals(n.canSing(), false);
equals(n.sing(), "Shh!");
equals(n.attack(), "Chop!");

equals(e.isQuiet, true);
equals(e.skillLevel, 200);
equals(e.canSing(), false);
equals(e.sing(), "Shh!");
equals(e.attack(), "Chop! Chop!");
equals(e.backflip(), "Woosh!");
equals(e.skillLevel, 201);
equals(e.canSing(), true);
equals(e.sing(), "Figaro!");
equals(e.toString(), "Hello, World!");

有没有人认为我的方法与 John Resig 的 original approach 有什么不对? ?欢迎提出建议和反馈!

注意:自从我最初发布这个问题以来,上面的代码已经进行了重大修改。以上代表最新版本。要了解它是如何演变的,请查看修订历史。

最佳答案

前段时间,我看了几个 JS 的对象系统,甚至实现了一些我自己的,例如 class.js ( ES5 version ) 和 proto.js .

我从未使用过它们的原因是:您最终会编写相同数量的代码。恰当的例子:Resig 的忍者示例(仅添加了一些空格):

var Person = Class.extend({
init: function(isDancing) {
this.dancing = isDancing;
},

dance: function() {
return this.dancing;
}
});

var Ninja = Person.extend({
init: function() {
this._super(false);
},

swingSword: function() {
return true;
}
});

19 行,264 字节。

带有 Object.create() 的标准 JS(这是一个 ECMAScript 5 函数,但出于我们的目的,可以用自定义 ES3 clone() 实现替换):

function Person(isDancing) {
this.dancing = isDancing;
}

Person.prototype.dance = function() {
return this.dancing;
};

function Ninja() {
Person.call(this, false);
}

Ninja.prototype = Object.create(Person.prototype);

Ninja.prototype.swingSword = function() {
return true;
};

17 行,282 字节。 Imo,额外的字节并不真正值得一个单独的对象系统增加的复杂性。通过添加一些自定义函数可以很容易地缩短标准示例,但同样:这并不值得。

关于javascript - 改进简单的 JavaScript 继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2510342/

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