You say, Do you understand JavaScript keyword this?

Foreword

Recently read an article on JavaScript keywords thisteaching articles, gains many, therefore, on the basis of this article, a little sorted out for everyone to share. Hope can contribute to learning JavaScript children's shoes, good understanding of thisthis most important keyword in JavaScript.

Meaning

1. Definitions

this is the "current" where the object property or method.

this.property
复制代码

The above code, this property represents an object property is currently located.

The following is a practical example.

var person = {
  name: '张三',
  describe: function () {
    return '姓名:'+ this.name;
  }
};

person.describe()
// "姓名:张三"
复制代码

2. this variability

Since the properties of the object may be assigned to another object, where the properties of the current object is variable, i.e., this point is variable.

var A = {
  name: '张三',
  describe: function () {
    return '姓名:'+ this.name;
  }
};

var B = {
  name: '李四'
};

B.describe = A.describe;
B.describe()
// "姓名:李四"
复制代码

A little remodeling this example, this dynamic will be able to see more clearly pointing.

function f() {
  return '姓名:'+ this.name;
}

var name='王五';

var A = {
  name: '张三',
  describe: f
};

var B = {
  name: '李四',
  describe: f
};

A.describe() // "姓名:张三"
B.describe() // "姓名:李四"
f() // "姓名:王五"
复制代码

3. The web programming application

Look at the example of a web programming.

<input type="text" name="age" size=3 onChange="validate(this, 18, 99);">

<script>
function validate(obj, lowval, hival){
  if ((obj.value < lowval) || (obj.value > hival))
    console.log('Invalid Value!');
}
</script>
复制代码

In summary, among the JavaScript language, everything is an object, the operating environment is object, so functions are run in an object, this is the object where the function is running (environment).

substance

1. Object of the memory address

JavaScript reason why there is this language of design, which has a relationship with memory data structures.

var obj = { foo:  5 };
复制代码

The above object is a code assigned to the variable obj. JavaScript engine will first code in memory, to generate an object {foo: 5}, then the memory address assigned to the variable object obj. In other words, the variable obj is an address (reference). To read back obj.foo, engine start obj get memory address, and then read out the address from the original object, it returns the attribute foo.

Original object stored in a dictionary structure, each property name corresponds to a property description object. For example, the above example foo properties, is actually stored in the following form.

{
  foo: {
    [[value]]: 5
    [[writable]]: true
    [[enumerable]]: true
    [[configurable]]: true
  }
}
复制代码

Note that the value stored in the value foo attribute Attribute Description inside the object.

2. The function of memory address

Such a structure is very clear, that the value of the property in question might be a function.

var obj = { foo: function () {} };
复制代码

In this case, the engine will function individually stored in memory, then the address is then assigned to the function foo attribute property value.

{
  foo: {
    [[value]]: 函数的地址
    ...
  }
}
复制代码

3. The function of the operating environment

Since the function is a single value, it can be performed in a different environment (context).

var f = function () {};
var obj = { f: f };

// 单独执行
f()

// obj 环境执行
obj.f()
复制代码

JavaScript allowed inside the body of the function, refer to the current environment of other variables.

var f = function () {
  console.log(x);
};
复制代码

In the above code, the function body using a variable x. This variable is provided by the operating environment.

4. this appearance of

Now the question becomes, because the functions can be executed in a different operating environment, it is necessary to have a mechanism to get the current operating environment (context) inside the function body. So, this appeared, it is designed to function inside the body, refer to the function of the current operating environment.

var f = function () {
  console.log(this.x);
}
复制代码

In the above code, the function body refers x this.x current operating environment.

var f = function () {
  console.log(this.x);
}

var x = 1;
var obj = {
  f: f,
  x: 2,
};

// 单独执行
f() // 1

// obj 环境执行
obj.f() // 2
复制代码

Using the occasion

1. Global Environment

Global environment using this, it refers to the top-level object window.

this === window // true

function f() {
  console.log(this === window);
}
f() // true
复制代码

The code above description, whether or not inside a function, as long as the running in the global environment, this refers to the top-level object window.

2. Constructor

Constructor this, it refers to an instance object.

var Obj = function (p) {
  this.p = p;
};
复制代码

