JS原型相关知识点,阿里P8大佬亲自讲解

  • __proto__

  • prototype

  • constructor

  • typeof && instanceof 原理浅析

    • typeof 基本用法
  • typeof 原理浅析

  • instanceof 基本用法

  • instanceof 原理浅析

  • ES5 中的继承实现方式

    • new 手写版本一
  • new 手写版本二

  • new 关键字

  • 类式继承

  • 构造函数继承

  • 组合式继承

  • 原型式继承

  • 寄生式继承

  • 寄生组合式继承

  • ES6 类的实现原理

    • _inherits
  • _possibleConstructorReturn

  • 基础类

  • 添加属性

  • 添加方法

  • extend 关键字

原型一把梭


这。。。说是最基础没人反驳吧,说没有用有人反驳吧,说很多人到现在没梳理清楚没人反驳吧!OK~ 为什么文章那么多,你却还没有弄明白?

在概念梳理之前,我们还是放一张老掉牙所谓的经典神图:

  • function Foo 就是一个方法,比如JavaScript 中内置的 ArrayString 等

  • function Object 就是一个 Object

  • function Function 就是 Function

  • 以上都是 function,所以 __proto__都是Function.prototype

  • 再次强调,String、Array、Number、Function、Object都是 function

老铁,如果对这张图已非常清晰,那么可直接跳过此章节

老规矩,我们直接来梳理概念。

函数对象和普通对象

老话说,万物皆对象。而我们都知道在 JavaScript 中,创建对象有好几种方式,比如对象字面量,或者直接通过构造函数 new 一个对象出来:

暂且我们先不管上面的代码有什么意义。至少,我们能看出,都是对象,却存在着差异性

其实在 JavaScript 中,我们将对象分为函数对象和普通对象。所谓的函数对象,其实就是 JavaScript 的用函数来模拟的类实现。JavaScript 中的 Object 和 Function 就是典型的函数对象。

关于函数对象和普通对象,最直观的感受就是。。。咱直接看代码:

function fun1(){};

const fun2 = function(){};

const fun3 = new Function(‘name’,‘console.log(name)’);

const obj1 = {};

const obj2 = new Object();

const obj3 = new fun1();

const obj4 = new new Function();

console.log(typeof Object);//function

console.log(typeof Function);//function

console.log(typeof fun1);//function

console.log(typeof fun2);//function

console.log(typeof fun3);//function

console.log(typeof obj1);//object

console.log(typeof obj2);//object

console.log(typeof obj3);//object

console.log(typeof obj4);//object

不知道大家看到上述代码有没有一些疑惑的地方~别着急,我们一点一点梳理。

上述代码中,obj1obj2obj3obj4都是普通对象,fun1fun2fun3 都是 Function 的实例,也就是函数对象。

所以可以看出,所有 Function 的实例都是函数对象,其他的均为普通对象,其中包括 Function 实例的实例

JavaScript 中万物皆对象,而对象皆出自构造(构造函数)

上图中,你疑惑的点是不是 Function 和 new Function 的关系。其实是这样子的:

Function.proto === Function.prototype//true

__proto__

首先我们需要明确两点:1️⃣__proto__constructor对象独有的。2️⃣prototype属性是函数独有的;

但是在 JavaScript 中,函数也是对象,所以函数也拥有__proto__和 constructor属性。

结合上面我们介绍的 Object 和 Function 的关系,看一下代码和关系图

function Person(){…};

let nealyang = new Person();

proto

再梳理上图关系之前,我们再来讲解下__proto__

__proto__ 的例子,说起来比较复杂,可以说是一个历史问题。

ECMAScript 规范描述 prototype 是一个隐式引用,但之前的一些浏览器,已经私自实现了 __proto__这个属性,使得可以通过 obj.__proto__ 这个显式的属性访问,访问到被定义为隐式属性的 prototype

