Qwe*_*tiy 93 javascript inheritance function ecmascript-6 javascript-inheritance
ES6允许扩展特殊对象.所以可以从函数继承.这样的对象可以作为函数调用,但是如何实现这种调用的逻辑呢?
class Smth extends Function {
constructor (x) {
// What should be done here
super();
}
}
(new Smth(256))() // to get 256 at this call?
Run Code Online (Sandbox Code Playgroud)
类的任何方法都可以通过引用类实例this.但是当它被称为函数时,this指的是window.当作为函数调用时,如何获取对类实例的引用?
PS:俄语同样的问题.
Ber*_*rgi 44
该super调用将调用Function构造函数,该构造函数需要代码字符串.如果要访问实例数据,可以对其进行硬编码:
class Smth extends Function {
constructor(x) {
super("return "+JSON.stringify(x)+";");
}
}
Run Code Online (Sandbox Code Playgroud)
但这并不令人满意.我们想要使用一个闭包.
让返回的函数成为可以访问实例变量的闭包是可能的,但并不容易.好处是super如果你不想要你就不必调用- 你仍然可以使用returnES6类构造函数中的任意对象.在这种情况下,我们会这样做
class Smth extends Function {
constructor(x) {
// refer to `smth` instead of `this`
function smth() { return x; };
Object.setPrototypeOf(smth, Smth.prototype);
return smth;
}
}
Run Code Online (Sandbox Code Playgroud)
但是我们可以做得更好,并从中抽象出来Smth:
class ExtensibleFunction extends Function {
constructor(f) {
return Object.setPrototypeOf(f, new.target.prototype);
}
}
class Smth extends ExtensibleFunction {
constructor(x) {
super(function() { return x; }); // closure
// console.log(this); // function() { return x; }
// console.log(this.prototype); // {constructor: …}
}
}
class Anth extends ExtensibleFunction {
constructor(x) {
super(() => { return this.x; }); // arrow function, no prototype object created
this.x = x;
}
}
class Evth extends ExtensibleFunction {
constructor(x) {
super(function f() { return f.x; }); // named function
this.x = x;
}
}
Run Code Online (Sandbox Code Playgroud)
不可否认,这在继承链中创建了一个额外的间接层,但这不一定是坏事(你可以扩展它而不是本机Function).如果你想避免它,请使用
function ExtensibleFunction(f) {
return Object.setPrototypeOf(f, new.target.prototype);
}
ExtensibleFunction.prototype = Function.prototype;
Run Code Online (Sandbox Code Playgroud)
但请注意,它Smth不会动态继承静态Function属性.
Adr*_*ien 27
这是我创建可调用对象的方法,这些对象正确引用其对象成员,并保持正确的继承,而不会弄乱原型.
class ExFunc extends Function {
constructor() {
super('...args', 'return this.__self__.__call__(...args)')
var self = this.bind(this)
this.__self__ = self
return self
}
// Example `__call__` method.
__call__(a, b, c) {
return [a, b, c];
}
}
Run Code Online (Sandbox Code Playgroud)
扩展此类并添加一个__call__方法,更多信息......
// This is an approach to creating callable objects
// that correctly reference their own object and object members,
// without messing with prototypes.
// A Class that extends Function so we can create
// objects that also behave like functions, i.e. callable objects.
class ExFunc extends Function {
constructor() {
super('...args', 'return this.__self__.__call__(...args)');
// Here we create a function dynamically using `super`, which calls
// the `Function` constructor which we are inheriting from. Our aim is to create
// a `Function` object that, when called, will pass the call along to an internal
// method `__call__`, to appear as though the object is callable. Our problem is
// that the code inside our function can't find the `__call__` method, because it
// has no reference to itself, the `this` object we just created.
// The `this` reference inside a function is called its context. We need to give
// our new `Function` object a `this` context of itself, so that it can access
// the `__call__` method and any other properties/methods attached to it.
// We can do this with `bind`:
var self = this.bind(this);
// We've wrapped our function object `this` in a bound function object, that
// provides a fixed context to the function, in this case itself.
this.__self__ = self;
// Now we have a new wrinkle, our function has a context of our `this` object but
// we are going to return the bound function from our constructor instead of the
// original `this`, so that it is callable. But the bound function is a wrapper
// around our original `this`, so anything we add to it won't be seen by the
// code running inside our function. An easy fix is to add a reference to the
// new `this` stored in `self` to the old `this` as `__self__`. Now our functions
// context can find the bound version of itself by following `this.__self__`.
self.person = 'Hank'
return self;
}
// An example property to demonstrate member access.
get venture() {
return this.person;
}
// Override this method in subclasses of ExFunc to take whatever arguments
// you want and perform whatever logic you like. It will be called whenever
// you use the obj as a function.
__call__(a, b, c) {
return [this.venture, a, b, c];
}
}
// A subclass of ExFunc with an overridden __call__ method.
class DaFunc extends ExFunc {
constructor() {
super()
this.a = 'a1'
this.b = 'b2'
this.person = 'Dean'
}
ab() {
return this.a + this.b
}
__call__(ans) {
return [this.ab(), this.venture, ans];
}
}
// Create objects from ExFunc and its subclass.
var callable1 = new ExFunc();
var callable2 = new DaFunc();
// Inheritance is correctly maintained.
console.log('\nInheritance maintained:');
console.log(callable2 instanceof Function); // true
console.log(callable2 instanceof ExFunc); // true
console.log(callable2 instanceof DaFunc); // true
// Test ExFunc and its subclass objects by calling them like functions.
console.log('\nCallable objects:');
console.log( callable1(1, 2, 3) ); // [ 'Hank', 1, 2, 3 ]
console.log( callable2(42) ); // [ 'a1b2', Dean', 42 ]
// Test property and method access
console.log(callable2.a, callable2.b, callable2.ab())Run Code Online (Sandbox Code Playgroud)
bind:function.bind()工作很像function.call(),他们共享一个类似的方法签名:
fn.call(this, arg1, arg2, arg3, ...);更多关于mdn
fn.bind(this, arg1, arg2, arg3, ...);更多关于mdn
在第一个参数中重新定义this函数内的上下文.其他参数也可以绑定到值.但是,在call立即使用绑定值调用函数的情况下,bind返回一个"异国情调"的函数对象,该对象透明地包装原始函数,this并预设任何参数.
所以当你定义一个函数时bind,它的一些参数:
var foo = function(a, b) {
console.log(this);
return a * b;
}
foo = foo.bind(['hello'], 2);
Run Code Online (Sandbox Code Playgroud)
只使用其余参数调用绑定函数,其上下文是预设的,在本例中为['hello'].
// We pass in arg `b` only because arg `a` is already set.
foo(2); // returns 4, logs `['hello']`
Run Code Online (Sandbox Code Playgroud)
Ori*_*iol 20
您可以使用(也许)陷阱将Smth实例包装在Proxy中:applyconstruct
class Smth extends Function {
constructor (x) {
super();
return new Proxy(this, {
apply: function(target, thisArg, argumentsList) {
return x;
}
});
}
}
new Smth(256)(); // 256
Run Code Online (Sandbox Code Playgroud)
不幸的是,这不太有效,因为它现在返回一个函数对象而不是一个类,所以看起来这实际上无法在不修改原型的情况下完成。瘸。
基本上问题是无法设置构造函数this的值Function。真正做到这一点的唯一方法是事后使用该.bind方法,但这不是非常类友好的。
我们可以在辅助基类中执行此操作,但是this直到初始调用之后才可用super,因此这有点棘手。
'use strict';
class ClassFunction extends function() {
const func = Function.apply(null, arguments);
let bound;
return function() {
if (!bound) {
bound = arguments[0];
return;
}
return func.apply(bound, arguments);
}
} {
constructor(...args) {
(super(...args))(this);
}
}
class Smth extends ClassFunction {
constructor(x) {
super('return this.x');
this.x = x;
}
}
console.log((new Smth(90))());Run Code Online (Sandbox Code Playgroud)
(示例需要现代浏览器或node --harmony。)
基本上,基本函数ClassFunctionextends 将Function使用自定义函数包装构造函数调用,该自定义函数类似于.bind,但允许稍后在第一次调用时进行绑定。然后在ClassFunction构造函数本身中,它调用返回的函数,super该函数现在是绑定函数,传递this以完成设置自定义绑定函数。
(super(...))(this);
Run Code Online (Sandbox Code Playgroud)
这一切都相当复杂,但它确实避免了原型的变异,出于优化原因,原型被认为是不好的形式,并且可以在浏览器控制台中生成警告。
| 归档时间: |
|
| 查看次数: |
21480 次 |
| 最近记录: |