什么是原型?

首先我们创建一个简单的空对象,再把它打印出来

var example = {}
console.log(example)

结果如下:

{
__proto__: {
constructor: ƒ Object(),
hasOwnProperty: ƒ hasOwnProperty(),
isPrototypeOf: ƒ isPrototypeOf(),
propertyIsEnumerable: ƒ propertyIsEnumerable(),
toLocaleString: ƒ toLocaleString(),
toString: ƒ toString(),
valueOf: ƒ valueOf()
}
}

我们创建的example是个空对象,按理说应该什么属性都没有,却出现了一个__proto__属性,这个属性是从哪里来的呢?实际上,当我们调用 var example = {} 时,相当于调用 var example = new Object(),隐式地继承了 Object.prototype 的属性和方法。Object.prototype 对象是 javascript 的根对象,javascript 的每个对象都是从这个对象来的,下面我们通过构造函数的例子看一下prototype、__proto__到底是什么。

我们来定义一个构造函数

function Person() {}

console.log(Person.prototype)

打印出 Person 的 prototype 属性,结果如下:

{
constructor: ƒ Person(),
__proto__: {
constructor: ƒ Object(),
hasOwnProperty: ƒ hasOwnProperty(),
isPrototypeOf: ƒ isPrototypeOf(),
propertyIsEnumerable: ƒ propertyIsEnumerable(),
toLocaleString: ƒ toLocaleString(),
toString: ƒ toString(),
valueOf: ƒ valueOf()
}
}

可以看到,这个属性包含了consturcor属性(指向自己)和__proto__属性(指向Object.prototype,即根对象。因为在js里,函数也是对象,继承自根对象)。所有的函数都有这样一个叫做prototype的属性,即原型对象,我们可以在原型对象上定义属性和方法:

Person.prototype.name = 'Jack'
Person.prototype.jump = function() {
console.log(this.name + '-jump')
}
console.log(Person.prototype)

这时打印出的原型对象为

{
name: "Jack",
jump: ƒ (),
constructor: ƒ doSomething(),
__proto__: {
constructor: ƒ Object(),
hasOwnProperty: ƒ hasOwnProperty(),
isPrototypeOf: ƒ isPrototypeOf(),
propertyIsEnumerable: ƒ propertyIsEnumerable(),
toLocaleString: ƒ toLocaleString(),
toString: ƒ toString(),
valueOf: ƒ valueOf()
}
}

name 属性和 jump 方法被加到了这个对象上面。那么,这个原型对象有什么用呢?

我们再用这个构造函数创建一个实例:

function Person() {}
Person.prototype.name = 'Jack'var jack = new Person()
jack.sex = 'male'
console.log(jack)

我们在构造函数原型和实例对象上都加了属性,现在把 jack 打印出来如下:

