关于原型链的那些事儿

11 篇文章 0 订阅
1.创建对象

我们知道,创造对象有很多种方法:
1.1 比如最原始的工厂模式
工厂模式创建对象
1.2 然后是构造函数模式
构造函数模式创建对象
以上两种方式不同的地方在于:
1.构造函数模式没有显式地创建对象;
2.构造函数模式直接将属性和方法赋给了this对象;
3.构造函数没有return语句

那么,要创建Person的新实例,必须使用new操作符,使用这种方式调用构造函数实际上经历了哪些步骤呢?
1.创建一个新对象;
2.将构造函数的原型对象赋给新对象的原型(继承原型的属性方法);
3.在新对象的作用域环境下执行构造函数代码(添加实例属性);
4.返回新对象

{
	let obj = {};
	obj._proto_ = Person.prototype;
	let result = Person.call(obj,"dan",20);
	return typeof result === 'object'? result : obj;
}

构造函数的问题:
每个Person的实例都会有一个同名的Function实例,虽然同名,但都是由Person的每个实例创建的,所以它们不相等,同时也没必要创建这么多具有相同功能的同名函数
1.3 原型模式:
原型模式创建对象

每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性,如果在实例中找到了这个属性,则返回该属性的值;如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性。

我们可以通过对象实例访问保存在原型中的值,但是不能通过对象实例重写原型中的值,比如对person1.name = null执行语句后,会在person1这个实例中新建一个实例属性,值为null,再次访问name时,由于实例中存在这个属性,它不会再往原型上查找,即使这个实例属性的值为null

检测一个属性在原型中还是实例中:

//判断一个对象中是否有某属性  in  和  obj.hasOwnProperty()
//如果obj实例中或其原型对象上有"name"属性,都会返回true
"name" in obj  ;   
obj.hasOwnProperty('name');  //只有obj实例中有 "name",才会返回true
//所以可以结合以上两个来确定一个属性是否只存在于原型中
!obj.hasOwnProperty('name') && ("name" in obj) 

Object.keys(obj) //此方法返回obj自身所有的可枚举属性,不包括obj的原型对象上的
Object.getOwnPropertyNames(obj) //此方法返回obj自身所有的实例属性(不包括obj的原型对象上的),不论是否可枚举,如constructor

1.4 组合使用构造函数模式和原型模式:
创建对象最常见的方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性

function Person(name,age){
	this.name = name;
    this.age = age;
    this.friends = ["Shelby","Court"];
}
	Person.prototype.sayName = function(){
		alert(this.name);  
	};
2.继承

继承有以下几种方式
2.1原型链:

function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperValue = function(){
    return this.property;
}
function SubType(){
    this.subproperty = false;
}
// 继承了 SuperType
SubType.prototype = new SuperType(); // 执行这一步时,相当于重写 SubType.prototype 

原型链的问题

  1. 最主要的问题来自包含引用类型值的原型
  2. 在创建子类型的实例时,不能向父类型的构造函数中传递参数

确定原型和实例的关系:

  1. instanceof
  2. isPrototypeOf
SubType instanceof  SuperType
SuperType.prototype.isPrototypeOf(subType) 

这里顺便讲一下instanceof实现的原理

//用一个函数实现instanceof的功能
function instanceofFnc(left,right){
	let prototype = right.prototype;
	let proto = left.__proto__;
	while(true){
	    if(proto === prototype)
		return true;
	    if(proto === null)
	    	return false;
	    //如果以上判断都没有结果,则继续往上查找
	    proto = proto.__proto__;
	}
}

2.2借用构造函数(经典继承/伪造对象)
借用构造函数实现继承
2.3 组合继承(伪经典继承)
将原型链和借用构造函数技术组合在一块,从而发挥二者之长的一种继承模式。

function SuperType(name){
    this.name = name;
    this.colors = ["name", "blue", "green"];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
};
function SubType(name, age){
    // 继承属性
    Supertype.call(this,name); // 第二次调用 SuperType()
    this.age = age;
}
// 继承方法
SubType.prototype = new SuperType(); // 第一次调用 SuperType()
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
    alert(this.age);
};

var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
instance1.colors; // "red,black,green,black"
instance1.sayName(); // "Nicholas"
isntance1.sayAge(); // 29

var instance2 = new SubType("Greg", 27);
instance2.colors; // "red,black,green"
instance2.sayName(); // "Greg"
isntance2.sayAge(); // 27

组合继承的问题是,两次调用了父类型的构造函数,这样会造成 子类型的实例和原型上具有相同的属性 的问题

2.4 原型式继承
es5中的Object.create()方法就是原型式继承的一种实现,在只传入了一个参数的情况下,实际上就是对其进行了一次浅复制

//用一个函数来实现这个方法只传一个参数的功能
function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}
//至于传两个参数的用法,可以再自行搜索一下

2.5 寄生式继承
寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像是它做了所有工作一样返回对象。
在这里插入图片描述
2.6 寄生组合式继承
寄生组合式继承即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后将结果指定给子类型的原型。

function inheritPrototype(subType,superType){
    var prototype = Object.create(superType.prototype); // 创建对象
    prototype.constructor = subType; // 增强对象
    subType.protoType = prototype; // 指定对象
}
function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
};

function SubType(name, age){
    SuperType.call(this, name);//继承父类型的实例属性
    this.age = age;
}
inheritPrototype(Subtype,SuperType);  //继承父类型的原型
SubType.prototype.sayAge = function(){
    alert(this.age);
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值