javascript - 关于经典继承(constructor stealing)有个疑问
迷茫
迷茫 2017-04-11 11:11:32
0
5
307

看别人的代码:

function SuperClass() {
    this.name = "women";
    this.bra = ["a", "b"];
}
function SubClass() {
    this.subname = "your sister";
    //将SuperClass的作用域赋予当前构造函数,实现继承
    SuperClass.call(this);
}

var sub1 = new SubClass();
sub1.bra.push("c");
console.log(sub1.bra);//["a","b","c"]
var sub2 = new SubClass();
console.log(sub2.bra);//["a","b"]

他的解释如下:
SuperClass.call(this);这一句话的意思是在SubClass的实例(上下文)环境中调用了SuperClass构造函数的初始化工作,这样每一个实例就会有自己的一份bra属性的副本了,互不产生影响了。

我有疑问的地方是:

  1. 为什么用 call 了就能每个实例都有一个副本?我查了一下 call 的作用也只是改变了 this 或者以其他对象身份运行某些方法,但是没有提到这样能够创建副本

谢谢

迷茫
迷茫

业精于勤,荒于嬉;行成于思,毁于随。

全員に返信(5)
伊谢尔伦

来看看创造实例的时候发生了什么。

//首先SubClass()的this指向sub1实例(中间还有个新创造的空{},先不管这个过程)。
var sub1 = new SubClass();
//开始执行下面的函数
//内部相当于sub1.subname = "your sister",SuperClass.call(sub1);
function SubClass() {
    this.subname = "your sister";
    SuperClass.call(this);
}
//然后因为用call调用了SuperClass,执行SuperClass函数
//因为将SubClass环境中的this传了进去,就相当于sub1.bra = ["a","b"]
function SuperClass() {
    this.name = "women";
    this.bra = ["a", "b"];
}

对于sub2的创造是一样的。
中间相当于sub2.bra=["a","b"]
而不是之前的
sub1.bra指向 XXX.prototype.bra
sub2.bra也指向 XXX.prototype.bra
现在都是各自本身的属性,修改就不会相互影响了。

いいねを押す +0
迷茫

首先你要知道构造函数过程中发生了什么,简单的说分四步
1.创建一个新对象
2.将构造函数的作用域赋给新对象(也就是this指向了新对象)
3.执行构造函数中的代码
4.返回新对象
所以 new SubClass()的过程为
1.生成一个新对象//先假设为obj
2.this指向了obj
3.执行代码

this.subname = "your sister";//等价为obj.subname="your sisiter"
SuperClass.call(this);//由于此时的this指向obj,所以执行superClass.call(obj)里面的代码等价为
                        obj.name = "women";
                        obj.bra = ["a", "b"];   

4.返回新对象obj

いいねを押す +0
洪涛
function SuperClass() {
    //此时this指向当前函数SuperClass
    this.name = "women";
    this.bra = ["a", "b"];
}
function SubClass() {
    this.subname = "your sister";
    SuperClass.call(this);
    //将this指向修改到指向superClass
}

var sub1 = new SubClass();①
//通过构造函数创建一个实例,此时会创建一个对象
sub1.bra.push("c");
console.log(sub1.bra);//["a","b","c"]
var sub2 = new SubClass();
console.log(sub2.bra);//["a","b"]

//sub1和sub2两个对象,两个数组

var obj  ={};
//声明一个空对象obj
obj.__proto__ = SubClass.prototype;
//将obj的__proto__属性赋值为构造函数(SubClass)的prototype属性
SubClass.call(obj);
//将构造函数的this指向赋给obj
return obj;
//返回这个对象
いいねを押す +0
伊谢尔伦

构造函数你new一个实例对象,其实就是复制了一次构造函数,同时实例根据设置的访问等级可以访问其内部的属性和方法,该对象是一个空对象,它的原型指向构造函数的prototype属性,而并不是构造函数本身,所以你对新生成的实例对象的修改是并不能影响到它的构造函数的内容,只能修改其实例自身。

いいねを押す +0
洪涛

谢谢大家,大家都说得对,不过只能采纳一个答案,我就采纳第一个回答的吧

另外我总结了一下:

  1. call直接使用超类的构造函数,将超类的构造函数生成的属性和方法放到子类,并且传入了当前的 this来运行,那么就相当于以子类的身份执行超类的构造函数,那么自然超类的构造函数的属性和方法会继承到子类里

  2. 因为每次 new 子类的时候,都会生成独立的子类实例对象,所以相互独立

(错误)3.因为每次 new 子类的时候,都会调用超类的构造函数,所以基于超类的构造函数在这一程度上是共享的关系,所有又能实现复用

感谢toBeTheLight纠正错误。经典继承的缺点是
1.没有复用性。因为超类的属性和方法是加载了子类实例的自身上,这个不叫复用,他们各自的属性和方法都是独立的内存空间,并没有实现复用。
2.定义在父类原型中的方法和属性,子类(实例)不可见。因为复用的东西我们一般加在超类的原型prototype上,但是调用超类的时候,没有通过new调用,所以就没有实例.__proto__指向超类.prototype这一步,所以子类(实例)就看不到超类上本来要做复用的方法和属性。

再次谢谢.

いいねを押す +0
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!