Preface
I don’t know whether it is accurate to use implicit calls to describe it. Their behavior is always hidden behind it and it shows off from time to time. It seems to be of little effect, but it is still useful to understand it. It is not guaranteed to make great achievements in your use.
The so-called implicit call simply means automatically calling some methods, which can be modified externally like hooks, thereby changing the established behavior.
Below I will list some implicit calls I have seen recently. Examples are all clicks until the end. Welcome to add them
Data type conversion toSting and valueOf
var obj = { a: 1, toString: function () { ('toString') return '2' }, valueOf: function () { ('valueOf') return 3 } } (obj == '2'); //Output 'valueOf' false in turn (String(obj));//Output in turn 'toString' '2'
var obj = { a: 1, toString: function () { ('toString') return '2' }, valueOf: function () { ('valueOf') return {} //Modify to object } } (obj == '2'); //Output 'valueOf' 'toString' true (Number(obj));//Output in turn 'valueOf' 'toString' 2
In the operation of the equality operator, the object will call valueOf first. If the returned value is an object, toString will be called except null, and then the returned value will be compared. The first example is equivalent to 3 == '2' output false. The second example is because the valueOf returns an object, and then executes toString, and finally equivalent to '2' == '2' output true. In the Number and String methods, Number will call valueOf first, and then call toString. The opposite is true in the String method.
In addition to the above two examples, data type conversion also exists in various other operations, such as numerical operations. When referring to reference types, the valueOf or toString methods will be called. As long as it is an object, these two methods will be inherited. We can re-overwrite these two methods, thereby affecting the behavior of data type conversion.
handleEvent in DOM2 event
var eventObj = { a: 1, handleEvent: function (e) { (this, e);//Return eventObj and event objects alert() } } ('click', eventObj)
You read that right. The second parameter of addEventListener can also be an object in addition to the function. After the event is triggered, the handleEvent method of the object will be executed. This point to eventObj when the method is executed. You can bind the data you want to pass in to eventObj object.
JSON Object toJSON
var Obj = { a: 10, toJSON: function () { return { a: 1, b: function () { }, c: NaN, d: -Infinity, e: Infinity, f: /\d/, g: new Error(), h: new Date(), i: undefined, } } } ((Obj)); //{"a":1,"c":null,"d":null,"e":null,"f":{},"g":{},"h":"2018-02-09T19:29:13.828Z"}
If the object passed into the stringify method of JSON has a toJSON method, the object executed by the method will be converted to the object returned after execution toJSON. One thing to note is that, as shown in the following code
var Obj1 = { a: 10, toJSON: function () { (this === Obj1);//true return this } } ((Obj1));//{"a":10}
var Obj2 = { a: 10, toJSON: function () { (this === Obj2);//true return { a: this } } } ((Obj2));//Report an error Maximum call stack size exceeded
If the above statement is obviously what we expect, but when there is no error in return this directly, you might as well make a bold guess about the internal comparison of the object returned by toJSON and the original object. If it is equal, use the original object directly
The promise object then
var obj = { then: function (resolve, reject) { setTimeout(function () { resolve(1000); }, 1000) } } (obj).then(function (data) { (data);// Delay is about 1 second and output is 1000 })
When a method is passed into an object, if there is then method, it will immediately execute the then method, which is equivalent to putting the method into a new promise. In addition to this behavior, there is also this behavior.
var timePromise = function (time) { return new Promise(function (resolve) { setTimeout(function () { resolve(time); }, time) }) } var timePromise1 = timePromise(1000); var timePromise2 = timePromise(2000); var timePromise3 = timePromise(3000); = function (resolve) { setTimeout(function () { resolve(4000); }, 4000) } ([timePromise1, timePromise2, timePromise3]).then(function (time) { (time);// Wait for about 4 seconds to output 4000 })
Object property accessors get and set
var obj = { _age: 100, get age() { return this._age < 18 ? this._age : 18; }, set age(value) { this._age = value; (`Age set to${value}age`); } } = 1000; //Age is set to 1000 years old = 200; //Age is set to 200 years old ();// 18 = 2; /////Age is set to 2 years old (); // 2
You can see that no matter how much the age is set, my age is 18 years old or under. When performing property access, I actually call the corresponding get set function of the object attribute. In addition to the above writing method, there are also the following writing method.
var input = ('input'); var span = ('span'); (input); (span); var obj = { _age:'' } var obj = (obj, 'age', { get: function () { return this._age; }, set: function (value) { this._age = value; = value; = value; } }); = function (e) { if ( === 37 || === 39) { return; } = }
Now the value of input and the attribute value of span are bound together
Traverser interface
var arr = [ 1, 2 , 3]; arr[] = function () { const self = this; let index = 0; return { next () { if(index < ) { return { value: self[index] ** self[index++], done: false } } else { return { value: undefined, done: true } } } } } ([...arr, 4]);//Return [1, 4, 27, 4] for(let value of arr) { (value); //Return 1 4 27 in turn }
You can see that whenever you call the extension operator or use the for...of loop to traverse the object, you will call the object's traversal interface. For example, Array, String, Map, Set, TypedArray and some class array objects such as arguments. NodeList natively has the traversal interface, while ordinary objects do not deploy this interface. If you want the object to use the extension operator or for...of loop, you can add this method to the object, or you can rewrite the method on the object that originally has the interface to change its behavior.
at last
I have thought of so much for the time being. Everyone is welcome to add it. Thank you for your support.