因此,情况是这样的,ECMAScript 规范说 prototype 应当是一个隐式引用:

  • 通过 Object.getPrototypeOf(obj) 间接访问指定对象的 prototype 对象

  • 通过 Object.setPrototypeOf(obj, anotherObj) 间接设置指定对象的 prototype 对象

  • 部分浏览器提前开了 __proto__ 的口子,使得可以通过 obj.__proto__ 直接访问原型,通过 obj.__proto__ = anotherObj 直接设置原型

  • ECMAScript 2015 规范只好向事实低头,将 __proto__ 属性纳入了规范的一部分

从浏览器的打印结果我们可以看出,上图对象 a 存在一个__proto__属性。而事实上,他只是开发者工具方便开发者查看原型的故意渲染出来的一个虚拟节点。虽然我们可以查看,但实则并不存在该对象上。

__proto__属性既不能被 for in 遍历出来,也不能被 Object.keys(obj) 查找出来。

访问对象的 obj.__proto__ 属性,默认走的是 Object.prototype 对象上 __proto__ 属性的 get/set 方法。

Object.defineProperty(Object.prototype,‘proto’,{

get(){

console.log(‘get’)

}

});

({}).proto;

console.log((new Object()).proto);

关于更多__proto__更深入的介绍,可以参看工业聚大佬的《深入理解 JavaScript 原型》一文。

这里我们需要知道的是,__proto__是对象所独有的,并且__proto__一个对象指向另一个对象,也就是他的原型对象。我们也可以理解为父类对象。它的作用就是当你在访问一个对象属性的时候,如果该对象内部不存在这个属性,那么就回去它的__proto__属性所指向的对象(父类对象)上查找,如果父类对象依旧不存在这个属性,那么就回去其父类的__proto__属性所指向的父类的父类上去查找。以此类推,知道找到 null。而这个查找的过程,也就构成了我们常说的原型链

prototype

object that provides shared properties for other objects

在规范里,prototype 被定义为:给其它对象提供共享属性的对象。prototype 自己也是对象,只是被用以承担某个职能罢了.

所有对象,都可以作为另一个对象的 prototype 来用。

修改__proto__的关系图,我们添加了 prototype,prototype是函数所独有的。**它的作用就是包含可以给特定类型的所有实例提供共享的属性和方法。它的含义就是函数的远行对象,**也就是这个函数所创建的实例的远行对象,正如上图:nealyang.__proto__ === Person.prototype。任何函数在创建的时候,都会默认给该函数添加 prototype 属性.

constructor

constructor属性也是对象所独有的,它是一个对象指向一个函数,这个函数就是该对象的构造函数

注意,每一个对象都有其对应的构造函数,本身或者继承而来。单从constructor这个属性来讲,只有prototype对象才有。每个函数在创建的时候,JavaScript 会同时创建一个该函数对应的prototype对象,而函数创建的对象.__proto__ === 该函数.prototype,该函数.prototype.constructor===该函数本身,故通过函数创建的对象即使自己没有constructor属性,它也能通过__proto__找到对应的constructor,所以任何对象最终都可以找到其对应的构造函数。

唯一特殊的可能就是我开篇抛出来的一个问题。JavaScript 原型的老祖宗:Function。它是它自己的构造函数。所以Function.prototype === Function.__proto

为了直观了解,我们在上面的图中,继续添加上constructor

其中 constructor 属性,虚线表示继承而来的 constructor 属性

__proto__介绍的原型链,我们在图中直观的标出来的话就是如下这个样子

typeof && instanceof 原理


问什么好端端的说原型、说继承会扯到类型判断的原理上来呢。毕竟原理上有一丝的联系,往往面试也是由浅入深、顺藤摸瓜的拧出整个知识面。所以这里我们也简单说一下吧。

typeof

MDN 文档点击这里:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/typeof

基本用法

typeof 的用法相比大家都比较熟悉,一般被用于来判断一个变量的类型。我们可以使用 typeof 来判断numberundefinedsymbolstringfunctionbooleanobject 这七种数据类型。但是遗憾的是,typeof 在判断 object 类型时候,有些许的尴尬。它并不能明确的告诉你,该 object 属于哪一种 object

