javascript 是一种基于原型的编程 (prototype based programming) 的语言, 而与我们通常的基于类编程 (class based programming) 有很大的区别,我列举重要的几点如下:

  1. 函数是first class object,也就是说函数与对象具有相同的语言地位
  2. 没有类,只有对象
  3. 函数也是一种对象,所谓的函数对象
  4. 对象是按引用来传递的

那么这种 prototype based programming 的语言如何实现继承呢(OO的一大基本要素), 这也便是 prototype 的由来。

看下面的代码片断:

function foo(a, b, c)
{
return a*b*c;
}
alert(foo.length);
alert(typeof foo.constructor);
alert(typeof foo.call);
alert(typeof foo.apply);
alert(typeof foo.prototype);

对于上面的代码,用浏览器运行后你会发现:

  1. length: 提供的是函数的参数个数
  2. prototype: 是一个object
  3. 其它三个都是function

而对于任何一个函数的声明,它都将会具有上面所述的5个property(方法或者属性)。

下面我们主要看下prototype。

// prototype
function Person(name, gender)
{
this.name = name;
this.gender = gender;
this.whoAreYou = function()
{//这个也是所谓的closure, 内部函数可以访问外部函数的变量
var res = "I'm " + this.name + " and I'm a " + this.gender +".";
return res;
};
}
// 那么在由Person创建的对象便具有了下面的几个属性
Person.prototype.age = 24;
Person.prototype.getAge = function()
{
return this.age;
};
flag = true;
if (flag)
{
var fun = new Person("Tower", "male");
alert(fun.name);
alert(fun.gender);
alert(fun.whoAreYou());
alert(fun.getAge());
}
Person.prototype.salary = 10000;
Person.prototype.getSalary = function()
{
return this.name + " can earn about " + this.salary + "RMB each month." ;
};
// 下面就是最神奇的地方, 我们改变了Person的prototype,而这个改变是在创建fun之后
// 而这个改变使得fun也具有了相同的属性和方法
// 继承的意味即此
if (flag)
{
alert(fun.getSalary());
alert(fun.constructor.prototype.age);//而这个相当于你直接调用 Person.prototype.age
alert(Person.prototype.age);
}

从上面的示例中我们可以发现,对于prototype的方法或者属性,我们可以动态地增加, 而由其创建的对象自动会继承相关的方法和属性。

另外,每个对象都有一个 constructor 属性,用于指向创建其的函数对象,如上例中的 fun.constructor 指向的就是 Person。

那么一个疑问就自然产生了, 函数对象中自身声明的方法和属性与prototype声明的对象有什么差别?

有下面几个差别:

  1. 自身声明的方法和属性是静态的,也就是说你在声明后,试图再去增加新的方法或者修改已有的方法,并不会对由其创建的对象产生影响,也即继承失败。
  2. 而prototype可以动态地增加新的方法或者修改已有的方法,从而是动态的一旦父函数对象声明了相关的prototype属性,由其创建的对象会自动继承这些prototype的属性。

继续上面的例子:

flag = true;
// 函数内部声明的方法是静态的,无法传递的
Person.school = "ISCAS";
Person.whoAreYou = function(){
return "zhutao";
};//动态更改声明期的方法,并不会影响由其创建的对象的方法, 即所谓的静态
if (flag)
{
alert(Person.school);
alert(fun.school);//输出的是 "undefined"
alert(Person.whoAreYou()); //输出 zhutao
alert(fun.whoAreYou()); // I'm Tower and I'm a male.
}
Person.prototype.getSalary = function(){
return "I can earn 1000000 USD";
};
if (flag)
{
alert(fun.getSalary());//已经继承了改变, 即所谓的动态
}

既然有函数对象本身的属性,也有prototype的属性,那么是由其创建的对象是如何搜索相应的属性的呢?

基本是按照下面的流程和顺序来进行。

  1. 先去搜索函数对象本身的属性,如果找到立即执行
  2. 如果1没有找到,则会去搜索prototype属性,有2种结果,找到则直接执行,否则继续搜索父对象的父对象的prototype,直至找到,或者到达 prototype chain 的结尾(结尾会是Object对象)

上面也回答如果函数对象本身的属性与prototype属性相同(重名)时的解决方式,函数本身的对象优先。

再看一个多重prototype链的例子:

