关于变量:DBeaver-下用-DuckDB-读取-parquet-文件qbit

官网文档:https://duckdb.org/docs/data/...DBeaver 变量读取示例 @set path='C:/Users/qbit/Desktop/simple.parquet'SELECT * FROM :path;SELECT * FROM ${path};SELECT * FROM read_parquet('C:/Users/qbit/Desktop/simple.parquet');SELECT * FROM read_parquet(:path); 本文出自 qbit snap

September 9, 2022 · 1 min · jiezi

JS变量和类型全面解析

原文作者:ConardLi大佬导读变量和类型是学习JavaScript最先接触到的东西,但是往往看起来最简单的东西往往还隐藏着很多你不了解、或者容易犯错的知识,比如下面几个问题: JavaScript中的变量在内存中的具体存储形式是什么?0.1+0.2为什么不等于0.3?发生小数计算错误的具体原因是什么?Symbol的特点,以及实际应用场景是什么?[] == ![]、[undefined] == false为什么等于true?代码中何时会发生隐式类型转换?转换的规则是什么?如何精确的判断变量的类型?如果你还不能很好的解答上面的问题,那说明你还没有完全掌握这部分的知识,那么请好好阅读下面的文章吧。 本文从底层原理到实际应用详细介绍了JavaScript中的变量和类型相关知识。 一、JavaScript数据类型ECMAScript标准规定了7种数据类型,其把这7种数据类型又分为两种:原始类型和对象类型。 原始类型 Null:只包含一个值:nullUndefined:只包含一个值:undefinedBoolean:包含两个值:true和falseNumber:整数或浮点数,还有一些特殊值(-Infinity、+Infinity、NaN)String:一串表示文本值的字符序列Symbol:一种实例是唯一且不可改变的数据类型(在es10中加入了第七种原始类型BigInt,现已被最新Chrome支持) 对象类型 Object:自己分一类丝毫不过分,除了常用的Object,Array、Function等都属于特殊的对象二、为什么区分原始类型和对象类型2.1 不可变性上面所提到的原始类型,在ECMAScript标准中,它们被定义为primitive values,即原始值,代表值本身是不可被改变的。 以字符串为例,我们在调用操作字符串的方法时,没有任何方法是可以直接改变字符串的: var str = 'ConardLi';str.slice(1);str.substr(1);str.trim(1);str.toLowerCase(1);str[0] = 1;console.log(str); // ConardLi在上面的代码中我们对str调用了几个方法,无一例外,这些方法都在原字符串的基础上产生了一个新字符串,而非直接去改变str,这就印证了字符串的不可变性。 那么,当我们继续调用下面的代码: str += '6'console.log(str); // ConardLi6你会发现,str的值被改变了,这不就打脸了字符串的不可变性么?其实不然,我们从内存上来理解: 在JavaScript中,每一个变量在内存中都需要一个空间来存储。 内存空间又被分为两种,栈内存与堆内存。 栈内存: 存储的值大小固定空间较小可以直接操作其保存的变量,运行效率高由系统自动分配存储空间JavaScript中的原始类型的值被直接存储在栈中,在变量定义时,栈就为其分配好了内存空间。 由于栈中的内存空间的大小是固定的,那么注定了存储在栈中的变量就是不可变的。 在上面的代码中,我们执行了str += '6'的操作,实际上是在栈中又开辟了一块内存空间用于存储'ConardLi6',然后将变量str指向这块空间,所以这并不违背不可变性的特点。 2.2 引用类型堆内存: 存储的值大小不定,可动态调整空间较大,运行效率低无法直接操作其内部存储,使用引用地址读取通过代码进行分配空间相对于上面具有不可变性的原始类型,我习惯把对象称为引用类型,引用类型的值实际存储在堆内存中,它在栈中只存储了一个固定长度的地址,这个地址指向堆内存中的值。 var obj1 = {name:"ConardLi"}var obj2 = {age:18}var obj3 = function(){...}var obj4 = [1,2,3,4,5,6,7,8,9] 由于内存是有限的,这些变量不可能一直在内存中占用资源,这里推荐下这篇文章JavaScript中的垃圾回收和内存泄漏,这里告诉你JavaScript是如何进行垃圾回收以及可能会发生内存泄漏的一些场景。当然,引用类型就不再具有不可变性了,我们可以轻易的改变它们: obj1.name = "ConardLi6";obj2.age = 19;obj4.length = 0;console.log(obj1); //{name:"ConardLi6"}console.log(obj2); // {age:19}console.log(obj4); // []以数组为例,它的很多方法都可以改变它自身。 ...

November 2, 2019 · 5 min · jiezi

乐字节Java变量与数据结构之二Java常量与变量

