作为一名前端小白,不知道大家是否遇到和我一样的问题。看了一道面试题的解析,当时觉得会了,可是过两天以后再看又不会了;盲目追求各种新技术,感觉什么都会点,但是一上手就不行了... 痛定思痛后,我终于认识到了问题所在,开始专注于基本功的修炼。近半年来通读了(其实是囫囵吞枣)《JavaScript高级程序设计》、《你不知道的JavaScript上、中、下》等书籍,本系列文章是我读书过程中对知识点的一些总结。喜欢的同学记得帮我点个赞😁。
懂王系列(一)之彻底搞懂JavaScript函数执行机制
懂王系列(二)之彻底搞懂JavaScript作用域
懂王系列(三)之彻底搞懂JavaScript对象
懂王系列(四)之彻底搞懂JavaScript类
懂王系列(五)之彻底搞懂JavaScript原型
懂王系列(六)之彻底搞懂JavaScript中的this
懂王系列(七)之彻底搞懂JavaScript数据类型
懂王系列(八)之彻底搞懂JavaScript语句
懂王系列(九)之彻底搞定JavaScript类型转换
1. JavaScript中的“类”
由于类是一种设计模式,所以 JavaScript 用一些方法)近似实现了类的功能法。
2. 类的机制
2.1 构造函数
类实例是由一个特殊的类方法构造的,这个方法名通常和类名相同,被称为构造函数。这个方法的任务就是初始化实例需要的所有信息
class CoolGuy {
specialTrick = nothing
CoolGuy( trick ) {
specialTrick = trick
}
showOff() {
output( "Here's my trick: ", specialTrick )
}
}
CoolGuy 类有一个 CoolGuy() 构造函数,执行 new CoolGuy() 时实际上调用的就是它。构造函数会返回一个对象(也就是类的一个实例),之后我们可以在这个对象上调用showOff() 方法,来输出指定 CoolGuy 的特长
类构造函数属于类,而且通常和类同名。此外,构造函数大多需要用 new 来调,这样语言引擎才知道你想要构造一个新的类实例
2.2 继承
在面向类的语言中,你可以先定义一个类,然后定义一个继承前者的类。后者通常被称为“子类”,前者通常被称为“父类”。
子类是一个单独的个体。虽然子类会继承父类许多特性,但是他是一个独一无二的存在。二者之间没有直接的联系。
定义好一个子类之后,相对于父类来说它就是一个独立并且完全不同的类。子类会包含父类行为的原始副本,但是也可以重写所有继承的行为甚至定义新行为。
3. 多态
在继承链的不同层次中一个方法名可以被多次定义,当调用方法时会自动选择合适的定义
3.1 多重继承
有些面向类的语言允许你继承多个“父类”。多重继承意味着所有父类的定义都会被复制到子类中。
从表面上来,对于类来说这似乎是一个非常有用的功能,可以把许多功能组合在一起。然而,这个机制同时也会带来很多复杂的问题。如果两个父类中都定义了 drive() 方法的话,子类引用的是哪个呢?难道每次都需要手动指定具体父类的 drive() 方法吗?这样多态继承的很多优点就不存在了
JavaScript 要简单得多:它本身并不提供“多重继承”功能。许多人认为这是件好事,因为使用多重继承的代价太高。
但是我们可以使用混入来实现多重继承。
4. 混入
4.1 显示混入
// 非常简单的 mixin(..) 例子 :
function mixin( sourceObj, targetObj ) {
for (var key in sourceObj) {
// 只会在不存在的情况下复制
if (!(key in targetObj)) {
targetObj[key] = sourceObj[key];
}
}
return targetObj;
}
使用混入
var Vehicle = {
engines: 1,
ignition: function() {
console.log( "Turning on my engine." );
},
drive: function() {
this.ignition();
console.log( "Steering and moving forward!" );
}
};
var Car = mixin( Vehicle, {
wheels: 4,
drive: function() {
Vehicle.drive.call( this );
console.log(
"Rolling on all " + this.wheels + " wheels!"
);
}
} );
从技术角度来说,函数实际上没有被复制,复制的是函数引用。所以,Car 中的属性 ignition 只是从 Vehicle 中复制过来的对于 ignition() 函数的引用。相反,属性 engines 就是直接从 Vehicle 中复制了值 1
Car 已经有了 drive 属性(函数),所以这个属性引用并没有被 mixin 重写,从而保留了Car 中定义的同名属性,实现了“子类”对“父类”属性的重写
4.2 隐式混入
var Something = {
cool: function() {
this.greeting = "Hello World";
this.count = this.count ? this.count + 1 : 1;
}
};
Something.cool();
Something.greeting; // "Hello World"
Something.count; // 1
var Another = {
cool: function() {
// 隐式把 Something 混入 Another
Something.cool.call( this );
}
};
Another.cool();
Another.greeting; // "Hello World"
Another.count; // 1 (count 不是共享状态)
在构造函数调用或者方法调用中使用 Something.cool.call( this )把 Something 的行为“混入”到了 Another 中
虽然这类技术利用了 this 的重新绑定功能,但是 Something.cool.call( this ) 仍然无法变成相对(而且更灵活的)引用,所以使用时千万要小心。通常来说,尽量避免使用这样的结构,以保证代码的整洁和可维护性。