JavaScript中继承机制的实现

        处于安全的考虑,本地类和宿主类不能作为基类。JavaScript中的继承是通过模仿实现的。


        对象冒充:构造函数方法使用this关键为对象添加属性和方法,并且赋值。但构造函数A只是

一个方法,是一个对象,因此可以将A赋值给其他对象B的方法。那么B对象将成为A中的this指向

的对象,那么B就可以获得A构造函数中的方法和属性

<script type="text/javascript">

	function PersonA(name) {
		//如果是用new关键字生成PersonA对象,那么this指向new生成的当前对象
		//如果将PersonA函数对象赋值给对象B的方法属性,那么this指向B对象,
		//即this关键字指向PersonA方法所属的对象
		this.name = name;
		this.sayName = function() { alert(this.name); }
	}

	function PersonB(name, age) {
		//当前对象的method属性引用PersonA方法
		this.method = PersonA; 

		//当前对象调用method方法。由于PersonA中的this指向当前对象,那么PersonA中语句就为
		//当前对象添加了name属性和sayName方法,并且初始化
		this.method(name); 

		//删除当前对象的method属性,因为该属性再也没有用处了。
		delete this.method;

		//为当前对象添加属性和方法
		this.age = age;
		this.sayAge = function() { alert(this.age); }
	}

	var obj1 = new PersonA("Koji");
	var obj2 = new PersonB("Luo", 22);
	obj1.sayName();  //Koji
	obj2.sayName();  //Luo   当前对象也有了name属性和sayName方法
	obj2.sayAge();   //22

</script>
        这只是表面实现了继承的能力,子类获得父类的属性和方法。在JavaScript中, 当将PersonA

方法赋值给PersonB的this的method属性时,PersonA中this指向PersonB中的this引用的对象。而当

通过new生成PersonB的对象时,PersonB中的this指向new关键字生成的对象。此时,PersonA中的

this和PersonB中的this都指向了通过new关键字生成的PersonB 的当前对象,那么可以通过PersonA

中的this和PersonB中的this为当前对象添加属性和方法


        对象冒充可以实现多继承。可以通过重复上面的获得构造函数方法并且调用该方法实现。但如

子类拥有相同的属性或方法,那么前面的构造方法为当前对象的属性赋的值会被后面的构造方法

为相同属性赋予的值替换掉,因为父类子类中的this都指向当前对象,属性的取值取决于最后为该

属性赋值的语句


        call()方法

<script type="text/javascript">

	function PersonA(name) {
		this.name = name;
		this.sayName = function() { alert(this.name); }
	}

	function PersonB(name, age) {
		//call方法的第一个参数是赋值给PersonA中的this的,后面的参数依次赋值给PersonA方法的
		//参数列表中对应的参数。那么传入当前对象this使得PersonA中的this引用当前对象。所以
		//PersonA中的语句可以为当前对象添加属性和方法。因此PersonB继承了PersonA的属性和方法
		PersonA.call(this, name);

		//为当前对象添加属性和方法
		this.age = age;
		this.sayAge = function() { alert(this.age); }
	}

	var obj1 = new PersonA("Koji");
	var obj2 = new PersonB("Luo", 22);
	obj1.sayName();  //Koji
	obj2.sayName();  //Luo   当前对象也有了name属性
	obj2.sayAge();   //22

</script>
        上面的call方法的第一个参数this使得PersonA中的this获得当前对象的引用。这样一来,

PersonA中的this和PersonB中的this又都指向了new生成的PersonB的当前对象。


        上面实现继承的实质是让“父类”构造函数和“子类”构造函数中的this关键字都引用子类的当前对

象(同一个对象),这样就可以通过“父类”的this和“子类”的this对当前对象添加属性和方法


        原型链(prototype chain)

<script type="text/javascript">

	function PersonA() {} //构造函数没有任何参数,这是使用原型链的标准模式

	PersonA.prototype.name = "Koji";
	PersonA.prototype.sayName = function() { alert(this.name); }

	function PersonB() {}

	//将PersonB对象的prototype属性设置为一个PersonA的对象,而PersonA对象本身拥有其
	//原型的属性和方法,那么PersonB的prototype便拥有了PersonA的属性和方法
	PersonB.prototype = new PersonA();

	//子类的属性和方法的添加必须在为PersonB的prototype改变值之后进行。如果在之前进行,
	//当PersonB的prototype引用别的对象时,先前设置的属性和方法都丢失了。
	PersonB.prototype.age = 22;
	PersonB.prototype.sayAge = function() { alert(this.age); }

	var obj1 = new PersonA();
	var obj2 = new PersonB();

	obj1.sayName();  //Koji
	obj2.sayName();  //Koji   当前对象也有了name属性
	obj2.sayAge();   //22

	alert(obj1 instanceof PersonA); //true
	alert(obj1 instanceof PersonB); //false
	alert(obj2 instanceof PersonA); //true
	alert(obj2 instanceof PersonB); //true

</script>
        原型链的缺点是不支持多继承,因为一个对象的prototype不能指向多个对象。同时使用原型链就

无法使用带参构造函数。原型链的关键是使子类构造函数的prototype属性引用父类的一个对象。


        混合方式:使用对象冒充继承构造函数的属性,用原型链继承prototype对象的方法

<script type="text/javascript">

	function PersonA(name) { //构造函数定义属性
		this.name = name;
	}

	//原型定义方法
	PersonA.prototype.sayName = function() { alert(this.name); }

	function PersonB(name, age) {
		//对象冒充继承属性,该属性是添加到当前对象中
		PersonA.call(this, name);

		this.age = age; //通过子类构造函数添加属性
	}

	//原型链继承父类方法,因为PersonA构造函数没有传参,实际上PersonB构造函数的prototype中
	//添加了name属性,只是没有赋值,其值为undefined
	PersonB.prototype = new PersonA();
	
	//通过子类的原型添加方法
	PersonB.prototype.sayAge = function() { alert(this.age); }

	var obj1 = new PersonA("Koji");
	var obj2 = new PersonB("Luo", 22);

	obj1.sayName();  //Koji
	obj2.sayName();  //Luo
	obj2.sayAge();   //22

	//下面的alert代码能够得到执行,证明PersonB的prototype对象中确实有name属性。
	for (var ele in PersonB.prototype) {
		if (ele == "name") {
			alert(true); 
		}
	}

</script>
        JavaScript依照原型链向上的方式搜索属性,即当访问当前对象的属性时,首先在当前对象中查询,

若找到,则返回属性值;若没有找到,则顺着原型链向上找。如果直到根对象的原型,即Object对

象的prototype中都没有找到该属性,则返回undefined。因为PersonB的构造函数即使没有传值,它

也会为当前对象添加一个name属性,设置默认值undefined。那么,当需要查看当前对象的name属

性时绝不会受到其构造函数prototype中的name属性的影响。因为按照原型链搜索方式,总是先找

到当前对象的name属性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值