Javascript重新定义并覆盖现有的函数体

pet*_*ter 23 javascript prototype

我想知道一旦它构建完成后我们还能改变它吗?

     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"
Run Code Online (Sandbox Code Playgroud)

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;
      } 
Run Code Online (Sandbox Code Playgroud)

我想知道为什么它允许在运行时添加功能

      O.prototype.newFunction = function(){
           return "this is a new function";
      }

      i.newFunction();   //  print 'this is a new function' with no problem.
Run Code Online (Sandbox Code Playgroud)

但一旦定义,就不允许你更改定义.我做错什么了吗 ?我们如何覆盖和重新定义类中的函数?有没有办法重用我们之前传递的参数来创建对象?在这种情况下,someValue如果我们想要向其扩展更多功能,我们如何重新使用.

Viv*_*ath 23

使用时new,this构造函数内部的值指向新创建的对象(有关new工作原理的更多信息,请查看此答案此答案).所以你的新实例i,有一个hello功能.当您尝试访问对象的属性时,它会沿着原型链向上走,直到找到它为止.由于hello存在于对象的实例上,因此无需走原型链来访问该hello返回的版本hhhhhhhh.从某种意义上说,您已经覆盖了实例中的默认实现.

如果不在构造函数内部分配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
Run Code Online (Sandbox Code Playgroud)

你正在做的事情是倒退.原型基本上提供了某种东西的"默认"形式,您可以在每个实例的基础上覆盖它.仅当在对象上找不到您要查找的属性时,才使用默认表单.也就是说,JavaScript将开始走向原型链,看看它是否能找到与您正在寻找的匹配的属性.它找到它,它将使用它.否则,它将返回undefined.

你在第一种情况下基本上拥有的内容如下:

Object.prototype.hello (not defined; returns "undefined")
|
+----O.prototype.hello (returns "hhhhhhhh")
     |
     +----i.hello (returns "hello, chris")
Run Code Online (Sandbox Code Playgroud)

所以当你这样做时i.hello,JavaScript会看到有一个hello属性i并使用它.现在,如果您没有明确定义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.)
Run Code Online (Sandbox Code Playgroud)

这意味着您可以在原型中提供默认实现,然后覆盖它(在某种意义上它就像子类).您还可以做的是通过直接修改实例来修改每个实例的行为.hello你在原型上的版本是一种故障安全和后备.

编辑:你的问题的答案:

基于每个实例的覆盖意味着您将属性或函数附加到特定实例.例如,您可以这样做:

i.goodbye = function() {
    return "Goodbye, cruel world!";
};
Run Code Online (Sandbox Code Playgroud)

这意味着此行为特定于该特定实例(即,仅针对i您可能已创建的任何其他实例).

如果你拿出来this,那你基本上有:

hello = function() {
    return "hello, " + someValue;
}
Run Code Online (Sandbox Code Playgroud)

这等同于:

window.hello = function() {
    return "hello, " + someValue;
}
Run Code Online (Sandbox Code Playgroud)

所以在这种情况下,hello是对该函数的全局引用.这意味着hello没有附加到任何对象.

hello如果您没有this.hello = function() { .... };构造函数内部,则可以是未定义的.我还谈到了JavaScript用来尝试解析对象属性的一般过程.正如我之前提到的,它涉及走向原型链.