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下给元素添加事件的方法与代码
Aug 13 Javascript
javascript 字符串连接的性能问题(多浏览器)
Nov 18 Javascript
Javascript 键盘事件的组合使用实现代码
May 04 Javascript
不使用浏览器运行javascript代码的方法
Jul 24 Javascript
Textarea根据内容自适应高度
Oct 28 Javascript
JavaScript中的变量定义与储存介绍
Dec 31 Javascript
javascript跨域原因以及解决方案分享
Apr 08 Javascript
JavaScript数据类型判定的总结笔记
Jul 31 Javascript
python爬取安居客二手房网站数据(实例讲解)
Oct 19 Javascript
浅析Vue中method与computed的区别
Mar 06 Javascript
Layui 导航默认展开和菜单栏选中高亮设置的方法
Sep 04 Javascript
JS继承实现方法及优缺点详解
Sep 02 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
经典的PHPer为什么被认为是草根?
2007/04/02 PHP
全新的PDO数据库操作类php版(仅适用Mysql)
2012/07/22 PHP
PHP类与对象中的private访问控制的疑问
2012/11/01 PHP
PHP垃圾回收机制引用计数器概念分析
2013/06/24 PHP
php权重计算方法代码分享
2014/01/09 PHP
php多次include后导致全局变量global失效的解决方法
2015/02/28 PHP
codeigniter中实现一次性加载多个view的方法
2015/03/20 PHP
PHP读取配置文件类实例(可读取ini,yaml,xml等)
2015/07/28 PHP
阿里云Win2016安装Apache和PHP环境图文教程
2018/03/11 PHP
javascript 面向对象全新理练之原型继承
2009/12/03 Javascript
js对象的比较
2011/02/26 Javascript
Javascript 八进制转义字符(8进制)
2011/04/08 Javascript
五个jQuery图片画廊插件 推荐
2011/05/12 Javascript
关于图片的预加载过程中隐藏未知的
2012/12/19 Javascript
ie与ff下的event事件使用介绍
2013/11/25 Javascript
Javascript实现获取窗口的大小和位置代码分享
2014/12/04 Javascript
jQuery实现3D文字特效的方法
2015/03/10 Javascript
如何解决jQuery EasyUI 已打开Tab重新加载问题
2016/12/19 Javascript
jQuery和CSS仿京东仿淘宝列表导航菜单
2017/01/04 Javascript
Bootstrap的Carousel配合dropload.js实现移动端滑动切换图片
2017/03/10 Javascript
Python线程的两种编程方式
2015/04/14 Python
python判断设备是否联网的方法
2018/06/29 Python
PyCharm代码提示忽略大小写设置方法
2018/10/28 Python
用Python解决x的n次方问题
2019/02/08 Python
Python爬虫 urllib2的使用方法详解
2019/09/23 Python
python求前n个阶乘的和实例
2020/04/02 Python
python获得命令行输入的参数的两种方式
2020/11/02 Python
详解三种方式实现平滑滚动页面到顶部的功能
2019/04/23 HTML / CSS
安纳塔拉酒店度假村及水疗官方网站:Anantara Hotel
2016/08/25 全球购物
专科毕业生自我鉴定
2013/12/01 职场文书
接待员岗位责任制
2014/02/10 职场文书
三好学生个人先进事迹材料
2014/05/17 职场文书
暖通工程师岗位职责
2014/06/12 职场文书
大学生万能检讨书范例
2014/10/04 职场文书
建国70周年的心得体会(2篇)
2019/09/20 职场文书
springboot @ConfigurationProperties和@PropertySource的区别
2021/06/11 Java/Android