JS 中原型和原型链深入理解
作者: erdu
segmentfault.com/a/1190000014717972
首先要搞明白几个概念:
函数(function)
函数对象(function object)
本地对象(native object)
内置对象(build-in object)
宿主对象(host object)
函数
function foo(){
}
var foo = function(){
}
前者为函数声明,后者为函数表达式。typeof foo的结果都是function。
函数对象
函数就是对象,代表函数的对象就是函数对象
官方定义, 在Javascript中,每一个函数实际上都是一个函数对象.JavaScript代码中定义函数,或者调用Function创建函数时,最终都会以类似这样的形式调用Function函数:var newFun = new Function(funArgs, funBody)
其实也就是说,我们定义的函数,语法上,都称为函数对象,看我们如何去使用。如果我们单纯的把它当成一个函数使用,那么它就是函数,如果我们通过他来实例化出对象来使用,那么它就可以当成一个函数对象来使用,在面向对象的范畴里面,函数对象类似于类的概念。
var foo = new function(){
}
typeof foo // object
或者
function Foo (){
}
var foo = new Foo();
typeof foo // object
上面,我们所建立的对象
本地对象
ECMA-262 把本地对象(native object)定义为“独立于宿主环境的 ECMAScript 实现提供的对象”。简单来说,本地对象就是 ECMA-262 定义的类(引用类型)。它们包括:
Object,Function,Array,String,Boolean,Number
Date,RegExp,Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError.
我们不能被他们起的名字是本地对象,就把他们理解成对象(虽然是事实上,它就是一个对象,因为JS中万物皆为对象),通过
typeof(Object)
typeof(Array)
typeof(Date)
typeof(RegExp)
typeof(Math)
返回的结果都是function
也就是说其实这些本地对象(类)是通过function建立起来的,
function Object(){
}
function Array(){
}
...
可以看出Object原本就是一个函数,通过new Object()之后实例化后,创建对象。类似于JAVA中的类。
内置对象
ECMA-262 把内置对象(built-in object)定义为“由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现”。这意味着开发者不必明确实例化内置对象,它已被实例化了。ECMA-262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每个内置对象都是本地对象)。
理清楚了这几个概念,有助于理解我们下面要讲述的原型和原型链。
prototype
prototype属性是每一个函数都具有的属性,但是不是一个对象都具有的属性。比如
function Foo(){
}
var foo = new Foo();
其中Foo中有prototype属性,而foo没有。但是foo中的隐含的__proto__属性指向Foo.prototype。
foo.__proto__ === Foo.prototype
为什么会存在prototype属性?
Javascript里面所有的数据类型都是对象,为了使JavaScript实现面向对象的思想,就必须要能够实现‘继承’使所有的对象连接起来。而如何实现继承呢?JavaScript采用了类似C++,java的方式,通过new的方式来实现实例。
举个例子,child1,child2都是Mother的孩子,且是双胞胎。(虽然不是很好,但是还是很能说明问题的)
function Mother(name){
this.name = name;
this.father = 'baba';
}
var child1 = new Mother('huahua');
var child2 = new Mother('huihui');
如果有一天,发现孩子的父亲其实是Baba,那么就要对孩子每一个孩子的father属性。
child1.father ='Baba';
console.log(child2.father) // baba
也就是说修改了其中一个孩子的father属性不会影响到下一个,属性的值无法共享。
正是这个原因才提出来prototype属性,把需要共享的属性放到构造函数也就是父类的实例中去。
__proto__
__proto__属性是每一个对象以及函数都隐含的一个属性。对于每一个含有__proto__属性,他所指向的是创建他的构造函数的prototype。原型链就是通过这个属性构件的。
想像一下,如果一个函数对象(也成为构造函数)a的prototype是另一个函数对象b构件出的实例,a的实例就可以通过__proto__与b的原型链起来。而b的原型其实就是Object的实例,所以a的实例对象,就可以通过原型链和object的prototype链接起来。
function a(){
}
function b(){
}
var b1 = new b();
a.prototype = b1;
var a1 = new a();
console.log(a1.__proto__===b1);//true
console.log(a1.__proto__.__proto__===b.prototype) //true
console.log(a1.__proto__.__proto__.__proto__===Object.prototype) //true
如果要理清原型和原型链的关系,首先要明确一下几个概念:
1.JS中的所有东西都是对象,函数也是对象, 而且是一种特殊的对象
2.JS中所有的东西都由Object衍生而来, 即所有东西原型链的终点指向Object.prototype
3.JS对象都有一个隐藏的__proto__属性,他指向创建它的构造函数的原型,但是有一个例外,Object.prototype.__proto__指向的是null。
4.JS中构造函数和实例(对象)之间的微妙关系
构造函数通过定义prototype来约定其实例的规格, 再通过 new 来构造出实例,他们的作用就是生产对象.
function Foo(){
}
var foo = new Foo();
foo其实是通过Foo.prototype来生成实例的。
构造函数本身又是方法(Function)的实例, 因此也可以查到它的__proto__(原型链)
function Foo(){
}
等价于
var Foo= new Function();
而Function实际上是
function Function(){
Native Code
}
也就是等价于
var Function= new Function();
所以说Function是通过自己创建出来的。正常情况下对象的__proto__是指向创建它的构造函数的prototype的.所以Function的__proto__指向的Function.prototype
Object 实际上也是通过Function创建出来的
typeof(Object)//function
所以,
function Object(){
Native Code
}
等价于
var Object = new Function();
那么Object的__proto__指向的是Function.prototype,也即是
Object.__proto__ === Function.prototype //true
下面再来看Function.prototype的__proto__指向哪里
因为JS中所有的东西都是对象,那么,Function.prototype 也是对象,既然是对象,那么Function.prototype肯定是通过Object创建出来的,所以,
Function.prototype.__proto__ === Object.prototype //true
综上所述,Function和Object的原型以及原型链的关系可以归纳为下图。
对于单个的对象实例,如果通过Object创建,
var obj = new Object();
那么它的原型和原型链的关系如下图。
如果通过函数对象来创建,
function Foo(){
}
var foo = new Foo();
那么它的原型和原型链的关系如下图
那JavaScript的整体的原型和原型链中的关系就很清晰了,如下图所示
作者: erdu
segmentfault.com/a/1190000014717972
首先要搞明白几个概念:
函数(function)
函数对象(function object)
本地对象(native object)
内置对象(build-in object)
宿主对象(host object)
函数
function foo(){
}
var foo = function(){
}
前者为函数声明,后者为函数表达式。typeof foo的结果都是function。
函数对象
函数就是对象,代表函数的对象就是函数对象
官方定义, 在Javascript中,每一个函数实际上都是一个函数对象.JavaScript代码中定义函数,或者调用Function创建函数时,最终都会以类似这样的形式调用Function函数:var newFun = new Function(funArgs, funBody)
其实也就是说,我们定义的函数,语法上,都称为函数对象,看我们如何去使用。如果我们单纯的把它当成一个函数使用,那么它就是函数,如果我们通过他来实例化出对象来使用,那么它就可以当成一个函数对象来使用,在面向对象的范畴里面,函数对象类似于类的概念。
var foo = new function(){
}
typeof foo // object
或者
function Foo (){
}
var foo = new Foo();
typeof foo // object
上面,我们所建立的对象
本地对象
ECMA-262 把本地对象(native object)定义为“独立于宿主环境的 ECMAScript 实现提供的对象”。简单来说,本地对象就是 ECMA-262 定义的类(引用类型)。它们包括:
Object,Function,Array,String,Boolean,Number
Date,RegExp,Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError.
我们不能被他们起的名字是本地对象,就把他们理解成对象(虽然是事实上,它就是一个对象,因为JS中万物皆为对象),通过
typeof(Object)
typeof(Array)
typeof(Date)
typeof(RegExp)
typeof(Math)
返回的结果都是function
也就是说其实这些本地对象(类)是通过function建立起来的,
function Object(){
}
function Array(){
}
...
可以看出Object原本就是一个函数,通过new Object()之后实例化后,创建对象。类似于JAVA中的类。
内置对象
ECMA-262 把内置对象(built-in object)定义为“由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现”。这意味着开发者不必明确实例化内置对象,它已被实例化了。ECMA-262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每个内置对象都是本地对象)。
理清楚了这几个概念,有助于理解我们下面要讲述的原型和原型链。
prototype
prototype属性是每一个函数都具有的属性,但是不是一个对象都具有的属性。比如
function Foo(){
}
var foo = new Foo();
其中Foo中有prototype属性,而foo没有。但是foo中的隐含的__proto__属性指向Foo.prototype。
foo.__proto__ === Foo.prototype
为什么会存在prototype属性?
Javascript里面所有的数据类型都是对象,为了使JavaScript实现面向对象的思想,就必须要能够实现‘继承’使所有的对象连接起来。而如何实现继承呢?JavaScript采用了类似C++,java的方式,通过new的方式来实现实例。
举个例子,child1,child2都是Mother的孩子,且是双胞胎。(虽然不是很好,但是还是很能说明问题的)
function Mother(name){
this.name = name;
this.father = 'baba';
}
var child1 = new Mother('huahua');
var child2 = new Mother('huihui');
如果有一天,发现孩子的父亲其实是Baba,那么就要对孩子每一个孩子的father属性。
child1.father ='Baba';
console.log(child2.father) // baba
也就是说修改了其中一个孩子的father属性不会影响到下一个,属性的值无法共享。
正是这个原因才提出来prototype属性,把需要共享的属性放到构造函数也就是父类的实例中去。
__proto__
__proto__属性是每一个对象以及函数都隐含的一个属性。对于每一个含有__proto__属性,他所指向的是创建他的构造函数的prototype。原型链就是通过这个属性构件的。
想像一下,如果一个函数对象(也成为构造函数)a的prototype是另一个函数对象b构件出的实例,a的实例就可以通过__proto__与b的原型链起来。而b的原型其实就是Object的实例,所以a的实例对象,就可以通过原型链和object的prototype链接起来。
function a(){
}
function b(){
}
var b1 = new b();
a.prototype = b1;
var a1 = new a();
console.log(a1.__proto__===b1);//true
console.log(a1.__proto__.__proto__===b.prototype) //true
console.log(a1.__proto__.__proto__.__proto__===Object.prototype) //true
如果要理清原型和原型链的关系,首先要明确一下几个概念:
1.JS中的所有东西都是对象,函数也是对象, 而且是一种特殊的对象
2.JS中所有的东西都由Object衍生而来, 即所有东西原型链的终点指向Object.prototype
3.JS对象都有一个隐藏的__proto__属性,他指向创建它的构造函数的原型,但是有一个例外,Object.prototype.__proto__指向的是null。
4.JS中构造函数和实例(对象)之间的微妙关系
构造函数通过定义prototype来约定其实例的规格, 再通过 new 来构造出实例,他们的作用就是生产对象.
function Foo(){
}
var foo = new Foo();
foo其实是通过Foo.prototype来生成实例的。
构造函数本身又是方法(Function)的实例, 因此也可以查到它的__proto__(原型链)
function Foo(){
}
等价于
var Foo= new Function();
而Function实际上是
function Function(){
Native Code
}
也就是等价于
var Function= new Function();
所以说Function是通过自己创建出来的。正常情况下对象的__proto__是指向创建它的构造函数的prototype的.所以Function的__proto__指向的Function.prototype
Object 实际上也是通过Function创建出来的
typeof(Object)//function
所以,
function Object(){
Native Code
}
等价于
var Object = new Function();
那么Object的__proto__指向的是Function.prototype,也即是
Object.__proto__ === Function.prototype //true
下面再来看Function.prototype的__proto__指向哪里
因为JS中所有的东西都是对象,那么,Function.prototype 也是对象,既然是对象,那么Function.prototype肯定是通过Object创建出来的,所以,
Function.prototype.__proto__ === Object.prototype //true
综上所述,Function和Object的原型以及原型链的关系可以归纳为下图。
对于单个的对象实例,如果通过Object创建,
var obj = new Object();
那么它的原型和原型链的关系如下图。
如果通过函数对象来创建,
function Foo(){
}
var foo = new Foo();
那么它的原型和原型链的关系如下图
那JavaScript的整体的原型和原型链中的关系就很清晰了,如下图所示
JS 中原型和原型链深入理解相关推荐
- 《js中原型和原型链的深入理解》的笔记
前言:在微信公众号前端大全上看过<js中原型和原型链的深入理解>,个人认为这是我看过的js原型链的文章中,在思维结构上理解最清楚的一个文章了,本着温故而知新,有害怕找不到这个文章,我就把文 ...
- 前端开发:JS中原型和原型链的介绍
前言 在前端开发过程中,涉及到JS原理相关的内容也就是常用的几大模块,不仅常用而且很重要,但是涉及到原理的话会有点难懂,尤其是对JS接触不太久的开发者来讲.本篇博文就来分享一下关于JS的原型和原型链相 ...
- JS题目总结:原型链/new/json/MVC/Promise
JS题目总结:原型链/new/json/MVC/Promise 1原型链相关 解读: 上图中,Object,Function,Array,Boolean都是构造函数 第一个框: object是实例对象 ...
- 【JS继承】JS继承之原型链继承
自我介绍:大家好,我是吉帅振的网络日志:微信公众号:吉帅振的网络日志:前端开发工程师,工作4年,去过上海.北京,经历创业公司,进过大厂,现在郑州敲代码. JS继承专栏 1[JS继承]什么是JS继承? ...
- 原型链的理解(全面)
创建一个实例 使用构造函数创建一个实例 function Star(age,name) {this.age = agethis.name = namethis.sing = function(){co ...
- [js] js怎样避免原型链上的对象共享?
[js] js怎样避免原型链上的对象共享? 组合继承 优势 公有的写在原型 私有的卸载构造函数 可以向父类传递参数 劣势 需要手动绑定constructor 封装性一般 重复调用父类性能损耗
- 【Day03】使用原型最大的好处及原型链的理解
面试题 使用原型最大的好处,原型链的理解 题解 原型优缺点简单分析 通过原型链继承的方式,原先存在父类型的实例中的所有属性和方法,现在也能存在于子类型的原型中了: 在通过原型链实现继承时,原型实际上会 ...
- js原型和原型链_理解JS中的原型和原型链
导读:JavaScript中(JS)的原型和原型链是web前端开发面试中经常被问到的问题:同时,如果我们能很好的理解JS中的原型和原型链,对于控制台输出的很多信息我们也能更好的理解,而原型链也是实现继 ...
- JS中的原型链(超清晰理解)
什么是原型链 原型链,所有的原型构成了一个链条,这个链条我们称之为原型链(prototype chain). 原型链的案例 如果我们执行下面这段代码,因为没有定义address这个属性,程序结果理所当 ...
最新文章
- 7 个让您需要渐进式 Web 应用程序做项目开发的理由
- 番石榴的EventBus –简单的发布者/订阅者
- 201673020127 词频统计软件项目报告
- java 正则表达式提取html纯文本
- mifare classic 2.2.3中文_Adobe Lightroom Classic CC 2019 v8.4.1 中文完整直装版
- 再学 GDI+[22]: TGPLinearGradientBrush - 之一: TLinearGradientMode
- 五分钟回顾 | 2016年智能交通大事件
- PetaLinux学习笔记 3
- bugly怎么读_腾讯Bugly巨坑:使用不当造成UI界面卡死
- 坚果云教你几招提升你办公效率的技巧!
- Python中基于TCP网络通信协议的多人聊天室
- 【LOJ6515】贪玩蓝月
- c8051f020 I/O配置小结
- 电脑突然间变卡的解决办法
- Threaded Binary Tree
- SLIM推荐模型及分析
- python 内置属性__setattr___python 属性四种管理方法property,descriptor, __get/setattr__, __getatribute __...
- 移动MM首届手机软件设计及创意大赛决赛取得圆满成功
- ARM汇编指令EQU与等号“=”的异同
- BCG 对话框表格控件CBCGPGridCtrl(不包含子)