JavaScript: ----es5重点回顾(一)

数据类型

es5及以前的JavaScript有六种数据类型,分别是:

  • number: 数值型,如:123
  • string: 字符型,如:'abc'
  • boolean: 布尔型,如:true或false
  • undefined: 未定义类型,只有undefined本身
  • null:空类型,只有null本身
  • object:对象,属于复合类型,又可以细分成Array,Function,RegExp等类型
 

类型判断

1.typeof

typeof常用来判断js中的数据类型

1 console.log(typeof 123)  // number
2 console.log(typeof 'abc')  // string
3 console.log(typeof true) // boolean
4 console.log(typeof undefined) // undefined
5 console.log(typeof null) // object  -->null被识别为object类型
6 console.log(typeof {}) // object
7 console.log(typeof []) // object  -->array被识别为object类型
8 console.log(typeof function(){}) // function 
9 console.log(typeof new RegExp()) // object  -->regexp被识别为object类型

缺点: 不能识别 null 、array以及regexp类型

 

2.instansceof

instansceof常用来判断某对象是否和某构造函数的prototype原型对象在同一条原型链上

console.log(123 instanceof Number) // false -->字面量形式的值会造成判断失误
console.log('abc' instanceof String) // false -->字面量形式的值会造成判断失误
console.log(true instanceof Boolean) // false -->字面量形式的值会造成判断失误
console.log({} instanceof Object) // true
console.log([] instanceof Array) // true
console.log(function(){} instanceof Function) // true
console.log(new RegExp instanceof RegExp) // true

缺点: 字面量形式的值不能通过instansceof来判断类型

 

3.constructor

1 console.log((123).constructor === Number) // true
2 console.log(('abc').constructor === String) // true
3 console.log((true).constructor === Boolean) // true
4 console.log(({}).constructor === Object) // true
5 console.log(([]).constructor === Array) // true
6 console.log((function(){}).constructor === Function) // true
7 console.log((new RegExp()).constructor === RegExp) // true

缺点: 更改构造函数的prototype原型对象后,实例的constructor会丢失

1 function fn (){
2 
3 }
4 fn.prototype = new RegExp()
5 
6 let obj = new fn()
7 
8 console.log(obj.constructor === fn) // false
9 console.log(obj.constructor === RegExp) // true
1 // instansceof依然可以正常判断
2 
3 obj instanceof fn // true
4 obj instanceof RegExp // true
 

4.Object.prototype.toString.call() (推荐使用)   

1 Object.prototype.toString.call(123) // "[object Number]"
2 Object.prototype.toString.call('abc') // "[object String]"
3 Object.prototype.toString.call(true) // "[object Boolean]"
4 Object.prototype.toString.call(undefined) // "[object Undefined]"
5 Object.prototype.toString.call(null) // "[object Null]"
6 Object.prototype.toString.call({}) // "[object Object]"
7 Object.prototype.toString.call([]) // "[object Array]"
8 Object.prototype.toString.call(function(){}) // "[object Function]"
9 Object.prototype.toString.call(new RegExp()) // "[object RegExp]"
 

Null和Undefined

null能够被转化成数字0,undefined则不可以。

1 Number(null) // 0
2 Number(undefined) // NaN
 

数值型Number

整数与浮点数

javascript语言底层没有整数的概念,在javascript内部,所有的数字都以64位浮点数的形式进行存储,所以数字1和数字1.0没有任何区别。

1 console.log(1 === 1.0) // true

在进行一些整数运算的时候,javascript会自动地把64位浮点数转换成32位整数,再进行运算。

而由于浮点数不是精确的值,所以在涉及小数的比较和运算时常常会出现怪异的结果,比如:

1 0.1 + 0.2 === 0.3 // false
 

数值范围

JavaScript 提供Number对象的MAX_VALUEMIN_VALUE属性,返回可以表示的具体的最大值和最小值。

