【美高梅开户网址】成立对象的情势与继承的两种艺术,理一理js中令人抓狂的目的

深入解读 JavaScript 中的面向对象编程

2017/07/07 · JavaScript
·
面向对象

初稿出处: 景庄   

面向对象编程是用抽象格局开创基于现实世界模型的一种编程方式,首要不外乎模块化、多态、和包裹两种技术。
对 JavaScript
而言,其主干是支撑面向对象的,同时它也提供了精锐灵活的基于原型的面向对象编程能力。
本文将会深深的钻探关于使用 JavaScript
举行面向对象编程的局部基本基础知识,包蕴对象的始建,继承机制,
说到底还会简单的牵线如何依靠 ES6
提供的新的类机制重写传统的JavaScript面向对象代码。

深深解读JavaScript面向对象编程实践

2016/03/14 · JavaScript
· 4 评论 ·
面向对象

原文出处:
景庄(@ali景庄)   

面向对象编程是用抽象格局开创基于实际世界模型的一种编程情势,首要概括模块化、多态、和打包三种技术。对JavaScript而言,其要旨是帮衬面向对象的,同时它也提供了强有力灵活的依照原型的面向对象编程能力。

本文将会深入的探究关于使用JavaScript进行面向对象编程的片段中坚基础知识,包蕴对象的创办,继承机制,最终还会不难的牵线怎么着借助ES6提供的新的类机制重写传统的JavaScript面向对象代码。

实质上要总计那多少个概念已经很久了,只是从前平素都觉着温馨还不算完全控制,而且知识点还不够系统,所以直接拖着,不过近日又重新看了几篇小说,自己也测试了弹指间,觉得始于有些清晰了,所以想在此间给自己做个计算吧,也期望在学的你们可以在那里学到一点东西。不要浮躁,逐步看,一边看一边做测试,那也是我多年来的感悟。看了不必然会,要实在自己入手去测试一下。

1.js创制对象的二种方法

面向对象的多少个概念

在进入正题前,先了解传统的面向对象编程(例如Java)中常会涉嫌到的定义,大致可以概括:

  • 类:定义对象的风味。它是目的的特性和章程的模板定义。
  • 对象(或称实例):类的一个实例。
  • 属性:对象的特性,比如颜色、尺寸等。
  • 艺术:对象的一言一行,比如行走、说话等。
  • 构造函数:对象初叶化的一刹那被调用的艺术。
  • 继承:子类能够继续父类的风味。例如,猫继承了动物的形似特性。
  • 包装:一种把多少和连锁的章程绑定在一道利用的措施。
  • 架空:结合复杂的接轨、方法、属性的靶子可以模拟现实的模子。
  • 多态:分裂的类可以定义相同的办法或性质。

在 JavaScript
的面向对象编程中大概也囊括那一个。但是在称呼上恐怕稍有两样,例如,JavaScript
中从不原生的“类”的概念,
而只有对象的定义。因而,随着你认识的深深,大家会混用对象、实例、构造函数等概念。

面向对象的多少个概念

在进入正题前,先掌握传统的面向对象编程(例如Java)中常会波及到的概念,大约可以蕴涵:

  • 类:定义对象的特点。它是目的的质量和办法的沙盘定义。
  • 目标(或称实例):类的一个实例。
  • 特性:对象的特征,比如颜色、尺寸等。
  • 主意:对象的表现,比如行走、说话等。
  • 构造函数:对象开首化的一眨眼间间被调用的方法。
  • 一连:子类可以再三再四父类的特点。例如,猫继承了动物的一般特性。
  • 包裹:一种把数量和连锁的章程绑定在同步利用的措施。
  • 泛泛:结合复杂的后续、方法、属性的目的可以模拟现实的模子。
  • 多态:不相同的类可以定义相同的办法或性质。

在JavaScript的面向对象编程中大致也囊括那几个。但是在号称上可能稍有不一致,例如,JavaScript中并未原生的“类”的概念,
而只有对象的定义。由此,随着你认识的长远,我们会混用对象、实例、构造函数等概念。

怎么是目的?

我的驾驭就是这是一个存储灌,你能够在内部储存任何事物,这一个事物就是咱们从前学的各个js里面的数据类型,然后给每一个名字贴上一个名字,方便大家以后找到。

例子:

//这个myFirstObject里面有两个属性,分别是firstName和 favoriteAuthor
var myFirstObject = {firstName: "Richard", favoriteAuthor: "Conrad"};

工厂方式

对象(类)的创建

在JavaScript中,大家日常可以接纳构造函数来创建特定项目的对象。诸如
Object 和 Array
这样的原生构造函数,在运行时会自动出现在推行环境中。其它,大家也足以创设自定义的构造函数。例如:

JavaScript

function Person(name, age, job) { this.name = name; this.age = age;
this.job = job; } var person1 = new Person(‘Weiwei’, 27, ‘Student’); var
person2 = new Person(‘Lily’, 25, ‘Doctor’);

1
2
3
4
5
6
7
function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
}
var person1 = new Person(‘Weiwei’, 27, ‘Student’);
var person2 = new Person(‘Lily’, 25, ‘Doctor’);

听从惯例,构造函数始终都应当以一个大写字母初步(和Java中定义的类一样),普通函数则小写字母开头。
要创建 Person 的新实例,必须运用
new
操作符。
以那种方法调用构造函数实际上会经历以下4个步骤:

  1. 【美高梅开户网址】成立对象的情势与继承的两种艺术,理一理js中令人抓狂的目的。创制一个新对象(实例)
  2. 将构造函数的法力域赋给新对象(也就是重设了this的指向,this就针对了这些新目标)
  3. 实践构造函数中的代码(为那一个新目标添加属性)
  4. 回去新对象

在上头的例子中,大家创制了 Person 的四个实例 person1person2

那三个对象默许都有一个 constructor 属性,该属性指向它们的布局函数
Person,也就是说:

JavaScript

console.log(person1.constructor == Person); //true
console.log(person2.constructor == Person); //true

1
2
console.log(person1.constructor == Person);  //true
console.log(person2.constructor == Person);  //true

对象(类)的创建

在JavaScript中,咱们一般可以运用构造函数来创制特定类型的目的。诸如Object和Array那样的原生构造函数,在运作时会自动出现在举办环境中。
除此以外,大家也可以成立自定义的构造函数。例如:

function Person(name, age, job) { this.name = name; this.age = age;
this.job = job; } var person1 = new Person(‘Weiwei’, 27, ‘Student’); var
person2 = new Person(‘Lily’, 25, ‘Doctor’);

1
2
3
4
5
6
7
8
function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
}
 
var person1 = new Person(‘Weiwei’, 27, ‘Student’);
var person2 = new Person(‘Lily’, 25, ‘Doctor’);

依据惯例,构造函数始终都应该以一个大写字母开始(和Java中定义的类一样),普通函数则小写字母初叶。
要创建Person的新实例,必须选取new操作符。以那种办法调用构造函数实际上会经历以下4个步骤:

  1. 创造一个新目的(实例)
  2. 将构造函数的功力域赋给新目的(也就是重设了this的指向,this就本着了那个新目标)
  3. 实施构造函数中的代码(为这一个新对象添加属性)
  4. 重回新对象

有关new操作符的更加多内容请参见那篇文档。

在上头的例子中,我们创设了Person的三个实例person1person2
那五个对象默许都有一个constructor特性,该属性指向它们的构造函数Person,也就是说:

console.log(person1.constructor == Person); //true
console.log(person2.constructor == Person); //true

1
2
console.log(person1.constructor == Person);  //true
console.log(person2.constructor == Person);  //true

哪些定义一个对象?

  • 目的字面量
  • 构造函数创造
  • 原型情势开创

缘何会发生工厂方式,原因是拔取同一个接口成立很多对象,会生出大批量的重复代码,为了缓解那几个难题,发生了工厂格局。

自定义对象的档次检测

我们可以动用instanceof操作符举行项目检测。我们成立的享有目的既是Object的实例,同时也是Person的实例。
因为具有的靶子都无冕自Object

JavaScript

console.log(person1 instanceof Object); //true console.log(person1
instanceof Person); //true console.log(person2 instanceof Object);
//true console.log(person2 instanceof Person); //true

1
2
3
4
console.log(person1 instanceof Object);  //true
console.log(person1 instanceof Person);  //true
console.log(person2 instanceof Object);  //true
console.log(person2 instanceof Person);  //true

自定义对象的种类检测

我们可以使用instanceof操作符进行项目检测。大家创造的具有目的既是Object的实例,同时也是Person的实例。
因为拥有的目的都蝉联自Object

console.log(person1 instanceof Object); //true console.log(person1
instanceof Person); //true console.log(person2 instanceof Object);
//true console.log(person2 instanceof Person); //true

1
2
3
4
console.log(person1 instanceof Object);  //true
console.log(person1 instanceof Person);  //true
console.log(person2 instanceof Object);  //true
console.log(person2 instanceof Person);  //true
对象字面量创制对象

那是最原始的点子,不过也不便于前面的多少个对象的创立。

//这是一个mango对象,这个对象里面有color shape sweetness属性以及一个​howSweetAmI的方法
​var mango = {
color: "yellow",
shape: "round",
sweetness: 8,
​
​howSweetAmI: function () {
console.log("Hmm Hmm Good");
}
}

