原文

在一个对象中绑定函数,称为这个对象的方法。

在JavaScript中,对象的定义是这样的:

var xiaoming = {
name: '小明',
birth: 1990
};

但是,如果我们给xiaoming绑定一个函数,就可以做更多的事情。比如,写个age()方法,返回xiaoming的年龄:

var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
}; xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年调用是25,明年调用就变成26了

绑定到对象上的函数称为方法,和普通函数也没啥区别,但是它在内部使用了一个this关键字,这个东东是什么?

在一个方法内部,this是一个特殊变量,它始终指向当前对象,也就是xiaoming这个变量。所以,this.birth可以拿到xiaomingbirth属性。

让我们拆开写:

function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
} var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
}; xiaoming.age(); // 25, 正常结果
getAge(); // NaN

单独调用函数getAge()怎么返回了NaN请注意,我们已经进入到了JavaScript的一个大坑里。

JavaScript的函数内部如果调用了this,那么这个this到底指向谁?

答案是,视情况而定!

如果以对象的方法形式调用,比如xiaoming.age(),该函数的this指向被调用的对象,也就是xiaoming,这是符合我们预期的。

如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window

坑爹啊!

更坑爹的是,如果这么写:

var fn = xiaoming.age; // 先拿到xiaoming的age函数
fn(); // NaN

也是不行的!要保证this指向正确,必须用obj.xxx()的形式调用!

由于这是一个巨大的设计错误,要想纠正可没那么简单。ECMA决定,在strict模式下让函数的this指向undefined,因此,在strict模式下,你会得到一个错误:

'use strict';

var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
}; var fn = xiaoming.age;
fn(); // Uncaught TypeError: Cannot read property 'birth' of undefined

这个决定只是让错误及时暴露出来,并没有解决this应该指向的正确位置。

有些时候,喜欢重构的你把方法重构了一下:

'use strict';

var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - this.birth;
}
return getAgeFromBirth();
}
}; xiaoming.age(); // Uncaught TypeError: Cannot read property 'birth' of undefined

结果又报错了!原因是this指针只在age方法的函数内指向xiaoming,在函数内部定义的函数,this又指向undefined了!(在非strict模式下,它重新指向全局对象window!)

修复的办法也不是没有,我们用一个that变量首先捕获this

'use strict';

var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var that = this; // 在方法内部一开始就捕获this
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - that.birth; // 用that而不是this
}
return getAgeFromBirth();
}
}; xiaoming.age(); //

var that = this;,你就可以放心地在方法内部定义其他函数,而不是把所有语句都堆到一个方法中。

apply

虽然在一个独立的函数调用中,根据是否是strict模式,this指向undefinedwindow,不过,我们还是可以控制this的指向的!

要指定函数的this指向哪个对象,可以用函数本身的apply方法,它接收两个参数,第一个参数就是需要绑定的this变量,第二个参数是Array,表示函数本身的参数。

apply修复getAge()调用:

function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
} var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
}; xiaoming.age(); //
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空

另一个与apply()类似的方法是call(),唯一区别是:

  • apply()把参数打包成Array再传入;

  • call()把参数按顺序传入。

比如调用Math.max(3, 5, 4),分别用apply()call()实现如下:

Math.max.apply(null, [3, 5, 4]); //
Math.max.call(null, 3, 5, 4); //

对普通函数调用,我们通常把this绑定为null

装饰器

利用apply(),我们还可以动态改变函数的行为。

JavaScript的所有对象都是动态的,即使内置的函数,我们也可以重新指向新的函数。

现在假定我们想统计一下代码一共调用了多少次parseInt(),可以把所有的调用都找出来,然后手动加上count += 1,不过这样做太傻了。最佳方案是用我们自己的函数替换掉默认的parseInt()

'use strict';

var count = 0;
var oldParseInt = parseInt; // 保存原函数 window.parseInt = function () {
count += 1;
return oldParseInt.apply(null, arguments); // 调用原函数
};

