参考文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
一、JavaScript 只有一种结构:对象。每个实例对象( object )都有一个私有属性(称之为 __proto__ )指向它的构造函数的原型对象(prototype )。
该原型对象也有一个自己的原型对象( __proto__ ) ,层层向上直到一个对象的原型对象为 null
。根据定义,null
没有原型,并作为这个原型链中的最后一个环节。几乎所有 JavaScript 中的对象都是位于原型链顶端的Object 的实例。
二、JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的
原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
示例 1
let f = function () {
this.a = 1;
this.b = 2;
}
console.log(f instanceof Function)//true
console.log(f.__proto__ ===Function.prototype)//true
let o = new f();
o是调用构造方法f,生成的实例
console.log(o instanceof f)//true
console.log(o.constructor ===f) // true
f.prototype.b = 3;
f.prototype.c = 4;
不要在 f 函数的原型上直接定义 f.prototype = {b:3,c:4};这样会直接打破原型链
console.log(o.a);
output:1 ,o的自身属性,值为1
console.log(o.b);
output:2 ,o的自身属性值为2,原型上的b会因为同名被遮蔽,成为属性遮蔽
console.log(o.c);
output:4 ,c并不是o的自身属性,当自身没有该属性时,就会往上一层的原型对象上找,
console.log(o.d);
outputundefind ,d不是o的自身属性,上层原型也没有,所以最后输出undefined
整个原型链如下
{a:1, b:2} ---> {b:3, c:4} ---> Object.prototype---> null
f其实Function对象的实例,所以f有__proto__私有属性指向其构造函数的原型对象
console.log(f.__proto__ ===Function.prototype)//true
同时,f又是一个函数,所以f也有prototype的属性
o.__proto__===f.prototype //true
实例o的__proto__指向f的prototype原型对象,f.prototype在这里应该当成f的原型
对象,而不应该当成f的prototype属性,尽管他们的值是一样的
示例2
var o = {a: 1};
var a = ["yo", "whadup", "?"]
var f = function f(){
return 2;
}
o的原型链o ---> Object.prototype ---> null
a的原型链a ---> Array.prototype ---> Object.prototype ---> null
f的原型链f ---> Function.prototype ---> Object.prototype ---> null
一个对象实例的__proto__指向了其原型对象,其原型对象的__proto__会一直向
上,Object.prototype.__proto__是null,这个实例会继承原型链中的方法
如 o指向了Object.prototype,那么o就有了Object.prototype中的方法
o.hasOwnProperty("a")//true,该方法只会查询实例自身,并不会遍历整个原型链
示例3 继承
"use strict";
class Animal{
static belong= "china";
flag = true;
constructor(age,name){
this.age = age;
this.name = name;
}
eat(){
console.log(this.age + "岁的"+ this.name + "会吃食");
}
static run(){console.log(this.name +"会跑")}
}
var o = new Animal(1,"猫");
o.sound = function sound(){console.log(this.name + "的叫声是喵喵")}
Animal.prototype.swim = function swim (){return this.name + "不会游泳"};
var x = new Animal(1,"鸡");
1、static修饰的变量或者方法,不属于实例,而是属于对象的构造函数的
o.constructor.run() === Animal.run() //true
2、没被static修饰的变量是会被实例继承的,如flag
o.hasOwnProperty("flag") === x.hasOwnProperty("flag")//true
3、没被static修饰的方法是属于Animal.prototype原型对象的,如eat
var y = Object.create(o);
以o的原型对象创建一个实例,实例y没有任何私有属性,o的私有属性及方法,以及继承来的
flag属性,都将作为y.__proto__的原型对象的方法和属性
class Bird extends Animal{
constructor(age ,name){
super(age,name)
}
get allParm(){return this.name + this.age}
set parm(newname){
this.name = newname
}
}
var a = new Bird(1,"小鸟");
Bird.prototype.bird = "飞";
1、a是Bird对象的实例,它指向的原型对象是Bird
a.__proto__===Bird.prototype //true
2、Bird对象中的get 和 set 都是属于Bird.prototype原型对象中的属性
3、Bird实例会继承Animal中非static修饰的变量
a.hasOwnProperty("flag") //true
示例4 protype与getPrototypeOf
var o = new Foo();
JavaScript 实际上执行的是:
var o = new Object();
o.__proto__ = Foo.prototype;
Foo.call(o);
o.someProp;
它检查 o 是否具有 someProp 属性。如果没有,它会查找
Object.getPrototypeOf(o).someProp,如果仍旧没有,它会继续查找
Object.getPrototypeOf(Object.getPrototypeOf(o)).someProp。
最后null没有原型对象,所以会返回undefined
Object.getPrototypeOf(o) === o.__proto__//true