function createPerson(name,age,job){

构造函数的标题

我们不提议在构造函数中一向定义方法,如果那样做的话,每个方法都要在每个实例上再也创造一回,那将极度损耗品质。
——不要忘了,ECMAScript中的函数是目的,每定义一个函数,也就实例化了一个对象。

侥幸的是,在ECMAScript中,大家可以依靠原型对象来化解那一个难点。

构造函数的题材

我们不指出在构造函数中一贯定义方法,若是这么做的话,每个方法都要在各样实例上再也创设两次,那将这几个损耗质量。
——不要忘了,ECMAScript中的函数是目的,每定义一个函数,也就实例化了一个目的。

有幸的是,在ECMAScript中,我们可以依靠原型对象来解决那几个题材。

缺点:那种情势纵然简单明了,不过试想一下,要是大家要定义种种各种的水果对象,每一个水果都有color shape sweetnees的特性,大家都要一个个概念是或不是会稍稍麻烦呢?

那看看下边这种构造函数的开创方法

    var o=new Object();

借助原型情势定义对象的方法

大家创建的每个函数都有一个prototype属性,这么些特性是一个指针,指向该函数的原型对象
该目的涵盖了由特定项目标具有实例共享的属性和章程。也就是说,大家可以运用原型对象来让具有目的实例共享它所蕴含的属性和方法。

JavaScript

function Person(name, age, job) { this.name = name; this.age = age;
this.job = job; } // 通过原型格局来拉长所有实例共享的法门 // sayName()
方法将会被Person的持有实例共享,而防止了重新创造Person.prototype.sayName = function () { console.log(this.name); }; var
person1 = new Person(‘Weiwei’, 27, ‘Student’); var person2 = new
Person(‘Lily’, 25, ‘Doctor’); console.log(person1.sayName ===
person2.sayName); // true person1.sayName(); // Weiwei
person2.sayName(); // Lily

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
}
// 通过原型模式来添加所有实例共享的方法
// sayName() 方法将会被Person的所有实例共享,而避免了重复创建
Person.prototype.sayName = function () {
  console.log(this.name);
};
var person1 = new Person(‘Weiwei’, 27, ‘Student’);
var person2 = new Person(‘Lily’, 25, ‘Doctor’);
console.log(person1.sayName === person2.sayName); // true
person1.sayName(); // Weiwei
person2.sayName(); // Lily

正如上面的代码所示,通过原型方式定义的法门sayName()为有着的实例所共享。也就是,
person1person2访问的是同一个sayName()函数。同样的,公共性质也可以运用原型格局进行定义。例如:

JavaScript

function Chinese (name) { this.name = name; } Chinese.prototype.country
= ‘China’; // 公共性质,所有实例共享

1
2
3
4
function Chinese (name) {
    this.name = name;
}
Chinese.prototype.country = ‘China’; // 公共属性,所有实例共享

当我们new Person()时,返回的Person实例会构成构造函数中定义的特性、行为和原型中定义的属性、行为,
变迁最后属于Person实例的习性和表现。

构造函数中定义的品质和行事的预先级要比原型中定义的性质和表现的先期级高,假使构造函数和原型中定义了同名的特性或作为,
构造函数中的属性或作为会覆盖原型中的同名的性质或行为。

凭借原型情势定义对象的法子

大家创造的种种函数都有一个prototype品质,这一个特性是一个指南针,指向该函数的原型对象
该对象涵盖了由特定项目的富有实例共享的质量和艺术。也就是说,大家可以使用原型对象来让具有目标实例共享它所包蕴的属性和章程。

function Person(name, age, job) { this.name = name; this.age = age;
this.job = job; } // 通过原型情势来丰盛所有实例共享的主意 // sayName()
方法将会被Person的保有实例共享,而防止了重新创制Person.prototype.sayName = function () { console.log(this.name); }; var
person1 = new Person(‘Weiwei’, 27, ‘Student’); var person2 = new
Person(‘Lily’, 25, ‘Doctor’); console.log(person1.sayName ===
person2.sayName); // true person1.sayName(); // Weiwei
person2.sayName(); // Lily

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
}
 
// 通过原型模式来添加所有实例共享的方法
// sayName() 方法将会被Person的所有实例共享,而避免了重复创建
Person.prototype.sayName = function () {
  console.log(this.name);
};
 
var person1 = new Person(‘Weiwei’, 27, ‘Student’);
var person2 = new Person(‘Lily’, 25, ‘Doctor’);
 
console.log(person1.sayName === person2.sayName); // true
 
person1.sayName(); // Weiwei
person2.sayName(); // Lily

正如上边的代码所示,通过原型格局定义的法门sayName()为保有的实例所共享。也就是,
person1person2走访的是同一个sayName()函数。同样的,公共属性也得以选择原型形式展开定义。例如:

function Chinese (name) { this.name = name; } Chinese.prototype.country
= ‘China’; // 公共属性,所有实例共享

1
2
3
4
5
function Chinese (name) {
    this.name = name;
}
 
Chinese.prototype.country = ‘China’; // 公共属性,所有实例共享

考虑用构造函数的创建方法

构造函数创造方法,就是概念一个构造函数,然后在里面安装属性和办法值,然后再用new去实例化对象,所有实例化的靶子都会有构造函数里面的性质和措施。

//在这里定义一个构造函数,在构造函数里面定义属性和方法,注意这里需要用this,后面就可以通过new来实例化对象,使用new的时候,就会将this指向这个实例化的对象。

function Fruit (theColor, theSweetness, theFruitName, theNativeToLand) {
​    this.type = "水果"
    this.color = theColor;
    this.sweetness = theSweetness;
    this.fruitName = theFruitName;
    this.nativeToLand = theNativeToLand;
​
    this.showName = function () {
        console.log("This is a " + this.fruitName);
    }
​
    this.nativeTo = function () {
    this.nativeToLand.forEach(function (eachCountry)  {
       console.log("Grown in:" + eachCountry);
        });
    }

}

    o.name=name;

原型对象

前天我们来长远的了然一下哪些是原型对象。

一经成立了一个新函数,就会基于一组特定的条条框框为该函数创立一个prototype质量,这几个特性指向函数的原型对象。
在默认情状下,所有原型对象都会自行得到一个constructor属性,这几个特性包罗一个针对性prototype特性所在函数的指针。
也就是说:Person.prototype.constructor指向Person构造函数。

创办了自定义的构造函数之后,其原型对象默认只会收获constructor质量;至于其余艺术,则都是从Object连续而来的。
当调用构造函数创制一个新实例后,该实例之少将含有一个指针(内部属性),指向构造函数的原型对象。ES5中称这么些指针为[[Prototype]]
在Firefox、Safari和Chrome在种种对象上都帮忙一个品质__proto__(近日已被放弃);而在其他落成中,那些特性对台本则是一点一滴不可知的。
要注意,以此链接存在于实例与构造函数的原型对象之间,而不是实例与构造函数之间

那三者关系的示意图如下:

美高梅开户网址 1

上图浮现了Person构造函数、Person的原型对象以及Person幸存的四个实例之间的涉及。

  • Person.prototype本着了原型对象
  • Person.prototype.constructor又指回了Person构造函数
  • Person的每个实例person1person2都带有一个中间属性(平常为__proto__),person1.__proto__person2.__proto__针对了原型对象

原型对象

今昔大家来浓厚的了然一下怎么着是原型对象。

假使创制了一个新函数,就会根据一组特定的平整为该函数成立一个prototype特性,这么些特性指向函数的原型对象。
在默许情状下,所有原型对象都会自行获取一个constructor属性,这几个特性包蕴一个对准prototype特性所在函数的指针。
也就是说:Person.prototype.constructor指向Person构造函数。

始建了自定义的构造函数之后,其原型对象默许只会拿走constructor品质;至于其余艺术,则都是从Object继承而来的。
当调用构造函数创造一个新实例后,该实例之准将涵盖一个指南针(内部属性),指向构造函数的原型对象。ES5中称那个指针为[[Prototype]]
在Firefox、Safari和Chrome在每个对象上都帮助一个性质__proto__(如今已被抛弃);而在其他已毕中,这几个特性对台本则是一点一滴不可知的。
要注意,这些链接存在于实例与构造函数的原型对象之间,而不是实例与构造函数之间

那三者关系的示意图如下:

美高梅开户网址 2

上图彰显了Person构造函数、Person的原型对象以及Person现有的四个实例之间的涉嫌。

  • Person.prototype针对了原型对象
  • Person.prototype.constructor又指回了Person构造函数
  • Person的各类实例person1person2都包蕴一个中间属性(日常为__proto__),person1.__proto__person2.__proto__针对了原型对象

接下去,大家就足以一向用new的不二法门来创设各类种种的水果对象了。

//创建一个芒果的对象。
var mangoFruit = new Fruit ("Yellow", 8, "Mango", ["South America", "Central America", "West Africa"]);
mangoFruit.showName(); // This is a Mango.​
mangoFruit.nativeTo();
​//Grown in:South America​
​// Grown in:Central America​
​// Grown in:West Africa​
​
//创建一个pineappleFruit的对象。
​var pineappleFruit = new Fruit ("Brown", 5, "Pineapple", ["United States"]);
pineappleFruit.showName(); // This is a Pineapple.

