JavaScript中几个重要的属性(this、constructor、prototype)介绍


Posted in Javascript onMay 19, 2013

this
this表示当前对象,如果在全局作用范围内使用this,则指代当前页面对象window; 如果在函数中使用this,则this指代什么是根据运行时此函数在什么对象上被调用。 我们还可以使用apply和call两个全局方法来改变函数中this的具体指向。
先看一个在全局作用范围内使用this的例子:

<script type=> 
console.log( === window); 
console.log(window.alert === .alert); 
console.log(.parseInt(, 10)); 
</script>

函数中的this是在运行时决定的,而不是函数定义时,如下:
foo() { 
console.log(.fruit); 
} 
fruit = ; 
foo(); 
pack = { 
fruit: , 
foo: foo 
}; 
pack.foo();

全局函数apply和call可以用来改变函数中this的指向,如下:
foo() { 
console.log(.fruit); 
} 
fruit = ; 
pack = { 
fruit: 
}; 
foo.apply(window); 
foo.apply(pack);

注:apply和call两个函数的作用相同,唯一的区别是两个函数的参数定义不同
因为在JavaScript中函数也是对象,所以我们可以看到如下有趣的例子:
foo() { 
( === window) { 
console.log(); 
} 
} 
foo.boo = () { 
( === foo) { 
console.log(); 
} ( === window) { 
console.log(); 
} 
}; 
foo(); 
foo.boo(); 
foo.boo.apply(window);

prototype
prototype本质上还是一个JavaScript对象。 并且每个函数都有一个默认的prototype属性。
如果这个函数被用在创建自定义对象的场景中,我们称这个函数为构造函数。 比如下面一个简单的场景:
Person(name) { 
.name = name; 
} 
Person.prototype = { 
getName: () { 
.name; 
} 
} 
zhang = Person(); 
console.log(zhang.getName());

作为类比,我们考虑下JavaScript中的数据类型 - 字符串(String)、数字(Number)、数组(Array)、对象(Object)、日期(Date)等。 我们有理由相信,在JavaScript内部这些类型都是作为构造函数来实现的,比如:
Array() {
}
arr1 = Array(1, 56, 34, 12);
arr2 = [1, 56, 34, 12];
同时对数组操作的很多方法(比如concat、join、push)应该也是在prototype属性中定义的。
实际上,JavaScript所有的固有数据类型都具有只读的prototype属性(这是可以理解的:因为如果修改了这些类型的prototype属性,则哪些预定义的方法就消失了), 但是我们可以向其中添加自己的扩展方法。
Array.prototype.min = () {
min = [0];
( i = 1; i < .length; i++) {
([i] < min) {
min = [i];
}
}
min;
};
console.log([1, 56, 34, 12].min());
注意:这里有一个陷阱,向Array的原型中添加扩展方法后,当使用for-in循环数组时,这个扩展方法也会被循环出来。
下面的代码说明这一点(假设已经向Array的原型中扩展了min方法):
arr = [1, 56, 34, 12];
total = 0;
( i arr) {
total += parseInt(arr[i], 10);
}
console.log(total);
解决方法也很简单:
arr = [1, 56, 34, 12];
total = 0;
( i arr) {
(arr.hasOwnProperty(i)) {
total += parseInt(arr[i], 10);
}
}
console.log(total);
constructor
constructor始终指向创建当前对象的构造函数。比如下面例子:
arr = [1, 56, 34, 12]; 
console.log(arr.constructor === Array); 
Foo = () { }; 
console.log(Foo.constructor === Function); 
obj = Foo(); 
console.log(obj.constructor === Foo); 
console.log(obj.constructor.constructor === Function);

但是当constructor遇到prototype时,有趣的事情就发生了。
我们知道每个函数都有一个默认的属性prototype,而这个prototype的constructor默认指向这个函数。如下例所示:
Person(name) { 
.name = name; 
}; 
Person.prototype.getName = () { 
.name; 
}; 
p = Person(); 
console.log(p.constructor === Person); 
console.log(Person.prototype.constructor === Person); 
console.log(p.constructor.prototype.constructor === Person);

当时当我们重新定义函数的prototype时(注意:和上例的区别,这里不是修改而是覆盖), constructor的行为就有点奇怪了,如下示例:
Person(name) { 
.name = name; 
}; 
Person.prototype = { 
getName: () { 
.name; 
} 
}; 
p = Person(); 
console.log(p.constructor === Person); 
console.log(Person.prototype.constructor === Person); 
console.log(p.constructor.prototype.constructor === Person);

为什么呢?
原来是因为覆盖Person.prototype时,等价于进行如下代码操作:
Person.prototype = Object({ 
getName: () { 
.name; 
} 
});

而constructor始终指向创建自身的构造函数,所以此时Person.prototype.constructor === Object,即是:
Person(name) { 
.name = name; 
}; 
Person.prototype = { 
getName: () { 
.name; 
} 
}; 
p = Person(); 
console.log(p.constructor === Object); 
console.log(Person.prototype.constructor === Object); 
console.log(p.constructor.prototype.constructor === Object);

