浅谈代码语言的魅力

本文探讨V8引擎的HiddenClasses和InlineCaches优化机制,分析Java中的逻辑运算与位运算及其应用场景,并介绍Go语言中函数作为类型的概念及实用案例。

 01 浅谈 V8 Hidden Classes 和 Inline Caches

Javascript 是动态的、基于属性链的语言,V8 是流行的 JavaScript 运行引擎。我们知道在运行时可以改变对象的属性和类型。为了定位对象的属性和类型,V8 引入隐藏类(Hidden Classes)概念,用于优化属性访问速度。看如下代码:

function Person(name, age) {
  this.name = name;
  this.age  = age;
}

const zhangsan = new Person('Zhangsan', 20);
const xiaofang = new Person('Xiaofang', 21);
xiaofang.gender = 'female';

初始化 Person 类时会给对象 zhangsan 创建隐藏类 C0,C0 还没有包含任何属性。当初始化属性 zhangsan.name 时会基于 C0 创建出新隐藏类 C1。由此类推,属性 age 初始化后,生成 C2。当初始化对象 xiaofang 时,由于属性结构相同其会复用 C0、C1、C2。但是给对象 xiaofang 增加属性 gender 时,其会基于 C2 生成新隐藏类 C3。

但如果你不小心执行了 delete 操作,那么情况就比较糟糕,如下:

function Person(name, age) {
    this.name = name;
    this.age  = age;
}
for (let i=0; i<1000000; i++) {
    const xiaofang = new Person('Xiaofang', 21);
    delete xiaofang.name;
}

上述代码加上 delete 语句,执行耗时 230ms。而去掉 delete 语句,执行耗时 4ms。差距如此大的原因就是在于隐藏类的破坏。我们可能一不小心在某些场景使用了 delete,特别是大循环体内时,性能退化就明显了。我们可以使用赋值 null 替换 delete。

V8 更进一步做了 Inline Caches 策略,可进一步提高属性访问速度。当多次访问属性时,如果能保持一个类的方法的参数类型不变,上下文不变,执行过程点不变,那么根据该缓存策略,函数内对象属性查找过程就能避免,提高函数执行速度。我们经常可能喜欢在函数体内定义函数,这些应该尽量避免。

02 浅析 Java 逻辑运算与位运算

逻辑运算与位运算

算数、赋值、逻辑、关系、自增自减、条件以及位运算等丰富的运算和相应的运算符是 Java 语言的主要特点之一,也是我们学习一门语言时的基础。本文我们主要简单了解一下 Java 中的逻辑运算和位运算,以及我们实际开发过程中如何更有效的应用它们的特性。

首先了解什么是逻辑运算和位运算:

逻辑运算:逻辑运算又称布尔运算。逻辑运算符要求操作数的数据类型为逻辑型,其运算结果也是逻辑型(boolean)值。逻辑运算符把各个运算的关系表达式连接起来组成一个复杂的逻辑表达式,以判断程序中的表达式是否成立,判断的结果是 true 或 false。

位运算:位运算是以二进制位为单位进行的运算,其操作数和运算结果都是整型值。这些整数类型包括 long,int,short,char 和 byte。

运算符

Java 中是如何执行这些运算的呢?那就是通过运算符。

逻辑运算符:短路与 "&&"、短路或 "||"、逻辑非 "!"、逻辑或 "|"、逻辑与 "&"。

  • &&(短路与)与 &(逻辑与)区别:看含义,区别就在于 "短路",看说明 "如果 a 为 false 则结果为 false,且不会计算 b"(因为不论 b 为何值,结果都为 false)。

  • ||(短路或)与 |(逻辑或)区别:同上区别同样在 "短路"。a | b : 如果 a 为 true 则结果为 true,但会继续计算 b(不具备短路能力时,会计算所有逻辑项)。

实践一

基于以上的学习,下面这个问题,在实际开发过程中你会如何决策呢?假设你有一个需求需要同时判断多个条件,这些条件你会有意识的做前后排序还是简单的无序罗列呢?如下你会选择方案 1 还是方案 2 呢?

public class Test {
    public static void main(String[] args) {
        // 方案1、a() && b()
        System.out.println(a() && b());
        // 方案2、b() && a()
        System.out.println(b() && a());
    }

