JS调用类方法报错怎么办?常见错误及解决方法汇总
刚学JS面向对象编程时,你是不是总遇到这样的场景——明明跟着教程写的类方法,一运行就报"xxx is not a function"?就像新手如何快速涨粉总卡在内容创作上,咱们学JS的拦路虎就是这些莫名其妙的报错。今天咱们就扒开这些错误的外衣,看看它们到底在闹什么妖!
(抓头发)先来看这个最气人的报错:"Uncaught TypeError: Cannot read property 'method' of undefined"。这时候你的代码可能是这样的:
class Cat {
meow() {
console.log('喵');
}
}
// 错误写法
Cat.meow(); // 直接拿模具当成品用
??三大典型翻车姿势??:
- 把类当对象直接调用方法(就像用模具喝咖啡)
- 在回调函数里丢了this(比如事件监听时)
- 用了箭头函数反而搞乱this指向
别急着砸键盘,咱们一个个来治。先说第一个问题,正确的打开方式应该是:
const myCat = new Cat();
myCat.meow(); // 这才是正确姿势
那第二个坑呢?看这段代码:
class Counter {
constructor() {
this.count = 0;
document.querySelector('button').addEventListener('click', this.increment);
}
increment() {
this.count++; // 这里this会变成button元素!
}
}
??解决方法三连击??:
- 用bind强行绑定:addEventListener('click', this.increment.bind(this))
- 箭头函数大法:在constructor里写this.increment = () => { ... }
- 最新提案的类字段语法:increment = () => { ... }
最近有学员问我:"为什么用React类组件时方法总报错?" 这个问题特别典型,咱们看个对比案例:
错误写法 | 正确写法 |
---|---|
handleClick() { ... } | handleClick = () => { ... } |
不绑定直接传方法给onClick | 在constructor里bind(this) |
第三个大坑是关于继承的,看这个父子类相爱相杀的例子:
class Animal {
constructor(name) {
this.name = name;
}
}
class Dog extends Animal {
bark() {
console.log(${super.name}在叫
); // 这里会报undefined!
}
}
??这里有两个知识点要考??:
- super只能调用父类的构造函数和方法,不能直接访问属性
- 子类必须在constructor里先调用super()
正确的打开方式应该是:
class Dog extends Animal {
constructor(name) {
super(name); // 必须先喂饱父类
}
bark() {
console.log(${this.name}在叫
); // 这时候才有name属性
}
}
移动端开发有个常见坑位——在小程序生命周期里调用方法。比如微信小程序里这样写:
Page({
data: { count: 0 },
onLoad() {
setTimeout(this.increment, 1000); // 这里直接报错!
},
increment() {
this.setData({ count: this.data.count +1 })
}
})
??解决方案三选一??:
- 改用箭头函数:increment = () => { ... }
- 闭包大法:setTimeout(() => this.increment(), 1000)
- 魔改bind:setTimeout(this.increment.bind(this), 1000)
有同学举手问:"为什么用Vue的时候类方法总丢失this?" 这个问题和框架特性有关。在Vue组件里挂载类方法要这样操作:
methods: {
...new MyClass().methods // 用展开运算符把类方法挂进来
}
还有个冷门但致命的错误——异步函数里的this丢失。看这段代码:
class API {
async fetchData() {
const result = await axios.get('/api');
this.process(result); // 这里可能变成undefined!
}
}
??保命技巧??:
- 在async函数开头先const self = this
- 改用箭头函数:fetchData = async () => { ... }
- 使用bind绑定:constructor里写this.fetchData = this.fetchData.bind(this)
小编观点:遇到报错千万别慌,重点看错误信息里的行号。实在看不懂就把this打印出来看看是什么妖魔鬼怪。记住,多用console.log调试,少砸键盘,毕竟换键盘的钱够买好几本编程书了。最后说句大实话——类方法报错十有八九都是this在搞事情,把这祖宗伺候好了代码就能跑!
本文由嘻道妙招独家原创,未经允许,严禁转载