(欢迎一起探讨,如果有什么地方写的不准确或是不正确也欢迎大家指出来~)

PS:

  • 建议将构造函数中的方法都定义到构造函数的原型中,那么由该构造函数创建的实例的方法都会指向同一个方法。(在构造函数内部声明的话,每创建一个实例都会重新实例化函数,那么每个实例中的函数的指向是不同的;如果定义在全局作用域中,且有很多方法,这样毫无封装性可言。)

一、属性和方法

构造函数可以定义三种属性和方法:

对象属性/对象方法:构造函数内定义的属性/方法

静态属性/静态方法:构造函数的静态属性/方法

原型属性/原型方法:构造函数的原型属性/方法

实例:

function Shape() {
// 对象属性和对象方法
this.color = 'red';
this.show = function(){
console.log('show')
}
} // 静态属性和静态方法
Shape.type = 'auto'
Shape.printing = function(){
console.log('Shape')
} // 原型属性和原型方法
Shape.prototype.area = 'unknow'
Shape.prototype.move = function() {
console.info('move');
}; // 实例
var rect = new Shape(); console.log(rect.color) // red
console.log(rect.show()) // show console.log(rect.area) // unknow
console.log(rect.move()) // move console.log(Shape.type) //auto
console.log(Shape.printing()) //Shape console.log(rect.type) // undefined
console.log(rect.printing) // undefined

构造函数的对象属性和对象方法、原型属性和原型方法,对应的实例都可以调用;

构造函数的静态属性和静态方法,对应的实例获取不到,会提示undefined,但是可由构造函数本身调用。

调用属性、方法 对象属性和对象方法 原型属性和原型方法 静态属性和静态方法
构造函数 undefined undefined 可以得到
实例 可以得到 可以得到 undefined

二、prototype、constructor、__proto__

在以上的基础上,再实例化一个新的对象和普通函数。

var circle = new Shape();

function test(){
console.log('test')
} console.log(Shape.prototype) // {area: "unknow", move: ƒ, constructor: ƒ}
console.log(Shape.constructor) // ƒ Function() { [native code] }
console.log(Shape.__proto__) // ƒ () { [native code] }
console.log(Shape.prototype.constructor) // ƒ Shape() { ... }
console.log(Shape.prototype.constructor === Shape) // true 构造函数的显式原型的构造器指向构造函数 // Shape的constructor(构造器)指向Function,__proto__(隐式原型)指向Function的原型ƒ () { [native code] }。
// 检测
console.log(Shape.__proto__ === Function.prototype) // true console.log(rect.prototype) // undefined
console.log(rect.constructor) // ƒ Shape() { ... }
console.log(rect.__proto__) // {area: "unknow", move: ƒ, constructor: ƒ} console.log(circle.prototype) // undefined
console.log(circle.constructor) // ƒ Shape() { ... }
console.log(circle.__proto__) // {area: "unknow", move: ƒ, constructor: ƒ} // 综上可以知道,
// 实例的原型均为undefined
// 实例(rect、circle)的隐式原型__proto__指向构造函数(Shape)的显式原型prototype
// 实例(rect、circle)的构造器constructor指向构造其的构造函数(Shape),代表是Shape的实例
// 而构造函数(Shape)是函数Function的实例,所以它的构造器是函数Function
// 那么构造函数(Shape)的隐式原型__proto__指向的是函数Function的显式原型prototype console.log(test.prototype) // {constructor: ƒ} test的原型指向一个包含construct和__proto__的对象
console.log(test.constructor) // ƒ Function() { [native code] }
console.log(test.__proto__) // ƒ () { [native code] } // 那么同理,普通函数的构造器指向Function;普通函数的隐式原型__ptoto__指向Function的显式原型prototype
console.log(test.__proto__ === Function.prototype) // true

所以,

指向 prototype显式原型 constructor构造器 __proto__隐式原型 prototype.constructor(显式原型的构造器)
构造函数 构造函数的原型 Function ƒ () { [native code] } 其本身
实例 undefined 构造其本身的构造函数 构造其本身的构造函数的原型 Cannot read property 'constructor' of undefined
普通函数 一个包含construct和__proto__的对象 Function ƒ () { [native code] } 其本身

综上可以知道

  • 实例的构造器constructor都指向构造其本身的构造函数。

  • 实例的隐式原型__proto__,均指向构造其本身的构造函数的显式原型prototype。

  • 构造函数也是函数,它的隐式原型__proto__指向Function的显式原型。

验证一下。