大家好,小乐又来给大家讲述Java基础知识。上次说了乐字节Java变量与数据类型之一:Java编程规范,关键字与标识符,这次将接着往下说,谈谈Java常量与变量。 1、常量1)、定义在程序执行的过程中,其值不发生改变的量。 2)、分类A:字面值常量 B:自定义常量(后面讲) 3)、字面值常量A:字符串常量 "hello" B:整数常量 12,23 C:小数常量 12.345 D:字符常量 'a','A','@' E:布尔常量 true,false F:空常量 null(后面讲) 4)、在Java中针对整数常量提供了四种表现形式A:二进制 由0,1组成。以0b开头。 B:八进制 由0,1,...7组成。以0开头。 C:十进制 由0,1,...9组成。整数默认是十进制。 D:十六进制 由0,1,...9,a,b,c,d,e,f(大小写均可)组成。以0x/0X开头。 2、变量语句:以分号来分割语句 int a;int b; 1)、定义在程序的执行过程中,其值在某个范围内可以发生改变的量。 2)、变量的定义格式:A:数据类型 变量名 = 初始化值; B:数据类型 变量名; 变量名 = 变量值; 3)、变量的两种用途:A、存值 B、取值 4)、变量的关注点:A、数据类型 B、变量名称 C、变量的值 D、变量的作用域,根据{} 来定 同一个作用域当中,变量不能重名 同一个变量在某一时刻,里面只能存在一个值,后来的值将替代/覆盖掉前面的值(前面的值永远找不到,没有撤销) 5)、使用变量注意项:A、变量本身存在 B、变量的值要存在 C、使用时一定要存在于作用域之内 其作用域:从定义开始,到离它最近的左大括号相对的右大括号结束。 6)、变量使用步骤: 注意:变量一旦被使用,那么必须保证它的值已经存在(形式参数除外) 关于Java常量与变量就讲到这里,明天我们再看Java数据类型,感谢关注乐字节! 乐字节原创,转载请注明出处!

July 3, 2019 · 1 min · jiezi

乐字节Java变量与数据结构之一Java编程规范关键字和标识符

大家好,我是乐字节的小乐,这次要给大家带来的是Java变量与数据类型。本文是第一集:Java编程规范,关键字与标识符。 一、编程规范任何地方的名字都需要见名知意; 代码适当缩进 书写过程成对编程 对代码进行合理注释 二、关键字1)、定义被Java语言赋予特定含义的单词 2)、特点全部小写 3)、注意事项A:goto和const作为保留字存在。 B:类似于Notepad++这样的高级记事本会对关键字有特殊颜色标记 4)、Java所有关键字和保留字 5)、常用关键字 三、标识符 (取的名字)1)、定义就是给类,接口,方法,变量等起名字的字符序列 2)、组成规则:A:英文大小写字母(字符统称-->中英文皆可,强烈不推荐使用中文) B:数字 C:$和_ 3)、注意事项:A:不能以数字开头 B:不能是java中的关键字 C:区分大小写 4)、常见的命名规则(见名知意)A:包 全部小写 单级包:小写 举例: com,shsxt,helloworld 多级包:小写,并用.隔开 举例:com.shsxt.helloworld 域名倒着写+模块名称 B:类或者接口 一个单词:首字母大写 举例:Student,Demo 多个单词:每个单词首字母大写 举例:HelloWorld,StudentName C:方法或者变量 一个单词:首字母小写 举例:name,main 多个单词:从第二个单词开始,每个单词首字母大写 举例:studentAge,showAllNames() D:常量 全部大写 一个单词:大写 举例:PI 多个单词:大写,并用_隔开 举例:STUDENT_MAX_AGE 命名规范:见名知意 四、注释1)、定义就是对程序进行解释说明的文字 2)、分类:A:单行注释 // B:多行注释 / 注释的内容 / C:文档注释(后面讲) /* / 3)、把HelloWorld案例写了一个带注释的版本。后面我们要写一个程序的过程。 需求: 分析: 实现: 代码体现: 4)、注释的作用A:解释说明程序,提高了代码的阅读性。 B:可以帮助我们调试程序。 后面我们会讲解一个更高端的一个调试工具 这次就到这里,后面会继续给大家带来第二集:Java常量与变量,请关注乐字节,,乐字节原创,欢迎关注,转载请注明出处

July 2, 2019 · 1 min · jiezi

JS进阶你真的掌握变量和类型了吗

