美文网首页IT 森林互联网科技
JS 中原型和原型链深入理解

JS 中原型和原型链深入理解

作者: 敬情 | 来源:发表于2018-05-14 19:24 被阅读38次
首先要搞明白几个概念:
1.函数(function)
2.函数对象(function object)
3.本地对象(native object)
4.内置对象(build-in object)
5.宿主对象(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();

那么它的原型和原型链的关系如下图。



如果通过函数对象来创建,

[图片上传中...(微信图片_20180514192431.jpg-843b46-1526297081378-0)]
function Foo(){
    
}
var foo = new Foo();

那么它的原型和原型链的关系如下图



那JavaScript的整体的原型和原型链中的关系就很清晰了,如下图所示


相关文章

  • 2018-01-09 关于javascript原型链的思考 pl

    s 深入理解原型和原型链? 构造函数 理解原型和原型链 new的时候js都干了什么? 一个实现继承的demo 构造...

  • JS博客

    JS构造函数及new运算符 JS原型对象和原型链 函数作用域和作用域链 干货分享:让你分分钟学会JS闭包 深入理解...

  • 廖雪峰JS小记

    (function(){})() 原型,原型链 浅谈Js原型的理解JS 原型与原型链终极详解 对象 对象:一种无序...

  • 深入理解JS 中原型和原型链

    JS 中原型和原型链深入理解 首先要搞明白几个概念: 函数(function) 函数对象(function obj...

  • 原型与新版的类-class

    首先来理解原型原型 === 共用属性可以先看看方姐的几篇文章:什么是JS原型链JS 中 proto 和 proto...

  • 原型和原型链

    今天发现一张特别好的图(↑↑↑上图↑↑↑),对原型和原型链的理解特别直观友好。 原型和原型链 基础储备:每个 JS...

  • 简单认识 JS 原型与原型链

    原型是JavaScript中一个比较难理解的概念, 为深入理解JavaScript 中的原型、原型链,整理下思路。...

  • JS原型、原型链深入理解

    目录 原型介绍 初识原型 创建规则 初识Object 初识Function "prototype"和"_proto...

  • JS原型、原型链深入理解

    原型是JavaScript中一个比较难理解的概念,原型相关的属性也比较多,对象有”prototype”属性,函数对...

  • 再来看一次JS继承

    原型链继承 理解原型链的概念 用一张图来理解原型链再合适不过了。 总结概括JS红宝书上对原型链的概念:每个函数都有...

网友评论

    本文标题:JS 中原型和原型链深入理解

    本文链接:https://www.haomeiwen.com/subject/iqlkdftx.html