原型(prototype) 、 类(class) 、 实例(instance)、继承、Object对象(相当于类)、原型链
当定义一个类的时候,就有他像对应的原型,如如没有显式继承一个指定类的时候,就默认原型是Object类的一个空实例(即没有任何属性)。
// 获取Panda默认原型(prototype)
let proto = Panda.prototype;
// 默认原型是Object类的一个空实例(即没有任何属性)
console.log( '默认原型: ', proto );
console.log( proto instanceof Object ); // true
可以通过 .type
给指定实例绑定一个名为 type 的属性(取值为字符串):
proto.type = '大熊猫';
也可给指定实例绑定一个名为 eat 的属性(取值为函数):
proto.eat = function(food) {
console.log(`${this.name}吃${food}`);
}
在JavaScript中可以通过 class 关键字来定义类,
// 用class关键字定义类
class Panda {
id = 1;
name = '大美';
constructor(){
console.log(this.id, this.name);
}
}
通过 new 构造函数()
形式创建实例(instance)。
let p = new Panda();
console.log( p );
console.log( 'id: ', p.id );
console.log( 'name: ', p.name );
console.log( 'type: ', p.type );
p.eat('胡萝卜');
用function关键字定义一个"对象"(实际上相当于类)。
function Panda() {
this.id = 1 ;
this.name = '大美';
console.log( 'id: ', this.id, 'name: ', this.name);
}
先确信一个对象(相当于类)
function Pot(name) {
this.name = name ;
}
之后通过 .constructor
给指定的对象获得对应原型上的constructor构造函数:
const cons = proto.constructor;
console.log( 'Pot.prototype.constructor: ', cons );
console.log( cons === Pot ); // true
之后通过构造函数来创建 Pot对象(相当于类)的实例,对于实例来说,可以通过从原型继承的constructor
属性获得创建该实例时使用的构造函数。
let p = new Pot('老王家的大铝锅');
console.log( p );
console.log( p.constructor );
通过 “对象字面量”(object literal) 创建实例 ,用function定义对象(相当于类)
const proto = {
type: '飞禽'
}
function Eagle(name) {
// 通过this关键字为当前新创建的实例绑定属性
this.name = name;
}
如果不显式指定原型,那么默认原型是 Object 类的一个空实例:
console.log( '修改前: ', Eagle.prototype );
可以通过 .prototype
替换指定对象对原型:直接讲一个实例赋值给prototype属性。
Eagle.prototype = proto;
之后便可以通话构造函数创建实例
let e = new Eagle('郅都');
console.log( e );
console.log( e.type );
也可以通过 .prototype.type
修改Lion对象
的原型: 动态为原型绑定属性
function Lion(name) {
this.name = name;
}
Lion.prototype.type = '走兽';
首先通过 用function定义对象(相当于类)。
function Animal() {
}
function Beast(name) {
this.name = name;
}
之后用Animal对象(相当于类)的实例替换Beast对象(相当于类)的默认原型
Beast.prototype = new Animal();
之后修改构造函数,通过 .prototype.constructor
让新原型的constructor属性指向当前构造函数。
Beast.prototype.constructor = Beast;
console.log( Beast.prototype.constructor );
之后可以通过 .prototype.
+属性 来扩展原型
Beast.prototype.type = '兽';
Beast.prototype.eat = function(food) {
console.log(`${this.name}吃${food}`);
}
而这个时候的Beast对象(相当于类)的每一个实例都从 Beast.prototype
继承属性
let b = new Beast('熊大');
console.log( b );
console.log( b.type );
b.eat('苹果');
let t = new Beast('熊二');
console.log( t );
console.log( t.type );
t.eat('蜂蜜');
首先通过class定义类:
class Animal extends Object {
constructor() {
// 只要通过extends显式继承了任何一个类,就建议显式调用父类构造
super();
}
}
注:不管显式继承哪一个类,建议显示调用父类构造,即 super()
。这样在之后使用 this 就不会报错
用class定义类并用extends显式指定直接父类
class Beast extends Animal {
constructor(name){
// 在子类构造中使用this之前或构造函数返回前必须首先调用父类构造
super(); // 用 super 可以调用父类构造函数
this.name = name;
}
eat(food) {
console.log(`${this.name}吃${food}`);
}
}
之后通过 .prototype.
+属性来修改Beast对象(相当于类)
的原型: 动态添加属性
Beast.prototype.type = '兽类';
之后每一个 Beast对象(相当于类)的每一个实例都从 Beast.prototype
继承属性
let b = new Beast('熊大');
console.log( b );
console.log( b.type ); // Betast.prototype.type
b.eat('苹果'); // Beast.prototype.eat
let t = new Beast('熊二');
console.log( t );
console.log( t.type ); // Betast.prototype.type
t.eat('蜂蜜'); // Beast.prototype.eat
可以通过调用 Object的类方法 获得 Object类上直接定义的所有类属性
let names = Object.getOwnPropertyNames( Object );
for(let i = 0 ; i < names.length; i++ ){
let name = names[i];
console.log(name);
}
以及调用 Object的类方法 获得 Object.prototype
上直接定义的所有属性名称
let names = Object.getOwnPropertyNames( Object.prototype );
for(let i = 0 ; i < names.length; i++ ){
let name = names[i];
console.log(name);
}
Object.prototype
上定义的属性:
hasOwnProperty(prop)
hasOwnProperty(prop)
hasOwnProperty(prop)
hasOwnProperty(prop)
hasOwnProperty(prop)
hasOwnProperty(prop)
通过追溯以及查看每个实例的原型,从而构造出来的,称作原型链。