导读变量和类型是学习JavaScript最先接触到的东西,但是往往看起来最简单的东西往往还隐藏着很多你不了解、或者容易犯错的知识,比如下面几个问题: JavaScript中的变量在内存中的具体存储形式是什么?0.1+0.2为什么不等于0.3?发生小数计算错误的具体原因是什么?Symbol的特点,以及实际应用场景是什么?[] == ![]、[undefined] == false为什么等于true?代码中何时会发生隐式类型转换?转换的规则是什么?如何精确的判断变量的类型?如果你还不能很好的解答上面的问题,那说明你还没有完全掌握这部分的知识,那么请好好阅读下面的文章吧。 本文从底层原理到实际应用详细介绍了JavaScript中的变量和类型相关知识。 一、JavaScript数据类型ECMAScript标准规定了7中数据类型,其把这7种数据类型又分为两种:原始类型和对象类型。 原始类型 Null:只包含一个值:nullUndefined:只包含一个值:undefinedBoolean:包含两个值:true和falseNumber:整数或浮点数,还有一些特殊值(-Infinity、+Infinity、NaN)String:一串表示文本值的字符序列Symbol:一种实例是唯一且不可改变的数据类型(在es10中加入了第七种原始类型BigInt,现已被最新Chrome支持) 对象类型 Object:自己分一类丝毫不过分,除了常用的Object,Array、Function等都属于特殊的对象二、为什么区分原始类型和对象类型2.1 不可变性上面所提到的原始类型,在ECMAScript标准中,它们被定义为primitive values,即原始值,代表值本身是不可被改变的。 以字符串为例,我们在调用操作字符串的方法时,没有任何方法是可以直接改变字符串的: var str = 'ConardLi';str.slice(1);str.substr(1);str.trim(1);str.toLowerCase(1);str[0] = 1;console.log(str); // ConardLi在上面的代码中我们对str调用了几个方法,无一例外,这些方法都在原字符串的基础上产生了一个新字符串,而非直接去改变str,这就印证了字符串的不可变性。 那么,当我们继续调用下面的代码: str += '6'console.log(str); // ConardLi6你会发现,str的值被改变了,这不就打脸了字符串的不可变性么?其实不然,我们从内存上来理解: 在JavaScript中,每一个变量在内存中都需要一个空间来存储。 内存空间又被分为两种,栈内存与堆内存。 栈内存: 存储的值大小固定空间较小可以直接操作其保存的变量,运行效率高由系统自动分配存储空间JavaScript中的原始类型的值被直接存储在栈中,在变量定义时,栈就为其分配好了内存空间。 由于栈中的内存空间的大小是固定的,那么注定了存储在栈中的变量就是不可变的。 在上面的代码中,我们执行了str += '6'的操作,实际上是在栈中又开辟了一块内存空间用于存储'ConardLi6',然后将变量str指向这块空间,所以这并不违背不可变性的特点。 2.2 引用类型堆内存: 存储的值大小不定,可动态调整空间较大,运行效率低无法直接操作其内部存储,使用引用地址读取通过代码进行分配空间相对于上面具有不可变性的原始类型,我习惯把对象称为引用类型,引用类型的值实际存储在堆内存中,它在栈中只存储了一个固定长度的地址,这个地址指向堆内存中的值。 var obj1 = {name:"ConardLi"}var obj2 = {age:18}var obj3 = function(){...}var obj4 = [1,2,3,4,5,6,7,8,9] 由于内存是有限的,这些变量不可能一直在内存中占用资源,这里推荐下这篇文章JavaScript中的垃圾回收和内存泄漏,这里告诉你JavaScript是如何进行垃圾回收以及可能会发生内存泄漏的一些场景。当然,引用类型就不再具有不可变性了,我们可以轻易的改变它们: obj1.name = "ConardLi6";obj2.age = 19;obj4.length = 0;console.log(obj1); //{name:"ConardLi6"}console.log(obj2); // {age:19}console.log(obj4); // []以数组为例,它的很多方法都可以改变它自身。 ...

May 28, 2019 · 5 min · jiezi

Javascript 函数和变量提升

变量提升和函数提升基本上是面试必问题目//先从一个面试题说起 console.log(a) if (a) { var a = 1; console.log(a) } function a() { console.log(this); } console.log(a); a() 下面我们针对这个栗子解析一下我们知道变量和很熟定义都会提升到作用域最前边唯一需要确认的是变量和函数的先后顺序我们预想 函数是用第一公民会不会提升到最前边呢?//如果是解析完顺序是这样的 function a() { console.log(this); } var a; console.log(a) if (a) { a = 1; console.log(a) } console.log(a); a()按照我们预想的解析结果应该是// undefined// undefined// 报错理由 函数在上var在下,第一个console时a未赋值,其结果是undefined,if为false 只剩最后一个console也是undefined 最后a is not a function.不过结果是我机智的认为 预想错了?//再次测试 var a; function a() { console.log(this); } console.log(a) if (a) { a = 1; console.log(a) } console.log(a); a()这样?对比一下结果人工解析结果 :1、a()2、13、14、a() 报错浏览器执行结果:没毛病!看到这里一切完美,不过我还是重新搜索了一些高质量文章,发现我错了,虽然执行结果是对的,不过浏览器和人工解析还是不一样的,和我们最开始预想的一样,函数优先。既然标题说到了 变量 和 函数,我们就一块来说说//简单的栗子function a(){ console.log(a) }console.log(a)var a = 1a()首先上边已经说到我们预想和认为的是错的。正确解析顺序是这样的function a(){ console.log(a) }var a;console.log(a)a = 1a()但是,这个但是很重要浏览器执行结果是:why?这就要讲讲我所了解到的原理。同名变量和函数,函数会提升到最前边,变量其次,为什么不那为什么结果不是我们人工执行的undefined呢?原因是 变量会被忽略,是的是忽略。。。function a(){ console.log(a) }var a;//忽略console.log(a) //打印函数本身a = 1a()// a is not a function完美!还有呢?是的还有同名变量是怎样的顺序,同名函数是怎样的顺序。同名变量console.log(a)var a = 1console.log(a)var a = 2console.log(a)//解析完顺序是这样的var a;var a; //忽略console.log(a) // undfineda = 1console.log(a) //1a = 2console.log(a)//2*同名变量,声明会被提升,后边会忽略。同名函数function a(){console.log(1)}console.log(a)function a(){console.log(2)}console.log(a)a()//解析完function a(){console.log(1)}function a(){console.log(2)}console.log(a)console.log(a)a()执行结果我想你已经猜到了,同名函数会被覆盖。终于完了!您的点赞是我继续下去的动力,谢谢! ...

January 8, 2019 · 1 min · jiezi

Javascript中的变量提升、函数提升及变量访问原则

