原型与原型链
- 所有函数都有一个特别的属性:
prototype
: 显式原型属性
- 所有实例对象都有一个特别的属性:
__proto__
: 隐式原型属性
- 显式原型与隐式原型的关系
- 函数的
prototype
: 定义函数时被自动赋值, 值默认为{}, 即用为原型对象 - 实例对象的
__proto__
: 在创建实例对象时被自动添加, 并赋值为构造函数的prototype
值 - 原型对象即为当前实例对象的父对象
- 函数的
- 原型链
- 所有的实例对象都有
__proto__
属性, 它指向的就是原型对象 - 这样通过
__proto__
属性就形成了一个链的结构---->原型链 - 当查找对象内部的属性/方法时, js引擎自动沿着这个原型链查找
- 当给对象属性赋值时不会使用原型链, 而只是在当前对象中进行操作
- 所有的实例对象都有
原型 prototype
在JavaScript中,每当定义一个函数数据类型(普通函数、类)时候,都会天生自带一prototype属性
,这个属性指向函数的原型对象,并且这个属性是一个对象数据类型的值。
- 函数的prototype属性(图)
- 每个函数都有一个
prototype
属性, 它默认指向一个Object空对象
(即称为: 原型对象) - 原型对象中有一个属性
constructor
, 它指向函数对象
- 每个函数都有一个
// 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
console.log(Date.prototype, typeof Date.prototype)
function Fun () {//alt + shift +r(重命名rename)
}
console.log(Fun.prototype) // 默认指向一个Object空对象(没有我们的属性)
// 原型对象中有一个属性constructor, 它指向函数对象
console.log(Date.prototype.constructor===Date)
console.log(Fun.prototype.constructor===Fun)
- 给原型对象添加属性(一般都是方法)
- 作用: 函数的所有实例对象自动拥有原型中的属性(方法)
//给原型对象添加属性(一般是方法) ===>实例对象可以访问
Fun.prototype.test = function () {
console.log('test()')
}
var fun = new Fun()
fun.test()
显示原型和隐式原型
- 每个函数function都有一个
prototype
,即显式原型(属性) - 每个实例对象都有一个
__proto__
,可称为隐式原型(属性) - 对象的隐式原型的值为其对应构造函数的显式原型的值
- 内存结构(图)
- 总结:
- 函数的
prototype
属性: 在定义函数时自动添加的, 默认值是一个空Object对象 - 对象的
__proto__
属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值 - 程序员能直接操作显式原型, 但不能直接操作隐式原型(ES6之前)
//定义构造函数
function Fn() { // 内部语句: this.prototype = {}
}
// 1. 每个函数function都有一个prototype,即显式原型属性, 默认指向一个空的Object对象
console.log(Fn.prototype)
// 2. 每个实例对象都有一个__proto__,可称为隐式原型
//创建实例对象
var fn = new Fn() // 内部语句: this.__proto__ = Fn.prototype
console.log(fn.__proto__)
// 3. 对象的隐式原型的值为其对应构造函数的显式原型的值
console.log(Fn.prototype===fn.__proto__) // true
//给原型添加方法
Fn.prototype.test = function () {
console.log('test()')
}
//通过实例调用原型的方法
fn.test()
constructor
每个原型都有一个constructor属性,指向该关联的构造函数。
function Person() {
}
console.log(Person===Person.prototype.constructor) //true
var person = new Person();
console.log(person.__proto__ == Person.prototype) // true
console.log(Person.prototype.constructor == Person) // true
原型链
在JavaScript中万物都是对象,对象和对象之间也有关系,并不是孤立存在的。对象之间的继承关系,在JavaScript中是通过prototype对象指向父类对象,直到指向Object对象为止,这样就形成了一个原型指向的链条,专业术语称之为原型链。
举例说明:person → Person → Object ,普通人继承人类,人类继承对象类
- 原型链(图解)
- 访问一个对象的属性时,
- 先在
自身属性
中查找,找到返回 - 如果没有, 再沿着
__proto__
这条链向上查找, 找到返回 - 如果最终没找到, 返回undefined
- 先在
- 别名: 隐式原型链
- 作用: 查找对象的属性(方法)
-
构造函数/原型/实体对象的关系(图解)
-
构造函数/原型/实体对象的关系2(图解)
-
我们可以使用对象的
hasOwnProperty()
来检查对象自身
中是否含有该属性; -
使用
in
检查对象中是否含有某个属性时,如果对象中没有但是原型中有
,也会返回true
function Person() {}
Person.prototype.a = 123;
Person.prototype.sayHello = function () {
alert("hello");
};
var person = new Person()
console.log(person.a)//123
console.log(person.hasOwnProperty('a'));//false
console.log('a'in person)//true
// console.log(Object)
//console.log(Object.prototype)
console.log(Object.prototype.__proto__)
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)
// 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
原型链属性问题
读取
对象的属性值时: 会自动到原型链中查找设
置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值- 方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上
function Fn() {
}
Fn.prototype.a = 'xxx'
var fn1 = new Fn()
console.log(fn1.a, fn1) // xxx, Fn{}
var fn2 = new Fn()
fn2.a = 'yyy'
console.log(fn1.a, fn2.a, fn2) // xxx , yyy , Fn{a:'yyy'}
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('Bob')
console.log(p1) //Person {name: "Bob", age: 12}
var p2 = new Person('Jack', 12)
p2.setName('Cat')
console.log(p2) //Person {name: "Cat", age: 12}
console.log(p1.__proto__===p2.__proto__) // true
instanceof
1. instanceof是如何判断的?
- 表达式: A instanceof B
- 左边的对象是否为右边类型的实例
- 如果B函数的显式原型
prototype
对象在A对象的隐式原型链__proto__
上, 返回true, 否则返回false
2. 手写instanceof
function myInstanceOf(a,b){
let left = a.__proto__;
let right = b.prototype;
while(true){
if(left == null){
return false
}
if(left == right){
return true
}
left = left.__proto__
}
}
3. Function是通过new自己产生的实例
function Foo() { }
var f1 = new Foo()
console.log(f1 instanceof Foo) // true
console.log(f1 instanceof Object) // true
console.log(Object instanceof Function) // true
console.log(Object instanceof Object) // true
console.log(Function instanceof Function) // true
console.log(Function instanceof Object) // true
function Foo() {}
console.log(Object instanceof Foo) // false
练习
function A () {
}
A.prototype.n = 1
var b = new A()
A.prototype = {
n: 2,
m: 3
}
var c = new A()
console.log(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() //找不到,会报错
F.a()
F.b()
console.log(f)
console.log(Object.prototype)
console.log(Function.prototype)