关于函数

在Javascript中函数实际上就是一个对象,具有引用类型的特征,所以你可以将函数直接传递给变量,这个变量将表示指向函数“对象"的指针,例如:

function test(message){
alert(message);
}
var f = test;
f('hello world');
你也可以直接将函数申明赋值给变量:
var f = function(message){
alert(message);
};
f('hello world');

在这种情况下,函数申明中可以省略函数名称,因为此时名称已经没有任何意义,我们可直接通过变量f来调用函数。

通过Function类型,我们可以更好地理解函数即对象:

var f = new Function("message","alert(message);");
f('hello world');

关于this

this可以看成调用函数的实际作用域上下文。比较以下函数的执行结果:

function test(){
this.property = 'hello world'; }
test();
alert(window.property); //由于在全局范围内调用,test函数中的this实际指向全局对象(window) var obj = {};
test.call(obj); //通过call第一个参数指定执行上下文范围,所以test函数中this指向obj实例。
alert(obj.property); var obj2 = {};
obj2.test2 = test; //将obj2实例方法test指向 全局test方法
obj2.test2(); //由于是在obj2上调用test方法,所以test函数中的this也指向了obj2实例
alert(obj2.property);

定义类型

在Javascript中可以定义构造函数,构造函数与一般函数没有任何区别,在创建实例时,如果我们使用了new关键字,那么这个函数就具有构造函数的特性,否则就是一般函数,如下所示,我们定义了一个Person类型:

function Person(){
this.name = 'xfrog';
this.Say = function(){
alert(this.name);
};
}

当使用new关键字时,可以创建一个新的Person对象实例:

var p1 = new Person();
p1.Say();

如果不使用new关键字,将直接执行Person函数,由于执行上下文为全局范围,故name属性和Say方法将被添加到window对象:

Person();
Say();
window.Say();

原型

注意上述Person的定义方式,当使用new来创建Person实例时,将会执行Person构造函数,也就是会声明name属性和Say方法,这样可能产生效率问题,注意以下代码:

var p1 = new Person();
var p2 = new Person();
var test = p1.Say == p2.Say;

比较p1和p2两个Say函数指针,返回false,表示每个Person实例中的Say方法都是独立的,而事实上Say函数的功能是完全一样的,我们完全没有必要为每个对象重新分配Say函数”对象“,如果Person实例很多,将会造成大量的内存耗用。

如果将Say函数提取出来放入全局执行范围,似乎可解决次问题:

function Person(){
this.name = 'xfrog';
this.Say = say;
} function say(){
alert(this.name);
} var p1 = new Person();
var p2 = new Person();
alert(p1.Say == p2.Say);
p1.name = 'wang';
p1.Say();

由于this始终和执行上下文相关,p1和p2实例中的Say方法中会正确地返回对应实例的name属性。但是,使用此方式有违面向对象的思想,也失去了类型密封的原则。还会造成大量的全局函数。

为了解决这些缺点,Javascript引出了原型的概念,简单理解,原型可以看成是类型的共享区,原型本身是一个对象,而对象中的属性对于类型来说是共享的。Javascript中每个类型通过prototype属性来表示原型,通过这个属性可指定共享方法:

function Person(){

     }
Person.prototype.name = 'xfrog';
Person.prototype.Say = function(){
alert(this.name);
}; var p1 = new Person();
var p2 = new Person();
alert(p1.Say == p2.Say); //返回true

为什么这里可以通过p1.Say来访问Say方法呢?这是因为ECMAScript标准规定了类型属性的查找顺序:先在类型的实例上查找,如果没有则继续在类型原型上查找,这一查找路径采用短路算法,即找到首个后即返回,考虑如下代码:

function Person(){
this.name = 'wang';
} Person.prototype.name = 'xfrog';
Person.prototype.Say = function(){
alert(this.name);
} var p1 = new Person();
p1.Say(); //将返回wang

上面提到prototype实际上是一个对象,那么我们是否可以直接访问呢? 在一些浏览器实现(如Chrome、Fixfox等)的确可通过实例的__proto__属性来访问内部的prototype对象,这种特征表明Javascript引擎在每个对象的内部都是通过一个变量来保存对prototype的引用,这保证了prototype对应整个类型的实例来说是共享的,例如,你可在Chrome浏览器内使用如下方式来访问Say方法:

p1.__proto__["Say"]();

由于原型是一个对象,我们可以直接将一个对象赋值给prototype:

function Person(){

     }

     Person.prototype = {name:'xfrog', Say:function(){
alert(this.name);
}};

注意这个方式下,实际上是完全替换了Person的prototype,这与上面Person.prototype.name方式还是有细微差异的,这是因为任何类型,Javascript引擎都会添加默认的prototype,在这个prototype中包含一个对构造函数的引用,即原型对象属性constructor,所以通常使用替代prototype方式时,我们需要手动加上constructor属性:

Person.prototype = {
constructor: Person,
name :'xfrog',
Say:function(){
alert(this.name);
}
}

注意,由于prototype对于整个类型是共享的,那么在prototype中的引用类型可能会存在问题,前面的Say函数作为一个对象,也是引用类型,所以每个实例中的Say都指向原型对象中的同一个函数,这本身没有问题,也是我们使用原型的初衷,但对于其他引用对象,可能结果并不是我们想要的:

