Какая между ними разница? как пользоваться?
call получает несколько параметров, первый — это контекст функции, то есть this, а последние параметры — это параметры самой функции.
let obj = {
name: "一个"
}
function allName(firstName, lastName) {
console.log(this)
console.log(`我的全名是“${firstName}${this.name}${lastName}”`)
}
// 很明显此时allName函数是没有name属性的
allName('我是', '前端') //我的全名是“我是前端” this指向window
allName.call(obj, '我是', '前端') //我的全名是“我是一个前端” this指向obj
apply
apply получает два параметра, первый параметр — это контекст функции this, а второй параметр — это параметр функции, который просто передается в виде массива.
allName.apply(obj, ['我是', '前端'])//我的全名是“我是一个前端” this指向obj
bind
bind получает несколько параметров, первым из которых является возвращаемое значение bindВозвращаемое значение является функциейthis контекста не будет выполнено немедленно.
let obj = {
name: "一个"
}
function allName(firstName, lastName, flag) {
console.log(this)
console.log(`我的全名是"${firstName}${this.name}${lastName}"我的座右铭是"${flag}"`)
}
allName.bind(obj) //不会执行
let fn = allName.bind(obj)
fn('我是', '前端', '好好学习天天向上')
// 也可以这样用,参数可以分开传。bind后的函数参数默认排列在原函数参数后边
fn = allName.bind(obj, "你是")
fn('前端', '好好学习天天向上')
Далее потрите руки, чтобы осуществить вызов, применить и привязать
реализовать вызов
let Person = {
name: 'Tom',
say() {
console.log(this)
console.log(`我叫${this.name}`)
}
}
// 先看代码执行效果
Person.say() //我叫Tom
Person1 = {
name: 'Tom1'
}
// 我们尝试用原生方法call来实现this指向Person1
Person.say.call(Person1) //我叫Tom1
В ходе первого выполнения печати и второго выполнения печати я обнаружил, что если у Person1 есть метод say, то Person1 напрямую выполняет Person1.say(). В результате я являюсь Tom1, и да, вызов реализован таким образом. посмотри на код
Function.prototype.MyCall = function(context) {
//context就是demo中的Person1
// 必须此时调用MyCall的函数是say方法,那么我们只需要在context上扩展一个say方法指向调用MyCall的say方法这样this
console.log(this)
context.say = this //Mycall里边的this就是我们虚拟的say方法
context.say()
}
// 测试
Person.say.MyCall(Person1)//我叫Tom1
let Person = {
name: 'Tom',
say() {
console.log(this)
console.log(`我叫${this.name}`)
}
}
Person1 = {
name: 'Tom1'
}
//如果没有参数
Person.say.call()
Это не указано, это указывает на окно
и мы тоже
Function.prototype.MyCall = function(context) {
// 如果没有参数我们参考call的处理方式
context = context || window
//context就是demo中的Person1
// 必须此时调用MyCall的函数是say方法,那么我们只需要在context上扩展一个say方法指向调用MyCall的say方法这样this
context.say = this //Mycall里边的this就是我们虚拟的say方法
context.say()
}
Person.say.MyCall()
// 找茬2:我们默认定义context.say = this fn如果已经被占用 嘎嘎 sb了。 不怕 搞定它
// say需要是一个唯一值 是不是突然想到es6的新类型 Symbol fn = Symbol() 不过我们装逼不嫌事大 都说自己实现了
function mySymbol(obj) {
// 不要问我为什么这么写,我也不知道就感觉这样nb
let unique = (Math.random() + new Date().getTime()).toString(32).slice(0, 8)
// 牛逼也要严谨
if (obj.hasOwnProperty(unique)) {
return mySymbol(obj) //递归调用
} else {
return unique
}
}
//接下来我们一并把多参数和执行完删除自定义方法删除掉一块搞定
Function.prototype.myCall1 = function(context) {
// 如果没有传或传的值为空对象 context指向window
context = context || window
let fn = mySymbol(context)
context[fn] = this //给context添加一个方法 指向this
// 处理参数 去除第一个参数this 其它传入fn函数
let arg = [...arguments].slice(1) //[...xxx]把类数组变成数组,arguments为啥不是数组自行搜索 slice返回一个新数组
context[fn](...arg) //执行fn
delete context[fn] //删除方法
}
let Person = {
name: 'Tom',
say(age) {
console.log(this)
console.log(`我叫${this.name}我今年${age}`)
}
}
Person1 = {
name: 'Tom1'
}
Person.say.call(Person1,18)//我叫Tom1我今年18
Результаты теста идеальны!
применить применить
Дальше применить намного проще, только когда параметров несколько, второй параметр является массивом, поэтому пошагово расписывать не буду.
Function.prototype.myApply = function(context) {
// 如果没有传或传的值为空对象 context指向window
if (typeof context === "undefined" || context === null) {
context = window
}
let fn = mySymbol(context)
context[fn] = this //给context添加一个方法 指向this
// 处理参数 去除第一个参数this 其它传入fn函数
let arg = [...arguments].slice(1) //[...xxx]把类数组变成数组,arguments为啥不是数组自行搜索 slice返回一个新数组
context[fn](arg) //执行fn
delete context[fn] //删除方法
}
реализовать привязку
Это очень отличается от вызова и подачи заявки, дайте мне выкурить сигарету и вернуться, чтобы убрать его Или старый способ сначала проанализировать, что умеет бинд и каковы характеристики 1. Вызов функции, измените это 2. Верните функцию, которая связывает это 3. Получить несколько параметров 4. Поддерживает передачу параметров в каррированной форме fn(1)(2)
Function.prototype.bind = function(context) {
//返回一个绑定this的函数,我们需要在此保存this
let self = this
// 可以支持柯里化传参,保存参数
let arg = [...arguments].slice(1)
// 返回一个函数
return function() {
//同样因为支持柯里化形式传参我们需要再次获取存储参数
let newArg = [...arguments]
console.log(newArg)
// 返回函数绑定this,传入两次保存的参数
//考虑返回函数有返回值做了return
return self.apply(context, arg.concat(newArg))
}
}
// 搞定测试
let fn = Person.say.bind(Person1)
fn()
fn(18)
Да, отлично, реализует привязку this, возвращает функцию, не выполняется сразу и может передавать параметры в каррированном виде. Для получения дополнительной информации о каррировании перейдите по ссылке:сегмент fault.com/ah/119000001…
Реализация упрощенной версии завершена
Комментарии или лайки приветствуются!