是还是不是很有益,可以把构造函数想象成一个大工厂,然后你假若选择new的措施去调用那个工厂,就相当于告诉那么些工厂给自己生养一个东西出来,那么那几个工厂就会用所有自己有些设备,把它有着的东西能生产的都生产出来。所以一旦在这些工厂上的设施能生育出来的都会被生产。

再来思考一个标题,这几个实例化对象期间是还是不是实际上都是有相似性的,就是您可以提炼出其中同样的性能和艺术。像上边极度例子,所有水果的type属性和showName方法是或不是都是相同的呢?这我们是否足以用原型来写?

    o.age=age;

搜寻对象属性

从上图大家发现,纵然Person的四个实例都不带有属性和办法,但大家却足以调用person1.sayName()
那是通过寻找对象属性的经过来贯彻的。

  1. 搜寻首先从目的实例自身开首(实例person1sayName属性吗?——没有)
  2. 即使没找到,则持续查找指针指向的原型对象person1.__proto__sayName属性吗?——有)

那也是三个对象实例共享原型所保存的性质和格局的基本原理。

留神,如若大家在目的的实例中重写了某个原型中已存在的性质,则该实例属性会屏蔽原型中的这一个属性。
那时候,可以应用delete操作符删除实例上的性质。

查找对象属性

从上图我们发现,就算Person的三个实例都不带有属性和措施,但我们却得以调用person1.sayName()
那是通过寻找对象属性的长河来已毕的。

  1. 查找首先从目的实例自己发轫(实例person1sayName属性吗?——没有)
  2. 只要没找到,则一而再搜寻指针指向的原型对象person1.__proto__sayName属性吗?——有)

那也是多个目标实例共享原型所保存的习性和方法的基本原理。

小心,若是我们在目的的实例中重写了某个原型中已存在的习性,则该实例属性会屏蔽原型中的这一个属性。
这时候,能够使用delete操作符删除实例上的习性。

什么是原型?prototype

js中每一个函数都会有自己的一个原型对象,这一个原型对象叫做prototype.而具备通过那个构造函数实例化的靶子都会指向这么些原型。其实您可以考虑一下,构造函数是工厂的话,原型其实是否足以是堆栈,所有实例化的对象就可以从仓库里面拿东西。所以大家可以把持有目的公用的属性和措施给放在prototype上边,那样就可以幸免属性和艺术的再度定义。上面用一个例证和图来说美素佳儿(Friso)下。

//这里我们使用原型来创建对象,所有对象共用的属性和方法就放在prototype上。
function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
}

// 通过原型模式来添加所有实例共享的方法
// sayName() 方法将会被Person的所有实例共享,而避免了重复创建
Person.prototype.sayName = function () {
  console.log(this.name);
};

var person1 = new Person('Weiwei', 27, 'Student');
var person2 = new Person('Lily', 25, 'Doctor');
person1.sayName(); // Weiwei
person2.sayName(); // Lily

实例化的指标中的name age
job属性是从构造函数那获得的,而实例化的靶子的原型指向了构造函数的原型对象,所以也会有sayName方法。

image.png

//注意,那里是出口true,所以实际上person1和person2的sayName方法都是同一个,来自同一个地址。

console.log(person1.sayName === person2.sayName); // true

    o.job=job;

Object.getPrototypeOf()

根据ECMAScript标准,someObject.[[Prototype]] 符号是用以指派
someObject 的原型。
以此等同于 JavaScript 的 __proto__
属性(现已弃用,因为它不是正式)。
从ECMAScript 5开始, [[Prototype]]
可以用Object.getPrototypeOf()Object.setPrototypeOf()访问器来访问。

其中Object.getPrototypeOf()在具备协理的兑现中,那几个艺术再次回到[[Prototype]]的值。例如:

JavaScript

person1.__proto__ === Object.getPrototypeOf(person1); // true
Object.getPrototypeOf(person1) === Person.prototype; // true

1
2
person1.__proto__ === Object.getPrototypeOf(person1); // true
Object.getPrototypeOf(person1) === Person.prototype; // true

也就是说,Object.getPrototypeOf(p1)回去的对象实际就是这些目标的原型。
本条点子的包容性请参见该链接)。

Object.getPrototypeOf()

根据ECMAScript标准,someObject.[[Prototype]] 符号是用来指派
someObject 的原型。
本条等同于 JavaScript 的 __proto__ 属性(现已弃用)。
从ECMAScript 5开始, [[Prototype]]
可以用Object.getPrototypeOf()Object.setPrototypeOf()访问器来访问。

其中Object.getPrototypeOf()在具有辅助的完成中,那一个主意再次来到[[Prototype]]的值。例如:

person1.__proto__ === Object.getPrototypeOf(person1); // true
Object.getPrototypeOf(person1) === Person.prototype; // true

1
2
person1.__proto__ === Object.getPrototypeOf(person1); // true
Object.getPrototypeOf(person1) === Person.prototype; // true

也就是说,Object.getPrototypeOf(p1)回去的对象实际就是这几个目的的原型。
以此点子的包容性请参考该链接)。

微小计算一下:

对象有二种分裂的成立方式,对象字面量,构造函数,结合原型来创立,最可行的也就是第三种创立格局了,防止同一属性和方法的再次创设,所以可以将对象公用
的特性和措施定义在prototype上。

    o.sayName=function(){

Object.keys()

要博取对象上所有可枚举的实例属性,可以采纳ES5中的Object.keys()方法。例如:

JavaScript

Object.keys(p1); // [“name”, “age”, “job”]

1
Object.keys(p1); // ["name", "age", "job"]

其余,倘若你想要获得所有实例属性,无论它是或不是可枚举,都可以使用Object.getOwnPropertyName()方法。

Object.keys()

要博取对象上所有可枚举的实例属性,可以运用ES5中的Object.keys()方法。例如:

Object.keys(p1); // [“name”, “age”, “job”]

1
Object.keys(p1); // ["name", "age", "job"]

别的,假使您想要获得所有实例属性,无论它是还是不是可枚举,都可以应用Object.getOwnPropertyName()方法。

!!!!注意!!!!

若是使用原型继承的话,如若有四个目的和特性要同时一并定义的话,需求专注将原型prototype的constructor属性重新赋值,是或不是听不懂了,别急,先看率先个例子,再看大家后边改进的。

例子1

//这是我们定义水果的属性和方法
function Fruit () {
​
}
​//一个一个使用Fruit.prototype来一一定义各个属性和方法。
Fruit.prototype.color = "Yellow";
Fruit.prototype.sweetness = 7;
Fruit.prototype.fruitName = "Generic Fruit";
Fruit.prototype.nativeToLand = "USA";
​
Fruit.prototype.showName = function () {
console.log("This is a " + this.fruitName);
}
​
Fruit.prototype.nativeTo = function () {
            console.log("Grown in:" + this.nativeToLand);
}

上边的法门即便也是可行的,然而一旦属性和艺术太多的话,是还是不是太低效了。

更简约的原型成立方法:

function Fruit () {
​
}
​//一个一个使用Fruit.prototype来一一定义各个属性和方法。
Fruit.prototype= {
//这里一定要将prototype的constructor属性重新指向Fruit。因为我们这样相当于是重写了prototype的值。
constructor: Fruit,
color = "Yellow";
sweetness = 7;
fruitName = "Generic Fruit";
showName = function () {
console.log("This is a " + this.fruitName);
}
nativeTo = function () {
            console.log("Grown in:" + this.nativeToLand);
}
}

地方的例证看懂了吧?就是每一个构造函数的prototype属性都会自带有一个constructor属性,这么些constructor属性又针对了构造函数,所以大家像上边那样定义的时候,也要将以此constructor属性给重新指向构造函数。(可以重复看一下下边我付诸的不胜图)

    console.log(this.name);

更简约的原型语法

在上头的代码中,假设大家要添加原型属性和方式,就要重复的敲一回Person.prototype。为了减小那一个重复的进程,
更广大的做法是用一个分包所有属性和方法的对象字面量来重写整个原型对象。
参考资料。

JavaScript

function Person(name, age, job) { this.name = name; this.age = age;
this.job = job; } // 重写整个原型对象 Person.prototype = { //
那里不可不要重新将构造函数指回Person构造函数,否则会指向这几个新创造的目标constructor: Person, // Attention! sayName: function () {
console.log(this.name); } }; var person1 = new Person(‘Weiwei’, 27,
‘Student’); var person2 = new Person(‘Lily’, 25, ‘Doctor’);
console.log(person1.sayName === person2.sayName); // true
person1.sayName(); // Weiwei person2.sayName(); // Lily

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
}
// 重写整个原型对象
Person.prototype = {
  
  // 这里务必要重新将构造函数指回Person构造函数,否则会指向这个新创建的对象
  constructor: Person, // Attention!
  sayName: function () {
    console.log(this.name);
  }
};
var person1 = new Person(‘Weiwei’, 27, ‘Student’);
var person2 = new Person(‘Lily’, 25, ‘Doctor’);
console.log(person1.sayName === person2.sayName); // true
person1.sayName();  // Weiwei
person2.sayName();  // Lily

在上边的代码中特地包括了一个constructor特性,并将它的值设置为Person,从而确保了通过该属性可以访问到适合的值。
留神,以那种办法重设constructor属性会促成它的[[Enumerable]]特征设置为true。默许处境下,原生的constructor特性是不胜枚举的。
你可以行使Object.defineProperty()

JavaScript