function Person(){
} Person.prototype = {
name: 'xfrog',
obj : { age: 18 },
Say : function(){
alert(this.obj.age);
}
}; var p1 = new Person();
var p2 = new Person();
p1.obj.age = 20;
p1.Say();
p2.Say();

p2.Say返回的是20,这是因为obj属性作为原型属性是共享的,在内存中只存在一个实例,所以通过p1修改后,p2只能得到修改后的状态。如果要避免此情况,可将obj属性放到实例中:

function Person(){
this.obj = { age: 18 };
}

Javascript中的函数、this以及原型的更多相关文章

  1. 浅析 JavaScript 中的 函数 uncurrying 反柯里化

    柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是 ...

  2. Javascript中的函数(三)

    一:概述 函数是进行模块化程序设计的基础,编写复杂的Ajax应用程序,必须对函数有更深入的了解.JavaScript中的函数不同于其他的语言,每个函数都是作为一个对象被维护和运行的.通过函数对象的性质 ...

  3. JavaScript中hasOwnProperty函数

      JavaScript中hasOwnProperty函数方法是返回一个布尔值,指出一个对象是否具有指定名称的属性. 使用方法: object.hasOwnProperty(proName) 其中参数 ...

  4. JavaScript中isPrototypeOf函数

    转自:http://www.ijavascript.cn/shouce/javascript-isprototypeof-247.html JavaScript中 isPrototypeOf 函数方法 ...

  5. JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解

    二.JavaScript中正则表达式函数详解(exec, test, match, replace, search, split) 1.使用正则表达式的方法去匹配查找字符串 1.1. exec方法详解 ...

  6. 前端学习 第六弹: javascript中的函数与闭包

    前端学习 第六弹:  javascript中的函数与闭包 当function里嵌套function时,内部的function可以访问外部function里的变量 function foo(x) {   ...

  7. JavaScript中的函数表达式

    在JavaScript中,函数是个非常重要的对象,函数通常有三种表现形式:函数声明,函数表达式和函数构造器创建的函数. 本文中主要看看函数表达式及其相关的知识点. 函数表达式 首先,看看函数表达式的表 ...

  8. JavaScript中Eval()函数的作用

    这一周感觉没什么写的,不过在研究dwz源码的时候有一个eval()的方法不是很了解,分享出来一起学习 -->首先来个最简单的理解 eval可以将字符串生成语句执行,和SQL的exec()类似. ...

  9. Javascript中call函数和apply函数的使用

    Javascript 中call函数和apply的使用: Javascript中的call函数和apply函数是对执行上下文进行切换,是将一个函数从当前执行的上下文切换到另一个对象中执行,例如: so ...

  10. 【JavaScript】Javascript中的函数声明和函数表达式

    Javascript有很多有趣的用法,在Google Code Search里能找到不少,举一个例子: <script> ~function() { alert("hello, ...

随机推荐

  1. Ubuntu: an error occurred while mounting /mnt/hgfs

    对于这个error,我采用的一个不完美的方法是: vi /etc/fstab .host:/projectname /mnt/hgfs vmhgfs rw,ttl=,uid=my_uid,gid=my ...

  2. python多线程与多进程

    由于python的内存回收机制不是线程安全的,所以就有了GIL保证每个进程内,同一时刻最多只有一个线程在运行. 于是,对于python的多线程来讲,其实同一时刻依然只有一个线程在运行.而且由于线程切换 ...

  3. java抽象类与接口 详解

    在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类. 抽象类往往用来表征我们在对问题 ...

  4. Nginx SSL配置过程

    1. 在godaddy购买了UCC SSL(最多5个域名)的SSL证书 2. 设置证书 -- 管理 -- 3. 需要制作证书申请CSR文件(在线工具制作或者openssl命令制作),保存CSR和key ...

  5. Oracle普通索引,唯一索引,主键的区别

    索引是我们经常使用的一种数据库优化手段,适当的业务操作场景使用适当的索引方案,可以显著的提升系统整体查询性能,当然用户体验也随之提高. 在Oracle中,唯一性索引(Unique Index)是我们经 ...

  6. sql server手工注入

    sql server手工注入 测试网站testasp.vulnweb.com 1. http://testasp.vulnweb.com/showforum.asp?id=0 http://testa ...

  7. powershell命令大全

    Name Category Synopsis ---- -------- -------- ac Alias Add-Content asnp Alias Add-PSSnapin clc Alias ...

  8. Android布局文件layout.xml的一些属性值

        第一类:属性值 true或者 false android:layout_centerHrizontal 水平居中 android:layout_centerVertical 垂直居中 andr ...

  9. ISO c++11 does not allow conversion from string literal to 'char*'

    http://stackoverflow.com/questions/9650058/deprecated-conversion-from-string-literal-to-char

  10. 极客DIY:使用树莓派制作一架四轴无人机

    如果你想DIY一台属于自己的无人机,那么接下来可以阅读这篇文章,阅读完毕之后也许对你会有启发. 这个项目主要用到的零件主要来自Erle Robotics(一个使用Linux系统的开源四轴飞行器项目). ...