小米技术社区
小米技术社区管理员 关于小米

27岁,山西运城人,职业电商经理人,前端开发工作者,从事过网站建设、网络推广、SEO、SEM、信息流推广、二类电商、网络运维、软件开发,等相关电商工作,经验较为丰富,小米技术社区致力于为广大从事Web前端开发的人员提供一些力所能及的引导和帮助 ...[更多]

E-mail:mzze@163.com

Q Q:32362389

W X:xiaomi168527

小米技术社区大牛王飞 关于王飞

27岁,山西运城人,职业电商经理人,网络工程师兼运维,从事过运营商网络建设,企业网络建设、优化。数据中心网络维护等通过,经验丰富,座右铭:当自己休息的时候,别忘了别人还在奔跑。 ...[更多]

E-mail:wf_live@126.com

Q Q:3940019

微博:王小贱ss

小米技术社区设计小艳 关于小艳

大于花一样的年龄,河南郑州是我家,2010年在北京接触团购网,2011年进入天猫淘宝一待就是四年,如今已经将设计走向国际化(ps:误打误撞开始进入阿里巴巴国际站的设计,嘿嘿)五年电商设计,丰富经验,从事过天猫淘宝阿里各项设计,店铺运营,产品拍摄;我将我的经历与您分享是我的快乐!座右铭:越努力越幸运! ...[更多]

E-mail:97157726@qq.com

Q Q:97157726

标签云
精品推荐
  • 什么是闭包?js闭包的2个最大用途以及注意事项

    什么是闭包?js闭包的2个最大用途以及注意事项

    各种专业文献上的"闭包"(closure)定义非常抽象,很难看懂。简单的说,闭包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因……
    134人已经看过了
您的位置:首页 > 前端开发 > Javascript > 原生JS

构造函数、原型对象、实例对象三者之间的关系;原型链概念引入和原型链继承

分类: 原生JS78个赞

用 构造函数 和 原型对象 混合定义方式来定义一个对象方法如下

//1.定义一个构造函数
    function Person(n,a){
        this.name = n;
        this.age = a;
    }
//2.通过原型对象设置方法
    Person.prototype.say = function(){
        console.log('我叫' + this.name + ',我今年' + this.age + '岁');
    }
//3.实例化构造函数得到 实例对象
    var person1 = new Person('张飞', 30);
    console.log(person1);


那么构造函数、原型对象、实例对象三者之间的关系是什么呢?

一、构造函数和实例对象获取原型对象

1.构造函数的prototype属性  存的是原型对象

console.log(Person.prototype);

2.实例对象的__proto__属性  存的也是原型对象

console.log(person1.__proto__);

他们的值是相等的哦

console.log(person1.__proto__ === Person.prototype);//true

二、原型对象和实例对象获取构造函数

1.通过原型对象的constructor属性,取到构造函数

console.log(Person.prototype.constructor);

2.实例对象也可以直接使用原型对象上的constructor获取构造函数

console.log(person1.constructor);

三、构造函数获取构实例对象

1.通过构造函数获取实例对象

var person1 = new Person('张飞', 30);

构造函数、原型对象、实例对象三者之间的关系的示意图



构造函数、原型对象、实例对象存在的特殊情况(存在问题的一种用法)

我们注意到,前面例子中每添加一个属性和方法就要敲一遍 构造函数.prototype 。 为减少不必要的输入,更常见的做法是用一个包含所有属性和方法的对象字面量来重写整个原型对象:

//1.定义一个构造函数
function Person(n,a){
this.name = n;
this.age = a;
}
//2.1旧向原型对象上添加一个方法,注意这个方法的用法
Person.prototype.say = function(){
console.log('我叫' + this.name + ',我今年' + this.age + '岁');
}
//2.2新直接替换了原来的原型对象 ,用这种方法需要先添加"constructor":Person, 因为产生的问题,原型对象本身的constructor属性丢失了,会取到Object函数
Person.prototype = {
"constructor":Person, //需要手动指定构造函数
"say":function(){
console.log('我叫' + this.name + ',我今年' + this.age + '岁');
}
};
//实例化构造函数得到 实例对象
var person1 = new Person('张三', 30);


问题:使用2.2这种方法直接替换原来的原型对象,需要在开始添加"constructor":Person, 要不然获取不到构造函数


