资讯专栏INFORMATION COLUMN

JavaScript面向对象的程序设计——“对象继承”的注意要点

zhongmeizhi / 2897人阅读

摘要:如继承了这里就不必写该方法的主要优势就是可以在子类型构造函数中向超类型构造函数传递参数。以上原型式继承通常只是想让一个对象与另一个对象保持类似的情况下,原型式继承是完全可以胜任的。

继承

继承分为接口继承实现继承;接口继承只继承方法签名,实现继承则继承实际的方法;由于函数没有签名,所以ECMAScript 中没有接口继承,只能依靠原型链来实现实现继承。

原型链

基本思想是利用原型链让一个引用类型继承另一个引用类型的属性和方法:

如:Person2.prototype 是Person1.prototype 的继承,那么(“--->” 意为“指向”):

Person2.prototype - [[Prototype]] ---> Person1.prototype
Person2 - prototype ---> Person2
person2 - [[Prototype]] ---> Person2.prototype
//Person2.prototype 无 constructor

Person1.prototype - cunstructor ---> Person1
Person1 - prototype ---> Person1.prototype
person1 - [[Prototype]] ---> Person1.prototype
具体方法

具体如何继承呢:

function People(){}; //原始的
People.prototype.sayWorld = function(){
    return "World people"
};

function Person(){}; //继承的
Person.prototype = new People(); //这里应该注意要先继承
Person.prototype.sayNation = function(){ //然后再修改prototype
    return "Chinese people"
};

var person = new Person(); //实例
console.log(person.sayNation()); //Chinese people
console.log(person.sayWorld()); //World people

一定要注意!!!给原型添加方法的代码一定要放在替换原型的语句之后!!!

再举个例子:

function WorldPeople(){};
WorldPeople.prototype = {
    constructor: WorldPeople,
    color: "",
    say: function(){
        return "People in the Earth."
    },
    friends: ["Oliver","Alice","Troy"]
};

function Chinese(){};
Chinese.prototype = new WorldPeople();
Chinese.prototype.color = "yellow";
Chinese.prototype.say = function(){
    return "i am Chinese."
};

var person1 = new Chinese();

console.log(person1.friends.toString());
console.log(person1.color);
console.log(person1.say());    
/*
[Log] Oliver,Alice,Troy (repetition.html, line 163)
[Log] yellow (repetition.html, line 164)
[Log] i am Chinese. (repetition.html, line 165)
*/
确定原型和实例的关系

instanceof 操作符和insPrototypeOf() 方法即可,如:

console.log(person1 instanceof Object); //true;
console.log(person1 instanceof WorldPeople); //true;
console.log(person1 instanceof Chinese); //true;

console.log(Object.prototype.isPrototypeOf(person1)); //true
console.log(WorldPeople.prototype.isPrototypeOf(person1)); //true
console.log(Chinese.prototype.isPrototypeOf(person1)); //true
谨慎定义方法

一定要记得,给原型添加方法的代码一定要放在替换原型的语句之后!

还要记得,通过原型链实现继承时,不能使用字面两创建原型方法,因为这样会重写原型链!

原型链的问题

包含引用类型值的原型,该属性会被所有实例共享;

在创建子类型的实例时,不能向超类型的构造函数中传递参数;

对于第一种问题:

function People(){}
People.prototype.friends = ["Alice","Oliver"];

function Person(){};
Person.prototype = new People();

var person1 = new Person();
var person2 = new People();

person1.friends.push("Troy");

console.log(person1.friends);
console.log(person2.friends); //两者完全相同

有什么解决办法呢:

借用构造函数(不推荐使用)

被称为“借用构造函数”的技术或伪造对象或经典继承。如:

function People(){
    this.friends = ["Alice","Oliver"];
}

function Person(){
    People.call(this); //继承了People
}

//这里就不必写Person.prototype = new People()

var person1 = new Person();
var person2 = new Person();

person1.friends.push("Troy");

console.log(person1.friends); //["Alice", "Oliver", "Troy"]
console.log(person2.friends); //["Alice", "Oliver"]

该方法的主要优势就是可以在子类型构造函数中向超类型构造函数传递参数。

又如:

function SuperType(name){
    this.name = name;
}

