函数高级
原型与原型链
原型
1.函数的prototype属性
-
每个函数都有一个prototype属性,它默认指向一个(即:原型对象),可在该对象中添加方法
-
指向的空对象(原型对象)中有一个属性constructor,指向
-
console.log(Date.prototype.constructor===Date)
2.给原型对象添加属性(一般是方法)===>实例对象(构造函数)可以访问
- 作用:构造函数的所有实例对象自动拥有其原型对象中的属性(方法)
显式原型与隐式原型
1.每个函数都有一个prototype属性,即(属性),默认指向Object空实例对象
//1.定义构造函数
function Fn() {//内部语句:this.prototyoe = {} 在声明后默认指向空对象
//Fn相当于全局变量,存储其函数对象的地址值
}
console.log(Fn.prototype)//保存的地址值
2.每个实例对象都有一个__proto__,可称为(属性),指向其构造函数的原型对象
//2.创建实例对象
var fn = new Fn() //内部语句:this.__proto__ = Fn.prototype
console.log(Fn.prototype===fn.__proto__)//true __proto__保存地址值
//3.给原型添加方法
Fn.prototype.test = function () {
console.log("test()")
}
//4.实例对象调用原型对象中定义的函数(方法)
//规则:先在本身属性上查找,没有再通过属性__proto__查找其对应原型对象内是否有该方法
fn.test()
3.实例对象的隐式原型的值为其对应构造函数的显式原型的值
4.内存结构图
5.总结
- 构造函数prototype属性:在时自动添加,默认指向一个空的Object实例对象(没有我们所指定的的属性或方法),除了Object,console.log(Object.prototype instanceof Object) //false 没有__proto__属性,console.log(Function.prototype instanceof Object) //true
- 实例对象的__proto__属性:时自动添加,默认值为构造函数的prototype属性值(地址值)
原型链(隐式原型链)
作用:查找对象的属性(方法)
步骤:
-
访问一个对象的属性时
-
先在自身属性中寻找,找到就返回
-
若没有,则沿着隐式原型属性_proto__这条链向上(直到原型链尽头,_
Object.prototype.__proto__ == null)查找,找到返回
-
如果最终也没找到,则返回undefined
JS引擎会先加载内置的函数,比如Object,因而在查找属性是并不是找到构造函数的原型对象就结束了,还需要往上查找,某构造函数的原型对象是一个空的Object对象的空是说其中没有我们指定的属性或方法,但它其实也是的实例对象,含有**_proto_属性指向的原型对象**。
任何函数(Object()也是)都有一个显式原型属性和一个隐式原型属性(为Function构造函数的实例对象,)且!所有函数的隐式原型属性都应该相等!因为都是var fn = new Function()产生。Funciton = new Function(),Function既是构造函数又是实例对象,表明显式原型属性等于隐式原型属性!
Function._proto_===Function.prototype,普通函数的显式原型指向一个空的Object实例对象,其隐式原型指向Function.prototype!
原型链属性问题
- 对象的属性值时:会自动到原型链中查找
- 对象的属性值时:不会查找原型链,如果当前对象没有此属性,会直接添加此属性并赋值
- 一般定义在原型中(这样通过该构造函数new的实例对象都能用,不需要每个对象都设置),一般通过构造函数定义在对象本身上(,构造函数可以构造不同的实例对象,但其隐式原型均指向构造函数的显式原型)
探索instanceof
1.instanceof是如何判断的?
-
表达式:A instanceof B
-
如果B函数的显式原型对象在A实例对象的原型链(隐式原型链)上有交集,返true,否则返false
-
只要B是Object,A只要不是Objcet,都为true
function fn() {} var f1 = new fn() console.log(f1 instanceof fn) //true console.log(f1 instanceof Object) //true 原型链尽头 Object.prototype f1是fn函数的实例对象指向fn.prototype,同时fn.prototype是Object函数的实例对象其隐式原型指向Object.prototype console.log(Object instanceof Function) //true 任何函数都是Function的实例对象 console.log(Object instanceof Objcet) /* true Object是构造函数 B为构造函数 Object.prototype(原型链尽头),A为Function的实例对象,因而其隐式原型指向Funciton.prototype,又因为Funciton.prototype为Object的实例对象,故指向Object.prototype*/ console.log(Function instanceof Function) //true Function = new Funciton() console.log(Funciton instanceof Object) //true function fo() {} console.log(Object instanceof fo) //fasle //Object走原型链到Object.prototype,任何函数都是Funcion的实例对象,因而其__proto__先指向Funciton.prototype,该显式原型又是Object的实例对象因而其__proto__指向Object.prototype,这是原型链走势,对于fo只走一步即fo.prototype,虽然其最后仍然指向Object.prototype,但因为其作为B,Object作为A,所以没有交集,反false
2.Function是通过new自己产生的实例
原型面试题
var A = function A () {
}//定义构造函数A
A.prototype.n = 1 //A的显式原型中添加n属性
var b = new A() //b为A的实例对象1 确定其隐式原型指向为最初的
A.prototype = {
n: 2,
m: 3
}//A的显式原型赋值新的对象地址值,之前的原型指向被更改
var c = new A()//c为A的实例对象2 此处隐式原型指向已经更改为新的
console.log(b.n,b.m,c.n,c.m)//1 undefined 2 3
function F1() {}//声明构造函数
Object.prototype.a = function(){
console.log("a()")
}//原型链尽头设置方法a
Function.prototype.b = function(){
console.log("b()")
}//Function显式原型设置方法b 其内部有隐式原型指向原型链尽头Object.prototype 任何函数的隐式原型能指向该显式原型,注意是函数不是其构造的实例对象!
var f = new F()//f为构造函数F的实例对象 注意不是Funciton!
f.a()//本身没有在原型链上找,找到原型链尽头 "a()"
f.b()//报错没有b这个函数 其指向应该是Object.prototype,但b方法在Function.prototype上并不在F函数上,F1函数的隐式原型才指向Function,才有b方法
F1.a()//"a()" 通过隐式原型链找到Object.prototype的方法a
F1.b()//"b()"
【注】构建函数new的实例对象,通过原型链最终肯定会指向原型链Object.prototype,顺序是先实例对象的隐式原型指向构建函数的显式原型,然后构造函数的显式原型指向原型链尽头,这期间实例对象的隐式原型并没有指向Function.prototype,构建函数的才指向Function.prototype,因而若Function.prototype有方法定义,构建函数才能调用因为在其隐式原型链上,但是实例对象无法调用,只能调用其构建函数的显式原型和原型链尽头上的方法!