1、变量提升什么是变量提升?在函数体内声明的变量,无论你是在函数的最底端还是中间声明的,那么都会把该变量的声明提升到函数的最顶端(相当于第一行),但是只是提升变量的声明,不会赋值。var num = 10;fun(); //输出结果为undefinedfunction fun(){ console.log(num); var num = 20;}/上面这个函数相当于: function fun(){ var num; console.log(num); num = 20; }/2、函数提升什么是函数提升?在JavaScript中以函数声明的方式创建的函数就跟用var创建的变量一样,它们的声明都会提前声明,这就使得我们在JavaScript中可以调用函数在前面,而声明函数在后面,这就是函数提升。func();function func(){ alert(“函数执行了!”);}/上面这段代码相当于:function func(){ alert(“函数执行了!”);}func();/3、函数与变量同名时的变量提升alert(fun); // 最终输出结果为:输出fun函数体function fun(){ alert(“我是一个函数”);}var fun = “我是一个变量”;alert(fun); // 输出:我是一个变量/* 为什么第一个alert输出的是fun函数体,而第二个alert输出的是“我是一个变量”?因为用var声明的变量及function声明的函数在执行前都会将声明提升到最前面,如果变量与函数同名,那么在声明的时候会忽略变量,只提升函数声明! *//上面这段代码相当于:function fun(){ alert(“我是一个函数”);}alert(fun);fun = “我是一个变量”;alert(fun);/4、变量搜索原则(变量访问原则)在JavaScript中变量的访问(搜索)是有原则的:1)、首先在访问变量的作用域(函数)中查找该变量,如果找到直接使用2)、如果没有找到,去上一级作用域中查找,如果找到直接使用3)、如果还是没有找到,则再去上一级作用域中查找,知道全局作用域4)、如果找到了就直接使用,如果没有找到则报错var num = 123;function foo1(){ function foo2(){ console.log(num); } /当调用foo2时,会首先去foo2这个作用域中查找是否有num变量,结果没找到则去上一级作用域(即foo1)中查找是否有foo1变量, 结果还 是没找到,则再去上一级作用域(全局作用域)中查找,结果找到了,则拿来使用/ foo2();}5、变量提升、变量搜索机制经典面试题fun();console.log(b);console.log(c);console.log(a);functoin fun(){ var a = b = c = 9; console.log(a); console.log(b); console.log(c);}

January 4, 2019 · 1 min · jiezi

【前端面试】变量和类型计算

1.题目1.JS使用typeof能得到哪些类型=== 和 == 的选择JS中有哪些内置函数JS变量按存储方式分为哪些类型,并描述其特点如何理解JSON2.知识点2.1 值类型和引用类型值类型(boolean,string,number,null,undefined)var a = 10;var b = a;a = 20;console.log(b); //10引用类型(对象,数组,函数)var a = {x:10}var b = a;a.x = 20;console.log(b); //20值类型直接把值存储在堆中,把a赋值给b在内存中是又给b开辟了一块新的空间,存储了同样的值。引用类型分两块存储,先在堆中存储一个实际的值,再在栈中存储一个堆中值的引用地址,指向堆中的对象。把a赋值给b是在栈中重新开辟一块空间存储的还是相同对象的引用地址,a和b存储的地址相同,指向的对象也相同。当对象值发生改变时,两者会同时改变。引用类型的值一般都比较大,采用此种存储方式可以节省内存空间。2.2 typeof运算符typeof ‘abc’ //stringtypeof 123 //numbertypeof true //booleantypeof undefined //undefinedtypeof null //objecttypeof {a:10} //objecttypeof [1,2,3] //objecttypeof console.log() //function2.3 类型转换强类型转换:通过String(),Number(),Boolean(),parseInt()函数强制转换可能发生隐式类型转换的场景字符串拼接使用==if语句逻辑循环一、首先看双等号前后有没有NaN,如果存在NaN,一律返回false。二、再看双等号前后有没有布尔,有布尔就将布尔转换为数字。(false是0,true是1)三、接着看双等号前后有没有字符串, 有三种情况:1、对方是对象,对象使用toString()或者valueOf()进行转换;2、对方是数字,字符串转数字;(前面已经举例)3、对方是字符串,直接比较;4、其他返回false四、如果是数字,对方是对象,对象取valueOf()或者toString()进行比较, 其他一律返回false五、null, undefined不会进行类型转换, 但它们俩相等上面的转换顺序一定要牢记,面试的时候,经常会出现类型的问题。‘100’==100 //转换成字符串’’==0 //转换成falseundefined == null; // true1 == true; // true2 == true; // false0 == false; // true0 == ’ ‘; // trueNaN == NaN; // false[] == false; // true[] == ![]; // true//在if中转换成false的:nullundefined’‘NaN0false10 && 0 //0 10转换成true’’ || ‘abc’ //abc ‘‘转换成false!window.abc //true 2.4 null和undefined的区别null:是被赋值过的对象,刻意把一个对象赋值为null,故意表示其为空,不应有值,所以对象为null是正常的,typeof null 返回 ‘object’ ,null可以转换为0undefined 表示“缺少值”,即此处应有一个值,但还没有定义;转为数值时为NaN(非数字值的特殊值) typeof undefined 返回 ‘undefined'3.题目解答3.1 JS使用typeof能得到哪些类型typeof ‘abc’ //stringtypeof 123 //numbertypeof true //booleantypeof undefined //undefinedtypeof null //objecttypeof {a:10} //objecttypeof [1,2,3] //objecttypeof console.log() //function3.2 === 和 == 的选择jquery源码中的写法:除了以下方式其他全部使用 ===if(obj.a == null){ //相当于 obj.a === undefined || obj.a === null}3.3 JS中有哪些内置函数单纯作为语言来说,不考虑node和浏览器webObjectArrayBooleanNumberStringFunctionDateRegExpError内置对象:Math,JSON3.4 JS变量按存储方式分为哪些类型,并描述其特点值类型何引用类型3.5 如何理解JSONJSON是JS中的一个内置对象区别JS对象 {x:10}JSON对象 {‘x’:10}JSON串 “{‘x’:10}”//将JS对象转换成json串JSON.stringify({x:10});//将json字符串转换成json对象JSON.parse("{‘x’:10}");3.6 严格模式目的消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为; 消除代码运行的一些不安全之处,保证代码运行的安全;提高编译器效率,增加运行速度;为未来新版本的Javascript做好铺垫。特性 “use strict”;可以选择放在一个函数中或自定义作用域中。禁止this指向全局对象 function f(){ return !this; } // 返回false,因为"this"指向全局对象,"!this"就是false function f(){ “use strict”; return !this; } // 返回true,因为严格模式下,this的值为undefined,所以"!this"为true。创设eval作用域正常模式下,Javascript语言有两种变量作用域(scope):全局作用域和函数作用域。严格模式创设了第三种作用域:eval作用域。正常模式下,eval语句的作用域,取决于它处于全局作用域,还是处于函数作用域。严格模式下,eval语句本身就是一个作用域,不再能够生成全局变量了,它所生成的变量只能用于eval内部。 “use strict”; var x = 2; console.info(eval(“var x = 5; x”)); // 5 console.info(x); // 2全局变量显式声明 v = 1; // 报错,v未声明 for(i = 0; i < 2; i++) { // 报错,i未声明 }禁止删除变量严格模式下无法删除变量。只有configurable设置为true的对象属性,才能被删除。 “use strict”; var x; delete x; // 语法错误 var o = Object.create(null, {‘x’: { value: 1, configurable: true }}); delete o.x; // 删除成功函数不能有重名的参数保留字为了向将来Javascript的新版本过渡,严格模式新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield。使用这些词作为变量名将会报错。 function package(protected) { // 语法错误 “use strict”; var implements; // 语法错误 }3.7 eval1.没有必须使用的应用场景2.不容易调试,可读性不好3.在旧的浏览器中如果你使用了eval,性能会下降10倍。4.容易xss ...