The above code defines a constructor Obj. Since this refers to an object instance, the constructor defined inside this.p, equivalent to a definition of the object instance attribute p.

var o = new Obj('Hello World!');
o.p // "Hello World!"
复制代码

3. object

If the method of the object which contains the object resides point is the way this, this run-time. This method assigned to another object, this will change the point.

However, this rule is not easy to grasp. Consider the following code.

var obj ={
  foo: function () {
    console.log(this);
  }
};

obj.foo() // obj
复制代码

In the above code, when executed obj.foo method, this refers to its internal obj.

However, the following types of usage of this will change the point of this.

// 情况一
(obj.foo = obj.foo)() // window
// 情况二
(false || obj.foo)() // window
// 情况三
(1, obj.foo)() // window
复制代码

The above three cases is equivalent to the following code.

// 情况一
(obj.foo = function () {
  console.log(this);
})()
// 等同于
(function () {
  console.log(this);
})()

// 情况二
(false || function () {
  console.log(this);
})()

// 情况三
(1, function () {
  console.log(this);
})()
复制代码

If this method a first layer of the object is not located, then this is just one of the current target point, and will not inherit more upper layers.

var a = {
  p: 'Hello',
  b: {
    m: function() {
      console.log(this.p);
    }
  }
};

a.b.m() // undefined
复制代码

In the above code, a second layer ABM method object, this method is not inside the point a, point ab & but, since the actual execution of the code are the following.

var b = {
  m: function() {
   console.log(this.p);
  }
};

var a = {
  p: 'Hello',
  b: b
};

(a.b).m() // 等同于 b.m()
复制代码

If you want to achieve the desired effect, only be written as follows.

var a = {
  b: {
    m: function() {
      console.log(this.p);
    },
    p: 'Hello'
  }
};
复制代码

If you then nested method inside the object assigned to a variable, this still points to the global object.

var a = {
  b: {
    m: function() {
      console.log(this.p);
    },
    p: 'Hello'
  }
};

var hello = a.b.m;
hello() // undefined
复制代码

The above code, m is a method of multilayer objects inside. For simplicity, it is assigned to the variable hello, when you call the result, this points to the top-level object. To avoid this problem, it can only be assigned to an object where m hello, when this call, this point will not change.

var hello = a.b;
hello.m() // Hello
复制代码

Use Precautions

Avoid this multilayer

Since this point is uncertain, it is not to comprise a plurality of layers in this function.

var o = {
  f1: function () {
    console.log(this);
    var f2 = function () {
      console.log(this);
    }();
  }
}

o.f1()
// Object
// Window
复制代码

The above code contains two layers of the this, the result of operation, a first pointing object O layer, the second layer of the global object, because the actual execution of the code are the following.

var temp = function () {
  console.log(this);
};

var o = {
  f1: function () {
    console.log(this);
    var f2 = temp();
  }
}
复制代码

One solution is to use a variable pointing to the second outer layer of this layer.

var o = {
  f1: function() {
    console.log(this);
    var that = this;
    var f2 = function() {
      console.log(that);
    }();
  }
}

o.f1()
// Object
// Object
复制代码

2. The processing method of avoiding this array

map and foreach array of methods, it allows to provide a function as a parameter. This internal function should not use this.

var o = {
  v: 'hello',
  p: [ 'a1', 'a2' ],
  f: function f() {
    this.p.forEach(function (item) {
      console.log(this.v + ' ' + item);
    });
  }
}

o.f()
// undefined a1
// undefined a2
复制代码

In the above code, the callback function in the this foreach method, in fact, is a pointer to the object window, and therefore fail to get the value of ov. Reason to keep this multilayer section is the same, this is not the inner layer directed outward, and the top-level object point.

One way to solve this problem, is the previously mentioned fixed intermediate variable using this.

var o = {
  v: 'hello',
  p: [ 'a1', 'a2' ],
  f: function f() {
    var that = this;
    this.p.forEach(function (item) {
      console.log(that.v+' '+item);
    });
  }
}

o.f()
// hello a1
// hello a2
复制代码

Another method is to foreach this method as the second parameter, which is fixed to the operating environment.

var o = {
  v: 'hello',
  p: [ 'a1', 'a2' ],
  f: function f() {
    this.p.forEach(function (item) {
      console.log(this.v + ' ' + item);
    }, this);
  }
}