// 测试:
parseInt('10');
parseInt('20');
parseInt('30');
console.log('count = ' + count); // 3

js之方法的更多相关文章

  1. js调用php和php调用js的方法举例

    js调用php和php调用js的方法举例1 JS方式调用PHP文件并取得php中的值 举一个简单的例子来说明: 如在页面a.html中用下面这句调用: <script type="te ...

  2. 通过cookie实现搜索框内容保存关闭浏览器之前的操作、jq js实现方法

    jq实现的方法: jq需要在页面中引入JQ.cookie插件 这是一个超轻量级插件 要实现的效果: 下面是jq代码: $(function(){ var til=$("#orderInfoC ...

  3. jquery.validate.min.js 用法方法示例

    页面html 代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://w ...

  4. jQuery 互相调用iframe页面中js的方法

    1,子iframe内调用父类函数方法: window.parent.func(); 2,子Iframe中获取父界面的元素: $("#xx", window.parent.docum ...

  5. JS扩展方法——字符串trim()

    转自:http://www.cnblogs.com/kissdodog/p/3386480.html <head> <title>测试JS扩展方法</title> ...

  6. Js apply 方法 详解

    Js apply方法详解 我在一开始看到JavaScript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...

  7. JavaScript基础12——js的方法重载

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. JS replace()方法-字符串首字母大写

    replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串. replace()方法有两个参数,第一个参数是正则表达式,正则表达式如果带全局标志/g,则是代表替换 ...

  9. JS trim()方法使用

    JS trim()方法使用上有浏览器限制: 1.直接使用 string.trim() 浏览器版本限制:JavaScript Version 1.8  2.间接使用<即自己使用正则构造类trim的 ...

  10. JS同名方法,

    JS同名方法只会调用最后一个方法. JS中同时绑定多个事件,先绑定的先调用.后绑定的后调用.

随机推荐

  1. 用python写个快排

    快排过程比较简单就直接上代码了: #!/usr/bin/python3 def quik_sort(L, left, right): if left <= right: key = L[left ...

  2. 【bzoj4869】[Shoi2017]相逢是问候 线段树+扩展欧拉定理

    Description Informatikverbindetdichundmich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以 分为两 ...

  3. Django模板—-自定义过滤器和标签

    一.filter和simple_tag 1.在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag. 2.在app中创建template ...

  4. js 对象 浅拷贝 和 深拷贝

    网上发现一个比较好的博客 阮一峰的感觉很不错推荐大家看看. http://www.ruanyifeng.com/blog/it/javascript/ 接下来看一下这两个拷贝方法 1.浅拷贝 拷贝就是 ...

  5. libcaffe.so.1.0.0: cannot open shared object file: No such file or directory 运行时报错

    caffe安装好后lib没有配置到/usr/lib或/usr/local/lib中,需手动配置: sudo vim ~/.bashrc export LD_LIBRARY_PATH=your_path ...

  6. 锐速破解版linux一键自动安装包

    锐速破解版linux一键自动安装包(5月28日更新) 锐速破解版安装方法: wget -N --no-check-certificate https://github.com/91yun/server ...

  7. 【转】idea project中导入其他文件夹下的模块,可能出现java.io.FileNotFoundException: XXX.xml

    在一个project 中导入一个java 模块, 我要执行该模块的main函数 ,在main函数中有一个 FileReader(“generatorConfig.xml”) 而generatorCon ...

  8. Moving docker images location to different partition

    By default docker will put all the data including images under /var/lib/docker(At least on Debian). ...

  9. ZQUOJ 22854 (优先队列+剪枝)

    题目:给出K , N , M   :  N为顶点数 , M为边数  : 求K个从1到N的不重复的最短边 , 可以来回的走: 分析:很自然的就可以想到用个优先队列广收下K次终点嘛 , 但是.0.0 爆了 ...

  10. opacity 兼容 ie8

    opacity: 0.6; filter: alpha(opacity=60);