Come and study this week this,this Abuse me thousands of times , I'll stay this Like first love , Every time I look this will , It refers to its caller , As soon as you do a problem, it will waste , This time, dig the roots , Get to know it this The mechanism of
Don't use this, Pass a context object to be displayed
function identify(person){
return person.name
}
function speak(person){
var greeting = "Hello , I am " + identify(person)
console.log(greeting)
}
const p1={
name:"ABC"
}
const p2={
name:"DEF"
}
identify(p1) // ABC
speak(p2) // Hello , I am DEF
Copy code
Use this, You can implicitly pass object references , So you can put API The design is more concise and easy to reuse
function identify(){
return this.name
}
const p1={
name:"ABC"
}
identify.call(p1) // ABC
Copy code
this Point to their own ( This is wrong !!!)
function fn(num){
console.log(num)
this.count++
}
fn.count = 0;
for(var i=0;i<5;i++){
fn(i)
}
console.log(fn.count) //0====>?????
Copy code
according to this A statement pointing to itself , that this.count++ amount to foo.count++ The actual output should be 5, But the final output is 0, Obviously, this understanding is wrong .
Solution
Create a global count attribute ( Global lexical scope is used , I dodged this)
var count =0;
function fn(){
this.count++
}
for(var i=0;i<5;i++){
fn(i)
}
console.log(this.count) //5
Copy code
Create a function count attribute ( Using variables fn The lexical scope of , I dodged this)
function fn(){
fn.count++
}
fn.count =0;
for(var i=0;i<5;i++){
fn(i)
}
console.log(fn.count) //5
Copy code
mandatory this Point to fn
function fn(){
this.count++
}
fn.count=0;
for(var i=0;i<5;i++){
fn.call(fn,i)
}
console.log(fn.count) //5
Copy code
this Scope of action
this Point to the scope of the function , This is wrong . In any case this Does not point to the lexical scope of the function
function foo(){
var a = 2;
this.bar()
}
function bar(){
console.log(a)
}
foo() //Uncaught ReferenceError: a is not defined
Copy code
Lexical scope
window
foo
a:
bar:function
Copy code
Whenever you want to this Mixed with lexical scope search , Be sure to remind yourself of , This is impossible .
this What is it
this It's bound at run time , Its context depends on the various conditions when the function is called .
this The binding of has nothing to do with the location of the function declaration , It just depends on how the function is called .
this Neither the function itself nor the lexical scope of the function .
Take a look back. JavaScript Execution process learning notes ,js In the execution phase ( Function call ) Conduct this The binding of ( Runtime binding )
The position : Is where the function is called in the code ( Is not the location of the function declaration )
function baz(){
console.log('baz')
bar()
}
function bar(){
console.log('bar')
foo()
}
function foo(){
debugger
console.log('foo')
}
baz();
Copy code
The call stack is shown in the figure Call Stack here this Point to window
const obj = {
name:' test ',
baz:function(){
console.log('baz')
this.bar()
},
bar:function(){
console.log('bar')
this.foo()
},
foo:function(){
console.log(foo)
}
}
obj.baz()
Copy code
The call stack is shown in the figure Call Stack here this Point to obj
const person = {
name:'ddd'
}
function speak(){
console.log(this.name)
}
speak();// this Point to window
speak.call(person) // this Point to person
Copy code
How to determine the location of a function during execution this The direction of ?
Independent function call
Nonstrict mode ,this Point to window
function foo(){
console.log(this.a)
}
var a = 2;
foo()//2
Copy code
Strict mode ,this Point to undefined
function foo(){
"use strict"
console.error(this.a)
}
var a = 2;
foo()//VM156:3 Uncaught TypeError: Cannot read property 'a' of undefined
Copy code
Does the function call location have a context object , Or is it contained or owned by an object
function foo(){
console.log(this.a)
}
var a = 'window'
var obj ={
a:'obj',
foo:foo
}
obj.foo() //'obj'
Copy code
Call position enable obj Context to reference function , Implicit binding rules this Points to the current context object obj
Object properties in the call chain , Only the last or last layer works in the call location
function foo(){
console.log(this.a)
}
var a = 'window'
var obj1 ={
a:'obj1',
foo:foo
}
var obj2 ={
a:'obj2',
obj1:obj1,
foo:foo
}
obj2.obj1.foo() // 'obj1'
Copy code
Implicit loss problem
Assignment operation ,bar = obj1.foo The actual is foo References to functions ,bar Call without any modifiers , Hide apply default binding rules
function foo(){
console.log(this.a)
}
var a = 'window'
var obj1 ={
a:'obj1',
foo:foo
}
var bar = obj1.foo
bar() // window
Copy code
Function passed as parameter , Parameter passing is actually an implicit assignment ,doFn(obj.foo) actual var fn = obj.foo; fn() ; fn Call without any modifiers , Hide apply default binding rules
function foo(){
console.log(this.a)
}
var a = 'window'
var obj ={
a:'obj',
foo:foo
}
function doFn(fn){
fn()// The position
}
doFn(obj.foo) // window
Copy code
Callback function this The loss of
function foo(){
console.log(this.a)
}
var a = 'window'
var obj ={
a:'obj',
foo:foo
}
setTimeout(obj.foo,100) //'window'
Copy code
setTimeout Internal implementation pseudo code , When a function is called obj.foo Assign a value to fn,fn Actually, it points to foo Self function
function setTimeout(fn,delay){
// Delay time
fn() // Actual call location
}
Copy code
Review the implicit binding above , We must include a property that points to a function in an object , And it is used to call the function indirectly through the attribute of the object , So that this Implicitly bind to this context object , So if we don't include functions inside objects , Instead, you want to force a function call on an object , Then you need to display the binding , It's possible to do this through the call() and apply() Method to implement .
call(obj,arg1,arg1,...),apply(obj,[arg1,arg2,..]), Their first argument is the object , It's for this Get ready , Bind the function to the this, In this way, you can point directly to this Bound object , This is called display binding
function foo(){
console.log(this.a)
}
var a = 'window'
var obj ={
a:'obj',
}
foo.call(obj)
Copy code
Can display binding solve the problem of implicit loss ?
function foo(){
console.log(this.a)
}
var a = 'window'
var obj ={
a:'obj',
}
foo.call(obj) // 'obj'
setTimeout(foo,100)// 'window'
Copy code
It can be seen that , It does not solve the problem of implicit loss , although foo.call(obj) take this Yes obj, However, when the display binding is actually called this, After the function is called this No longer under your control , However, it is not possible to determine when a function is passed as an argument to another function , How will other functions call this function .
for instance , A tool function you use , This function is asynchronous , You need to do something after asynchrony ends , The traditional operation is through the callback function , After the asynchronous operation of the tool function is completed , Call the function you passed , But you used it in your own function this, And expect this Point to a specific object , Use call perhaps apply For display binding , The display binding is bound when the function is called , At this time, your function has been executed , The expectation is that the tool function will call its own function after asynchronous execution , How to call your own function in a tool function , We don't know , Can be called directly , You can show bindings this, here this Our direction is no longer under our control .
function myFun(){
console.log(this.name)
}
var name = 'window'
var p1 = {
name:'p1'
}
var p2 = {
name:'p2'
}
myFun.call(p1); // 'p1'
// Tool function
function util(fn){
// Function call Black box operation for users I don't know how to call it internally , therefore this Uncontrolled
fn()// 1、 Call directly 'window'
fn.call(p2) Show bound calls // 'p2'
}
util(myFun)
Copy code
We know because the function is used as a parameter Or callback delivery is , We don't know how to call it internally , That is this Our binding is out of our control , To solve this problem is when the function is passed Conduct this Binding also keeps the function from calling , This way, no matter how the tool function calls your function ,this The direction is certain
function myFun(){
console.log(this.name)
}
var name = 'window'
var p1 = {
name:'p1'
}
var p2 = {
name:'p2'
}
// Tool function
function util(fn){
setTimeout(fn,100)
}
// Wrapping function
function bindFn(obj){
return function(){
myFun.call(obj)
}
}
var fn = bindFn(p1) // It returns a function , Avoid being called directly
util(fn) // fn Manually call the display binding when executing , binding this
Copy code
Create a function package , Each time the function executes this Bind to the expected object , Return a function at the same time , Avoid functions being called directly , See here , Do you remember what we often use bind function ?
bind Source code :developer.mozilla.org/zh-CN/docs/…
if(!Function.prototype.mBind)(function(){
var slice = Array.prototype.slice
Function.prototype.mBind = function(){
var self = this;
var args = slice.call(arguments,1)
var target = arguments[0]
if(typeof self !=='function'){
throw new TypeError('Function.prototype.bind - ' +
'what is trying to be bound is not callable');
}
return function(){
return self.apply(target,args.concat(slice.call(arguments)))
}
}
})()
var person = {
name:'ddd',
say:function(){
console.log(this.name)
}
}
var say = person.say;
var b =say.mBind(person)
b()
Copy code
Use new To call a function , Or when a function call occurs , The following operations will be performed automatically
(1) Create a new object
(2) This new object executes [[Prototype]] Connect
(3) The new object is bound to the of the function call this
(4) If the function does not return another object , that new The function in the expression will automatically return the new object
to glance at new Results of operation
function Person(name,age){
this.name = name ;
this.age = age;
}
var p = new Person('sss',122)
console.log(p)
Copy code
Realize it by yourself :
function newOperator(ctor){
// First judgement
if(typeof ctor !=='function'){
throw 'newOperator function the first param must be a function';
}
// 1. Create a new object
var obj = {}
// 2. establish [[prototype]] Connect
obj.__proto__ = ctor.prototype
// 3. binding this To new object
var args = Array.prototype.slice.call(arguments, 1);
var result = ctor.apply(obj,args)
// 4. Determine the return value
var isObject = typeof result === 'object' && result !== null;
var isFunction = typeof result === 'function';
return isObject || isFunction ? result : obj;
}
function Person(name,age){
this.name = name ;
this.age = age;
}
var p1 = newOperator(Person,"ddd",'123')
console.log(p1)
Copy code
1 and 2 Steps can be used es6 Of Object.create(ctor.prototype), Create a new object and change it [[prototype]] Connect
this Bound with 4 Rules , If multiple applications are applied at the same time , What are the priorities ?
There is no doubt that the default binding has the lowest priority
function say(){
console.log(this.name)
}
var p1 ={
name:'p1',
say:say
}
var p2 = {
name:'p2',
say:say
}
p1.say.call(p2);// p2
p1.say.call(p1)// p1
Copy code
This shows that binding takes precedence over implicit binding
function foo(name){
this.name = name
}
var p1 = {
foo:foo
}
var p2 ={}
p1.foo('p1')
console.log(p1.name) //p1
p1.foo.call(p2,'p2')
console.log(p2.name) //p2
var p3 = new p1.foo('p3')
console.log(p1.name) //p1
console.log(p3.name) //p3
Copy code
Read from this new Binding takes precedence over implicit binding
Does the function exist new call ? If it is this Binding is the newly created object
var p = new Person()
Copy code
Function by call、apply、bind call ? If it is this Points to the bound object
foo.call(p)
Copy code
Is the function called in the context of an object? ( Implicit call )? If it is this Point to the context object
var obj = {
name:'dd',
foo:foo
}
obj.foo()
Copy code
None of the above belong to , Default binding , Strict mode this Bound to the undefined, Non strict mode is bound to window
Arrow function does not use this Of 4 Bar rule , It is determined by the outer function or global scope this
Function.prototype.myCall = function(context){
var context = context ? context : window
context.fn = this
var args = Array.prototype.slice(arguments,1)
var result = context.fn(args)
delete context.fn
return result
}
Copy code
Function.prototype.myApply = function(context) {
context = context ? Object(context) : window
context.fn = this
let args = [...arguments][1]
if (!args) {
return context.fn()
}
let result = context.fn(args)
delete context.fn;
return result
}
Copy code
var obj = {
a: 10,
b: this.a + 10,
fn: function() {
return this.a;
}
}
console.log(obj.b); //NaN this.a this Point to window this.a = undefined
console.log(obj.fn()); // 10 this Point to obj Implicit binding rules
Copy code
var a = 20;
var obj = {
a: 10,
getA: function() {
return this.a;
}
}
console.log(obj.getA()); // 10 this Point to obj Implicit binding rules
var test = obj.getA;
console.log(test()); // 20 After the assignment test in this Point to the big picture The default binding
Copy code
var a = 5;
// Top level function :this Point to window
function fn1() {
var a = 6;
console.log(a);
console.log(this.a); // this Point to the caller
}
function fn2(fn) { // This is equivalent to an implicit assignment fn = f1
var a = 7;
fn(); //window call
}
var obj = {
a: 8,
getA: fn1
}
fn2(obj.getA); // 6 In the current scope a=6; 5 this Refers to the global scope window
Copy code
function fn() {
// "use strict";
// In strict mode : prohibit this Keyword points to global object
console.log(this); //undefined
var a = 1;
var obj = {
a: 10,
c: this.a + 20 // Not for undefined Add attribute
}
return obj.c;
}
console.log(fn()); //Cannot read property 'a' of undefined
Copy code
function Person(name, age) {
this.name = name;
this.age = age;
console.log(this);// Use new Created objects , Output Person
}
Person.prototype.getName = function() {
console.log(this); // Which object is used to call ,this Who do you mean , Output Person
}
var p1 = new Person("test", 18)
p1.getName()
Copy code
var obj = {
foo: "test",
fn: function() { // Object ,this Point to the object
var mine = this;
console.log(this.foo); //"test"
console.log(mine.foo); //"test"
// Method this Point to window
(function(){
console.log(this.foo); //undefined
console.log(mine.foo); //"test" mine Local variable pointing to method mine, Final direction obj object
})()
}
}
obj.fn();
Copy code
function foo() {
console.log(this.a);
}
var a = 2;
var o = {
a: 3,
foo: foo
}
var p = {
a: 4,
}
o.foo(); // 3 this Point to o
(p.foo = o.foo)(); 2 this Self calling function points to global
p.foo = o.foo;
p.foo(); 4 // this Point to p
Copy code
function foo() {
console.log(this.a);
}
var obj1 = {
a: 3,
foo: foo
};
var obj2 = {
a: 5,
foo: foo
};
obj1.foo();//3 Implicit binding
obj2.foo();//5 Implicit binding
obj1.foo.call(obj2)//5 According to the binding
obj2.foo.call(obj1)//3 According to the binding
Copy code