jQuery跨作用域访问变量问题:日历插件方法调用提示未定义
解决跨作用域访问日历插件方法的问题
这个问题我之前也碰到过,核心原因是你的CalendarApp构造函数和实例都被包裹在自执行匿名函数的局部作用域里了,外部(包括其他页面的document.ready代码)根本访问不到它们。而且你原代码里还有个小问题:最后调用$.CalendarApp.init()的时候,$.CalendarApp其实根本不存在,因为你没把构造函数或实例挂载到jQuery的命名空间上。
下面给你几个可行的解决方案,你可以根据自己的项目需求选择:
方案一:将日历实例挂载到jQuery命名空间(推荐)
修改calendar.js的代码,把CalendarApp的实例挂载到jQuery上,这样外部就能直接访问到:
! function($) { "use strict"; var CalendarApp = function() { this.$calendar = $('#calendar'), this.$calendarObj = null }; CalendarApp.prototype.init = function() { // 初始化日历,这里假设calendar()方法返回的实例包含changeDate this.$calendarObj = this.$calendar.calendar(); return this; // 返回实例,方便后续调用 }; // 创建实例并挂载到jQuery命名空间 $.CalendarApp = new CalendarApp(); }(window.jQuery); $(window).on('load', function() { $.CalendarApp.init(); });
然后在另一个页面的document.ready里这样调用:
$(document).ready(function(){ // 注意:window.load比document.ready执行晚,所以要先判断日历是否已初始化 if ($.CalendarApp && $.CalendarApp.$calendarObj) { $.CalendarApp.$calendarObj.changeDate(); } });
方案二:用自定义事件触发(更模块化,不污染全局)
如果不想暴露全局实例,可以通过自定义事件来实现跨作用域调用,这种方式更符合模块化开发的思路:
修改calendar.js:
! function($) { "use strict"; var CalendarApp = function() { this.$calendar = $('#calendar'), this.$calendarObj = null }; CalendarApp.prototype.init = function() { this.$calendarObj = this.$calendar.calendar(); // 监听自定义事件,接收参数并调用方法 $(document).on('calendar.changeDate', (e, targetDate) => { this.$calendarObj.changeDate(targetDate); }); }; const app = new CalendarApp(); $(window).on('load', function() { app.init(); }); }(window.jQuery);
在另一个页面触发事件:
$(document).ready(function(){ // 触发自定义事件,可传递需要的日期参数 $(document).trigger('calendar.changeDate', [new Date()]); });
方案三:暴露为全局变量(简单直接,不推荐大型项目)
如果项目比较小,不介意全局变量,也可以直接把实例挂到window上:
修改calendar.js:
! function($) { "use strict"; window.CalendarApp = function() { this.$calendar = $('#calendar'), this.$calendarObj = null }; window.CalendarApp.prototype.init = function() { this.$calendarObj = this.$calendar.calendar(); return this; }; // 创建全局实例 window.calendarInstance = new window.CalendarApp(); }(window.jQuery); $(window).on('load', function() { window.calendarInstance.init(); });
另一个页面调用:
$(document).ready(function(){ if (window.calendarInstance && window.calendarInstance.$calendarObj) { window.calendarInstance.$calendarObj.changeDate(); } });
额外注意事项
- 确保
calendar.js在另一个页面的脚本之前加载,否则会出现找不到对象的错误。 - 注意
window.load和document.ready的执行顺序:window.load是所有资源加载完成后才触发,而document.ready只要DOM加载完就执行。如果另一个页面的document.ready先跑,日历可能还没初始化,所以一定要加存在性判断,或者把日历的初始化放到document.ready里。
内容的提问来源于stack exchange,提问作者Nimesh




