JavaScript它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分(ES6之前),全靠一种很奇特的"原型链"(prototype chain)模式,来实现继承,在学习原型和原型链之前我们先介绍一下’构造函数’
1.构造函数(constructor)
构造函数其实就是普通的 函数,只不过我们为了一眼能看出这是一个构造函数,习惯函数名称都要首字母大写,调用方式有所不同需要用new关键字来调用,构造函数的目的就是为了做一个"模具"(创建自定义类),做蛋糕要有蛋糕的模具,写代码也是一样,具有相同方法和属性的代码用这个模具生产(new)一个就可以了,而不需要把所有的方法和属性在重新写一遍
<script>
function Animal(name, age) {//构造函数
this.name = name;//属性
this.age = age;//属性
this.say = function () {//方法
console.log(this.name);
}
}
var monkey = new Animal("猴子", 4);
monkey.say()//输出猴子
var dog = new Animal("狗子", 3);
dog.say()//输出狗子
</script>
结果输出:
通过以上输出结果可以看出,每new一个Animal()实例对象就会生成一个对应的Animal对象,对象里除了变化的属性(name,age),say这个方法是不会变的,那我们想每创建一个对象就添加一个重复的方法,这样是对资源的一种浪费,那我们应该吧这类方法放在一个地方,让每个实例对象都能访问到呢?解决这问题就需要我们知道原型(prototype)继续看下面文章
2.原型(prototype)
那么原型是什么呢? w3chool写到:所有 JavaScript 对象都从原型继承属性和方法。废话不多说,看题!!!
<script>
function Animal(name, age) {//构造函数
this.name = name;//属性
this.age = age;//属性
}
Animal.prototype.say = function () {//把say方法放到原型上
console.log(this.name);
}
Animal.prototype.isAnimal = true;//把isAnimal属性放到原型上
var monkey = new Animal("猴子", 4);
console.log(monkey)
monkey.say()//输出猴子
console.log(monkey.isAnimal)
var dog = new Animal("狗子", 3);
console.log(dog)
dog.say()//输出狗子
console.log(dog.isAnimal)
</script>
结果输出:
我们发现,say()方法和isAnimal属性不在每个new出的对象实例上,但是我们我们还能打印出来???
原型(prototype)其实就是一个公共的区域,所有同一个类创建的实例,都可以访问这个公共的区域(Animal.prototype),那我们避免重复创建相同的方法和属性就可以把这些相同的属性和方法创建到这个公共的区域中(Animal.prototype)看图
__proto__是什么?? 实例dog和monkey怎么就能访问到这个公共区域(Animal.prototype)了呢???
我们接着看下面"原型链"
3.原型链
__ proto __:
每个对象都有一个__proto__属性,这个属性是用来标识自己所继承的原型。也可以这么理解在对象实例创建的时候,通过new关键字调用函数时,JavaScript会把实例(如:dog)和Animal.prototype建立一个联系,这个联系就就是 __ proto __ ,并且把构造函数的prototype来实现继承构造函数prototype的所有属性和方法,将this绑定到实例上
constructor:
原型对象中有一个属性是constructor(构造函数),他很简单,就是指向函数对象(Animal( ))
补充上面结构图形
那么我们利用这两个属性(__ proto __和constructor)来实现继承效果 看题
// 动物
function Animal(name) {
this.name = name;
}
// 给动物添加方法
Animal.prototype.getInfo = function () {
console.log('我的名字是:' + this.name);
};
// 猫
function Cat(name, age) {
this.age = age;
Animal.call(this, name);
}
// 设置猫的原型为动物
Cat.prototype = new Animal();
//恢复构造函数为猫
Cat.prototype.constuctor=Cat;
// 给猫添加方法
Cat.prototype.getAge = function () {![在这里插入图片描述](https://img-blog.csdnimg.cn/20190622110602172.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI3MTE4ODk1,size_16,color_FFFFFF,t_70)
console.log('我的年龄是:' + this.age);
};
// 建立猫对象
var cat = new Cat('可爱的猫咪', 19);
cat.getInfo();
cat.getAge();
//建立动物对象
var animal = new Animal('动物');
animal.getInfo();
我们了解了继承那我直接往下说
上面那么个Animal( )结构图其实就是原型链的一部分,在JavaScript中万物皆对象,每个对象之间都是有联系的,他们依据 __ proto __,相互联系着,对象之间的继承关系,通过prototype对象指向父类的对象,这些一直到Object对象为止,这就是原型链,(你要说到Object再往上指向是啥?老子有一句名言,叫做天地万物生于有,有生于无 所以Object.prototype.proto==null)
当JavaScript引擎查找对象的属性时,先查找对象本身是否存在该属性,如果不存在,会在原型链__proto__上查找,但不会查找自身的prototype
祭出祖传图例
到此为止~~~~~~~~~~~~~~~~~~~~~~~~~~~~~