jQuery.val 如何能够绕过值 属性 上的 get/set 函数?
How is jQuery.val able to bypass the get/set functions on the value property?
const { get, set } = Object.getOwnPropertyDescriptor(HTMLSelectElement.prototype, 'value');
let countryElement = $('select[name="country_id"]').get(0);
Object.defineProperty(countryElement, 'value', {
get() {
console.log('calling get');
return get.call(this);
},
set(newVal) {
console.log('New value assigned to selected[name="country_id"]: ' + newVal);
return set.call(this, newVal);
}
});
如果我运行 document.querySelector('select[name="country_id"]').value = 'CA'
则调用设置函数。如果我 运行 $('select[name="country_id"]').val('CA')
不会调用设置函数。
我的目标是观察由我无法更改的第三方 JS 工具执行的表单字段的更改。但是,我无法让它工作。当我深入研究这个问题时,我发现我什至可以 jQuery 来更改值而无需通过我的 set 函数。但我不明白这怎么可能。
查看 jQuery 的源代码。 val
确实如此,最终:
hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
// If set returns undefined, fall back to normal setting
if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
this.value = val;
}
所以它访问并调用了 jQuery.valHooks.select.set
,在源代码的其他地方确实如此:
set: function( elem, value ) {
var optionSet, option,
options = elem.options,
values = jQuery.makeArray( value ),
i = options.length;
while ( i-- ) {
option = options[ i ];
/* eslint-disable no-cond-assign */
if ( option.selected =
jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
) {
optionSet = true;
}
/* eslint-enable no-cond-assign */
}
// Force browsers to behave consistently when non-matching value is set
if ( !optionSet ) {
elem.selectedIndex = -1;
}
return values;
}
它遍历选项。上面函数中唯一真正改变 DOM 的行是:
option.selected = jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
或
elem.selectedIndex = -1;
所以,jQuery 根本没有调用值 setter。您可以模拟它在做什么,并通过分配给您想要 selected.
的选项的 selected
属性 来设置 <select>
的值
const { get, set } = Object.getOwnPropertyDescriptor(HTMLSelectElement.prototype, 'value');
let countryElement = $('select[name="country_id"]').get(0);
Object.defineProperty(countryElement, 'value', {
get() {
console.log('calling get');
return get.call(this);
},
set(newVal) {
console.log('New value assigned to selected[name="country_id"]: ' + newVal);
return set.call(this, newVal);
}
});
countryElement.children[1].selected = true;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select name="country_id">
<option>foo</option>
<option value="CA">CA</option>
</select>
My goal is to observe changes to a form field which are executed by a third party JS tool which I cannot change.
有多种方法可以更改 <select>
值,其中包括 .value
、设置选项的 .selected
属性 以及设置 [= select 的 23=]。您需要实施所有这些才能可靠地执行您想要的操作。
const { get, set } = Object.getOwnPropertyDescriptor(HTMLSelectElement.prototype, 'value');
let countryElement = $('select[name="country_id"]').get(0);
Object.defineProperty(countryElement, 'value', {
get() {
console.log('calling get');
return get.call(this);
},
set(newVal) {
console.log('New value assigned to selected[name="country_id"]: ' + newVal);
return set.call(this, newVal);
}
});
如果我运行 document.querySelector('select[name="country_id"]').value = 'CA'
则调用设置函数。如果我 运行 $('select[name="country_id"]').val('CA')
不会调用设置函数。
我的目标是观察由我无法更改的第三方 JS 工具执行的表单字段的更改。但是,我无法让它工作。当我深入研究这个问题时,我发现我什至可以 jQuery 来更改值而无需通过我的 set 函数。但我不明白这怎么可能。
查看 jQuery 的源代码。 val
确实如此,最终:
hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
// If set returns undefined, fall back to normal setting
if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
this.value = val;
}
所以它访问并调用了 jQuery.valHooks.select.set
,在源代码的其他地方确实如此:
set: function( elem, value ) {
var optionSet, option,
options = elem.options,
values = jQuery.makeArray( value ),
i = options.length;
while ( i-- ) {
option = options[ i ];
/* eslint-disable no-cond-assign */
if ( option.selected =
jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
) {
optionSet = true;
}
/* eslint-enable no-cond-assign */
}
// Force browsers to behave consistently when non-matching value is set
if ( !optionSet ) {
elem.selectedIndex = -1;
}
return values;
}
它遍历选项。上面函数中唯一真正改变 DOM 的行是:
option.selected = jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
或
elem.selectedIndex = -1;
所以,jQuery 根本没有调用值 setter。您可以模拟它在做什么,并通过分配给您想要 selected.
的选项的selected
属性 来设置 <select>
的值
const { get, set } = Object.getOwnPropertyDescriptor(HTMLSelectElement.prototype, 'value');
let countryElement = $('select[name="country_id"]').get(0);
Object.defineProperty(countryElement, 'value', {
get() {
console.log('calling get');
return get.call(this);
},
set(newVal) {
console.log('New value assigned to selected[name="country_id"]: ' + newVal);
return set.call(this, newVal);
}
});
countryElement.children[1].selected = true;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select name="country_id">
<option>foo</option>
<option value="CA">CA</option>
</select>
My goal is to observe changes to a form field which are executed by a third party JS tool which I cannot change.
有多种方法可以更改 <select>
值,其中包括 .value
、设置选项的 .selected
属性 以及设置 [= select 的 23=]。您需要实施所有这些才能可靠地执行您想要的操作。