{
sex: "male",
__proto__: {
name: "Jack",
constructor: ƒ doSomething(),
__proto__: {
constructor: ƒ Object(),
hasOwnProperty: ƒ hasOwnProperty(),
isPrototypeOf: ƒ isPrototypeOf(),
propertyIsEnumerable: ƒ propertyIsEnumerable(),
toLocaleString: ƒ toLocaleString(),
toString: ƒ toString(),
valueOf: ƒ valueOf()
}
}

可以看到,jack 有个 __proto__ 属性,这个属性跟它的构造函数 Person 的 prototype 属性内容是一样的,我们打印如下内容:

console.log(jack.name)   // Jack

得到的结果是 “Jack”,在jack的属性里并没有name这一项,name 是定义在Person 的 prototype 属性上的,然而我们却能从jack中访问到,这就是原型的继承作用。我们访问jack.name时,浏览器首先查找jack有没有name属性,有的话直接获取,没有的话会去jack.__proto__属性里查询,再查不到继续在jack.__proto__.proto__里找……由此形成一条链,即原型链。在这里jack.__proto__.__proto__就是Object.prototype。需要注意的是,原型继承的核心是prototype,而不是__proto__,__proto__是浏览器内部属性,只是用来访问原型对象prototype属性的。下面我们来看一下怎么让两个不相关的对象通过原型链实现继承。

// 定义父对象
var father = {
name: 'Jack'
}
// 定义子对象的构造函数
function Son() {}
// 令子对象的构造函数的原型指向父对象
Son.prototype = father
// 创建子对象实例
var son = new Son() console.log(son.name) // Jack

核心代码就是标红的那句:令子对象的构造函数的原型对象指向父对象。

总结:在javascript里,每个函数都有叫做原型对象的prototype属性,js的根对象是Object.prototype。通过构造函数创建出的实例能继承构造函数原型对象的属性和方法。

javascript 面向对象学习(二)——原型与继承的更多相关文章

  1. JavaScript之面向对象学习二(原型属性对象与in操作符)获取对象中所有属性的方法

    1.原型属性对象于in操作符之in单独使用 有两种方式使用in操作符:单独使用和在for-in循环中使用.在单独使用中,代码如下: function Person(){ } Person.protot ...

  2. (二)Javascript面向对象编程:构造函数的继承

    Javascript面向对象编程:构造函数的继承   这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生成实例. 今天要介绍的是,对象之间的"继承 ...

  3. JavaScript 面向对象程序设计(下)——继承与多态 【转】

    JavaScript 面向对象程序设计(下)--继承与多态 前面我们讨论了如何在 JavaScript 语言中实现对私有实例成员.公有实例成员.私有静态成员.公有静态成员和静态类的封装.这次我们来讨论 ...

  4. Lua面向对象之二:类继承

    1.类继承 ①代码 Sharp = { } --① 父类 function Sharp:new() local new_sharp = { } self.__index = self --②,self ...

  5. Javascript面向对象特性实现封装、继承、接口详细案例——进级高手篇

    Javascript面向对象特性实现(封装.继承.接口) Javascript作为弱类型语言,和Java.php等服务端脚本语言相比,拥有极强的灵活性.对于小型的web需求,在编写javascript ...

  6. Javascript面向对象特性实现封装、继承、接口详细案例

    Javascript面向对象特性实现(封装.继承.接口) Javascript作为弱类型语言,和Java.php等服务端脚本语言相比,拥有极强的灵活性.对于小型的web需求,在编写javascript ...

  7. JavaScript面向对象学习笔记

    JavaScript 常被描述为一种基于原型的语言 (prototype-based language)--每个对象拥有一个原型对象,对象以其原型为模板.从原型继承方法和属性.原型对象也可能拥有原型, ...

  8. javascript 面向对象 new 关键字 原型链 构造函数

    JavaScript面向对象JavaScript 语言使用构造函数(constructor)作为对象的模板.所谓"构造函数",就是专门用来生成实例对象的函数.它就是对象的模板,描述 ...

  9. JavaScript面向对象 实例与原型

    JavaScript 面向对象 和 C# 不太一样,js 的对象是继承自原型的如下: 首先创建一个 js 实例 new  function function f () {} 这个函数 会继承 Func ...

随机推荐

  1. Scrapy 框架 入门教程

    Scrapy入门教程 在本篇教程中,我已经安装好Scrapy 本篇教程中将带您完成下列任务: 创建一个Scrapy项目 定义提取的Item 编写爬取网站的 spider 并提取 Item 编写 Ite ...

  2. 委托 事件 observer

    详细介绍http://www.cnblogs.com/jcz1206/articles/2730793.html  ---摘录别人的 using System;using System.Collect ...

  3. 矩阵重叠面积计算 线段树hdu1542

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  4. python 日期、时间

    1.字符类型的时间 转为 时间数组 t1 = '2013-10-10 23:40:00'timeArray = time.strptime(t1, "%Y-%m-%d %H:%M:%S&qu ...

  5. Java——线程安全的集合

    线程安全的集合    java.util.concurrent包:ConcurrentHashMap,ConcurrentSkipListMap,ConcurrentSkipListSet,Concu ...

  6. vue路由中使用keep-alive 以及activated和deactivated 钩子

    本次只是记录下开发中碰到的问题. 最近做一个活动页面,涉及到角色和权限的问题,需要跳转很多页面,于是vue-router走起,顺便keep-alive也用起来了,嗯,跳转的很爽,但是一个详情页面组件, ...

  7. 【JavaScript数据结构系列】02-栈Stack

    [JavaScript数据结构系列]02-栈Stack 码路工人 CoderMonkey 转载请注明作者与出处 ## 1. 认识栈结构 栈是非常常用的一种数据结构,与数组同属线性数据结构,不同于数组的 ...

  8. [C#学习教程-委托]001.大道至简之委托(代理),匿名函数,Lambda表达式

    引言:此文翻译自CodeProject上的同名文章<C# Delegates,Anonymous Methods, and Lambda Expressions>,在此一起Mark一下,此 ...

  9. [JavaWeb基础] 014.Struts2 标签库学习

    在Struts1和Struts2中都有很多很方便使用的标签库,使用它可以让我们的页面代码更加的简洁,易懂,规范.标签的形式就跟html的标签形式一样.上面的篇章中我们也讲解了自定义标签那么在如何使用标 ...

  10. 五、Java - 集合

    一.集合 Java 中的集合类存放于 java.util 包中,是一个存放对象的容器. 集合存放的是对对象的引用,对象本身还是存在于 JVM 堆内存中. 存放的是对象,即引用数据类型,对于基本数据类型 ...