JS笔记3.5--原型链/继承/多态/封装

1.原型链

原型链是一种关系,实例对象和原型对象之间的关系,
关系通过原型(proto)联系

原型指向可以改变

实例对象的原型__proto__指向的是该实例对象的构造函数的原型对象
如果构造函数的原型对象的指向发生改变,实例对象的原型__proto__指向也会发生改变。

1.1 如果先在构造函数的原型中添加方法,然后改变构造函数的原型的指向,那么实例对象获取不到该方法。

<script type="text/javascript">
			function Person(age){
				this.age = age;
			}
			Person.prototype.eat = function()
			{
				console.log('人要吃饭')
			}
			
			function Student(){}
			Student.prototype.study = function(){
				console.log('请问如何学好原型链')
			}

			Student.prototype = new Person(23);//先在Student的原型中添加方法,然后改变Student原型指向,将其指向Person的实例对象
			var stu = new Student();
			stu.study(); //报错,找不到该方法
			stu.eat();//人要吃饭
		</script>

1.2 要想改变构造函数的原型的指向,还想让实例对象获取构造函数的原型的方法。需要先改变指向,然后再添加方法。

		<script type="text/javascript">
			function Person(age){
				this.age = age;
			}
			Person.prototype.eat = function()
			{
				console.log('人要吃饭')
			}
			
			function Student(){}
			Student.prototype = new Person(10) //原型的指向改变
			Student.prototype.study = function(){ //再添加方法
				console.log('请问如何学好原型链')
			}
			var stu = new Student()
			stu.study();//请问如何学好原型链 可以获取该方法
			stu.eat();//人要吃饭
		</script>

1.3 原型的最终指向

对象都有__proto__
构造函数的prototype也是对象,所以也有__proto__
实例对象的__proto__指向构造函数的prototype
那么构造函数的原型prototype的__proto__应该也指向某个构造函数的原型prototype
构造函数的原型prototype的__proto__ 指向Object.prototype
Object.prototype.__proto__是null

对象.xxx:是属性 没有赋值是undefined

XXX:是变量 没有赋值就报错

面向对象的特性:封装、继承和多态

2.封装

  1. 概念:隐藏实现细节,仅对外公开接口
  2. 为什么要封装?
    不封装的缺点:当一个类把自己的成员变量暴露给外部的时候,那么该类就失去对属性的管理权,别人可以任意的修改你的属性。
    封装就是将数据隐藏起来,只能用此类的方法才可以读取或者设置数据,不可被外部任意修改。封装是面向对象设计本质,这样降低了数据被误用的可能 (提高安全性和灵活性)。
  3. 局部变量和局部函数:在函数定义域中定义的变量是局部变量,在函数定义域中定义的函数是局部函数
  4. 对象的私有属性和私有函数:默认情况下,对象的属性和方法都是公开的,只要拿到对象,就可以操作对象的属性和方法。外界不能直接访问的变量和函数就是私有变量和私有函数。在构造函数内部定义的变量和函数,就是私有变量和函数。
  5. 通过 对象.XXX 找不到对象的私有属性。而是给该对象添加一个属性。
  6. 在给一个对象不存在的属性赋值时,不会到该对象的构造函数中查找,而是给该对象添加该属性,并赋值。
  7. 实例属性和方法:通过实例对象访问的属性和方法
  8. 静态属性和方法:通过构造函数访问的属性和方法

多态:

    * 多态:一个对象有不同的行为,或者是同一个行为针对不同的对象,产生不同的结果,
	* 要想有多态,就要先有继承,
	* js中可以模拟多态,但是不会去使用,也不会模拟

继承:

面向对象的编程语言通过类(class)实现面向对象,但是JS不是面向对象的编程序言,而是基于对象的编程语言。所以JS中没有类,而是通过构造函数模拟面向对象的编程思想。

    * 继承: 首先继承是一种关系,类(class)与类之间的关系,JS中没有类,但是可以通过构造函数模拟类,然后通过原型来实现继承
    * 继承也是为了数据共享,js中的继承也是为了实现数据共享
    * 原型作用之一:数据共享,节省内存空间
    * 原型作用之二:为了实现继承
		<script type="text/javascript">
			/*
			* 继承:
			* 人:拥有属性:姓名,性别,年龄 拥有行为:吃饭, 睡觉, 玩
			* 学生:继承人的属性和行为。
			* 此外,学生还有属性:成绩 行为:学习
			*/ 
		    function Person(name,sex,age){
				this.name = name;
				this.sex = sex;
				this.age = age;
			}
			Person.prototype.eat = function(){
				console.log('人要吃饭')
			}
			Person.prototype.sleep = function(){
				console.log('人要睡觉')
			}
			Person.prototype.play = function(){
				console.log('人要开心')
			}
			function Student(score){
				this.score = score
			}
			Student.prototype = new Person('jiaody','f',23)//改变原型对象的指向,让Student继承Person的属性和方法
			Student.prototype.study = function(){
				console.log('今天学习了吗')
			}
			var stu = new Student(99)
			console.log(stu.name);//jiaody
			console.log(stu.sex);//f
			console.log(stu.age);//23
			stu.eat();//人要吃饭
			stu.sleep();//人要睡觉
			stu.play();//人要开心
			console.log(stu.score)//99
			stu.study();//今天学习了吗
		</script>