console.log(person1.constructor); //实例对象获取构造函数
//结果:不写"constructor":Person,得到的是到Object() ,只有写了才会得到构造函数,因为替换后原型对象本身的constructor属性丢失了,
console.log(Person.prototype.constructor); //原型对象获取构造函数
//结果:不写"constructor":Person,得到的是到Object() ,只有写了才会得到构造函数,因为替换后原型对象本身的constructor属性丢失了,
console.log(Person.prototype); //构造函数获取原型对象
console.log(Person.prototype.__proto__); //构造函数获取原型对象的原型对象
console.log(person1.__proto__.__proto__);//实力函数获取原型对象的原型对象
//找到一个对象的原型对象,还可以继续找原型对象的原型对象,直到找到最顶层(Object.prototype)为止

不写"constructor":Person,的控制台输出(不正常)

替换后原型对象本身的constructor属性丢失了,输出显示object

写了"constructor":Person,的控制台输出(正常)

加了constructor后显示正常



原型链:

//定义两个构造函数
    function A(){
        this.age = 20;
    }

    function B(){
        // this.age = 30
    }

    //实例化 构造函数A得到一个对象
    var obj = new A();
    //将A的实例对象,设置为 B的原型对象
    B.prototype = obj;
    //实例化 构造函数B
    var obj2 = new B();
    console.log(obj2); //B
    console.log(obj2.__proto__);// obj2的原型对象为A
    console.log(obj2.__proto__.__proto__);  //结果为Object() obj2的原型对象的原型对象;A.prototype 相当于是 new Object()
    console.log(obj2.__proto__.__proto__.__proto__); //结果为Object() obj2的原型对象的原型对象的原型对象;A.prototype 相当于是 new Object()
    console.log(obj2.age); //结果为20,因为构造函数B的this.age被注释,所以他使用A的age为20 这种原型对象的链式结构,叫做是原型链

查找一个对象的成员,先从自身找,如果没找到,就继续在原型对象的原型对象上找,这种原型对象的链式结构,叫做是原型链

原型链的原理:

1. 查找一个对象的成员,先从自身找(包括自身构造函数中定义的成员),

2. 如果找到就直接使用。

3. 如果没找到,就继续在原型对象的原型对象上找,

4.直到找到最顶层的原型对象(Object.prototype)

这种根据原型对象的链式结构,进行的链式查找方式,通常也叫做原型链(从查找对象的成员的方式角度)

原型链原理示意图1

原型链原理示意图2


原型链的继承

使用场景:人  都会说话 走路  有的人会打球 有的人会唱歌

多个子类构造函数  继承 同一个父类构造函数


来通过案例1了解下原型链的继承

// A 构造函数
	function A(){
		this.age = 30;
	}
	//原型对象
	A.prototype.say = function(){
		console.log('hello');
	}
    //实例对象
	var obj_a = new A();

	console.log(obj_a.age); //结果30
	obj_a.say(); //hello
	//obj_a  继承了  原型对象 A.prototype ,能够直接使用原型对象的方法


原型链的继承进阶案例2:

//让B的实例对象 继承 A的实例对象

//基本语法: B.prototype = new A();

	//A是父类构造函数
	this.age = 30;
	}
	A.prototype.say = function(){
		console.log('hello');
	}

	var obj_a = new A();

	// B是子类构造函数
	function B(){
		this.sex = "男";
	}
	B.prototype = obj_a;  // B.prototype = new A();
	B.prototype.zou = function(){
		console.log('走路');
	}

	//实例化子类构造函数B,得到一个子对象
	var obj_b = new B();
	//B的实例对象,可以使用A实例对象的成员
	console.log( obj_b.age );
	obj_b.say();
	obj_b.zou();


原型链的继承进阶案例3:

//父类构造函数
	function Person(){

	}
	Person.prototype.say = function(){
		console.log('所有人都会说话');
	}
	Person.prototype.walk = function(){
		console.log('所有人都会走路');
	}

	//子类构造函数  歌手
	function Ren(){

	}
	Ren.prototype = new Person();
	Ren.prototype.changge = function(){
		console.log('唱歌');
	}
	var obj = new Ren();
	obj.say();  //所有人都会说话
	obj.walk(); //所有人都会走路
	obj.changge(); //唱歌

	//子类构造函数  球员
	function Ball(){

	}
	Ball.prototype = new Person();
	Ball.prototype.play = function(){
		console.log('打球')
	}

	var obj2 = new Ball();
	obj2.say(); //所有人都会说话
	obj2.walk(); //所有人都会走路
	obj2.play(); //打球


小米技术社区