1 Number.MAX_VALUE // 1.7976931348623157e+308
2 Number.MIN_VALUE // 5e-324
 

NaN

NaN是javascript数值类型中的特殊值,它表示的是 Not a Number,即“非数字”,主要出现在将字符串解析成数字出错的场合。(或者进行 0/0 运算的时候)

1 5 - 'a' // NaN
2 5 * 'a' // NaN
3 5 / 'a' // NaN
1 0 / 0 // NaN

NaN不等于任何值,包括它本身,NaN在布尔运算时会被当作false,NaN与任何数(包括它自己)的运算,得到的都是NaN

 

字符型String

在javascript中,字符串可以被视为数组(与数组依然有区别),因此可以使用方括号来取值

1 var str = 'abc'
2 str[0] // a
3 str[2] // c

同时可以用length属性来返回字符串的长度

1 var str = 'abc'
2 str.length // 3
 

布尔型Boolean

在javascript中,0,''"(空字符串),undefined,null,NaN以及false本身会被认为是false,其余值都会被认为是true。

 

对象Object

对象是js中的核心概念之一,简单来说,对象是由一组或多组“键值对”形成的集合,是一种无序的数据结构模型。

在js中,所有对象的键名都是字符串,所以加不加引号都可以(数字会被隐式转换成字符串)。

 

属性的读取

js里读取对象属性(上对应的值)有两种方法,第一种是通过点运算符,第二种是通过方括号运算符。

1 var obj = {
2   name: 'yoohohoho'  
3 }
4 
5 obj.name // yoohohoho
6 obj['name'] // yoohohoho
 

属性的赋值

赋值方式同读取

1 var obj = {}
2 obj.name = 'yoohohoho'
3 obj['age'] = 18
4 
5 console.log(obj) // {name: 'yoohohoho',age: 18}
 

属性的查看

查看一个对象本身的所有属性名,可以使用Object.keys()方法,该方法返回一个键名数组。

 

属性的删除

 delete命令用于删除对象自身的属性(及对应的值),成功后返回true(注意: 如果该属性不存在与对象之上,依然会返回true)

1 var obj = {}
2 obj.name = 'yoohohoho'
3 
4 console.log(obj) // {name: 'yoohohoho'}
5 
6 delete obj.name
7 
8 console.log(obj) // {}
 

判断属性是否存在

in运算符用于检查对象中是否包含某个属性(名),包含则返回true,不包含则返回false。

1 var obj = {}
2 obj.name = 'yoohohoho'
3 
4 
5 // 键名必须是一个字符串,右边是目标对象
6 'name' in obj // true

注意: in 运算符不能判断该属性是否为继承属性,如果要判断该属性是否为继承属性,应使用hasOwnProperty。

1 var obj = {}
2 
3 console.log('toString' in obj) // true
4 
5 console.log(obj.hasOwnProperty('toString')) // false
 

属性的遍历: for...in...

for...in可以遍历对象上的所有可枚举(enumerable)属性,包括对象继承的属性。结合hasOwnPropert方法来判断某个属性是否为对象自身的属性。

 

数组Array

本质上来说,js中的数组是一种特殊的对象。数组的特殊性体现在,它的键名是按次序排列的一组整数(0,1,2...)。

1 var arr = ['a','b','c']
2 
3 Object.keys(arr) // ["0","1","2"]

 

in运算符和for...in遍历

in运算符和for...in遍历同样适用于数组

 1 var arr = ['a','b','c']
 2 
 3 console.log(1 in arr) // true
 4 console.log('2' in arr) // true
 5 console.log(4 in arr) // false
 6 
 7 
 8 // 如果数组某个位置是空位,in运算符返回false
 9 
10 var arr2 = []
11 arr2[100] = 'a'
12 
13 console.log(100 in arr2) // true
14 console.log(1 in arr2) // false
15 
16 
17 for(var index in arr){
18   console.log(arr[index])  // 'a','b','c'
19 }

 for...in方法遍历数组时会遍历数组的非数字键(如果有),所以不推荐用for...in来遍历数组。

 