    /**
     * 一个耗时的逻辑判断
     */
    public static boolean a() {
        System.out.println("do a!");
        boolean a = false;
        // 耗时耗性能的逻辑
        for (int i = 0; i < 1000000; i++) {
            // 耗时操作
            a = true;
        }
        return a;
    }

    /**
     * 一个简单的逻辑判断
     */
    public static boolean b() {
        System.out.println("do b!");
        return false;
    }
}

想必大家都能做出正确的选择,这其实是一个非常小的知识点,但平时开发过程很多人都会忽视。我们在日常开发过程中要注重细节,越是基础的逻辑越能积蓄更大的能量,养成良好的编程习惯以及性能意识。

短路与(&&)和短路或(||)由于短路机制的存在,能够优化逻辑运算的计算,从而提高效率。在实际开发过程中,应该有意识的使用短路与和短路或的短路能力,来优化我们的逻辑运算。

位运算符:包含位逻辑运算符(位与 '&',位或 '|',位非 '~',位异或 '^'),位移运算符(右移 '>>',左移 '<<',右移补零 '>>>')

逻辑比较简单,我们不再详述,我们主要看看位运算如何应用到我们的日常实际开发中。也许我们会发现,我们日常开发中好像并不经常用到位运算,但我们在看 Android 源码的时候确能经常看到相应的使用。比如 View 中的 mPrivateFlags、mPrivateFlags1、mPrivateFlags2、mPrivateFlags3 等等,它们一个变量甚至可以保存几十个不同的状态,这也就是通过位运算能够达到的一个优势,可以让 “多状态” 的管理像单状态管理一样简单高效。

实践二

假设一共有七种颜色,一个物体同时能拥有多种颜色,我们该如何简单高效的维护该物体的颜色属性呢?

1、维护一个颜色属性集合,每拥有一个颜色就向集合中添加,移除则删除?

2、维护 7 个布尔值指向不同的色值,每拥有一个就设置为 true,否则为 false?

以上只是简单的举几个例子,比如用布尔值来维护状态,这也是我们最常用的方法,这种对单状态的维护会很简单和直观,但对多状态的维护就会显得不那么适合。

这时我们就可以尝试考虑采用位运算的方式。回顾位运算的按位与和按位或,按位或在对应位不同时则为 1,是不是等同于我们添加了一个状态?同理,按位与在对应位都是 1 时则为 1,是不是就可以判断是否具有某个状态?我们则可用不同位的 1 来表示不同的状态,最终结果具有哪个位置的 1 就说明具有哪个状态,这样我们就能以一个属性来同时管理多个状态了。

public class Test {
    /** 单属性维护多状态 */
    private static int mColors = 0B00000000;
    private static final int RED = 0B00000001;
    private static final int ORANGE = 0B00000010;
    private static final int YELLOW = 0B00000100;
    private static final int GREEN = 0B00001000;
    private static final int BLUE = 0B00010000;
    private static final int PURPLE = 0B00100000;
    private static final int PINK = 0B01000000;

    public static void main(String[] args) {
        // 同时具有红绿蓝三色,mColors = 0B00011001
        mColors = mColors | RED | GREEN | BLUE;
        System.out.println(mColors);
        // 判断是否具有红色,true
        System.out.println((mColors & RED) != 0);
        // 判断是否具有黄色,false
        System.out.println((mColors & YELLOW) != 0);
        // 添加黄色,mColors = 0B00011101
        mColors |= YELLOW;
        // 判断是否具有黄色,true
        System.out.println((mColors & YELLOW) != 0);
        // 移除黄色,mColors = 0B00011001
        mColors &= ~YELLOW;
        // 判断是否具有黄色,false
        System.out.println((mColors & YELLOW) != 0);
    }
}

总结


基础语法中存在容易让人忽视的特性,有时却会有很大的妙用,掌握这些特性,能够为我们解决实际问题提供更多的可能性,以及拓宽我们的视野。

03 理解 Golang 的 type func ()


在 Go 语言中,可以用 type 关键字自定义类型,比如常用的:

type Myint int // 定义了MyInt类型,其基础类型是int,与int有相同的底层数据结构,但是是完全不通的两种类型
type Book struct {  // 定义了一个Book结构体,包含Title和PageNum两个字段
    Title    string
    PageNum  int
}