// 多重prototype链的例子
function Employee(name)
{
this.name = "";
this.dept = "general";
this.gender = "unknown";
}
function WorkerBee()
{
this.projects = [];
this.hasCar = false;
}
WorkerBee.prototype = new Employee; // 第一层prototype链
function Engineer()
{
this.dept = "engineer"; //覆盖了 "父对象"
this.language = "javascript";
}
Engineer.prototype = new WorkerBee; // 第二层prototype链
var jay = new Engineer("Jay");
if (flag)
{
alert(jay.dept); //engineer, 找到的是自己的属性
alert(jay.hasCar); // false, 搜索到的是自己上一层的属性
alert(jay.gender); // unknown, 搜索到的是自己上二层的属性
}

上面这个示例的对象关系如下:

javascript 的prototype给语言本身增加了很强的灵活性,但与 class based programming 相比整个思维逻辑还是有很大的不同,所以需要更多地思考和揣摩。

而javascript是披着c语言外衣的函数式语言的理解自然也需要更多地思考。

window.onload = function()
{
/*
每个对象实例都有个属性成员用于指向到它的instanceof 对象(暂称为父对象)的原型(prototype)
我们把这种层层指向父原型的关系称为[原型链 prototype chian]
原型也具有父原型,因为它往往也是一个对象实例,除非我们人为地去改变它
在JavaScript中,"一切都是对象,函数是第一型。"
Function和Object都是函数的实例。
Function的父原型指向到Function的原型,Function.prototype的父原型是Object的原型
Object的父原型也指向到Function的原型,Object.prototype是所有父原型的顶层
在spiderMonkey引擎中,父原型可以通过 __proto__ 进行访问 大家在看的时候最后能反复的读几篇,能加深理解,尤其是原型,父原型,还有原型链的意思. * prototype 访问的是原型
* __proto__ 访问的父原型
* instanceof 原型链的父类
*/
Function.prototype.hi = function(){alert('hi Function');}
Object.prototype.hi = function(){alert('hi Object');} var a = function()
{
this.txt = 'a';
}; a.prototype = {
say:function(){alert('a');}
}; alert(a instanceof Function);//a是Function的实例;
alert(a.__proto__ === Function.prototype); //a的父原型指向到Function的原型;
//a.__proto__父原型 Function
//Function.prototype 父原型 Function
alert(Function instanceof Object); //Function是Object的实例;
alert(Function.__proto__ === Function.prototype); //Function的父原型指向到Function的原型;
alert(Function.prototype.__proto__ === Object.prototype); //Function的原型的父原型指向到Object的原型
alert(Object.__proto__ === Function.prototype); //Object的父原型指向到Function的原型;
alert(Object.prototype.__proto__);
//Object的原型是所有父原型的顶端,它不再具有父原型,所以结果为null;
alert(a.prototype instanceof Object);
//a的原型也是一个对象
alert(a.prototype.__proto__ === Object.prototype);
//a的原型的父原型指向Object的原型
};

转载随意,但请带上本文地址:

http://www.nowamagic.net/librarys/veda/detail/1238

 
 

最新文章

  1. 使用adb shell 进入手机修改文件的权限
  2. 控制台手动编译Qt5程序
  3. JavaScript笔记基础篇(三)
  4. SpringMVC 接收ajax发送的数组对象
  5. vue相关
  6. mysql巡检脚本
  7. Java的Git管理工具Gitblit
  8. js数组练习
  9. IOS应用程序生命周期详解
  10. assert的基本用法
  11. spring文件上传
  12. 近期学习的原生JS知识以及jQuery框架
  13. solr7.2安装实例,中文分词器
  14. Spring Security 入门(1-9)国际化的使用
  15. Memcache架构新思考
  16. 【读书笔记】深入应用C++11代码优化与工业级应用 读书笔记01
  17. Hive学习笔记:基础语法
  18. 【EasyUI学习-1】MyEclipse+easyui学习官方Demo
  19. Distributed1:链接服务器
  20. VS 2010 应用程序无法启动

热门文章

  1. hdu 2899 Strange fuction——模拟退火
  2. wpf控件提示Value ‘’ can not convert
  3. Numpy:dot()函数
  4. 侯捷STL学习(六)--深入list && Iterator traits
  5. Rails的静态资源管理(一)——Asset Pipeline是什么
  6. ManualResetEvent 用法
  7. windows下python访问ipv6报错
  8. 问题:oracle select into;结果:oracle SELECT INTO 和 INSERT INTO SELECT 两种表复制语句详解
  9. #调整随机森林的参数(调整n_estimators随机森林中树的数量默认10个树,精度递增显著,但并不是越多越好),加上verbose=True,显示进程使用信息
  10. docker 笔记 (6)搭建本地registry