数组的空位

当数组的某个位置是空元素,即两个逗号之间没有任何值,我们称该数组存在空位。

空位不会影响数组的length属性。

1 var arr = [1,,3]  // arr  -->[1,empty,3]
2 arr.length // 3

如果数组内最后一个元素之后有逗号,不会产生空位。

1 var arr = [1,,3,]
2 arr.length // 3    arr -->[1,empty,3]

数组的空位是可以读取的,返回undefined。

使用delete命令删除一个数组成员,会形成空位,但不会影响数组的length属性。

数组中某个位置是空位和数组中某个位置是undefined,是不一样的(虽然空位返回的值是undefined)。具体体现在,空位会被数组的forEach方法、for...in方法、以及Object.keys()方法在遍历的时候跳过,而undefined不会被跳过

 

类似数组的对象 array-like object

如果一个对象的所有键名都是正整数或零,并且有(不可变)length属性,那么这个对象就可以被称为“类似数组的对象”(array-like object)。

典型的“类似数组的对象”是函数的arguments对象以及大多数DOM元素集,还有字符串。

 

函数Function

前面说过,对象是js中的核心概念之一,另一个重要的概念则是函数。

在js中,函数是第一等公民,这意味着函数与其他js中的数据类型地位平等,凡是可以使用值的地方,都可以使用函数

 1 function fn(){
 2   console.log('我是一个函数')  
 3 }
 4 
 5 var a = fn // 把函数当作一个值进行赋值操作
 6 
 7 
 8 // 把函数当作另一个函数的参数以及返回值进行操作
 9 function b (fn){
10     return fn 
11 }
12 
13 a()
14 b(fn)()
 

函数的属性和方法

name属性

函数的name属性用来返回函数的名称(如果是通过变量赋值操作定义的匿名函数,则name返回变量名;具名函数依然返回函数的函数名)。

1 function fn(){
2     
3 }
4 
5 fn.name // "fn"
1 var fn2 = function(){}
2 
3 fn2.name // "fn2'
4 
5 var fn3 = function add(a,b){ return a + b }
6 
7 fn3.name // "add"
 
length属性

函数的length属性返回函数形参的个数,和实际传入的参数无关。

1 function add(a,b){
2 
3 }
4 
5 add.length // 2
 
toString()方法

函数的toString方法返回一个字符串,内容是函数的源码。

对于原生的函数,toString方法返回function 函数名(){ [native code] }。

 

函数作用域

作用域(scope)指的是变量存在的范围。在es6以前,js中只有两种作用域:

一种是全局作用域,变量在整个程序中一直存在,所有地方都可以读取;另一种是函数作用域,变量只在函数内部存在,函数内部可以读取(注:es6以前没有块级作用域)。

函数内部优先读取此作用域内的变量,如果内部已有这个变量则不会再往外部寻找(变量遮蔽),如果内部没有找到则会到外层作用域寻找,直到找到全局作用域下(这里的作用域是指函数声明时所在的作用域,而非运行时所在的作用域)。

 
函数(和变量)提升

在函数(以及全局)作用域内,用function声明的函数(以及用var声明的变量)会被提升到代码头部,相当于在调用之前就已经声明了。

但是,如果调用赋值语句声明的函数,js会报错。

1 fn() // Uncaught TypeError: fn is not a function  -->js解析器不能识别为函数
2 
3 var fn = function(){
4   console.log(1)  
5 }
 

参数

参数的省略

在js中,函数的参数不是必须的,js允许参数进行省略。

1 function fn (a,b){
2     console.log(a,b)
3 }
4 
5 fn(1)   // 1,undefined -->省略了第二个参数
6 fn(1,2)  // 1,2
7 fn(1,2,3)  // 1,2
 