// 重设构造函数,只适用于ES5匹配的浏览器
Object.defineProperty(Person.prototype, “constructor”, { enumerable:
false, value: Person });

1
2
3
4
5
// 重设构造函数,只适用于ES5兼容的浏览器
Object.defineProperty(Person.prototype, "constructor", {
  enumerable: false,
  value: Person
});

更不难的原型语法

在地点的代码中,假若我们要添加原型属性和艺术,就要重新的敲一遍Person.prototype。为了缩短这几个重复的历程,
更广阔的做法是用一个暗含所有属性和格局的靶子字面量来重写整个原型对象。
参考资料。

function Person(name, age, job) { this.name = name; this.age = age;
this.job = job; } Person.prototype = { //
那里不可不要双重将构造函数指回Person构造函数,否则会指向那一个新创设的靶子
constructor: Person, // Attention! sayName: function () {
console.log(this.name); } }; var person1 = new Person(‘Weiwei’, 27,
‘Student’); var person2 = new Person(‘Lily’, 25, ‘Doctor’);
console.log(person1.sayName === person2.sayName); // true
person1.sayName(); // Weiwei person2.sayName(); // Lily

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
}
 
Person.prototype = {
 
  // 这里务必要重新将构造函数指回Person构造函数,否则会指向这个新创建的对象
  constructor: Person, // Attention!
 
  sayName: function () {
    console.log(this.name);
  }
};
 
var person1 = new Person(‘Weiwei’, 27, ‘Student’);
var person2 = new Person(‘Lily’, 25, ‘Doctor’);
 
console.log(person1.sayName === person2.sayName); // true
 
person1.sayName();  // Weiwei
person2.sayName();  // Lily

在地点的代码中专门包括了一个constructor属性,并将它的值设置为Person,从而有限支持了通过该属性可以访问到相当的值。
小心,以那种措施重设constructor质量会招致它的[[Enumerable]]特性设置为true。默许意况下,原生的constructor质量是不胜枚举的。
您可以运用Object.defineProperty()

// 重设构造函数,只适用于ES5匹配的浏览器
Object.defineProperty(Person.prototype, “constructor”, { enumerable:
false, value: Person });

1
2
3
4
5
// 重设构造函数,只适用于ES5兼容的浏览器
Object.defineProperty(Person.prototype, "constructor", {
  enumerable: false,
  value: Person
});

什么读取对象的性能:

// We have been using dot notation so far in the examples above, here is another example again:​
​var book = {title: "Ways to Go", pages: 280, bookMark1:"Page 20"};
​
​// To access the properties of the book object with dot notation, you do this:​
console.log ( book.title); // Ways to Go​
console.log ( book.pages); // 280


//当然,也可以用方括号来写:
console.log ( book["title"]); //Ways to Go​
console.log ( book["pages"]); // 280​

   }

重组使用构造函数格局和原型形式

成立自定义类型的最广大方法,就是组成使用构造函数方式与原型方式。构造函数格局用于定义实例属性,
而原型格局用于定义方法和共享的性质。结果,每个实例都会有投机的一份实例属性的副本,但与此同时又共享着对方的引用,
最大限度的节约了内存。

组合使用构造函数形式和原型方式

创设自定义类型的最普遍方法,就是整合使用构造函数情势与原型形式。构造函数方式用于定义实例属性,
而原型格局用于定义方法和共享的习性。结果,每个实例都会有投机的一份实例属性的副本,但与此同时又共享着对方的引用,
最大限度的节约了内存。

哪些促成目的的连续:

  • 原型继承
  • 构造函数继承
  • 原型和构造函数继承
  • 开创空对象方法

原型继承:

  • 构造函数都有一个对准原型对象的指针
  • 原型对象都有一个对准构造函数的constructor
  • 实例化对象都有一个针对原型的[[prototype]]属性

function Father () {
  this.fatherValue = true;
}

Father.prototype.getFatherValue = function () {
  console.log(this.fatherValue);
};

function Child () {
  this.childValue = false;
}

// 实现继承:继承自Father
Child.prototype = new Father();

Child.prototype.getChildValue = function () {
  console.log(this.childValue);
};

var instance = new Child();
instance.getFatherValue(); // true
instance.getChildValue();  // false