怎么修正这种问题呢?方法也很简单,重新覆盖Person.prototype.constructor即可:
Person(name) { 
.name = name; 
}; 
Person.prototype = Object({ 
getName: () { 
.name; 
} 
}); 
Person.prototype.constructor = Person; 
p = Person(); 
console.log(p.constructor === Person); 
console.log(Person.prototype.constructor === Person); 
console.log(p.constructor.prototype.constructor === Person);
Javascript 相关文章推荐
用javascript编写的第一人称射击游戏
Feb 25 Javascript
JavaScript字符串插入、删除、替换函数使用示例
Jul 25 Javascript
js实现顶部可折叠的菜单工具栏效果实例
May 09 Javascript
浅谈JavaScript 浏览器对象
Jun 03 Javascript
AngularJS基础 ng-disabled 指令详解及简单示例
Aug 01 Javascript
详解JS中的快速排序与冒泡
Jan 10 Javascript
详解JS异步加载的三种方式
Mar 07 Javascript
微信小程序 Buffer缓冲区的详解
Jul 06 Javascript
AngularJS 中ui-view传参的实例详解
Aug 25 Javascript
js + css实现标签内容切换功能(实例讲解)
Oct 09 Javascript
vue多页面项目中路由使用history模式的方法
Sep 23 Javascript
全网小程序接口请求封装实例代码
Nov 06 Javascript
js函数中onmousedown和onclick的区别和联系探讨
May 19 #Javascript
下拉菜单点击实现连接跳转功能的js代码
May 19 #Javascript
js操纵跨frame的三级联动select下拉选项实例介绍
May 19 #Javascript
固定背景实现的背景滚动特效示例分享
May 19 #Javascript
Jquery实现鼠标移上弹出提示框、移出消失思路及代码
May 19 #Javascript
扩展js对象数组的OrderByAsc和OrderByDesc方法实现思路
May 17 #Javascript
js获取元素到文档区域document的(横向、纵向)坐标的两种方法
May 17 #Javascript
You might like
PHP面向对象编程快速入门
2006/10/09 PHP
php中理解print EOT分界符和echo EOT的用法区别小结
2010/02/21 PHP
PHP的魔术常量__METHOD__简介
2014/07/08 PHP
PHP递归遍历指定文件夹内的文件实现方法
2016/11/15 PHP
php编程实现简单的网页版计算器功能示例
2017/04/26 PHP
不同的jQuery API来处理不同的浏览器事件
2012/12/09 Javascript
12款经典的白富美型—jquery图片轮播插件—前端开发必备
2013/01/08 Javascript
原生js结合html5制作简易的双色子游戏
2015/03/30 Javascript
再谈JavaScript线程
2015/07/10 Javascript
javascript中setAttribute()函数使用方法及兼容性
2015/07/19 Javascript
javascript绘制漂亮的心型线效果完整实例
2016/02/02 Javascript
javascript作用域、作用域链(菜鸟必看)
2016/06/16 Javascript
JS中with的替代方法与String中的正则方法详解
2016/12/23 Javascript
javascript数据结构中栈的应用之符号平衡问题
2017/04/11 Javascript
老生常谈combobox和combotree模糊查询
2017/04/17 Javascript
Koa2 之文件上传下载的示例代码
2018/03/29 Javascript
vue实现购物车的监听
2020/04/20 Javascript
vue 全局封装loading加载教程(全局监听)
2020/11/05 Javascript
Python实现对一个函数应用多个装饰器的方法示例
2018/02/09 Python
Python后台开发Django的教程详解(启动)
2019/04/08 Python
pyqt5之将textBrowser的内容写入txt文档的方法
2019/06/21 Python
使用python将mysql数据库的数据转换为json数据的方法
2019/07/01 Python
Python+Selenium使用Page Object实现页面自动化测试
2019/07/14 Python
Python实现元素等待代码实例
2019/11/11 Python
django创建超级用户时指定添加其它字段方式
2020/05/14 Python
python统计mysql数据量变化并调用接口告警的示例代码
2020/09/21 Python
自定义Django_rest_framework_jwt登陆错误返回的解决
2020/10/18 Python
Pytorch实验常用代码段汇总
2020/11/19 Python
阿迪达斯意大利在线商店:adidas意大利
2016/09/19 全球购物
PAUL HEWITT手表美国站:德国北部时尚生活配饰品牌,船锚元素
2017/11/18 全球购物
学生爱国演讲稿
2014/01/14 职场文书
职务说明书范文
2014/05/07 职场文书
个人师德师风自我剖析材料
2014/09/29 职场文书
党员先进事迹材料
2014/12/19 职场文书
2015年评职称个人工作总结
2015/10/15 职场文书
Python快速实现一键抠图功能的全过程
2021/06/29 Python