另类继承实现方法
修改构造函数this指向从而实现继承
我们有时候可以借助call方法
来实现简单的继承效果!
举个栗子
function Animal(name,age,food){
this.username=name;
this.age=age;
this.eat=function (){
console.log('这只['+this.username+']动物要吃['+food+']');
}
}
Animal.prototype.color='黑色';
Animal.prototype.say=function (){
console.log('我的名字叫'+this.name);
}
function Panda(name,age,eat){
this.like='玩耍';
Animal.call(this,name,age,eat); //借用一下
}
var p1=new Panda('熊猫盼盼',18,'竹叶');
//打印输出
console.log(p1);
p1.eat();
结果
)
这个案例中,应用了call
修改this
指向来达到一个共享的目的!
但是这种使用call
等方法来修改this
严格意义上来讲,只能算借用!
因为这种方式有一个很大的缺点,就是不能继承
所谓父类
中原型
里面的属性
和方法
,不然你看上图,打印的结果当中并没有出现Animal类
原型对象中的color属性
和say方法
所以这种继承
方式如何和prototype
修改原型方式结合一起使用就会有意想不到的效果,并且参数的传递也会更加灵活多变!
举个栗子
//定义构造函数
function Person(userename,age,sex){
this.name=userename;
this.age=age;
this.sex=sex;
this.type='人类';
}
Person.prototype.say=function(){
console.log("hello world");
}
function Student(username,age,sex,score){
//借用Person构造函数
Person.call(this,username,age,sex);
//定义属性
this.score=score
}
//改变原型指向
Student.prototype=new Person();//不传值
Student.prototype.behavior=function(){
console.log("英语学习!!");
}
var s1=new Student("张三",15,"男","100分")
//打印结果看看
console.log(s1);
console.log(s1.type);
console.log(s1.name);
console.log(s1.age);
console.log(s1.sex);
console.log('考试得分:'+s1.score);
s1.behavior();
s1.say();
代码分析
从上面的代码中,我们可以看到构造函数Student
中我们借用了Person构造函数
, 然后在通过prototype
修改原型指向,这样一来,不仅可以获取到父类构造函数
中的属性和方法
也可以获取到父类原型对象
中的属性和方法
这时都可以通过__proto__
这个链条拿到!
如图
通过循环复制实现继承
我们的原型对象prototype
既然是一个对象
,那么我们也可以通过循环复制
的手法把父级原型对象
里面的属性和方法拷贝到目标原型对象
下,同时也可以结合call方法
借用构造函数
中的属性和方法
代码如下
function Person(username,age) {
this.name=username;
this.age=age;
}
Person.prototype.type = "人类";
Person.prototype.nationality = "中国";
Person.prototype.job = '软件开发';
Person.prototype.like = '足球,篮球,游戏';
Person.prototype.test = 123;
function Student(username,age) {
Person.call(this,username,age);
}
var per = Person.prototype;
var stu = Student.prototype;
//过滤不需要的属性
var arr=['type','nationality','test'];
for (k in per) {
if(arr.indexOf(k)==-1){
stu[k] = per[k];
}
}
var s1=new Student('李四',18);
var s2=new Student('王五',25);
console.log(s1);
console.log(s2);
如图
__proto__
的兼容性
根据MDN
官方的建议,其实__proto__
是被弃用了的!
那么到底我们平常使用什么来修改原型的指针呢?
在 JavaScript
中,你的确是可以通过直接修改实例对象
的 __proto__
属性来达到目的!
__proto__
是一个非标准的属性
,它在大多数的js
环境中都可以使用,包括浏览器
和Node.js
但是由于这个属性是非标准
的,它在一些环境中可能不可用,或者在未来的标准中可能会被弃用,也就是说虽然一些浏览器仍然支持__proto__
,但也许已从相关的web标准
中移除,也许正准备移除或者出于兼容性而保留!
__proto__浏览器兼容性如下表
所以如果可以的话我们尽量不使用__proto__
而改成其他,例如:Object.setPrototypeOf方法
举个栗子
让我们使用Object.setPrototypeOf
来实现一个简单的继承
代码如下
function Test(){
}
Test.prototype.company='重庆科技';
function Test2(){
}
Test2.prototype.num=100;
function Test3(){
}
Test3.prototype.username='张三';
//实现继承
Object.setPrototypeOf(Test2.prototype, Test.prototype);
Object.setPrototypeOf(Test3.prototype, Test2.prototype);
var t3=new Test3();
console.log(t3);
效果
再看一个案例!
const a = {
company : '重庆科技' };
const b = {
age: 33 };
const c = {
username: "张三" };
//实现继承
Object.setPrototypeOf(a, b);
Object.setPrototypeOf(b, c);
console.log(a);
console.log(a.username);
console.log(a.age);
console.log(a.company);
效果如下
所以我觉得可以的情况下,尽量使用标准的Object.setPrototypeOf方法
来实现继承
因为Object.setPrototypeOf方法
基本上被所有现代浏览器引擎所支持, 并且也允许动态地修改对象
的原型