January 3, 2019 · 2 min · jiezi

一眼看穿????JS变量,作用域和内存问题

这篇文章将梳理下环境,作用域链,变量对象和活动对象,以及内存管理问题。基本类型和引用类型的值我们都知道JS中的数据类型有两大类,基本数据类型和引用数据类型,下面从三个方面来解剖他们①保存方式基本类型的值是指简单的数据段,引用类型的值是指那些可能由多个值构成的对象。基本类型按值访问可以直接操作保存在变量中实际的值引用类型按引用地址访问保存在内存中的对象,而JS不能不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间,所以说在实际操作过程中操作的是对象的引用,而不是实际的对象。②复制变量值基本类型在复制变量值的时候,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上。也就是说基础类型的值复制给新变量后,会在栈内存中开辟一个新的地址空间去存储值,原值和复制值参与任何操作都互不影响引用类型在复制变量值的时候,同样会在栈内存中开辟一个新的地址空间去存储值,只不过,引用类型复制的是指针,原值和复制值的指针指向同一堆内存中存储的值,也就是说着两个变量实际上将引用同一对象,因此改变其中一个变量,就会影响到另一个变量。③传递参数先了解一个基本原则,ECMAScript中所有函数的参数都是按值传递的,千万不能觉得在局部作用域中修改的对象会在全局作用域中反映出来,就说明参数是按引用传递的。根据这个原则,如果参数值是基本类型的,在函数内部修改值,并不会影响到函数外部的值,但如果是引用类型的,参数依旧是值传递,只不过传递的是栈内存的地址值,因此函数内部的修改会影响到函数外部的值。下面看一个????let obj_value = { a: 1, b: 2}function func(val) { val.a = 3 val.c = 6 console.log(val) // {a: 3, b: 2, c: 6}}console.log(obj_value) // {a: 1, b: 2}func(obj_value)console.log(obj_value) // {a: 3, b: 2, c: 6}下面????能证明引用类型的参数也是按值传递的function func(obj) { obj.a = 1 obj = {} obj.a = 2}let test = {}func(test)console.log(test.a) // 1上面的????,按照我们理解应该打印出a=2,但事与愿违,首先,test在函数func中新增了一个a属性并赋值为1,此时,obj中传递的是引用类型在栈内存中存储的地址值,也就是说函数内的obj复制的是test地址,他们两个共同指向一个对象,因此通过obj新增,修改删除操作都会反映到函数外部,接下来再看函数内的第二条语句,obj={},这就不得了了,这是重写,也就是说它会抹去obj原本存储的地址值,这就切断了test和obj共同指向一个对象这个联系,因此第三条语句,obj.a=2就是函数内部的事情了。所以总结一句话,引用类型的增删改操作与其关联所有对象都会受到波及和影响,重新就会切断自身与其余对象的联系检测类型typeof()(只适用于基本类型,不适用于对象)typeof函数可用于检测string,number,boolean,undefined,function还是symbol,但如果变量的值是引用类型或null,则typeof会返回object。ECMA-262规定任何在内部实现[[call]]方法的对象都应该在应用typeof操作符时返回"function"对于正则表达式类型的typeof检测,在IE和Firefox中会返回object,其余的返回function。let func = function() {}console.log(typeof (’’)) // stringconsole.log(typeof (1)) // numberconsole.log(typeof (true)) // booleanconsole.log(typeof (undefined)) // undefinedconsole.log(typeof ({})) // objectconsole.log(typeof (null)) // objectconsole.log(typeof (Symbol(’’))) //symbolconsole.log(typeof (func)) // functioninstanceof(只适用于对象,不适用于基本类型)instanceof操作符用于判断是什么类型的对象如果变量是给定引用类型的实例,那么instanceof操作符就会返回true根据规定,所有的引用类型的值都是Object的实例,因此在检测一个引用类型值和Object构造函数时,instanceof操作符始终会返回true,instanceof操作符检测基本类型的值,该操作符始终会返回false,因为基本类型不是对象。执行环境及作用域执行环境也称为环境,它定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。全局执行环境是最外围的一个执行环境,根据ECMAScript实现所在的宿主环境不同,表示执行环境的对象也不一样,在web浏览器中,全局执行环境被认为是window对象,因此,在浏览器中,创建的所有全局变量和函数都是作为window对象的属性和方法。ECMAScript程序中执行流的控制机制每个函数都有各自的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中,而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。作用域链代码在环境中执行,就会创建变量对象的作用域链,作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在的环境的变量对象,如果这个环境是函数,则将其活动对象作为变量对象。什么是活动对象呢?活动对象实际就是变量对象在真正执行时的另一种形式。活动对象一开始只包含一个变量,即arguments对象。作用域中的下一个变量对象来自外部环境,再下一个变量对象来自下一个环境,层层嵌套,一直延续到全局执行环境,全局执行环境的变量对象始终都是作用域链中的最后一个对象环境的访问是沿着作用域链进行的,作用域链是单向的,即由里到外,内部环境可以访问外部环境,反之不行。变量对象和活动对象的概念变量对象(VO)变量对象是与执行上下文对应的概念,定义执行上下文中的所有变量,函数以及当前执行上下文函数的参数列表,也就是说变量对象定义着一个函数内定义的参数列表、内部变量和内部函数变量对象的内部顺序是参数列表->内部函数->内部变量变量对象的创建过程检查当前执行环境的参数列表,建立Arguments对象。检查当前执行环境上的function函数声明,每检查到一个函数声明,就在变量对象中以函数名建立一个属性,属性值则指向函数所在的内存地址。检查当前执行环境上的所有var变量声明,每检查到一个var声明,如果VO(变量对象)中已存在function属性名,则调过,不存在就在变量对象中以变量名建立一个属性,属性值为undefined。变量对象是在函数被调用,但是函数尚未执行的时刻被创建的,这个创建变量对象的过程实际就是函数内数据(函数参数,内部变量,内部函数)初始化的过程。活动对象(AO)未进入执行阶段之前,变量对象中的属性都不能访问!但是进入执行阶段之后,变量对象转变为了活动对象,里面的属性都能被访问了,然后开始进行执行阶段的操作。所以活动对象实际就是变量对象在真正执行时的另一种形式。全局变量对象我们上面说的都是函数上下文中的变量对象,是根据执行上下文中的数据(参数、变量、函数)确定其内容的,全局上下文中的变量对象则有所不同。以浏览器为例,全局变量对象是window对象,全局上下文在执行前的初始化阶段,全局变量、函数都是被挂载倒window上的。执行上下文的生命周期延长作用域链执行环境的类型就两种——全局和局部(函数)延长作用域链的意思是在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除。延长方法(以下两个语句都会在作用域链的前端添加一个变量对象):try-catch语句的catch块:会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明。with语句:会指定的对象添加到作用域链中通过with语句延长作用域链function addLink() { let name = ‘george’ with(local) { var url = href + name // 此时通过with语句将local对象添加到addLink环境的头部,因此在addLink中就有权可以访问local对象的属性和方法 } return url }没有块级作用域JS只有函数作用域和全局作用域,没有块级作用域。声明变量var声明的变量会自动被添加到最接近的环境中在函数内部,最接近的环境就是函数的局部环境,在with语句中,最接近的环境是函数环境,初始化变量若没有通过var声明,该变量会自动被添加到全局环境。查询表示符当某个环境中为了读取和写入一个标识符时,必须通过搜索来确定标识符实际代表什么。搜索过程从作用域链的前端开始,沿着作用域链向上查找,一直追溯到全局环境变量对象,找到标识符,搜索过程停止,反之,返回undefined。垃圾收集JS具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存收集原理找出那些不再继续使用的变量,然后释放其占用的内存,为此垃圾收集器会按照固定的时间间隔(或代码中预定的收集时间),周期性地执行这一操作。收集方法标记清除引用计数标记清除(最常用的垃圾收集方式)原理:垃圾收集器在运行的时候回给存储在内存中的所有变量都加上标记,然后去掉环境中的变量以及被环境中的变量引用的变量的标记,最后删除被标记的变量。标记清除算法将“不再使用的对象”定义为“无法到达的对象”。即从根部(在JS中就是全局对象)出发定时扫描内存中的对象,凡是能从根部到达的对象,保留。那些从根部出发无法触及到的对象被标记为不再使用,稍后进行回收。引用计数原理:通过名字很好理解,引用计数,就是跟踪记录每个值被引用的次数,当引用次数为0时,将其删除。计数方法:当声明一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1,如果同一个值被赋给另一个变量,则该值的引用次数加1,相反,包含这个值引用的变量又取的另一个值,则这个值的引用次数减1。引用计数的严重问题——循环引用循环引用指的是对象A中包含一个指向对象B的指针,而对象B中也包含一个指向对象A的引用。当出现循环引用的时候,引用次数永远不可能为0,这会导致内存得不到回收。解决方法:手动断开不需要的引用,即,将引用对象置为null立即执行垃圾回收函数IE中:window.CollectGarbage()Opera7或更高版本:window.opera.collect()管理内存分配给web浏览器的可用内存数量通常要比分配给桌面应用程序的少对于浏览器而言,确保占用最少的内存可以让页面获得更好的性能。优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据,一旦数据不再有用,最好通过将其值设置为null来释放其引用,这个做法叫做解除引用。这一做法适用于大多数全局变量和全局对象的属性,局部变量会在它们离开执行环境时自动被解除引用。 ...

December 9, 2018 · 1 min · jiezi

PHP变量的引用赋值与传值赋值

一、使用 memory_get_usage() 查看PHP内存使用量1. 传值赋值// 定义一个变量$a = range(0, 10000);var_dump(memory_get_usage());// 定义变量b,将a变量的值赋值给b$b = $a;var_dump(memory_get_usage());// 对a进行修改// COW: Copy-On-Write$a = range(0, 10000);var_dump(memory_get_usage());输出结果:int(989768)int(989856)int(1855608)定义一个变量 $a = range(0, 10000);$b = $a;对a进行修改 $a = range(0, 10000);PHP写时复制机制(Copy-on-Write,也缩写为COW)顾名思义,就是在写入时才真正复制一份内存进行修改。COW最早应用在Unix系统中对线程与内存使用的优化,后面广泛的被使用在各种编程语言中,如C++的STL等。 在PHP内核中,COW也是主要的内存优化手段。在通过变量赋值的方式赋值给变量时,不会申请新内存来存放新变量的值,而是简单的通过一个计数器来共用内存。只有在其中的一个引用指向变量的值发生变化时,才申请新空间来保存值内容,以减少对内存的占用。在很多场景下PHP都使用COW进行内存的优化。比如:变量的多次赋值、函数参数传递,并在函数体内修改实参等。2. 引用赋值// 定义一个变量$a = range(0, 10000);var_dump(memory_get_usage());// 定义变量b,将a变量的引用赋给b$b = &$a;var_dump(memory_get_usage());// 对a进行修改$a = range(0, 10000);var_dump(memory_get_usage());输出结果:int(989760)int(989848)int(989840)定义一个变量 $a = range(0, 10000);定义变量b,将a变量的引用赋给b $b = &$a;对a进行修改 $a = range(0, 10000);二、使用 xdebug_debug_zval() 查看变量的引用情况xdebug_debug_zval() 用于显示变量的信息。需要安装xdebug扩展。1. 传值赋值$a = 1;xdebug_debug_zval(‘a’);// 定义变量b,把a的值赋值给b$b = $a;xdebug_debug_zval(‘a’);xdebug_debug_zval(‘b’);// a进行写操作$a = 2;xdebug_debug_zval(‘a’);xdebug_debug_zval(‘b’);输出结果:a: (refcount=1, is_ref=0)=1a: (refcount=2, is_ref=0)=1b: (refcount=2, is_ref=0)=1a: (refcount=1, is_ref=0)=2b: (refcount=1, is_ref=0)=1定义变量 $a = 1;$a = 1;xdebug_debug_zval(‘a’);输出a: (refcount=1, is_ref=0)=1refcount=1 表示该变量指向的内存地址的引用个数变为1is_ref=0 表示该变量不是引用定义变量 $b ,把 $a 的值赋给 $b, $b = $a;$b = $a;xdebug_debug_zval(‘a’);xdebug_debug_zval(‘b’);输出a: (refcount=2, is_ref=0)=1b: (refcount=2, is_ref=0)=1refcount=2 表示该变量指向的内存地址的引用个数变为2is_ref=0 表示该变量不是引用对变量 $a 进行写操作 $a = 2;$a = 2;xdebug_debug_zval(‘a’);xdebug_debug_zval(‘b’);输出a: (refcount=1, is_ref=0)=2b: (refcount=1, is_ref=0)=1因为COW机制,对变量 $a 进行写操作时,会为变量 $a 新分配一块内存空间,用于存储变量 $a 的值。此时 $a 和 $b 指向的内存地址的引用个数都变为1。2. 引用赋值$a = 1;xdebug_debug_zval(‘a’);// 定义变量b,把a的引用赋给b$b = &$a;xdebug_debug_zval(‘a’);xdebug_debug_zval(‘b’);// a进行写操作$a = 2;xdebug_debug_zval(‘a’);xdebug_debug_zval(‘b’);a: (refcount=1, is_ref=0)=1a: (refcount=2, is_ref=1)=1b: (refcount=2, is_ref=1)=1a: (refcount=2, is_ref=1)=2b: (refcount=2, is_ref=1)=2定义变量 $a = 1;$a = 1;xdebug_debug_zval(‘a’);输出a: (refcount=1, is_ref=0)=1refcount=1 表示该变量指向的内存地址的引用个数变为1is_ref=0 表示该变量不是引用定义变量 $b ,把 $a 的引用赋给 $b, $b = &$a;$b = &$a;xdebug_debug_zval(‘a’);xdebug_debug_zval(‘b’);输出a: (refcount=2, is_ref=1)=1b: (refcount=2, is_ref=1)=1refcount=2 表示该变量指向的内存地址的引用个数变为2is_ref=1 表示该变量是引用对变量 $a 进行写操作 $a = 2;$a = 2;xdebug_debug_zval(‘a’);xdebug_debug_zval(‘b’);输出a: (refcount=2, is_ref=1)=2b: (refcount=2, is_ref=1)=2因为变量 $a 和变量 $b 指向相同的内存地址,其实引用。对变量 $a 进行写操作时,会直接修改指向的内存空间的值,因此变量 $b 的值会跟着一起改变。三、当变量时引用时,unset()只会取消引用,不会销毁内存空间$a = 1;$b = &$a;// unset 只会取消引用,不会销毁内存空间unset($b);echo $a;输出1定义变量 $a ,并将 $a 的引用赋给变量 $b$a = 1;$b = &$a;销毁 $bunset($b);输出 $a虽然销毁的 $b,但是 $a 的引用和内存空间依旧存在。echo $a;输出1四、php中对象本身就是引用赋值class Person{ public $age = 1;}$p1 = new Person;xdebug_debug_zval(‘p1’);$p2 = $p1;xdebug_debug_zval(‘p1’);xdebug_debug_zval(‘p2’);$p2->age = 2;xdebug_debug_zval(‘p1’);xdebug_debug_zval(‘p2’);p1: (refcount=1, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }p1: (refcount=2, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }p2: (refcount=2, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }p1: (refcount=2, is_ref=0)=class Person { public $age = (refcount=1, is_ref=0)=2 }p2: (refcount=2, is_ref=0)=class Person { public $age = (refcount=1, is_ref=0)=2 }实例化对象 $p1 = new Person;$p1 = new Person;xdebug_debug_zval(‘p1’);输出p1: (refcount=1, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }refcount=1 表示该变量指向的内存地址的引用个数变为1is_ref=0 表示该变量不是引用把 $p1 赋给 $p2$p2 = $p1;xdebug_debug_zval(‘p1’);xdebug_debug_zval(‘p2’);输出p1: (refcount=2, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }p2: (refcount=2, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }refcount=2 表示该变量指向的内存地址的引用个数变为2对 $p2 中的属性 age 进行写操作$p2->age = 2;xdebug_debug_zval(‘p1’);xdebug_debug_zval(‘p2’);输出p1: (refcount=2, is_ref=0)=class Person { public $age = (refcount=1, is_ref=0)=2 }p2: (refcount=2, is_ref=0)=class Person { public $age = (refcount=1, is_ref=0)=2 }因为php中对象本身就是引用赋值。对 $p2 中的属性 age 进行写操作时,会直接修改指向的内存空间的值,因此变量 $p1 的 age 属性的值会跟着一起改变。五、实战例题分析/** * 写出如下程序的输出结果 * * $d = [‘a’, ‘b’, ‘c’]; * * foreach($d as $k => $v) * { * $v = &$d[$k]; * } * * 程序运行时,每一次循环结束后变量 $d 的值是什么?请解释。 * 程序执行完成后,变量 $d 的值是什么?请解释。 */1. 第一次循环推算出进入 foreach 时 $v、$d[$k] 的值$k = 0$v = ‘a’$d[$k] = $d[0] = ‘a’此时,$v 和 $d[0] 在内存中分别开辟了一块空间![$v 和 $d[0] 在内存中分别开辟了一块空间](http://md.ws65535.top/xsj/201...$v = &$d[0] 改变了 $v 指向的内存地址$v = &$d[0]![$v = &$d[0] 改变了 $val 指向的内存地址](http://md.ws65535.top/xsj/201…第一次循环后 $d 的值:[‘a’, ‘b’, ‘c’]2. 第二次循环进入 foreach 时 $v 被赋值为 ‘b’,此时$v指向的内存地址与 $d[0] 相同,且为引用,因此 $d[0] 的值被修改为 ‘b’$v = ‘b’ => $d[0] = ‘b’![$v = ‘b’ => $d[0] = ‘b’](http://md.ws65535.top/xsj/201…推算出进入 foreach 时 $d[$k] 的值$k = 1$d[$k] = $d[1] = ‘b’![$d[2] = ‘b’](http://md.ws65535.top/xsj/201...$v = &$d[1] 改变了 $v 指向的内存地址$v = &$d[1]![$v = &$d[1]](http://md.ws65535.top/xsj/201…第二次循环后 $d 的值[‘b’, ‘b’, ‘c’]3. 第三次循环进入 foreach 时 $v 被赋值为 ‘c’,此时$v指向的内存地址与 $d[1] 相同,且为引用,因此 $d[1] 的值被修改为 ‘c’$v = ‘c’ => $d[1] = ‘c’![$v = ‘c’ => $d[1] = ‘c’](http://md.ws65535.top/xsj/201…推算出进入 foreach 时 $d[$k] 的值$k = 2$d[2] = ‘c’![$d[2] = ‘c’](http://md.ws65535.top/xsj/201...$v = &$d[2] 改变了 $v 指向的内存地址$v = &$d[2]![$v = &$d[2]](http://md.ws65535.top/xsj/201…第三次循环后 $d 的值[‘b’, ‘c’, ‘c’]4. 实测$d = [‘a’, ‘b’, ‘c’];foreach ($d as $k=>$v){ $v = &$d[$k]; print_r($d);}print_r($d);输出:Array( [0] => a [1] => b [2] => c)Array( [0] => b [1] => b [2] => c)Array( [0] => b [1] => c [2] => c)Array( [0] => b [1] => c [2] => c) ...

September 2, 2018 · 3 min · jiezi