JavaScript 原型

Javascript 里面的一些内建的基础类型,如 Object,Array,Number,Date,String,RegExp
都是基于函数创建的,在Js的世界里,我们把这种函数叫构造函数。
但也有例外,如Math,只是一个对象,它的__proto__Object

1
2
3
4
5
6
console.log(Object.prototype)
//chrome: Object {}
console.log(Object.__proto__);
//chrome: function Empty(){}

__proto__prototype 分别是什么呢,是不是和原型有关?

  • __proto__可以理解为原型的引用或指针
  • prototype可以理解为原型对象

举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
var someone = {
name:'alex',
sex:'male',
job:'happy coder'
}
var otherOne = {
name:'mike'
}
otherOne.__proto__ = soameone;
console.log(otherOne);

很可惜__proto__这个原型引用的属性不是ES6之前的标准,所以IE浏览器是不支持的。

那又怎么实现对象的扩展呢?

prototype一直是标准,那么 prototype又是怎么用于这个场景的呢?

1
2
3
4
5
6
7
8
//给Object增加一个create方法,这个方法创建一个使用原对象作为其原型的新对象
if (typeof Object.create !== 'function') {
Object.create = function(o) {
var F = function() {};//建立一个空的构造函数(或者理解为类)
F.prototype = o;//通过给构造函数的原型对象进行赋值,也就是将作为参数对象赋值给空的构造函数
return new F();//再实例化这个构造函数的对象
}
}

在ES5的时候,已经支持原生的Object.create,如果为了兼容不支持的浏览器,可以使用以上方法。

1
2
var otherOne = Object.create(someone);
otherOne.name = 'Mike';

一个对象的原型引用只能一个,这样就形成了一个链,我们把这个链称之为“原型链”。

对象与对象之间的这个继承关系,是通过这种原型链形成的。

创建JS对象有三种方式:直接量创建,构造函数创建,Object.create创建

  1. 直接量创建最简单
1
2
3
4
5
6
7
8
9
var someone = {
name:'alex',
sex:'male',
job:'happy coder'
}
var num5 = 5;
var array = [1,2,3,5]
  1. 构造函数创建
1
2
3
4
5
6
7
8
function Cat()
{
this.name = 'cat';
this.color = 'black';
}
var cat = new Cat();
  1. Object.create创建
    如上一章节的代码,不再赘述

性能

在原型链上查找属性比较耗时,对性能有副作用,这在性能要求苛刻的情况下很重要。另外,试图访问不存在的属性时会遍历整个原型链。

注意:不好的实践:扩展原生对象的原型(除非移植较新 JavaScript 引擎的特性)