Javascript重新定义和覆盖现有的函数体
Javascript redefine and override existing function body
我想知道,一旦构建好函数体,我们还能更改它吗?
var O = function(someValue){
this.hello = function(){
return "hello, " + someValue;
}
}
O.prototype.hello = function(){
return "hhhhhhh";
}
var i = new O("chris");
i.hello(); // -> this still returns the old definition "hello, chris"
javascript语句O.prototype.hello = function(){....}
不会覆盖和重新定义hello函数的行为。为什么?我知道如果您尝试重用参数someValue
,它将出现类型错误。
// this will fail since it can't find the parameter 'someValue'
O.prototype.hello = function(){
return "aloha, " + someValue;
}
我想知道为什么它允许在运行时添加功能,比如
O.prototype.newFunction = function(){
return "this is a new function";
}
i.newFunction(); // print 'this is a new function' with no problem.
但不允许在定义后更改定义。我做错什么了吗?我们如何重写和重新定义类中的函数?有没有一种方法可以重用我们之前传递的参数来创建对象?在这种情况下,如果我们想为someValue
扩展更多的函数,我们如何重用它。
当您使用new
时,构造函数中this
的值指向新创建的对象(有关new
如何工作的更多信息,请查看此答案和此答案)。因此,您的新实例i
具有hello
函数。当你试图访问一个对象的属性时,它会沿着原型链向上走,直到找到它。由于hello
存在于对象的实例上,所以不需要沿着原型链往上走就可以访问返回hhhhhhhh
的hello
版本。从某种意义上说,您已经覆盖了实例中的默认实现。
如果不在构造函数中将hello
分配给this
,则可以看到这种行为
var O = function(someValue) {
}
O.prototype.hello = function(){
return "hhhhhhh";
}
var i = new O("chris");
console.log(i.hello()); //this prints out hhhhhhh
你所做的有点倒退。原型基本上提供了某种东西的"默认"形式,您可以在每个实例的基础上覆盖它。只有在对象上找不到您要查找的属性时,才会使用默认表单。也就是说,JavaScript将开始在原型链上遍历,看看它是否能找到与您所寻找的属性相匹配的属性。如果它找到了它,它就会使用它。否则返回undefined
。
在第一种情况下,您基本上拥有的内容如下:
Object.prototype.hello (not defined; returns "undefined")
|
+----O.prototype.hello (returns "hhhhhhhh")
|
+----i.hello (returns "hello, chris")
因此,当您执行i.hello
时,JavaScript会看到i
上有一个hello
属性并使用它。现在,如果您没有明确定义hello
属性,那么您基本上有以下内容:
Object.prototype.hello (not defined; returns "undefined")
|
+----O.prototype.hello (returns "hhhhhhhh")
|
+----i.hello (is "undefined", so JavaScript will walk up the chain until
it sees O.prototype.hello, which does have a defined value
it can use.)
这意味着你可以在原型中提供一个默认的实现,然后覆盖它(从某种意义上说,这就像子类)。您还可以通过直接修改实例来修改每个实例的行为。原型上的hello
版本是一种故障保护和回退。
编辑:问题答案:
基于每个实例的重写意味着将属性或函数附加到特定实例。例如,你可以做:
i.goodbye = function() {
return "Goodbye, cruel world!";
};
这意味着此行为特定于特定实例(即,仅适用于i
,而不适用于您可能创建的任何其他实例)。
如果你取出this
,那么你基本上已经有了:
hello = function() {
return "hello, " + someValue;
}
这相当于做:
window.hello = function() {
return "hello, " + someValue;
}
因此,在这种情况下,hello
是对该函数的全局引用。这意味着hello
没有附加到任何对象。
如果您的构造函数中没有this.hello = function() { .... };
,那么hello
可能是未定义的。我还谈到了JavaScript用来解析对象属性的一般过程。正如我之前提到的,它涉及到走上原型链。
当您使用new O("somename");
创建O
对象的实例时,您正在将实例方法分配给新创建的对象。然后,当您将另一个同名方法分配给O
的prototype
时,该方法已被实例方法覆盖。因此:
Object.prototype.hello // undefined
|
O.prototype.hello // alternate function
|
i.hello // original function provided in constructor
JavaScript从链的底部开始,当找到与名称匹配的名称时停止。因此,它在i.hello
处停止并且从未看到O.prototype.hello
。
JavaScript(从ECMAScript 5开始)实际上(据我所知)并没有为您提供一种很好的方法来实现私有变量,比如可以通过定义后添加的实例方法访问的私有变量(在实例或prototype
上添加)。闭包在很大程度上实现了这一点,但如果你想在闭包之外添加可以访问闭包变量的方法,你需要公开get
和/或set
方法,这些方法可以让这些新方法访问闭包变量:
// Possibility #1 - marked as private member
var O = function(someValue) {
this._someValue = someValue;
};
O.prototype.hello = function() { return "hhhh"; };
var i = new O("somename");
i.hello = function() { return "aloha," + this._someValue; };
console.log(O.hello()); // hhhh
console.log(i.hello()); // aloha, somename
// Possibility #2 - factory function + closure with get and set methods
var OMaker = function(someValue) {
var realO = function() {};
realO.prototype.getSomeValue = function() { return someValue; };
realO.prototype.setSomeValue = function(newVal) { someValue = newVal; };
realO.prototype.hello = function() { return "hhhh"; };
return realO;
};
var O = OMaker("somename"),
i = new O();
i.hello = function() { return "aloha," + this.getSomeValue(); };
console.log(O.hello()); // hhhh
console.log(i.hello()); // aloha, somename
// Possibility #3 - eschew prototype inheritance and create new objects
var O = function(someValue) {
return {
getValue: function() { return someValue; },
setValue: function(newValue) { someValue = newValue; },
hello: function() { return "hhhh"; }
};
};
var i = O(); // Note the lack of the "new" keyword
i.hello = function() { return "aloha," + this.getSomeValue(); };
console.log(O.hello()); // hhhh
console.log(i.hello()); // aloha, somename
你真的很想阅读bobince关于JavaScript中OOP的精彩回答,了解更多关于这个主题的信息。
编号。你不能,但这里有一个很好的例子,通过以不同的方式模式化你的继承,可以绕过这个限制。
JavaScript覆盖方法
// Create a class
function Vehicle(color){
this.color = color;
}
// Add an instance method
Vehicle.prototype.go = function(){
return "Underway in " + this.color;
}
// Add a second class
function Car(color){
this.color = color;
}
// And declare it is a subclass of the first
Car.prototype = new Vehicle();
// Override the instance method
Car.prototype.go = function(){
return Vehicle.prototype.go.call(this) + " car"
}
// Create some instances and see the overridden behavior.
var v = new Vehicle("blue");
v.go() // "Underway in blue"
var c = new Car("red");
c.go() // "Underway in red car"
首先,您需要了解原型继承
当您使用O
作为构造函数创建对象时,会发生以下情况:
- 首先,创建一个新对象
- 第二,该对象的hello属性被设置为一个函数(通过您定义的构造函数)
- 第三,创建来自对象的指向
O.prototype
对象的秘密链接
当引用O
对象的属性时,首先在对象本身中查找这些属性。只有当对象本身没有属性时,它才会查找其原型。
其次,您需要了解闭包
someValue
是在O
函数中定义的变量(而不是属性)。它只能从同一函数(或O
函数内部定义的任何函数)中定义的其他事物访问。因此,我们说"someValue
是闭合的"。您在O
之外定义的函数无法访问它。
为了实现您想要的,您需要将someValue设置为一个属性(这使它不像private
,更像public
)。或者,您需要在O
的原始定义中定义所有需要访问someValue
的函数。
要在创建i
之后更改i.hello
指向的内容,需要直接设置对象的属性。
i.hello = function () { /* stuff */ };
如果我没有记错,作为对象的直接成员的函数优先于该对象原型的类似命名成员。因此,O.prototype.hello
被O.hello
取代,即使前者在代码的后面定义。
someValue
对O.prototype.hello
不可用的原因是,someValue
的作用域被约束为构造函数以及在其中定义或执行的任何函数。由于O.prototype.hello
是在O
构造函数的作用域之外定义的,所以它不知道someValue
当您访问属性时,系统首先在实例中查找它。如果没有找到,它会在原型中查找它。这就是为什么使用This.hello,而不是O.prototype.hello。
如果您希望覆盖hello的实现,则需要使用JavaScript继承。以下是一个基本示例:
var A = function(){
console.log("A is getting constructed");
};
A.prototype.constructor = A;
A.prototype.someValue = 1;
A.prototype.hello = function() {
console.log("A.hello(): " + this.someValue);
};
var B = function(){
//Constructor of A is automatically called before B's
console.log("B is getting constructed");
};
B.prototype = new A; //Inherit from A
B.prototype.constructor = B;
B.prototype.hello = function() {
console.log("B.hello() called");
console.log("Calling base class method");
A.prototype.hello.call(this);
};
var a = new A();
a.hello();
var b = new B();
b.hello();
这是因为当您访问对象的属性时,JavaScript在进入其原型之前首先检查对象的属性。
这类似于Java的派生类覆盖基类功能。
为了更好地理解,请查看继承属性中的代码示例
还要注意,您的案例中的someValue是构造函数的本地值。如果您在其他函数中需要它,您应该将它分配给构造函数内的this.someValue。
您可以在这里覆盖特定对象的hello函数,如下所示。但不适用于整个班级。
i.hello = function(){ console.log('even here someValue is not accessible');};
var O = function(someValue){
this.someValue = someValue;
this.hello = function(){
return "hello, " + someValue;
}
}
var i = new O("chris");
console.log(i.hello()); // prints hello, chris
i.hello = function() {
return 'Hi there '+ this.someValue;
}
console.log(i.hello()); // prints Hi there chris
var test = new O('Sujay')
console.log(test.hello()) // this still prints hello, Sujay
请注意,这里我们没有更改构造函数,因此这将不适用于其他实例,如上例中的test
。
最好的方法是只在原型&而不是在构造函数中,就像下面的片段一样。
var O = function(someValue){
this.someValue = someValue;
};
O.prototype.hello = function(){
return "hello, " + this.someValue;
};
var i = new O("chris");
console.log(i.hello()); // prints hello, chris
O.prototype.hello = function() {
return 'Hi there '+ this.someValue;
}
console.log(i.hello()); // prints Hi there chris
var test = new O('Sujay')
console.log(test.hello()) // prints Hi there Sujay
覆盖已创建实例的方法refreshEditor:
var cp = hot1.getPlugin('comments');
cp.refreshEditor = (function (original) {
return function (force) {
//do something additional
if(console) {
console.log('test!!!!!!!!!');
console.log(force)
}
original.call(cp, force);
}
})(cp.refreshEditor);
- 覆盖函数中的函数
- 如何在 JavaScript 中获取函数体文本
- Javascript重新定义和覆盖现有的函数体
- 为什么可以'我们在函数体中为函数对象添加属性,就像在javascript中为对象文字添加属性一样
- 如何在javascript中覆盖函数的行为
- 在运行时将代码插入函数体
- 从函数体参数中获取值
- Javascript闭包覆盖函数表达式
- 为什么错误显示为函数体之前缺少{
- 如何在jquery中使用函数体onload
- 具有生成名称的 Javascript 覆盖函数
- 在节点导出中覆盖函数的 toString()
- for 循环中的覆盖函数
- 在 JavaScript 中扩展或覆盖函数
- JS:正则表达式,用于查找函数体中的所有函数调用
- 覆盖函数(例如“alert”)并调用原始函数
- Javascript覆盖函数
- CoffeeScript::我不知道为什么在使用 ajax 时返回函数体
- 如何在javascript中使用原型覆盖函数
- 为什么函数变量(当登录控制台时)没有显示整个函数体