function SubType(){
    SuperType.call(this,"Oliver"); //这里不仅仅继承了SuperType,而且还向它传递了参数
    this.age = 18;
}

var person = new SubType();
console.log(person.name); //Oliver
console.log(person.age); //18

由于函数不可复用等问题,不推荐使用。

组合继承(最常用的模式)

也叫做伪经典继承。如:

//不通用的属性
function SuperType(name){
    this.name = name;
    this.colors = ["Blue","Red","Black"];
}
//通用的方法
SuperType.prototype.sayName = function(){
    return (this.name);
};

//继承属性并新增属性
function SubType(name,age){
    SuperType.call(this,name);//继承属性
    this.age = age;//新增属性
}
//继承方法并新增方法
SubType.prototype = new SuperType();//继承方法
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){//新增方法
    return (this.age);
};

var person1 = new SubType("Oliver",18);
var person2 = new SubType("Troy",24);
person1.colors.pop();
console.log(person1.colors);
console.log(person2.colors);
console.log(person1.sayName() + person1.sayAge());
console.log(person2.sayName() + person2.sayAge());

/*
[Log] ["Blue", "Red"] (repetition.html, line 255)
[Log] ["Blue", "Red", "Black"] (repetition.html, line 256)
[Log] Oliver18 (repetition.html, line 257)
[Log] Troy24 (repetition.html, line 258)
*/

最常用的方法。再举个例子:

function People(name,age){
    this.name = name;
    this.age = age;
    this.friends = [];
}
People.prototype.friendsList = function(){
    document.write(this.friends.toString());
};

function Person(name,age,color,job){
    People.call(this,name,age);
    this.color = color;
    this.job = job;
}
Person.prototype = new People();
Person.prototype.constructor = Person;
Person.prototype.sayInfo = function(){
    document.write(this.name + this.age + this.color + this.job);
};

var person1 = new Person("Oliver",18,"yellow","Hero");
person1.friends.push("Alice");
person1.sayInfo(); //Oliver18yellowHero
person1.friendsList(); //Alice

var person2 = new Person("Troy",24,"White","Fighter");
person2.friends.push("Oliver","Islan");
person2.sayInfo(); //Troy24WhiteFighter
person2.friendsList(); //Oliver,Islan

平时用这个方法已经足够。又如:

function Cars(name){
    this.name = name;
    this.hasColor = ["blue","black"];
}
Cars.prototype.sayName = function(){
    console.log(this.name);
};

function Car(name,color){
    Cars.call(this,name);
    this.color = color;
}
Car.prototype = new Cars();
Car.prototype.constructor = Car;
Car.prototype.sayColor = function(){
    console.log(this.color);
};
var benz = new Car("Benz-C200","Black");
benz.hasColor.push("red");
benz.sayName();
benz.sayColor();
console.log(benz.hasColor);
var benz2 = new Car("Benz-C180","White");
benz2.hasColor.push("white");
benz2.sayName();
benz2.sayColor();
console.log(benz2.hasColor);    
/*
[Log] Benz-C200 (repetition.html, line 309)
[Log] Black (repetition.html, line 319)
[Log] ["blue", "black", "red"] (repetition.html, line 325)
[Log] Benz-C180 (repetition.html, line 309)
[Log] White (repetition.html, line 319)
[Log] ["blue", "black", "white"] (repetition.html, line 330)
*/

结合创建对象和继承对象,来一个比较吧:

重要!

重要!

重要!

//组合使用构造函数模式和原型模式-创建对象
function Person(name,age){
    this.name = name;
    this.age = age;
    this.friendsList = ["Alice","Islan"];
}
Person.prototype.friends = function(){
    console.log(this.friendsList.toString());
};

var person1 = new Person("Oliver",18);
var person2 = new Person("Troy",24);
person1.friendsList.pop();
person1.friends(); //Alice
person2.friends(); //Alice,Islan
//组合继承-继承对象
function Person(name,age){
    this.name = name;
    this.age = age;
    this.friendsList = ["Alice","Islan"];
}
Person.prototype.friends = function(){
    console.log(this.friendsList.toString());
};
function Info(name,age,job){
    Person.call(this,name,age);
    this.job = job;
}
Info.prototype = new Person();
Info.prototype.constructor = Info;
Info.prototype.sayJob = function(){
    console.log(this.job);
};

