一、JavaScript对象的概述
我们几乎所有接触的看到的事物,都可以抽象成对象
所有对象,至少都包含两个基本的元素:属性和方法
属性:描述特征,静态的概念
方法:描述行为,动态的概念
JavaScript是基于对象的编程语言,注意,是基于不是面向。
JavaScript不是面向对象的语言,很多面向对象的语言具有的功能,它是不具备的,但是,有些属于面向对象的特征,它又是支持的,所以我们说它是基于而不是面向:
功能 | 说明 |
对象类型 | JavaScript支持内置和用户定义的对象类型,但不支持强制的数据类型,任何类型的对象都可以赋予任意类型的值 |
对象实例化 | 对象类型用new运算符实例化,创建具体对象实例 |
对象合成 | 对象类型可以使用其他内置类型或者通过用户定义的类型来定义 |
模块化 | JavaScript代码可以用模块方式定义,但JavaScript并不提供强制模块化软件开发的特性 |
对象复用 | JavaScript可以通过<script>标记的sre属性实现复用 |
信息隐藏 | JavaScript并不提供也不支持任何信息隐藏功能 |
包装 | 由于没有信息隐藏功能,因此无法用于开发包装对象类型,用类型语句定义的任何方法和属性都可以直接访问 |
继承 | JavaScript不提供对象类型间继承的特性 |
分类 | 由于JavaScript不支持继承,因此无法开发层次形的对象类型 |
多态 | JavaScript支持多态功能,它可通过定义函数数组参数实现 |
下面具体使用JavaScript对象涉及的一些基础知识点:
1.引用对象的途径
- 引用JavaScript内置的对象,比如常用的内置对象有Date对象,String对象, Array对象,Math对象...
- 引用浏览器的内部的对象
- 引用自定义的对象
不管使用哪个途径得到的对象,都有一 个基本前提,这个对象必须已经存在,不然,引用不存在的对象,就会报错!
2. JavaScript是基于对象的编程语言,所以它提供了操作对象的能力,具体相关的部分语句:
语句名称 | 语法 | 说明 |
for in 语句 |
for(变量 in 对象){ //语句块; } |
用于对数组进行循环操作,也可用它对某个对象的所有属性进行循环操作 |
this 关键字 | this | this 是对当前的引用。在JavaScript中,由于对象的引用是多层次的,往往一个对象的引用需要对另一个对象的引用,而另一个对象有可能又要引用其他对象,这样可能造成混乱。最后用户不知道现在引用的是哪一个对象,为此JavaScript提供了一个用于将对象指定当前对象语句this |
new 运算符 | Newobject = new object(oaraneters table); | new运算符可以创建一个新的对象。其中,Newobject 是创建的新对象;object 是已经存在的对象;oaraneters table是参数表;new 是 JavaScript中的命令语句 |
3、JavaScript对象属性的引用方式
- "."点运算符
- 字符串的方式引用
var people = { name:"北冥", age:18, hobby:"爱打代码,爱钻牛角尖" } console.log(people);//Object { name: "北冥", age: 18, hobby: "爱打代码,爱钻牛角尖" } console.log(people.name);//北冥 console.log(people["hobby"]);//爱打代码,爱钻牛角尖
4、JavaScript对象的方法的引用
很简单:对象名+点+方法名+括号
不管使用哪个途径得到的对象,都有一 个基本前提,这个对象必须已经存在,不然,引用不存在的对象,就会报错!
二、函数
函数是一段可以反复调用的代码块。函数还能接受输入的参数,不同的参数会返回不同的值。
1、JavaScript 有三种声明函数的方法:
- function 命令
function命令声明的代码区块,就是一个函数。
function命令后面是函数名,函数名后面是一对圆括号,里面是传入函数的参数。
函数体放在大括号里面。
下面的代码命名了一个beiMing()函数,以后使用beiMing()这种形式, 就可以调用相应的代码。
function beiMing(str){ console.log(str); }
- 函数表达式
除了用function命令声明函数,还可以采用变量赋值的写法。
var meiMing = function(str){ console.log(str); };
这种写法将一个匿名函数赋值给变量。
这时,这个匿名函数又称函数表达式,因为赋值语句的等号右侧只能放表达式。
采用函数表达式声明函数时,function命 令后面不带有函数名。
如果加上函数名,该函数名只在函数体内部有效,在函数体外部无效:var mei = function ming(str){ console.log(str); }; ming(123); //错误:ming is not defined
这种写法的用处有两个:
一是可以在函数体内部调用自身
二是方便除错(除错工具显示函数调用栈时,将显示函数名,而不再显示这里是一个匿名函数)。 - Function 构造函数
var add = new Function('x','y','return x + y'); //参数前面的是形参,最后个是函数体 //等同于 function add(x, y) { return x+ y; }
除了最后一个参数是add函数的“函数体”,其他参数都是add函数的参数。
你可以传递任意数量的参数给Function构造函数,只有最后一个参数会被当做函数体,如果只有一个参数,该参数就是函数体。
Function构造函数可以不使用new命令,返回结果完全一样。总的来说,这种声明函数的方式非常不直观,几乎无人使用。
2、函数的重复声明:
如果同一个函数被多次声明,后面的声明就会覆盖前面的声明。
function bei(){ console.log(1); } bei();//结果是2 function bei(){ console.log(2); } bei();//结果还是2
上面代码中,后一个的函数声明覆盖了前面一个,所以前一个声明的函数在任何时候都是无效的。
函数可以调用自身,这就是递归
3、第一等公民:
- JavaScript语言将函数看作一种值,与其它值(数值、字符串、布尔值等等)地位相同。
- 凡是可以使用值的地方,就能使用函数。比如,可以把函数赋值给变量和对象的属性,也可以当作参数传入其他函数,或者作为函数的结果返回。
- 函数只是一个可以执行的值,此外并无特殊之处。
- 由于函数与其他数据类型地位平等,所以JavaScript语言中又称函数为第一等公民。
function add(x, y){ return x+y; } //做为值,能将值赋给一个变量 var add2 = add; console.log(add(1,1));//结果2 console.log(add2(1,1));//结果2 //把函数作为一个参数传出去给另一个函数,作为另一个函数的返回值 function a(sun){//这里的形式参数可以是函数 return sun; //这里返回的值也可以是函数 } var rs = a(add)(1,1);//后面的这个括号, js解析起会识别为,里边作为参数的add函数的实参 console.log(rs);//结果为2
4、函数名的提升:
JavaScript 引擎将函数名视同变量名,所以采用function命令 声明函数时,整个函数会像变量声明一样,被提升到代码头部。所以,下面的代码不会报错。
a();//函数提升后,所以在函数声明的前面可以调用 function a(){ console.log("a"); }
但是我们用函数表达式的方式声明函数时,函数不会被提升,所以会报错,也说明了如果用表达式和function命令声明同一个函数,function命令的函数会被提升因此失效,解释了函数重复声明问题:
a();//报错 var a = function(){ console.log("a"); } a();//放在声明后,不报错
不能在条件语句中使用function命令的方式声明函数,只能用表达式声明函数。
因为在if/else语句里,function命令声明的函数会被提升,而表达式在预编译里不提前。
5、函数属性和方法
name 属性
函数的name属性返回函数的名字,一般用来获取参数函数的名字:
function a(){} var b = function(){}//匿名函数 var c = function d(){}//具名函数 console.log(a.name);//结果a console.log(b.name);//结果b console.log(c.name);//结果d //这里说明用函数表达式创建函数的时候,后面的函数是匿名函数,还是具名函数的情况name返回值是不一样的
lenght 属性
函数的length属性返回函数预期传入的参数个数,即函数定义之中的参数个数。
function arr(a,c,b){} arr.length;//结果是3
length属性提供了一种机制,判断定义时和调用时参数的差异
toString() 方法
函数的toString方法返回-一个字符串,内容是函数的源码,注释也会被返回。
function a(){} var b = a.toString() console.log(b); //结果:function a(){}
用这一点,可以变相实现获取多行字符串:
function add(x, y) { return x + y; //北冥 //爱你 } function getStr(str) { var strArr = str.toString().split(" "); //将a对象转化为一个数组,数组以换行为分割点 var rs = strArr.slice(2,4).join(" "); //返回strArr数组指定下面内容,并以换行为拼接点 //slice()方法可从已有的数组中返回选定的元素。返回的内容[start,end) console.log(rs);//输出://北冥 //爱你 } getStr(add);
6、函数作用域
作用域(scope) 指的是变量存在的范围。
在ES5的规范中,Javascript 只有两种作用域:
- 一种是全局作用域,变量在整个程序中一直存在,所有地方都可以读取;
- 另一种是函数作用域,变量只在函数内部存在。
知识点:
- 函数内部定义的变量,会在该作用域内覆盖同名全局变量。也就是在函数作用域内,函数内部定义的变量优先于全局变量。
- 与全局作用域一样,函数作用域内部也会产生"变量提升"现象,即:var命令声明的变量,不管在什么位置, 变量声明都会被提升到函数体的头部。
- 它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关
- 函数体内部声明的函数,作用域绑定函数体内部。
7、参数
函数运行的时候,有时需要提供外部数据,不同的外部数据会得到不同的结果,这种外部数据就叫参数。可以参考:参数 https://www.cnblogs.com/beimingdaoren/p/12455484.html
7.1参数的省略
函数参数不是必需的,JavaScript 允许省略参数。
function a1(a,b){ return a; } console.log(a1(1,2,3));//结果:1 console.log(a1(1));//结果:1 console.log(a1());//结果:1 console.log(a1.length);//结果:2
上面代码的函数f定义了两个参数,但是运行时无论提供多少个参数(或者不提供参数),JavaScript都不会报错。省略的参数的值就变为undefined,需要注意的是,函数的length属性与实际传入的参数个数无关,只反映函数预期传入的参数个数。
但是,没有办法只省略靠前的参数,而保留靠后的参数。如果一定要省略靠前的参数,只有显式传入undefined:
function a1(a,b){ return a; } console.log(a1(,2));//报错:Unexpected token console.log(a1(undefined,2));//结果undefined
7.2参数的传递
函数参数如果是原始类型的值(数值、字符串、布尔值), 传递方式是值传递。也就是值拷贝形式,这意味着,在函数体内修改参数值,不会影响到函数外部。
但是,如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递(引用传递)。也就是说,传入函数的是原始值的地址,因此在函数内部修改参数,将会影响到原始值。
注意,如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值。
7.3同名参数
如果有同名的参数,则取最后出现的那个值。
function bei(a,a){ console.log(a); } bei(1,2);//结果是:2
上面代码中,函数有两个参数,且参数名都是a。取值的时候,以后面的a为准,即使后面的a没有值或被省略,也是以其为准:
function bei(a,a){ console.log(a); } bei(1);//结果是:undefined
8、arguments 对象
由于JavaScript允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。这就是arguments对象的由来。
arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。
var f = function(one) { console.log(arguments[0]); console.log(arguments[1]); console.log(arguments[2]); } f(1, 2, 3) //结果:1、2、3
严格模式下,arguments对象是一个只读对象, 修改它是无效的,但不会报错。
通过arguments对象的length属性,可以判断函数被调用时到底带了几个参数。
需要注意的是,虽然arguments很像数组,但它是一个对象。数组专有的方法(比如slice) ,不能在arguments对象上直接使用。但可以将arguments转为真正的数组。
9、函数的其他知识点
9.1 闭包
闭包(closure) 是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。
理解闭包,首先必须理解变量作用域。前面提到,JavaScript 有两种作用域:全局作用域和函数作用域。函数内部可以直接读取全局变量。
如果出于种种原因,我们有时候是需要得到函数内的局部变量。 正常情况下,这是办不到的,只有通过变通方法才能实现。 那就是在函数的内部,再定义一个函数。
function f1() { var n = 999;//f1函数中的局部变量 function f2() { console.log(n);// 999 } }
上面代码中,函数f2就在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。
这就是JavaScript语言特有的"链式作用域”结构(chain scope):子对象会一级一级地向上寻找所有父对象的变量。
所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
既然f2可以读取f1的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗:
function f1() { var n = 999;//f1函数中的局部变量 function f2() { console.log(n);//f2函数定义在f1内部,所以在f2中可以拿到f1的局部变量n } //把f2函数,作为返回值给返回出去 return f2; } //f1函数体外面调用 var fun = f1(); fun();//结果999
上面优码中,函数f1的返回值就是函数f2,由于f2可以读取f1的内部变量,所以就可以在外部获得f1的内部变量了。
闭包就是函数f2,即能够读取其他函数内部变量的函数。
由于在JavaScript语言中,只有函数内部的子函数才能读取内部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
闭包最大的特点,就是它可以“记住”诞生的环境,比如f2记住了它诞生的环境f1,所以从f2可以得到f1的内部变量。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在。一个用处是封装对象的私有属性和私有方法(和java中的get set方法类似)。
注意,外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。
9.2 立即调用的函数表达式(IIFE)
在Javascript中,圆括号()是一种运算符,跟在函数名之后,表示调用该函数。
比如,print()就表示调用print函数。
有时,我们需要在定义函数之后,立即调用该函数。
这时,不能在函数的定义之后加上圆括号,这会产生语法错误:
function f(){console. log("f")}();//报错
产生这个错误的原因是,function这个关键字即可以当作语句, 也可以当作表达式。
//语句 function f(){} //表达式 var f = function f(){}
为了避免解析上的歧义,JavaScript 引擎规定,如果function关键字出现在行首,一律解释成语句。
因此,JavaScript引擎看到行首是function关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。
解决方法就是不要让function出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面。
(function(){ /* code */ }()); //或者 (function(){ /* code */ })();
上面两种写法都是以圆括号开头,引擎就会认为后面跟的是一个表示式,而不是函数定义语句,所以就避免了错误。
这就叫做“立即调用的函数表达式”(Immediately-Invoked Function Expression),简称IIFE。
注意:上面写法最后的分号一定要有:
(function(){/* code */}()) (function(){/* code */}()) //上面代码的两行之间没有分号,JavaScript会将它们连在一起解释,将第二行解释为第一行的参数。
9.3 call,apply和bind命令
9.3_1 call:
一般用来指定this的环境, 在没有学之前或者理解不透彻的话,都会有这么些问题:
var a = { user: "小冥", fn: function() { console.log(this.user); } } var b = a.fn; b(); //结果:undefined a.fn();//结果:小冥
我们是想打印对象a里面的user却打印出来undefined是怎么回事呢? 如果我们直接执行a.fn()却是可以的。
函数里边的this关键字,指的什么?哪个调用了 该函数, this就指向那个。window.b()调用时,this指向window,所以结果为undefined
使用call方法后:
var a = { user: "小冥", fn: function() { console.log(this.user); } } var b = a.fn; b.call(a);//结果:小冥
通过在call方法,调用变量b指向的函数,并且把函数中的this指向,call方法里的第一个参数, 这里就是a啦!
使用call方法插入多个参数时,第一个参数是定义函数中的this关键字的指向,后面的参数才是给函数的形参的。
9.3_2 apply:
apply与call方法的使用一样,只不过apply在多个参数时与call不同:第二个参数必须是一个数组。
如果call和apply的第一 个参数写的是null,那么this指向的是window对象
9.3_3 bind:
前面call和apply可以说是兄弟,区别只有一丢丢!
bind和他们是不一样的,但是它们都可以用来改变this的指向,这点上又有点关系。
var a = { user: "小白", fn: function() { console.log(this.user); } } var b = a.fn; var c = b.bind(a); console.log(c); //结果是函数a c(); //结果:小冥
我们发现代码没有被打印, 对,这就是bind和call. apply方法的不同, 实际上bind方法返回的是一个修改过后的函数。
总结:call和apply都是改变上下文中的this并立即执行这个函数,bind方法可以让对应的函数想什么时候调就什么时候调用,并且可以将参数在执行的时候添加,这是它们的区别,根据自己的实际情况来选择使用。
三、内置对象
JS里的内置对象,JS语言本身就已经存在的对象,不用我们自己创建,我们直接就可以使用的对象。比如: Array、 Math、 Number、 String. Date、 Boolean、 Object、Function等等都是内 置对象
1、Array对象
数组定义:简而言之就是一组有序的数据集合,其索引为从0开始且自然增长的整数,元素值可以是任何js数据!并且包含一个名为length的属性,该属性表示数组元素的个数!
在JS里数组,可以被看成是一个特殊的对象。 属于JS内置对象中的一个!
1.1 创建数组:
//方法一,字面量创建 var array1 = {1,2,"bei"}; //方法二,new关键字 var array2 = new Array(1,2,"ming");
当new Array()的括号里只有一个数字的时候,这个数字表示数组的长度,不是数组的元素
1.2 获取数组长度:lenght属性
var arr1 = [1, 2, 3, 4]; console.log("数组arr1的长度:" + arr1.length);//结果:4 console.log("给数组arr1增加一个元素"); arr1[arr1.length] = arr1.length + 1; console.log(arr1.length);//结果:5
1.3 遍历数组:for、for...in:
var arr =[1,2,3,4,5,"bei","ming"]; //for循环遍历,当数组较长的时候,可以用变量来获取他的长度,优化代码,提高性能 for(let i = 0;i<arr.length;i++){ console.log(arr[i]); } //for...in循环遍历 for(let x in arr){ console.log(arr[x]); }
1.4数组对象包含的方法汇总:
1、concat()连接两个或以上的数组,返回的是一个新数组,不影响原数组(concat合并多个数组(加的是数组中的元素),也可跟元素合并):
var arr = [1]; var arr1 = [ "concat"]; var arr3 = arr.concat(arr1); console.log(arr3);//[1,"concat"]
2、push()方法可向数组的末尾添加一个或多个元素,该方法会改变原数组,并且遵循数组提供的先进后出栈功能,返回值是数组新的长度;
(unshift()方法是向数组头部添加一个或多个元素,使用上同push方法,但不推荐使用,因为无法再底版IE下正常使用):
var arr = [1,2,3]; arr.push(4); console.log(arr);//[1,2,3,4] arr.unshift(0); console.log(arr);//[0,1,2,3,4]
3、pop()方法弹出数组最后一个元素,该方法会改变原数组,删除元素并且数组长度-1,返回值是删除的元素的值,如果数组是空数组,则不进行删除,返回值是undefined;
shift()方法删除数组第一个元素,使用上同pop方法(内部中,pop:取出 ;shift:转移,改变):
var arr = [1,2,3,4]; var rs = arr.pop(); console.log(arr);//[1,2,3] console.log(rs);//4 var rs2 = arr.shift(); console.log(arr);//[2,3] console.log(rs2);//1
4、sort()对数组进行排序,改变的是原数组元素顺序,默认是按字符编(ASCII)码排序:
var arr = ['a','b','A']; arr.sort(); console.log(arr);//[ "A", "a", "b" ]
sort()也可以自定义排序:
var arr = [1,2,5,4,3]; arr.sort(); console.log(arr);//[1,2,3,4,5] arr.sort(drop);//自定义排序 console.log(arr);//[5,4,3,2,1] function drop(x,y){//自定义降序排序函数 return y-x; }
5、slice(start,end)数组的截取函数,start 必需,end 选填,均可以为负数,返回的是start到end (不包括end)之间的元素,返回新数组,不影响原来数组(slice 切开):
var arr = [1, 2, 3, 4, 5]; var arr1 = arr.slice(2, 4); console.log(arr);//[1,2,3,4,5] console.log(arr1);//[3,4]
6、splise(index,howmamty.te....itemX)方法删除、添加或替换数组,会操作原数组,返回的是含有被删除的元素的数组,index必需起始位置,howmany必需数量可以为0,即不操作,第三个参数添加到数组,替代数组index的位置:
var arr = [1,2,3,4]; //增加5,6 arr.splice(4,0,5,6); console.log(arr);//[1,2,3,4,5,6] //删除4,5,6 arr.splice(3,3); console.log(arr);//[1,2,3] //修改3为33 arr.splice(2,1,33); console.log(arr);//[1,2,33]
7、reverse()颠倒元素顺序,改变原数组:
var arr = [1,2,3,4,5]; arr.reverse(); console.log(arr);//[5,4,3,2,1]
8、join()方法将数组拆分成字符串,返回值字符串,默认分隔符为逗号“,”:
var arr = [1,2,3]; arr. join("-"); //"1-2-3"
9、toString()将数组转换成字符串,返回字符串,格式为逗号隔开:
var arr = [1,2,3]; arr. toString(); //"1,2,3"
10、map():返回一个新的Array,每个元素为调用function的结果:
var arr1 = [1,2,3,4,5]; function add(x){ return x*2; } var arr2 = arr1.map(add); console.log(arr1);//[ 1, 2, 3, 4, 5 ] console.log(arr2);//[ 2, 4, 6, 8, 10 ]
11、filter():返回一个符合function条件的元素数组:
var arr1 = [1,2,3,4,5,6]; function rule(num){ return num >= 4; } var arr2 = arr1.filter(rule); console.log(arr1);//[ 1, 2, 3, 4, 5, 6 ] console.log(arr2);//[ 4, 5, 6 ]
12、some():返回一个boolean,判断是否有元素符合function条件:
var arr1 = [1,2,3,4,5,6]; function rule(num){ return num >= 4; } var b = arr1.some(rule); console.log(arr1);//[ 1, 2, 3, 4, 5, 6 ] console.log(b);//true
13、enery():返回一个boolean,判断所有元素是否符合function条件:
var arr1 = [1,2,3,4,5,6]; function rule(num){ return num >= 4; } var b = arr1.every(rule); console.log(arr1);//[ 1, 2, 3, 4, 5, 6 ] console.log(b);//false
14、forEach():没有返回值,只是针对每个元素调用function:
var arr1 = [1,2,3,4,5,6]; function number(item,index,arr){ arr[index] = item+1; } arr1.forEach(number); console.log(arr1);//[ 2, 3, 4, 5, 6, 7 ]
2、String对象
首先区别一下String和string:
- js区分大小写,所以他们两个是代表不同的意思;
- String是构造函数,string是变量的一个类型
- typeof String是function,typeof string是undefined, typeof "abc" 是string;
- new String('xxx')返回的是一个字符串对象,String有属性和方法,而string没有。
构造函数:是一种特殊的方法。主要用来在创建对象时初始化对象,即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。
2.1、String的创建
String对象主要作用:对字符串进行操作,如:截取一段子串、 查找字符串/字符、转换大小写等等。
创建方式一:new String(Value)构造函数:
var str = new String("abc"); console.log(typeof str);//object
创建方式二:直接赋值(推荐):
var str = "abc"; console.log(typeof str);//string,我们创建的变量是基本数据类型:string,但是string可以调用String的方法;
创建方式二,创建出来的变量,也能调用String的属性和方法:这时候会使用String类型把str包装成引用类型,然后使用String类型内部定义的substring方法,最后把这个方法运行的结果赋值给str变量:
new String("abc"); str = new String(" abc").substring();
其实本质是在执行代码的一瞬间,将str包装成了String引用类型,然后再调用String引用类型下面的substring方法,继而重新将结果再值赋给str,最后的效果就是str="abc"。
Js里边的这种现象我们称为: JS的包装类,变量类型string的对应包装类就是String对象。
var str = "abc";//string类型的字符串,不具备属性和方法 str.color = "red";//如果string是一个对象,具有属性和方法,那么在这里应该得到"red" console.log(str.color);//结果:undefined var Str = new String("ABC"); Str.color = "RED"; console.log(Str.color);//结果:RED
2.2、String的属性
就一个length属性:返回字符串中字符数
var str = "abc"; console.log(str.length);//3 console.log("北冥骑鲲打代码".length);//7 console.log("".length);//0
2.3、String的方法:
1、charAt(index):返回一个字符串中指定位置的字符,编号从0开始,若传入个不存在的数值,就返回空字符串:
var a = "abc"; var b = a.charAt(1); console.log(a);//abc console.log(b);//a
2、charCodeAt(index):返回一个字符串中指定位置字符的unicode编码:
var a = "abc"; console.log(a.charCodeAt(1));//98:字符b的Unicode编码,但是注意结果是10进制的 console.log(a.charCodeAt(11));//NAN:获取一个不存在的字符,返回NAN
补充一个知识点: Unicode编码表
了解Unicode
- Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。
- Unicode是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一 的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
- 1990年开始研发,1994年正式公布。
- 它是一个标准是一个规范, UTF-8这个我们经常用的编码格式,就是这个规范的一个具体的实现!
在js中的使用方法: u+十六进制的unicode编码
console.log("xxxx")在HTML使用的方法: &#+十进制的unicode编码+英文分号
<h1> ☠</h1>
3、concat(value1,value2,...valueN):连接一个或多个字符串,并返回连接后的字符串:
var s1 = "bei ming "; var s2 = "dao ren "; var s = s1.concat(s2); console.log(s);//bei ming dao ren
(少量的字符串一般用+号链接即可)
4、indexOf(value,|startPosition):在实例中从前往后查找一个字符串或字符,并返回找到第一个值的位置(从0开始计数、startPosition查找位置)若未找到,返回-1:
var str = "bei ming"; console.log(str.indexOf("i"));//结果:2
5、lastIndexOf(value,|startPosition):在实例中从后往前查找一个字符串或字符,并返回找到第一个值的位置(从0开始计数、startPosition查找位置)若未找到,返回-1,用法和indexOf类似。
6、localeCompare(value):实例与参数进行比较,返回比较结果:
var s = 'abc'; console.log(s.localeCompare('ab')); // => 1 :实例此参数大 console.log(s.localeCompare('abc')); // => 0 :实例与参数相等 console.log(s.localeCompare('abcd')); // => -1 :实例比参数小
7、slice(start,|end):返回从字符串start位置到end前一个位置的子串:
var s = 'abcdefg'; console.log(s.slice(1)); //bcdefg :省略end参数,结束位置为末尾 console.log(s.slice(1,3)); //bc:返回从位置序号1到位置序号2(end前一个位置)的子串 console.log(s.slice(-3)); //efg :返回从倒数第三个开始到末尾的所有字符 console.log(s.slice(-3,-1));//ef:返回从倒数第三个开始到第:二个(end前一个位置)的所有字符
8、split(delimiter, |arrayLength):将字符串按照某种分隔符切分成一个由字符串组成的数组并返回
参数:
①delimiter {regexp | string}:指定的分隔符,可以为正则表达式或字符串。
②arrayLength {int} 可选:分割数组的长度。若省略,返回所有分割的子串。
注意:若分隔符在字符串的第一个或最后一个,将添加一个空字符串到返回的数组。
var str1 = "a,b,c,d,e"; var str2 = ",a,b,c,d,e"; var arr1 = str1.split(","); console.log(arr1);//结果:[ "a", "b", "c", "d", "e" ] var arr2 = str2.split(",");//分隔符在最前面或者最后面,会添加一个空字符串 console.log(arr2);//结果:[ ",a", "b", "c", "d", "e" ]
9、substr(start, |wordLength):返回从字符串start位置开始计算到wordLength个长度的子串
10、substring(start, |end):返回从字符串start位置到end前一个位置的子串(和slice方法雷同):
var str = "abcdef"; console.log(str.substr(1,2));//结果:bc console.log(str.substring(1,3));//结果:bc console.log(str.slice(1,3));//结果:bc
11、toUpperCase():将字符串转换为大写并返回
12、toLowerCase():将字符串转换为小写并返回
13、trim():移除字符串开头和结尾处的空白字符并返回:
var str = " Bei Mimg " console.log(str.toUpperCase());//结果: BEI MIMG console.log(str.toLowerCase());//结果: bei mimg console.log(str.trim());//结果:Bei Mimg
3、Math对象
- Math也是一个内置对象, 为数学常 量和数学函数提供了属性和方法,而不是一个函数对象。
- 与其它全局对象不同的是,Math不是一个构造器,Math的所有属性和方法都是静态的。
- 你用到的常数π可以用Math.PI表示,用 x 作参数Math.sin(x)调用sin函数,JavaScript中的常数,是以全精度的实数定义的。
3.1、属性:
我们在实际中,很少使用到Math对象,这里做了解就可以了,具体可参照:https://www.w3school.com.cn/js/js_math.asp
4、Date对象
- Date对象是JavaScript原生的时间库。
- 它以1970年1月肛1日00:00:00作为时间的零点,可以表示的时间范围是前后各1亿天(单位为毫秒)。
4.1、把Date对象当成普通函数来使用(很少使用)
Date对象可以作为普通函数直接调用,返回一个代表当前时间的字符串。
无论有没有参数,直接调用Date总是返回当前时间。
var rs = Date(); var rs1 = Date(2020,5,2); console.log(rs);//Sat May 02 2020 09:52:50 GMT+0800 (中国标准时间) console.log(rs1);//Sat May 02 2020 09:52:50 GMT+0800 (中国标准时间)
4.2、构造函数的用法(常用)
Date还可以当作构造函数使用。
对它使用new命令,会返回一个Date对象的实例。如果不加参数,实例代表的就是当前时间。
var today = new Date();//构造函数不传参数,返回的是当前时间的字符串 console.log(today);//Date Sat May 02 2020 09:55:27 GMT+0800 (中国标准时间)
作为构造函数时,Date对象可以接受多种格式的参数,返回一个该参数对应的时间实例:
var today1 = new Date("May 2,2020");//构造函数传入参数,返回的是传入时间的字符串 console.log(today1);//Date Sat May 02 2020 00:00:00 GMT+0800 (中国标准时间) var today2 = new Date(2020,4,2,0,0,0,0);//按年月日时分秒传入参数,注意月份从0开始 console.log(today2);//Date Sat May 02 2020 00:00:00 GMT+0800 (中国标准时间)
关于Date构造函数的这些参数,有几点扩展补充:
第一点,参数可以是负整数,代表1970年元旦之前的时间。
var day = new Date(-1231241234567); console.log(day);//Date Fri Dec 26 1930 20:32:45 GMT+0800 (中国标准时间)
第二点,只要是能被Date parse()方法解析的字符串,都可以当作参数。
//下面返回的都是:Date Fri Feb 15 2020 08:00:00 GMT+0800 (中国标准时间) new Date('2020-2-15'); new Date('2020/2/15'); new Date('02/15/2020'); new Date('FEB 15,2020'); new Date('February,15,2020'); new Date('February 15,2020'); new Date('15 Feb 2020'); new Date('15,February,2020');
第三点,参数为年、月、日等多个整数时,年和月是不能省略的,其他参数都可以省略的。
也就是说,这时至少需要两个参数,因为如果只使用“年”这一个参数,Date会将其解释为毫秒数。
console.log(new Date(2020)); //上面代码中的2020被解析为毫秒数,结果:Date Thu Jan 01 1970 08:00:02 GMT+0800 (中国标准时间) console.log(new Date(2020,0)); console.log(new Date(2020,0,1)); console.log(new Date(2020,0,1,0)); console.log(new Date(2020,0,1,0,0,0,0)); //上面代码中,不管有几个参数返回的都是:Date Wed Jan 01 2020 00:00:00 GMT+0800 (中国标准时间)
各个参数的取值范围如下:
- 年:使用四位数年份,比如2000。如果写成两位数或个位数,则加上1900, 即10代表1910年。如果是负数,表示公元前。
- 月: 0表示一月,依次类推,11表示12月。
- 日: 1到31。
- 小时: 0到23。
- 分钟: 0到59。
- 秒: 0到59
- 毫秒: 0到999。
注意,月份从0开始计算,但是,天数从1开始计算。
另外,除了日期的默认值为1,小时、分钟、秒钟和毫秒的默认值都是0。
这些参数如果超出了正常范围,会被自动折算。比如,如果月设为15,就折算为下一年的4月。
4.3、日期的运算
类型自动转换时,Date实例如果转为数值,则等于对应的毫秒数;
如果转为字符串,则等于对应的日期字符串。
所以,两个日期实例对象进行减法运算时,返回的是它们间隔的毫秒数;
进行加法运算时,返回的是两个字符串连接而成的新字符串。
var d1 = new Date(2020,5,1); var d2 = new Date(2020,5,2); console.log(d2-d1);//时间戳:86400000 console.log(d2+d1);//字符串:Tue Jun 02 2020 00:00:00 GMT+0800 (中国标准时间)Mon Jun 01 2020 00:00:00 GMT+0800 (中国标准时间)
4.4、静态方法
Date.now方法:返回当前时间距离时间零点(1970年1月1日00:00:00 UTC)的毫秒数,即时间戳。
console.log(Date.now());//
Date.parse()方法:用来解析日期字符串,返回该时间距离时间零点(1970年1月1日00:00:00)的毫秒数。
日期字符串应该符合RFC 2822和ISO 8061这两个标准,即YYYY-MM-DD HH:mm:ss.sss Z格式,其中最后的Z表示时区。但是其他格式也可以被解析,具体看上面补充的第三点。
console.log(Date.parse(2020,5,2));//1577836800000
Date.UTC()方法:接受年、月、日等变量作为参数,返回该时间距离时间零点(1970年1月1日00:00:00 UTC)的毫秒数。
该访法的参数用法与Date构造函数完全一致,比如月从0开始计算,日期从1开始计算。
区别在于Date.UTC方法的参数,会被解释为UTC时间(世界标准时间),Date构造函数的参数会被解释为当前时区的时间。
5、实例方法
Date的实例对象,有几十个自己的方法,除了valueOf,可以分为以下三类。
- to类:从Date对象返回一个字符串,表示指定的时间。
- get类:获取Date对象的日期和时间。
- set类:设置Date对象的日期和时间。
5.1、Date.valueOf()方法:返回实例对象距离时间零点(1970年1月1日00:00:00 UTC)对应的毫秒数,改方法等同于getTime方法。
var d = new Date(); console.log(d.getTime());//1588388977488 console.log(d.valueOf());//1588388977488
5.2、to类:
方法 | 说明 |
toSource() | 返回该对象的源代码 |
Date.toString() | 返回一个完整的日期字符串 (直接输出日期对象,会默认调用toString()方法) |
Date.toUTCString() | 返回对应的UTC(世界标准)时间 也就是比北京时间早8小时(东八区) |
Date.toISOString() | 返回对应的ISO 8601写法 |
5.3、get类:
Date对象提供了一系列get方法,用来获取实例对象某个方面的值。
- getTime():返回实例距离1970年1月1日00:00:00的毫秒数,等同于valueOf方法。
- getDate():返回实例对象对应每个月的几号(从1开始)。
- getDay():返回星期几,星期日为0,星期一为1,以此类推。
- getYear():返回距离1900的年数。
- getFullYear():返回四位的年份。
- getMonth():返回月份(0表示1月, 11表示12月)。
- getHours():返回小时(0-23)。
- getMilliseconds():返回毫秒(0-999)。
- getMinutes():返回分钟(0-59)。
- getSeconds():返回秒(0-59)。
- getTimezoneOffset():返回当前时间与UTC(世界标准时间)的时区差异,即UTC减当前时间,以分钟表示,返回结果考虑到了夏令时因素。
5.4、set类:
Date对象提供了一系列set方法,用来设置实例对象某个方面的值。
- setDate(date):设置实例对象对应的每个月的几号(1-31),返回改变后毫秒时间戳。
- setYear(year):设置距离1900年的年数。
- setFullYear(year [, month, date]): 设置四位年份。
- setHours(hour [, min, sec, ms]):设置小时(0-23) 。
- setMilliseconds():设置毫秒(0-999) 。
- setMinutes(min [, sec, ms]):设置分钟(0-59)。
- setMonth(month [, date]):设置月份(0-11) 。
- setSeconds(sec[, ms]):设置秒(0-59) 。
- setTimel(milliseconds):设置毫秒时间戳。
这些方法基本是跟get方法一一对应的,但是没有setDay方法,因为星期几是计算出来的,而不是设置的。另外,需要注意的是,凡是涉及到设置月份,都是0开始计算的。
5、Number对象
Number对象是数值对应的包装对象,可以作为构造函数使用,也可以作为工具函数使用。
注意,Number是一个对象,而number是一种数据类型。
作为构造函数时,它用于生成值为数值的对象:
var a = new Number(1); console.log(a);//1 console.log(typeof(a));//object //上面代码中,Number对象作为构造函数使用,返回一个值为1的对象
作为工具函数时,它可以将任何类型的值转化为数值:
console.log(Number(true));//1 console.log(Number("12345"));//12345 console.log("北冥最帅");//NAN
Number对象拥有一些静态属性,很少使用,这里就不举例了。
实例方法:
a、toString()方法:
NUmber对象部署了自己的toString()方法,用来将一个数值转换为字符串形式。
console.log(typecof(10).toString());//string
toString()方法可以接受一个参数,表示输出的进制。
console.log((10).toString(2));//2进制数:1010
在使用数值.toString()的时候数值要用()括号括起来,不然编译器会把.toString()前的识别为一个小数点
b、toFlxed()方法:
toFlxed()方法先将一个数转为指定位数的小数,然后返回此小数对应的字符串。
console.log((10).toFixed(2));//10.00 (类型为string)
出于浮点数的原因,小数5的四舍五入是不稳定的,最好不使用此方法进行四舍五入 。
c、toPrecision()方法:
toPrecision()方法用于将一个数转换为指定位数的小数,和toFlxed()方法差不多,但返回的不是字符串,最好也不使用此方法做四舍五入。
6、Boolean对象
Boolean对象是JavaScript的三个包装对象之一,作为构造函数,它主要用于生成布尔值的包装对象实例。
var b = new Boolean(true); console.log(type(b));//object(对象) console.log(b.valueOf());//true(值) //上面代码的变量b是一个Boolean对象的实例,它的类型是对象,值为布尔值true
//注意,false对应的包装对象实例,布尔值运算结果也是true if(new Boolean(false)){ console.log("true"); //true } if(new Boolean(false).valueOf()){ console.log("true");//(不被执行) }
上面代码的第二个例子第一个if,之所以得到true,是因为false对应的包装对象实例是一个对象,进行逻辑运算时,被自动转化成布尔值true(因为所有对象对应的布尔值都是true)
Boolean函数的类型转换作用:
Boolean对象除了可以作为构造函数,还可以单独使用,将任意值转化为布尔值,这时Boolean就是一个单独的工具方法。
Boolean(undefined)//false Boolean(null);//false Boolean(0);//false Boolean("");//false Boolean(NaN);//flase Boolean(1);//true Boolean("false");//true Boolean([]);//true Boolean({});//true Boolean(function(){});//true Boolean(/foo/);//true //上面代码中几种得到的情况,都值得记住。
随便提一下,使用双重的否运算符(!)也可以将任意值转为对应的布尔值
!!undefined //false !!null //false !!0 //false !!"" //false !!NaN //false !!1 //true !!"false" //true !![] //true !!{} //true !!function(){} //true !!/foo/ //true
最后,对于一些特殊值,Boolean对象前面不加new,会得到完全相反的结果,必须小心
if(Boolean(false)){ console.log("true"); //无输出 } if(new Boolean(false)){ console.log("true"); //true } if(Boolean(null)){ console.log("true"); //无输出 } if(new Boolean(null)){ console.log("true"); //true }
7、Object对象
JavaScript原生提供Object对象(注意开头是大写的O),JavaScript的所有其他对象都是Object的实例,和java里的Object一样,在js里他也是老大。
Object对象的原生方法分成两类:Object本身的方法与Object的实例方法。
1、Object对象本身的方法
所谓“本身的方法”就是直接定义在Object对象的方法,就是静态方法,直接用Object这个对象名称来调用的方法。
Object.print = function(o){ console.log(o); }; //上面代码,print方法就是直接定义在Object对象上。
2、Object的实例方法
所谓实例方法就是定义在Object原型对象Object.prototype上的方法,它可以被Object的对象实例直接使用。
Object.prototype.println = function(o){ console.log(o); } //调用实例方法 var obj = new Object(); obj.println("调用实例方法");//调用实例方法
上面的代码中,Object.prototype定义了一个println,然后生成一个Object的实例obj。obj直接继承了Object.prototype的属性和方法,可以直接使用obj.println调用print方法。也就是说,obj对象的println方法实质上就是调用Object.prototype.println方法。
(关于原型对象Object.prototy
pe的详细解释,后面补发)
凡是定义在Object.prototyp对象上面的属性和方法,将被所有实例对象共享就可以了。
函数Object()
Object本身是一个函数,可以当作工具方法使用,将任意值转换为对象。
这个方法常用于保证某个值一定是对象。
如果参数为空(或者为undefined和null),Object()返回一个空对象:
var obj = Object(); //等同于 var obj = Object(undefined); var obj = Object(null); obj instanceof Object //true; //上面代码的含义,是将undefined和null转换为对象,结果得到了一个空对象obj。instanceof返回true,就表示obj对象是Object的实例。
如果参数是原始类型的值,Object方法将其转换为对应的包装对象的实例:
var object1 = Object(1);//这里没有new关键字,这个时候,是工具函数,不是构造函数 console.log(typeof object1);//object console.log(object1 instanceof Object);//true console.log(object1 instanceof Number);//true console.log(object1 instanceof String);//false
利用这一点,可以写一个判断变量是否为对象的函数:
function isObject(value){ return value === Object(value); } isObject([]);//true ifObject(123);//false
Object 构造函数
Object不仅可以当作工具函数使用,还可以当作构造函数使用,即前面可以使用new命令。
Object构造函数的首要用途,是直接通过它来生成新对象。
var obj = new Object();
注意,通过var obj = new Object() 的写法生成新对象,与字面量的写法var obj = {}是等价的,或者说,后者是前者的一种简便写法
Object构造函数的用法与工具方法很相似,几乎一模一样
使用时,可以接受一个参数,如果该参数是-一个对象,则直接返回这个对象;如果是一个原始类型的值,则返回该值对应的包装对象。
Object 的静态方法
所谓“静态方法”,是指部署在Object对象自身的方法。
使用指定的原型及属性创建一个新对象
Object.create(prototype)
Object.create(prototype,descriptors)
创建或配置指定对象的某个属性
Object.defineProperty(object,name,desc)
创建或配置指定对象的一个或多个属性
Object.defineProperties(object,descriptors)
将指定对象设置为不可改变 (冻结对象)
Object.freeze(object)
查询指定对象的指定属性的特性
Object.getOwnPropertyDescriptor(object,name)
返回一个包含指定对象的所有非继承属性名的数组,包括不可枚举属性
Object.getOwnPropertyNames(object)
返回指定对象的原型
Object.getPrototypeOf(object)
检查当前对象是否含有某个非继承的属性
Object.hasOwnProperty(propertyname)
检查当前对象是否能添加新属性
Object.isExtensible(object)
检查当前对象是否已冻结
Object.isFrozen(object)
简单指定对象是否为封闭的
Object.isSealed(object)
返回一个包含指定对象的所有能非继承可枚举属性名的数组
Object.keys(object)
组织向指定对象添加新的属性
Object.preventExtensions(object)
检测某个属性是否在for/in循环中可见(是否可枚举)
Object.propertyIsEnumerable(propertyname)
阻止向指定对象添加新的属性或删除现有属性
Object.seal(object)
定义一个对象的字符串表示形式
Object.toString(object)
定义一个对象的本地化的字符串表示形式
Object.toLocaleString(object)
给定对象的原始值
Object.valueOf(object)
Object.setPrototypeOf(child, parent)
Object.getOwnPropertySymbols(o)
Object.entries()