JavaScript是修改函数原型的更好方法

JavaScript是修改函数原型的更好方法,javascript,constructor,prototype,Javascript,Constructor,Prototype,我希望创建一个构造函数的构造函数。 关于此线程:,似乎唯一的解决方案是: Function.prototype.add = function(name, value) { this.prototype[name] = value; }; Function.prototype.remove = function(name) { delete this.prototype[name]; }; 但是我不想修改通用的函数原型。。。而且: var A = new ConstBuilder

我希望创建一个构造函数的构造函数。 关于此线程:,似乎唯一的解决方案是:

Function.prototype.add = function(name, value) {
    this.prototype[name] = value;
};
Function.prototype.remove = function(name) {
    delete this.prototype[name];
};
但是我不想修改通用的
函数
原型。。。而且:

var A = new ConstBuilder().add('test', function() {
    console.log('test');
}).getConstructor();
但是我不想在构造函数本身周围有一个对象包装器

问题是,通常构造函数创建新对象,从构造函数原型继承方法。我试图做的是实例化函数而不是对象,但修改函数原型属性的唯一方法是修改其
\uuuuuu proto\uuuuu
属性:

var constructorPrototype = {
    add : function(name, value) {
        this.prototype[name] = value ;
    }
} ;

var ConstBuilder = function() {
    var constructor = function() {} ;
    constructor.prototype = {} ;
    // The only way (?), but quite deprecated...
    constructor.__proto__ = constructorPrototype ;
    return constructor ;
} ;

// Not working way...
//ConstBuilder.prototype = constructorPrototype ;

var A = new ConstBuilder() ;
A.add('test', function() {
    console.log('test') ;
}) ;

var a = new A() ;
a.test() ; // "test"

constructorPrototype.remove : function() {
    delete this.prototype[name] ;
} ;

A.remove('test') ;

a.test() ; // Error: test is not a function.
注意
A.prototype
不是
A.\uuuu proto\uuuu
而是
A.prototype
(新的A)。\uu proto\uuu

通过修改
\uuuu proto\uuuu
,它可以完美地工作,真是太遗憾了。 我读到Firefox集成了一个“Object.setPrototypeOf()”,但它只是实验性的


这是我想做的另一种方式吗?

的确如此。要执行您希望执行的操作,唯一的方法是对要返回的函数的
\uuuu proto\uuu
属性进行变异。然而,这并不是一件坏事。事实上,ES6 Harmony将把它作为功能标准化

但是,我建议您不要对对象的
[[Prototype]]
进行变异,因为这会使您的程序非常慢。有一种更快的替代方案:

不要使用原型 传统上,原型用于定义对特定类型对象进行操作的函数。这些专门处理某个参数的函数称为方法

例如,
obj.func(a,b,c)
专门处理
obj
obj
的实例。另一方面,
func(obj,a,b,c)
不专门处理任何参数(即,
obj
可以是任何值)

按照此示例,您可以按如下方式重写
添加
删除

function add(func, name, value) {
    func.prototype[name] = value;
}

function remove(func, name) {
    delete func.prototype[name];
}
现在,您可以在任何需要的函数上使用
add
remove
。你根本不必担心继承问题

唯一的问题是名称空间冲突。假设您已经有一个名为
add
的函数:您要做什么?答案很简单。您可以创建一个新的命名空间:

Function.add = function (func, name, value) {
    func.prototype[name] = value;
};

Function.remove = function remove(func, name) {
    delete func.prototype[name];
};
事实上,这正是本机JavaScript API通常所做的。例如:

function Shape(constructor) {
    this.constructor = constructor;
}

function Circle(x, y, r) {
    this.x = x;
    this.y = y;
    this.r = r;
}

function Rectangle(x1, y1, x2, y2) {
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
}

Circle.prototype = new Shape(Circle);
Rectangle.prototype = new Shape(Rectangle);
  • 对象。创建
  • Object.getPrototypeOf
  • Object.setPrototypeOf
  • 诸如此类

    要点是:泛化总是比专门化好。我们使用原型来专门化。我们用正规函数来推广。泛化比专业化有很多优势:

  • 您不需要像
    call
    apply
    这样的方法来“非专用化”专用函数
  • 您不必担心继承和原型链
  • 您的代码更清晰,更容易理解
  • 这就是为什么我总是喜欢泛化而不是专门化。我使用原型的唯一原因是创建联合类型。例如:

    function Shape(constructor) {
        this.constructor = constructor;
    }
    
    function Circle(x, y, r) {
        this.x = x;
        this.y = y;
        this.r = r;
    }
    
    function Rectangle(x1, y1, x2, y2) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
    }
    
    Circle.prototype = new Shape(Circle);
    Rectangle.prototype = new Shape(Rectangle);
    
    我没有将方法添加到
    Circle.prototype
    Rectangle.prototype
    中,而是执行以下操作:

    Circle.area = function (circle) {
      return Math.PI * circle.r * circle.r;
    };
    
    Rectangle.area = function (rectangle) {
      return Math.abs((rectangle.x2 - rectangle.x1) * (rectangle.y2 - rectangle.y1));
    };
    
    Shape.prototype.area = function () {
      return this.constructor.area(this);
    };
    

    现在您可以使用
    Circle.area(notCircleInstance)
    代替
    Circle.prototype.area.call(notCircleInstance)
    。这是一个双赢的局面。泛化总是比专门化好。

    a.constructor.prototype==a.\u proto\u,除非你断开链接。这有助于跨浏览器实现吗?我修改的不是
    a.\u proto
    ,而是
    a.\u proto\u
    ,它是一个函数,不是
    ConstBuilder
    的实例,as
    ConstBuilder
    直接返回它,而不是返回它的新实例;我说得很宽泛。所以,X.constructor.prototype==X.uu proto_u我试过
    constructor.constructor.prototype=constructorPrototype但它也不起作用:\非常感谢,这正是我想要的答案。我知道变异
    \uuuuuuuuuuuuuuuuu
    很慢,但我不知道为什么。你能告诉我为什么这么慢吗?我不想推广这些方法(
    add
    remove
    ),因为我正在创建一个模块化框架,可以添加其他函数来修改新的构造函数,我认为自由修改
    函数
    原型不是一个好主意。我给出了这两个函数,但实际上构造函数使用了将近十个其他函数,如果对它们进行概括将是一件麻烦的事情,因为它们不必“适用于”每个函数。下面继续: