原型
原型什么时候产生的?
执行函数定义的时候,prototype 显示原型就创建出来了,由于函数本身也是对象(实例对象),里面的隐式原型proto也产生了
原型的理解
原型就是对象,JS 中原型一共有两个,一个是 prototype,一个是proto属性
- prototype:浏览器的标准属性,程序员使用的,显示原型,存在于函数中
__proto__
:浏览器的非标准属性,浏览器使用的,隐式原型,存在于实例对象中- 函数中有 prototype,实例对象中有proto
- 实例对象也是对象,里面就有proto
- 实例对象的proto与对应函数的 prototype 都指向原型对象
- 无论是构造函数还是普通函数,或者是方法,只要是函数,内部就有 prototype
原型的作用
一、共享数据,节省内存空间
1、实例对象一般都是通过构造函数进行创建的,实例化对象的时候做的四件事:
- var per = new Person('illion',20)
1) 申请一块空闲的空间,用来存储当前的实例对象
2) 设置this为当前的实例对象(修改this的指向)
3) 初始化实例对象中的属性和方法的值
4) 把this作为当前对象进行返回
2、 在构造函数中定义的属性及方法,仅仅是编写代码进行定义而已,而实际上里面定义的属性及方法是属于每个实例对象的,所以,创建多个对象,就会开辟多个空间,每个空间中的每个对象都有自己的属性及方法,大量创建对象,对象的方法都不是同一个方法(方法也是函数,函数代码也占用空间),为了节省内存空间,那么可以使用原型的方式,实现数据共享,节省内存空间。
二、通过改变原型实现 JS 中的继承
1). 通过改变原型指向实现继承
2). 借用构造函数显示继承
3). 组合继承
4). 拷贝继承:浅拷贝和深拷贝
原型对象上有一个constructor
属性指向对应的构造函数
function Fn () {}
const fn = new Fn()
区别执行函数定义与执行函数
- 执行函数定义: 也就是去创建函数对象, 只是有可能被 JS 引擎提升预处理执行
- 执行函数: 执行函数体中所有语句
- 先有函数定义的执行,才有执行函数
- 常见的回调
- DOM 事件的回调 btn.onClick=function(){}
- 定时器中的回调
- ajax 回调函数
- 生命周期的回调
- 立即执行函数(Immediately-Invokey Function Expression) 匿名函数自调用
- 作用:隐藏内部实现,减少命名空间的污染
;(function(){
var num = 20;
})();
var num = 10;
说说函数对象上的prototype
属性?
(prototype什么时候出现,执行函数定义的时候)
-
执行函数定义(有可能被提升执行)创建函数对象
-
给函数对象添加prototype属性, 属性值为空的Object实例对象, 也就是原型对象
-
给原型对象添加constructor属性, 值为函数
-
伪代码:
// 给函数对象添加prototype属性, 属性值为空的Object实例对象, 也就是原型对象 function Fn(){} console.dir(Fn) var obj ={} console.log(obj.__proto__===Object.prototype) //true console.log(Fn.prototype.__proto__===Object.prototype) //true // 伪代码 this.prototype = {} // this就是函数对象 this.prototype.constructor = Fn
-
说说实例对象上的__proto__
属性?
(_proto-什么时候出现,实例化对象的时候)
JS引擎在创建实例对象时内部自动执行时, 会自动给实例对象添加__proto__
属性, 值为构造函数的 prototype属性的值
this.__proto__ = Fn.prototype // this是实例对象
原型链
(实际上是隐式原型链,言外之意就是和显示原型没毛关系,显示原型产生实例的一瞬间起的作用)
-
从对象的
__proto__
开始, 连接的所有对象, 就是我们常说的原型链, 也可称为隐式原型链
-
查找对象属性简单说: 先在自身上查找, 找不到就沿着原型链查找,如果还找不到返回undefined
查找对象上属性的基本流程
1、 先在对象自身上查找, 如果有, 直接返回
2、如果没有, 根据__proto__
在原型对象上查找, 如果有, 直接返回
3、 如果没有根据原型对象的__proto__
在原型对象的原型对象上查找, 一直查找到Object原型对象为止
4、 如果找到了返回, 如果查找不到由于它的__proto__
为null, 只能返回undefined
5、 查找对象属性时候,会不会读函数的prototype?(会还是不会)
```js
// 简单的原型链
function F1(){}
F1.prototype.number =100
function F2(){}
F2.prototype=new F1()
F2.prototype.number =200
function F3(){}
F3.prototype=new F2()
F3.prototype.number =300
var f3 = new F3()
console.log(f3.number)
console.dir(f3) //300
```
表达式a.b的解析流程
var a = 10 //a是一个变量,值是数字类型的,引用类型的对象可以点属性或者方法,然后使用
//a是数字类型,但是由于a.b了,此时a就变成了基本包装类型----引用类型了
// a是一个对象了,b就是一个属性,但是属性没有赋值,所以,结果就是undefined
console.log(a.b)//undefined 没有报错
- 查看a变量: 作用域链查看
- 不存在 ==> 报错
- 存在, 得到它的值
- 基本类型(var a=null/a=undefined,此时a.b报错)
- null/undefined ===> 报错
- number/string/boolean ==> 创建一个包含此值的包装类型对象, 进入下面流程
- 地址值 ===> 解析.b ===> 查找b属性
- 先在自身找, 找到了返回, 如果没有找到
- 原型链查找
- 找到了返回
- 没找到, 返回undefined
- 基本类型(var a=null/a=undefined,此时a.b报错)
a.b这个表达式中,总结知识点:数据类型(null/undefined,string/number/boolean),作用域(局部作用域/全局作用域),域解析,执行上下文环境,原型/原型链—>原型相关应用
instanceOf
-
作用: 判断一个任意类型对象的具体类型
- 如何判断?
- 对于 A instanceof B
- A是实例对象, B是构造函数
- 如果B的prototype属性所指向的原型对象是A实例对象的原型链接上的某个对象, 返回true, 否则返回false
- 如何判断?
// 构造函数
function Foo() { }
// f1是实例对象---引用变量,存储的是当前的这个对象所在的空间的地址
const f1 = new Foo()
const f2 = new Foo()
const o1 = new Object()
const o2 = {}
// 下面的结果
// 所有的函数都是Function的实例对象
console.log(Foo instanceof Object)//true
// 所有的函数都是Function的实例对象
console.log(Foo instanceof Function)//true
console.log(Object instanceof Object)//true
console.log(Function instanceof Function)//true
console.log(Function instanceof Object)//true
console.log(Object instanceof Foo)//false
console.log(f1 instanceof Function)//false
console.log(f1 instanceof Object)//true
原型与原型链结构图
```
1. 对象中有__proto__,函数中有prototype
- 实例对象中__proto__指向的是当前实例对象对应的构造函数中的prototype
- 而每个prototype都是一个对象,所以,内部必然有__proto__,普通函数中的prototype的__proto__指向的是Object的prototype
- 每个函数是Function的实例对象,所以,只要是函数,那么函数对象中__proto__指向的都是Function的prototype,那么这个prototype中的__proto__指向的仍然是Object的prototype
- 但是,Object这个构造函数也是函数,所以,Object的__proto__指向的是Function的prototype
- Function这个构造函数也是对象,所以里面的__proto__指向的是Function的prototype
```