pointer to this in ES5
According to this
the priority of the pointer, list the following four situations that are often encountered, from top to bottom, the priority is from high to low (the priority will be compared in detail later).
- Is the function
new
called with ( new binding )? If it is,this
it is the newly constructed object.var bar = new foo()
- Is the function used
call
orapply
called ( explicitly bound ), or even hidden inbind
hard bindings ? If it is,this
it is an explicitly specified object.var bar = foo.call( obj2 )
- Is the function called with an environment object (also called an owner or container object) ( implicit binding )? If it is,
this
it is that environment object.var bar = obj1.foo()
- Otherwise, the default
this
( default binding ) is used. If it isstrict mode
under , it isundefined
, otherwise it is anglobal
object.var bar = foo()
That's all you need to understand the this
binding rules for ordinary function calls. Yes...almost all.
apply、call、bind
Because apply and call exist in Function.prototype, each method has these two properties.
- call
函数名.call(对象,arg1....argn)
//功能:
//1.调用函数
//2.将函数内部的this指向第一个参数的对象
//3.将第二个及以后所有的参数,作为实参传递给函数
- The main purpose of apply
is to pass parameters directly with an array
函数名.apply(对象, 数组/伪数组);
//功能:
//1.调用函数
//2.将函数内部的this指向第一个参数的对象
//3.将第二个参数中的数组(伪数组)中的元素,拆解开依次的传递给函数作为实参
//案例求数组中最大值 var a=Math.max.apply( null, [ 1, 2, 5, 3, 4 ] ); console.log(a);// 输出:5
- bind
- is to create a new function, we have to call it manually:
var a ={
name : "Cherry",
fn : function (a,b) { console.log( a + b) } } var b = a.fn; b.bind(a,1,2)() // 3
-
Precautions
- The functions of call and apply are almost the same, the only difference is the way of passing parameters! !
2. If the first parameter of call and apply is null or undefined, then this points to window
3. If the first parameter of call and apply is data of value type, then the data of this value type will be converted into its corresponding The data of the reference type, and then point this to the data of this reference type.
4.call and apply execute the function immediately. The bind method allows the corresponding function to be called whenever it wants, and the parameters can be called at the time of execution. Add, this is the difference between them, choose to use according to your actual situation.
5. When the number of parameters is determined, you can use call; when the number of parameters is uncertain, you can use apply
- The functions of call and apply are almost the same, the only difference is the way of passing parameters! !
applyApply
JavaScript
var array1 = [12 , "foo" , {name "Joe"} , -2458]; var array2 = ["Doe" , 555 , 100]; Array.prototype.push.apply(array1, array2); /* array1 值为 [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */
call application (convert pseudo-array to array)
var arrayLike = {0: 'name', 1: 'age', 2: 'sex', length: 3 } Array.prototype.join.call(arrayLike, '&'); // name&age&sex Array.prototype.slice.call(arrayLike, 0); // ["name", "age", "sex"] // slice可以做到类数组转数组 Array.prototype.map.call(arrayLike, function(item){ return item.toUpperCase(); }); // ["NAME", "AGE", "SEX"]
call application (judging complex data types)
console.log(
Object.prototype.toString.call(num),
Object.prototype.toString.call(str),
Object.prototype.toString.call(bool),
Object.prototype.toString.call(arr), Object.prototype.toString.call(json), Object.prototype.toString.call(func), Object.prototype.toString.call(und), Object.prototype.toString.call(nul), Object.prototype.toString.call(date), Object.prototype.toString.call(reg), Object.prototype.toString.call(error) ); // '[object Number]' '[object String]' '[object Boolean]' '[object Array]' '[object Object]' // '[object Function]' '[object Undefined]' '[object Null]' '[object Date]' '[object RegExp]' '[object Error]'
Bind is applied in react
The following example is a case from the react official website
class Toggle extends React.Component { constructor(props) { super(props); this.state = {isToggleOn: true}; // This binding is necessary to make `this` work in the callback this.handleClick = this.handleClick.bind(this); } handleClick() { console.log(this); this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })); } render() { return ( <button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button> ); } } ReactDOM.render( <Toggle />, document.getElementById('root') );
If you forget to bind
this.handleClick
and pass it toonClick
,this
will beundefined
when the function is actually called.
Point to this in ES6
Arrow function this points to note
The object in the body of the arrow function this
, if it is wrapped in the function, is the object where the function is called, and if it is placed in the global, it refers to the global object window. And fixed does not change. In other words , the inner part this
is the outer code block.this
The following is a comparative analysis of the difference between this in ordinary functions and arrow functions
// 普通函数
function foo() { setTimeout(function() { console.log('id:', this.id); }); } var id = 21; foo.call({ id: 42 }); //21
// 箭头函数
function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; foo.call({ id: 42 }); //42 // 上面的匿名函数定义时所在的执行环境就是foo函数,所以匿名函数内部的this执向始终会和foo函数的this执向保持一致,不会更改,如同下面的这个案例 function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; foo(); //21(没有用call)
// ES5普通函数模拟上面es6函数的执行过程
function foo() { var _this = this; setTimeout(function () { console.log('id:', _this.id); }, 100); }
The function of call is to change the execution environment of the foo function from window to the object
{id: 42}
timer. The function of the timer is to delay the execution of the external execution environment of the current function, regardless of whether the delay time is set or not.
Ordinary function explanation: this points to the function foo
scope when it is defined, but when the function is executed 100 milliseconds after the timer, this points to the window object at this time
Arrow function explanation: this always points to the object where it was defined, that is, always points to the foo
scope
Further analysis of this
var handler = {
id: '123456',
init: function() { document.addEventListener('click', event => this.doSomething(event.type), false); }, doSomething: function(type) { console.log('Handling ' + type + ' for ' + this.id); } }; handler.init()// Handlingclickfor123456
The this of the arrow function always points to handler
, if it is a normal function, this points todocument
this
The fixed point is not because there is a binding this
mechanism inside the arrow function. The actual reason is that the arrow function does not have its own at all this
, resulting in the inner this
code blockthis
. Precisely because it doesn't this
, it can't be used as a constructor.
Considerations (Binding Events)
In IE678, addEventListener and removeEventListener are not supported, but two methods, attachEvent and detachEvent, are supported.
语法:target.attachEvent(“on”+type, listener);
The difference between attachEvent and addEventListener:
- This in the attchEvent points to not the caller of the event, but the window (wonderful) , and the caller of the event pointed to by addEventListener.
- The type of attachEvent must be added on, otherwise it will have no effect
interview questions
The following interview questions 1, 2, and 4 are all designed to refer to the question. If it is not well understood, it can be understood that in es5, this always points to the object that called it last. excerpt link
The following concepts related to pointer applications and bindings are taken from the You Dont Konw JS link
interview question one
this.x = 9; // this refers to global "window" object here in the browser
var module = { x: 81, getX: function() { return this.x; } }; module.getX(); // 81 var retrieveX = module.getX; retrieveX(); // returns 9 - The function gets invoked at the global scope // Create a new function with 'this' bound to module // New programmers might confuse the // global var x with module's property x var boundGetX = retrieveX.bind(module); boundGetX(); // 81
retrieveX
It's just getX
a reference to the function, which is just getX
a pointer ( getX
the other pointer is module.getX
), so it retrieveX
still points to the getX
function itself
Similar to the case above, the following func is just a function reference, so even inside the function, it is still the executed function itself, which is not restricted by lexical scope (arrow functions are restricted)
document.getElementById( 'div1' ).onclick = function(){ console.log( this.id );// 输出: div1 var func = function(){ console.log ( this.id );// 输出: undefined } func(); }; //修正后 document.getElementById( 'div1' ).onclick = function(){ var func = function(){ console.log ( this.id );// 输出: div1 } func.call(this); };
function foo() { console.log( this.a ); } var a = 2; var o = { a: 3, foo: foo }; var p = { a: 4 }; o.foo(); // 3 (p.foo = o.foo)(); // 2
Interview question two
var A = function( name ){
this.name = name; }; var B = function(){ A.apply(this,arguments); }; B.prototype.getName = function(){ return this.name; }; var b=new B('sven'); console.log( b.getName() ); // 输出: 'sven'
Interview question three
Indeed, many functions in packages, and many built-in functions in the JavaScript language and the host environment, take an optional parameter, often called a "context", designed as an alternative to ensure that you The callback function uses a specific this instead of having to use bind(..).
for example:
function foo(el) {
console.log( el, this.id ); } var obj = { id: "awesome" }; // 使用`obj`作为`this`来调用`foo(..)` [1, 2, 3].forEach( foo, obj ); // 1 awesome 2 awesome 3 awesome
Interview question four
Explicit binding takes precedence over implicit binding
function foo() { console.log( this.a ); } var obj1 = { a: 2, foo: foo }; var obj2 = { a: 3, foo: foo }; obj1.foo(); // 2 obj2.foo(); // 3 obj1.foo.call( obj2 ); // 3 obj2.foo.call( obj1 ); // 2
The priority of new binding is higher than implicit binding (new and call/apply cannot be used at the same time, so new foo.call(obj1) is not allowed, that is, new binding and explicit binding cannot be tested directly)