同样地,Go 语言也支持自定义函数类型,具有相同的参数和返回值列表(不包括参数名与函数名,需要参数和返回值列表的类型与顺序一致)的函数被视为同一种类型。既然函数被当做一种类型可以被定义,那同样地,再 Go 语言里,函数可以像其他类型一样,被当做普通的值,再其他函数之间传递、作变量赋值、做类型判断和类型转换,举个例子:

type PowerCanculator func(num int) int   // 幂次计算
 
func PowerBase2(num int) int {    // 以2为底的幂次计算
    return 1 << num
}
 
func main() {
    var pc PowerCanculator
    var result int
    pc = PowerBase2
    result = pc(2)
    fmt.Println(result) // 结果为4
}

在以上例子里,PowerBase2 作为 PowerCanculator 类型的一种实现,被当做参数赋值给一个 PowerCanculator 类型的函数变量并调用。

那么函数被作为参数传递有什么好处或者妙用呢,我们可以考虑这样一个场景:我们希望有个计算器,能够进行任意数字计算,且所有参数和具体的操作都由调用方给出,这样我们的计算器仅做统一调度即可,该如何实现?

type PowerCanculator func(num int) int   // 幂次计算
  
func PowerBase2(num int) int {    // 以2为底的幂次计算
    return 1 << num
}
 
func PowerBase4(num int) int {    // 以4为底的幂次计算
    return 1 << (num+1)
}
 
func Canculator(num int, pc PowerCanculator) (int, error) {
    if pc == nil {
        return 0,errors.New("param error")
    }
    return pc(num),nil
}
 
func main() {
   result1, err := Canculator(2, PowerBase2)
   if err != nil {
      fmt.Println(err)
   }
   fmt.Println(result1) //结果为4
   result2, err := Canculator(2, PowerBase4)
   if err != nil {
      fmt.Println(err)
   }
   fmt.Println(result2) //结果为16
}

以上是一个函数被当做另外一个函数的参数传入的例子,那么函数既然被当做了一个普通参数,那么它是否也可以被当做另外一个函数的返回值返回呢,答案是可以:

fun PowerCanculatorGenerator(base int)  PowerCanculator {
    switch base{
    case 2:
        return PowerBase2
    case 4:
        return PowerBase4
    default:
        return nil
    }
}

func main() {
    var base int
    var powerBase2 PowerCanculator
    var powerBase4 PowerCanculator
    
    powerBase2 = PowerCanculatorGenerator(2)    
    powerBase4 = PowerCanculatorGenerator(4)
    fmt.Println(powerBase2(2)) //结果为4
    fmt.Println(powerBase4(2)) //结果为16
}

以上是一个简单的例子,其实函数类型最典型的应用场景,是进行 http 服务路由注册的时候,比如说现在有两个 http 请求 uri 分别是 /sayhi 和 /saybye,在进行 http 请求实现时,可以这么写:

func mHttp() {
    http.HandleFunc("/sayhi", hi)   
    http.HandleFunc("/sayBye", bye)
    http.ListenAndServe("0.0.0.0:8888",nil)
}
 
func hi(w http.ResponseWriter, r *http.Request) {
 
}
 
func bye(w http.ResponseWriter, r *http.Request) {
 
}

其中在 http 包里就存在一个函数类型:

type HandlerFunc func(ResponseWriter, *Request)

不难看出,HandlerFunc 是一个函数类型,有两个参数,而 hi 和 bye 是对 HandlerFunc 的实现,通过指定 HandleFunc 里函数变量的值,实现不同服务的路由注册。

以上内容,其实总得来说是在说明函数的两个关键特性:

1. 可以被当做参数传入函数;

2. 可以作为返回值从函数中返回。

其实,函数在 Go 语言中被称作『一等公民』,除了拥有函数的基本特性和上述两个特性之外,还具备更多特殊运用,比如对函数进行显式类型转换等,这里就不多做赘述,感兴趣的同学可以自行查阅相关文章和书籍~

