<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript">
/**
@authors Benjamin
@date 2013-11-12 10:23:40
深入理解javascript 原型和原型链
最近不是很忙,空余时间整理最近几天看到的关于原型和原型链的文章,收获还是不小的。
今天十八届三中全会即将闭幕,期待新一届领导班子的改革方略,能够惠民吧
房价,户籍都是让80后很蛋疼的问题哈,当然,做为屌丝的我,肯定也是。
开篇先了解下两个很有用的属性:
一、__proto__属性:
__proto__属性未来会成为ES6标准的一部分,目前,该属性在各个浏览器下的实现差别也许比较大.Firefox是最先实现的这个魔法属性(magic property)的浏览器,而且该属性在Firefox中的表现也最有望能成为标准.我们通常用的__proto__属性都是从Object.prototype上继承下来的,那到底__proto__与prototype什么关系呢?
1)所有构造器/函数的__proto__都指向Function.prototype,它是一个空函数(Empty function)
看看实例:
*/
console.log(Number.__proto__ === Function.prototype) // true
console.log(Boolean.__proto__ === Function.prototype) // true
console.log(String.__proto__ === Function.prototype) // true
console.log(Object.__proto__ === Function.prototype) // true
console.log(Function.__proto__ === Function.prototype) // true
console.log(Array.__proto__ === Function.prototype) // true
console.log(RegExp.__proto__ === Function.prototype) // true
console.log(Error.__proto__ === Function.prototype) // true
console.log(Date.__proto__ === Function.prototype) // true
/*
JavaScript中有内置(build-in)构造器/对象共计12个(ES5中新加了JSON),这里列举了可访问的8个构造器。剩下如Global不能直接访问,Arguments仅在函数调用时由JS引擎创建,Math,JSON是以对象形式存在的,无需new。它们的__proto__是Object.prototype。如下
*/
console.log("对象测试...");
console.log(Math.__proto__ === Object.prototype);//true
console.log(JSON.__proto__ === Object.prototype);//true
/**
* 上面说的“所有构造器/函数”当然包括自定义的。看下面的例子:
*/
var Employee = function (){
};
function Person(){
}
console.log("自定义函数测试...");
console.log(Employee.__proto__ === Function.prototype);//true
console.log(Person.__proto__ === Function.prototype);//true
/**
* 由以上测试得出,所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身。所有构造器都继承了Function.prototype的属性及方法。如length、call、apply、bind(ES5)。另,Function.prototype也是唯一一个typeof XXX.prototype为 “function”的prototype。其它的构造器的prototype都是一个对象,下面来测试下:
*/
console.log("类型测试中...");
console.log(typeof Function.prototype) // function
console.log(typeof Object.prototype) // object
console.log(typeof Number.prototype) // object
console.log(typeof Boolean.prototype) // object
console.log(typeof String.prototype) // object
console.log(typeof Array.prototype) // object
console.log(typeof RegExp.prototype) // object
console.log(typeof Error.prototype) // object
console.log(typeof Date.prototype) // object
console.log(typeof Object.prototype) // object
/**
* Function.prototype 是一个空函数,我们来测试下
*/
console.log("空函数测试...");
console.log(Function.prototype);//function(){}
//用alert来看会更直接点
//alert(Function.prototype);//function(){}
/**
* 下面我们来看看Function.prototype 的__proto__是谁呢?看下面的测试
*/
console.log("Function.prototype的__proto__测试...");
console.log(Function.prototype.__proto__ === Object.prototype);//true
/**
* 那Object.prototype的__proto__又是谁呢?看下面测试
*/
console.log(Object.prototype.__proto__);//输出null
/*
2)所有对象的__proto__都指向其构造器的prototype
来看看以下实例
*/
console.log("对象的__proto__测试中...");
//函数声明
function Foo(){
}
var foo = new Foo();//对象实例化
console.log(foo.__proto__ === Foo.prototype);//true
//函数表达式
var Foo = function (){}
var foo = new Foo();//对象实例化
console.log(foo.__proto__ === Foo.prototype);//true
/**
* 看完自定义函数,下面我们来看看javascript引擎内置构造器
*/
var
arr = ["aaa", "bbb"],
reg = /^abc$/g,
obj = {
name: "张三",
age: 20
},
date = new Date(),
error = new Error("fdasfdasfd");
console.log("内置构造器的对象测试...");
console.log(arr.__proto__ === Array.prototype);//true
console.log(obj.__proto__ === Object.prototype);//true
console.log(reg.__proto__ === RegExp.prototype);//true
console.log(date.__proto__ === Date.prototype);//true
console.log(error.__proto__ === Error.prototype);//true
/**
* 二、constuctor属性
* constructor属性始终指向创建当前对象的构造函数,看下面的实例
*/
var
arr = ["aaa", "bbb"],
reg = /^abc$/g,
obj = {
name: "张三",
age: 20
},
date = new Date(),
error = new Error("fdasfdasfd");
console.log("constructor指向测试...");
console.log(arr.constructor === Array);//true
console.log(obj.constructor === Object);//true
console.log(reg.constructor === RegExp);//true
console.log(date.constructor === Date);//true
console.log(error.constructor === Error);//true
/**
* 我们都知道函数是对象,对象都有prototype属性,那么这个prototype的constructor属性指向谁呢?
* 由以下实例得出结论,其constructor指也向其构造函数
*/
console.log("prototype的constructor属性指向测试...");
//函数声明
function Foo(){
}
console.log(Foo.prototype.constructor === Foo);//true
//函数表达式
var Foo = function (){
};
console.log(Foo.prototype.constructor === Foo);
/**
* 那么一个函数的实例指向谁呢?
*/
function Foo(){
}
var f1 = new Foo();
console.log("测试constructor实例化指向...");
console.log(f1.constructor === Foo);
console.log(f1.constructor.prototype.constructor === Foo);
/**
* 到此我们来必须来总结下子了:
* f1 = new Foo();
* f1.__proto__ === Foo.prototype.__proto__ === Object.prototype
* Foo.prototype.constructor === Foo
* Foo.__proto__ === Function.prototype.__proto__ === Object.prototype
* 这样看起来貌似还是比较乱,下面用一张图来总结以上问题,如下图:
*/
/**
* 开一个怪例子,当我们重定义prototype对象时,constructor的行为会有什么变化呢?
*/
function Foo(name){
this.name = name;
}
Foo.prototype = {
getName :function (){
return this.name;
}
};
var f1 = new Foo();
console.log("重定义prototype对象测试...");
console.log(f1.constructor === Foo); //false
console.log(Foo.prototype.constructor === Foo);//false
console.log(f1.constructor === Object);//true
console.log(Foo.prototype.constructor === Object);//true
/**
* 是什么原因导致的此问题呢?来分析哈子,其实定义Foo.prototype = {}
* 其实等价于Foo.prototype = new Object({"getName":function(){return this.name;}})
* 因此Foo.prototype.constuctor === Obeject 返回true
* 那么怎么让前面的两个false 变为true,做如下操作:
*/
Foo.prototype.constructor = Foo;
var f1 = new Foo();
console.log("重新指向测试...");
console.log(f1.constructor === Foo); //true
console.log(Foo.prototype.constructor === Foo);//true
</script>
</body>
</html>