js-原型链
1、 函数的prototype属性
- 每个 函数 都有一个prototype属性(是一个object类型数据),它默认指向一个object空对象(即称为:原型对象,不是真的空的,是没有我们自己定义的数据)
console.log(typeof Date.prototype) //object
console.log(Date.prototype) //如图1所示
function fun(){}
console.log(fun.prototype) //默认指向一个object空对象(没有我们的属性)
图1
图2
/* Date函数的流程基本就是
首先创建一个Date函数,
然后通过Date.prototype(指向原型对象)向Date函数原型对象中添加很多方法
如下:以函数fun为例
*/
function fun(){}
fun.prototype.test = function(){}
console.log(fun.prototype)
- 原型对象(定义函数的原型即prototype)中有一个属性constructor,他指向函数对象
// 原型对象中有一个属性constructor,他指向函数对象
console.log(Date.prototype.constructor === Date) // true
console.log(fun.prototype.constructor === fun) // true
2、 给原型对象添加属性(一般都是方法)
- 作用:函数的所有实例对象自动拥有原型中的属性(方法)
/*
给原型对象添加属性(一般都是方法)===》实例对象可以访问
*/
function Fun(){}
Fun.prototype.test = function(){
console.log('test()')
}
var fun = new Fun() // 实例化对象
fun.test() //test() 实例对象可以直接访问
3、 显式原型与隐式原型
- 每个函数function都有一个prototype,即显式原型
- 每个实例对象都有一个__proto__,即隐式原型
- 对象的隐式原型的值为其对应的构造函数的显式原型的值
/*
每个**函数function**都有一个prototype,即显式原型,默认指向一个object空对象(不是真的空的,是没有我们自己定义的数据)
*/
function Fn(){ //内部语句:this.prototype = {}
}
console.log(Fn.prototype)
/*
每个**实例对象**都有一个__proto__,即隐式原型,默认指向一个object空对象
*/
var fn = new Fn() // 实例化对象,内部语句:this.__proto__ = Fn.prototype
console.log(fn.__proto__)
/*
对象的隐式原型的值为其对应的构造函数的显式原型的值,引用地址值相同,指向同一个对象
*/
console.log(Fn.prototype === fn.__proto__) //true
Fn.prototype.test = function(){
console.log('test()')
}
fn.test() // test() 对象可以直接访问自己__proto__里面的属性和方法,本质上 对象的__proto__与其构造函数的prototype 指向的是同一个对象
- 内存结构
- 总结:
(1)对象的prototype属性:在定义函数时自动添加的,默认值是一个空object对象(不是真的空的,是没有我们自己定义的数据)
(2)对象的__proto__属性:创建对象时自动添加的,默认值是构造函数的prototype属性值
(3)程序员可直接操作显式原型,但不能操作隐式原型(es6之前)
4、 原型链
- 访问一个对象的属性时,先在自身属性中查找,找到返回
- 如果没有,再沿着_proto_这条链向上查找。找到返回
- 如果最终没有找到,返回undefined
- 别名: 原型链本质上是隐式原型链,故别名叫隐式原型链
- 作用:查找对象的属性(方法)
console.log(fn.test3) //undefined
console.log(fn.test3()) //fn.test3()有这个()表示在执行,会报错说没有定义声明这个test3这个方法
- 函数的显式原型指向的对象:默认是空的实例对象(但Object不满足)
var fn = new Fn()
console.log(Fn.prototype instanceof Object) //true
console.log(Object.prototype instanceof Object) //false
console.log(Function.prototype instanceof Object) //true
- 所有函数都是Function的实例(包含Function)
//所有函数都是Functionde的实例对象,故有隐式原型属性
console.log(Function.__proto__ === Function.prototype) //true
- Object的原型对象是原型链的尽头
//所有函数都是Functionde的实例对象,故有隐式原型属性
console.log(Object.prototype .__proto__ ) //null
5、 原型链-属性问题
- 读取对象的属性值时:会自动到原型链中查找(先在自身属性中找,没有的话就去原型链中找)
- 设置对象的属性值时:不回查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其值
function Fn(){}
Fn.prototype.a = 'xxx'
var fn1 = new Fn()
console.log(fn1 .a,fn1) //xxx
var fn2 = new Fn()
fn2.a = 'yyy'
console.log(fn1.a,fn2.a,fn2) //xxx yyy
- 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
// 属性一般通过构造函数定义在对象本身上,不通过prototype设置,不定义在原型上
function Person(name.age){
this.name = name
this.age = age
}
// 方法一般定义在原型中
Person.prototype.setName(name){
this.name = name
}
var persion= new Person(‘tom’,12)
persion.setName('Bob')
console.log(persion.name,persion.age) //Bob 12
var persion2= new Person(‘tom’,13)
persion2.setName('Cat')
console.log(persion2.name,persion2.age) // Cat 13
- 每个对象都有自己的属性 persion,persion2,对象的方法放在原型中
- 实例对象的隐式原型(proto)与构造函数的显式原型指向同一个对象,所以persion与persion1的__proto__属性是相同的,因为他们的构造函数都是Persion
// 属性一般通过构造函数定义在对象本身上,不通过prototype设置,不定义在原型上
function Person(name.age){
this.name = name
this.age = age
}
// 方法一般定义在原型中
Person.prototype.setName(name){
this.name = name
}
var persion= new Person(‘tom’,12)
persion.setName('Bob')
console.log(persion.name,persion.age) //Bob 12
var persion2= new Person(‘tom’,13)
persion2.setName('Cat')
console.log(persion2.name,persion2.age) // Cat 13
console.log(persion.__proto__ === persion2.__proto__) //true
6、 A instanceof B------判断A是否为B的实例
- instanceof是如何判断的
*表达式:A instanceof B
*如果B函数的显示原型对象在A对象的原型链上,返回true,否则返回false
*如下图// Foo.prototype有__proto__说明是个实例对象,即函数的原型对象默认是空的Object实例对象
function Foo(){}
var f1 = new Foo()
console.log(f1 instanceof Foo,f1 instanceof Object ,) // true,true
// Foo.prototype有__proto__说明是个实例对象,即函数的原型对象默认是空的Object实例对象
- Function是通过new自己产生的实例
//注:Object = new Function(),Object是函数
console.log(Object instanceof Function) // true
console.log(Object instanceof Object ) // true
console.log(Functioninstanceof Function) // true
console.log(Function instanceof Object ) // true
function Foo(){}
console.log(Object instanceof Foo) // false
(Object instanceof Function) // true
(Object instanceof Object ) // true -------- 所有函数的原型对象都是空的Object的实例:Function.prototype.proto = Object.prototype(Object除外)
(Functioninstanceof Function) // true -------- Function是通过new自己产生的实例
(Function instanceof Object ) // true
(Object instanceof Foo) // false
(b.n,b.m,c.n,c.m)// 1,undefined,2,3
function F(){}
Object.prototype.a = function(){
console.log('a()')
}
Function.prototype.b = function(){
console.log('b()')
}
var f = new F()
f.a() // a()
f.b() //报错 not a function
console.log(f )
console.log(Object.prototype)
//f.a()------------------------ a()
//f.b()------------------------ 报错
//f.b()------------------------ 报错原因,到不了Function.prototype,找不到Function.prototype.b
function F(){}
Object.prototype.a = function(){
console.log('a()')
}
Function.prototype.b = function(){
console.log('b()')
}
var f = new F()
f.a() // a()
F.a() // a()
F.b() // b()
console.log(f )
console.log(Object.prototype)
console.log(Function.prototype)
F.a() // a()
F.b() // b()