类, 类的实例,类的构造函数,类的成员函数/类原型
1: 类: 具有相同类型的一类实例的逻辑描述;
2: 类的实例: 被构造函数出来的具有这个类的实例特征的一个表;
3: 类的成员函数: 完成对应的逻辑,通过this来操作不通的实例;
// “function Person”叫做类的构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
// “.get_age”叫做类的方法,又叫做类的成员函数
// 用 this 操作类的实例来完成特定的逻辑;
Person.prototype.get_age = function() {
return this.age;
}
Person.prototype.get_name = function() {
return this.name;
}
// end
var xiaoming = new Person("xiaoming", 12);
//new 函数的作用相当于手写了下面这样的一个表:
var my_person = {
//数据
name: "xxxxx",
age: 12,
//成员函数
__proto__: {
get_name: Person.prototype.get_name,
get_age: Person.prototype.get_age,
}
};
//“xiaohong”叫做类的实例
var xiaohong = new Person("xiaohong", 13);
var xiaotian = new Person("xiaotian", 13);
console.log(xiaotian);
console.log(xiaohong);
console.log(xiaoming);
xiaotian.get_name();
xiaoming.get_name();
xiaotian.get_name();
// xiaotian, xiaoming, xiaohong 者三个实例都有相同的结构:
// 1:每个人实例 都有 name, age,
// 2: 每个实例都有一个 (函数)方法get_name, get_age;
// 他们这三个实例,属于同一个类型;
// 或者说他们三个实例,都是Person类
// 把Person看作是一个类, xiaotian, xiaoming,xiaohong可以看作是类的 3个实例;
举一个例子:新建一个Enemy.js文件,写入
// 类
function Enemy(name, level) {
this.name = name;
this.level = level;
}
// “Enemy.prototype”这个表我们又把他叫做“类原型”;
Enemy.prototype.attack_player = function() {
console.log("attack_player", this);
}
// 类结束
module.exports = Enemy;
在 main.js 文件中
var Enemy = require("./Enemy")
var e1 = new Enemy("e1", 1);
e1.attack_player();
var e2 = new Enemy("e2", 2);
e2.attack_player();
继承
为何要用继承?
为了扩展“类的原型”,类的原型不需要构造函数里的实例
例1:继承机制: 猫的代码---> 波斯猫的代码(在猫的代码的基础上扩展波斯猫的代码
例2:敌人--> 扩展成特殊的敌人。在原来敌人的基础上--> 继承原来的代码, --> 再添加;
实现继承,例如:
- new 机制使得 Cat 的空表"__ proto __"被创建,并携带参数 name "Black Cat"
- 然后化身为函数 Cat 中的 this
- 接着被 .call 显式传递给函数 Animal 中的 this,并携带参数name "Black Cat"
- 执行函数 Animal,意味着向 Cat 表中添加和函数 Animal相同地 key 和 value
- 打印出 "Black Cat"
function Animal(name){
this.name = name;
this.showName = function(){
console.log(this.name);
}
}
function Cat(name){
Animal.call(this, name);
}
var cat = new Cat("Black Cat");
cat.showName();
// step1: 创建一个BossEnemy的构造函数;
function BossEnemy(name, level) {
--------------------------------------------------------------------------------
// 调用基类的构造函数
// 如何继承“构造函数里的成员”?
// new 一个 "BossEnemy",就是在表 BossEnemy 下新建一个类原型__proto__空表
// 因为在 new 机制下,函数 BossEnemy 下的 this,就是类原型__proto__空表
// 接着被 .call 显式传递给构造函数 Enemy,构造函数 Enemy 下的 this,就被传递为表 BossEnemy 下的类原型__proto__空表
// 执行构造函数 Enemy,将构造函数 Enemy 下的实例,添加到表 BossEnemy 下的类原型__proto__空表
// 又因为在 new 机制,会返回表 BossEnemy 下的类原型__proto__表
// 当 var boss = new BossEnemy("通天教主", 10) 时
// 意思是表 BossEnemy 下的类原型__proto__空表,携带着由参数name, level 分别传过来的 "通天教主", 10
// 被传入到构造函数 Enemy 中,执行的内容是向类原型__proto__空表里添加数据
// key = name,value = 参数name
// 所以最终返回的表,就是 attack_player Enemy { name: '通天教主', level: 10, blood: 100 }
Enemy.call(this, name, level) //这里的this 是 new BossEnemy() 的空表
// 如何扩展自己的成员?
this.blood = 100;
}
// step2: 把 Enemy 里面所有的原型方法,都复制过来;
// 注意:不能直接这样写。当我们修改BossEnemy.prototype原型的时候,同时也会修改到Enemy.prototype。
// 因为他们两个变量都指向同一个“表的实例”,所以要新建一个表
// BossEnemy.prototype = Enemy.prototype;
--------------------------------------------------------------------------------
// 如何继承“构造函数 Enemy 的表 prototype”?
// 写法1
BossEnemy.prototype = {};
for(var i in Enemy.prototype) {
BossEnemy.prototype[i] = Enemy.prototype[i];
}
// “规范的”写法2
// 通过下面这两行,var a 就相当于构造函数
// 要继承基类 Enemy.prototype,只继承 prototype。
// 如果直接 new 一个Enemy,除了继承它的 prototype
// 还会把函数 Enemy 里的数据(this.xxx) 全都拿过来。
var a = function() {}
//a.prototype 指向 Enemy.prototype
a.prototype = Enemy.prototype;
// 用 new 函数4个步骤,把类的原型 Enemy.prototype 复制到表__proto__中。
BossEnemy.prototype = new a(); // {__proto__: Enemy原型}
--------------------------------------------------------------------------------
// 如何扩展原型?
// 获取到原型以后,就继承了 Enemy 的原型方法;
BossEnemy.prototype.boss_attack = function() {
console.log("boss_attack");
}
var boss = new BossEnemy("通天教主", 10);
// 表的访问
boss.boss_attack();
boss.attack_player();
--------------------------------------------------------------------------------
// 重载
// 根据优先找到表 BossEnemy.prototype.attack_player 的,会把Enemy.prototype.attack_player 冲掉
BossEnemy.prototype.attack_player = function() {
//调用基类的 prototype
Enemy.prototype.attack_player.call(this);
// 这里的 this,还是 new BossEnemy 的表
console.log("BossEnemy get name");
return this.name;
}
boss.attack_player();
/*
打印出:
attack_player Enemy { name: '通天教主', level: 10, blood: 100 }
BossEnemy get name
*/
Class函数
javascript 没有类,继承语法的, new, this, 模拟,有些地方些了一个继承函数。这个Class函数,能帮我们得到新的类
function Class(class_desic) {
var new_class = function(name, level) {
if (class_desic.extend) { // 有基类
// 调用基类的构造函数
class_desic.extend.call(this, name, level);
}
// 加一个初始化的接口
if (class_desic.init) {
class_desic.init.call(this);
}
}
if (class_desic.extend) {
var a = function() {};
a.prototype = class_desic.extend.prototype;
new_class.prototype = new a();
}
else {
new_class.prototype = {};
}
for(var i in class_desic) {
if (i == "extend") {
continue;
}
new_class.prototype[i] = class_desic[i];
}
return new_class;
}
var BossEnemy2 = Class({
// 定义写死的关键字 extend 是继承自那个基类
extend: Enemy, // 对象的名字
init: function(){
},
boss_attack: function() {
},
add_blood: function() {
console.log("add_blood", this);
/*
这里的 this 指的也是 b2 的 this
b2 的实例显式的绑定过来
这里的 this 也是指后面调用的实例
*/
},
});
var b2 = new BossEnemy2("boss2", 1111);
console.log(b2);
b2.add_blood();
网友评论