学习目标
文章目录
一、复习
-
1、由于实例对象的原型指向的就是构造函数的原型可以省去__proto__
-
实例对象中的__proto__指向的就是该实例对象中的构造函数中的prototype
-
2、为什么使用原型?
-
本身在构造函数中定义的属性和方法,当实例化对象的时候,实例对象中的属性和方法都是在自己的空间中存在的,如果是多个对象。这些属性和方法都会在单独的空间中存在,浪费内存空间,所以,为了数据共享,把想要节省空间的属性或者方法写在原型对象中,达到了数据共享,实现了节省内存空间
-
3、如果构造函数中的:属性或者方法实现的效果都是一样的,那么可以写到原型对象当中
-
4、当内置对象不满足需求可以通过原型为内置对象添加属性或方法,方便开发
-
5、高内聚、低耦合
-
6、面向对象的思想来做: 分析对象,抽象出对象的特征和行为,定义构造函数,属性可以不共享部分方法需要共享,方法加到prototype中定义(在原型中定义方法,数据共享,节省内存空间)
-
7、window.变量=值;把这个局部变量的值暴露给window,成为了全局变量
-
8、对象.bind(参数);---->改变this的指向
面向对象编程思想:
根据需求,分析对象,找到对象有什么特征和行为,通过代码的方式来实现需求,要想实现这个需求,就要创建对象,要想创建对象,就应该先有构造函数,然后通过构造函数来创建对象,通过对象调用属性和方法来实现相应的功能及需求,即可
一、实例对象和构造函数之间有没有直接关系?
- 没有
- 而真正的实例对象和原型对象有关系,实例对象和原型对象之间的关系叫原型链,这种关系通过__proto__
二、原型链
- 原型链:是一种关系,实例对象和原型对象之间的关系,关系是通过原型(__proto__)来联系的
- 如果想要使用一些属性和方法,并且属性的值在每个对象中都是一样的,方法在每个对象中的操作都是一样,那么,为了共享数据,节省内存空间,是可以把每个属性和方法通过原型的方式赋值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uKBQ4NI4-1580717960781)(media\原型链.jpg)]
三、原型的指向是否可以改变
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BklaSiPi-1580717960783)(media\原型的指向是可以改变的.jpg)]
-
原型的指向是可以发生改变的
-
实例对象的原型__proto__指向的是该对象所在的构造函数的原型对象
-
构造函数的原型对象(prototype)指向如果改变了,实例对象的原型(__proto__)指向也会发生改变
-
原型的指向是可以改变的
-
实例对象和原型之间的关系是通过__proto__原型来联系的,这个关系就是原型链
四、原型最终指向了哪里?
-
实例对象中有__proto__原型
-
构造函数中有prototype原型
-
prototype是对象
-
所以,prototype这个对象中也有__proto__,那么指向了哪里
-
实例对象中的__proto__指向的是构造函数的prototype
-
所以,prototype这个对象中的__proto__指向的应该是某个构造函数的原型prototype
-
Person的prototype中的__proto__的指向
-
console.log(Person.prototype.__proto__);
-
per实例对象的__proto__——>Person.prototype的__proto__——>Object.prototype的__proto__是null
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XmccTvgM-1580717960784)(media\原型链最终的指向是Object的prototype的_proto__是null.jpg)]
五、原型指向改变如何添加方法和访问
改变了原型对象的指向:构造函数.prototype = new Person(10);
- 如果原型指向改变了,那么就应该在原型改变之后添加原型方法
六、实例对象对象的属性和原型对象属性重名问题
-
实例对象访问这个属性,应该先从实例对象中去找,找到了就直接使用,找不到就去指向的原型对象中去找,找到了就使用,找不到呢?——>undefined
-
通过实例对象能否改变原型对象中的属性值?不能
就想改变原型不过对象中属性的值,怎么办?直接通过原型对象.属性=值;可以改变 -
原型链:实例对象和原型对象之间的关系,通过__proto__
七、div对象原型链最终的指向
var divObj = document.getElementById("dv");
console.dir(divObj);//查看对象结构
divObj.__proto__——>HTMLDivElement.prototype的__proto__——>Node.prototype的__proto__——>EventTarget.prototype的__proto__——>Object.prototype没有__proto__,所以Object.prototype中的__proto__是null
八、原型继承
-
继承的目的:解决代码重复,造成了代码的冗余
-
改变构造函数的原型的指向即可
-
语法:
构造函数.prototype = new 对象();
因为任何实例对象中都会__proto__原型对象,指向的是该实例对象中的构造函数中的prototype
九、借用构造函数实现继承
-
为了数据共享,改变原型指向,做带了继承——>通过改变原型指向实现的继承
-
缺陷:因为改变原型指向的同时实现继承,直接初始化了属性,继承过来的属性的值都是一样的了,所以,这就是问题,只能重新调用对象的属性进行重新赋值
-
解决方案:继承的时候,不用改变原型的指向,直接调用父级的构造函数的方式来为属性赋值就可以了——>借用构造函数:把要继承的父级的构造函数拿过来,使用一下就可以了
-
借用构造函数:构造函数名字.call(当前对象,属性,属性,属性…)
-
解决了属性继承,并且值不重复的问题
-
缺陷:父级类别的方法不能继承
十、拷贝继承(for in)
- 浅拷贝:被没有把原型对象中__proto__指向的原型对象继承过来
- 拷贝继承:把一个对象中的属性或者方法直接复制到另一个对象中
- 遍历prototype对象的属性或者方法
十一、总结继承
- 继承:类与类之间的关系,面向对象的语言的继承是为了多态服务的
- js不是一门面向对象语言,但是可以模拟面向对象,模拟继承,为了节省内存空间
- 继承:
- 原型作用之一:数据共享 目的是:为了节省内存空间
- 原型作用之二:继承 目的是:为了节省内存空间
- 原型继承:改变原型指向 缺陷:属性值直接被初始化
- 借用构造函数继承:主要解决属性的问题 缺陷:父类中的方法不能被继承
- 组合继承:原型继承(不传值)+借用构造函数继承
既能解决属性问题,又能解决方法的问题 - 拷贝继承:就是把对象中需要共享的属性或者方法,直接遍历的方式复制到另一个对象中
十二、逆推继承看原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OHQnhLF3-1580717960785)(media\逆推继承看原型.jpg)]
十三、函数中this指向的问题
调用方式 | 非严格模式 | 备注 |
---|---|---|
普通函数调用 | window | 严格模式下是 undefined |
构造函数调用 | 实例对象 | 原型中方法中this也是实力对象 |
对象方法调用 | 该方法所属的对象 | 紧挨着的对象 |
事件绑定方法 | 绑定事件对象 | |
定时器函数 | window |
十四、严格模式
开启严格模式:"use strict";
function f1() {
console.log(this);
}
f1();//开启严格模式输出的是undefined,除非加window
十五、函数的角色
函数的声明:
function f1(){
console.log("我是函数");
}
f1();
函数表达式:
var ff= function () {
console.log("我也是一个函数哟");
}
ff();
函数声明如果在if-else的语句中,在IE8浏览器中会出现问题问题:IE8中:会预解析,把函数提升,后面的函数把前面同名函数替换了以后宁愿用函数表达式,都不用函数声明
十六、函数也是对象
- 函数是对象,对象不一定是函数
- 对象中__proto__原型,是对象
- 函数中有prototype原型,是对象
- 如果一个东西里面有prototype,又有__proto__,说明是函数,也是对象
- 所有的函数实际上都是Function的构造函数创建出来的实例对象
十七、数组中forEacs方法
回调函数:函数作为参数使用
Array.forEach(function(ele){
ele就是数组中每个元素
});