构造函数,原型,原型对象,构造器,原型链


<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <meta name="Generator" content="EditPlus">
  <meta name="Author" content="">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
  <title>Document</title>

 </head>
 <body>
	<div id="cont">Hello World</div>

	<script>
		// 创建构造函数Person
		function Person(name, age) {
			this.name = name;
			this.age = age;
		}

		// 通过new实例化构造函数Person
		let p1 = new Person("lili", 23);
		let p2 = new Person("jerry", 24);
		console.log("p1--->", p1);  // { name:"lili", 23}
		console.log("p2--->", p2);  // { name:"jerry", 24}
		console.log("p1.constructor == person--->", p1.constructor == person);	 // true
		console.log("p1 == Person.prototype--->", p1 == Person.prototype); // false n prototype属性没有办法从构造函数中继承,只能由构造函数本身访问
		console.log("Person.prototype == Person--->", Person.prototype == Person);  // false
		console.log("p1.constructor == Person.prototype.constructor--->", p1.constructor == Person.prototype.constructor);  // true
		console.log("p1.__proto__ == Person.prototype--->", p1.__proto__ == Person.prototype);  // true
		console.log("Person.__proto__ == Function.prototype--->", Person.__proto__ == Function.prototype);  // true
		console.log("Person.prototype.__proto__ == Object.prototype--->",  Person.prototype.__proto__ == Object.prototype);  // true



		// 构造器 constructor  原型 prototype
		// 每个对象都有一个constructor属性,指向这个对象所在的构造函数
		p1.constructor == Person;
		p2.constructor == Person;
		// Person.prototype是Person的原型“对象”,所以这个对象也有constructor属性,同样指向Person
		Person.prototype.constructor == Person;

		// 由此可见三者是等同关系,并且都等于Person:  构造函数的原型对象(prototype)的构造器(constructor)指向该构造函数
		p1.constructor == p2.constructor;		
		p1.constructor == Person.prototype.constructor == Person;

		// 原型链__proto__
		// 每个对象都有一个 __proto__ 属性指向创建它的构造函数的原型
		p1.__proto__ == Person.prototype;
		p2.__proto__ == Person.prototype;

		// Person本身是一个“构造函数”,那么创建它的构造函数就是一个Function
		Person.__proto__ == Function.prototype;

		// Person.prototype 是一个原型“对象”, 那么创建它的构造函数就是一个Object
		Person.prototype.__proto__ == Object.prototype;

		


		// 创建构造函数Dog
		function Dog(name, size) {
			this.name = name;
			this.size = size;
			this.eat = function() {
				console.log("吃肉肉");
			}
		};

		// 创建实例化对象 dog1
		let dog1 = new Dog("apple", 22);
		// js的构造函数和实例化对象之间,并不能够实现共享数据,节省内存空间的作用,所以我们就引入了原型这一个概念
		// 给构造函数Dog添加原型方法
		Dog.prototype.sell = function() {
			console.log("滑雪");
		};


		// 使用原型的注意事项
		// 原型属性和方法统一定义时,需要定义构造器constructor,即使构造函数的原型对象中的构造函数指向该构造函数,否则原型属性和方法定义失败	

		// 添加原型方法
		Person.prototype.job = "程序员";
		Person.prototype.address = "苏州";
		Person.prototype.study = function() {
			console.log("学习JavaScript");
		}
		// 可以这样定位吗?  ----》不可以
		Person.prototype = {
			job : "程序员",
			address : "苏州",
			study : function() { console.log("学习JavaScript"); }
		};
		// 上面的原型对象定义出错,需要加上constructor手动修改构造器的指向
		Person.prototype = {
			constructor : Person,
			job : "程序员",
			address : "苏州",
			study : function() { console.log("学习JavaScript"); }
		};


		// 换个构造函数名字 是一样的道理
		var example = new Object();
		example.constructor == Object;
		example.__proto__ == Object.prototype;
		Object.__proto__ == Function.prototype;
		Object.prototype.__proto == Object.prototype;
		// 当原型的__proto__属性等于该原型的时候,就说明指向到了最顶层的对像null
		Object.prototype.__proto == null && Object.prototype == null;



		// 1. Math和JSON是以对象存在的,所以
		Math.__proto__ === Object.prototype;	
		JSON.__proto__ === Object.prototype;

		// 2. Function.prototype是唯一一个typeof(Function.prototyoe) == "funciton"的原型,其他构造器的原型都是Object
		typeof Function.prototype == "function";

		// 3. 重写会导致constructor指向发生改变
		function Person() {}
		Person.prototype.name = "小名"

		person1 = new Person();
		person1.constructor.prototype.name = "小花";
		console.log(Person.prototype,name, person1.constructor === Person);   // 小花  true

		person1 = {  // 这里已经属于重写构造函数了
			getName: function() {
				console.log("获取姓名");
			};
		}
		console.log(Person.prototype,name, person1.constructor === Person, person1.constructor === Object);   // 小花  false  true
		
		// 测试题1 
		A.prototype.n = 1;
		var b = new A();
		A.prototype = {
			n : 2,
			m : 3,
		}
		var c = new A();
		console.log(b.n, b.m, c.n, c.m);    // 1 undefined 2 3 

		// 测试题2 
		var F = function() {  };   // F 为构造函数

		Object.prototype.a = function() {
			console.log("a()");
		};  // 等价于 F.prototype.__proto__  将值不仅写入构造函数prototype原型对象中,也写入了实例对象__proto__ 对象中

		Function.prototype.b = function() {
			console.log("b()");
		};   // 等价于F.__proto__ ,将值仅仅写入构造函数prototype原型对象中,不写入实例对象__proto__ 对象中
		var f = new F();

		// 解析:
		f.constructor == F == F.prototype.constructor;
		f.__proto__ == F.prototype;
		Object.prototype == F.prototype.__proto__;
		Function.prototype == F.__proto__;

		f.a()   // a()
		f.b()   // 报错  f.b is not a function
		F.a()   // a()
		F.b()   // b()


		// 测试题3
		var f =  new Foo("L");
		f.lastName = function() {
			console.log(this.name);
		};
		f.lastName();   // "L"  自身属性
		f.alertName();  // "Lkikllua"  原型属性
		// 以上函数中,f共有3个属性,f自身的属性有2个(name属性和lastName属性),还有一个alertName是原型属性
		f.firstName();  // 这里f自身属性中没有firstName属性,它的原型Foo函数中也没有这个属性,所以要再往上一次Foo的原型上去找这格属性,这种有多层原型的函数就是原型链,直到null为止结束原型链
		var item;
		for(item in f) {
			// 高级浏览器已经在for in中屏蔽了来自原型的属性,但是这里建议加上这个判断,保证程序的健壮性
			if( f.hasOwnProperty(item) ) {
				console.loe(item);  // 循环遍历f函数,如果f函数有它自身的属性item,则打印出item属性
			}
		}


		// 测试4
		// 原型链继承例子:
		function Name() {
			this.name = function() {
				console.log("kkkkk");
			}
		};
		function FirstName() {
			this.firstName = function() {
				consoel.log("llll");
			}
		};
		Name.prototype = new FirstName();
		var he = new Name();
		console.log(he.name); // "kkkkk"
		console.log(he.firstName);  // "llll"

		// 原型链继承例子2:
		function Elem(id) {
			this.elem = document.getElementById(id);
		}; 
		Elem.prototype.html = function(val) {
			var elem = this.elem;
			if(val) {
				elem.innerHTML = val;
				return this  // 链式操作
			}else {
				return elem.innerHTML;
			}
		};
		Elem.prototype.on = function(type, fn) {
			var elem = this.elem;
			elem.addEventListener(type, fn);  // addEventListener() 方法由于向指定元素添加事件
		};
		var div1 = new Elem("div1");
		// console.log(div1.html());
		div1.html(`<p>hello kkkkk</p >`).on("click", function() {
				alert("clicked");
			}).html(`<p>javascript</p >`);
		
	
		/**
			创建构造函数Person
			function Person() {
				this.name = name;
				this.age = age;
			}
			
			// 通过new实例化构造函数Person
			let p1 = new Person("lili",23);
			
			总结:
			1.prototype 属性没有办法从构造函数中继承,只能由构造函数本身来访问
			2.实例对象中都有__proto__属性,而构造函数中都有prototype属性,  构造函数.prototyo == 实例对象.__proto__  【 Person.prototype == p1.__proto__ 】
			3.构造函数的原型对象(prototype)的构造器(constructor)指向该构造函数    构造函数.prototype.constructor == 实例对象.constructor   【 p1.constructor == Person.prototype.constructor == Person 】
			4.Person本身是一个构造函数,那么创建它的构造函数就是一个Function    【Person.__proto__ == Function.prototype 】
			5.Person.prototype 是一个原型“对象”, 那么创建它的构造函数就是一个Object    【 Person.prototype.__proto__ == Object.prototype 】
			6.原型法添加方法的好处是:所有对象都共享,节约内存,通过构造函数添加成员方法会存在浪费内存
			7.JS中给同一个构造函数的实例对象,添加共有属性和方法,需要使用prototype这一属性,也就是原型对象来实现
			8.实例化完成后,所以实例均会与原型对象形成多对一的隐性关联关系。所有实例会共享原型对象的方法和属性,当然也包括constructor。当原型对象被添加一个属性或者方法后,均会被所有实例共享,即可以通过任意一个实例进行访问。如果原型对象的属性和方法与实例的属性和方法名称一致,则实例自身的属性和方法优先级高于原型对象上的。
			9.原型属性和方法统一定义时,需要定义构造器constructor,即使构造函数的原型对象中的构造器指向该构造函数,否则原型属性和方法定义失败。
			10.当原型的__proto__属性等于该原型的时候,就说明指向到了最顶层的对像null。
			11.Function.prototype是唯一一个typeof(Function.prototyoe) == "funciton"的原型,其他构造器的原型都是Object。
			12.原型链
				1) 构造函数,原型和实例的关系
					① 构造函数都有一个属性prototype,这个属性是一个对象(Object的实例)
					② 原型对象prototype里面有一个constructor属性,该属性指向原型对象所属的构造函数
					③ 实例对象都有一个__proto__属性,该属性也指向构造函数的原型对象,他是一个非标准属性,不可以用于编程,它是用于浏览器自己使用的
				2) prototype与__proto__的关系
					① prototype是构造函数的属性
					② __proto__ 是实例对象的属性
						这两者都指向同一个对象
					【总结】① 函数也是对象,对象不一定是函数
							② 对象的本质: 无效的键值对集合;键值对当中的值可以是任意数据类型的值
							③ 对象就是一个容器,这个容器当中放的就是(属性和方法)
				3) 属性搜索
					① 在访问对象的某个成员的时候,会先在对象中找是否存在
					② 如果当前对象中没有就在构造函数的原型对象中找
					③ 如果原型对象中没有找到就到原型对象的原型上找
					④ 直到Object的原型对象的原型是null为止			
		 */					
	</script>
 </body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值