参数的传递方式

如果函数传递的参数是简单类型(Number,String,Boolean),则实际传递的是原值的拷贝,这意味着在函数体内修改参数的值并不会影响到函数外原始的值。

但是,如果函数传递的参数是复杂类型(Array,Object,Function),则实际传递的是原值的地址,这意味着一旦在函数体内修改参数的值,将会影响到原始值。

 
同名参数

如果参数列表中含有同名的参数,则取最后出现的那个值。

1 function fn(a,a,a){
2     console.log(a) // undefined
3 }
4 
5 fn(1,2) // --> 虽然传递了两个参数,但是由于同名取的是最后的值,所以a的值还是undefined
 
arguments对象

 函数内部的arguments对象包含了函数运行时的所有参数,其中arguments[0]代表第一个参数,arguments[1]代表第二个参数,以此类推。

正常模式下,arguments对象可以在运行时修改。

 

1 function fn(a,b){
2   arguments[0] = 2
3   arguments[1] = 3    
4   console.log(a+b)  // 5
5 }
6 
7 fn(1,2)

 

严格模式下,arguments对象与函数运行时的参数无关,也就是说,修改arguments对象不会影响到实际的函数参数。

1 function fn(a,b){
2   'use strict'  // 声明使用严格模式
3   arguments[0] = 2
4   arguments[1] = 3
5   console.log(a+b)  // 3
6 }
7 
8 fn(1,2)

前面说过,虽然arguments对象很像数组,但实际上是一个类似数组的对象。因此,数组的专有方法(slice、forEach等)是不能在arguments对象上直接使用的。

 

闭包

闭包是js语言的一大特色,很多高级应用都需要依靠闭包来实现。

理解闭包首先要理解变量作用域,前面说过,es6之前js有两种作用域:全局作用域和函数作用域。

函数内部可以读取外部声明的变量(如果内部没有),而函数外部则不能读取内部声明的变量。

1 var num = 1
2 
3 function fn(){
4     console.log(num)   //  1
5 }
6 
7 fn()
1 function fn(){
2   var num = 1  
3 }
4 
5 
6 console.log(num)  // num is not defined

由于种种原因,我们可能需要得到函数内部声明的局部变量,正常情况下是办不到的,于是利用了一种变通的方法:在函数内部再定义一个函数,将这个函数返回。

 1 function fn1(){
 2   var num = 1
 3 
 4   function fn2(){
 5     console.log(num)  // 1  
 6   }    
 7   return fn2  
 8 }
 9 
10 fn1()()

由于js的作用域是链式结构,子对象会根据声明时所在的层级一层层地向上寻找所有父对象的变量,所以我们在函数fn1的内部声明了一个函数fn2,fn2能够通过作用域链寻找到fn1的变量,然后再将fn2返回,我们在外部调用fn1拿到返回的函数fn2,继续调用fn2就拿到了num的值。

这个定义在fn1函数中的fn2函数就是闭包。

闭包最大的特点就是能够记住它诞生的环境,即闭包可以使它诞生的环境一直存在

 1 function createIncrementor(start){
 2   return function(){
 3     return start++       
 4   }  
 5 }
 6 
 7 var inc = createIncrementor(5)
 8 
 9 inc() // 5
10 inc() // 6
11 inc() // 7  -->会一直在之前的基础上进行++操作

可以看到,通过闭包,start的状态被保留了,每次的调用都是在上次调用后的基础上进行计算。

原因是,inc始终都保留在内存中,而inc的存在依赖于createIncrementor函数,因此也会保留createIncrementor的上下文,使之不会被垃圾回收机制回收。

注意: 如果多次调用createIncrementor函数会返回多个闭包,易造成额外的内存消耗,所以不应滥用闭包。

 

 网道 - JavaScript教程

 

 

转载于:https://www.cnblogs.com/chenmoumou/p/10837625.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值