let s = new String(‘abc’);

typeof s === ‘object’// true

typeof null;//“object”

原理浅析

要想弄明白为什么 typeof 判断 null 为 object,其实需要从js 底层如何存储变量类型来说起。虽然说,这是 JavaScript 设计的一个 bug。

在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null 也因此返回 "object"。曾有一个 ECMAScript 的修复提案(通过选择性加入的方式),但被拒绝了。该提案会导致 typeof null === 'null'

js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息:

  • 1:整数

  • 110:布尔

  • 100:字符串

  • 010:浮点数

  • 000:对象

但是,对于 undefined 和 null 来说,这两个值的信息存储是有点特殊的:

  • null:所有机器码均为0

  • undefined:用 −2^30 整数来表示

所以在用 typeof 来判断变量类型的时候,我们需要注意,最好是用 typeof 来判断基本数据类型(包括symbol),避免对 null 的判断。

typeof 只是咱在讨论原型带出的 instanceof 的附加讨论区

instanceof

object instanceof constructor

instanceof 和 typeof 非常的类似。instanceof 运算符用来检测 constructor.prototype是否存在于参数 object 的原型链上。与 typeof 方法不同的是,instanceof 方法要求开发者明确地确认对象为某特定类型。

基本用法

// 定义构造函数

function C(){}

function D(){}

var o = new C();

o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype

o instanceof D; // false,因为 D.prototype 不在 o 的原型链上

o instanceof Object; // true,因为 Object.prototype.isPrototypeOf(o) 返回 true

C.prototype instanceof Object // true,同上

C.prototype = {};

var o2 = new C();

o2 instanceof C; // true

o instanceof C; // false,C.prototype 指向了一个空对象,这个空对象不在 o 的原型链上.

D.prototype = new C(); // 继承

var o3 = new D();

o3 instanceof D; // true

o3 instanceof C; // true 因为 C.prototype 现在在 o3 的原型链上

如上,是 instanceof 的基本用法,它可以判断一个实例是否是其父类型或者祖先类型的实例。

console.log(Object instanceof Object);//true

console.log(Function instanceof Function);//true

console.log(Number instanceof Number);//false

console.log(String instanceof String);//false

console.log(Function instanceof Object);//true

console.log(Foo instanceof Function);//true

console.log(Foo instanceof Foo);//false

为什么 Object 和 Function instanceof 自己等于 true,而其他类 instanceof 自己却又不等于 true 呢?如何解释?

要想从根本上了解 instanceof 的奥秘,需要从两个方面着手:1,语言规范中是如何定义这个运算符的。2,JavaScript 原型继承机制。

原理浅析

经过上述的分析,想必大家对这种经典神图已经不那么陌生了吧,那咱就对着这张图来聊聊instanceof

这里,我直接将规范定义翻译为 JavaScript 代码如下:

function instance_of(L, R) {//L 表示左表达式,R 表示右表达式

var O = R.prototype;// 取 R 的显示原型

L = L.proto;// 取 L 的隐式原型

while (true) {

if (L === null)

return false;

if (O === L)// 这里重点:当 O 严格等于 L 时,返回 true

return true;

L = L.proto;

}

}

所以如上原理,加上上文解释的原型相关知识,我们再来解析下为什么Object 和 Function instanceof 自己等于 true

  • Object instanceof Object

// 为了方便表述,首先区分左侧表达式和右侧表达式

ObjectL = Object, ObjectR = Object;

// 下面根据规范逐步推演

O = ObjectR.prototype = Object.prototype

L = ObjectL.proto = Function.prototype

// 第一次判断

O != L

// 循环查找 L 是否还有 proto

L = Function.prototype.proto = Object.prototype

// 第二次判断

O == L

// 返回 true

  • Function instanceof Function

// 为了方便表述,首先区分左侧表达式和右侧表达式

FunctionL = Function, FunctionR = Function;

// 下面根据规范逐步推演

O = FunctionR.prototype = Function.prototype

L = FunctionL.proto = Function.prototype

