我对 JavaScript 比较陌生,并且经常在我使用的第三方库中看到 .extend 和 .prototype。我认为这与 Prototype javascript 库有关,但我开始认为情况并非如此。这些是干什么用的?
7 回答
Javascript 的继承是基于原型的,因此您可以扩展对象的原型,例如 Date、Math,甚至是您自己的自定义对象。
Date.prototype.lol = function() {
alert('hi');
};
( new Date ).lol() // alert message
在上面的代码片段中,我为所有Date 对象(已经存在的对象和所有新对象)定义了一个方法。
extend
通常是一个高级函数,它复制要从基类扩展的新子类的原型。
因此,您可以执行以下操作:
extend( Fighter, Human )
并且Fighter
构造函数/对象将继承 的原型Human
,因此如果您定义诸如live
和die
on Human
then之类的方法,Fighter
也会继承这些。
更新说明:
“高级函数”意味着 .extend 不是内置的,但通常由 jQuery 或 Prototype 等库提供。
.extend()
由许多第三方库添加,以方便从其他对象创建对象。有关一些示例,请参见http://api.jquery.com/jQuery.extend/或http://www.prototypejs.org/api/object/extend。
.prototype
指的是对象的“模板”(如果你想这样称呼它),所以通过向对象的原型添加方法(你在库中看到很多添加到字符串、日期、数学甚至函数的方法)这些方法被添加到该对象的每个新实例中。
extend
例如jQuery或PrototypeJS中的方法,将所有属性从源对象复制到目标对象。
现在关于prototype
属性,它是函数对象的成员,它是语言核心的一部分。
任何函数都可以用作构造函数,以创建新的对象实例。所有函数都有这个prototype
属性。
当您new
在函数对象上使用运算符时,将创建一个新对象,并将继承自其构造函数prototype
。
例如:
function Foo () {
}
Foo.prototype.bar = true;
var foo = new Foo();
foo.bar; // true
foo instanceof Foo; // true
Foo.prototype.isPrototypeOf(foo); // true
Javascript 继承似乎无处不在。堪称“Javascript 语言奇事”。
这个想法是有一个基类,然后您扩展基类以获得类似继承的功能(不完全,但仍然如此)。
整个想法是获得原型的真正含义。直到我看到 John Resig 的代码(接近什么jQuery.extend
)写了一个代码块来完成它,他声称 base2 和原型库是灵感的源泉,我才明白这一点。
这是代码。
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function(){
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function(){};
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
有三个部分在做这项工作。首先,循环遍历属性并将它们添加到实例中。之后,您创建一个构造函数以供稍后添加到对象中。现在,关键行是:
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
您首先将 指向Class.prototype
所需的原型。现在,整个对象已经改变,这意味着您需要强制布局回到它自己的布局。
以及使用示例:
var Car = Class.Extend({
setColor: function(clr){
color = clr;
}
});
var volvo = Car.Extend({
getColor: function () {
return color;
}
});
在John Resig的帖子中的 Javascript Inheritance 中阅读更多相关信息。
extend
第三方库中的某些功能比其他功能更复杂。例如, Knockout.js包含一个最简单的一个,它没有 jQuery 所做的一些检查:
function extend(target, source) {
if (source) {
for(var prop in source) {
if(source.hasOwnProperty(prop)) {
target[prop] = source[prop];
}
}
}
return target;
}
.extends()
创建一个类,它是另一个类的子类。
在幕后Child.prototype.__proto__
将其值设置为Parent.prototype
以便继承方法。.prototype
从一个到另一个继承特性。
.__proto__
是 Prototype 的 getter/setter。
这对我来说似乎是最清晰和最简单的例子,这只是附加属性或替换现有的。
function replaceProperties(copyTo, copyFrom) {
for (var property in copyFrom)
copyTo[property] = copyFrom[property]
return copyTo
}