contrast
1. call/apply
- The first argument is the changed THIS reference, which is written to whoever it is (special: in non-strict mode, passed
null/undefined
It also points to window. - The only difference: the way functions are executed, the way arguments are passed,
call
Is passed on one by one,apply
Pass the parameters in an array as a whole
func.call([context],10.20)
func.apply([context],[10.20])
Copy the code
2. bind
call/apply
Bind changes this and executes the function directly, whereas bind does not execute the function immediately.- In addition, additional parameters can be passed at binding time, and additional parameters can be passed at execution time.
call
- When the first parameter is null or undefined, this refers to the global object Window, and the primitive value refers to the auto-wrapped object of the primitive value, such as String, Number, or Boolean
- To avoid conflicts between function names and attributes of the context, use the Symbol type as the unique value
- The function is executed as a context property passed in
- Delete this property after the function completes execution
- Return execution result
function add(c, d) {
return this.a + this.b + c + d;
}
const obj = { a: 1.b: 2 };
function es6call(context, ... args) {
context = context || window / / 1.
context === null ? context = window : null;
let type = typeof context;
if(type ! = ="object"&& type ! = ="function"&& type ! = ="symbol") {
//=> Indicates that it is not a reference type but a basic type value
switch (type) {
case 'number':
context = new Number(context);
break;
case 'string':
context = new String(context);
break;
case 'boolean':
context = new Boolean(context);
break; }}let $fn = Symbol(a)// 2. Create a unique Symbol variable to avoid duplication
context.$fn = this;// this = the function add that needs to be executed
args = args ? args : []
$fn is called as an object call, in which case this refers to the context
let result = args.length > 0? context.$fn(... args) : context.$fn();// 3. Execute context.$fn(), which is the function add to be executed, and pass in the argument, in which case this refers to context
delete context.$fn; / / 4.
returnresult; ,,,5.
}
console.log(add.es6call(obj, 3.4)); / / 10
Copy the code
- It is also possible to write methods on the prototype of function
Function.prototype.myCall = function((context, ... args){}Copy the code
apply
- The former part is the same as call
- The second argument may not be passed, but the type must be array or array-like
function apply(context = window, args) {
context.$fn = this;
letresult = context.$fn(... args);delete context.$fn;
return result;
}
Copy the code
bind
- Need to consider:
- Bind () can pass multiple arguments in addition to this;
- New functions created by bind may pass in multiple arguments;
- New functions may be called as constructors;
- A function may have a return value;
- Implementation method:
- The bind method does not execute immediately and needs to return a function to be executed; (closures)
- Implement scope binding (apply)
- Parameter passing (array passing for apply)
- When used as a constructor, stereotype inheritance is performed
~ function anonymous(proto) {
function bind(context){
//=>this: the function to be executed
//context may be null or undefined
if (context == undefined) {
context = window;
}
// Get the collection of arguments passed
/ / the arguments {0: context, ", ", length: 3} incoming the arguments is an array class. Not a real array, so you can't use the slice method of an array
var args = [].slice.call(arguments.1) // equivalent to arguments.slice, gets the collection of arguments passed
// The function that needs to be executed finally
var _this = this //obj.fn
function anonymous(){
var innerArg = [].slice.call(arguments.0) // Accept the parameters passed in when anonymous is executed. We cut it off at 0.
args = args.concat(innerArg) // Concatenate two arrays
// If this of the current function refers to this in the constructor, it is considered new
var new_this = this instanceof _this ? this : context
_this.apply(new_this, args)
}
// To complete the new operation, there is one more thing you need to do to perform the prototype link
// Maintain prototype relationships
var fnNoop = function(){} / / empty function
if(this.prototype){
fnNoop.prototype = this.prototype
}
anonymous.prototype = new fnNoop()
return anonymous
}
proto.bind = bind
}(Function.prototype)
Copy the code