// 第一次判断

O == L

// 返回 true

  • Foo instanceof Foo

// 为了方便表述,首先区分左侧表达式和右侧表达式

FooL = Foo, FooR = Foo;

// 下面根据规范逐步推演

O = FooR.prototype = Foo.prototype

L = FooL.proto = Function.prototype

// 第一次判断

O != L

// 循环再次查找 L 是否还有 proto

L = Function.prototype.proto = Object.prototype

// 第二次判断

O != L

// 再次循环查找 L 是否还有 proto

L = Object.prototype.proto = null

// 第三次判断

L == null

// 返回 false

ES5 中的继承实现方式


在继承实现上,工业聚大大在他的原型文章中,将原型继承分为两大类,显式继承和隐式继承。感兴趣的可以点击文末参考链接查看。

但是本文还是希望能够基于“通俗”的方式来讲解几种常见的继承方式和优缺点。大家可多多对比查看,其实原理都是一样,名词也只是所谓的代称而已。

关于继承的文章,很多书本和博客中都有很详细的讲解。以下几种继承方式,均总结与《JavaScript 设计模式》一书。也是笔者三年前写的一篇文章了。

new 关键字

在讲解继承之前呢,我觉得 new 这个东西很有必要介绍下~

一个例子看下new 关键字都干了啥

function Person(name,age){

this.name = name;

this.age = age;

this.sex = ‘male’;

}

Person.prototype.isHandsome = true;

Person.prototype.sayName = function(){

console.log(Hello , my name is ${this.name});

}

let handsomeBoy = new Person(‘Nealyang’,25);

console.log(handsomeBoy.name) // Nealyang

console.log(handsomeBoy.sex) // male

console.log(handsomeBoy.isHandsome) // true

handsomeBoy.sayName(); // Hello , my name is Nealyang

从上面的例子我们可以看到:

  • 访问到 Person 构造函数里的属性

  • 访问到 Person.prototype 中的属性

new 手写版本一

function objectFactory() {

const obj = new Object(),//从Object.prototype上克隆一个对象

Constructor = [].shift.call(arguments);//取得外部传入的构造器

const F=function(){};

F.prototype= Constructor.prototype;

obj=new F();//指向正确的原型

Constructor.apply(obj, arguments);//借用外部传入的构造器给obj设置属性

return obj;//返回 obj

};

  • new Object() 的方式新建了一个对象 obj

  • 取出第一个参数,就是我们要传入的构造函数。此外因为 shift 会修改原数组,所以 arguments 会被去除第一个参数

  • 将 obj 的原型指向构造函数,这样 obj 就可以访问到构造函数原型中的属性

  • 使用 apply,改变构造函数 this 的指向到新建的对象,这样 obj 就可以访问到构造函数中的属性

  • 返回 obj

下面我们来测试一下:

function Person(name,age){

this.name = name;

this.age = age;

this.sex = ‘male’;

}

Person.prototype.isHandsome = true;

Person.prototype.sayName = function(){

console.log(Hello , my name is ${this.name});

}

function objectFactory() {

let obj = new Object(),//从Object.prototype上克隆一个对象

Constructor = [].shift.call(arguments);//取得外部传入的构造器

console.log({Constructor})

const F=function(){};

F.prototype= Constructor.prototype;

obj=new F();//指向正确的原型

Constructor.apply(obj, arguments);//借用外部传入的构造器给obj设置属性

return obj;//返回 obj

};

let handsomeBoy = objectFactory(Person,‘Nealyang’,25);

console.log(handsomeBoy.name) // Nealyang

console.log(handsomeBoy.sex) // male

console.log(handsomeBoy.isHandsome) // true

handsomeBoy.sayName(); // Hello , my name is Nealyang

注意上面我们没有直接修改 obj 的__proto__隐式挂载。

new 手写版本二

考虑构造函数又返回值的情况:

  • 如果构造函数返回一个对象,那么我们也返回这个对象

  • 如上否则,就返回默认值

