js原型和原型链你只要看这一篇

一、原型概述

    任何对象都有一个原型对象,这个原型对象由对象的内置属性_proto_指向它的构造函数的prototyoe指向的对象,即任何对象都是由一个构造函数创建的,被创建的对象都可以获得构造函数的prototype属性,注意:对象是没有prototype属性,只有方法才有prototype属性。

    任何对象都有一个constructor属性,指向创建此对象的构造函数,比如说{}对象,它的构造函数是function Object(){}。

 

	function Person() {
	}
	var p = new Person();
	//方法才有prototype,普通对象无prototype
	console.log(Person.prototype); // Object{} 
	console.log(p.prototype); // undifined
	
	//任何对象都是有构造函数constructor,由构造函数创建的对象也可以获得构造函数的引用
	//此处只是打印下列对象的构造函数是什么。
	console.log(p.constructor); //function Person(){}  
	console.log(Person.constructor); //function Function(){} 
	console.log({}.constructor); // function Object(){}
	console.log(Object.constructor); // function Function() {}
	console.log([].constructor);  //function Array(){} 

    那什么是构造函数呢?

    用function声明的都是函数,而如果直接调用的话,那么Person()就是一个普通函数,只有用函数new产生对象时,这个函数才是new出来对象的构造函数

二、创建对象的过程

    2.1 、声明方法的过程

    首先,当我们声明一个function关键字的方法时,会为这个方法添加一个prototype属性,指向默认的原型对象,并且此prototype的constructor属性就是此方法。此二个属性会在创建对象时被对象的属性引用。

	function Hello() {
	}
	console.log(Hello.prototype); // Object {} -- > 内部的constructor 指向Hello方法
	console.log(Hello.prototype.constructor); // function Hello(){}

  2.2、创建一个对象,从构造函数继承了什么属性?

    console.log(h.constructor); // function Hello(){}
    console.log(Object.getPrototypeOf(h)==Hello.prototype); // true  备注:getPrototypeOf是获取_proto_

  我们惊喜的发现,new出来的对象,它的constructor指向了方法对象,它的_proto_和prototype相等。

  即new一个对象,它的_proto_属性指向了方法的prototype属性,并且constructor指向了prototype的constructor属性。

  由构造函数创建一个对象,此对象多了一个_proto_属性指向构造函数的prototype,一个constructor属性指向构造函数的prototype的constructor属性。

  2.3 、创建一个对象的过程

	function Hehe(name) {
		this.name = name;
	}
	var h = new Hehe("笑你妹");
	//伪代码:
	function newObj(name){
		 var obj = {};
		 obj.__proto__ = Hehe.prototype; 
		 obj.constructor = Hehe.prototype.constructor;
		 var result = Hehe.call(obj, name);
		 return typeof result==='object'&& result!=null ? result : obj;  //当无返回对象或默认时返回obj。
	}
	var hh = newObj("笑你妹");
	console.log(hh);
	console.log(h);
	//虽然hh!=h,但是可以看到这个hh就和h的结构一样了。

    过程:先创建一个空对象,设置一个_proto_指向方法的原型,设置constructor,用新对象做this指向方法,返回新对象。

2.4、总结

    从上面说明的过程中,我们发现只要是对象就是有构造函数来创建的,并且内部二个属性是从构造函数的prototype衍生的一个指向,而构造函数的prototype也是一个对象,那么它应该肯定也有一个构造函数,首先它是一个Object {} 对象,那么它的构造函数肯定是Object,所以就会有一个指针_proto_指向Object.prototype。最后Object.prototype因为没有_proto_,指向null,这样就构成了一个原型链。

    三、原型链分析

    什么是原型链?

    原型链的核心就是依赖对象的_proto_的指向,当自身不存在的属性时,就一层层的扒出创建对象的构造函数,直至到Object时,就没有_proto_指向了。

    如何分析原型链?

    因为_proto_实质找的是prototype,所以我们只要找这个链条上的构造函数的prototype。其中Object.prototype是没有_proto_属性的,等于null。

    3.1、最简单的原型链分析

    function Person(name){
            this.name = name;
     }
     var p = new Person();
     //p ---> Person.prototype --->Object.prototype---->null

     上面原型链的分析:p的构造函数是Person创建的,那么Person.prototype就是继承的第一个原型,而Person.prototype没有自定义设置,默认就是一个Object对象,即是Object构造函数创建的,那么就是继承了Object.prototype,而Object.prototype再往上就没有_proto_指向了,等于null

    属性搜索原则:
     1.当访问一个对象的成员的时候,会现在自身找有没有,如果找到直接使用。
     2.如果没有找到,则去原型链指向的对象的构造函数的prototype中找,找到直接使用,没找到就返回undifined或报错。

     3.2、原型继承

//原型继承的基本案例
function Person(name, age) {
	this.name = name;
	this.age = age;
}
//1.直接替换原型对象 
var parent = {
	sayHello : function() {
		console.log("方式1:替换原型对象");
	}
}
Person.prototype = parent;
var p = new Person("张三", 50);
p.sayHello();
//2.混入式原型继承
console.log(".............混入式原型继承..............");
function Student(name, age) {
	this.name = name;
	this.age = age;
}
var parent2 = {
	sayHello : function() {
		console.log("方式2:原型继承之混入式加载成员");
	}
}
for ( var k in parent2) {
	Student.prototype[k] = parent2[k];
}
var p = new Student("张三", 50);
p.sayHello();

    3.3 原型链案例

// 查询原型链上的对象的方法
function findProtoType(obj) {
  var arr = [];
  while (obj != null) {
    obj = Object.getPrototypeOf(obj);
    arr.push(obj);
  }
  return arr;
};

function Root() {}

function Child() {}

Child.prototype = new Root();
Child.prototype.constructor = Child; // 这个步骤是为了让原型对象打印显示成自身(继承prototype同时也继承了constructor,因此替换成自身)

function Item() {}

Item.prototype = new Child();
Item.prototype.constructor = Item;

var result = findProtoType(new Item());
console.log(result);
//  [ Item { constructor: [Function: Item] },Child { constructor: [Function: Child] }, Root {}, {}, null ]

谢谢观看!

end!

 

  • 31
    点赞
  • 227
    收藏
    觉得还不错? 一键收藏
  • 17
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值