Angular4继承场景报错:无法设置undefined的color属性及name属性赋值失败
Hey,这两个都是Angular 4里很常见的属性赋值坑,我帮你逐个分析解决:
问题1:Cannot set property 'color' of undefined
这个错误的本质很简单:你试图给一个还没初始化的对象的属性赋值。举个典型的错误场景:
export class MyComponent { // 只做了类型声明,但没有给styleConfig赋值为实际的对象 styleConfig: { color?: string }; ngOnInit() { // 此时styleConfig是undefined,自然没法设置它的color属性 this.styleConfig.color = 'blue'; } }
解决方案
有几种简单的修复方式,选适合你的场景:
声明时直接初始化对象:最省事的方式,直接给默认值
styleConfig: { color?: string } = {}; // 初始化为空对象赋值前先判断并初始化:适合对象可能在其他地方被初始化的场景
ngOnInit() { // 先确保styleConfig是一个对象,再赋值 this.styleConfig = this.styleConfig || {}; this.styleConfig.color = 'blue'; }复杂对象用接口+构造函数初始化:如果对象结构复杂,建议用接口规范类型,然后在构造函数里初始化
interface StyleConfig { color: string; fontSize?: number; } export class MyComponent { styleConfig: StyleConfig; constructor() { // 构造函数里初始化完整对象 this.styleConfig = { color: '#333' }; } }
问题2:继承ClassB的ClassA调用search方法时设置name属性报错
这个问题要分几种常见情况来排查,都是继承和this指向的典型问题:
情况1:子类没调用父类构造函数super()
Angular里的类(不管是组件还是普通类)继承时,子类的构造函数必须第一行就调用super(),否则父类的属性上下文不会被初始化,直接设置this.name就会报错。比如错误写法:
class ClassB { name: string; } class ClassA extends ClassB { constructor() { // 没调用super(),父类的name属性所在的实例上下文没初始化 this.name = 'initial'; } search() { this.name = 'search result'; // 这里会报错 } }
修复方式
在子类构造函数第一行调用super():
class ClassA extends ClassB { constructor() { super(); // 先初始化父类上下文 this.name = 'initial'; } search() { this.name = 'search result'; // 正常赋值 } }
情况2:search方法里的this指向不对
如果search方法里有异步操作(比如setTimeout、HTTP请求)或者作为回调函数使用,很容易出现this指向不是ClassA实例的情况,此时设置this.name就会报错。比如:
class ClassA extends ClassB { search() { // 普通函数回调里的this指向全局对象(浏览器里是window),不是ClassA实例 setTimeout(function() { this.name = 'timeout result'; }, 1000); } }
修复方式
有两种常用的绑定this的方法:
用箭头函数回调:箭头函数会自动捕获外部的
this(也就是ClassA实例)search() { setTimeout(() => { this.name = 'timeout result'; // 现在this指向ClassA实例 }, 1000); }构造函数里绑定方法:把
search方法的this永久绑定到当前实例class ClassA extends ClassB { constructor() { super(); // 绑定this到实例,之后不管怎么调用search,this都是当前实例 this.search = this.search.bind(this); } search() { setTimeout(function() { this.name = 'timeout result'; }, 1000); } }
情况3:父类的name属性是private修饰
如果ClassB里的name属性用了private修饰,子类ClassA是无法直接访问这个属性的,设置时会报错:
class ClassB { private name: string; // private属性只能在ClassB内部访问 } class ClassA extends ClassB { search() { this.name = 'test'; // 报错:属性'name'是私有的,只能在'ClassB'中访问 } }
修复方式
把父类的name属性改成protected(允许子类访问)或者public(对外公开):
// 用protected,子类可访问,外部不可直接访问 class ClassB { protected name: string; } // 或者用public,所有地方都能访问 class ClassB { public name: string; }
内容的提问来源于stack exchange,提问作者YK mar
相关产品推荐
相关产品推荐

