2020 年阿里前端技术专家磐冲一篇《我在阿里招前端,我该怎么帮你?》可谓是火了半个前端圈子 原文链接。
磐冲对职级在技术层面上的要求描述的条理清晰,感兴趣的同学自行打开原文链接查看。这里从文中的 JavaScript 技术开始,同大家一起学习进步。首先看看磐冲是如何“翻译”简历中的“熟练掌握 JavaScript”
熟练掌握 JavaScript。
初级:
- JavaScript 各种概念都得了解,《JavaScript 语言精粹》这本书的目录都得有概念,并且这些核心点都能脱口而出是什么。这里列举一些做参考:
- 知道组合寄生继承,知道 class 继承。
- 知道怎么创建类 function + class。
- 知道闭包在实际场景中怎么用,常见的坑。
- 知道模块是什么,怎么用。
- 知道 event loop 是什么,能举例说明 event loop 怎么影响平时的编码。
- 掌握基础数据结构,比如堆、栈、树,并了解这些数据结构计算机基础中的作用。
- 知道 ES6 数组相关方法,比如 forEach,map,reduce。
中级:
- 知道 class 继承与组合寄生继承的差别,并能举例说明。
- 知道 event loop 原理,知道宏微任务,并且能从个人理解层面说出为什么要区分。知道 node 和浏览器在实现 loop 时候的差别。
- 能将继承、作用域、闭包、模块这些概念融汇贯通,并且结合实际例子说明这几个概念怎样结合在一起。
- 能脱口而出 2 种以上设计模式的核心思想,并结合 js 语言特性举例或口喷基础实现。
- 掌握一些基础算法核心思想或简单算法问题,比如排序,大数相加。
不要有太大压力,首先以上内容仅针对阿里磐冲他们部门,其次,慌的一部分原因是因为 JD 描述基础名词比较多,建议看起来吃力的小伙伴,先火速补一补基础知识,推荐两本书,一本是磐冲提到的《JavaScript 语言精粹》,另一本是《JavaScript 忍者秘籍》。
看到这里,已完成 ⅓ 的阅读。
深入理解继承
老生常谈:原型与原型链
首先,在 js 中每个对象都含有原型的引用,每个对象的原型也可以拥有一个原型,以此类推便形成了原型链。查找特定属性将会被委托到整个原型链上,当没有更多原型可以查找时,才会停止查找。
因此原型链在 ECMAScript 规范中作为实现继承的主要方式。但这种方式缺陷也十分明显:
- 实例共享引用类型,易造成使用修改的混乱
- 创建子类时无法传递参数。
使用构造函数
function Foo () {};
Foo.prototype.bar = function() {
return true;
};
const foo = new Foo();
使用 new 操作符调用该函数,便是作为构造器进行调用,创建了新的分配对象并将及设置为函数的上下文(可通过 this 访问)new 返回的结果是这个新对象的引用。
缺陷
- 所有方法都在构造函数中定义,无法做到函数复用,且使用超类定义方法时,该方法对子类也不可见。
原型链与构造函数组合继承
主要思路:通过原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承,请看以下代码:
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name)
}
function SuperType(name, age) {
// 继承属性
SuperType.call(this, name);
// 先继承,后定义新的自定义属性
this.age = age
}
// 继承方法
SuperType.prototype = new SuperType();
// 先继承,后定义新的自定义属性
Object.defineProperty(
SubType.prototype,
"constructor", {
enumerable: false,
value: SubType
});
SubType.prototype.sayAge = function(){
console.log(this.age);
}
var instance1 = new SubType("james",9);
instance1.colors.push("black");
console.log(instance1.colors);
instance1.sayName();
instance1.sayAge();
优点
- instanceOf() / isPrototypeOf() 可识别基于组合继承创建的对象。
缺点
- 调用两次超类构造函数:①创建子类原型时,②子类构造函数内部。子类最终包含超类对象的全部实例属性。
原型式继承
在不创建自定义类型的情况下,借助原型链,基于已有对象创建新对象:传入一个对象,返回一个原型对象为该对象的新对象。(so many 对象可你还是个单身狗。)
原理代码
function object(o) {
function F () {};
F.prototype = o;
return new F();
}
实际可通过 Object.create() 方法规范原型式继承。
var person1 = {
name: 'a',
friends: ['b', 'c'],
}
var person2 = Object.create(person1, {
name: {
value: 'Luuu'
}
})
person2.friends.push('d')
console.log(person2.name) // luuu
var person3 = Object.create(person1)
person3.name = 'xx'
person3.friends.push('e')
console.log(person3.friends) // b, c, d, e
优点
- 可基于一个对象实现继承,不必创建构造函数
缺点
- 与原型链缺点一致,所有实例会共享对象引用中属性值。
看到这里,已完成 ⅔ 的阅读。
寄生式继承
实现思路与工厂设计模式类似,先创建一个仅用于封装继承过程的函数,在该函数内部用某种方式增强对象,并返回。相当于原型式继承寄生于函数中,故如此命名。
function object(o) {
function F () {}
F.prototype = o
return new F()
}
function createFoo(o) {
// 通过调用函数创建一个新对象
var clone = object(o)
// 用某种方式增强对象
clone.hello = function () {
alert('hi!')
}
// 返回该对象
return clone
}
寄生组合式继承
通过借用构造函数来继承属性;
通过原型链的形式继承方法;
思路是:为了指定子类原型,而调用超类构造函数。使用寄生式继承来获得超类原型,再讲结果指定给子类原型。
function object(o){
function F(){}
F.prototype = o;
return new F();
}
function intProto(sub, super){
//创建对象
var proto = object(super.prototype);
//增强对象
proto.constructor = sub;
//指定对象
sub.prototype = proto;
}
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name, age){
// 继承属性
SuperType.call(this, name);
this.age = age;
}
intProto(SubType, SuperType);
// 继承原型方法
SubType.prototype.sayAge = function(){
alert(this.age);
};
使用关键字 class
ES6 引入的关键字 class,虽然提供了更优雅的实现继承的方式,本质仍是基于原型的实现的语法糖。
class Foo {
constructor(name) {
this.name = name;
}
swingSord() {
return true;
}
}
var foo = new Foo('luuu')