javaScript原型深入理解篇

几个函数与对象的概念:

1. 函数(function)

前者为函数声明,后者为函数表达式,typeof foo的结果都是function。

function foo(){

}
var foo = function(){

}

 

2. 函数对象(function Object)

《js《js中原型和原型链的深入理解》中原型和原型链的深入理解》的作者的解释是“函数就是对象,代表函数的对象就是函数对象。”
前面这句话,觉的特别难理解,代表函数的对象是什么意思,之后作者给出了官方定义:

 

 

 其实也就是说,我们定义的函数,语法上,都称为函数对象,看我们如何去使用。如果我们单纯的把它当成一个函数使用,那么它就是函数,如果我们通过他来实例化出对象来使用(new出来的),那么它就可以当成一个函数对象来使用,在面向对象的范畴里面,函数对象类似于类的概念。给出这样的定义就清晰多了,函数对象类似与类的概念。这里的函数Foo是构造函数。

var foo = new function(){

}()
typeof foo // object

//或者

function Foo (){

}
var foo = new Foo();

typeof foo // object

 

3. 本地对象(native object)

 

 

 回归本地对象,我们不能被他们起的名字是本地对象,就把它们理解为对象(虽然他们就是对象,因为js中万物皆对象),但是通过:

typeof(Object)//function
typeof(Array)//function
typeof(Date)//function
typeof(RegExp)//function
typeof(Math)//object--《js中原型和原型链的深入理解》作者就把这个写成了function,幸好我自己运行了一下。Math也不是本地对象

也就是说上面那些输出结果为function的本地对象(类)是通过function建立起来的。

function Object(){

}
function Array(){

}
...

可以看出Object原本就是一个函数,通过new Object()之后实例化后,创建对象。
理清楚了这几个概念,有助于理解我们下面要讲述的原型和原型链。

4. 内置对象(build-in object)

 

 

 

5. 宿主对象(host object)

 

 

 

prototype

prototype属性是每一个函数都具有的属性,但是不是一个对象都具有的属性。比如:

function Foo(){

}

var foo = new Foo();

foo.__proto__ === Foo.prototype

其中Foo中有prototype属性,而foo没有。但是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 来构造出实例,他们的作用就是生产对象.
  5. Function.prototype 是唯一一个typeof XXX.prototype为 “function”的prototype  ( 函数原型对象被指定为一个函数对象,以确保与ECMAScript 2015规范之前创建的ECMAScript代码兼容。)
  6. Function.__proto__ === Function.prototype (重要)   
  7. Function.prototype.__proto__ === Object.prototype (重要) 
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的整体的原型和原型链中的关系就很清晰了,如下图所示:

 

posted @ 2022-02-22 23:40  北巷听雨  阅读(38)  评论(0编辑  收藏  举报
返回顶端