js自学笔记---基础部分二
Posted 吕松松
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js自学笔记---基础部分二相关的知识,希望对你有一定的参考价值。
前言:引用类型的值(对象)是引用类型的一个实例。引用类型是一种数据结构,用于将数据和功能组织在一起。有时候也被称为对象定义,因为它们描述的是一类对象所具有的属性和方法。
1.引用数据类型
Object类型
var person = new Object();//通过object的构造函数去创建对象 var person = { //通过对象字面量表示法创建 name:"张三", "age":23, 5:true //数值属性名5会自动转成字符串 }; var person = {}; //与new Object();相同,但是使用字面量创建对象不会调用Object构造函数使用字面量方式像函数传递大量可选参数:function displayInfo(args){ var output = ""; if(typeof args.name == "string"){ output += "Name:"+args.name; } if(typeof args.age == "number"){ output += "Age:"+args.age; } } displayInfo({ name:"张三", age: 2 }); displayInfo({ name:"李四" });tips:对必需的值使用命名参数,对多个可选参数使用字面量方式封装。使用方括号访问对象的属性:var propertyName = "name"; person[propertyName]; // 可通过变量访问属性 person[first name]; // 可访问带特殊字符,或关键字的属性名
Array类型
//创建数组的方法 //一 var colors = new Array(); //二 var colors1 = ["red","blue"]; //注意: colors1[3] = "green"; alert(colors1[3]); //green alert(colors1[4]); //undefined colors1.length = 2; //通过设置数组长度可以移除数组后面的项,或添加新项 colors1[colors1.length] = "black"; //在数组末尾添加项 colors1[colors1.length] = "yellow";
数组检测: instanceof ,Array.isArray(value)
转换方法:
var person1 = { toLocaleString : function(){ //重写方法 return "张三"; } toString : function(){ return "李四"; } }; var person2 = { toLocaleString : function(){ return "张三2"; } toString : function(){ return "李四2"; } }; var people = [person1,person2]; alert(people); //默认调用数组元素的toString() 李四,李四2 console.log(people.toString());//调用每个元素的toString() 李四,李四2 console.log(people.toLocaleString());//张三,张三2数组继承的toLocaleString(),toString()和valueOf()方法,在默认情况下都会以逗号分隔的字符串形式返回数组顶。使用join()方法可以改变不用的分隔符。alert(people.join("||"));// 李四||李四2栈方法
使数组表现得像栈一样push():接收任意数量的参数,将它们逐个添加到数组末尾,并返回修改后的数组长度。pop():从数组末尾移除最后一项,减少数组的length值,然后返回移除的项。
队列方法
shift():移除数组的第一项并返回该项,同时将数组长度减1。
var arr = []; var count = arr.push("zhangsan","lisi","wangwu","zhaoliu","sunqi"); console.log(count); var firstItem = arr.shift(); //移除第一项,数组长度-1,返回移除的项 console.log(firstItem); //zhangsan console.log(arr[0]); //lisi
unshift():在数组前端添加任意个项,返回新数组长度
重排序方法
reverse():反转数组项的顺序sort():默认按升序排列数组项,sort()方法会调用每个数组项的toString()转型方法,然后比较得到的字符串,以确定如何排序。即使数组中的每一项都是数值,sort()方法比较的也是字符串。
var arr = [0,1,5,10,15]; alert(arr.sort()); // 0,1,10,15,5 按字符串比较10在5之前给定比较函数:比较函数接收两个参数,如果第一个参数应该位于第二个参数前则返回负数,相等返回0var arr = [0,1,5,10,15]; alert(arr.sort()); // 0,1,10,15,5 按字符串比较10在5之前 function compare(value1,value2){ if(value1<value2){ return -1; }else if(value1 > value2){ return 1; }else{ return 0; } } arr.sort(compare); alert(arr); //0,1,5,10,15操作方法
concat():数组连接,方法会先创建当前数组的一个副本,然后将接收到的参数添加到这个副本的末尾,最后返回新构建的数组。
var arr = ["red","blue","yellow"]; var arr1 = arr.concat(["green","gray"]); //拼接数组 var arr2 = arr1.concat("purple",["orange","black"]); alert(arr); // red,blue,yellow原来数组不变 alert(arr1);// red,blue,yellow,green,gray alert(arr2);// red,blue,yellow,green,gray,purple,orange,black
slice():截取子数组var arr = ["red","blue","yellow","green","gray","purple","orange","black"]; var arr1 = arr.slice(1); //blue,yellow,green,gray,purple,orange,black var arr2 = arr.slice(1,5); //blue,yellow,green,gray alert(arr1); alert(arr2);注意:如果slice()方法参数中是负数,就用数组长度加负数来确定位置。如果结束位置小于其实位置,返回空数组。
splice()方法:主要用途是向数组的中部插入项
- 删除:指定两个参数(要删除的第一项的位置,要删除的项数),splice(0,2) 删除数组前两项
- 插入:可以向指定位置插入任意数量的项3个参数(起始位置,要删除的项数0,插入的项)splice(2,0,"red","green")从当前数组的位置2开始插入red,green两项
- 替换:指定位置插入任意项,同时删除任意项,3个参数(起始位置,删除的项数,插入的项),插入的项数不必与删除的项数相等。如 splice(2,1,"red","green") 删除位置2的一项元素,在位置2添加red,green
注意:splice()方法始终返回一个数组,数组中包含从原来数组中删除的项,如果没删除任何项,则返回一个空数组。
var arr = ["red","blue","yellow","green","gray","purple","orange","black"]; var removed = arr.splice(0,1); //删除第一项 alert(removed) var removed1 = arr.splice(2,0,"hehe","haha");//位置2插入两项 alert(removed1); var removed2 = arr.splice(2,2,"heihei","huahua"); alert(removed2); alert(arr);位置方法
indexOf():从数组头开始查找,没找到返回-1lastIndexOf():从数组尾开始查找
var person = {name:"zhangsan"}; var people = [{name:"zhangsan"}]; var people1 = [person]; alert(people.indexOf(person)); // -1 查找的项必须严格相等 alert(people1.indexOf(person)); // 0迭代方法
every():对数组中的每一项运行给定函数,如果该函数每一项都返回true,则返回true。
some():对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true。
var numbers = [1,2,3,4,5,4,3,2,1]; //只要有一个是false就立刻返回false,结束迭代 var everyResult = numbers.every(function(item,index,array){ console.log(item);//迭代的项 console.log(index);//数组下标 return (item>2); }); alert(everyResult); //只要有一项返回true,就结束迭代 var someResult = numbers.some(function(item,index,array){ console.log(item); console.log(index); return (item>2); }); alert(someResult);
filter():对数组每一项给定函数,返回函数返回true的项组成的数组
var numbers = [1,2,3,4,5,4,3,2,1]; var filterResult = numbers.filter(function(item,index,array){ return item>2; }); alert(filterResult); // 3,4,5,4,3通常用来过滤掉数组中不符合条件的项
forEach():对数组每一项给定函数,没有返回值。与for循环迭代数组一样
var numbers = [1,2,3,4,5,4,3,2,1]; numbers.forEach(function(item,index,array){ //操作 });map():对数组中的每一项运行给定函数,返回每次函数调用的结果返组成的数组
var numbers = [1,2,3,4,5,4,3,2,1]; var mapResult = numbers.map(function(item,index,array){ return item*2; }); alert(mapResult); // 2,4,6,8,10,8,6,4,2
通常用来创建包含的项与另一个数组一一对应的数组
缩小方法
reduce():从数组的第一项开始,逐个遍历到最后reduceRight():从数组最后一项开始,向前遍历
var numbers = [1,2,3,4,5]; var sum = numbers.reduce(function(prev,cur,index,array){ return prev+cur; }); alert(sum);//15 前一个元素与当前迭代的元素相加Date类型
Date类型使用UTC(Coordinated Universal Time,国际协调时间) 19701月1日零点开始经过的毫秒数来保存日期。
var date3 = new Date(); //获取当前日期 var date = new Date("May 28, 2016"); var date1 = Date.now(); //获取当前日期的毫秒数 var date2 = +new Date(); //获取当前日期的毫秒数 alert(date); alert(date1); alert(date2-date1); alert(date3);
继承方法重写:
valueOf():获取日期的毫秒数值
var date1 = new Date(2016,0,1);//0-11月,0-23小时,军用时间 var date2 = new Date(2016,0,2); alert(date1 < date2); //true alert(date1 > date2); //false
日期格式化:
toDateString():以特定格式显示 星期,月,日,年
toTimeString():以特定格式显示 时,分,秒,时区
RegExp类型
Function类型
函数实际上是对象,每个函数都是Function类型的实例,而且与其它引用类型一样具有属性和方法。函数名实际上也是一个指向函数对象的指针,不会与函数绑定
函数的定义:
var sum = function(num1,num2){ return num1+num2; }; function sum(num1,num2){ return num1+num2; } var sum = new Function("num1","num2","return num1+num2"); //不推荐注意:使用Function构造函数去创建函数对象的时候,会导致代码解析两次(第一次是解析ECMAScript代码,第二次是解析传入构造函数中的字符串参数),从而影响性能。
由于函数名仅仅是指向函数的指针,所以一个函数可以有多个名称。
没有重载
var sum = function(num1,num2){ return num1+num2; }; function sum(num1,num2,num3){ return num1+num2+num3; } //相当于,在创建第二个函数的时候,实际上覆盖了引用第一个函数的变量sum sum = function(num1,num2,num3){ return num1+num2+num3; }
函数声明与表达式
在解析器向执行环境加载数据时,解析器会先读取函数声明,并使其在执行任何代码前可用。函数表达式则要等到解析器执行到该表达式所在的代码行时才被解释执行。
alert(sum(10,10)); //20,不会报错 function sum(num1,num2){ return num1+num2; } alert(sum1(12,12)); //会报错,Uncaught TypeError: sum1 is not a function var sum1 = function(num1,num2){ return num1+num2; }
说明:第一段代码正常执行,因为在代码开始执行之前,解析器就已经通过一个名为函数声明提升(function declaration hoisting)的过程,读取并将函数声明添加到执行环境中。对代码求值时,javascript引擎在第一遍会声明函数并将它们放到源代码树的顶部。所以,即使声明函数的代码在调用它的代码的后面,JavaScript引擎也能把函数声明提升到顶部。
第二段代码出错,原因在于函数位于一个初始化语句中,而不是一个函数声明。也就是说,在执行到函数所在的语句之前,sum1并不会保存有对函数的引用。
作为值的函数
ECMAScript中的函数名本来就是变量,所以函数也可以作为值来使用(可以将函数当参数传递,也可以在函数中返回另一个函数);function callFunction(functionName,param){ return functionName(param); } function add10(num){ return num+10; } var result = callFunction(add10,10); // 20,注意传入的是add10函数的指针,而不是add10()函数执行后的结果 function sayHello(name){ return "hello "+name; } var result1 = callFunction(sayHello,"ethan"); //hello ethan
作为返回值的函数,例子:(获取一个根据指定属性名排序的函数)
function getComparisonFunction(propertyName){ return function(object1,object2){ var value1 = object1[propertyName];//使用[]可根据变量访问属性 var value2 = object2[propertyName]; if(value1<value2){ return -1; }else if(value1>value2){ return 1; }else{ return 0; } } } var data = [{name:"zhangsan",age:25},{name:"lisi",age:26}]; data.sort(getComparisonFunction("name"));//根据name排序,lisi,zhangsan console.log(data); data.sort(getComparisonFunction("age"));//根据age排序,zhangsan,lisi console.log(data);
函数内部属性
函数内部有两个特殊的对象,arguments(类数组对象)和this:arguments包含着传入函数中的所有参数。虽然arguments对象的主要用途是保存函数参数,但这个对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。
function factorial(num){//通过递归算法,定义一个阶乘函数,与函数名紧耦合 if(num <=1){ return 1; }else{ return num*factorial(num-1); } } //使用callee改进 function factorial1(num){ if(num <=1){ return 1; }else{ return num*arguments.callee(num-1);//callee指向factorial1函数 } } var trueFactorial = factorial1;//让trueFactorial指向阶乘函数 var factorial1 = function(){//解除factorial1与阶乘函数的关联 return 0; }; console.log(trueFactorial(5));//120 console.log(factorial1(5));// 0this引用的是函数据以执行的环境对象,当在全局作用域中调用函数时,this对象引用的就是window
function sayHello(){ return this.helloName; } window.helloName = "window"; sayHello();//全局,window调用,this指向window。返回"window" var o = {helloName:"ooooo"}; o.sayHello = sayHello; o.sayHello(); //通过o对象调用sayHello函数,this指向的是o,返回 "ooooo"
ECMAScript5中也规范化了另一个函数对象的属性:caller。这个属性中保存着调用当前函数的函数的引用(如果在全局作用域中调用,它的值为null)
function outer(){ inner(); } function inner(){ alert(arguments.callee.caller);//arguments.callee指向inner()函数,arguments.callee.caller指向outer()函数 } outer();
length:表示函数希望接收的命名参数的个数函数属性和方法
prototype:对于ECMAScript中的引用类型而言,prototype是保存它们所有实例方法的真正所在。toString()和valueOf()等方法都保存在prototype名下,只不过是通过各自对象的实例访问罢了。prototype是不可枚举的,无法使用for-in发现。
每个函数都包含两个非继承而来的方法:apply()和call()。用途就是在特定的作用域中调用函数,相当于设置函数体内this对象的值。
apply():接收两个参数,一个是在其中运行函数的作用域,另一个是参数数组(可以是Array的实例,也可以是arguments对象),如:
function sum(num1,num2){ return num1+num2; } function callSum1(num1,num2){ return sum.apply(this,arguments); } function callSum2(num1,num2){ return sum.apply(this,[num1,num2]); } console.log(callSum1(10,10)); console.log(callSum2(10,20));call()方法与apply()方法的作用相同,它们的区别仅在于接收参数的方式不同。call()方法接收参数时必须逐个列出来(明确传入的每个参数)
使用apply()与call()方法扩充函数赖以运行的作用域。window.color = "red"; var o = {color:"blue"}; function sayColor(){ alert(this.color); } sayColor.apply(this); // window.color red sayColor.call(window);// window.color red sayColor.apply(o); // o.color blue注意:使用call()或apply()来扩充作用域的好处,就是对象与方法不需要有任何耦合
bind():创建函数的实例,this指向传给bind()函数的值。window.color = "red"; var o = {color:"blue"}; function sayColor(){ alert(this.color); } var sayColorObj = sayColor.bind(o); //sayColor() sayColorObj(); //blue 创建了sayColorObj()函数,this指向o对象基本包装类型
Boolean,Number,String。每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象。
var s1 = "some text"; var s2 = s1.substring(2); console.log(s2); // me text在上面代码中,s1字符串可以调用方法,实际上在读取模式中,后台会自动完成一下处理(1)创建String 类型的一个实例
(2)在实例上调用指定的方法
(3)销毁这个实例
var s1 = new String("some text"); var s2 = s1.substring(2); s1 = null;说明:引用类型与基本包装类型的主要区别就是对象的生存期。使用new创建的应用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,只存在于一行代码执行的瞬间,然后就立刻销毁。意味着我们不能在运行时为基本类型添加属性和方法
tips:可以显示调用Boolean,Number,String的构造函数来创建基本包装类型的对象。不过在非必须的情况下尽量不要这么做,因为这样很容易让人分不清自己是在处理基本类型还是引用类型。对基本包装类型的实例调用typeof会返回"object",而且所有基本包装类型的对象都会被转换为true。
var obj = new Object("some text"); alert(obj instanceof String); //trueObject构造函数也像工厂方法一样,根据传入值的类型,返回相应的基本包装类型实例。
var value = "22"; var number = Number(value);//转型函数 alert(typeof(number)); //"number" var obj = new Number(value); //构造函数 alert(typeof obj); // "object"注意:使用构造函数和同名的转型函数是不一样的。
Boolean类型
常见问题:(Boolean类型容易造成误解)
var falseObj = new Boolean(false); var result = falseObj && true; //在布尔表达式中,所有对象都会转换成true alert(result); var falseValue = false; result1 = falseValue && true; alert(result1); // falseconsole.log(typeof falseObj); //object console.log(typeof falseValue); //boolean console.log(falseObj instanceof Boolean); // true console.log(falseValue instanceof Boolean); // false最好不要用Boolean
Number类型
toString(2);转换成指定的进制,返回字符串
toFixed(2);保留指定的小数位,返回字符串(四舍五入)
String类型
var stringValue = new String("zhang san"); alert(stringValue.length);每个String的实例都有length属性,表示字符串中字符的个数。即使字符串中包含双字节字符,每个字符也只算一个字符
1. 字符方法
var stringValue = new String("zhang san"); alert(stringValue.charAt(1)); // h alert(stringValue.charCodeAt(1)); // 104 输出h的字符编码 alert(stringValue[1]);// 直接使用数字索引加[]来访问字符串中的特定字符2.字符串操作方法slice(),substr(),substring()。不会修改字符串本身,而是返回一个基本类型的字符串。
var stringValue = new String("zhang san"); stringValue.slice(3); // ng san stringValue.substring(3);// ng san stringValue.substr(3); // ng san stringValue.slice(3,7);// ng s 下标3~7的字符 stringValue.substring(3.7);// ng s stringValue.substr(3,7); // ng san 下标3开始,取7位字符3.字符串位置方法从字符串中搜索给定的子字符串,然后返回子字符串的位置(没找到就返回-1)
var stringValue = new String("zhang san"); alert(stringValue.indexOf("a")); //从开头向后搜索 2 alert(stringValue.lastIndexOf("a"));//从结尾向前搜索 7 alert(stringValue.indexOf("a",4));// 从第四位开始向后搜索 7 alert(stringValue.lastIndexOf("a",4))//从第四位开始向前搜索 2通过循环查询出所有匹配的子字符串
var stringValue = "'Card Crawl' Developers Bringing 'Enyo',a Tactical Roguelike to Mobile"; var posArr = []; var pos = stringValue.indexOf("e"); while(pos > -1){ posArr.push(pos); pos = stringValue.indexOf("e",pos+1); } alert(posArr);4.trim()方法var stringValue = " zhang san "; var trimmedStr = stringValue.trim(); alert(trimmedStr); // 返回字符串的副本,原始字符串不变5.字符串大小写转换方法var stringValue = " zhang san "; alert(stringValue.toLocaleUpperCase()); // ZHANG SAN alert(stringValue.toLocaleLowerCase()); // zhang san alert(stringValue.toUpperCase()); // ZHANG SAN alert(stringValue.toLowerCase());// zhang san6.字符串的模式匹配方法match();只接收一个参数,正则表达式或RegExp对象。
var stringValue = "cat, bat , sat , fat"; var pattern = /.at/; var matches = stringValue.match(pattern); console.log(matches); var pos = stringValue.search(/at/); alert(pos);macth()方法返回数组:第一项是与整个模式匹配的字符串,之后每一项保存着与正则表达式中的捕获组匹配的字符串。
search()返回字符串匹配的索引,从头向后查找replace()方法,替换匹配的子字符串
var stringValue = "cat, bat , cat , fat"; var result = stringValue.replace("at","kkk"); //替换第一个匹配的at子字符串 alert(result); // ckkk, bat , cat , fat var result1 = stringValue.replace(/at/g,"kkk"); alert(result1); // ckkk, bkkk , ckkk , fkkksplit()方法:将字符串根据指定的分割符切分成多个子字符串,返回数组(可指定第二个参数,指定返回的数组大小)
localeCompare()方法:比较两个字符串,字符串子字母表中排在参数前,返回负数-1。相等返回0,之后返回1var stringVal = "red"; result = stringVal.localeCompare("blue"); alert(result); // 1fromCharCode()方法:String构造函数本身还有一个静态方法,接收一个或多个字符编码,转成字符串返回(与charCodeAt()相反)alert(String.fromCharCode(104,101,108,108,111)); //hello单体内置对象
定义:由ECMAScript实现提供的,不依赖于宿主环境的对象,这些对象在ECMAScript程序执行之前就已经存在了。不必显示地实例化内置对象,因为它们已经实例化了。Object,Array,String,Global,Math都是内置对象
Global对象
全局对象,不属于任何其他对象的属性和方法,最终都是它的属性和方法,所有在全局作用域中定义的属性和函数,都是Global对象的属性。如:isNaN(),isFinite(),parseInt(),parseFloat(),都是Global对象的方法。1.URI 编码方法encodeURI():对整个URI(如:http://www.hehe.com/illegal value.htm),不会对冒号,正斜杠,问号和井号编码encodeURIComponent():对URI中某一段(如:illegal value.htm) 进行编码,对所有非标准字符进行编码
有效的URI中不能包含某些特殊字符,通过上面的方法,可以对URI进行编码,用UTF-8编码替换无效的字符。
var uri = "http://www.hehe.com/illegal value.htm#start"; alert(encodeURI(uri)); //将 空格 变成了 %20 decodeURI() var encodeUri = encodeURIComponent(uri); //对所有特殊字符都做了转换 var decodeUri = decodeURIComponent(encodeUri); //解码 alert(decodeUri);一般常用的是encodeRUIComponent()方法,只需要对传给后台的参数进行编码即可。
2.eval()方法
eval("alert('hi')");//等价与 alert("hi");当调用eval()方法时,解析器会将参数当作ECMAScript语句来解析,然后将执行结果插入到原位置。通过eval()执行的代码作用域就是当前执行的环境。因此被执行的代码具有与当前执行环境相同的作用域链。如:var msg = "hehe"; eval("alert(msg)"); //hehe eval(eval("function sayHi(){alert('hi');}"));//定义一个函数 sayHi();//可以调用
3.Global对象的属性
undefined,NaN,Infinity,Object,Array,Function,Boolean,String等等
4.window对象
说明:ECMAScript虽然没有指出如何直接访问Global对象,但Web浏览器都是将这个全局对象作为window对象的一部分加以实现的。因此,在全局作用域中声明的所有变量和函数,就都成为了window对象的属性。
var color = "red"; function sayColor(){ alert(window.color); }; window.sayColor(); //red
另一种获取global对象的方法:
var global = function(){ return this; }();
上面创建了一个立即调用的函数表达式,返回this。在没有给函数明确指定this值的情况下(无论是通过将函数添加为对象的方法,还是通过调用call(),apply()),this值等于Global对象。
Math对象
max()和min()方法:var max = Math.max(2,43,23,76,23); //接收任意多个数值参数 var min = Math.min(2,43,23,76,23); alert(max); // 76 alert(min); // 2 var valArr = [2,43,23,76,23]; var maxRes = Math.max.apply(Math,valArr); //使用math方法找到数组中的最大值 alert(maxRes);
舍入方法:将小数值舍入为整数值
Math.ceil():向上舍入
Math.floor():向下舍入
Math.round():四舍五入
console.log(Math.ceil(25.9)); //26 console.log(Math.ceil(25.5)); //26 console.log(Math.ceil(25.1)); //26 console.log(Math.floor(25.9)); //25 console.log(Math.floor(25.5)); //25 console.log(Math.floor(25.1)); //25 console.log(Math.round(25.9)); //26 console.log(Math.round(25.5)); //26 console.log(Math.round(25.1)); //25
random()方法:返回介于0和1之间的一个随机数,不包括0和1
var num = Math.floor(Math.random()*可能的数值总数+第一个可能的值); var num = Math.floor(Math.random()*10+1); //1~10的随机数 var num = Math.floor(Math.random()*9+2);//2~10的随机数function selectForm(lowerValue,upperValue){ var choices = upperValue - lowerValue +1; return Math.floor(Math.random()*choices+lowerValue); } var arr = ["red","green","blue","yellow","black","purple","brown"]; console.log(arr[selectForm(0,arr.length-1)]);小结:
- 引用类型与传统面向对象程序设计中的类相似,但实现不同
- Object是一个基础类型,其他所有类型都从Object继承了基本的属性和方法
- Array类型是一组值的有序列表,同时还提供了操作和转换这些值的功能
- 每个包装类型都映射到同名的基本类型;
- 在读取模式下访问基本类型值时,会创建对应的基本包装类型的一个对象,方便数据的操作
- 操作基本类型值的语句一旦执行完毕,创建的包装对象就会销毁
函数实际上是Function类型的实例,因此函数也是对象;函数也拥有方法,来增强其行为
在所有代码执行之前,作用域中就已经存在两个内置对象:Global和Math。在大多数ECMAScript的实现中都不能直接访问Global对象;不过,web浏览器实现了承担该角色的window对象。全局变量和函数都是Global对象的属性。
以上是关于js自学笔记---基础部分二的主要内容,如果未能解决你的问题,请参考以下文章