function objectFactory() {

var obj = new Object(),//从Object.prototype上克隆一个对象

Constructor = [].shift.call(arguments);//取得外部传入的构造器

var F=function(){};

F.prototype= Constructor.prototype;

obj=new F();//指向正确的原型

var ret = Constructor.apply(obj, arguments);//借用外部传入的构造器给obj设置属性

return typeof ret === ‘object’ ? ret : obj;//确保构造器总是返回一个对象

};

关于 call、apply、bind、this 等用法和原理讲解:【THE LAST TIME】this:call、apply、bind

类式继承

function SuperClass() {

this.superValue = true;

}

SuperClass.prototype.getSuperValue = function() {

return this.superValue;

}

function SubClass() {

this.subValue = false;

}

SubClass.prototype = new SuperClass();

SubClass.prototype.getSubValue = function() {

return this.subValue;

}

var instance = new SubClass();

console.log(instance instanceof SuperClass)//true

console.log(instance instanceof SubClass)//true

console.log(SubClass instanceof SuperClass)//false

从我们之前介绍的 instanceof 的原理我们知道,第三个 console 如果这么写就返回 true 了console.log(SubClass.prototype instanceof SuperClass)

虽然实现起来清晰简洁,但是这种继承方式有两个缺点:

  • 由于子类通过其原型prototype对父类实例化,继承了父类,所以说父类中如果共有属性是引用类型,就会在子类中被所有的实例所共享,因此一个子类的实例更改子类原型从父类构造函数中继承的共有属性就会直接影响到其他的子类

  • 由于子类实现的继承是靠其原型prototype对父类进行实例化实现的,因此在创建父类的时候,是无法向父类传递参数的。因而在实例化父类的时候也无法对父类构造函数内的属性进行初始化

构造函数继承

function SuperClass(id) {

this.books = [‘js’,‘css’];

this.id = id;

}

SuperClass.prototype.showBooks = function() {

console.log(this.books);

}

function SubClass(id) {

//继承父类

SuperClass.call(this,id);

}

//创建第一个子类实例

var instance1 = new SubClass(10);

//创建第二个子类实例

var instance2 = new SubClass(11);

instance1.books.push(‘html’);

console.log(instance1)

console.log(instance2)

instance1.showBooks();//TypeError

SuperClass.call(this,id)当然就是构造函数继承的核心语句了.由于父类中给this绑定属性,因此子类自然也就继承父类的共有属性。由于这种类型的继承没有涉及到原型prototype,所以父类的原型方法自然不会被子类继承,而如果想被子类继承,就必须放到构造函数中,这样创建出来的每一个实例都会单独的拥有一份而不能共用,这样就违背了代码复用的原则,所以综合上述两种,我们提出了组合式继承方法

组合式继承

function SuperClass(name) {

this.name = name;

this.books = [‘Js’,‘CSS’];

}

SuperClass.prototype.getBooks = function() {

console.log(this.books);

}

function SubClass(name,time) {

SuperClass.call(this,name);

this.time = time;

}

SubClass.prototype = new SuperClass();

SubClass.prototype.getTime = function() {

console.log(this.time);

}

如上,我们就解决了之前说到的一些问题,但是是不是从代码看,还是有些不爽呢?至少这个SuperClass的构造函数执行了两遍就感觉非常的不妥.

原型式继承

function inheritObject(o) {

//声明一个过渡对象

function F() { }

//过渡对象的原型继承父对象

F.prototype = o;

//返回过渡对象的实例,该对象的原型继承了父对象

return new F();

}

原型式继承大致的实现方式如上,是不是想到了我们new关键字模拟的实现?

其实这种方式和类式继承非常的相似,他只是对类式继承的一个封装,其中的过渡对象就相当于类式继承的子类,只不过在原型继承中作为一个普通的过渡对象存在,目的是为了创建要返回的新的实例对象。

var book = {

name:‘js book’,

likeBook:[‘css Book’,‘html book’]

}

var newBook = inheritObject(book);

newBook.name = ‘ajax book’;

newBook.likeBook.push(‘react book’);

