共计 4845 个字符,预计需要花费 13 分钟才能阅读完成。
1. 什么是办法
首先让咱们定义并调用惯例函数:
function greet(who) {return `Hello, ${who}!`;
}
greet('World'); // => 'Hello, World!'
惯例函数定义 的模式为关键字 function
后跟名称、参数和函数体:function greet(who) {...}
。
greet('World')
是 惯例函数调用。函数 greet('World')
从参数承受数据。
如果 who
是对象的属性怎么办?要想轻松拜访对象的属性,能够将函数附加到该对象,也就是创立一个办法。
让咱们把 greet()
作为对象 world
的一个办法:
const world = {
who: 'World',
greet() {return `Hello, ${this.who}!`;
}
}
world.greet(); // => 'Hello, World!'
greet() { ...}
当初是属于 world
对象的一个 办法 。world.greet()
是一种办法调用。
在 greet()
办法外部,this
指向该办法所属的对象 world
。这就是为什么 this.who
表达式可能拜访属性 who
的起因。
this
也叫 上下文(context)。
上下文是可选的
在上个例子中,咱们用了 this
来拜访该办法所属的对象,然而 JavaScript 并没有强制应用 this
的办法。
所以能够将对象作为办法的命名空间来应用:
const namespace = {greet(who) {return `Hello, ${who}!`;
},
farewell(who) {return `Good bye, ${who}!`;
}
}
namespace.greet('World'); // => 'Hello, World!'
namespace.farewell('World'); // => 'Good bye, World!'
namespace
是一个领有 2 种办法的对象:namespace.greet()
和 namespace.farewell()
。
这些办法没有用 this
,而 namespace
是办法的所有者。
2. 对象字面量办法
如下面所示,你能够间接在对象字面量中定义方法:
const world = {
who: 'World',
greet() {return `Hello, ${this.who}!`;
}
};
world.greet(); // => 'Hello, World!'
greet(){....}
是在对象字面量上定义的办法。这种定义类型称为 简写办法定义(ES2015+ 开始可用)。
办法定义的语法也更长:
const world = {
who: 'World',
greet: function() {return `Hello, ${this.who}!`;
}
}
world.greet(); // => 'Hello, World!'
greet: function() {...}
是 办法定义。留神冒号和 function
关键字。
动静增加办法
办法只是一个函数,它作为属性被保留在对象上。因而能够向对象动静增加办法:
const world = {
who: 'World',
greet() {return `Hello, ${this.who}!`;
}
};
// 一个带有函数的新属性
world.farewell = function () {return `Good bye, ${this.who}!`;
}
world.farewell(); // => 'Good bye, World!'
首先,world
对象没有 farewell
办法,它是被动静增加的。
调用动静增加的办法齐全没有问题:world.farewell()
。
3. 类办法
在 JavaScript 中,class
语法定义了一个类,该类是它实例的模板。
一个类也能够有办法:
class Greeter {constructor(who) {this.who = who;}
greet() {console.log(this === myGreeter); // => true
return `Hello, ${this.who}!`;
}
}
const myGreeter = new Greeter('World');
myGreeter.greet(); // => 'Hello, World!'
greet() {...}
是在类外部定义的办法。
每次应用 new
操作符创立类的实例时(例如,myGreeter = new Greeter('World')
),都能够通过办法来创立实例。
myGreeter.greet()
是在实例上调用 greet()
办法的,办法外部的 this
等于实例自身,即 this
等于 greet() { ...}
办法外部的 myGreeter
。
4. 如何调用办法
4.1 办法调用
对象或类上定义方法只是实现了工作的一半。为了放弃办法的上下文,你必须确保将其作为“办法”去调用。
回忆一下带有 greet()
办法的 world
对象。让咱们检查一下当办法和惯例函数 greet()
被调用时,this
的值是什么:
const world = {
who: 'World',
greet() {console.log(this === world); return `Hello, ${this.who}!`;
}
};
// 办法调用
world.greet(); // => true
const greetFunc = world.greet;
// 惯例函数调用
greetFunc(); // => false
world.greet()
是一种办法调用。对象 world
,后跟一个点 .
,最初是办法自身,这就是 办法调用。
greetFunc
与 world.greet
的性能雷同。然而当作为 惯例函数 greetFunc()
调用时,greet()
外部的 this
不等于 world
对象,而是等于全局对象(在浏览器中是 window
)。
命名相似 greetFunc = world.greet
的表达式,将办法与其对象 离开。当稍后调用拆散的办法 greetFunc()
时,会使 this
等于全局对象。
将办法与其对象离开能够采取不同的模式:
// 办法是离开的!this 失落!const myMethodFunc = myObject.myMethod;
// 办法是离开的!this 失落!setTimeout(myObject.myMethod, 1000);
// 办法是离开的!this 失落!myButton.addEventListener('click', myObject.myMethod)
// 办法是离开的!this 失落!<button onClick={myObject.myMethod}>My React Button</button>
为防止失落办法的上下文,要确保应用办法调用 world.greet()
或将办法手动绑定到对象 greetFunc = world.greet.bind(this)
。
4.2 间接函数调用
在上一节中,惯例函数调用已将 this
解析为全局对象。那么有没有一种办法能够使惯例函数具备 this
的可自定义值?
能够应用上面的间接函数调用:
myFunc.call(thisArg, arg1, arg2, ..., argN);
myFunc.apply(thisArg, [arg1, arg2, ..., argN]);
myFunc.call(thisArg)
和 myFunc.apply(thisArg)
的第一个参数是间接调用的上下文(this
的值)。换句话说,你能够手动扭转函数中 this
的值。
例如,让咱们将 greet()
定义为惯例函数,并定义一个具备 who
属性的对象 aliens
:
function greet() {return `Hello, ${this.who}!`;
}
const aliens = {who: 'Aliens'};
greet.call(aliens); // => 'Hello, Aliens!'
greet.apply(aliens); // => 'Hello, Aliens!'
greet.call(aliens)
和 greet.apply(aliens)
都是间接办法调用。函数 greet()
中的 this
值等于 aliens
对象。
间接调用使你能够在对象上模仿办法调用。
4.3 绑定函数调用
最初是在对象上使函数作为办法调用的第三种办法:将函数绑定为具备特定上下文。
能够用非凡办法创立绑定函数:
const myBoundFunc = myFunc.bind(thisArg, arg1, arg2, ..., argN);
myFunc.bind(thisArg)
的第一个参数是函数要绑定到的上下文。
例如,让咱们重用 greet()
并将其绑定到 aliens
上下文:
function greet() {return `Hello, ${this.who}!`;
}
const aliens = {who: 'Aliens'};
const greetAliens = greet.bind(aliens);
greetAliens(); // => 'Hello, Aliens!'
调用 greet.bind(aliens)
会创立一个新函数,其中 this
绑定到 aliens
对象。
而后,当调用绑定函数 greetAliens()
时,this
等于该函数外部的 aliens
。
同样,应用绑定函数还能够模仿办法调用。
5. 箭头函数办法
不倡议将箭头性能用作办法,起因如下:
// 把 greet() 办法定义为箭头函数
const world = {
who: 'World',
greet: () => {return `Hello, ${this.who}!`;
}
};
world.greet(); // => 'Hello, undefined!'
world.greet()
返回 'Hello, undefined!'
,而不是预期的 'Hello, World!'
。
问题是箭头函数内的 this
属于内部作用域,你想要 this
等于 world
对象,然而在浏览器中 this
是 window
。'Hello, ${this.who}!'
的计算结果为 Hello, ${windows.who}!
,所以最初的后果是 'Hello, undefined!'
。
只管我很喜爱箭头函数,然而不能把它们用作办法。
总结
办法是属于对象的函数。办法的上下文(this
值)等于该办法所属的对象。
你还能够在类上定义方法。类办法中的 this
等于实例。
仅定义一个办法是不够的,还要可能调用才行。个别办法调用实用以下语法:
// 办法调用
myObject.myMethod('Arg 1', 'Arg 2');
在 JavaScript 中,你能够定义一个不属于对象的惯例函数,而后将该函数作为对任意对象的办法来调用。你能够通过间接函数调用或将函数绑定到特定上下文来实现:
// 间接函数调用
myRegularFunc.call(myObject, 'Arg 1', 'Arg 2');
myRegularFunc.apply(myObject, 'Arg 1', 'Arg 2');
// 绑定函数
const myBoundFunc = myRegularFunc.bind(myObject);
myBoundFunc('Arg 1', 'Arg 2');
本文首发微信公众号:前端先锋
欢送扫描二维码关注公众号,每天都给你推送陈腐的前端技术文章
欢送持续浏览本专栏其它高赞文章:
- 深刻了解 Shadow DOM v1
- 一步步教你用 WebVR 实现虚拟现实游戏
- 13 个帮你进步开发效率的古代 CSS 框架
- 疾速上手 BootstrapVue
- JavaScript 引擎是如何工作的?从调用栈到 Promise 你须要晓得的所有
- WebSocket 实战:在 Node 和 React 之间进行实时通信
- 对于 Git 的 20 个面试题
- 深刻解析 Node.js 的 console.log
- Node.js 到底是什么?
- 30 分钟用 Node.js 构建一个 API 服务器
- Javascript 的对象拷贝
- 程序员 30 岁前月薪达不到 30K,该何去何从
- 14 个最好的 JavaScript 数据可视化库
- 8 个给前端的顶级 VS Code 扩大插件
- Node.js 多线程齐全指南
- 把 HTML 转成 PDF 的 4 个计划及实现
- 更多文章 …