Время написания: 2019-08-21
Время обновления: 2021-03-24Автор: девушка-призрак.
Примечания: эта статья
整理
js изменяет применение, вызов, привязку этого объекта функцииусловие:
整理中
2021-03-24
подать заявку, позвонить, привязать
Что общего у применения, призыва и связывания
-
apply , call , bind используются для изменения точки this объекта функции;
-
Первый параметр apply, call, bind — это объект, на который указывает this, то есть контекст, который вы хотите указать;
-
apply , call , bind могут использовать последующие параметры для передачи параметров;
Различия между применением, вызовом и привязкой
-
bind
Является частичным типом функции и возвращает соответствующую функцию, что удобно для последующего вызова, применения и вызовы вызываются сразу. -
call
Немедленный вызов, параметры нужно передавать по порядку, а apply помещает параметры в массив. Например:func.call(this, arg1, arg2);. (В нестрогом режиме) Когда число параметров неизвестно, функция также может пройти по всем параметрам через массив аргументов. -
apply
Немедленный вызов, помещение аргументов в массив. Например:func.apply(this, [arg1, arg2]).
某个函数的仅仅需要在被调用时改变this指向,使用bind
.
某个函数需要立即执行时,参数是明确知道数量时用 call , 而不确定的时候用 apply,然后把参数 push进数组传递进去
.
bind
Function.prototype.bind(thisArg [ arg1 [ arg2, …]]) — это новый метод расширения функции в ES5, bind() возвращает новый объект функции, this функции привязывается к thisArg и отправляется в Параметры, передаваемые в обработчике события
Объяснение MDN:
Метод bind() создает новую функцию, при вызове bind() this новой функции указывается как первый параметр bind(), а остальные параметры будут использоваться как параметры новой функции для использования при вызове.
связать экземпляр вызова
this.height = '155'; // 在浏览器中,this 指向全局的 "window" 对象
let user = {
height: '170',
getHeight: function() { return this.height; }
};
// 自身调用
user.getHeight(); //user调用getX,此时getX里的this指的是user
console.log(user.getHeight()); // '170'
// 赋值调用
let tianZhen = user.getHeight; // 相当于 tianZhen = function() { return this.height; }
tianZhen(); // tianZhen函数是在全局作用域中调用的,相当于window.tianZhen(),此时tianZhen = function() { return this.height; }里的this指window
console.log(tianZhen()); // '155'
// 赋值绑定调用
let bindGetH = tianZhen.bind(user); // 把 'this' 绑定到 user 对象,此时bindGetH未立即执行。相当于 tianZhen = function() { return user.height; }
bindGetH(); // 即使在全局作用域直接调用,window.tianZhen()。function() { return user.height; },得到user里的height
console.log(bindGetH()); // '170'
Фактическое использование привязки
В общем паттерне singleton мы обычно используем _this, that, self и т. д. для сохранения this, чтобы мы могли продолжать ссылаться на него после изменения контекста.Привязка dom компонента во vue редко использует bind, а в react — с помощью React .createClass автоматически привязывает this каждого метода к текущему компоненту, но при использовании классов ES6 или чистых функций вам необходимо привязать это вручную, и в настоящее время bind очень подходит. так:
1. Используйте привязку при добавлении метода в дом и передайте это (контекст, который должен связать это),
<button onClick={this.test.bind(this)}>点我一下</button>
import React, {Component} from 'react'
class Greeter extends Component{
constructor (props) {
super(props)
this.state = {}
}
test (value) {
console.log(value)
}
render () {
return (
<div>
<button onClick={this.test.bind(this,3)}>点我一下</button>
</div>
)
}
}
или вот так
2. Преимущество привязки this в конструкторе конструктора состоит в том, что его нужно привязать только один раз, и нет необходимости привязывать его в dom, избегая повторной привязки каждый раз, когда он отображается, и его не нужно привязывать снова, когда функция повторно используется в другом месте.
constructor (props) { super(props) this.test=this.test.bind(this) }
import React, {Component} from 'react'
class Greeter extends Component{
constructor (props) {
super(props)
this.state = {}
this.test=this.test.bind(this)
}
test (value) {
console.log(value)
}
render () {
return (
<div>
<button onClick={this.test(3)}>点我一下</button>
</div>
)
}
}
Кроме того, вы также можете использовать функции стрелок для привязки при добавлении событий в дом, например<button onClick={()=>{this.test()}}>点我一下</button>
, который не будет подробно объясняться здесь.
Последовательные вызовы bind()
Мы можем подумать над вопросом, а именно: если bind() дважды подряд или bind() три раза подряд, каково выходное значение?
В следующем коде bind() создает функцию, чье ключевое слово this будет установлено на переданное значение, когда событие должно быть вызвано (здесь ссылается на первое переданное значение при вызове bind()). Один параметр имеет значение thisArg) . Итак, здесь мы передаем желаемый контекст this в функцию bind(). Затем, когда функция обратного вызова выполняется, this указывает на thisArg. Еще один простой каштан:
let foo = { x: 3 }
let bar = function(){
console.log(this.x);
}
bar(); // undefined
let func = bar.bind(foo);
func(); // 3
Здесь мы создаем новую функцию func.Когда связанная функция создается с помощью bind(), при ее выполнении для нее будет установлено значение foo вместо глобальной области видимости, как при вызове bar() . Есть интересный вопрос, если вы выполняете bind() два раза подряд или bind() три раза подряд, каково выходное значение? так:
let foo = { x: 3 };
let sed = { x: 4 };
let fiv = { x: 5 };
let bar = function(){
console.log(this.x);
}
bar(); // undefined
let func = bar.bind(foo).bind(sed);
func(); // 3
let func2 = bar.bind(foo).bind(sed).bind(fiv);
func2(); // 3
Ответ заключается в том, что оба раза все равно будет выведено 3 вместо ожидаемых 4 и 5 .
Причина в том, что в Javascript несколько раз bind() недействителен.
По более глубокой причине реализация bind() эквивалентна использованию функции для внутреннего переноса вызова/приложения.Второй bind() эквивалентен повторному переносу первого bind(), поэтому связывание после второго раза неэффективно. . Вы можете посмотреть на официальном сайтеПолифилл для Function.prototype.bindвыполнить
подать заявку, звоните
В javascript и вызов, и применение существуют для изменения контекста, в котором выполняется функция, другими словами, для изменения точки this внутри тела функции.
Основная особенность JavaScript заключается в том, что функции имеют такие понятия, как «контекст времени определения», «контекст времени выполнения» и «контекст может быть изменен».
Начнем с примера:
function fruits() {}
fruits.prototype = {
color: "red",
say: function() {
console.log("My color is " + this.color);
}
}
let apple = new fruits;
apple.say(); //My color is red
Но если у нас есть объект банан= {color : "yellow"} и мы не хотим переопределять для него метод say, то мы можем использовать метод say Apple через вызов или применение:
function fruits() {}
fruits.prototype = {
color: "red",
say: function() {
console.log("My color is " + this.color);
}
}
let apple = new fruits;
apple.say(); //My color is red
let banana = {
color: "yellow"
}
apple.say.call(banana); //My color is yellow
apple.say.apply(banana); //My color is yellow
Поэтому видно, что вызов и применение динамически изменяют это, когда у объекта нет метода (у банана нет метода say в этом каштане), но у других есть (у Apple есть метод say в этом каштане) , мы можем использовать методы других объектов для работы с вызовом или применением.
Разница между применением и вызовом
Для применения и вызова функции точно такие же, но способ приема параметров отличается.
-
call
Немедленный вызов, параметры нужно передавать по порядку, а apply помещает параметры в массив. Например:func.call(this, arg1, arg2);. (В нестрогом режиме) Когда число параметров неизвестно, функция также может пройти по всем параметрам через массив аргументов. -
apply
Немедленный вызов, помещение аргументов в массив. Например:func.apply(this, [arg1, arg2]).
Например, есть функция, определенная следующим образом:
let func = function(arg1, arg2) {
console.log(arg1, arg2)
};
func.call(this, '1', '2');
func.apply(this, ['1', '2'])
Если это контекст, который вы хотите указать, это может быть любой объект JavaScript (все является объектом в JavaScript), call должен передавать параметры по порядку, а apply помещает параметры в массив. В JavaScript количество параметров функции не фиксировано, так сказать условия применяются, используйте вызов, когда ваши параметры четко известны. А когда вы не уверены, используйте применить, а затем поместите параметры в массив и передайте их. Когда число параметров неизвестно, функция также может пройти по всем параметрам через массив аргументов. Чтобы укрепить и углубить память, вот несколько распространенных способов использования:
Добавить между массивами
let array1 = [12 , "foo" , { name: "Joe" } , -2458];
let array2 = ["Doe" , 555 , 100];
Array.prototype.push.apply(array1, array2);
console.log(array1); // [12, "foo", {name: "Joe"}, -2458, "Doe", 555, 100]
console.log(array2); // ["Doe", 555, 100]
Получить максимальное и минимальное значение в массиве
let numbers = [5, 458 , 120 , -215 ];
let maxInNumbers1 = Math.max.apply(Math, numbers);
let maxInNumbers2 = Math.max.call(Math,5, 458 , 120 , -215);
// 或者let maxInNumbers2 = Math.max.call(Math, ...numbers);
console.log(maxInNumbers1); //458
console.log(maxInNumbers2); //458
У самого числа нет метода max, но у Math он есть, и мы можем использовать его методы с вызовом или применением.
Проверьте, является ли это массивом(при условии, что метод toString() не был переопределен)
Использование typeof для оценки типа данных в JavaScript позволяет различать только основные типы, а именно: число, строка, неопределенный, логический, объект. Для null, массива, функции и объекта использование typeof единообразно возвращает строку объекта. Чтобы различать объекты, массивы и функции, недостаточно просто использовать typeof.
В JS вы можете использовать метод Object.prototype.toString, чтобы определить, к какому встроенному типу принадлежит объект. Разделяется на ноль, строку, логическое значение, число, неопределенное значение, массив, функцию, объект, дату, математику и т. д.
Конечно, вы также можете напрямую использовать оператор instanceof для оценки.
Используйте демо-вызов следующим образом, чтобы проверить, является ли он массивом
function isArray(obj){
return Object.prototype.toString.apply(obj) === '[object Array]' ;
// 或者 return Object.prototype.toString.call(obj) === '[object Array]' ;
}
let arrFlag = isArray(['7', '6']);
console.log(arrFlag); // true
Массивы класса (псевдо) используют методы массива
В Javascript есть объектная структура, называемая псевдомассивом. Более особенным является объект arguments, а также такие вызовы, как getElementsByTagName, document.childNodes и им подобные, которые возвращают объекты NodeList, являющиеся псевдомассивами. Методы push , pop array в Array не могут быть применены.
Но мы можем преобразовать его в реальный объект массива со свойством длины через Array.prototype.slice.call, чтобы domNodes могли применять все методы в Array.
通过 Array.prototype.slice.call 或 Array.prototype.slice.apply 转化为标准数组
伪类数组是无法直接使用Array的内置方法,所以会抛错
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta height="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<span>1</span>
<span>2</span>
</div>
</body>
<script>
let domNodes1 = Array.prototype.slice.call(document.getElementsByTagName('span'));
// 或者
let domNodes2 = Array.prototype.slice.apply(document.getElementsByTagName('span'));
console.log(domNodes1);
console.log(domNodes2);
применять, звонить, связывать сравнение
Так в чем же разница между Apply, Call и Bind?
Когда использовать apply, call и когда использовать bind.
Простой каштан:
var obj = {x: 81,
};
var foo = {
getX: function() {
return this.x;
}
}
console.log(foo.getX.bind(obj)()); //81
console.log(foo.getX.call(obj)); //81
console.log(foo.getX.apply(obj)); //81
Все три вывода равны 81, но обратите внимание на использование метода bind(), за которым следует пара круглых скобок.
То есть разница в том, что когда вы хотите изменить контекст не сразу, а колбэком, используйте метод bind(). Принимая во внимание, что apply/call выполняет функцию немедленно.
Подводя итог еще раз:
apply , call , bind используются для изменения точки this объекта функции; Первый параметр apply, call, bind — это объект, на который указывает this, то есть контекст, который вы хотите указать; apply , call , bind могут использовать последующие параметры для передачи параметров;
Привязка соответствующая функция возвращается, чтобы облегчить позже вызов; Применить, вызов немедленно вызывается.