基于实例的 JavaScript 继承

Instance based JavaScript Inheritance

本文关键字:继承 JavaScript 基于实例      更新时间:2023-09-26

我的问题与JavaScript继承有关,

var a = new Array();
var b = new Array();
a.prototype.max = function () {
 alert("Max");
}
b.max();

根据我的理解,b.max() 会给出错误说 b 没有最大值,但令人惊讶的是(对我来说)它在第 3 行 a 没有原型时给了我错误。 当我做类型a时,它给了我对象,对象可以具有原型属性。我阅读JavaScript遵循原型继承,即基于实例的继承,所以我的问题是我已经创建了一个Array实例,但原型属性仍然没有定义。

你能解释一下我哪里出错了,或者我没有正确理解什么概念吗

> var a = new Array();

a是 Array 对象的实例,默认情况下只有函数对象具有原型属性。所有对象都有一个隐藏的 [[Prototype]] 属性,您无法访问该属性(通过非标准 __proto__ 属性除外),并在构造它们时引用其构造函数的原型(或通过 __proto__ 进行修改)。

因此,在尝试解决时:

a.prototype.max 

然后

a.prototype

定义,因此尝试获取未定义的max 属性会引发引用错误。

b也是 Array 的一个实例,但它没有 max 属性。即使您这样做:

a.prototype = {max: function(){});

b仍然没有 max 属性,因为它继承自 Array.prototype ,而不是 a.prototype

附言。请参阅 ECMA-262 §15.3.2.1:"为每个函数自动创建一个原型属性,以提供将该函数用作构造函数的可能性。

prototype属于函数对象,而不是每个对象。

所以Array.prototype是对的,a.prototype错的。

它应该是这样的:

var a = new Array();
var b = new Array();
Array.prototype.max = function () {
 alert("Max");
}
b.max();

最好不要扩展像 Array 这样的东西,尤其是当你编写一个库或期望你的代码被许多其他程序重新使用时。

Object.prototype.somethingElse=22;
Array.prototype.something=22;
var arr=[1];
for(thing in arr){
  console.log(thing);//0, something,somethingElse
};

除了这个问题之外,您的代码还可以与具有冲突的 Array.prototype.max 实现的库一起使用。

从 Iframe 或 Frame 中,max 函数不存在,因为 (i) 帧中的数组与主页上的数组不同。

而是编写一个函数,您可以call数组或将数组作为额外的参数传递:

function max(){
  console.log(this);//<=[1,2]
  return Math.max.apply(Math,this);
};
var arr = [1,2];
max.call(arr);//=2

prototype 属性是在函数对象本身而不是实例上定义的。从技术上讲,您可以使用max函数更新Array.prototype,但是当前帧(过去和现在)中的所有数组都将具有"max"方法。 如果您希望与第三方JavaScript一起工作,那么修改本机类的原型是不受欢迎的。 如果要从本机Array类继承,可以使用下面列出的简单inherits函数并调用父类构造函数。 有关为什么这种继承方法优于其他方法的更详细说明,请查看这篇关于继承函数如何工作的文章

function inherits(childConstructor, parentConstructor){
    var TempConstructor = function(){};
    TempConstructor.prototype = parentConstructor.prototype; // Inherit parent prototype chain
    childConstructor.prototype = new TempConstructor(); // Create buffer object to prevent assignments directly to parent prototype reference.
    childConstructor.prototype.constructor = childConstructor; // Reset the constructor property back the the child constructor (currently set to TempConstructor )
};
var CustomArray = function(){
    // Normally the below line would suffice, but the native Array class is overloaded in that a cast (or call) returns a new array instance.
    //Array.apply(this, arguments);
    this.push.apply(this, arguments); // This will achive what we originally wanted from `Array.apply(this, arguments);`
}
inherits(CustomArray, Array);
CustomArray.prototype.max = function(){
    var length = this.length;
    if(!length){
        return;
    }
    var maxValue = this[0];
    for(var i = 1; i < length; ++i){
        var value = this[i];
        if(value > maxValue){
            maxValue = value;
        }
    }
    return maxValue;
}


var nativeArray0 = new Array();
var nativeArray1 = new Array(1, 3, 4, 9, 5, 0, 7, 11, 2);
var customArray0 = new CustomArray();
var customArray1 = new CustomArray('c', 'a', 'd', 'b', 'f', 'y', 'g', 'p');
alert('customArray0.max() = ' + customArray0.max());  // undefined
alert('customArray1.max() = ' + customArray1.max());  // y
alert('CustomArray.prototype.max.call(nativeArray1) = ' + CustomArray.prototype.max.call(nativeArray1)); // 11
alert('nativeArray0.length = ' + nativeArray0.length); // 0
alert('nativeArray1.length = ' + nativeArray1.length); // 9
alert('nativeArray1[3] = ' + nativeArray1[3]); // 9
alert('customArray0.length = ' + customArray0.length); // 0
alert('customArray1.length = ' + customArray1.length); // 8
alert('customArray1[3] = ' + customArray1[3]); // b