JavaScript 对象可以有原型链,也可以是函数吗?

IT技术 javascript inheritance
2021-02-14 18:23:06
function a () {
    return "foo";
}

a.b = function () {
    return "bar";
}

function c () { };
c.prototype = a;

var d = new c();
d.b(); // returns "bar"
d(); // throws exception, d is not a function

有什么方法d可以成为一个函数,但仍然从 继承属性a

6个回答

实际上,事实证明这是可能的,尽管是以一种非标准的方式。

Mozilla、Webkit、Blink/V8、Rhino 和 ActionScript 提供了一个非标准__proto__属性,允许在创建对象后更改其原型。在这些平台上,以下代码是可能的:

function a () {
    return "foo";
}

a.b = function () {
    return "bar";
}

function c () {
    return "hatstand";
}
c.__proto__ = a;

c(); // returns "hatstand"
c.b(); // returns "bar"; inherited from a

这可能对任何不需要担心跨平台兼容性的人有用。

但是请注意,只有对象属性才能被继承。例如:

var d = {};
d.__proto__ = a;
d.b(); // returns "bar"
d(); // throws exception -- the fact that d is inheriting from a function
     // doesn't make d itself a function.

简短的回答:不可能。

这行代码:

var d = new c();

自动假定它d是一个对象。除非c是内置对象的构造函数,例如,Function但是如果c已经被语言定义了,你就不能操纵它的原型,也不能从你喜欢的任何东西“继承”它。好吧,在某些解释器中你可以,但你不能在所有解释器中安全地做到这一点——标准说:“你不要弄乱标准对象,否则解释器会打击你!”。

内置对象是“唯一的”,JavaScript 不提供复制它们的方法。如果不使用不兼容的技巧,就不可能重新创建字符串、数字、函数等。

@Codyfunction $http() { /* code */ }; $http.post = function() { /* code */ }问题是post函数是直接在$http函数对象上定义的,而不是来自原型链,这就是这个问题的意思。
2021-05-05 18:23:06
@Darth Android,你绝对是对的!我会纠正投票。对于那个很抱歉。顺便说一下,我想我有一个解决方法——如果有兴趣,请查看我的编辑。
2021-05-07 18:23:06
投票否决。这个有可能!AngularJS 有一个名为$http. 用法可以是:$http({})$http.post()这是可能的,但是如何???
2021-05-10 18:23:06

基于关于类似问题的元讨论, 我将根据@alexander-mills原件在此处发布此答案


这现在可以以符合标准的方式完成

首先创建一个继承的对象 Function

const obj = Object.create(Function.prototype);  // Ensures availability of call, apply ext

然后将自定义方法和属性添加到 obj

接下来声明函数

const f = function(){
    // Hello, World!
};

并设置obj为原型f

Object.setPrototypeOf(f,obj);

示范

const obj = Object.create(Function.prototype);

// Define an 'answer' method on 'obj'
obj.answer = function() {
  // Call this object
  this.call(); // Logs 'Hello, World'
  console.log('The ultimate answer is 42');
}

const f = function() {
  // Standard example
  console.log('Hello, World');
};

Object.setPrototypeOf(f, obj);

// 'f' is now an object with an 'answer' method
f.answer();
// But is still a callable function
f();

是的,如果您使用__proto__Daniel Cassidy 提到财产,这是可能的诀窍是c实际返回一个已a附加到其原型链的函数

function a () {
    return "foo";
}

a.b = function () {
    return "bar";
}

function c () {
    var func = function() {
        return "I am a function";
    };
    func.__proto__ = a;
    return func;
}
c.prototype = a;

var d = new c();
d.b(); // returns "bar"
d(); // returns "I am a function"

但是,如果您想instanceof返回更好的结果,则需要原型链进行更多调整

d instanceof c // true
d instanceof a // false
c instanceof a // false

它真的必须是一个原型链吗?您可以使用 mixin 模式使函数具有 a 的所有属性。如果你真的想要,你甚至可以用一个很好的“新”语法包装它来伪造它。

function a () {
    return "foo";
}

a.b = function () {
    return "bar";
}

function c () {
    var f = function(){
        return a();
    };

    //mixin all properties on a
    for(var prop in a){
        f[prop] = a[prop];
    }

    return f; //just returns the function instead of "this"
};

var d = new c(); //doesn't need the new keyword, but just for fun it still works

alert(d()); //show "foo"

alert(d.b()); //shows "bar"

您可以在不影响 a 的情况下向 d 添加属性。这与您想要的唯一区别是对 a 的更改不会影响 c 的现有“实例”。

是的,我求助于使用 mixin。在我的情况下,a 被修改的可能性很小,并且更改应该反映在 d 中,但在实践中不太可能是大问题。
2021-05-01 18:23:06