原型与原型链
什么是原型?
在声明定义函数时,函数都会有一个prototype
属性,这个属性就是一个指针,指向一个对象,而这个对象就是原型对象(简称原型)
原型的作用?
通过构造函数创建的实例对象,可以直接访问到构造函数的prototype
属性上(即原型对象)的属性和方法
什么是原型链?
对象有__proto__
属性, 属性值指向了当前的原型对象, 原型对象也是对象, 原型对象也有__proto__
属性,原型对象的__proto__
属性值指向了原型对象的原型对象, 这样一环套一环,形成的链式结构叫做原型链
原型链图解
原型链特点:
- 实例对象的隐式原型(
__proto__
)等于构造函数的显示原型(prototype
)
f1.__proto__ === Foo.prototype //true
- 所有的函数都是
Function
的实例,即函数都是通过new
Function
产生的
Foo.__proto__ === Function.prototype //true
Date.__proto__ === Function.prototype //true
Object.__proto__ === Function.prototype //true
Function
也是new
自己产生的,即Function
的隐式原型等于自己的显示原型
Function.__proto__ === Function.prototype //true
- 原型对象也是对象,所以原型对象也是
new
Object
产生的,即原型对象的隐式原型指向Object的显示原型
Foo.prototype.__proto__ === Objecct.prototype //true
Function.prototype.__proto__ === Objecct.prototype //true
Object
的原型,是原型链的尽头
Object.prototype.__proto__ === null //true
- 原型对象自带
constructor
,该属性指向当前的构造函数
Foo.prototype.constructor === Foo //true
Object.prototype.constructor === Object //true
Function.prototype.constructor === Function //true
注意点:
- 实例对象上只有
__proto__
属性 - 函数上有
prototype
属性和__proto__
属性 - 原型对象上有
constructor
属性和__proto__
属性
属性查找原则
- 首先在对象自身上来查找是否有该属性, 如果有, 就返回属性值.
- 如果没有, 就去对象的原型对象上来查找, 如果有, 就返回属性值.
- 如果也没有, 就沿着对象的原型链继续往上找, 直到Object.prototype, 如果有, 就返回属性值.
- 如果还没有, 返回undefined
简化记忆: 沿着对象的原型链往上找
注意点: 关键看对象上是否有该属性, 而不在乎其值是啥
属性设置原则
- 如果对象自身有该属性, 设置的话就是在修改操作, 只会影响到对象自身, 不会影响到原型和原型链上的属性.
- 如果对象自身没有该属性, 设置的话就是在给对象添加该属性, 只会影响到对象自身, 不会影响到原型和原型链上的属性.
简单记忆: 有就修改, 没有就添加
面试题:
function Person(name, age){
// ****有形参, 无实参, 形参是undefined*****
this.name = name;
this.age = age;
}
Person.prototype.name = "lw";
Object.prototype.gender = "male";
// 变化的点
var p = new Person();
console.log(p);
// p实例对象的原型链
// p ==> Person.prototype ==> Object.prototype ==> null;
console.log(p.name); // undefined ****
console.log(p.age); // undefined ****
console.log(p.gender); // male
console.log(p.sex); // undefined
function Person(name) {
// name ==> undefined
if (name) {
this.name = name;
}
}
Person.prototype.name = "ls";
Person.prototype.money = 100;
var p = new Person();
console.log(p);
// p实例对象自身没有name属性
console.log(p.name); // ls undefined
console.log(p.money); // 100 100
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() //a()
F.b() //b()
补充
instanceof
判断复杂数据的具体类型的原理是什么?
A intanceof B如果B的显示原型属性指向的对象在A的原型链上,则返回true,否则返回false
- instanceof的底层原理,手动实现一个instanceof
/*
封装一个instanceof的具体实现
参数:
A: 实例对象
B: 构造函数
返回值:true或者false
*/
function myInstanceof(A, B) {
// 判断A的数据类型,如果A是简单数据类型或者null,则直接返回false
var styleA = typeof A
if((styleA !== 'function' && styleA !== 'object') || styleA === null) {
return false
}
// 判断B构造函数的显示原型是否在A实例对象的隐式原型上
var protoA = A.__proto__
while(protoA !== null) {
if(protoA === B.prototype) {
return true
}
protoA = protoA.__proto__
}
return false
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。