函数的prototype
- 每个函数都有一个prototype的属性,默认指向一个Object对象(原型对象)
- 原型对象中有一个属性constructor,指向函数对象
- 函数中所有的实例对象自动拥有原型中的属性(或方法,因此可以给原型对象添加属性或方法)
显式原型和隐式原型
- 每个函数function都有个prototype属性,即显式原型,属性值是个普通对象
- 每个引用类型都有个__proto__属性,即隐式原型,属性值是个普通对象
- 引用类型的隐式原型的值为其对应构造函数的显式原型的值
- 在定义函数时自动添加prototype属性,默认指向一个空的Object对象
- 在创建对象时自动添加__proto__属性,默认值为构造函数的prototype属性值
function Fn() { // 内部语句: this.prototype = {}
}
// 每个函数function都有一个prototype,即显式原型(属性),默认指向一个空的Object对象
console.log(Fn.prototype)
// 每个实例对象都有一个__proto__,即隐式原型(属性)
// 创建实例对象
var fn = new Fn() //fn是Fn()的实例对象,内部语句: this.__proto__ = Fn.prototype
console.log(fn.__proto__)
// 对象的隐式原型的值为其对应构造函数的显式原型的值
console.log(fn.__proto__ === Fn.prototype) // true
// 给原型添加方法
Fn.prototype.test = function() {
console.log("test()")
}
// 通过实例调动原型方法
fn.test()
原型链
当访问对象属性的时候,会在的属性上找,没找到的时候会往__proto__属性上面找,,即在对象的构造函数prototype上面查找,如果没找到会接着重复上述步骤,直到查找到Object.prototype时
Object.prototype.proto === null查找结束,返回undefined。所有从原型或更高级原型中得到执行的方法,其中this在执行时,指向当前触发事件的对象。js对象就是通过原型链实现属性的继承。
/**
* 1、原型链(图解)
* 访问一个对象的属性时,
* 先在自身属性中查找,找到返回
* 如果没有,再沿着__proto__这条链向上查找,找到返回
* 如果最终没找到,返回undefined
* 别名:隐式原型链
* 作用:查找对象的属性(方法)
* 2、构造函数/原型/实体对象的关系(图解)
* 3、构造函数/原型/实体对象的关系2(图解)
* 4、所有函数的__proto__都是一样
*/
console.log(Object)
console.log(Object.prototype)
consolo.log(Object.prototype.__proto__) // null
function Fn() {
this.test1 = function() {
console.log('test1')
}
}
console.log(Fn.prototype)
Fn.prototype.test2 = function() {
console.log('test2')
}
var fn = new Fn()
fn.test1()
fn.test2()
console.log(fn.toString())
console.log(fn.test3) // undefined
// fn.test3() // 报错
/*
1、函数的显式原型指向的对象:默认是空Object实例对象(但Object不满足)
*/
console.log(Fn.prototype instanceof Object) // true
console.log(Object.prototype instanceof Object) // false
console.log(Function.prototype instanceof Object) // true
/*
2、所有函数都是Function的实力(包含Function)
*/
console.log(Function.__proto__ === Function.prototype)
/*
3、Object的原型对象是原型链的尽头
*/
console.log(Object.prototype.__proto__) // null
// 原型链属性问题
/**
* 1、读取对象属性值时:会自动到原型链中查找
* 2、设置对象的属性值时:不会查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其值
* 3、方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
*/
function Fn1() {
}
Fn1.prototype.a = '1234'
var fn1 = new Fn1()
console.log(fn1.a) // 1234
var fn2 = new Fn1()
fn2.a = '5678'
console.log(fn1.a, fn2.a, fn2) // 1234 5678
function Person (name, age) {
this.name = name
this.age = age
}
Person.prototype.setName = function(name) {
this.name = name
}
var p1 = new Person('Tom', 12)
p1.setName('Jordan')
console.log(p1)
console.log(p1.name, p1.age) // Jordan 12
var p2 = new Person('jack', 12)
p1.setName('cat')
console.log(p2)
console.log(p1.__proto__ === p2.__proto__) // true
如下图解原型链