原型prototype
- 函数的prototype属性
- 每个函数都有一个prototype属性,它默认指向一个Object空对象(即称为:原型对象)
- 原型对象中有一个属性constructor,它指向函数对象
- 给原型对象添加属性(一般为方法)
- 作用:函数的所有实例对象自动拥有原型中的属性(方法)
console.log(Date.prototype, typeof Date.prototype) // Date在初始化时,已经添加了许多方法
function Fn() {}
console.log(Fn.prototype) // 默认指向一个Object空对象(没有开发者添加的属性)
Fn.prototype.test = function (){
console.log('test()')
}
console.log(Fn.prototype) // 此时Object中有了开发者添加的方法
// 原型对象中有一个属性constructor,它指向函数对象
console.log(Date.prototype.constructor === Date)
console.log(Fn.prototype.constructor === Fn)
// 给原型对象添加属性(一般为方法)=> 实例对象可以访问
var fn = new Fun()
fn.test() // test()
显式原型和隐式原型
- 每一个函数function都有显式原型,即prototype属性
- 每一个实例对象都有隐式原型,即__proto__属性
- 实例对象的隐式原型 指向 其对应函数的显式原型
function Fn() { // 内部语句:this.prototype = {}
// add some propert
}
// 1.每一个函数function都有显式原型,即prototype属性
console.log(Fn.prototype)
var fn = new Fn() // 内部语句:this.__proto__ = Fn.prototype
// 2. 每一个实例对象都有隐式原型,即__proto__属性
console.log(fn.__proto__)
// 3. 实例对象的隐式原型 **指向** 其对应函数的显式原型
console.log(fn.__proto__ === Fn.prototype) // true
// 给原型添加方法
Fn.prototype.test = function () {
console.log('test()')
}
fn.test() // test()
- 内存结构(图)
- 总结:
- 函数对象的prototype属性:在定义函数对象时自动添加,默认值是一个空object对象
- 实例对象的__proto__属性:在创建实例对象时自动添加,默认值是其构造函数的prototype属性值
- 开发者能直接操作显式原型,但不能直接操作隐式原型(ES6之前)
原型链
- 图解
-
访问一个对象的属性时
- 首先在自身属性中查找,找到返回
- 如果没有,再沿着__proto__这条链向上查找,找到返回
- 如果最终没找到,则返回undefined
-
别名:隐式原型链
-
作用:查找对象的属性(方法)
-
function Fn() {
this.test1 = function () {
console.log('test1()')
}
}
Fn.prototype.test2 = function () {
console.log('test2()')
}
var fn = new Fn()
fn.test1() // fn => 4 => test1
fn.test2() // fn => 4 => 5 => test2
console.log(fn.toString()) // fn => 4 => 5 => 8 => toString
fn.test3() // Error: fn.test3 is not a function
- 构造函数与实例对象的关系(图解)
- 所有函数的__proto__都是指向Function的原型对象
- 所有函数都是Function的实例,包括它本身
- 函数的显式原型指向的对象默认是空Object实例对象,但是函数对象Object指向的是null
- Object的原型对象是原型链尽头
// 引擎内部还会有以下两条语句
// Function = new Function()
// Function Object = new Function()
function Foo() { // 内部相当于 Function Foo = new Function()
// add some properties
}
// 函数的显式原型指向的对象默认是空Object实例对象,但是函数对象Object指向的是null
console.log(Foo.prototype instanceof Object) // true
console.log(Object.prototype instanceof Object) // false
console.log(Function.prototype instanceof Object) // true
// 所有函数都是Function的实例,包括它本身
console.log(Function.__proto__ === Function.prototype) // true
// Object的原型对象是原型链尽头
console.log(Object.prototype.__proto__) // null
属性问题
- 读取对象的属性值时:会自动到原型链中查找
- 设置对象的属性值时:不会查找原型链,如果当前对象中没有此属性,则直接添加此属性到对象中
- 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
function Fn() {
// add some properties
}
Fn.prototype.a = 'xxx'
var fn1 = new Fn()
console.log(fn1.a) // xxx
var fn2 = new Fn()
fn2.a = 'yyy' // 注意!此时添加到fn2实例对象的属性中
console.log(fn1.a) // xxx
console.log(fn2.a) // yyy
// 一般情况下,属性一般通过构造函数定义在对象本身上
function Person(name, age) {
this.name = name,
this.age = age
}
Person.prototype.setName = function(name) {
this.name = name
}
var p1 = new Person('Joshua', 22)
p1.setName('Bob')
console.log(p1)