配图是网上找的
构造函数创建对象:
function Person() {
}
var person = new Person();
person.name = 'Kevin';
console.log(person.name) // Kevin
// Person 就是一个构造函数,我们使用 new 创建了一个实例对象 person
prototype
每个函数都有一个 prototype 属性
每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个关联对象即原型(prototype),每一个对象都会从原型中”继承“属性
为了方便理解,将Person构造函数理解为类,将实例化person理解为对象,只有类拥有prototype
属性,而对象没有(这里只是个人为了方便理解的一种方式)
function Person() {
}
// prototype是函数才会有的属性
Person.prototype.name = 'Kevin';
Person.prototype.age = '24';
Person.sex = 'boy';
var person1 = new Person(); // 实例化
var person2 = new Person();
console.log(person1.name) // Kevin
console.log(person2.age) // 24 每一个成员都会继承原型中的所有属性
proto
每一个JavaScript实例对象(除了 null )都具有的一个属性proto,这个属性会指向该类的原型
对象拥有_proto_
属性,指向原型
function Person() {
}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true 实例化对象的proto属性等于原型
constructor
每个原型都有一个 constructor 属性指向关联的构造函数,实例原型指向构造函数
function Person() {
}
console.log(Person === Person.prototype.constructor); // true
图里没画上的线路:对象person可通过constructor
得到类Person
原型、类、对象
(这里只是个人为了方便理解的一种方式)
原型
可理解为该类拥有的属性,若一个类想要操作一个属性,不能直接进行操作,必须通过原型来进行(函数对象里声明的变量不是属性),即原型、类、对象的关系可以进一步缩减理解为类和对象之间的关系,原型只是对象拥有的属性,类和对象能通过一些方法(prototype、proto)来访问到这个属性
function Person() {
}
Person.prototype.name = 'Kevin'; // 通过原型
Person.sex = 'boy'; // 直接操作
console.log(Person.prototype) // Person { name: 'Kevin'}
console.log(Person.sex) // undefined 直接设置属性失败
console.log(Person.name) // undefined 直接读取属性失败
console.log(Person.prototype.name) // Kevin
类
声明对象功能并实例化一个对象
对象
每一个对象都拥有类的全部功能,当然也可拥有类的属性,而类的属性存放在原型,通过原型进行操作,因此当对象要拿到类属性,只能在原型中拿(当对象中添加了同名属性时,优先度对象>类),当对象中找不到指定属性时,才会往上层寻找
function Person() {
}
Person.prototype.name = 'Kevin';
var person = new Person();
person.name = 'Daisy';
console.log(person.name) // Daisy
delete person.name; // 删除成员person中刚添加的name属性
console.log(person.name) // Kevin
对象、类、原型、Object之间的关系
Object.prototype.age = '24';
function Person() {
}
var person = new Person();
Person.prototype.age_ = '23';
console.log(Person.prototype); // Person { age_: 23 }
console.log(Person.prototype.age) // 上面显示的是原型自己内部的属性,实际自己也继承了Object原型的age
console.log(Person.age); // 24
console.log(person.age_); // 23
可以分为两条链路理解:
Object原型 → Object类 → Object对象(Object成员即其他对象的原型)
原型 → 类 → 对象
这样的好处就是只需要记住原型、类、对象的关系三者之间固有的关系即可(加上记住其他类原型即Object三者关系中的对象)
完整的原型链
ES5和ES6
ES5中函数定义类:
function Foo(x,y) {
this.x = x;
this.y = y;
}
Foo.prototype.toString = function(){
console.log(this.x, this.y)
}
var foo = new Foo(1,2)
foo.toString()
// 1 2
ES6中定义类:
调用类的方法也就是调用原型(prototype)上的方法
class Foo {
constructor(x,y){
this.x = x;
this.y = y;
}
toString(){
console.log(this.x, this.y)
}
}
var foo = new Foo(1,2)
foo.toString()
// 1 2
ES6中,class实际上也是一个function对象,其原型链与es6一致,但有几点需要注意
constructor()
方法表示构造函数,与原型链中的.constructor
无关class Foo {
constructor(x,y){
this.x = x;
this.y = y;
}
toString(){
console.log(this.x, this.y)
}
}
Foo.prototype.name = 'Jack'
var foo = new Foo(1,2)
console.log(Foo) // Function: Foo]
console.log(foo) // Foo { x: 1, y: 2 }
console.log(Foo === foo.constructor) // true 成员访问对象 foo.__proto__.constructor
console.log(Foo.prototype) // Foo { name: 'Jack' } 对象访问原型
console.log(foo.__proto__) // Foo { name: 'Jack' } 成员访问原型