console.log(Shape.__proto__ === Shape.constructor.prototype) // true
console.log(Shape.__proto__ === Function.prototype) // true console.log(rect.__proto__ === rect.constructor.prototype) // true
console.log(rect.__proto__ === Shape.prototype) // true console.log(circle.__proto__ === circle.constructor.prototype) // true
console.log(circle.__proto__ === Shape.prototype) // true console.log(test.__proto__ === test.constructor.prototype) // true
console.log(test.__proto__ === Function.prototype) // true

可能会有人觉得实例也是函数,所以会有疑问:实例的原型为什么是undefined

来验证一下

// test的原型和rect、circle的原型可能会有疑问
console.log(typeof test) // "function"
console.log(typeof rect + '---' + typeof circle) // "object---object"

每个函数都有prototype属性。

实例都有一个constructor(构造函数)属性,该属性指向构造它的构造函数。

调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。即__proto__属性。

默认情况下,所有原型对象prototype都会自动获得一个constructor属性,这个属性包含一个指向原型对象prototype属性的函数的指针。如:Shape.prototype.constructor === Shape

构造函数的原型对象prototype就是通过调用构造函数而创建的那个对象实例的隐式原型。

使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。(重点在 共享


PS:

几个方法:

显式原型相关:

可以通过 hasOwnProperty 判断一个对象是否包含自定义属性而不是原型链上的属性。

in 操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例还是原型中。

同时使用 hasOwnPropertyin 操作符,就可以确定该属性到底是存在于对象中,还是存在于原型中。

// hasOwnProperty
console.log(rect.hasOwnProperty('color')) // true
console.log(rect.hasOwnProperty('area')) // false // in操作符
console.log('color' in rect); // true
console.log('area' in rect); // true

隐式原型相关:

可以通过 isPrototypeOf 来确定对象之间的关系(__proto__)

可以通过 Object.getPrototypeOf() 得到__proto__的值。

// isPrototypeOf
console.log(Shape.prototype.isPrototypeOf(rect)) // true
console.log(Shape.prototype.isPrototypeOf(test)) // false // Object.getPrototypeOf()
console.log(Object.getPrototypeOf(rect) === Shape.prototype); // true
console.log(Object.getPrototypeOf(test) === Shape.prototype); // false

原型链:

通过原型添加的属性和方法,实例中虽然不包含这些属性和方法,但是却可以使用在构造函数的原型中定义的属性和方法。

实例通过隐式原型__proto__去该构造函数的原型中去找属性和方法,如果没有,该构造函数的原型通过它的隐式原型__proto__去找构造它的构造函数的原型中去找,以此类推。这个通过__proto__属性连接起来的链条就是原型链。

原型链最终得到的值是null;Object的原型对象是原型链的尽头。


// 隐式原型
console.log(circle.__proto__ === Shape.prototype) // true
console.log(circle.__proto__.__proto__ === Object.prototype) // true
console.log(circle.__proto__.__proto__.__proto__) // null /*
* 以上代码可以理解为
* circle.__proto__ === Shape.prototype
* Shape.prototype.__proto__ === Object.prototype
* Object.prototype.__proto__ === null
*/

额外:

那么Function呢?

console.log(Function.constructor === Function) // true
console.log(Function.constructor === Object) // false // 根据以上输出,可以认为它的__proto__就是它的prototype
console.log(Function.__proto__ === Function.prototype) // true 这句说明Function是Function的实例对象

另外,Function和Object是什么关系呢?

console.log(Object.constructor === Function) // true
console.log(Object.constructor === Object) // false console.log(Object.__proto__ === Function.prototype) // true 这句说明Object是Function的实例对象
// 那么Object也是函数

另外,instanceof的例子

// =====instanceof 用来检测 构造函数的 prototype 属性是否出现在某个实例对象的原型链上
console.log(Object instanceof Function) // true
// 因为Object.__proto__ === Function.prototype console.log(Object instanceof Object) // true
// 因为Object.__proto__ === Function.prototype,Function.prototype.__proto__ === Object.prototype console.log(Function instanceof Function) // true
// 因为 Function.__proto__ === Function.prototype console.log(Function instanceof Object) // true
// 因为 Function.__proto__ === Function.prototype,Function.prototype.__proto__ === Object.prototype

参考:

https://segmentfault.com/q/1010000000249140

构造函数、原型对象prototype、实例、隐式原型__proto__的理解的更多相关文章

  1. 275 原型与原型链:显式原型prototype ,隐式原型__proto__,隐式原型链,原型链_属性问题,给原型对象添加属性/方法

    1.所有函数都有一个特别的属性 prototype : 显式原型属性 [普通构造函数的实例对象没有prototype 属性,构造函数有__proto__属性,原型对象有__proto__属性 ] 2. ...

  2. JS 原型链 prototypt 和隐式原型 _proto_

    prototype(原型) :  对象的一个属性,此属性使您有能力向对象添加属性和方法,当访问对象不存在属性是会自动到 prototype 中找 _proto_(隐式原型): 此对象构造函数(类)的原 ...

  3. JavaScript 隐式原型(_proto_)与显示原型(prototype)

    作者:苏墨橘链接:https://www.zhihu.com/question/34183746/answer/59043879来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...

  4. [js高手之路]原型对象(prototype)与原型链相关属性与方法详解

    一,instanceof: instanceof检测左侧的__proto__原型链上,是否存在右侧的prototype原型. 我在之前的两篇文章 [js高手之路]构造函数的基本特性与优缺点 [js高手 ...

  5. JS高阶---显式原型和隐式原型

    前言: 1.函数对象即函数的prototype原型属性指向原型对象,在创建函数时便存在,默认为空Object 2.实例对象的__proto__隐式原型在实例化创建实例时产生,值等于构造函数的显式pro ...

  6. js高级——构造函数,实例对象和原型对象——prototype、__proto__和constructor构造器

    一.前言 了解JavaScript面向对象,需要先了解三个名词: 构造函数,实例对象和原型对象. 注意:JavaScript中没有类(class)的概念,取而代之的是构造函数,两者类似却又有很大的差别 ...

  7. Javascript 构造函数、原型对象、实例之间的关系

    # Javascript 构造函数.原型对象.实例之间的关系 # 创建对象的方式 # 1.new object() 缺点:创建多个对象困难 var hero = new Object(); // 空对 ...

  8. [js高手之路]使用原型对象(prototype)需要注意的地方

    我们先来一个简单的构造函数+原型对象的小程序 function CreateObj( uName, uAge ) { this.userName = uName; this.userAge = uAg ...

  9. 原型链 | 显示原型、隐式原型 | 构造关系constructor | instanceof

    1.原型关系 prototype 显式原型:prototype 隐式原型:__proto__ 1. 每个函数function都有一个prototype,即显式原型(属性)2. 每个实例对象都有一个__ ...

随机推荐

  1. A表数据插入到B表(表结构不一致)

    D_A  有E\F\H 3字段 D_B 有 A\B\C\D\E\ID 字段 将 D_B 个别字段插入到D_A  表 INSERT INTO  D_A(E,F,H) select B,A,ID from ...

  2. bzoj 2424: [HAOI2010]订货 (费用流)

    直接费用流,天数就是点数 type arr=record toward,next,cap,cost:longint; end; const maxm=; maxn=; mm=<<; var ...

  3. BZOJ4199:[NOI2015]品酒大会——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4199 https://www.luogu.org/problemnew/show/P2178#su ...

  4. 20165218 2017-2018-1 《Java程序设计》第三周学习总结

    20165218 2017-2018-1 <Java程序设计>第三周学习总结 教材学习内容总结-第四章 类与对象 面向对象语言 需要完成某种任务时,首先要想到,谁去完成任务,即哪个对象去完 ...

  5. UVA.357 Let Me Count The Ways (DP 完全背包)

    UVA.357 Let Me Count The Ways (DP 完全背包) 题意分析 与UVA.UVA.674 Coin Change是一模一样的题.需要注意的是,此题的数据量较大,dp数组需要使 ...

  6. 洛谷P3396 哈希冲突 (分块)

    洛谷P3396 哈希冲突 题目背景 此题约为NOIP提高组Day2T2难度. 题目描述 众所周知,模数的hash会产生冲突.例如,如果模的数p=7,那么4和11便冲突了. B君对hash冲突很感兴趣. ...

  7. HDU1281: 棋盘游戏(二分图匹配)

    棋盘游戏 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  8. group by多字段分组

    在平时的开发任务中我们经常会用到MYSQL的GROUP BY分组, 用来获取数据表中以分组字段为依据的统计数据.比如有一个学生选课表,表结构如下: Table: Subject_Selection S ...

  9. 搭建JavaWeb应用开发环境

    下载和安装Tomcat服务器 下载Tomcat安装程序包:http://tomcat.apache.org/,下载一个zip版本,解压到本地即完成了Tomcat的安装. 测试是否安装成功:进入Tomc ...

  10. POJ2155 树状数组

    Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 26650   Accepted: 9825 Descripti ...