浅谈Javascript中的函数、this以及原型


Posted in Javascript onOctober 09, 2016

关于函数

在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以及原型全部内容了,希望大家多多支持三水点靠木~

Javascript 相关文章推荐
利用WebBrowser彻底解决Web打印问题(包括后台打印)
Jun 22 Javascript
javascript 闭包
Sep 15 Javascript
js获取字符串最后一位方法汇总
Nov 13 Javascript
node.js中的fs.readFileSync方法使用说明
Dec 15 Javascript
表单验证正则表达式实例代码详解
Nov 09 Javascript
JS区分浏览器页面是刷新还是关闭
Apr 17 Javascript
jQuery.ajax实现根据不同的Content-Type做出不同的响应
Nov 03 Javascript
jquery操作ID带有变量的节点实例
Dec 07 Javascript
Bootstrap栅格系统的使用和理解2
Dec 14 Javascript
浅谈JavaScript中promise的使用
Jan 11 Javascript
Vue实例简单方法介绍
Jan 20 Javascript
微信小程序自定义弹窗滚动与页面滚动冲突的解决方法
Jul 16 Javascript
常用Javascript函数与原型功能收藏(必看篇)
Oct 09 #Javascript
javascript汉字拼音互转的简单实例
Oct 09 #Javascript
Javascript农历与公历相互转换的简单实例
Oct 09 #Javascript
Angularjs 创建可复用组件实例代码
Oct 09 #Javascript
Boostrap实现的登录界面实例代码
Oct 09 #Javascript
深入理解bootstrap框架之第二章整体架构
Oct 09 #Javascript
javascript 判断是否是微信浏览器的方法
Oct 09 #Javascript
You might like
Php Ctemplate引擎开发相关内容
2012/03/03 PHP
php向js函数传参的几种方法
2014/08/10 PHP
ThinkPHP设置禁止百度等搜索引擎转码(简单实用)
2016/02/15 PHP
PHP5.5新特性之yield理解与用法实例分析
2019/01/11 PHP
php7 错误处理机制修改实例分析
2020/05/25 PHP
jQuery.ajax 用户登录验证代码
2010/10/29 Javascript
javascript tips提示框组件实现代码
2010/11/19 Javascript
jQuery插件实现控制网页元素动态居中显示
2015/03/24 Javascript
js实现点击链接后延迟3秒再跳转的方法
2015/06/05 Javascript
基于jQuery实现音乐播放试听列表
2016/04/14 Javascript
异步加载JS、CSS代码(推荐)
2016/06/15 Javascript
Bootstrap的fileinput插件实现多文件上传的方法
2016/09/05 Javascript
jQuery Ajax 实现在html页面实时显示用户登录状态
2016/12/30 Javascript
js实现日历的简单算法
2017/01/24 Javascript
canvas时钟效果
2017/02/16 Javascript
React-Native做一个文本输入框组件的实现代码
2017/08/10 Javascript
vue-cli下的vuex的简单Demo图解(实现加1减1操作)
2018/02/26 Javascript
vue 组件高级用法实例详解
2018/04/11 Javascript
详解js 创建对象的几种方法
2019/03/08 Javascript
Node.js设置定时任务之node-schedule模块的使用详解
2020/04/28 Javascript
javascript中layim之查找好友查找群组
2021/02/06 Javascript
vue3.0 自适应不同分辨率电脑的操作
2021/02/06 Vue.js
对python cv2批量灰度图片并保存的实例讲解
2018/11/09 Python
日本最大的眼镜购物网站:Oh My Glasses
2016/11/13 全球购物
澳大利亚家居用品零售商:Harris Scarfe
2020/10/10 全球购物
英国奢侈品在线精品店:Hervia
2020/09/03 全球购物
校长先进事迹材料
2014/02/01 职场文书
简单租房协议书(范本)
2014/10/13 职场文书
2014年小学图书室工作总结
2014/12/09 职场文书
赢在执行观后感
2015/06/16 职场文书
导游词之无锡梅园
2019/11/28 职场文书
MySQL中InnoDB存储引擎的锁的基本使用教程
2021/05/26 MySQL
Oracle 临时表空间SQL语句的实现
2021/09/25 Oracle
MySQL对数据表已有表进行分区表的实现
2021/11/01 MySQL
详解gantt甘特图可拖拽、编辑(vue、react都可用 highcharts)
2021/11/27 Vue.js
Win10服务主机占用内存怎么办?Win10服务主机进程占用大量内存解决方法
2022/09/23 数码科技