var otherBook = inheritObject(book);

otherBook.name = ‘canvas book’;

otherBook.likeBook.push(‘node book’);

console.log(newBook,otherBook);

如上代码我们可以看出,原型式继承和类式继承一个样子,对于引用类型的变量,还是存在子类实例共享的情况。

所以,我们还有下面的寄生式继

寄生式继承

var book = {

name:‘js book’,

likeBook:[‘html book’,‘css book’]

}

function createBook(obj) {

//通过原型方式创建新的对象

var o = new inheritObject(obj);

// 拓展新对象

o.getName = function(name) {

console.log(name)

}

// 返回拓展后的新对象

return o;

}

其实寄生式继承就是对原型继承的拓展,一个二次封装的过程,这样新创建的对象不仅仅有父类的属性和方法,还新增了别的属性和方法。

寄生组合式继承

回到之前的组合式继承,那时候我们将类式继承和构造函数继承组合使用,但是存在的问题就是子类不是父类的实例,而子类的原型是父类的实例,所以才有了寄生组合式继承

而寄生组合式继承是寄生式继承和构造函数继承的组合。但是这里寄生式继承有些特殊,这里他处理不是对象,而是类的原型。

function inheritObject(o) {

//声明一个过渡对象

function F() { }

//过渡对象的原型继承父对象

F.prototype = o;

//返回过渡对象的实例,该对象的原型继承了父对象

return new F();

}

function inheritPrototype(subClass,superClass) {

// 复制一份父类的原型副本到变量中

var p = inheritObject(superClass.prototype);

// 修正因为重写子类的原型导致子类的constructor属性被修改

p.constructor = subClass;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

总结:

  • 函数式编程其实是一种编程思想,它追求更细的粒度,将应用拆分成一组组极小的单元函数,组合调用操作数据流;

  • 它提倡着 纯函数 / 函数复合 / 数据不可变, 谨慎对待函数内的 状态共享 / 依赖外部 / 副作用;

Tips:

其实我们很难也不需要在面试过程中去完美地阐述出整套思想,这里也只是浅尝辄止,一些个人理解而已。博主也是初级小菜鸟,停留在表面而已,只求对大家能有所帮助,轻喷🤣;

我个人觉得: 这些编程范式之间,其实并不矛盾,各有各的 优劣势

理解和学习它们的理念与优势,合理地 设计融合,将优秀的软件编程思想用于提升我们应用;

所有设计思想,最终的目标一定是使我们的应用更加 解耦颗粒化、易拓展、易测试、高复用,开发更为高效和安全

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

型导致子类的constructor属性被修改

p.constructor = subClass;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-Lnp4I5cB-1712195748596)]
[外链图片转存中…(img-RL1aR2hO-1712195748596)]
[外链图片转存中…(img-PrGvQ4ze-1712195748596)]
[外链图片转存中…(img-pevUbRws-1712195748597)]
[外链图片转存中…(img-ileZwqgO-1712195748597)]
[外链图片转存中…(img-3alxVgUg-1712195748597)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-8uY8N0CH-1712195748597)]

总结:

  • 函数式编程其实是一种编程思想,它追求更细的粒度,将应用拆分成一组组极小的单元函数,组合调用操作数据流;

  • 它提倡着 纯函数 / 函数复合 / 数据不可变, 谨慎对待函数内的 状态共享 / 依赖外部 / 副作用;

Tips:

其实我们很难也不需要在面试过程中去完美地阐述出整套思想,这里也只是浅尝辄止,一些个人理解而已。博主也是初级小菜鸟,停留在表面而已,只求对大家能有所帮助,轻喷🤣;

我个人觉得: 这些编程范式之间,其实并不矛盾,各有各的 优劣势

理解和学习它们的理念与优势,合理地 设计融合,将优秀的软件编程思想用于提升我们应用;

所有设计思想,最终的目标一定是使我们的应用更加 解耦颗粒化、易拓展、易测试、高复用,开发更为高效和安全

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

  • 14
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值