var person1 = new Info("Oliver",18,"Master");
var person2 = new Info("Troy",24,"Hero");
person1.friendsList.pop();
person1.friends(); //Alice
person2.friends(); //Alice,Islan
person1.sayJob(); //Master
person2.sayJob(); //Hero

对比一下,就可以看出,继承属性主要应用到call 操作符给超类型构造函数传递参数;而继承方法则要注意不可使用字面量语法。

以上

原型式继承

通常只是想让一个对象与另一个对象保持类似的情况下,原型式继承是完全可以胜任的。共享相应的引用类型的值的属性。

语法是:

function object(o){
    function F(){};
    F.prototype = o;
    return new F();
}

如:

function object(o){
    function F(){};
    F.prototype = o;
    return new F();
}

var person = {
    name: "Oliver",
    friends: ["Alice","Islan"]
};

var anotherPerson = object(person);
anotherPerson.name = "Troy";
anotherPerson.friends.push("Ellen");

var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Ellen";
yetAnotherPerson.friends.push("Troy","Oliver");

console.log(person.friends);

又如:

function object(o){
    function F(){};
    F.prototype = o;
    return new F();
}

var person = {
    name: "Oliver",
    friends: ["Alice","Islan"]
};

var anotherPerson = object(person);
anotherPerson.name = "Troy";
anotherPerson.friends.push("Oliver");

console.log(person.friends);["Alice", "Islan", "Oliver"]

这种方法比较简单,只是想让person 和anotherPerson 保持类似并共享引用类型的值的属性。

寄生式继承(不能做到函数复用而导致效率降低)

创建一个封装继承过程的函数而已:

function createAnotherObj(obj){
    var clone = obj;
    clone.sayHi = function(){
        console.log("hi");
    };
    return clone;
}

var person = {
    name: "Troy",
    friends: ["Alice"]
};

var anotherObj = createAnotherObj(person);
anotherObj.sayHi();
anotherObj.name = "Oliver";
anotherObj.friends.push("Ellen");
console.log(person.friends);
console.log(anotherObj.friends); //两个完全一样
寄生组合式继承(最理想的继承范式)

基本逻辑就是首先创建一个超类型原型的一个副本;然后为副本添加constructor 属性;最后把副本赋值给子类型的原型。如:

function inheritPrototype(SubType,SuperType){
    var prototype = Object(SuperType.prototype);
    prototype.constructor = SubType;
    SubType.prototype = prototype;
}

function SuperType(name){
    this.name = name;
    this.color = ["red","yellow"];
}
SuperType.prototype.list = function(){
    console.log(this.color.toString());
};

function SubType(name,age){
    SuperType.call(this,name);
    this.age = age;
}
inheritPrototype(SubType,SuperType);
SubType.prototype.sayName = function(){
    console.log(this.name);
};

var type1 = new SubType("Oliver",18);
var type2 = new SubType("Troy",24)
type2.color.pop();
type1.list(); //red,yellow
type2.list(); //red

应该常用这种模式,比较完善。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86266.html

相关文章

  • JavaScript面向对象

    摘要:构造函数的两个特征函数内部使用了,指向所要生成的对象实例。将一个空对象的指向构造函数的属性,这个对象就是要返回的实例对象。用面向对象开发时,把要生成的实例对象的特有属性放到构造函数内,把共有的方法放到构造函数的里面。 JS中面向对象的概念 面向对象OOP是一种组织代码结构、实现功能过程的思维方式。它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的...

    Eirunye 评论0 收藏0
  • JavaScript面向对象程序设计——“对象基本概念”注意要点

    摘要:描述符对象就是上面提到的个描述其行为的特性和。真是奇怪读取属性的特征使用的方法,可以取得给定属性的描述符。接收两个参数所在的对象和要读取其描述符的属性名称。 对象的基本概念 面向对象(Object-Oriented,OO),的语言最大的特征就是它们都有类的概念,通过类可以创建任意多个具有相同属性和方法的对象。 创建自定义对象最简单的方式就是创建一个Object 的实例,然后再给他添加属...

    HmyBmny 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    李昌杰 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    Lyux 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    AaronYuan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<