Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript od”)调用—在同一实例上使用相同参数调用相同的方法—实现了这一点?可怕的变戏法和诡计_Javascript - Fatal编程技术网

Javascript od”)调用—在同一实例上使用相同参数调用相同的方法—实现了这一点?可怕的变戏法和诡计

Javascript od”)调用—在同一实例上使用相同参数调用相同的方法—实现了这一点?可怕的变戏法和诡计,javascript,Javascript,我们看到this.uber总是调用C.inherits(B)创建的方法。B.prototype.uber是不相关的。所有调用都将使用相同的d对象(由闭包引用),它存储每个方法名称的递归深度。p是C.prototype,而v是B.prototype 第一个调用来自实例方法(在构造函数中创建)。d.exampleMethod仍然是0(或者只是初始化为它,因为它以前不存在),我们转到else分支选择下一个要调用的方法。这里它检查p[name]==this[name],即C.prototype.exam

我们看到
this.uber
总是调用
C.inherits(B)
创建的方法。
B.prototype.uber
是不相关的。所有调用都将使用相同的
d
对象(由闭包引用),它存储每个方法名称的递归深度。
p
C.prototype
,而
v
B.prototype

第一个调用来自实例方法(在构造函数中创建)。
d.exampleMethod
仍然是0(或者只是初始化为它,因为它以前不存在),我们转到
else
分支选择下一个要调用的方法。这里它检查
p[name]==this[name]
,即
C.prototype.exampleMethod==x.exampleMethod
,当实例(
this
/
x
)有自己的(实例)方法时,这是错误的。因此它从
p
,而不是从
v
中选择方法来调用下一步。它增加递归计数并在实例上调用它

第二个调用来自
C.prototype
方法。如果这是第一个调用(在只有prototype方法时通常如此),
d.exampleMethod
将是
0
。我们再次转到
else
分支,但是当没有实例方法时,我们将使比较求值为true并选择
v[name]
调用,即我们继承的父方法。它将增加递归计数并调用所选方法

第三个调用将来自
B.prototype
方法,而
d.exampleMethod
将是
1
。这实际上已经在第二个调用中发生了,因为Crockford忘记了在这里说明实例方法。无论如何,它现在转到
if
分支,并从
v
向上进入原型链,ass如果
.constructor
属性在任何地方都已正确设置(
继承了它)。它会对存储的次数执行此操作,然后选择要从相应对象调用的下一个方法-
A.prototype。在本例中,exampleMethod

计数必须按methodname进行,因为可以尝试从任何调用的超级方法调用不同的方法


至少这一定是个想法,因为很明显,如果有实例方法,计数是完全不可能的。或者当原型链中的对象不拥有相应的方法时,也可能是Crockford试图处理但失败的情况。

