原文

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

在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. django中itsdangerous的用法

    itsdangerous用来解决什么问题,为什么需要用到itsdangerous? 安装命令:pip install itsdangerous 有时候你想向不可信的环境发送一些数据,但如何安全完成这个 ...

  2. MySQL学习笔记(一):查询

    查询实例: 1.创建数据库并使用: create database school; use school; 2.创建表并插入内容: create table student( Sno char(9) ...

  3. dsp之BF531笔记

    获得更多资料欢迎进入我的网站或者 csdn或者博客园 很久以前的BF531的笔记,觉得有用分享出来.摘自于open dsp 通用Gpio ADSP-BF53x 处理器上有16 个PF 接口,这些接口就 ...

  4. win7关闭关机时的自动终止的功能

    gpedit.msc->计算器配置->管理模板->系统->关机选项->启用 参考: http://www.xitongcheng.com/jiaocheng/win7_a ...

  5. 单据头->实体服务规则中根据单据类型设置可见性或必录等

  6. 带权并查集 - How Many Answers Are Wrong

    思路: 带权并查集+向量偏移 #include <iostream> using namespace std; int n, m; ]; ]; // 到根节点的距离 ; void init ...

  7. JAVA基础——重新认识String字符串

    深入剖析Java之String字符串 在程序开发中字符串无处不在,如用户登陆时输入的用户名.密码等使用的就是字符串. 在 Java 中,字符串被作为 String 类型的对象处理. String 类位 ...

  8. Adobe Fireworks CS5 | Adobe Dreamweaver CS5 | Adobe Photoshop CS5 Extended 绿色精简版最新下载地址

    下载地址可能已经不能直接下载,可以用迅雷下载试试 Adobe Photoshop CS5 简体中文绿色版 下载地址:Adobe_Photoshop_CS5_Extended.7z 此绿色版特点:1. ...

  9. C++_基础2-复合数据类型

    C语言使用术语“派生类型”,C++对类关系使用术语“派生”.所以就改用“复合类型”. 数组 数组是一种数据格式,能够存储多个同类型的值. 数组声明应指出以下三点: 存储在每个元素中的值的类型: 数组名 ...

  10. 【算法笔记】B1029 旧键盘

    1029 旧键盘 (20 分) 旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现.现在给出应该输入的一段文字.以及实际被输入的文字,请你列出肯定坏掉的那些键. 输入格式: 输入在 2 ...