极致管理软件开发平台基于Microsoft .Net开发技术和模型驱动的技术架构,是面向业务应用的管理软件开发平台。极致管理软件开发平台提供数据实体定义工具、界面设计工具、系统发布工具和运行时框架组件,帮助软件开发人员突破技术瓶颈,实现少写代码或不写代码、快速地开发应用软件的目的。 极致管理软件开发平台基于模型驱动的技术架构,不仅能够快速地开发应用软件,而且开发的软件系统具有高度的扩展性和可维护性,能够根据的用户需求快速地对软件系统进行调整,降低了软件实施和维护过程中的成本和风险,使软件系统能够充分满足用户的个性化需求,以及用户不断发展和完善信息系统的长期目标。 极致管理软件开发平台体现了极致公司充分把握目前管理软件平台化开发的新趋势,融合了极致公司在管理软件领域的行业经验和主流的开发技术,能够帮助软件企业实现“快速开发、随需而变”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得前所未有的高回报。 极致管理软件开发平台的基本思想 一、模型驱动的技术架构 极致管理软件开发平台基于模型驱动的技术架构,通过元数据来保存数据实体、用户界面和业务流程的模型。应用软件系统通过运行时框架根据元数据描述的模型来访问数据、加载用户界面并驱动业务流程。 以模型驱动的方式,而不是编程的方式,使软件系统更加易于理解,并且有更好的扩展性和可维护性。 数据实体元数据 使用极致数据实体定义工具进行数据实体定义时,一方面对数据实体的定义进行了描述,另一方面建立了数据实体之间的关系,这两方面的数据都作为元数据保存到数据库中。极致管理软件开发平台通过OR Mapping(对象-关系映射)的方式封装了对数据库的访问,以对象的方式来访问数据库中的数据,避免了通过写SQL语句来创建或维护数据表,或通过写SQL语句实现对数据的新增、修改、删除和查询的传统编程方式。 元数据的建立和OR Mapping的数据访问方式实现了面向对象的数据访问方式,能够简化编程并实现对业务逻辑的扩展,同时还为实现多数据库的支持建立了良好基础。极致管理软件开发平台简化了以数据为中心的应用程序中与数据持久化相关的编程任务,使开发人员能够将开发重点专注于实现面向对象的业务模型和商业逻辑。 用户界面元数据 极致管理软件开发平台突破了传统的用户界面编程方式,通过定义界面元数据的方式,而不是编程方式来设计用户界面。极致界面设计工具能够根据数据实体的属性以及数据实体之间的关系快速地设计单据、序时薄、报表、菜单、工具栏等用户界面,同时支持通用表单的设计。通过极致界面设计工具设计的用户界面以界面元数据的方式保存在数据库中,运行时框架组件动态加载界面元数据并创建用户界面。通过元数据来描述用户界面的方式实现的界面的动态构造,使用户界面易于调整和维护。 业务流程元数据 极致管理软件开发平台集成工作流引擎,能够对业务流程进行建模。业务流程建模的结果以元数据的方式保存在数据库中,运行时由工作流引擎根据元数据的描述驱动业务流程。 二、成熟的软件基础结构 极致管理软件开发平台集成了诸多的管理软件基础结构,例如对于互联网直联的支持、对多种数据库的支持、集成的工作流引擎、短信平台和邮件系统等。 极致管理软件开发平台预置了大量的基本操作,例如单据的新增、修改、删除、复制、审核、套打等操作,报表的过滤、打印、预览、联查、导出、快速查找、图表分析等操作。 极致管理软件开发平台还提供了基于以上管理软件基础结构开发的诸多的标准组件,例如用户数据库管理、组织机构管理、用户管理、权限管理、文档管理、数据导入导出等,在通过极致管理软件开发平台开发软件系统能够直接使用。 通过使用极致管理软件开发平台提供的基础结构,在开发软件系统时能够极大地缩短软件的开发周期,降低软件开发成本
EasyPlat.Net提供基于DATASET的三层结构,可以通过直接使用BizSQL进行两层开发。 支持集团级企业系统,一行代码数据库记录增删改查; 包含账号、角色、权限,菜单管理;导入、导出、打印、加密等方法;公共字典、XML字典使用;日志记录,主表+明细表单据处理,RDL自定义报表等。 用户可以在此基础上几天之内完成快速开发企业实用的系统。(Winxp/Win7+MS SQL2005/2008+VS2010+.NetFramework4+C#)。 手册目录: 1:系统结构 4 1.1:系统构架 4 1.2:系统目录结构 6 1.3:系统表结构 6 2:界面介绍 7 3:使用流程 9 3.1 建立部门 9 3.2 录入员工资料 10 3.3 建立角色 11 3.4 给角色分配菜单 11 3.5 给角色设置菜单权限 12 3.6 注册员工账号 12 3.7 给账号分配角色 12 3.8 开发功能 13 3.9 注册功能为系统菜单 13 3.10 把菜单分配给角色 13 3.11 账号登录 14 4:快速开发功能(增加个兼职功能模块为例) 14 4.1 进入企业管理器,增加数据库表Admin_EmpOtherDuty 14 4.2 生成界面(目前没有提供根据数据库表自动生成需要的界面) 15 4.3 一行代码实现读取数据、操作数据库 20 4.4 执行自己的SQL语句 22 4.5 开发完成功能,之后就是:注册菜单,把菜单分配给角色 22 5:标准部件使用 24 5.1 快速定义标准字典 24 5.2 使用XML字典 25 5.3 记录日志 25 5.4 票据级打印——LODOP使用 26 5.5、打印GridView 28 5.6 生成PDF文件 29 5.7 Excel导入、导出 29 5.8 柱状图、圆饼图、折线图等图表使用 31 5.9 CKEditor、CKFinder使用 32 6:权限控制使用 34 6.1 按钮控制 34 6.2数据范围控制——无部门条件的查询 35 6.3数据范围控制——有部门条件的查询 38 7:SQLHelper的一些方法说明 39 8:深入开发 43 8.1 使用基于DataSet的三层结构开发自己的模块(建议这样开发) 43 8.2 主表,明细表操作(2013-10-18) 43 8.3 RDL自定义报表 44 8.4报表高级使用和开发 46
EasyPlat.Net快速开发平台源码 源码描述: 功能介绍: EasyPlat.Net提供基于DATASET的三层结构,可以通过直接使用BizSQL进行两层开发。包含账号、角色、权 限,菜单管理;导入、导出、打印、加密等方法;公共字典、XML字典使用;多种打印、导入导出、图表支持, 日志记录等。 用户可以在此基础上7天之内完成快速开发企业实用的系统, 一行代码插入数据,一行代码更新数据等不用写大 部分代码。(Winxp/Win7+MS SQL2005/2008+VS2010+.NetFramework4+C#)。 注意: 开发环境为Visual Studio 2010,数据库为SQL Server 2005,数据库文件在DB_51aspx文件夹中附加就行。 默认管理员登录名密码为:admin 123 更新历史 2013-08-03 1:在数据库表增加超级用户 root,admin 删除 APP_DATA目录下的SpecUser.xml 删除 SysIndex目录下的OpenRootFace.aspx 增加数据库表 Sys_Admin CREATE TABLE [dbo].[Sys_Admin]( [RtID] [int] IDENTITY(1,1) NOT NULL, [Name] [varchar](30) COLLATE Chinese_PRC_CI_AS NOT NULL, [Pwd] [varchar](200) COLLATE Chinese_PRC_CI_AS NULL, [Statu] [char](1) COLLATE Chinese_PRC_CI_AS NULL CONSTRAINT [DF_Sys_Root_Statu] DEFAULT ('Y'), CONSTRAINT [PK_Sys_Root] PRIMARY KEY CLUSTERED ( [RtID] ASC )WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY]; ---MD5密码123 自己在数据库修改为自己保密的密码,此3个账号之外不可增加其 insert Sys_Admin (name,pwd) values ('root','5fa285e1bebe0a6623e33afc04a1fbd5'); insert Sys_Admin (name,pwd) values ('admin','5fa285e1bebe0a6623e33afc04a1fbd5'); insert Sys_Admin (name,pwd) values ('xiao','5fa285e1bebe0a6623e33afc04a1fbd5'); 2:解决超级用户登录增操作菜单管理,提示没有超级用户权限 3:增加MD5加密字符串和执行SQL语句界面 ModSystem/RootTools.aspx 注册菜单分配权限即可使用 4:增加初始化存储过程 sp_ClearDb
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值