第一章 JavaScript实现
核心(ECMAScript)
文档对象模型(DOM)
浏览器对象模型(BOM)
1.1 核心(ECMAScript)
由ECMA-262定义,提供核心语言的功能
宿主环境包括:web浏览器、Node(一种服务大端的Javascript平台)、Adobe Flash
能够实现ECMAScript的方法有:Javascript和Adobe ActionScript两种
1.2 DOM级别
提供访问和操作网页内容的方法和接口
DOM1级别:DOM核心+DOM HTML 。目标是映射文档的结构
DOM2级别:在DOM1的基础之上,增加了如下模块:
(1)DOM视图(DOM views),定义了跟踪不同文档视图的接口
(2)DOM事件:定义了元素事件和事件处理的接口
(3)DOM样式:css样式
(4)DOM遍历和范围:定义了遍历和操作文档的接口
1.2.1Dom获取页面元素的方式
(1)通过ID获取页面元素
(2)通过类名获取页面元素(返回的是数组,但不常用)
(3)通过标签获取页面元素(返回的是数组)
(4)h5提供的查选择器querySelector
//标签获取
document.querySelector('div'); //返回的是第一个标签名为div
//类名获取
document.querySelector('.div'); //返回的是第一个类名为div
//Id获取
document.querySelector('#div');
(5)h5提供的查询选择器querySelectorAll (最常用)
//标签获取
document.querySelectorAll('div'); //返回的是所有标签名为div
//类名获取
document.querySelectorAll('.div'); //返回的是所有标类名为div
//Id获取
document.querySelectorAll('#div');
1.2.2 获取元素里的内容操作
Document
222
span
1.2.3获取标签元素的属性getAttribute、设置元素属性setAttribute、removeAttribute
console.log(div.getAttribute("id"))
console.log(div.getAttribute("class"))
div.removeAttribute("b")
//通过覆盖class的属性值来达到切换的效果
var i = true
setInterval(function() {
if (i) {
myMlass = 'tow'
div.setAttribute('class', myMlass)
i = false
} else {
myMlass = 'one'
div.setAttribute('class', myMlass)
i = true
}
}, 1000)
//通过背景的属性值来达到切换的效果
var i = true
setInterval(function() {
if (i) {
div.style.background = 'green'
} else {
div.style.background = 'yellow'
}
i = !i
}, 1000)
//通过添加和删除的属性值来达到切换的效果
var i = true
setInterval(function() {
if (i) {
div.classList.add('tow')
} else {
div.classList.remove('tow')
}
i = !i
}, 1000)
/ 三种背景颜色的切换
var num = 0
setInterval(function() {
num++
if (num == 1) {
div.classList.add("one")
} else if (num == 2) {
div.classList.remove("one")
div.classList.add("tow")
} else {
div.className = "" //清空所有的class属性
}
if (num == 3) {
num = 0
}
}, 1000)
呼吸轮播图
var sum = 0
var imgs = document.querySelectorAll('img')
var len = document.querySelectorAll('img').length;
setInterval(function() {
sum++
for (var i = 0; i < len; i++) {
if (sum % len == i) {
imgs[i].style.opacity = '1'
} else {
imgs[i].style.opacity = '0'
}
}
}, 2000)
除此之外,获取class元素的一些属性
(1)className会返回该元素里所有类,且返回的类型为字符串
Document
222
span
Document
222
span
(2)classList会返回该元素里所有类,且返回的类型为数组类型
Document
222
span
(3)textContent与innerHTML的区别和来联系
var div = document.getElementsByTagName('div')[0]
console.log(div.textContent) //不会解析元素标签,只会打印标签里面的文本内容
console.log(div.innerHTML) //会解析元素标签
1.2.4 获取元素的内联样式、嵌入样式和外部样式。 getComputedStyle(“element”)
Document
1.3 浏览器对象模型(BOM)
提供与浏览器交互的方法和接口。开发人人员使用BOM可以控制浏览器显示的页面以外的部分
二 在HTML中嵌套javascript代码
2.1 标签的位置
javascript代码在head和body中的区别:
head中的javascript代码,必须等到全部javascript代码都被下载、解析和执行完成以后,才开始呈现页面的内容(浏览器在遇到
标签时才开始呈现内容),这样会导致浏览器在呈现页面时出现明显的延迟。在body中的javascript代码会在解析前,页面的内容将完全呈现在浏览器中
2.2 延迟
只适用与外部脚本
defer是延迟属性,即要等到浏览器遇到标签后再执行,在HTML5规范要求脚本按照它们出现的先后顺序执行,因此第一个延迟脚本会先于第二个延迟脚本执行,且它们都会先与DOMContentLoaded事件。有的浏览器不支持该属性,所以,延迟脚本放在页面底部仍然是最佳选择
2.3 异步脚本
async属性与defer属性类似,都是用于改变处理脚本的行为,都只适/用于外部文件。告诉浏览器立即下载文件。但,async并不保证按照它们的先后顺序执行
2.4文档模式
文档模式种类:混杂模式、标准模式、准标准模式(IE后来提出的)
PS:标准模式与准标准模式差异不大,所以大多时候都被笼统的称为标准模式
2.5 noscript元素
用以在不支持JavaScript的浏览器中替代的内容。这个元素可以包含能够出现在文档
中的任何HTML元素(script元素除外)只有一下其中的任意情况才会被触发:
(1)浏览器不支持脚本
(2)浏览器支持脚本,但被禁用
三 基本概念
3.1 语法
3.1.1 区分大小写
ECMAScript中的一切(变量、函数名和操作符)都区分大小写。
3.1.2 严格模式
要在整个脚本中启动严格模式,可以在顶部添加如下代码:
“use strict”;
3.2 数据类型
基本数据类型:Undegined、Null、Boolean、Number、Stirng 基本数据类型的一系列操作不会改变本身的值
字符串不可变性: 在js当中,操作字符串的时候,并不是在原来的字符串上进行修改,而是重新开辟内存,生成新的字符串,把变量重新指向新的字符串,原来的字符串并不会马上消失,而是等待垃圾回收机制进行回收
复杂数据类型(引用数据类型):object。比如有函数、数组、对象
// 基本数据类型传参,传的是副本
// 引用数据类型传参,传的是地址
var a = 10
function fn(a) {
a = 12
return ("函数内的参数值:" + a)
}
console.log(fn(a))
console.log("函数外的值:" + a)
var arr = [1, 2, 6, 3, 4]
function max(arr) {
arr = [12] //开辟另一个空间
return "函数内的数组元素:" + arr
}
console.log(max(arr))
console.log("函数外的数组元素:" + arr)
var arr = [1, 2, 6, 3, 4]
function max(arr) {
arr.push("我是最后的元素") //这是在原来的地址上进行修改值的内容
return "函数内的数组元素:" + arr
}
console.log(max(arr))
console.log("函数外的数组元素:" + arr)
3.2.1 typeof操作符
typeof是一个操作符而不是函数,因此可以是typeof(xxxx);也可以是typeof xxxx;
var mass1=undefined; alert("mass1的值"+(mass1==undefined));//返回值true var mass2 ;alert("mass2的值"+(mass2==undefined));//返回值true
说明这两种情况效果的一样的
var a
console.log(a === undefined) //true
console.log(typeof(a) === 'undefined') //true
3.2.2 NAN
非数值是一种特殊的数值
表示一个本来要返回一个数值却没有返回数值的操作情况,可以直接返回NAN
alert(NaN==NaN);//返回的是false
isNaN函数判断的是这个参数是否不是数值
alert("这个值是非数值:"+isNaN(10));
有三种方法可以把非数值转换成数值的函数:
Number()、parseInt()、parseFloat()
(1)Number可以用于任何数据类型
(2)parseInt
空格和函数转换成数字时,都会是NAN类型,只有字符串数字才能转换成数字
var input = prompt('只能输入数字:')
var str = Number(input)
if (isNaN(str)) {
console.log('请输入数字!!')
} else {
console.log('欢迎使用!!')
}
注释:
prompt() 方法用于显示可提示用户进行输入的对话框。
语法:
prompt(text,defaultText)
参数 | 描述 |
---|---|
text | 可选。要在对话框中显示的纯文本(而不是 HTML 格式的文本)。 |
defaultText | 可选。默认的输入文本。 |
说明
如果用户单击提示框的取消按钮,则返回 null。如果用户单击确认按钮,则返回输入字段当前显示的文本。
在用户点击确定按钮或取消按钮把对话框关闭之前,它将阻止用户对浏览器的所有输入。在调用 prompt() 时,将暂停对 JavaScript 代码的执行,在用户作出响应之前,不会执行下一条语句。
3.2.3 转换为字符
第一种方式:toString()方法
除了null和undefined的值没有这个方法外,像数值、布尔值、对象和字符串都有toString()方法
第二种方式:String()方法
因为null和undefined的值没有toString()方法,所以,在不知道要转换的值是否有toString()方法,可以使用String(),因为String()方法适用与所有值。
String()方法有以下规则:
(1)如果值有toString(),则调用toString()方法
(2)如果值是null,则返回“null”
(3)如果值是undefined,则返回“ undefined”
3.2.3 转换为布尔值
Boolean()
把其他任意类型转换为布尔
在js当中,有哪些可以转换为false
null,undefined,0,"",false,NaN
隐式转换 !!数据
3.3 语句
3.3.1 for-in语句
例句:
for(var a in b){
.......
}
函数也是数据类型
3.4函数
只有函数才能形成局部作用域
3.4.1函数返回值
每一个函数都有一个默认返回值,undefined,所以,一个函数写
renturn 没有返回值;
return xxx;
没有retuen
三者是等价的,都会返回值undefined
function test() {
console.log('我是函数test');
}
function test1() {
console.log('我是函数test1');
return;
}
function test2() {
console.log('我是函数test2');
return undefined;
}
console.log(test())//我是函数test undefined
console.log(test1())//我是函数test1 undefined
console.log(test2())//我是函数test2 undefined
// Ps:函数默认返回值undefined,所以没有写return和写return但没有返回值以及返回值undefined都是一样的
(1)如果函数里没有写return关键字,函数执行完毕之后,默认返回undefined
(2)如果函数里写有return关键字,但没有跟任何值,函数执行完毕之后,默认返回undefined
(3)如果函数里写有return关键字,且后面跟有值,则函数执行完毕之后,返回return后面的这个东西
注意:return 除了能够返回函数的返回值外,还可终止函数的执行
function arr() {
console.log(1)
console.log(2)
return;
console.log(3)
}
arr()//只返执行 console.log(1)和console.log(2)
3.4.2函数有无括号的区别
var test=function test() {
console.log('我是函数test');
}
console.log(test())
//返回
/* console.log('我是函数test');
undefined
*/
Ps: 如果函数里面没有写return关键字,函数执行完毕之后,会默认的到undefined
console.log(test)
// 返回
/*
function test() {
console.log('我是函数test');
}
*/
//Ps:函数名加括号,返回的是函数里面的值,而没有括号的则是当成了变量
3.4.3 函数传参
function bigTow(arr) {
for (var i = 0; i < arr.length; i++) {
arr[i] = arr[i] * 2;
return arr;
}
}
var arr1 = [1, 2, 4, 3];
arr1 = bigTow(arr1);
console.log(arr1);
3.4.4 形参和实参
// 传参
// 乘2的函数
function bigTow(arr) { //此处的参数是形参
return arr * 2;
}
// 比较大小的函数
function numMax(arr) { //此处的参数是形参
var max = arr[0];
for (var i = 0; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i]
}
}
return max;
}
var arr1 = [1, 2, 4, 3];
var b = bigTow(numMax(arr1)) //此处的参数是实参
console.log('最大值:' + numMax(arr1))
console.log('最大值乘以2:' + b);
函数里面的参数都是形参,调用函数里面的参数是实参
3.4.5 匿名函数
匿名函数只是用一次,可以当参数传递
// 匿名函数
function methad(a, b, fn) { //回调
return fn(a, b)
}
console.log(methad(2, 2, function(a, b) { //匿名函数传参
return a + b
}))
3.4.6 自执行函数
(1)无参
(function() {
console.log('无参闭包')
})()
(2)有参
// ------------自执行函数(闭包)------------
(function(a, b) {
console.log(a * b)
})(2, 3)
3.4.7 作用域
在js中只有函数才有作用域
函数执行顺序是,先找函数里面的变量,即就近原则。没有时,则会向外层函数查找。
3.4.8 变量提升
变量可以提升,函数也可以提升
先提升变量,再提升函数
console.log(a);
var a = 1;
console.log(a);
function a() {
return false;
}
//-----变量提升
var a
function a() {
return false
}
console.log(a) //打印的是函数,因为变量a被函数a赋值
a = 1
console.log(a) //此时打印的是值1
3.4.9 闭包
闭包的作用:
第一:闭包可以解决函数外部无法访问函数内部变量的问题
如果我们要获取函数fn()里的变量,该怎么办呢?
function fn() {
var a = 10;
}
console.log(a) //报错,a没有定义
此时我们可以通过 return a 返回出a,外面就可以获取函数fn()里的变量a了
function fn() {
var a = 10;
return a
}
console.log(fn()) //a=10
第二:可以持久保持函数的变量
为什么呢?因为函数一旦调用里面的内容就会被销毁,下一次调用又是一个新的函数,和上一个调用的不相关了
function fn(){
var num = 5;
num+=1;
alert(num);
}
fn(); //6
fn(); //6
function fn(){
var num = 0;
return function(){
num+=1;
alert(num);
};
}
var f = fn();
f(); //1
f(); //2
这里之所以执行玩这个函数num没有被销毁是因为那个匿名函数的问题,因为这个匿名函数用到了这个num,所以没有被销毁,一直保持在内存中,因此我们f()时num可以一直加。
过多的使用闭包导致内存泄漏
3.5 数组的方法
3.5.1 concat数组连接
// ---------------数组的方法-------------
var arr1 = [1, 2, 3, 4]
var arr2 = [5, 6, 7, 8]
console.log(arr2.concat(arr1)) //数值arr2连接arr1 5, 6, 7, 8,1, 2, 3, 4
console.log(arr1) //1, 2, 3, 4
console.log(arr2) //5, 6, 7, 8
// Ps 说明数组的连接不会改变原来的数组值
concat是数组连接字符串或数组连接数组
3.5.2 join字符串分割
// --------join
var arr3 = [22, 3, 4, 5]
console.log(arr3.join('+')) //22+3+4+5
join是通过某种字符来连接数组的元素
3.5.3 shift删除第一个数组元素
//----------shift删除数组的第一个元素
var arr4 = [1, 2, 3, 4, 5, 6];
console.log('删除第一个元素前的数组:' + arr4) //删除第一个元素前的数组:1,2,3,4,5,6
console.log('删除第一个元素为' + arr4.shift()) //删除第一个元素为1
console.log('删除第一个元素后的数组:' + arr4) //删除第一个元素后的数组:2,3,4,5,6
// ps 能够改变原来的数组
3.5.4 pop删除最后一个数组元素
//----------pop删除数组的第一个元素
var arr5 = [1, 2, 3, 4, 5, 6];
console.log('删除最后一个元素前的数组:' + arr5) //删O除最后一个元素前的数组:1,2,3,4,5,6
console.log('删除最后一个元素为' + arr5.pop()) //删除最后一个元素为6
console.log('删除最后一个元素后的数组:' + arr5) //删除最后一个元素后的数组:1,2,3,4,5
// ps 能够改变原来的数组
3.5.5 indexOf查询数组元素
indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置
stringObject.indexOf(searchvalue,fromindex)
参数 | 描述 |
---|---|
searchvalue | 必需。规定需检索的字符串值。 |
fromindex | 可选的整数参数。规定在字符串中开始检索的位置。它的合法取值是 0 到 stringObject.length - 1。如省略该参数,则将从字符串的首字符开始检索。 |
注意 | 注释:indexOf() 方法对大小写敏感!如果要检索的字符串值没有出现,则该方法返回 -1。 |
实例1:
//-----------indexOf
var arr6 = [1, 2, 2, 3, 4, 5, 2, 7, 2]
var index = 0;
var arr = []
while ((index = arr6.indexOf(2, index)) != -1) {
arr.push(index)
index++
}
console.log('数组中2的下标分别为:' + arr)
// Ps:indexOf查询的是数组元素,元素存在时返回的是1,不存在时返回-1
实例2:去重方法一
var array = [1, 2, 3, 4, 3, 1, 7, 8]
var arr = [] //创建一个空的数组
function deRepeat(array) {
for (var i = 0; i < array.length; i++) { //遍历数组array
if ((arr.indexOf(array[i])) == -1) { //拿array[i]去arr中查找,如果不存在则存入
arr.push(array[i])
}
}
return arr
}
console.log('去重前的数组为:' + array) //去重前的数组为:1,2,3,4,3,1,7,8
console.log('去重时的数组为:' + deRepeat(array)) //去重时的数组为:1,2,3,4,7,8
console.log('去重后的数组为:' + array) //去重后的数组为:1,2,3,4,3,1,7,8
// 数组去重的方法二
var array = [1, 2, 3, 4, 2, 2, , 2, 3, 5, 6]
function deRepeat(array) {
for (var i = 0; i < array.length; i++) {
if (array.indexOf(array[i], i + 1) == -1) {
//--------------
} else {
array.splice(array[i], 1)
i-- //此处只删除第一元素,所以,为了后面的还存在与之相同的元素,此处需要自减用来抵消for循环里的自加,依旧是当前元素与后面的元素比较
}
}
return array;
}
console.log('去重前的数组:' + array) //去重前的数组:1,2,3,4,2,2,,2,3,5,6
console.log('去重时的数组:' + deRepeat(array)) //去重时的数组:1,2,3,5,6
3.5.6 slice 截取数组的元素
//-------------slice
var arr7 = [1, 2, 3, 4, 5]
console.log('截取前的数组为:' + arr7) //截取前的数组为:1,2,3,4,5
console.log('截取时的数组为:' + arr7.slice(1, 3)) //截取时的数组为:2,3
console.log('截取后的数组为:' + arr7) //截取后的数组为:1,2,3,4,5
Ps:不会改变原来的数组元素,截取的时候不包括第二个参数,因为第二个参数代表的是下标,左包右不包
3.5.7 splice 删除数组的元素
splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目
语法:
arrayObject.splice(index,howmany,item1,.....,itemX)
参数 | 描述 |
---|---|
index | 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置 |
howmany | 必需。要删除的项目数量。如果设置为 0,则不会删除项目。 |
item1, ..., itemX | 可选。向数组添加的新项目。 |
说明
splice() 方法可删除从 index 处开始的零个或多个元素,并且用参数列表中声明的一个或多个值来替换那些被删除的元素。
如果从 arrayObject 中删除了元素,则返回的是含有被删除的元素的数组。
注释:请注意,splice() 方法与 slice() 方法的作用是不同的,splice() 方法会直接对数组进行修改。
3.5.7.1 删除
// ------------splice
var arr8 = [1, 2, 3, 4, 5]
console.log('截取前的数组为:' + arr8) //截取前的数组为:1,2,3,4,5
console.log('删除的数组元素为:' + arr8.splice(1, 3)) //删除的数组元素为:2,3,4
console.log('截取后的数组为:' + arr8) //截取后的数组为:1,5
Ps:会改变原来的数组元素,截取的时候包括第二个参数,因为第二个参数代表的是长度
3.5.7.2 添加
// 添加数组元素
var arr9 = [1, 2, 3, 4, 5]
console.log('截取前的数组arr9为:' + arr9) //截取前的数组为:1,2,3,4,5
console.log('截取时的数组arr9为:' + arr9.splice(0, 0, 'a0', 2)) //截取时的数组为:
console.log('截取后的数组arr9为:' + arr9) //截取后的数组为:a0,2,1,2,3,4,5
3.5.7.3 字符串拆分成数组
var str = "ab cd ef";
var arr = str.split(" ");
console.log(str) // ab cd ef
console.log(arr) //["ab", "cd", "ef"]
3.5.7.4 数组拆分成字符串
//先转为数组再反转
function myReverse(str) {
var arr = str.split("")
var max = parseInt(arr.length / 2)
console.log("原来数组:[" + arr + "]")
for (var i = 0; i < max; i++) {
var temp = arr[i]
arr[i] = arr[arr.length - 1 - i]
arr[arr.length - 1 - i] = temp
}
return "反转后的数组:[" + arr + "]"
}
var str = myReverse(prompt())
console.log(str)
3.5.8 filter的使用
var arrNew=this.datasArr.filter(item =>{
return item.areaName===regionName;
})
//item是遍历数组datasArr的
3.6 定时器函数
// 循环定时器
var num = 10
function down() {
//此处的计数器不能声明在函数中,因为定时器每次调用函数时,都只是执行函数一次,所以计数器始终是初始值
console.log('此时为:' + num)
if (num == 1) {
clearInterval(setInter)
}
document.querySelector('body').innerHTML = '此时为:' + num; //这个方法可以把数据打印在页面中,且可以清楚前一个页面
num--
}
var setInter = setInterval(down, 1000)
// 一次性定时器
setTimeout(function() {
console.log('一次性定时')
}, 1000)
*/
倒计时
//---------倒计时-------
var div = document.getElementsByTagName('div')[0]
div.style.fontSize = '100px'
div.style.width = '100px'
div.style.height = '100px'
div.style.textAlign = 'center'
div.style.lineHeight = '100px'
div.style.marginLeft = '50%'
var i = 100
var timer = setInterval(function() {
div.innerHTML = i
i--
if (i < 0) {
clearInterval(timer)
}
}, 1000)
3.7 Math
- Math.ceil() 向上取整
- Math.floor() 向下取整
- Math.pow(x,y) 求x的y次方
- Math.max(x,y,z,...) 求两个或多个数字的最大值
- Math.min(x,y,z...) 求两个或者多个数字的最小值
- Math.random() 获得[0,1)之间的随机数
- Math.PI js当中的圆周率
3.8 Date
//时间戳的设置
function TIme(str) {
var time = Number(str)
var date = new Date(time)
var nian = date.getFullYear()
var yue = date.getMonth() + 1
var ri = date.getDate()
return `${nian}-${yue}-${ri}`
}
var date = new Date(); //获取当前系统的时间
// console.log('当前系统的时间:' + date)
var date1 = new Date(2019, 9, 10) //月份是从0开始的,所以此处的打印的月份是10月份
console.log('指定设置年份' + date1)
console.log('年份为:' + date.getFullYear())
console.log('当前月份为:' + (date.getMonth() + 1)) //月份需要加1
console.log('当前号数:' + date.getDate())
console.log('当前时间:' + date.getHours())
console.log('当前分钟:' + date.getMinutes())
console.log('当前秒:' + date.getSeconds())
console.log('当前毫秒数为:' + date.getMilliseconds()) //1~1000
console.log('当前时间戳为:' + date.getTime()) //获取时间戳毫秒数
var ms = +new Date(); //获取毫秒数
// console.log(ms);
ps:月份需要加1
3.9 字符串的方法
字符串中第一个字符的下标是 0
3.9.1 charAt
var str = 'abcdefghijklmn';
//获取字符串里指定位置的字符
console.log('第1个位置的字符:' + str.charAt(0)) //获取指定位置的字符串,下标从0开始 返回a
3.9.2 concat
var str1 = '000'
var str2 = 'ABC'
console.log('连接时的字符串' + str1.concat(str2)) //连接时的字符串000ABC,不改变原来的值
console.log('连接后的字符串' + str1) //连接后的字符串000
3.9.3 截取
3.9.3.1 slice截取
从start开始,到end结束的字符,可以取到start,不能得到end
//截取字符串slice()
var str = 'abcdefghijklmn';
console.log('截取字符之前:' + str) //截取字符之前:abcdefghijklmn
console.log('截取小标从0到下标为2的字符:' + str.slice(0, 3)) //截取小标从0到下标为2的字符:abc
console.log('截取小标从1到下标为2的字符:' + str.slice(1, 3)) //截取小标从1到下标为2的字符:bc
console.log('截取字符之后:' + str) //截取字符之后:abcdefghijklmn
// PS:左包右不包
3.9.3.2 substring 截取
从start开始,到end结束的字符,可以取到start,不能得到end
var str = 'abcdefghijklmn';
console.log("数组字符串:" + str)
console.log("str.substring(0, 2):" + str.substring(0, 2)) //str.substring(0, 2):ab
// PS: 得不到(不包含)第二个参数的位置
//---------slice截取、substring 截取的区别------------
str = "helloworld!";
console.log(str.slice(1, 5)); //ello
console.log(str.slice(5, 1)); //
console.log(str.substring(5, 1)); //ello
console.log(str.substring(1, 5)); //ello
3.9.3.2 substr 截取
意思是从start开始,一共截取length的长度
var str = 'abcdefghijklmn';
console.log("数组字符串:" + str) //数组字符串:abcdefghijklmn
console.log("str.substr(0,3):" + str.substr(0, 3)) //str.substr(0,3):abc
// ps: 第二个参数是lenth( 长度)