浅谈javascript中的继承

函数预编译的过程

函数预编译发生在函数执行之前
只有函数表达式才可以执行,函数声明并不可以执行。
预编译时函数会生成自己的执行上下文。每个执行上下文都是独一无二的,在函数执行完成时,销毁执行上下文。
预编译的过程可以分为以下4个步骤:

  1. 形成了自己的执行上下文,变量提升,这时执行上下文里存储所有作用域中的变量。
  2. 若有形参,找出所有形式参数,存到形成的执行上下文里中。若形参与变量名重复,则形参覆盖变量。
  3. 给形参赋值;
  4. 函数提升,若函数内部还声明了其它函数,则将函数存到执行上下文中;
Star.prototype = {};
   var Star = function() {};
   var star1 = new Star();

在javaScript 中我们通常并不会关心构造函数(Star)的原型指向谁(这里Star的原型应指向Function.prototype)。
javascript 中并没有真正的类,而我们所说的继承可以理解成委托。

当new的时候发生了什么

    var Star = function() {};
    var star1 = new Star();

new Star()时也会执行Star函数,所以会触发预编译过程。
Star函数在预编译时,在自己的函数作用域里声明了一个变量this,此时this的值为{}。
函数都具有返回值所以在构造函数内部会 return this

当在构造函数中访问原型上的属性a时,实际上是将a属性复制了一份,当你在构造函数中改变a属性的值时,原型上a属性的值并不会改变。

__proto__和constructor

所有的对象上都有_prop_属性。

  • 一般通过Object.getPrototypeOf(对象)来获取一个对象的_prop_.
  • 一般通过Object.prototype.isPrototypeOf(对象)判断当前对象是否在指定对象的原型链上。
  • 一般通过 对象 instanof 函数判断函数的原型是否在对象的原型链上。在有iframe时不建议使用这种方法,因为数组的指向会发生改变。
    举例:
//判断一个值是否为数组   现在可以用Array.isArray()判断。
Array.prototype.isPrototypeOf();
//第二种法
[] instanceof	Array          
  • 一般通过Object.prototype.hasOwnProperty(属性名)判断一个对象自身是否拥有某个属性。

Object.create() 创建一个对象,该对象的_prop_属性指向传入该函数的参数。

所有的函数都有prototype属性,值为对象。

在每个对象的原型上都有两个私有属性_proto_constructor ,这两个属性会随着原型链一直继承。
_proto_:会沿着原型链向上查找,一直找到原型链的最顶端。
constructor:找到原型对应的构造函数。

继承的几种方式

	function Origin () {
	};
	function Target () {
	}

下文我们会用OriginTarget两个函数做示例,默认 是Target继承Origin

1 传统模式- 原型链继承

	function Father (name,age) {
		this.name = name;
		this.age = age;
	}
	Origin.propotype = new Father();
	Target.propotype = new Origin();
	var target = new target();

弊端:会继承原型链上许多多余的东西,比如我们只需要Target函数

2 通过call和apply的方式

	function Target (){
		Origin.call(this);//只在了new的时候才有效
	}

弊端:每 new 一次都会call 一次,都会多执行一次Origin函数,造成性能与效率的浪费。并且不能继承原型,继承的是构造函数。

3 共享模式

	Target.propotype = Origin.propotype;

弊端:修改Target.propotype 的同时也会修改Origin.propotype
所有的_prop_最终都会指向Object.propotype,因此Target.propotypeOrigin.propotype都是引用值。
比如:

	Target.propotype.lastName = 'li';

此时打印Origin.propotype.lastName的值:

	console.log(Origin.propotype.lastName);

返回值为:
"li"
通常在我们开发过程中较为理想的状态是:Origin的原型 可以继承 Target原型 的方法和属性,并且修改其中任何一个原型都不会互相影响,即上述操作的理想状态为: console.log(Origin.propotype.lastName),返回值为‘undefined’
因为,我们构建了新的模式 圣杯模式

圣杯模式

	var Star = function (){
	}
	
	var inhreit = (function (Target,Origin){
		var F = function(){} ;
		retutn function () {
			F.prototype = Origin.propotype;
			Target.prototype = new F();
			Target.prototype.constructor = Target;
		}	
	})

var obj = {};
Object.creat(obj);
Object.creat()方法将会创建一个对象,这个对象的prototype指向传入的参数(这里是
obj);

工厂模式

每个构造函数都相当于一个工厂,所有通过 new被创造的对象都拥有其构造函数的方法和属性,我们又可以对每个对象扩展新的属性,并且这些对象之间并不会互相影响,这样就加工出许多相同的部件。当需要创造多个相同的实例时,可以利用构造函数的特性来开发。这种开发模式被称为“工厂模式”。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值