最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

深入理解javaScript原型继承

来源:懂视网 责编:小采 时间:2020-11-27 20:24:58
文档

深入理解javaScript原型继承

深入理解javaScript原型继承:继承的本质:重用在探讨 javaScript 的原型继承之前,先不妨想想为什么要继承?考虑一个场景,如果我们有两个对象,它们一部分属性相同,另一部属性不同。通常一个好的设计方案是将相同逻辑抽出来,实现重用。以 xiaoMing liLei 两位同学举例。这两位同学有自
推荐度:
导读深入理解javaScript原型继承:继承的本质:重用在探讨 javaScript 的原型继承之前,先不妨想想为什么要继承?考虑一个场景,如果我们有两个对象,它们一部分属性相同,另一部属性不同。通常一个好的设计方案是将相同逻辑抽出来,实现重用。以 xiaoMing liLei 两位同学举例。这两位同学有自

继承的本质:重用

在探讨 javaScript 的原型继承之前,先不妨想想为什么要继承?

考虑一个场景,如果我们有两个对象,它们一部分属性相同,另一部属性不同。通常一个好的设计方案是将相同逻辑抽出来,实现重用。

以 xiaoMing liLei 两位同学举例。这两位同学有自己的名字,并且会介绍自己。抽象为程序对象,可以做如下表示。

var xiaoMing = {
 name : "xiaoMing",
 hello : function(){
 console.log( 'Hello, my name is '+ this.name + '.');
 }
}

var liLei = {
 name : "liLei",
 hello : function(){
 console.log( 'Hello, my name is '+ this.name + '.');
 }
}

使用过 java 的同学,可能第一眼就想到了用面向对象来解决这个问题。创造一个 Person 的类,然后实例化 xiaoMing 和 liLei 两个对象。在 ES6 中也有类似于 java 中类的概念: class 。

下面使用 ES6 的语法,用面向对象的思路来重构上面的代码。

class Person {
 constructor(name){
 this.name = name
 }

 hello(){
 console.log(this.name);
 }
}

var xiaoMing = new Person('xiaoMing');
var liLei = new Person('liLei');

可以看到,使用类创建对象,达到了重用的目的。它基于的逻辑是,两个或多个对象的结构功能类似,可以抽象出一个模板,依照模板复制出多个相似的对象。

使用类创建对象,就像自行车制造商一遍一遍地重用相同的蓝图来制造大量的自行车。

然解决重用问题的方案,当然不止一种。传统面向对象的类,只是其中的一种方案。下面轮到我们的主角“原型继承”登场了,它从另一个角度解决了重用的问题。

原型继承的原理

原型对象

javaScript 中的 object 由两部分组成,普通属性的集合,和原型属性。

var o = {
 a : 'a',
 ...
 __proto__: prototypeObj
}

普通属性指的就是 a ; 原型属性 指的是 __proto__ 。这本不属于规范的一部分,后来 chrome 通过 __proto__ 将这个语言底层属性给暴露出来了,慢慢的被大家所接受,也就添加到 ES6 规范中了。 o.__proto__ 的值 prototypeObj 也就是 原型对象 。原型对象其实也就是一个普通对象,之所以叫原型对象的原因,只是因为它是原型属性所指的值。

原型对象所以特殊,是因为它拥有一个普通对象没有的能力:将它的属性共享给其他对象。

在 ES6 规范 中,对它是如下定义的:

object that provides shared properties for other objects

属性读操作

回到最开始的例子,看看如何利用原型继承实现重用的目的。

var prototypeObj = {
 hello: function(){
 console.log( 'Hello, my name is '+ this.name + '.');
 }
 // ...
}

var xiaoMing = {
 name : "xiaoMing",
 __proto__ : prototypeObj
}

var liLei = {
 name : "liLei",
 __proto__ : prototypeObj
}

xiaoMing.hello(); // Hello, my name is xiaoMing.
liLei.hello(); // Hello, my name is liLei.

xiaoMing liLei 对象上,并没直接拥有 hello 属性(方法),但是却能读取该属性(执行该方法),这是为什么?

想象一个场景,你在做数学作业,遇到一个很难的题目,你不会做。而你有一个好兄弟,数学很厉害,你去请教他,把这道题做出来了。

xiaoMing 对象上,没有 hello 属性,但是它有一个好兄弟, prototypeObj 。属性读操作,在 xiaoMing 身上没有找到 hello 属性,就会去问它的兄弟 prototypeObj 。所以 hello 方法会被执行。

原型链

还是做数学题的例子。你的数学题目很难,你的兄弟也没有答案,他推荐你去问另外一个同学。这样直到有了答案或者再也没有人可以问,你就不会再问下去。这样就好像有一条无形链条把你和同学们牵在了一起。

在 JS 中,读操作通过 __proto__ 会一层一层链下去的结构,就叫 原型链 。

var deepPrototypeObj = {
 hello: function(){
 console.log( 'Hello, my name is '+ this.name + '.');
 }
 __proto__ : null
}

var prototypeObj = {
 __proto__ : deepPrototypeObj
}

var xiaoMing = {
 name : "xiaoMing",
 __proto__ : prototypeObj
}

var liLei = {
 name : "liLei",
 __proto__ : prototypeObj
}

xiaoMing.hello(); // Hello, my name is xiaoMing.
liLei.hello(); // Hello, my name is liLei.

原型继承的实现

在上面的例子中,通过直接修改了 __proto__ 属性值,实现了原型继承。但是在实际生产中,

代替的方式是使用 Object.create() 方法。

调用 Object.create() 方法会创建一个新对象,同时指定该对象的原型对象为传入的第一个参数。

我们将上面的例子改一下。

var prototypeObj = {
 hello: function(){
 console.log( 'Hello, my name is '+ this.name + '.');
 }
 // ...
}

var xiaoMing = Object.create(prototypeObj);
var liLei = Object.create(prototypeObj);

xiaoMing.name = "xiaoMing";
liLei.name = "liLei";

xiaoMing.hello(); // Hello, my name is xiaoMing.
liLei.hello(); // Hello, my name is liLei.

You-Dont-Know-JS 的作者,对这种原型继承的实现取了一个很好玩的名字 OLOO (objects-linked-to-other-objects) ,这种实现方式的优点是没有使用任何类的概念,只有 object ,所以它是很符合 javaScript 的特性的。

因为JS 中本无类,只有 object 。

无奈的是,喜欢类的程序员是在太多,所以在 ES6 新增了 class 概念。下一篇会讲 class 在 JS 中的实现原理

小结

类创建对象,达到了重用的目的。它基于的逻辑是,两个或多个对象的结构功能类似,可以抽象出一个模板,依照模板 复制 出多个相似的对象。就像自行车制造商一遍一遍地重用相同的蓝图来制造大量的自行车。

使用原型继承,同样可以达到重用的目的。它基于的逻辑是,两个或多个对象的对象有一部分共用属性,可以将共用的属性抽象到另一个独立公共对象上,通过特殊的原型属性,将公共对象和普通对象链接起来,再利用属性读(写)规则进行遍历查找,实现属性 共享 。

文档

深入理解javaScript原型继承

深入理解javaScript原型继承:继承的本质:重用在探讨 javaScript 的原型继承之前,先不妨想想为什么要继承?考虑一个场景,如果我们有两个对象,它们一部分属性相同,另一部属性不同。通常一个好的设计方案是将相同逻辑抽出来,实现重用。以 xiaoMing liLei 两位同学举例。这两位同学有自
推荐度:
标签: js 理解 原型
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top