第八章 面向对象之二:function与面向对象的关系(两个实现面向对象的重要属性)

每一个函数建立完成之后,javaScript都会自动的给它添加两个属性和一个配套对象(配套类),即prototype属性和__proto__属性,而配套对象(类)叫做“原型对象”。

只要是函数,它就有这个原型对象,我们无法删除它。

原型对象的意义在于,它包含的属性和方法对于通过此函数创建的实例来说,是公用的。而我们在函数本身内部定义的属性和方法不是公用的,每次建立实例之后,虽然两个实例都具有想通的属性和方法,但是实际上是两份相同的拷贝,并不是同一段内存的属性和方法,它们的各自修改不会对其他实例造成影响,但是这对于内存的高效率使用是很不方便的。

函数(类)才有原型对象属性(prototype属性),实例是没有的。这对于javaScript自带的构造函数(Array、Boolean、RegExp等)也是一样的。

我们如何使用原型对象?函数本身的prototype属性保存的就是原型对象的地址,我们可以通过prototype属性访问(设置)原型对象的属性和方法(函数.prototype.属性/方法)。

原型对象本身跟普通对象(函数、类)是基本一样的,它也可以有自定义的属性和方法,区别在于以下两点:

一、 它没有prototype属性。(其实可以理解,本身已经是原型对象了)
二、 它有一个constructor属性,保存的是函数(类)本身的地址。也就是通过constructor属性,原型对象可以找到它所配套的原始函数。(也就是它知道它是谁的原型对象)。

<script>
function Person() { // 创建一个空函数(类)

}

// 添加原型属性和方法
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "sofeware Engineer";
Person.prototype.sayName = function () {
console.log( this.name );
};

// Person.prototype = {

// person1和person2的sayName是同一个内存地址的函数
var person1 = new Person();
person1.sayName();
var person2 = new Person();
person2.sayName();
console.log( person1.sayName === person2.sayName );
// -----------------------------------------------------

// 看看函数是否有perototype属性(有的,而且Array是js自带的构造函数,当然也有)
console.dir( Array );
// -----------------------------------------------------

// 看实例是否有prototype属性(实际没有,但是有__proto__属性)
var a = new Array();
console.dir( a );
console.dir( person1 );
// -----------------------------------------------------

</script>

请仔细查看console输出的信息,对照我们上边整理的知识点。

__proto___跟prototype一样,都是函数自带的属性,当然这个属性不止是函数有,通过函数(类)创建的实例也是有的。

在ECMAScript里管这个属性称为“[[Prototype]]”,在浏览器里的实现称为:__proto__。它包含的是指向创造这个实例函数(类)的原型对象。听着有点晕,就是实例一般都是通过new 函数()这种表达式创造出来的,这个实例的__proto__属性指向的就是这个函数的原型对象。

__proto__本身是无法修改的,但是某些浏览器为了方便把__proto__暴露出来了,我们可以对他进行修改,比如firefox和chrome。

__proto__属性是javaScript实现原型链的关键,javaScript实现面向对象的继承是基于原型链的,因此__proto__属性是javaScript实现继承的根本,搞清楚__proto__的真相就理解了继承。

我们说所有的函数和实例都包含__proto__属性,javaScript内部的称为内建类型的Array类型(实际上Array是一个函数)也有,它的__proto__的指向应该是它的父类的原型对象,也就是Function的原型对象。

Object在javaScript里是所有函数(类)的基类,实际上javaScript自带的内建类型(Array,Boolean,String,Function,RegExp,Error等)的父类都是object。

在javaScript里,可以理解为所有的函数都是通过Function关键字来进行初始化的,比如Person(){}这个空函数,实际上可以理解为Person = new Function(),也就是说,我们创建一个自定义函数Person,它的__proto__应该指向Function的原型对象,而Function原型对象的__proto__指向Object的原型对象,Object的__proto__是null。如此,构成了从实例到根父类的连接,这就是原型链。

因此可以说,函数是一个特殊的存在,它既是一个类,也是一个实例。

当执行实例的一个方法时,javaScript这么规定,先找实例本身是否有此方法,没有按照 __proto__的指向找向父类的对象,如果父类对象没有这个方法则找父类对象的原型对象,看父类的原型对象是否有此方法,如果没有按照父类原型对象的__proto__的指向找父父类的原型对象,父父类对象没有去找父父类对象的原型对象,如果找到那么执行,如果还找不到就继续向上,一直到object的原型对象的__proto__指向的null。

我们可以通过实例的__proto__访问父类原型对象的属性和方法,但是无法更改它,我们自定义一个同名的属性或方法会覆盖掉父类的属性和方法。如果我们覆盖了同名属性或方法,通过delete操作符可以删除实例的同名属性或方法,从而重新访问父类的属性和方法。

person1.name = "Greg";
person1.sayName(); // 来自实例
person2.sayName(); // 来自继承

delete person1.name;
person1.sayName(); // 来自继承
person2.sayName(); // 来自继承

有关原型的几个函数:
1、 isPrototypeOf/Object.getPrototypeof():访问__proto__。

  • isPrototypeOf用法:父类.isPrototypeOf(实例),返回true表明实例的__proto__指向父类的原型对象,false则相反。
  • Object.getPototypeof(实例):返回实例的__proto__引用,并且Object.getPrototypeOf(实例).原型属性/方法可以直接调用原型的属性和方法。