改变原型指向实现继承的缺陷

//为了数据共享,改变原型指向,做到了继承--->通过改变原型指向实现的继承
//缺陷:因为改变原型指向的同时实现继承,直接初始化了属性,继承过来的属性的值都一样 ---> 问题
//只能重新调用对象的属性进行重新赋值。
//解决方案:继承的时候,不用改变原型的指向,直接调用父级的构造函数的方式来为属性赋值---> 借用构造函数:把要继承的父级的构造函数拿过来使用
	<script type="text/javascript">
     function Person(name,age,sex,weight) {
     this.name=name;
     this.age=age;
     this.sex=sex;
     this.weight=weight;
   }
   Person.prototype.sayHi=function () {
     console.log("您好");
   };
   function Student(score) {
     this.score=score;
   }
   //修改原型对象的指向实现继承,同时继承了属性值
   Student.prototype=new Person("小明",10,"男","50kg");
   var stu1=new Student("100");
   console.log(stu1.name,stu1.age,stu1.sex,stu1.weight,stu1.score);//小明 10 男 50kg 100
   stu1.sayHi();

   var stu2=new Student("120");
   stu2.name="张三";//想要修改继承过来的属性值,只能重新给属性赋值
   stu2.age=20;//想要修改继承过来的属性值,只能重新给属性赋值
   stu2.sex="女";//想要修改继承过来的属性值,只能重新给属性赋值
   console.log(stu2.name,stu2.age,stu2.sex,stu2.weight,stu2.score);//张三 20 女 50kg 120
   stu2.sayHi();
   var stu3=new Student("130");
   console.log(stu3.name,stu3.age,stu3.sex,stu3.weight,stu3.score);//小明 10 男 50kg 130
   stu3.sayHi();
	</script>

借用构造函数实现继承

语法:父级构造函数名.call(this,属性名,属性名,属性名…)
//解决了属性继承,并且值不重复的问题
//缺陷:父级类别中的方法不能继承

		<script type="text/javascript">
			function Person(name, age, sex, weight) {
				this.name = name;
				this.age = age;
				this.sex = sex;
				this.weight = weight;
			}
			Person.prototype.sayHi = function() {
				console.log("您好");
			};

			function Student(name, age, sex, weight, score) {
				Person.call(this, name, age, sex, weight)
				this.score = score;
			}
			var stu1 = new Student("小明", 10, "男", "10kg", "100");
			stu1.sayHi();//父级原型对象中的方法无法继承,报错.
			console.log(stu1.name, stu1.age, stu1.sex, stu1.weight, stu1.score);//小明 10 男 10kg 100

			var stu2 = new Student("小红", 20, "女", "20kg", "120");
			console.log(stu2.name, stu2.age, stu2.sex, stu2.weight, stu2.score)//小红 20 女 20kg 120
		</script>

组合继承:修改原型对象指向+借用构造函数

修改原型对象指向:继承父级的方法
借用父级构造函数:继承父级的属性

			function Person(name, age, sex, weight) {
				this.name = name;
				this.age = age;
				this.sex = sex;
				this.weight = weight;
			}
			Person.prototype.sayHi = function() {
				console.log("您好");
			};

			function Student(name, age, sex, weight, score) {
				Person.call(this, name, age, sex, weight) //借用构造函数继承
				this.score = score;
			}
			Student.prototype = new Person();//修改原型对象的指向但不传入参数
			Student.prototype.eat = function(){
				console.log('就知道吃')
			}
			var stu1 = new Student("小明", 10, "男", "10kg", "100");
			stu1.sayHi();//您好 
			stu1.eat();//就知道吃
			console.log(stu1.name, stu1.age, stu1.sex, stu1.weight, stu1.score);//小明 10 男 10kg 100

			var stu2 = new Student("小红", 20, "女", "20kg", "120");
			console.log(stu2.name, stu2.age, stu2.sex, stu2.weight, stu2.score)//小红 20 女 20kg 120
		</script>

拷贝继承

把一个对象中的方法或属性直接复制给另一个对象

    function Person() {
    }
    Person.prototype.age=10;
    Person.prototype.sex="男";
    Person.prototype.height=100;
    Person.prototype.play=function () {
      console.log("玩的好开心");
    };
    var obj2={};
    //Person的构造中有原型prototype,prototype就是一个对象,那么里面,age,sex,height,play都是该对象中的属性或者方法

    for(var key in Person.prototype){
      obj2[key]=Person.prototype[key];
    }
    console.dir(obj2);
    obj2.play();
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值