这太过时了(从ES5开始,您将使用
Object.create
而不是
new parent()
——我们使用的是ES2017/ES8)虽然你的好奇心是可以理解的,但对我个人来说,这个实现看起来完全是垃圾,而且由于ES6
class
语法以及Babel等用于向后兼容的Transpiler的广泛使用,它已经过时了。一旦你理解了这段代码,请在ternet帮个忙,不要试图重复使用它。@Ryan和Patrick Roberts:我只是想理解它,这样我就可以理解我正在读的JS书中的其他一些例子。@kittu:如果你的JS书谈论的是这个函数的实现细节,它可能已经过时了。如果你只需要知道它的功能,那就是继承(在定义构造函数
Derived
之后,您可以
Derived.inherits(Base)
使
Derived
实例具有
Base
原型)以及在父类上调用“overrided”方法的方法(ES6和其他语言中的
super.foo(x)
将编写为
this.uber('foo',x)
)。@Ryan我不理解检查
d[name]
的过程,就像
if(t){
它是超级过时的(从ES5开始,您将使用
对象。创建
而不是
新父对象()
——我们使用的是ES2017/ES8)虽然你的好奇心是可以理解的,但对我个人来说,这个实现看起来完全是垃圾,而且由于ES6
class
语法以及Babel等用于向后兼容的Transpiler的广泛使用,它已经过时了。一旦你理解了这段代码,请在ternet帮个忙,不要试图重复使用它。@Ryan和Patrick Roberts:我只是想理解它,这样我就可以理解我正在读的JS书中的其他一些例子。@kittu:如果你的JS书谈论的是这个函数的实现细节,它可能已经过时了。如果你只需要知道它的功能,那就是继承(在定义构造函数
Derived
之后,您可以
Derived.inherits(Base)
使
Derived
实例具有
Base
原型)以及在父类上调用“overrided”方法的方法(ES6和其他语言中的
super.foo(x)
将编写为
this.uber('foo',x)
)。@Ryan我不懂检查
d[name]
,就像
if(t){
Wow一样,我们甚至可以让它通过
uber
(从示例中删除
x
C.prototype
方法)。至少它不会因为计数而溢出堆栈。如果您想知道超级调用是如何正确完成的,请参阅对
此的赋值支持。exampleMethod
在一个原型中定义了
exampleMethod
,这就是它的目的…我们非常感谢您的牺牲。哇,我们甚至可以让它进行方法调用通过
uber
(从示例中删除
x
C.prototype
方法)。至少它不会由于计数而溢出堆栈。如果您想知道超级调用是如何正确完成的,请参阅该支持
Function.method('inherits', function(parent){
    this.prototype = new parent();
    var d = {},
    p = this.prototype;
    this.prototype.constructor = parent;
    this.method('uber', function uber(name){   //LINE 1
        if(!(name in d)){
            d[name] = 0;
        }

        var f, r, t = d[name], v = parent.prototype;
        if(t){
            while(t){
                v = v.constructor.prototype;
                t -= 1;
            }
            f = v[name];
        } else {
            f = p[name];
            if(f == this[name]){
                f = v[name];
            }
        }
        d[name] +=1;
        r = f.apply(this, Array.prototype.slice.apply(arguments, [1]));
        d[name] -= 1;
        return r;
    });
    return this;
});
// He extended the "prototype" of the Function object to have some syntactic sugar
// for extending prototypes with new methods (a method called 'method').

// This line extends the prototype of the Function object by a method called 'inherits' using the syntactic sugar method mentioned above.
Function.method('inherits', function(parent){
    /** 'this' is a reference to the Function the 'inherits' method is called 
     * on, for example lets asume you defined a function called 'Apple'
     * and call the method 'inherits' on it, 'this' would be a reference of 'Apple'-Function object.
    **/

    /**
     * Hes extending the prototype of the base function by the prototype of
     * the 'parent' function (the only argument the 'inherits' method takes),
     * by creating a new instance of it.
    **/
    this.prototype = new parent();
    // BAD VARIABLE NAMING!!!
    var d = {}, // variable to create a dictionary for faster lookup later on.
    p = this.prototype; // save the prototype of the base function into variable with a short name
    this.prototype.constructor = parent; // set the constructor of the base function to be the parent.


    /**
     * Extend the base function's prototype by a method called 'uber',
     * it will nearly the same function as the 'super' keyword in OO-languages,
     * but only to call methods of the parent class.
     **/
    this.method('uber', function uber(name){

        if(!(name in d)){
            // if the value name doesn't exist in the dictionary
            d[name] = 0; // set the key to the value of name and the value to 0
        }

        // BAD VARIABLE NAMING AGAIN!!!
        var f, r, t = d[name], v = parent.prototype;
        // f is used to store the method to call later on.
        // t is the value of the key inside the 'd' dictionary which indicates the depth to go up the prototype tree
        // v is the parent functions prototype
        // r is the result the method 'f' yields later on.

        // check if the attribute 'name' exists in the dicionary.
        // because if it doesn't exist t will be 0 which resolves to false.
        if(t){
            // the loop is used to walk the tree prototype tree until the implementation with the depth of t is found. 
            while(t){
                v = v.constructor.prototype;
                t -= 1;
            }
            f = v[name]; // set f to the method name of the t-th parent protoype 
        } else {
            // if the attibute 'name' doesn't exist inside the dictionary
            f = p[name]; // use the method 'name' of the base class prototype.
            if(f == this[name]){
                // if the method 'name' is a member of the base class 
                f = v[name]; // use the method 'name' of the parent prototype instead.
            }
        }

        // increment the corresponding dictionary value for the depth of the 'uber' call.
        d[name] +=1;
        // call the method saved to 'f' in context of the base class and apply the 'arguments' array to it and save the result to 'r'.
        r = f.apply(this, Array.prototype.slice.apply(arguments, [1]));
        // decrement the corresponding dictionary value for the depth of the 'uber' call.
        d[name] -= 1;
        // return the result
        return r;
    });
    return this;
});
function A() { }
A.prototype.exampleMethod = function() {
    console.log("top");
    return "result";
};
function B() { }
B.inherits(A);
B.prototype.exampleMethod = function() {
    console.log("parent");
    return this.uber("exampleMethod");
};
function C() {
    this.exampleMethod = function() {
        console.log("instance");
        return this.uber("exampleMethod");
    }
}
C.inherits(B);
C.prototype.exampleMethod = function() {
    console.log("prototype");
    return this.uber("exampleMethod");
};

var x = new C();
console.log(x.exampleMethod());