2、 hasOwnProperty:
用法:实例.hasOwnProperty(属性/方法名)
判断属性或方法名是否来自于实例(或原型),在实例内返回true,在原型中返回false。

时间: 2024-10-05 03:59:21

第八章 面向对象之二:function与面向对象的关系(两个实现面向对象的重要属性)的相关文章

Java_Day06(java 基础下与面向对象,二维数组与面向对象基础)

1:二维数组(理解) (1)元素是一维数组的数组. (2)格式: A:数据类型[][] 数组名 = new 数据类型[m][n]; m表示这个二维数组有多少个一维数组 n表示每一个一维数组的元素个数 以下格式也可以表示二维数组:不推荐这样去使用 数据类型 数组名[][] = new 数据类型[m][n]; 数据类型[] 数组名[] = new 数据类型[m][n]; B:数据类型[][] 数组名 = new 数据类型[m][]; C:数据类型[][] 数组名 = new 数据类型[][]{{..

面向对象系列二(封装)

只需要最简单的操作就能实现一系列复杂的功能,是做一个个技术攻克的目的.一台精密仪器,一架家用电器,一个小米手机,这些可能我们都在用,或者用过.它们的内部都无比的复杂,使用了各种各样的配件,运用了极多的原理和知识.我们在使用的时候都具有相同的感受:简单.方便.太好了!面对原本复杂的东西,我们却能通过简单介绍就能运用自如,甚至有的能无师自通,这都为什么?这就用到了面向对象的封装性. 面向对象的封装性就是将复杂的处理封装在"盒子"的内部,只凭借装外壳的少量的按钮或键盘就能轻松实现功能.哦,原

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

这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生成实例. 今天要介绍的是,对象之间的"继承"的五种方法. 比如,现在有一个"动物"对象的构造函数. function Animal(){ this.species = "动物"; } 还有一个"猫"对象的构造函数. function Cat(name,color){ this.name = name; this.color = col

第八章 用户界面(二)

在 WinForm 上使用控件 控件就是类,派生自 System.Windows.Forms.Control,由此类派生出的任何类都能显示在窗体上,只要将它添加到窗体对象的 Controls 集合中. 现在我们看一下用控件画树形的方法.WinForms 库定义了 TreeView 类,这是专门用于显示树形结构的:自然,我们就用这个控件来显示树.使用 TreeView,需要创建它的实例,并设置属性.调用方法,对它进行配置.最重要的,是将需要显示的结点添加到 Nodes 集合中.这个控件准备好以后,

一张图看懂Function和Object的关系及简述instanceof运算符

我在写一篇图解prototype和__proto__的区别时,搜资料搜到了一个有意思的现象,下面这两个运算返回的结果是一样的: Function instanceof Object;//true Object instanceof Function;//true 这个是怎么一回事呢?要从运算符instanceof说起. 一.instanceof究竟是运算什么的? 我曾经简单理解instanceof只是检测一个对象是否是另个对象new出来的实例(例如var a = new Object(),a i

JavaScript中Function和Object的关系

今天,QQ技术讨论群里面有一个人在聊天,说今天面试,面试官问他的第一个问题他就懵逼了,说是Function和Object的关系,或者说他们有什么区别.当时我微微一笑,心想这么简单的问题你都解释不清楚,那你竟然还有信心去面试.可是,当我试图组织语言来嘲讽他几句时,发现我也组织不清楚.痛定思痛,一步一步来屡一下他们之间的关系. 首先,Function是一个构造函数,那它一定就有它对应的原型对象Function.prototype,我们使用控制台打印可以得出Function.prototype=fun

JS原型的问题Object和Function到底是什么关系

var F = function(){}; Objcert.prototype.a = function(){}; Function.prototype.b = function(){}; F 既能访问到a,也能访问到(Object 和 Function也同样,但是所有的实例只能访问到a):F是Object 和 Function 两个的实例,那么Object 和 Function 到底是什么关系? 下面是对Object 和 Function 的了解 F instanceof Object tru

指针与二维数组间的关系

1.四种表示a[i][j]的形式是等价的: a[i][j]==*(a[i]+j)==*(*(a+i)+j)==(*(a+i))[j] 2.通过行指针p引用二维数组a的元素a[i][j]的方法可用以下4种等价形式: p[i][j]==*(p[i]+j)==*(*(p+i)+j)==(*(p+i))[j] 3.对指向二维数组的行指针p进行初始化的方法: p=a 或p=&a[0] 4.对指向二维数组的列指针进行初始化的方法(以下三种方法等价): p=a[0] 或 p=*a 或 p=&a[0][0

Function和Object的关系

Function和Object的关系 借别人的图,借用里面的例子,声明了一个构造函数Foo,通过构造函数Foo声明了一个f1实例,以下记录自己的分析理解. 这两条线比较乱,要是绕的脑子乱了跳过就好. 主线:(从f1实例到null是一条笔直的链条) f1继承自构造函数Foo的显式原型Foo.prototype:f1.__proto__ ——> Foo.prototype Foo.prototype继承自Foo函数的构造函数Object的原型Object.prototype:Foo.prototyp