您的位置:首页 > Web前端 > JavaScript

javascript中的__proto__和prototype 原型链

2015-11-23 18:57 603 查看
  很多书上__proto__和prototype都翻译成原型,这是错误的译法,因为这两个东东并不是同一个东东.就像objectObject(),对象这三者一样,这三者不是同一个东东.object指的数据类型,Object()指的是一个标识为Object的函数对象. 而object,function数据类型的对象就是我们常说的对象,但关于对象我有更广的涵义(请看另两篇文章:一切都是对象,程序世界里的对象)

  首先所有的引用类型的数据对象(也就是数据类型为object和function的数据对象)都默认有__proto__属性,这是原型链机制所要求的
但有的运行环境不能直接访问__proto__,在nodejs中是可以访问的,并且巧用__proto__可以解决很多常见的问题.而prototype是只有数据类型为function的数据对象才默认有的属性(Function.prototype函数对象是个例外,没有prototype属性),并且在原型机制中起到作用,当然你也可以自己为objject类型的数据对象添加prototype属性,但这样并没有在原型机制中起到作用,除非你自己指定.

__proto__和prototype是原型机制中所默认需要的两个内置对象,我来举个例子先:

var a ={};
var b;
var Fn = function(){};
b = new Fn();
a.__proto__ = Fn.prototype;
console.log(typeof a );
console.log(typeof b );
console.log(a instanceof Fn);
console.log(b instanceof Fn);

输出为:
object
object
true
true
首先来看var Fn = function(){};,其实这里声明并创建了function类型的数据对象function(){};,并且让标识对象Fn指向数据对象的内存地址,
那么我们就可以用Fn来代表那个数据对象.在创建Fn时,默认内置了一些对象,其中就是__proto__和prototype,这两个对象.其中Fn.__proto__ = Function.prototype;Fn.prototype.constructor = Fn;这两个操作都是默认完成的.那么b = new Fn();因为这是new操作,所以Fn()运行时,就把this指向一个{},并且返回this,所以b的数据类型是object,new操作还默认了进行这个操作 b.__proto__ = Fn.prototype.所以console.log(b instanceof Fn);为true;

而a.__proto__ = Fn.prototype;是我们自己指定的,取得了相同的效果.
__proto__和prototype我从大家熟悉的继承来说吧, __proto__相当于继承于,prototype相当于被继承,a.__proto__ = Fn.prototype
这句话就是说,a的原型是Fn.prototype,也可以理解为a继承Fn.prototype,不管怎么说,其实就是说a可以用到Fn.prototype所具有的属性
所以__proto__是用来指定原型对象的,而prototype是用来被__proto__指定的,当然,__proto__并不一定要指向prototype,可以人工控制.
好,我们改一下上面的例子.

var a ={name:"a"};
var b;
var Fn = function(){};
Fn.prototype = {age:3};
a.__proto__ = Fn.prototype;
b = new Fn();
console.log(a.age );
console.log(b.age );
console.log(a instanceof Fn);
console.log(b instanceof Fn);
输出为:
3
3
true
true

由此我们可以看到,a,b的原型都是Fn.prototype,所以都能访问到age属性.

在默认情况下:
1.function数据类型的数据对象的__proto__==Function.prototype 如: var Fn(){};那么Fn.__proto__ == Function.prototype
2.object数据类型的数据对象的__proto__==相应函数对象的prototype 如: var a = new Fn(); 那么a.__proto__ == Fn.prototype;
3.fuction数据类型的数据对象内置有prototype,并且prototype数据类型是object ; 如 typeof Fn.prototype == object;
4.fuction数据类型的数据对象的prototype.constructor == 函数对象 如: Fn.prototype.constructor == Fn;

注意:Function.prototype比较特殊,特殊点在于:
1)Function.prototype的数据类型是function,而不是object,而其它function类型的数据对象的prototype数据类型默认为object
2)Function.prototype.__proto__==Object.prototype(object数据类型),其它function类型的数据对象的__proto__是不能指向object类型的对象
3)Function.prototype没有prototype,其它function类型的数据对象都默认有prototype

Object.prototype也有点特殊,因为Object.prototype.__proto__ == null; 其实 typeof null == object ; 说明null还是object数据类型

特别注意,上面4点是在默认情况下的有这样的关系,但可以控制其改变:
如:
var a ={name:"a"};
var Fn = function(){
console.log(a.name);
};
Fn.age = 3;
a.__proto__ = Fn;
console.log(a.name);// a
console.log(a.age);//3
上面说明a.__proto__可以指向function数据类型的对象Fn.但要说明的是:Fn.__proto__ = a; 这是不行的,会报错.
也就是说object数据类型的对象的__proto__可以指向object数据类型的对象或者function数据类型的对象.
但function数据类型的对象的__proto__只能指向function数据类型的对象,不能指向object数据类型的对象.

只有一个特殊:Function.prototype

我们常用__proto__和prototype来实现继承关系.

举个例子:

var a ={name:"a"};
var Fn = function(){
console.log(a.name);
};
Fn.age = 3;
var Fb = function(){};
Fb.sex = "男";
Fn.__proto__ = Fb;

a.__proto__ = Fn;
console.log(a.name);
console.log(a.age);
console.log(a.sex);

输出为:

a
3


最后,引用别人的一张图

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: