1.JS中数据类型有哪些
a.JavaScript包含5种基本数据类型,分别是 Undefined / Null / Boolean / Number / String ,基本数据类型就这五种。
b.JavaScript包含一种类型,Object,Object类型是所有对象的基类。
c.JavaScript中并没有浮点数和整数之分,统一用Numer来表示。
2.变量,作用域,内存问题
(一)变量
a.JavaScript变量分为两种:基本类型和引用类型。其中基本类型就是前面提到的5种基本数据类型,引用类型就是前面提到的 Object 以及基于它的其他复杂数据类型。
基本数据类型:在内存中占据实际大小的空间,赋值的时候,会在内存中创建一份新的副本。保存在 栈内存 中。(按值访问)
引用类型:引用类型数据在栈内存中保存的实际上是对象在堆内存中的引用地址。通过这个引用地址可以快速查找到保存中堆内存中的对象,赋值的时候,只是创建了一个新的指针指向对象。保存在 堆内存 中。
b.变量的内存分配:基本类型在内存中是实际的值;而引用类型在内存中就是一个指针,指向一个对象,多个引用类型可能同时指向同一个对象。确定一个变量是哪种基本类型用typeof操作符。确定一个变量是哪种引用类型用instanceof操作符。
(二)作用域:变量是在某个特定的作用域中声明的,作用域决定了这些变量的生命周期,以及哪些代码可以访问其中的变量。
a.变量是在某个特定的作用域中声明的,作用域决定了这些变量的生命周期,以及哪些代码可以访问其中的变量。
b.JavaScript作用域只包括全局作用域和函数作用域,es6中加入了块级作用域,let声明。
c.作用域是可以嵌套的,从而形成作用域链。由于作用域链的存在,可以让变量的查找向上追溯,即子函数可以访问父函数的作用域=>祖先函数的作用域=>直到全局作用域,这种函数我们也称为闭包()
(三)内存问题:JavaScript引擎具有自动垃圾回收机制,不需要太关注内存分配和垃圾回收问题。这儿就不展开了!
3.JS引用类型
Object是唯一的复杂数据类型,引用类型都是从Object类型上继承而来。JavaScript又可以往引用类型上加属性和方法。那么,函数也可以!这也是JavaScript函数强大和复杂的地方。也就是说:函数也可以拥有自定义方法和属性
Array:数组类型
Date:日期类型
RegExp :正则表达式类型
Function:函数类型
等等
4.typeOf返回的数据类型
console.log(typeof undefined); //undefined
console.log(typeof 123); //number
console.log(typeof NaN); //number
console.log(typeof '123'); //string
console.log(typeof true); //boolean
console.log(typeof [1,2,3]); //object
console.log(typeof {"id": 11}); //object
console.log(typeof null); //object
console.log(typeof console.log); //function
console.log(typeof typeof []); //string
注意:
typeof 返回的任何一个结果都是字符串类型 如:'number','bpolean' 都是以字符串的形式存在的
判断一个数组类型:
a.从构造函数入手,obj instanceof Array ,typeof a != 'undefined' 判断a变量存在。而instanceof只会返回一个布尔值。
b.调用对象原型中的toString方法, Object.prototype.toString.call(obj);因为很多对象继承的toString()方法被重写了,为了能够调用正确的toString()版本,也就是最原始的版本。可以使用Function.call()的方法,其中call可以这么理解,相当于obj去借用这个 Object.prototype.toString();
Object.prototype.toString.call(new Date()); //"[object Date]"
Object.prototype.toString.call(Window); //"[object window]"
Object.prototype.toString.call(/./); //"[object RegExp]"
5.类型转换
对象在转换基本类型时,首先会调用 valueOf 然后调用 toString。并且这两个方法你是可以重写的。
6.函数
a.函数的调用方式
(1)function 命令:function命令声明的代码区块,就是一个函数。function命令后面是函数名,函数名后面是一对圆括号,里面是传入函数的参数。函数体放在大括号里面。
(2)函数表达式:除了用function命令声明函数,还可以采用变量赋值的写法。
(3)Function构造函数定义:通过Function构造函数创建函数,可向构造函数中传入任意数量的参数,但值得注意的是传入的最后一个参数会作为函数体,而其他参数则作为参数传入函数中。用该方法去定义函数是不推荐使用的,因为该语法会导致解析两次代码,第一次解析常规ECMAScript代码,第二次解析传入构造函数的字符串,影响性能。
b.函数内部属性
(1) arguments:包含函数所有参数的伪数组, 其arguments.callee属性指向含有该arguments对象的函数。该属性可用于递归函数的函数调用
function factorial(num){
if(num<=1){ return 1; }
else{ return num*arguments.callee(num-1); }
}//好处:低耦合
(2)this:函数执行的环境变量。
(3)caller:调用当前函数的函数引用。
c.函数的属性和方法
(1)length:该属性指定义函数时,需要传入参数的个数。使用为:函数名.length;
(2)prototype:原型函数。
(3)apply和call:方法均改变调用函数的环境对象,简而言之就是改变函数的this值。两者除了传入参数的方式不同外,没有什么区别。apply在传参时,可传入数组或伪数组arguments,call是将参数依次列出传入函数的
(4)bind():创建一个函数实例,其this值会被绑定到传给bind()函数的值。
注意:如果同一个函数被多次声明,后面的声明就会覆盖前面的声明。
(5)立即调用的函数表达式(IIFE)(function(){ /* code */ }());
(6)闭包: 闭包就是能够读取其他函数内部变量的函数,例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数.
var arr = [{name:"lyf",age:20},{name:"gulu",age:18}];
function nameSort(name){
return function(obj1,obj2){
return obj1[name]-obj2[name]; }
}
arr.sort(nameSort("age"));