什么是原型?

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

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. 终于明白了vue使用axios发送post请求时的坑及解决原理

    前言:在做项目的时候正好同事碰到了这个问题,问为什么用axios在发送请求的时候没有成功,请求不到数据,反而是报错了,下图就是报错请求本尊 vue里代码如下: this.$http.post('/ge ...

  2. 初识Mysql 外键

    1.创建学生表(主表) CREATE TABLE `stu` ( `stunum` int(10) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT N ...

  3. C语言数据类型整理

    基本类型: 它们是算术类型,包括两种类型:整数类型和浮点类型. 枚举类型: 它们也是算术类型,被用来定义在程序中只能赋予其一定的离散整数值的变量. void 类型: 类型说明符 void 表明没有可用 ...

  4. 【java】关键字volatile

    volatile 1. 含义: volatile是JVM提供的轻量级的同步机制,具有三个特点:保证可见性.不保证原子性.禁止指令重排. 1.1 保证可见性 一个线程修改了共享变量并写回主内存,其他线程 ...

  5. [PHP自动化-进阶]001.CURL模拟登录并采集数据

    引言:PHP可以通过libcurl实现模拟登录,提交数据,违法乱纪,烧杀抢虐等等事项. 简单说明一下"libcurl",补一下脑: libcurl目前支持http.https.ft ...

  6. nginx 配置重定向及nginx配置if

    需求:地址 http://testa/inlinePreview/live.html?id=463738305721405440重定向到 http://testb/shares/live.html?n ...

  7. Parrot os安装docker及docker-compose

    一.安装docker 1.添加Docker pgp key curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key ...

  8. Rocket - debug - dm registers

    https://mp.weixin.qq.com/s/P48K17TyRoZC7xBMltbXKQ 简单介绍调试模块中每个寄存器的定义. 1. DMI_RegAddrs 记录DMI访问的各个寄存器的地 ...

  9. Rocket - tilelink - Bundles

    https://mp.weixin.qq.com/s/jrqBg2AIpQogBrpwNXjmwg   简单介绍Bundles文件中对TileLink规范(1.7.1)的定义. 参考链接:https: ...

  10. hdl - 软件编程与硬件建模

    https://mp.weixin.qq.com/s/Y75I9e3s4fDPZuv-CyiNDA   介绍软件编程思维与硬件建模思维的不同与相似之处.   ​​   1. 软件编程思维   编程,意 ...