地点的关键点就是用“`Child.prototype = new Father();

![image.png](http://upload-images.jianshu.io/upload_images/5763769-c4014978c0314834.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

可以看一下这一个原型链的一个搜索的过程:

var instance = new Child();
instance.getFatherValue(); // true
instance.getChildValue(); // false

当我们查找```instance.getFatherValue(); ```的时候,是如何一个查找的过程呢?

- 先看一下instance 实例上有没有,没有则继续
- Chile prototype上查找有没有,也没有该方法,则继续向上查找
- 向上查找的是Father prototype的属性和方法,查找到了,则输出。

>这种原型继承的方法,其实就相当于延长了Child的原型链,因为其原型现在又可以再向上查找到Father的原型,相当于延长原型链之后可以继续再向上去查找到Father原型上的属性和方法。

#####思考一下:这其实也给了我们一个提示,如果实例,原型上有相同的方法的话,我们一般读取该属性的时候,也是直接读取到了实例上的属性和方法,除非实例本身没有,才会继续往上查找。

####缺点:
这个方法其实也是有缺点的,因为Child的实例化对象的一些属性和方法都是在该原型链上查找的,所以一些引用值得修改也会影响到所有实例化对象的属性,先看个例子。

function father(name,age) {
this.name = name
this.age = age
this.friends = [“lili”,”koko”]
}
father.prototype.sayname = function () {
console.log(this.name)
}
function children(school) {
this.school = school
}
children.prototype = new father()
children.prototype.sayname = function () {
console.log(“我就是不说自己的名字”)
}
var instance = new children(“幼儿园”)
var instance2 = new children(“幼儿园”)
//那里大家修改了instance的friends的值
instance.friends.push(“yoyo”)
//大家输出children的多个实例对象试一下,看看五个的属性值的区分
console.log(instance)
console.log(instance2)

![instance的输出.png](http://upload-images.jianshu.io/upload_images/5763769-2bbc0a638ee61a39.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![instance2的输出.png](http://upload-images.jianshu.io/upload_images/5763769-b2e3d6d0c8f39176.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

其实从上面两个图也可以发现,一旦修改了一个实例对象上的一个引用值,其他实例化对象的属性值也跟着变化了。因为这里的friends是引用类型的数据,所有的实例都会共享这个属性值,一旦修改其他也跟着修改了。

####构造函数继承

function Animal(){
    this.species = “动物”;
  }
Animal.prototype.say = function(){console.log(“hahaha”)}
 function Cat(name,color){
//那里运用的是构造函数的屡次三番,调用Animal构造函数,再用apply将this指向Cat本身
    Animal.apply(this, arguments);
    this.name = name;
    this.color = color;
  }
  var cat1 = new Cat(“大毛”,”黄色”);
  alert(cat1.species); // 动物
//那样的话Cat的实例化对象就都有Animal的特性了。

>//Cat这个实例化对象就有Animal的属性,但是不会继承来自于Animal原型上的方法。

![image.png](http://upload-images.jianshu.io/upload_images/5763769-49c23d31a71c5e79.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

>构造函数的好处是可以在调用的时候输入参数,```Animal.apply(this, arguments);
```这里可以重新将Cat的参数赋值给Animal中的构造函数。但是这样其实还是有不好之处就是每次新生成一个实例化对象的时候,就会调用一次构造函数。除此之外,Cat并不能继承来自于Animal原型上的方法,这不能实现方法上的复用。

所以,我们可以考虑结合原型方法和构造函数方法。

刚刚是不是说到,只使用原型方法的话,继承父类的所有属性和方法,但是所有实例没有自己的属性,可能会因为一个实例的属性的更改而影响到其他实例;而构造函数的方法只能实现构造函数内的属性方法继承,不能实现父类原型上的继承;;

那就结合这两种方法来实现以下;

// 父类构造函数
function Person (name, age, job) {
this.name = name;
this.age = age;
this.job = job;
}

// 父类方法
Person.prototype.sayName = function () {
console.log(this.name);
};

// ————–

// 子类构造函数
function Student (name, age, job, school) {
// 继承父类的有着实例属性(得到父类构造函数中的属性)
Person.call(this, name, age, job);
this.school = school; // 添加新的子类属性
}

// 继承父类的原型方法(获得父类原型链上的品质和措施)
Student.prototype = new Person();

// 新增的子类方法
Student.prototype.saySchool = function () {
console.log(this.school);
};

var person1 = new Person(‘Weiwei’, 27, ‘Student’);
var student1 = new Student(‘Lily’, 25, ‘Doctor’, “Southeast
University”);

console.log(person1.sayName === student1.sayName); // true

person1.sayName(); // Weiwei
student1.sayName(); // Lily
student1.saySchool(); // Southeast University

![image.png](http://upload-images.jianshu.io/upload_images/5763769-508d69653dfb5c9f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

这个就是比较好的继承方法,将父类的属性继承过来,所有的实例都有自己的属性,同时将原型上的方法也继承过来,实现所有实例都有公共的属性和方法。当然,细心的你也许已经发现了,就是这个Student子类的原型上除了有saySchool方法之外,还有父类构造函数内的那些name job age属性,那是因为我们是使用```Student.prototype = new Person();```来实现继承的,所以该原型实际上就是Person的实例;

所以其实这个方法虽然是好,但是也会出现这样一个情况,属性的覆盖,原型上还有对应父类的属性。这也不是我们最初想要的结果。

所以,我们又引入了另外一个方法

####利用中间空对象的方法继承。
>什么意思呢?我们上面的结合原型和构造函数的方法之所以会出现原型上还有相同的属性的问题是因为,我们用```Student.prototype = new Person();```来实现继承,相当于把Student.prototype重新赋值成Person的实例了,我们就肯定会有Person 构造函数上的属性和原型上的方法。那么我们要的最理想的状态就是用```Student.prototype = new Person();```的时候,Person的构造函数上没有属性,但是这显然不够理智,那么我们就可以引入一个中间的空对象,来实现继承。
啊啊啊,还是看例子吧。

//若是那规范的话,是还是不是很周密,Child的原型是F的一个实例,而F的构造函数我们是设置成空的。
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();

>所以我们可以用这样的方式来封装起来以后可以使用‘

//那些就是Child继承Parent的办法。
function extend(Child, Parent) {
    var F = function(){};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
    Child.uber = Parent.prototype;
  }

我们再来写个例子吧;

// 父类构造函数
function Person (name, age, job) {
this.name = name;
this.age = age;
this.job = job;
}

// 父类方法
Person.prototype.sayName = function () {
console.log(this.name);
};

// ————–

// 子类构造函数
function Student (name, age, job, school) {
// 继承父类的持有实例属性(得到父类构造函数中的属性)
Person.call(this, name, age, job);
this.school = school; // 添加新的子类属性
}

function extend(Child, Parent) {
    var F = function(){};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
    Child.uber = Parent.prototype;
  }
extend( Student,Person);
//调用该方法,完结持续父类原型链上的习性和办法;

// 新增的子类方法
Student.prototype.saySchool = function () {
console.log(this.school);
};

var person1 = new Person(‘Weiwei’, 27, ‘Student’);
var student1 = new Student(‘Lily’, 25, ‘Doctor’, “Southeast
University”);

console.log(person1.sayName === student1.sayName); // true

person1.sayName(); // Weiwei
student1.sayName(); // Lily
student1.saySchool(); // Southeast University
console.log(student1)

![image.png](http://upload-images.jianshu.io/upload_images/5763769-e762216f5426ad1e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

>这样继承是不是好多了,至少跟前面的例子相比,我们的原型链上不会再继承来自父类上的属性;



>后面还有方法会继续总结的,今天先写到这里好了,感觉自己写的过程真的会发现很不一样,也算是了解多了一些。


参考链接:
http://javascriptissexy.com/javascript-objects-in-detail/#
http://javascriptissexy.com/javascript-prototype-in-plain-detailed-language/#
http://javascriptissexy.com/oop-in-javascript-what-you-need-to-know/#
http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html

  return o;

继承

基本上的面向对象语言都帮衬三种持续格局:接口继承和落到实处连续。ECMAScript只辅助落到实处连续,而且其完结持续紧要依靠原型链来完结。

前方大家领会,JavaScript中实例的属性和行事是由构造函数和原型两片段共同构成的。借使大家想让Child继承Father
那就是说我们就要求把Father构造函数和原型中属性和行为全体传给Child的构造函数和原型。

继承

大抵的面向对象语言都辅助两种持续格局:接口继承和兑现持续。ECMAScript只协助促成持续,而且其落到实处一连紧要信赖原型链来完成。

}

原型链继承

应用原型链作为完毕一而再的主导思想是:利用原型让一个引用类型继承另一个引用类型的习性和方法。首先大家先想起一些基本概念:

  • 每个构造函数都有一个原型对象(prototype
  • 原型对象涵盖一个针对性构造函数的指针(constructor
  • 实例都富含一个针对性原型对象的其中指针([[Prototype]]

借使大家让原型对象等于另一个档次的完结,结果会怎么着?明显,此刻的原型对象将涵盖一个针对另一个原型的指针
对应的,另一个原型中也蕴涵着一个对准另一个构造函数的指针。假使另一个原型又是另一个类其余实例,那么上述提到如故创立,
那样罕见推进,就构成了实例与原型的链条。
更详尽的情节可以参考以此链接美高梅开户网址 ,。
先看一个简练的事例,它以身作则了运用原型链完毕延续的主导框架:

JavaScript

function Father () { this.fatherValue = true; }
Father.prototype.getFatherValue = function () {
console.log(this.fatherValue); }; function Child () { this.childValue =
false; } // 已毕持续:继承自Father Child.prototype = new Father();
Child.prototype.getChildValue = function () {
console.log(this.childValue); }; var instance = new Child();
instance.getFatherValue(); // true instance.getChildValue(); // false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Father () {
  this.fatherValue = true;
}
Father.prototype.getFatherValue = function () {
  console.log(this.fatherValue);
};
function Child () {
  this.childValue = false;
}
// 实现继承:继承自Father
Child.prototype = new Father();
Child.prototype.getChildValue = function () {
  console.log(this.childValue);
};
var instance = new Child();
instance.getFatherValue(); // true
instance.getChildValue();  // false

在上头的代码中,原型链继承的骨干语句是Child.prototype = new Father(),它落成了ChildFather的继承,
而延续是由此创制Father的实例,并将该实例赋给Child.prototype实现的。

兑现的精神是重写原型对象,代之以一个新品类的实例。也就是说,原来存在于Father的实例中的所有属性和形式,
现在也存在于Child.prototype中了。

以此事例中的实例以及构造函数和原型之间的涉嫌如下图所示:

美高梅开户网址 3

在地点的代码中,大家从不动用Child默许提供的原型,而是给它换了一个新原型;这些新原型就是Father的实例。
于是,新原型不仅抱有了作为一个Father的实例所兼有的上上下下属性和章程。而且其内部还有一个指南针[[Prototype]],指向了Father的原型。

  • instance指向Child的原型对象
  • Child的原型对象指向Father的原型对象
  • getFatherValue()办法照旧还在Father.prototype
  • 但是,fatherValue则位于Child.prototype
  • instance.constructor方今针对的是Father

因为fatherValue是一个实例属性,而getFatherValue()则是一个原型方法。既然Child.prototype现在是Father的实例,
那么fatherValue理所当然就位于该实例中。

由此落成原型链,本质上扩张了本章前边介绍的原型搜索机制。例如,instance.getFatherValue()会经历多个搜索步骤:

  1. 追寻实例
  2. 搜索Child.prototype
  3. 搜索Father.prototype

原型链继承

运用原型链作为贯彻持续的着力思想是:利用原型让一个引用类型继承另一个引用类型的习性和措施。首先大家先想起一些基本概念:

  • 各样构造函数都有一个原型对象(prototype
  • 原型对象涵盖一个对准构造函数的指针(constructor
  • 实例都富含一个对准原型对象的中间指针([[Prototype]]

即使大家让原型对象等于另一个门类的落成,结果会怎么样?明显,那时候的原型对象将包含一个针对性另一个原型的指针
对应的,另一个原型中也蕴藏着一个针对另一个构造函数的指针。假若另一个原型又是另一个品种的实例,那么上述提到照旧成立,
那般罕见递进,就组成了实例与原型的链子。
更详尽的始末可以参考其一链接。
先看一个简便的事例,它以身作则了选拔原型链完成持续的着力框架:

function Father () { this.fatherValue = true; }
Father.prototype.getFatherValue = function () {
console.log(this.fatherValue); }; function Child () { this.childValue =
false; } // 达成一而再:继承自Father Child.prototype = new Father();
Child.prototype.getChildValue = function () {
console.log(this.childValue); }; var instance = new Child();
instance.getFatherValue(); // true instance.getChildValue(); // false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function Father () {
  this.fatherValue = true;
}
 
Father.prototype.getFatherValue = function () {
  console.log(this.fatherValue);
};
 
function Child () {
  this.childValue = false;
}
 
// 实现继承:继承自Father
Child.prototype = new Father();
 
Child.prototype.getChildValue = function () {
  console.log(this.childValue);
};
 
var instance = new Child();
instance.getFatherValue(); // true
instance.getChildValue();  // false

在上头的代码中,原型链继承的主干语句是Child.prototype = new Father(),它完毕了ChildFather的继承,
而三番五次是经过创制Father的实例,并将该实例赋给Child.prototype实现的。

已毕的原形是重写原型对象,代之以一个新品类的实例。也就是说,原来存在于Father的实例中的所有属性和办法,
后天也设有于Child.prototype中了。

这么些例子中的实例以及构造函数和原型之间的关联如下图所示:

美高梅开户网址 4

在地方的代码中,大家从没使用Child默许提供的原型,而是给它换了一个新原型;这一个新原型就是Father的实例。
于是,新原型不仅具备了作为一个Father的实例所具备的成套属性和方法。而且其里面还有一个指南针[[Prototype]],指向了Father的原型。

  • instance指向Child的原型对象
  • Child的原型对象指向Father的原型对象
  • getFatherValue()办法如故还在Father.prototype
  • 但是,fatherValue则位于Child.prototype
  • instance.constructor当今针对的是Father

因为fatherValue是一个实例属性,而getFatherValue()则是一个原型方法。既然Child.prototype现在是Father的实例,
那么fatherValue理所当然就放在该实例中。

透过兑现原型链,本质上增添了本章前边介绍的原型搜索机制。例如,instance.getFatherValue()会经历多少个搜索步骤:

  1. 招来实例
  2. 搜索Child.prototype
  3. 搜索Father.prototype

var person1=createPerson(“kobe”,”34″,”player”);

别忘了Object

抱有的函数都默认原型都是Object的实例,由此默许原型都会蕴藏一个之中指针[[Prototype]],指向Object.prototype
那也正是拥有自定义类型都会三番五次toString()valueOf()等默认方法的根本原因。所以,
俺们说下面例子展示的原型链中还应有包含其余一个继续层次。关于Object的越来越多内容,可以参照那篇博客。

也就是说,Child继承了Father,而Father继承了Object。当调用了instance.toString()时,
事实上调用的是保存在Object.prototype中的那些情势。

别忘了Object

装有的函数都默许原型都是Object的实例,因而默许原型都会包括一个里面指针[[Prototype]],指向Object.prototype
那也正是拥有自定义类型都会持续toString()valueOf()等默许方法的根本原因。所以,
咱俩说地点例子彰显的原型链中还应该包含别的一个继承层次。关于Object的越来越多内容,能够参照那篇博客。

也就是说,Child继承了Father,而Father继承了Object。当调用了instance.toString()时,
实际上调用的是保存在Object.prototype中的那一个情势。

var person2=createPerosn(“patty”,”32″,”singer”);

原型链继承的题材

率先是各种,一定要先三番五次父类,然后为子类添加新措施。

其次,运用原型链落成一连时,不能选取对象字面量创立原型方法。因为如此做就会重写原型链,如上面的事例所示:

JavaScript

function Father () { this.fatherValue = true; }
Father.prototype.getFatherValue = function () {
console.log(this.fatherValue); }; function Child () { this.childValue =
false; } // 继承了Father // 此时的原型链为 Child -> Father ->
Object Child.prototype = new Father(); //
使用字面量添加新措施,会造成上一行代码无效 //
此时我们考虑的原型链被隔绝,而是改为 Child -> Object //
所以我们不引进这么写了 Child.prototype = { getChildValue: function () {
console.log(this.childValue); } }; var instance = new Child();
instance.getChildValue(); // false instance.getFatherValue(); // error!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Father () {
  this.fatherValue = true;
}
Father.prototype.getFatherValue = function () {
  console.log(this.fatherValue);
};
function Child () {
  this.childValue = false;
}
// 继承了Father
// 此时的原型链为 Child -> Father -> Object
Child.prototype = new Father();
// 使用字面量添加新方法,会导致上一行代码无效
// 此时我们设想的原型链被切断,而是变成 Child -> Object
// 所以我们不推荐这么写了
Child.prototype = {
  getChildValue: function () {
    console.log(this.childValue);
  }
};
var instance = new Child();
instance.getChildValue();  // false
instance.getFatherValue(); // error!

在上头的代码中,大家连年一次修改了Child.prototype的值。由于今天的原型包涵的是一个Object的实例,
而非Father的实例,因而大家着想中的原型链已经被割裂——ChildFather里面已经没有涉嫌了。

末尾,在开创子类型的实例时,无法向超类型的构造函数中传递参数。实际上,应该算得没有艺术在不影响所有目的实例的动静下,
给超类型的构造函数传递参数。由此,大家很少单独行使原型链。

原型链继承的难点

先是是各种,一定要先三番五次父类,然后为子类添加新章程。

其次,利用原型链完结持续时,无法使用对象字面量成立原型方法。因为如此做就会重写原型链,如上边的事例所示:

function Father () { this.fatherValue = true; }
Father.prototype.getFatherValue = function () {
console.log(this.fatherValue); }; function Child () { this.childValue =
false; } // 继承了Father // 此时的原型链为 Child -> Father ->
Object Child.prototype = new Father(); //
使用字面量添加新格局,会招致上一行代码无效 //
此时大家着想的原型链被隔离,而是成为 Child -> Object Child.prototype
= { getChildValue: function () { console.log(this.childValue); } }; var
instance = new Child(); instance.getChildValue(); // false
instance.getFatherValue(); // error!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function Father () {
  this.fatherValue = true;
}
 
Father.prototype.getFatherValue = function () {
  console.log(this.fatherValue);
};
 
function Child () {
  this.childValue = false;
}
 
// 继承了Father
// 此时的原型链为 Child -> Father -> Object
Child.prototype = new Father();
 
// 使用字面量添加新方法,会导致上一行代码无效
// 此时我们设想的原型链被切断,而是变成 Child -> Object
Child.prototype = {
  getChildValue: function () {
    console.log(this.childValue);
  }
};
 
var instance = new Child();
instance.getChildValue();  // false
instance.getFatherValue(); // error!

在上面的代码中,大家连年一遍修改了Child.prototype的值。由于现在的原型包涵的是一个Object的实例,
而非Father的实例,因而大家考虑中的原型链已经被切断——ChildFather时期一度远非涉及了。

说到底,在开立子类型的实例时,不可能向超类型的构造函数中传递参数。实际上,应该算得没有艺术在不影响所有目的实例的情况下,
给超类型的构造函数传递参数。因而,大家很少单独行使原型链。

 构造函数情势

借用构造函数继承

借用构造函数(constructor
stealing)的基本思维如下:即在子类构造函数的里边调用超类型构造函数。

JavaScript

function Father (name) { this.name = name; this.colors = [‘red’,
‘blue’, ‘green’]; } function Child (name) { //
继承了Father,同时传递了参数 //
之所以那样做,是为着获取Father构造函数中的所有属性和格局 //
之所以用call,是为了校勘Father内部this的针对性 Father.call(this, name); }
var instance1 = new Child(“weiwei”); instance1.colors.push(‘black’);
console.log(instance1.colors); // [ ‘red’, ‘blue’, ‘green’, ‘black’ ]
console.log(instance1.name); // weiwei var instance2 = new
Child(“lily”); console.log(instance2.colors); // [ ‘red’, ‘blue’,
‘green’ ] console.log(instance2.name); // lily

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Father (name) {
  this.name = name;
  this.colors = [‘red’, ‘blue’, ‘green’];
}
function Child (name) {
  // 继承了Father,同时传递了参数
  // 之所以这么做,是为了获得Father构造函数中的所有属性和方法
  // 之所以用call,是为了修正Father内部this的指向
  Father.call(this, name);
}
var instance1 = new Child("weiwei");
instance1.colors.push(‘black’);
console.log(instance1.colors); // [ ‘red’, ‘blue’, ‘green’, ‘black’ ]
console.log(instance1.name); // weiwei
var instance2 = new Child("lily");
console.log(instance2.colors); // [ ‘red’, ‘blue’, ‘green’ ]
console.log(instance2.name); // lily

为了保险Father构造函数不会重写子类型的特性,能够在调用超类型构造函数后,再添加应该在子类型中定义的属性。

借用构造函数继承

借用构造函数(constructor
stealing)的主导思想如下:即在子类构造函数的其中调用超类型构造函数。

function Father (name) { this.name = name; this.colors = [‘red’,
‘blue’, ‘green’]; } function Child (name) { //
继承了Father,同时传递了参数 Father.call(this, name); } var instance1 =
new Child(“weiwei”); instance1.colors.push(‘black’);
console.log(instance1.colors); // [ ‘red’, ‘blue’, ‘green’, ‘black’ ]
console.log(instance1.name); // weiwei var instance2 = new
Child(“lily”); console.log(instance2.colors); // [ ‘red’, ‘blue’,
‘green’ ] console.log(instance2.name); // lily

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Father (name) {
  this.name = name;
  this.colors = [‘red’, ‘blue’, ‘green’];
}
 
function Child (name) {
  // 继承了Father,同时传递了参数
  Father.call(this, name);
}
 
var instance1 = new Child("weiwei");
instance1.colors.push(‘black’);
console.log(instance1.colors); // [ ‘red’, ‘blue’, ‘green’, ‘black’ ]
console.log(instance1.name); // weiwei
 
var instance2 = new Child("lily");
console.log(instance2.colors); // [ ‘red’, ‘blue’, ‘green’ ]
console.log(instance2.name); // lily

为了有限支撑Father构造函数不会重写子类型的品质,可以在调用超类型构造函数后,再添加应该在子类型中定义的习性。

与工厂形式差距的是,没有出示的成立对象,间接将品质和形式赋值this对象,没有return语句。

借用构造函数的短处

同构造函数一样,不能兑现形式的复用(所有的办法会被再一次创设一份)。

借用构造函数的弱点

同构造函数一样,不能落成格局的复用。

function Person(name,age,job){

整合使用原型链和借用构造函数

一般说来,大家会组成使用原型链继承和借用构造函数来促成持续。也就是说,使用原型链完毕对原型属性和措施的接轨,
而由此借用构造函数来促成对实例属性的一连。那样,既通过在原型上定义方法完成了函数复用,又可以有限扶助每个实例都有它和谐的特性。
大家改造最初的例子如下:

JavaScript

// 父类构造函数 function Person (name, age, job) { this.name = name;
this.age = age; this.job = job; } // 父类方法 Person.prototype.sayName =
function () { console.log(this.name); }; // ————– //
子类构造函数 function Student (name, age, job, school) { //
继承父类的所有实例属性(得到父类构造函数中的属性) Person.call(this,
name, age, job); this.school = school; // 添加新的子类属性 } //
继承父类的原型方法(获得父类原型链上的习性和方法) Student.prototype =
new Person(); // 新增的子类方法 Student.prototype.saySchool = function
() { console.log(this.school); }; var person1 = new Person(‘Weiwei’, 27,
‘Student’); var student1 = new Student(‘Lily’, 25, ‘Doctor’, “Southeast
University”); console.log(person1.sayName === student1.sayName); // true
person1.sayName(); // Weiwei student1.sayName(); // Lilystudent1.saySchool(); // Southeast University

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 父类构造函数
function Person (name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
}
// 父类方法
Person.prototype.sayName = function () {
  console.log(this.name);
};
// ————–
// 子类构造函数
function Student (name, age, job, school) {
  // 继承父类的所有实例属性(获得父类构造函数中的属性)
  Person.call(this, name, age, job);
  this.school = school; // 添加新的子类属性
}
// 继承父类的原型方法(获得父类原型链上的属性和方法)
Student.prototype = new Person();
// 新增的子类方法
Student.prototype.saySchool = function () {
  console.log(this.school);
};
var person1 = new Person(‘Weiwei’, 27, ‘Student’);
var student1 = new Student(‘Lily’, 25, ‘Doctor’, "Southeast University");
console.log(person1.sayName === student1.sayName); // true
person1.sayName();  // Weiwei
student1.sayName(); // Lily
student1.saySchool(); // Southeast University

组成集成幸免了原型链和借用构造函数的欠缺,融合了它们的独到之处,成为了JavaScript中最常用的存续情势。
而且,instanceofisPropertyOf()也可以用于识别基于组合继承创制的靶子。

组成使用原型链和借用构造函数

普通,大家会构成使用原型链继承和借用构造函数来完毕持续。也就是说,使用原型链完毕对原型属性和章程的接续,
而因此借用构造函数来落到实处对实例属性的接续。那样,既通过在原型上定义方法完毕了函数复用,又可以确保每个实例都有它自己的品质。
大家改造最初的例证如下:

// 父类构造函数 function Person (name, age, job) { this.name = name;
this.age = age; this.job = job; } // 父类方法 Person.prototype.sayName =
function () { console.log(this.name); }; // ————– //
子类构造函数 function Student (name, age, job, school) { //
继承父类的所有实例属性 Person.call(this, name, age, job); this.school =
school; // 添加新的子类属性 } // 继承父类的原型方法 Student.prototype =
new Person(); // 新增的子类方法 Student.prototype.saySchool = function
() { console.log(this.school); }; var person1 = new Person(‘Weiwei’, 27,
‘Student’); var student1 = new Student(‘莉莉’, 25, ‘Doctor’, “Southeast
University”); console.log(person1.sayName === student1.sayName); // true
person1.sayName(); // Weiwei student1.sayName(); // Lilystudent1.saySchool(); // Southeast University

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 父类构造函数
function Person (name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
}
 
// 父类方法
Person.prototype.sayName = function () {
  console.log(this.name);
};
 
// ————–
 
// 子类构造函数
function Student (name, age, job, school) {
  // 继承父类的所有实例属性
  Person.call(this, name, age, job);
  this.school = school; // 添加新的子类属性
}
 
// 继承父类的原型方法
Student.prototype = new Person();
 
// 新增的子类方法
Student.prototype.saySchool = function () {
  console.log(this.school);
};
 
var person1 = new Person(‘Weiwei’, 27, ‘Student’);
var student1 = new Student(‘Lily’, 25, ‘Doctor’, "Southeast University");
 
console.log(person1.sayName === student1.sayName); // true
 
person1.sayName();  // Weiwei
student1.sayName(); // Lily
student1.saySchool(); // Southeast University

整合集成防止了原型链和借用构造函数的通病,融合了它们的助益,成为了JavaScript中最常用的接续方式。
而且,instanceofisPropertyOf()也可以用于识别基于组合继承创建的目的。

    this.name=name;

整合继承的立异版:使用Object.create()

在地点,我们继承父类的原型方法应用的是Student.prototype = new Person()
这样做有那多少个的标题。
校订措施是行使ES5中新增的Object.create()。可以调用那一个办法来创立一个新对象。新目的的原型就是调用create()办法传入的第四个参数:

JavaScript

Student.prototype = Object.create(Person.prototype);
console.log(Student.prototype.constructor); // [Function: Person] //
设置 constructor 属性指向 Student Student.prototype.constructor =
Student;

1
2
3
4
Student.prototype = Object.create(Person.prototype);
console.log(Student.prototype.constructor); // [Function: Person]
// 设置 constructor 属性指向 Student
Student.prototype.constructor = Student;

详细用法可以参考文档。
关于Object.create()的兑现,大家得以参照一个简练的polyfill:

JavaScript

function createObject(proto) { function F() { } F.prototype = proto;
return new F(); } // Usage: Student.prototype =
createObject(Person.prototype);

1
2
3
4
5
6
7
function createObject(proto) {
    function F() { }
    F.prototype = proto;
    return new F();
}
// Usage:
Student.prototype = createObject(Person.prototype);

从实质上讲,createObject()对传播其中的靶子实施了三遍浅复制。

重组继承的立异版:使用Object.create()

在上头,大家后续父类的原型方法应用的是Student.prototype = new Person()
这样做有诸多的标题。
精雕细刻格局是使用ES5中新增的Object.create()。可以调用那个格局来创立一个新目的。新对象的原型就是调用create()方法传入的率先个参数:

Student.prototype = Object.create(Person.prototype);
console.log(Student.prototype.constructor); // [Function: Person] //
设置 constructor 属性指向 Student Student.prototype.constructor =
Student;

1
2
3
4
5
6
Student.prototype = Object.create(Person.prototype);
 
console.log(Student.prototype.constructor); // [Function: Person]
 
// 设置 constructor 属性指向 Student
Student.prototype.constructor = Student;

详尽用法可以参照文档。
关于Object.create()的贯彻,大家可以参考一个大致的polyfill:

function createObject(proto) { function F() { } F.prototype = proto;
return new F(); } // Usage: Student.prototype =
createObject(Person.prototype);

1
2
3
4
5
6
7
8
function createObject(proto) {
    function F() { }
    F.prototype = proto;
    return new F();
}
 
// Usage:
Student.prototype = createObject(Person.prototype);

从精神上讲,createObject()对传播其中的目的执行了三回浅复制。

    this.age=age;

ES6中的面向对象语法

ES6中引入了一套新的显要字用来兑现class。
但它并不是映入了一种新的面向对象继承情势。JavaScript依旧是依照原型的,这个新的重点字概括class、
constructor、
static、
extends、
和super。

class要害字然则是提供了一种在本文中所研讨的依据原型形式和构造器方式的面向对象的接轨方式的语法糖(syntactic
sugar)

对前面的代码修改如下:

JavaScript

‘use strict’; class Person { constructor (name, age, job) { this.name =
name; this.age = age; this.job = job; } sayName () {
console.log(this.name); } } class Student extends Person { constructor
(name, age, school) { super(name, age, ‘Student’); this.school = school;
} saySchool () { console.log(this.school); } } var stu1 = new
Student(‘weiwei’, 20, ‘Southeast University’); var stu2 = new
Student(‘lily’, 22, ‘Nanjing University’); stu1.sayName(); // weiwei
stu1.saySchool(); // Southeast University stu2.sayName(); // lily
stu2.saySchool(); // Nanjing University

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
‘use strict’;
class Person {
  constructor (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
  }
  sayName () {
    console.log(this.name);
  }
}
class Student extends Person {
  constructor (name, age, school) {
    super(name, age, ‘Student’);
    this.school = school;
  }
  saySchool () {
    console.log(this.school);
  }
}
var stu1 = new Student(‘weiwei’, 20, ‘Southeast University’);
var stu2 = new Student(‘lily’, 22, ‘Nanjing University’);
stu1.sayName(); // weiwei
stu1.saySchool(); // Southeast University
stu2.sayName(); // lily
stu2.saySchool(); // Nanjing University

ES6中的面向对象语法

ES6中引入了一套新的要害字用来已毕class。
JavaScript照旧是按照原型的,这一个新的重点字概括class、
constructor、
static、
extends、
和super。

对前边的代码修改如下:

‘use strict’; class Person { constructor (name, age, job) { this.name =
name; this.age = age; this.job = job; } sayName () {
console.log(this.name); } } class Student extends Person { constructor
(name, age, school) { super(name, age, ‘Student’); this.school = school;
} saySchool () { console.log(this.school); } } var stu1 = new
Student(‘weiwei’, 20, ‘Southeast University’); var stu2 = new
Student(‘lily’, 22, ‘Nanjing University’); stu1.sayName(); // weiwei
stu1.saySchool(); // Southeast University stu2.sayName(); // lily
stu2.saySchool(); // Nanjing University

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
‘use strict’;
 
class Person {
 
  constructor (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
  }
 
  sayName () {
    console.log(this.name);
  }
 
}
 
class Student extends Person {
 
  constructor (name, age, school) {
    super(name, age, ‘Student’);
    this.school = school;
  }
 
  saySchool () {
    console.log(this.school);
  }
 
}
 
var stu1 = new Student(‘weiwei’, 20, ‘Southeast University’);
var stu2 = new Student(‘lily’, 22, ‘Nanjing University’);
 
stu1.sayName(); // weiwei
stu1.saySchool(); // Southeast University
 
stu2.sayName(); // lily
stu2.saySchool(); // Nanjing University

    this.job=job;

类:class

是JavaScript中存活基于原型的后续的语法糖。ES6中的并不是一种新的创制对象的方法,只不过是一种“特殊的函数”,
故此也包蕴类表明式和类声明,
但必要留意的是,与函数注脚区其他是,类申明不会被提升。
参照链接

类:class

是JavaScript中存活基于原型的接续的语法糖。ES6中的并不是一种新的创设对象的法门,只可是是一种“特殊的函数”,
之所以也囊括类表明式和类声明,
但必要注意的是,与函数表明不相同的是,类声明不会被提升。
参照链接

    this.sayName=function(){

类构造器:constructor

constructor()措施是有一种奇特的和class一路用于成立和初步化对象的艺术。注意,在ES6类中不得不有一个称号为constructor的方法,
要不然会报错。在constructor()艺术中可以调用super重点字调用父类构造器。若是您未曾点名一个构造器方法,
类会自动使用一个默许的构造器。参照链接

类构造器:constructor

constructor()办法是有一种奇特的和class一头用于成立和开始化对象的办法。注意,在ES6类中只好有一个称呼为constructor的方法,
否则会报错。在constructor()主意中可以调用super关键字调用父类构造器。如果您从未点名一个构造器方法,
类会自动使用一个默许的构造器。参考链接

    console.log(this.name);

类的静态方法:static

静态方法就是可以直接利用类名调用的章程,而不用对类进行实例化,当然实例化后的类也无从调用静态方法。
静态方法常被用于创立应用的工具函数。参照链接

类的静态方法:static

静态方法就是足以间接行使类名调用的主意,而不必对类举行实例化,当然实例化后的类也无能为力调用静态方法。
静态方法常被用来创造应用的工具函数。参考链接

   };

后续父类:extends

extends重点字可以用于后续父类。使用extends可以增添一个放到的对象(如Date),也足以是自定义对象,或者是null

接轨父类:extends

extends重中之重字可以用来后续父类。使用extends可以扩展一个内置的靶子(如Date),也可以是自定义对象,或者是null

}

关键字:super

super重视字用于调用父对象上的函数。
super.propsuper[expr]表明式在类和目的字面量中的任何办法定义中都有效。

JavaScript

super([arguments]); // 调用父类构造器
super.functionOnParent([arguments]); // 调用父类中的方法

1
2
super([arguments]); // 调用父类构造器
super.functionOnParent([arguments]); // 调用父类中的方法

倘若是在类的构造器中,需求在this主要字从前使用。参考链接

关键字:super

super重大字用于调用父对象上的函数。
super.propsuper[expr]表达式在类和对象字面量中的任何办法定义中都有效。

super([arguments]); // 调用父类构造器
super.functionOnParent([arguments]); // 调用父类中的方法

1
2
super([arguments]); // 调用父类构造器
super.functionOnParent([arguments]); // 调用父类中的方法

如假如在类的构造器中,要求在this重点字从前使用。参考链接

var person1=new Person();

小结

本文对JavaScript的面向对象机制举办了较为深入的解读,尤其是构造函数和原型链格局完结目标的开创、继承、以及实例化。
其余,本文还简要介绍了如在ES6中编辑面向对象代码。

小结

正文对JavaScript的面向对象机制举办了比较长远的解读,尤其是构造函数和原型链方式落成目的的开创、继承、以及实例化。
别的,本文还简要介绍了如在ES6中编辑面向对象代码。

var person2=new Person();

References

  1. 详解Javascript中的Object对象
  2. new操作符
  3. JavaScript面向对象简介
  4. Object.create()
  5. 继续与原型链
  6. Understanding the prototype property in
    JavaScript

    1 赞 8 收藏
    评论

美高梅开户网址 5

References

  1. 详解Javascript中的Object对象
  2. new操作符
  3. JavaScript面向对象简介
  4. Object.create()
  5. 继承与原型链

    2 赞 7 收藏 4
    评论

美高梅开户网址 6

console.log(person1.sayName==person2.sayName)//false
验证分歧实例的同名函数是不对等的

只要大家想要的结果是双边对等,可以如此落成

function  Person(name,age,job){

   this.name=name;

   this.age=age;

   this.job=job;

   this.sayName=sayName;

}

function sayName(){

   console.log(this.name);

}

var person1=new Person();

var person2=new Person();

console.log(person1.sayName==person2.sayName);//true

创设Person的新实例,要求采取new操作符,那种情势下调用构造函数会经历多少个等级,分别是:

开创一个新目的

将构造函数的成效域赋值给那几个新的靶子

实施构造函数中的代码

回来新目标

person1和person2那多少个目的都有一个constructor属性,该属性指向Person

console.log(person1.constructor==Person);//true

console.log(person2.constructor==Person);//true

原型格局

特色:新目的的那几个属性和方法是富有实例共享的

function Person(){

}

Person.prototype.name=”kobe”;

Person.prototype.age=38;

Person.prototype.sayName=function(){

   console.log(this.name);

}

var person1=new Person();

var person2=new Person();

console.log(person1.sayName==person2.sayName);//true

奇迹大家想清楚该属性到底是存在对象中如故存在原型中,可以应用以下办法

咱俩应用in操作符和hasOwnProperty结合判断

“name” in object无论该属性到底存在原型中要么对象中,都会重回true

而hasOwnProperty唯有存在实例中才回去true

so:只有in操作符重返true,而hasOwnProperty再次回到false,能确定属性是原型中的属性。

function hasPrototypeProperty(object,name){

   return !object.hasOwnProperty(name)&&(name in object);

}

原型对象存在难题,牵一发而动全身

function Person(){

}

Perosn.prototype=function(){

   constructor;Person,

   name:”kobe”,

   age:”29″,

   job:”player”,

   friends:[“shely”,”count”],

   sayName:function(){

       console.log(this.name); 

  }

};

var person1=new Person();

var person2=new Person();

person1.friends.push(“ann”);

console.log(person1.friends===person2.friends);//true

化解的艺术:是利用构造函数格局和原型情势

function Person(name,age,job){

   this.name=name;

   this.age=age;

   this.job=job;

   this.friends=[“she”,”ya”];

}

Person.prototype={

   constructor:Person,

   sayName:function(){

      console.log(this.name);  

}

};

var person1=new Person();

var person2=new Person();

person1.friends.push(“VAN”);

console.log(person1.friends===person2.friends);//false

动态原型情势

function Person(name,age,job){

   this.name=name;

   this.age=age;

   this.job=job;

   if(typeof this.sayName!=”function”){

   Person.prototype.sayName=function(){

      console.log(this.name);

   }

   };

}

寄生构造函数方式

function Person(name,age,job){

   var o=new Object();

   o.name=name;

   o.age=age;

   o.job=job;

   o.sayName=function(){

      console.log(this.name); 

   };

   return o;

}

var friend=new Person();//此情势与工厂形式尤其近乎

2.js落实持续的三种方式

原型链继承:原型对象属性共享

function Parent2(){

   this.name=”kobe”;

   this.play=[1,2,3];

}

function Child2(){

   this.type=”children”;

}

Child2.prototype=new Parent2();

var say1=new Child2();

var say2=new Child2();

say1.play.push(“van”);

console.log(say1.play==say2.play);//true

借用构造函数完毕再而三:不可能完成一而再原型对象

function Parent1(){

   this.name=”kobe”;

}

Parent1.prototype.age=90;

function Child(){

   Parent1.call(this);

   this.type=”service”;

}

var say=new Child();

console.log();//error

组合式继承

function Parent4(name){

   this.name=”kobe”;

   this.play=[1,2,3];

}

Parent4.prototype.sayName=function(){

  

}

function Child4(name,age){

   Parent3.call(this,name);

   this.age=age;

}

Child4.prototype=new Parent4();

Child4.prototype.constructor=Child4;

Child4.prototype.sayAge=function(){

   console.log(this.age);

};

var ins1=new Child4();

var ins2=new Child4();

ins1.push.push(4);

console.log(ins1.play==ins2.play);//false

原型式继承

function object(){

   function F(){}

   F.prototype=o;

   return new F();

}

var person={

   name:”kobe”,

   friends;[“yang”,”du”,”geng”]

};

var onePerson=object(person);

var twoPerson=object(person);

寄生式继承

function object(o){

   function F(){}

   F.prototype=o;

   return new F();

}

 function create(o){

   var clone=object(o);

   clone.sayHi=function(){

     console.log(“hi”);

   };

   return clone;

}

var person={

   name:”kobe”,

   friends:[“james”,”waston”,”sun”]

};

var anotherPerson=creat(person);

anotherPerson.sayHi();//hi

寄生式组合继承

function inheritPrototype(Child5,Parent5){
    var prototype=Object(Parent5.prototype);
    prototype.constructor=Child5;
    Child5.prototype=prototype;
}
function Parent5(name){
    this.name=name;
    this.colors=[“red”,”blue”,”green”];
}
Parent5.prototype.sayName=function(){
    console.log(this.name);
};
function Child5(name,age){
    Parent5.call(this.name);
    this.age=age;
}
inheritPrototype(Child5,Parent5);
Child5.prototype.sayAge=function(){
     console.log(this.age);
};

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图