o.f()
// hello a1
// hello a2
复制代码

3. Avoid the callback function of this

Callback function tend to change this point, it is best avoided.

var o = new Object();
o.f = function () {
  console.log(this === o);
}

// jQuery 的写法
$('#button').on('click', o.f);
复制代码

Binding of this method

1. call

The method of function call instance, this may be directed inside the specified function (i.e., where the scope of a function performed), then the specified scope, the function call.

var obj = {};

var f = function () {
  return this;
};

f() === window // true
f.call(obj) === obj // true
复制代码

Parameter method call, it should be an object. If the argument is null, null and undefined, the global object is passed in default.

var n = 123;
var obj = { n: 456 };

function a() {
  console.log(this.n);
}

a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
a.call(window) // 123
a.call(obj) // 456
复制代码

If the argument is a call method original value, then the primitive value is automatically transferred to the corresponding object to be packaged, then the incoming call method.

var f = function () {
  return this;
};

f.call(5)
// Number {[[PrimitiveValue]]: 5}
复制代码

The method can also accept a plurality of call parameters.

func.call(thisValue, arg1, arg2, ...)
复制代码

That object call first argument is this to be pointing to the back of the parameters is required when the function call parameters.

function add(a, b) {
  return a + b;
}

add.call(this, 1, 2) // 3
复制代码

Application call a method of native method calls the object.

var obj = {};
obj.hasOwnProperty('toString') // false

// 覆盖掉继承的 hasOwnProperty 方法
obj.hasOwnProperty = function () {
  return true;
};
obj.hasOwnProperty('toString') // true

Object.prototype.hasOwnProperty.call(obj, 'toString') // false
复制代码

2. apply

The method of action and apply a method similar to call, this point is also changed, and then calls the function. The only difference is that it receives an array as a function of the parameter performed, using the following format.

func.apply(thisValue, [arg1, arg2, ...])
复制代码

The first argument apply this method is that the object to be pointed, if set to null or undefined, the equivalent to specifying the global object. The second parameter is an array, all members of the array as a parameter in turn, passed the original function. Parameters of the original function, one must add a call process, but apply method, it must be added in the form of an array.

function f(x, y){
  console.log(x + y);
}

f.call(null, 1, 1) // 2
f.apply(null, [1, 1]) // 2
复制代码

(1) find the maximum element of the array

JavaScript does not provide a function to find the largest element of the array. The method and the apply Math.max incorporated methods, it can be returned to the largest element of the array.

var a = [10, 2, 4, 15, 9];
Math.max.apply(null, a) // 15
复制代码

(2) the array element becomes empty undefined

Apply method by using the empty Array constructor element array becomes undefined.

Array.apply(null, ['a', ,'b'])
// [ 'a', undefined, 'b' ]
复制代码

(3) Conversion of the array-like objects

Further, by using an array of object slice method, a similar array of objects (such as the arguments object) into a real array.

Array.prototype.slice.apply({0: 1, length: 1}) // [1]
Array.prototype.slice.apply({0: 1}) // []
Array.prototype.slice.apply({0: 1, length: 2}) // [1, undefined]
Array.prototype.slice.apply({length: 1}) // [undefined]
复制代码

(4) binding callback object

The previous example button click event, can be rewritten as follows.

var o = new Object();

o.f = function () {
  console.log(this === o);
}

var f = function (){
  o.f.apply(o);
  // 或者 o.f.call(o);
};

// jQuery 的写法
$('#button').on('click', f);
复制代码

3. bind

bind method is used to bind this function in vivo to an object, and then returns a new function.

var d = new Date();
d.getTime() // 1481869925657

var print = d.getTime;
print() // Uncaught TypeError: this is not a Date object.
复制代码

bind ways to solve this problem.

var print = d.getTime.bind(d);
print() // 1481869925657
复制代码

The method is to bind the parameter to be bound to this subject, the following is an example of a clearer.

var counter = {
  count: 0,
  inc: function () {
    this.count++;
  }
};

var func = counter.inc.bind(counter);
func();
counter.count // 1
复制代码

Other objects bound to this are possible.

var counter = {
  count: 0,
  inc: function () {
    this.count++;
  }
};

