call apply bind
都有着改变this
指向的功能,什么叫改变this指向呢?this
:当前作用域的顶层对象。某个方法内可能引用了他当前作用域的对象的属性,改变this指向就是把他的this更换为其他对象。这么做的意义是什么呢?话不多说,上代码。
const Animal = {
name: '动物',
say() {
console.log(`大家好,我是${this.name}`)
}
}
const Cat = {
name: '大狸猫'
}
Animal.say.call(Cat)
// 大家好,我是大狸猫
Animal.say.apply(Cat)
// 大家好,我是大狸猫
Animal.say.bind(Cat)()
// 大家好,我是大狸猫
上图三个方法都能通过传参改变
Animal.say
方法中的this
。call apply bind
都是Function.prototype
上的方法,通过传参的方式把内部this
替换为参数中的对象。来看区别,为什么bind
后面还跟了个括号?括号表示调用,逆向思考可以得知,bind
方法返回了一个新的函数,手动执行才能调用。call
和apply
都是直接调用。bind
写法虽然看上去麻烦点,但如果你此时不想调用而是在未来的某一刻调用,这个时候就可以赋值给一个变量,等到需要的时候再调用了
const Animal = {
name: '动物',
say(food, sport) {
console.log(`大家好,我是${this.name}, 我喜欢吃${food},我喜欢的运动是${sport}`)
}
}
const Cat = {
name: '大狸猫'
}
Animal.say.call(Cat, '猫草', '抓老鼠')
// 大家好,我是大狸猫, 我喜欢吃猫草,我喜欢的运动是抓老鼠
Animal.say.apply(Cat, ['猫草', '抓老鼠'])
// 大家好,我是大狸猫, 我喜欢吃猫草,我喜欢的运动是抓老鼠
Animal.say.bind(Cat)('猫草', '抓老鼠')
// 大家好,我是大狸猫, 我喜欢吃猫草,我喜欢的运动是抓老鼠
可以看出,额外参数都紧跟在第一个参数之后,
call
和bind
参数以散列形式,apply
参数以数组形式,并推理出apply
拥有打散数组的功能
const Animal = {
name: '动物',
say(food, sport) {
console.log(`大家好,我是${this.name}, 我喜欢吃${food},我喜欢的运动是${sport}`)
}
}
const Cat = {
name: '大狸猫'
}
Animal.say.bind(Cat)('猫草', '抓老鼠')
// 大家好,我是大狸猫, 我喜欢吃猫草,我喜欢的运动是抓老鼠
Animal.say.bind(Cat, '猫草1')('猫草', '抓老鼠')
// 大家好,我是大狸猫, 我喜欢吃猫草1,我喜欢的运动是猫草
Animal.say.bind(Cat, '猫草1', '抓老鼠1')('猫草', '抓老鼠')
// 大家好,我是大狸猫, 我喜欢吃猫草1,我喜欢的运动是抓老鼠1
以上代码可以看出,
bind
方法产数传递,如果bind
方法内有参数以bind
方法内参数为主。
实际应用
import React from 'react'
export default class App extends React.component {
state = {
age: 24
}
constructor() {
super()
this.checkAdult = this.checkAdult.bind(this)
}
checkAdult() {
console.log(this.state.age >= 18 ? '成年了' : '未成年')
}
render() {
return (
<button onClick={this.checkAdult}>检测</button>
)
}
}
在
react
中,我们在可以在构造函数内实现this
绑定(当然我们也可以使用箭头函数或者public class fields语法(stage 2)直接在class内赋值)
react相关this指向相关问题
Math.max.apply(Math, [5, 2, 6, 9, 20, 12])
数组的求最大值(也可以使用es6的扩展运算符
Math.max(...arr))
继承
function Animal(sound) {
this.sound = sound
this.say = function() {
console.log(this.sound)
}
}
function Dog() {
Animal.apply(this, arguments)
}
const dog = new Dog('wang wang')
dog.say()
// wang wang
在构造函数
Dog
内使用call
或者apply
,此时Animal
的所有属性和方法都被在此声明,实现继承
伪数组转换成数组
伪数组也称类数组。像arguments 或者 获取一组元素返回的集合都是伪数组。
(arguments,NodeList)
const imgArr = Array.prototype.slice.call(document.querySelectorAll('img'))
function Dog() {
const ages = Array.prototype.slice.call(arguments)
}
当然也可以用ES6简单写法
const arg = Array.from(arguments);
const arg = [...arguments]
console.log(arg instanceof Array)
// true
Array.from()
能将类数组(arguments,NodeList)
,可迭代对象(Set,Map)
,字符串(String)
转换成数组
Array.prototype.slice.call()
能将类数组(arguments,NodeList)
,字符串(String)
转换成数组
总结
-
call apply bind
都有着改变this
指向的作用,并且第一个参数都是目标this
对象,bind
返回一个新的函数 - 额外参数下,
call
和bind
的参数都以散列形式,apply
以数组形式
在不破坏原对象的情况下,使用这几个方法是最好的选择。但随着新版es的出现,他们的大部分功能都已能被新的语法糖替代。不过对于开发者来说,但还是应该要了解的,这些知识经常出现在面试题中,况且只有了解原理才能更熟练的掌握新语法的用法,小到api,大到框架,脚踏实地,才能走得更高。
网友评论