首页 > W3C Lab > JavaScript > 我对JavaScript原型链的理解——从new说起
2015
09-16

我对JavaScript原型链的理解——从new说起

习惯面向类编程的人都知道,从一个构造函数(抽象类)实例化一个子类或实例时应该用 new 这个操作符;

我们通常所说的面向对象是什么,JavaScript是面向对象的语言, ECMA 定义的对象指的就是一些无序键值对的集合;

有人说 JavaScript 所有的东西都是对象,其实并不是这样,JavaScript中有5种简单值(string,number,boolean,undefined,null)类型并不是对象,只是如果你要对简单值进行操作时,比如需要对一个string取长度,运用string.length时,JavaScript引擎会把简单值包装成一个对象,而这个对象会有length这个属性,于是你就得到了string的长度了。

那 JavaScript 中的内对象都有哪些呢? 有 9 种(String,Number,Boolean,Object,Function,Array,Date,RegEx,Error),这里9个对象的prototype属性中的 [[prototype]]属性都指向 Object的prototype属性,所以除了Object其他所有的对象,都是Oject原型的子原型,说起来简直不不能在绕口了。

而JavaScript把所有的内置方法都藏在了Object这个对象的prototype属性中,其他所有子原型都通过原型链机制的 [[prototype]] 向上查找,所以才让人误以为JavaScript中所有的东西都是对象呢。

那么 JavaScript 中并没有类这个概念,更没有构造函数的概念,可它依然有 new 这个操作符,JavaScript 中 new 操作符到底是干什么用的呢?下面来仔细说明一下,首先 new 这个操作符只可以接一个 函数(function),我们前面说过的9种对象全都可以用 new 操作符,那么 内置的9种对象到底是对象还是函数呢?其实还是对象,只是这些对象都可以调用,具体为什么可以调用我也不知道,也就是说,在 JavaScript 的世界中只有三种东西:

  1. 简单类型 (string,number,boolean,undefined,null)
  2. 可调用的对象(String,Number,Boolean,Object,Function,Array,Date,RegEx,Error)
  3. 不可调用的对象(你自己用var obj={};声明的对象就是不可调用的对象了)

那么好办了new 只能对 第二种类型的东西进行操作,那么这个操作会执行什么呢?

比如我先定义一个函数

function foo (){this.a=1;}

var bar =new foo(); <-最后这个()对于不传入参数的函数是没有卵的区别的,完全可以不写,当然最好还是写

哎呀,有人说妈妈你看这个foo为什么是小写的,是的 javascript里没有 class这个语句,也没有类的概念,只有对象,在js的世界里,请放弃对类的执着

我们这个非常简单的代码,先声明了一个函数,然后用new来操作并把返回值赋给bar了,具体的操作如下

  1. foo函数会被执行
  2. 如果foo函数没有返回一个对象,就像我们这样,那么就会自动生成一个新的空对象(并把函数中的this绑定到这个对象上,也就相当于用bar替换掉了this),把这个对象的引用交给bar(这里要多说一句,js中的 = 号赋值,简单类型的值会直接复制给左边,而对象(所有9种对象)只传递引用,不会产生新的对象)
  3. 如果foo返回了对象,就把return的对象引用给foo,相当与没加new ,而且没有任何卵用,所以foo一定不能返回对象哦
  4. 新对象会自动添加一个[[prototype]]属性,连接到foo这个对象(foo虽然表面上看起来是个函数,其实只是批着能被调用外衣的对象)的prototype属性(前面并没有说过这个属性(也是个对象),这个 prototype 是所有可执行对象被声明后自动生成的一个属性(对象),这个prototype对象只有一个constructor属性,值就是指向这个被声明的函数)。([[prototype]]这个属性是不能枚举的,以至于我根本不知道这个东西到底是一个属性还是仅仅是个连接,而chrome的实现里,会添加一个__proto__的属性,它实际上就是这个[[prototype]]的马甲)

 

最后编辑:
作者:scplay
这个作者貌似有点懒,什么都没有留下。

留下一个回复

你的email不会被公开。