var obj = {
  count: 100
};
var func = counter.inc.bind(obj);
func();
obj.count // 101
复制代码

bind can also accept more parameters, these parameters will bind the parameters of the original function.

var add = function (x, y) {
  return x * this.m + y * this.n;
}

var obj = {
  m: 2,
  n: 2
};

var newAdd = add.bind(obj, 5);
newAdd(5) // 20
复制代码

If the first argument to the bind method is null or undefined, equal to bind to this global object, this points to the function is the top-level objects (browser window).

function add(x, y) {
  return x + y;
}

var plus5 = add.bind(null, 5);
plus5(10) // 15
复制代码

There are some bind method to use and pay attention.

(1) each time a new function returns

Each time you run the bind method, it returns a new function, which can cause problems. For example, monitor the event, it can not be written as follows.

element.addEventListener('click', o.m.bind(o));
复制代码

The above code, click the event bind method bind an anonymous function generated. This will not lead to unbind, so the following code is invalid.

element.removeEventListener('click', o.m.bind(o));
复制代码

The correct way is written as follows:

var listener = o.m.bind(o);
element.addEventListener('click', listener);
//  ...
element.removeEventListener('click', listener);
复制代码

(2) in conjunction with the use of callback

JavaScript callback function is one of the most common model, but a common mistake is to include this method as a direct callback function. The solution is to use the bind method, bindings will counter.inc counter.

var counter = {
  count: 0,
  inc: function () {
    'use strict';
    this.count++;
  }
};

function callIt(callback) {
  callback();
}

callIt(counter.inc.bind(counter));
counter.count // 1
复制代码

Another situation is more subtle, is that some methods accept an array as a function parameter. These internal functions this point, you may also be wrong.

var obj = {
  name: '张三',
  times: [1, 2, 3],
  print: function () {
    this.times.forEach(function (n) {
      console.log(this.name);
    });
  }
};

obj.print()
// 没有任何输出
复制代码

Little change it, you can see more clearly.

obj.print = function () {
  this.times.forEach(function (n) {
    console.log(this === window);
  });
};

obj.print()
// true
// true
// true
复制代码

To solve this problem, which are bound by this bind method.

obj.print = function () {
  this.times.forEach(function (n) {
    console.log(this.name);
  }.bind(this));
};

obj.print()
// 张三
// 张三
// 张三
复制代码

(3) Method used in conjunction with call

Using the bind method, you can be rewritten to use some form of native JavaScript method to slice an array of methods, for example.

[1, 2, 3].slice(0, 1) // [1]
// 等同于
Array.prototype.slice.call([1, 2, 3], 0, 1) // [1]
复制代码

call method is essentially a call Function.prototype.call method, so the above expression can be rewritten with the bind method.

var slice = Function.prototype.call.bind(Array.prototype.slice);
slice([1, 2, 3], 0, 1) // [1]
复制代码

Similar notation can also be used for other array method.

var push = Function.prototype.call.bind(Array.prototype.push);
var pop = Function.prototype.call.bind(Array.prototype.pop);

var a = [1 ,2 ,3];
push(a, 4)
a // [1, 2, 3, 4]

pop(a)
a // [1, 2, 3]
复制代码

If further, the Function.prototype.call method to bind to Function.prototype.bind objects, it means calling in the form of bind can also be rewritten.

function f() {
  console.log(this.v);
}

var o = { v: 123 };
var bind = Function.prototype.call.bind(Function.prototype.bind);
bind(f, o)() // 123
复制代码

to sum up

  • Keyword this is a function of the current operating environment
  • Due to changes in the operating environment will function, so this has also been the variability
  • Memory address of the function is independent of the method of the object is only referenced memory address of the function
  • this usage scenarios: global environment, constructors, object methods
  • The object of this method, because of changes in the operating environment, change the point of this
  • And nested callback function this, the window object often point
  • This fixed point of two methods: a fixed intermediate values, binding 2 operating environment.
  • call, apply, bind can be used in this function a fixed point

Description link

Keyword this

Reproduced in: https: //juejin.im/post/5d06180d6fb9a07eab687f6e

Guess you like

Origin blog.csdn.net/weixin_33709364/article/details/93179138