link1644 link1645 link1646 link1647 link1648 link1649 link1650 link1651 link1652 link1653 link1654 link1655 link1656 link1657 link1658 link1659 link1660 link1661 link1662 link1663 link1664 link1665 link1666 link1667 link1668 link1669 link1670 link1671 link1672 link1673 link1674 link1675 link1676 link1677 link1678 link1679 link1680 link1681 link1682 link1683 link1684 link1685 link1686 link1687 link1688 link1689 link1690 link1691 link1692 link1693 link1694 link1695 link1696 link1697 link1698 link1699 link1700 link1701 link1702 link1703 link1704 link1705 link1706 link1707 link1708 link1709 link1710 link1711 link1712 link1713 link1714 link1715 link1716 link1717 link1718 link1719 link1720 link1721 link1722 link1723 link1724 link1725 link1726 link1727 link1728 link1729 link1730 link1731 link1732 link1733 link1734 link1735 link1736 link1737 link1738 link1739 link1740 link1741 link1742 link1743 link1744 link1745 link1746 link1747 link1748 link1749 link1750 link1751 link1752 link1753 link1754 link1755 link1756 link1757 link1758 link1759 link1760 link1761 link1762 link1763 link1764 link1765 link1766 link1767 link1768 link1769 link1770 link1771 link1772 link1773 link1774 link1775 link1776 link1777 link1778 link1779 link1780

[Vue.js] Vue watch providing wrong this context Subscribe to RSS

when using lodash to debounce a function call but when wondering why my this value is not inheriting the scope like I expect.

These are are the relevant parts of my vue.js component.

import debounce from ‘lodash/debounce’;

watch: {
query: debounce(() => {
this.autocomplete();
}, 200, {
leading: false,
trailing: true
}),

The above case does not work because my this value does not point to the vue.js component but rather shows an Object like this:

Object
__esModule: true
default: Object
__proto: Object

Isn’t my arrow syntax suppose to inherit the context of this?

The following seem to works fine:

query: debounce(function test() {
this.autocomplete();
}, 200, {
leading: false,
trailing: true
})

There is probably an easy answer for this but when hoping someone can help me out here.

Solution :

This is only an additional answer to explain the misunderstanding of this in arrow functions.

How does this work in arrow functions?

this in lexical functions always refers to the surrounding scope. That can either be:

The nearest surrounding function
The nearest surrounding module
The global scope

If we have a look at the code, and we assume you’re using ES6 modules (judging from the import/export statements):

import debounce from ‘lodash/debounce’;

export default {
watch: {
query: debounce(() => {
this.autocomplete();
}, 200, {
leading: false,
trailing: true
}),
}
};

Let’s go through the list:

1. The nearest surrounding function

There is no surrounding function for the arrow function. An example would be:

var obj = {
a: function() {
return () => {
console.log(this);
}
}
};

obj.a()(); // `this` refers to `obj`, because `this` refers to `obj` in the surrounding function `a`

2. The nearest surrounding module

Since we are in a (fake) module in this case, this is defined in the module scope as pseudo module object (probably a babel or webpack object?).

Object
__esModule: true
default: Object
__proto: Object

It seems because vue.js binds these properties, methods and events by default

That’s true and it’s a very useful feature of vue. But it doesn’t help us in this case, because this cannot be overridden in an arrow function, it always refers to the surrounding scope.

Have a look at the following link for a deeper understanding of arrow functions: http://exploringjs.com/es6/ch\_arrow-functions.html#\_variables-that-are-lexical-in-arrow-functions

Solution 2:

See https://vuejs.org/v2/guide/instance.html#Properties-and-Methods

Dont use arrow functions on an instance property or callback (e.g. vm.$watch(‘a’, newVal => this.myMethod())). As arrow functions are bound to the parent context, this will not be the vue.js instance as youd expect and this.myMethod will be undefined.

As the same limitation applies to watchers, you have to use something like this:

watch: {
query: function() {
return debounce(() => {
this.autocomplete();
},
200,
{
leading: false,
trailing: true
});
}
}