本文将结合两种常见的编程范式来回顾一下js语言层面的一些特性并理解视角。
编程范式
我们之前讨论过编程范例,让我们回顾一下它们:
我们在编程中解决的每个问题都对应于多个问题的组合,并且每种编程语言都实现一个或多个。
OOP和FP是两种比较常见的编程范式,js也都支持。 有很多相关的讨论。 这里仅介绍其中一种观点。 更多细节将在后面的章节中介绍。
核
根据前面的说法,两种范式的区别在于 FP 比 OOP 少了一个状态,即
面向对象侧重于数据的各种处理。 数据是对象的内部状态。 C++ Plus 将对象的本质表达为用于设计和扩展自己的数据结构:
of - (OOP) 是和你自己的数据类型
函数式编程关注的是数据流的流动。 从外界输入数据,最终返回相应的结果。 函数式编程简介被概括为数据流而不是控制流。
核心是数据流而不是流
适用场景
以下结论参考vs[]
面向对象专家也表示:
OO 按部分编写代码。 FP 按部分编写代码。
面向对象的可读性是通过封装各个部分来实现的,而函数式可读性是通过最小化各个部分来实现的。 即前者封装了数据和数据动作,后者将各种操作进行拆分,使其最小化。
日常开发中如何选择
每个应用程序都是由各种组件组成的,但组件的形式并不固定,比如数据等。
不同的编程语言往往会使用不同的原子元素来组成组件,比如Java使用对象等,而在js中,由于天然支持面向对象和函数式编程,所以在项目中往往会混合使用它们。 我们可以使用对象组合来生成函数式编程的数据类型,并使用函数式编程生成对象来进行面向对象编程。 不管怎么写,软件开发的本质就是组合。
的 是
我们的工作就是根据不同的情况使用不同的编程范式,像盖房子一样组合不同的组件。 在详细讨论这两种范式之前,让我们首先了解一下 js 本身。
js中的相关功能
我们首先需要了解js语言的各种特性,然后才能使用范式这样的工具更好的结合我们开发的软件。 这部分主要是参考。
js语言设计
Eich开发了js。 在这篇文章中,他提到了js设计过程中的一些问题。
浏览器中需要内置脚本语言。 按照领导的要求,首先要像java(看起来像Java,所以很多语法都和java类似)。 作者更喜欢它,所以最终选择了与 First-class Functions 相同的语言以及与 Self 相同的语言作为主要组件。 受Java的影响,原始类型和对象之间存在着和的区别。
上面的设计以及后续的开发就成为了现在的js。
js特性概述
js中有两种数据结构,原始类型和对象。 js中的对象创建不是基于类的,而是有很多方法,比如字面量或者构造函数。 每个构造函数都有一个用于实现的属性。 基于原型(-based)的继承。 构造函数还具有对构造函数本身的引用。 当实现继承时,该属性可能会发生变化,需要按照约定进行更正,但这不是必需的(更多信息请参见此处)。
说到构造函数,这里有一些相关的概念。 函数是包含[[Call]]的特殊对象,因此可以通过函数调用来执行相关代码,而构造函数是包含[[ ]]的特殊函数,可以通过new或super调用创建对象。
js中的对象原型链
通过构造函数创建的每个对象都有一个对构造函数属性的隐式引用(可以访问但不推荐),该属性本身可能有一个对其的非空引用等。这称为原型链。 当访问对象的属性时,会首先从对象本身开始查找。 如果找不到,则沿着原型链查找,直到找到或者最后发现没有找到。 原型链上的属性可以被覆盖。
与基于类继承的语言相比,一般来说,状态归实例所有,方法归类所有,只有结构体和行为()被继承,但js所有的都可以继承。 这里。
原型链的末尾为空。 为了明确对象的原型链包含哪些内容,大致可以分为以下几种
var obj={}
//原型链 obj=>Object.prototype=>null
var arr =[]
//arr=>Array.prototype=>Object.prototype=>null
//如果是自定义构造函数也一样
var P=function(){}
var p=new P()
//p=>P.prototype=>Object.prototype=>null
//1. 使用Object.create()
var q=Object.create(p)
// q=>p
//2. 直接修改构造函数的prototype
function Q(){}
Q.prototype=p
var q=new Q()
//q=>p
//3. 通过Object.setPrototypeOf(obj, prototype)设置__proto__属性,可以直接修改原型链,这个操作很浪费性能,少用
function P(){
this.b=1
}
function Q(){
this.a=2
}
var q=new Q()
Object.setPrototypeOf(q,P.prototype)
// q=>P.prototype
//4. 使用call和apply借用构造函数时,和原型无关
var P=function(v){
this.a=v
}
function Q(v){
P.call(this,v)
}
var q=new Q(2)
// q=>Q.prototype=>Object.prototype=>null
我们可以判断一个构造函数是否在指定对象的原型链中
function Q(){
this.a=2
}
var q=new Q()
console.log(q instanceof Q)
console.log(q instanceof Object)
可以通过.()获取对象的属性
上有一些属性和方法。 被所有其他对象继承,并且某些字段可能在特定对象的继承过程中被覆盖。
另外,还有很多静态方法用于处理对象的各种操作。 详情请参阅
js中的函数
js中的所有函数都是 , 包括 和 本身的实例,甚至还有各种内置构造函数(如Array),因此有
Function.__proto__===Function.prototype//true
Function.prototype.__proto__===Object.prototype//true,即Function instanceof Object
//原型链 Function=>Function.prototype=>Object.prototype,以下类似
Object.__proto__===Function.prototype//true,即Object instanceof Function
Array.__proto__===Function.prototype //true
function a(){}
a.__proto__===Function.prototype//true
可见,在到达之前都需要传递所有函数的原型链。 函数是一个对象和一个函数。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。