本系列课程主要会讲到标题中的 J avascriPt 部分由于内容过多所以分开了本系列课程相对来说比较重要
Javascript 是属于 HTML 和 web 的编程语言 Javascript 是一种轻量级的编程语言 Javascript 是可插入HTML 页面的编程代码 JavascriPt 插入HTML 页面后,可由所有的现代浏览器执行主要是前端中最重要的一门语言 Javascript 的学习使用 Javascript 可以做出很多有意思的效果以及优化和用户的交互体验
为什么要学习 Javasciprt ?
学习了 Javascript 有什么用?
学习完了对我有什么帮助?
这系列课程内容较多在第一阶段讲解的可能会有一大部分剩下的放在第二阶段讲解第一阶段主要重点在 Js 语法以及第二阶段主要在数据交互方面以及新语法
html4
css3/css2
xml
Markdown
. SCript 标签 JaVascript 的发展历程 J avas 。: iPt 因为互联网而生,紧跟着浏览器的出现而问世。最初主要应用在 web 浏览器找域作为脚本语言进行使用要想清楚 JavascriPt 的发展史就要了解浏览器的发展史
1 990 年底,欧洲核能研究组织科学家 Tim 日 erners 一 Lee 发明了万维网( world wide web )从此可以在网上浏览网页文件。最早的网页只能在操作系统的终端里浏览,也就是说只能使用命令行操作,网页都是在字符窗口中显示,这当然非常不方便
1 992 年底,美国国家超级电脑应用中心( NcsA )开始开发一个独立的浏览器,叫做 Mosaic 。这是人类历史上第一个浏览器,从此网页可以在图形界面的窗口浏览
1994 年 10 月, NcsA 的一个主要程序员 Marc Andreessen 联合风险投资家 Jim clark ,成立了 Mosaic 通信公司 ( Mosaic Communications ) ,不久后改名为 Netscape 。这家公司的方向,就是在 Mosaic 的基础上,开发面向昔通用户的新一代的浏览器 Netscape Navigator 1 994 年 12 月, Navigato 「发布了 1 . 0 版,市场份额一举超过 90 %
N etscaPe 公司很快发现, Navigato 「浏览器需要一种可以嵌入网页的脚本语言,用来控制浏览器行为管理层对这种浏览器脚本语言的设想是二功能不需要招虽,语法较为简单,容易学习和部署。那一年,正逢 sun 公司的 Java 语言问世,市场推广活动非常成功。 N etsc 即 e 公司决定与 sun 公司合作,浏览器支持嵌入 J ava 小程序(后来称为 Ja va a PPlet )。但是,浏览器脚本语言是否就选用 Java ,则存在争论.后来,还是决定不使用 J ava ,因为网页小程序不需要 Java 这么“重”的语法。但是,同时也决定脚本语言的语法要接近 Java ,并且可以支持 Java 程字 N etsca pe 公司的这种浏览器脚本语言,最初名字叫做 M ocha , 1995 年 9 月改为 Livescript 12 月, N etscape 公司与 sun 公司( Java 语言的发明者和所有者)达成协议,后者允许将这种语言叫做 JavascriPt 。这样一来, N etsoaPe 公司可以借助 Java 语言的声势,而 Sun 公司则将自己的影响力扩展到了浏览器后来 J ava 语言的浏览器插件失败了, JavascriPt 反而发扬光大。
ECMAScript 是一个重要的标准 简单的说 ECMAScript阐述了以下内容
ECMAScript分成几个不同的版本,它是在一个叫做 ECMA-262的标准中定义的。和其他标准一样,ECMA-262会被编辑和更新。当有了主要更新时,就会发布一个标准的新版。版本是5.1,于2011年6月发布并开始6.0版的制定
ECMAScript 6(简称ES6)是于2015年6月正式发布的Javascript语言的标准,正式名为ECMAScript 2015(ES2015)。它的目标是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言
1996年8月,微软模仿 JavaScript开发了一种相近的语言,取名为JScript(JavaScript是Netscape的注册商标,微软不能用),首先内置于IE3.0。Netscape公司面临丧失浏览器脚本语言的主导权的局面。
1996年11月,Netscape 公司决定将JavaScript提交给国际标准化组织 ECMA(European Computer Manufacturers Association),希望 JavaScrip能够成为国际标准,以此抵抗微软
ECMAScript 只用来标准化 Javascript 这种语言的基本语法结构,与部署环境相关的标准都由其他标准规定,比如DOM的标准就是由w3C组织(World wide web Consortium)制定的
DOM(文档对象模型)是HTML和XM的应用程序接口(APl)。DoM将把整个页面规划成由节点层级构成的文档。HTML 或xML 页面的每个部分都是一个节点的衍生物btml
DOM通过创建树来表示文档,从而使开发者对文档的内容和结构具有空前的控制力。用DOMAPI可以轻松地删除、添加和替换节点
BOM主要处理浏览器窗口和框架,不过通常浏览器特定的 Javascript扩展都被看做BOM的一部分。这些扩展包括
在编程语言中 一般固定值称为字面量 如3.14
数字(Number) 字面量可以是整数或者小数
字符串(String) 字面量可以是单引号或者双引号
表达式字面量 用于计算
5 + 6
5 + 10
document.write();
console.log();
console.dir();
console.error();
console.time();
console.timeEnd();
console.info();
console.warn();
高级用法
console.table([['中国','美国'],['好']]);
//格式化输出
/*
console.log支持的格式标志有:
%s 占位符
%d 或 %i 整数
%f 浮点数
%c css样式
*/
console.log('%d + %d = %d',1,2,3)
console.group('分组1');
console.log('语文');
console.log('数学');
console.group('其他科目');
console.log('化学');
console.log('地理');
console.log('历史');
console.groupEnd('其他科目');
console.groupEnd('分组1');
JavaScript 是发给浏览器的命令
用于分隔JavaScript语句
a = 5;
b = 6;
c = a + b;
或者
a = 5; b = 6; c = a + b;
JavaScript 是脚本语言 浏览器在读取代码时 会逐行的执行脚本代码 对于其他有的编程语言来说 在执行前会对所有代码进行编译
注释可以用于提高代码的阅读性
语法
单行注释以 //
开头
// 输出标题
document.getElementById("myH1").innerHTML = "欢迎来到我的主页";
多行注释 以 /*
开始 */
结束
/*
注释内容
*/
变量是用于存储信息的容器 在JS中我们可以通过变量来存储具体的数据
var x = 5;
var y = 6;
var z = x+y;
在ES5中我们通过 var 来声明变量
JS中不严格区分数据类型 所以我们仅仅使用var来进行变量声明 可以存储JavaScript中的任意类型
通过 = 符号来进行赋值 右边的是值 左边的是变量名称 给右边的值赋予左边的变量
var a = 5;
var a = 15;
var b = 15;
var a = 2 , b = 2;
var a,b,c = 5;
var a = b = c = 1;
首字符
组成
禁忌
Javascript 的保留关键字不可以用作变量、标签或者函数名。有些保留关键字是作为 Javascript 以后扩展使用
小提示: 这里指的保留字关键字就是和var一样的具有特殊意义的名称不能当做变量的名称来使用
必须显式声明
重复声明
隐式声明
不声明直接赋值
先声明 后读写
先赋值 后运算
console.log(a); // undefined 将a声明提前了 所以输出undefined 并不会报错
var a = 5;
typeof
检测数据类型
typeof name === 'string'
typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型
它返回值是一个字符串,该字符串说明运算数的类型。typeof 一般只能返回如下几个结果
number,boolean,string,function,object,undefined。我们可以使用 typeof 来获取一个变量是否存在,如 if(typeof a!=“undefined”){alert(“ok”)},而不要去使用 if(a) 因为如果 a 不存在(未声明)则会出错,对于 Array,Null 等特殊对象使用 typeof 一律返回 object,这正是 typeof 的局限性
instanceof
检测数据类型
person instanceof Person
instanceof 用于判断一个变量是否某个对象的实例,如 var a=new Array();alert(a instanceof Array); 返回true
在函数体外部定义的变量
在函数体内部定义的无var的变量
在任何位置都可以调用
在函数内部使用 var 定义
函数的参数
在函数内部可以调用
局部变量高于同名全局变量
参数变量高于同名全局变量
局部变量高于同名参数变量
全局变量是全局对象的属性
内层函数可以访问外层函数局部变量
外层函数不可以访问内层函数局部变量
全局变量
局部变量
回收机制
在JS中我们会接触到非常多的数据类型 大致有8种到现在 在第一阶段我们接触6种
==
会返回 true(123).toString(2)
Number()
parseInt()
parseInt("f",16)
可以接收第二个参数进行进制的转换为10进制parseFloat()
|
"string | 0"
结果是0 "123 | 0" 结果是 123
加减乘除转换数值
console.log("123"*1); // 123
console.log(+"123"); // 123
console.log(-"123"); // -123
console.log("123"/1); // 123
>>
console.log("123" >> 0); // 123
~~
~~("123") // 123
Math.js
/**
* Created by Jerry Tong on 2016/7/4.
*/
Math.add = function(v1, v2)
{
var r1, r2, m;
try
{
r1 = v1.toString().split(".")[1].length;
}
catch (e)
{
r1 = 0;
}
try
{
r2 = v2.toString().split(".")[1].length;
}
catch (e)
{
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2));
return (v1 * m + v2 * m) / m;
}
Number.prototype.add = function(v)
{
return Math.add(v, this);
}
Math.sub = function(v1, v2)
{
return Math.add(v1, -v2);
}
Number.prototype.sub = function(v)
{
return Math.sub(this, v);
}
Math.mul = function(v1, v2)
{
var m = 0;
var s1 = v1.toString();
var s2 = v2.toString();
try
{
m += s1.split(".")[1].length;
}
catch (e)
{
}
try
{
m += s2.split(".")[1].length;
}
catch (e)
{
}
return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);
}
Number.prototype.mul = function(v)
{
return Math.mul(v, this);
}
Math.div = function(v1, v2)
{
var t1 = 0;
var t2 = 0;
var r1, r2;
try
{
t1 = v1.toString().split(".")[1].length;
}
catch (e)
{
}
try
{
t2 = v2.toString().split(".")[1].length;
}
catch (e)
{
}
with (Math)
{
r1 = Number(v1.toString().replace(".", ""));
r2 = Number(v2.toString().replace(".", ""));
return (r1 / r2) * pow(10, t2 - t1);
}
}
Number.prototype.div = function(v)
{
return Math.div(this, v);
}
Number(123.54566.toFixed(2)).valueOf()
Number(123.54566.toFixed(2))
Object.prototype.toString.call(ObjectName) // [object Array]
语法
if(条件表达式1){
代码段1
}else if(条件表达式2){
代码段2
}else{
代码段3
}
特性
语法
switch(1){
case 1:
console.log(1);
break;
case 2:
console.log(20);
default:
console.log("default");
}
格式
特性
语法
var a = 0;
while(a < 5) {
console.log(a);
a++;
}
流程
特性
语法
var a = 5;
do{
console.log(a);
a++;
}while(a < 10);
流程
特性
语法
for(var i = 1 ; i < 10 ; i++){
console.log(i);
}
流程
双重for循环
for(var i = 1 ; i < 10 ; i++){
for(var j = 1 ; j <= i; j++){
document.write(" "+j+"*"+i+"="+i*j+" ");
}
document.writeln("
");
}
document.writeln("");
for(var i = 1 ; i < 5 ; i++){
document.writeln("");
for(var j = 1 ; j < 6; j++){
document.writeln("第"+i+"第"+j+"列 ");
}
document.writeln(" ");
}
document.writeln("
");
语法
var a = {
name:"Lucson",
age:18
};
for(var temp in a){
console.log(temp);
}
作用
注意事项
语法
var a = [{},2,3]
for(var temp of a){
console.log(temp);
}
作用
注意事项
语法
var a = [1,2,3,4];
a.forEach(function(item,index,arr){
console.log(item,index);
})
作用
特性
终止函数体的运行 并且返回一个值
使用方式
function getName(){
// 返回值
return "小明";
// return 下面如果还有语句 则不会执行
}
var a = getName();
console.log(a); // 小明
终止整个循环不在进行判断
使用方式
for(var i = 1 ; i < 5 ; i ++){
if(i == 4){
// 直接退出循环
break;
}
console.log(i); // 1 2 3
}
结束本次循环 接着去判断是否执行下次循环
使用方式
for(var i = 1 ; i < 5 ; i ++){
if(i == 2){
// 跳过本次循环 继续执行下一次循环
continue;
}
console.log(i); // 1 3 4
}
函数是定义一次但是可以多次调用的一段JS代码 函数有时候会传参数 即函数被调用时指定了的局部变量 函数常常使用这些参数来计算一个返回值 这个值也成为函数调用表达式的值 同时函数是一个功能的封装 通过调用这个功能完成某一些操作
函数对于每一种语言来说都是一个非常核心的概念 通过函数可以封装任意多条语句 而且可以在任意地方任意时候进行调用 JavaScript 中使用 function 关键字来声明函数 后面跟一组参数以及函数体
function box(){
console.log("调用我我才会执行");
}
box();
function box(name,age){
console.log("name:"+name,"age:"+age);
}
box("lucson",21);
带参数和不带参数的函数 都没有定义返回值 而是调用后直接执行的 实际上任何函数都可以通过 return 关键字来返回需要返回的值
无参数函数带返回值
function box(){
return "我是返回的值";
}
console.log(box("lucson",21)); // 我是返回的值
有参数函数带返回值
function box(name,age){
console.log("name:"+name,"age:"+age);
return name+"-"+age
}
console.log(box("lucson",21)); // lucson-21
还可以给带有返回值的函数赋值给一个变量 通过变量进行操作
function box(name,age){
return name+"-"+age
}
var a = box("lucson",21);
console.log(a); // lucson-21
return关键字还有一个作用就是退出当前函数 和 break 不同 break是用在循环里和switch语句中的
第一个 return 后面的语句不在执行
function box(name,age){
return 100;
return name+"-"+age;
}
var a = box("lucson",21);
console.log(a); // 100
break用在函数内将会提示JS错误信息
function box(name,age){
break;
}
var a = box("lucson",21); // SyntaxError: Illegal break statement
JavaScript 不介意传递进来多少参数 也不会因为参数杂乱无章产生错误 但是函数内部有一个对象来接受到我们所传递进来的参数 它是一个数组
function box(name,age){
console.log(arguments[0],arguments[1])
}
var a = box("lucson",21); // lucson 21
arguments 对象的 length 属性可以得到参数的数量
function box(name,age){
return arguments.length;
}
var a = box("lucson",21);
console.log(a); // 2
没有参数我们通过arguments[]获取会获得undefined
可以利用length属性来智能判断有多少参数 然后吧参数进行应用
现在我们实现一个累计进行相加操作的函数但是其传递的参数是不固定的
function box(){
var sum = 0;
if(arguments.length == 0) return sum;
for(var i = 0 ; i < arguments.length ; i++){
if(typeof arguments[i] != "number") {
sum = 0;
break;
}
sum += arguments[i];
}
return sum;
}
var a = box(1,2,10);
console.log(a); // 2
Js中没有重载功能
重载指的就是相同的函数名称 不同的参数列表或者类型
function box(name){
console.log(name);
}
function box(name,age){
console.log(name,age)
}
box("Lucson",21);
普通声明
function box(num1,num2){
return num1 + num2;
}
使用变量初始化函数
var box = function(num1,num2){
return num1 + num2;
};
使用构造函数声明
var box = new Function("num1","num2","return num1+num2;");
function box(sum,num){
return sum+num;
}
function sum(num){
return num+10;
}
var result = box(sum(10),10);
console.log(result); // 30
function box(sum,num){
return sum(10)+num;
}
function sum(num){
return num+10;
}
var result = box(sum,10);
console.log(result);
有时候我们需要很多个数据 这个时候我们就可以传递一个对象到函数中去
function box(obj){
return obj.name+"-"+obj.age;
}
var result = box({
name:"lee",
age:21
});
console.log(result);
有时候我们需要先获取到某些数据在进行下一步操作这时候可能就需要
function requestData(sendMessage,num){
sendMessage(num)+"-新的数据";
}
requestData(function(num){
console.log(num);
},10);
在函数的内部 有两个特殊的对象:arguments 和 this arguments 是一个类数组对象 包含着传入函数中的所有参数 主要用途是保护函数参数 但是这个对象还有一个 名叫 callee 的属性 该属性是一个指针 指向拥有arguments对象的函数
实现阶乘就必须使用递归函数
function num(n){
if(n <= 1){
return 1;
}else{
return n * num(n-1);
/*return n * arguments.callee(n-1);*/
}
}
/* 理解递归 */
4*3
4*3*2
4*3*2*1
4*3*2
4*6
24
console.log(num(4)); //4 * 3 * 2 * 1
我们实现了一个阶乘函数 但是现在如果我们的函数名称发生了改变 那么我们函数内部的函数也是需要进行修改的 如果有多个函数名的话我们难不成要都修改了吗?
其实我们这时候就可以通过 arguments.callee() 来搞定这个问题 详细代码例如上面的注释内容
函数内部另一个特殊对象时 this 其实 this 就相当于它被调用时那个函数的作用域
但是这个也有点不太准确 因为this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象
当在全局作用域中使用 this 的话 this 指向的使 window 对象
window 是 JS 中最大的对象 最外围的
console.log(window); // window
console.log(this); // window
我们可以发现通过给 window 添加属性可以直接获取到
window.color = "蓝色的";
console.log(this.color);
以下例子演示了this的指向
window.color = "蓝色的";
var obj = {
color:"红色的",
sayHello:function(){
return this.color;
}
}
console.log(this.color);
console.log(obj.sayHello());
全局作用域下的函数内部的this也是指向 window
window.color = "蓝色的";
function sayHello(){
return this.color;
}
console.log(window.sayHello());
下面例子再次加深this的理解
window.color = "蓝色的";
function sayHello(){
return this.color;
}
var obj = {
color:"红色的"
}
obj.sayHello = sayHello;
console.log(window.sayHello());
console.log(obj.sayHello());
简单来说 就是谁调用某个属性或者方法那么this就指向谁
持续看例子:
function a(){
var user = "xxx";
console.log(this.user); //undefined
console.log(this); //Window
}
a();
按照我们上面说的this最终指向的是调用它的对象,这里的函数a实际是被Window对象所点出来的,下面的代码就可以证明
function a(){
var user = "xxx";
console.log(this.user); //undefined
console.log(this); //Window
}
window.a();
和上面代码一样吧,其实alert也是window的一个属性,也是window点出来的
持续看例子:
var o = {
user:"xxx",
fn:function(){
console.log(this.user); //xxx
}
}
o.fn();
这里的this指向的是对象o,因为你调用这个fn是通过o.fn()执行的,那自然指向就是对象o 在调用的时候才能决定,谁调用的就指向谁
持续看例子:
var o = {
user:"追梦子",
fn:function(){
console.log(this.user); //追梦子
}
}
window.o.fn();
这段代码和上面的那段代码几乎是一样的,但是这里的this为什么不是指向window,如果按照上面的理论,最终this指向的是调用它的对象,这里先说个而外话,window是js中的全局对象,我们创建的变量实际上是给window添加属性,所以这里可以用window点o对象
这里先不解释为什么上面的那段代码this为什么没有指向window,我们再来看一段代码
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //12
}
}
}
o.b.fn();
这里的输出结果也是 12
总结: this只会指向直接调用他的那个对象 即使调用他的那个对象也被调用 仍然指向他的直接上级的对象
再看例子:
var o = {
a:10,
b:{
// a:12,
fn:function(){
console.log(this.a); //undefined
}
}
}
o.b.fn();
尽管对象b中没有属性a,这个this指向的也是对象b,因为this只会指向它的上一级对象,不管这个对象中有没有this要的东西
特殊的情况:
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
这里this指向的是window this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的
然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window 因为最后是被wwindow调用执行的
this 碰上 return
当我们函数返回一个对象时再去实例化这个时候这个内部的this指向就指向了 window
function fn() {
this.aaa = "Lucson";
return {};
}
let v = new fn();
console.log(v.aaa); // undefined
当我们函数返回一个不是对象的内容再去实例化这个时候这个内部的this指向就不会指向 window 了
function fn() {
this.aaa = "Lucson";
return 123;
}
let v = new fn();
console.log(v.aaa); // Lucson
JS 中 函数是对象 因此函数也拥有属性和方法
每个函数都包含两个属性 一个 是 length 一个 是 prototype
function box(name,age){}
console.log(box.length); // 2
对于 prototype 属性 他是保存所有实例方法的所在 也就是原型 这个属性现在暂时不讲 我们在面向对象的时候在去说它
prototype 下面有两个方法
apply 和 call 是一样的 不一样的是 传递参数的方式不同 两个都能通过假冒其他的对象去调用其他对象的方法
function box(num1,num2){
return num1+num2;
}
function sum(num1,num2){
return box.call(this,num1,num2);
}
console.log(sum(10,10));
传递参数调用方法不是 apply 和 call 真正需要使用的地方 它们的主要作用是修改作用域
使用 apply 和 call 的最大好处就是对象不需要与方法发生耦合 就是相互关联 那么扩展和维护就会产生一些连锁反应
例子
var color = "red";
function sayColor(){
return this.color;
}
var obj = {
color:"blue"
}
// obj.sayColor = sayColor; 这一句不需要了 断开关联
console.log(sayColor.call(obj));
console.log(sayColor.call(window));
function box(num1,num2){
return num1+num2;
}
function sum(num1,num2){
return box.apply(this,[num1,num2]);
}
console.log(sum(10,10));
通过 bind 方法 可以改变函数内部的this指向 但是我们使用apply和call冒充之后是直接调用了函数而使用bind仅仅是绑定而不会同时调用
他返回的使一个函数所以我们需要再加一个小括号进行调用
window.color = "蓝色的";
function sayHello(num){
return this.color+num;
}
var obj = {
color:"红色的"
}
concole.log(sayHello.bind(this,10)());
concole.log(sayHello.bind(obj,10)());
其实 call 函数 就是在对应的对象里添加一个函数 达到调用的目的
function Fn(a,b,c,d,e) {
console.log(this.clothes,a,b,c,d,e);
return a;
}
const o = {
clothes:"shirt",
};
Function.prototype.myCall = function (o) {
o = o || window;
const newArgs = [];
o.fn = this;
for(let i = 1 ; i < arguments.length; i++){
newArgs.push("arguments["+i+"]");
}
let res = eval("o.fn("+newArgs+")");
delete o.fn;
return res;
};
console.log(Fn.myCall(o,1,2,3,4,5));
function Fn(a,b,c,d,e) {
console.log(this.clothes,a,b,c,d,e);
return a;
}
const o = {
clothes:"shirt",
};
Function.prototype.myApply = function (o,arrArgs) {
o = o || window;
const newArgs = [];
o.fn = this;
let res = null;
if(!arrArgs){
res = o.fn();
}else {
for(let i = 0 ; i < arrArgs.length; i++){
newArgs.push("arrArgs["+i+"]");
}
res = eval("o.fn("+newArgs+")");
}
delete o.fn;
return res;
};
console.log(Fn.myApply(o,[{},2,3,4,5]));
function Fn(a,b,c,d) {
console.log(this.clothes,a,b,c,d);
return a;
}
const o = {
clothes:"shirt",
};
Function.prototype.myBind = function (o) {
let that = this,args1 = Array.prototype.slice.call(arguments,1),args2;
return function () {
args2 = Array.prototype.slice.call(arguments);
that.apply(o,args1.push.apply(args1,args2) && args1);
}
};
Fn.myBind(o,1,2,3)(4);
我们都知道 在JS中分为两大类数据类型 一种是基本类型 一种是引用类型
函数也是属于引用类型 也是在堆中进行存储的 不过函数在 堆空间的存储就是一串字符串
同时也会分配一个引用地址 在函数调用时会在栈中运行 通过函数名访问到当前这个堆中存储的函数字符串 然后进行解析
ECStack 执行环境栈,它也是浏览器从内存中拿出的一块内存,但是是栈结构内存,作用是执行代码,而非保存代码
EC 执行上下文,EC不同于ECStack它虽然同样是栈内存,但是它的作用是为了在函数执行时,区分全局和函数作用域执行所处的不同作用域(保障每个词法作用域下的代码的独立性
浏览器会将供JS调用的属性和方法存放在GO中(内置对象),同时浏览器会声明一个名为window的属性指向这个对象
代码执行时,会创建变量,VO就是用于存储这些变量的空间
VO通常用于存放全局变量(全局变量一般情况下是不被释放的),而函数执行或其他情况下形成的私有上下文的变量存储在AO中,AO是VO的一种,区别是AO通常指的是进出栈较为频繁的对象
函数创建时,会从内存中新建一块堆内存来存储代码块。在函数执行时,会从堆中取出代码字符串,存放在新建的栈中
把之前在函数堆中存储的字符串拿过来在当前上下文中执行
通过学习大量的字符串处理函数 让我们对字符串的处理游刃有余 可以进行多样的格式化操作
要注意实例出来的String可直接赋值的String的区别
var str1 = new String("Lucson");
var str2 = "Lucson";
console.log(str1 == str2); // true
console.log(str1 === str2); // false
console.log(typeof str1); // object
console.log(typeof str2); // string
console.log(str2[0]); // u
console.log(str1[0]); // u
获取到字符串的长度
var str = "Lucson";
console.log(str.length); // 6
var str1 = "中文";
console.log(str1.length); // 2
var str1 = "\n\t";
console.log(str1.length); // 2
功能
返回字符串中第N个字符
参数
下标
返回值
合法范围 返回地n个字符的实际值
超出范围 返回空字符串
例子
var str = "Lucson";
console.log(str.charAt(0)) // L
功能
返回字符串中第N个字符的代码
参数
超出范围 返回NaN
返回值
例子
var str = new String("Lucson");
console.log(str.charCodeAt(2)); // c的 Unicode 值 99
console.log(str.charCodeAt(6)); // NaN 超出范围
功能
根据字符编码创建字符串
参数
0个或者多个参数,代表字符的Unicode编码
返回值
由指定编码字符组成的新字符串
特性
静态方法 实为构造函数String的属性
例子
console.log(String.fromCharCode("99")); // c
charCodeAt 和 fromCharCode 互为反向操作
功能
根据字符串查找位置下标
从前向后进行检索 看其是否含有子串
参数
返回值
例子
var str = "Lucson";
console.log(str.indexOf("u")) // 1
console.log(str.indexOf("u",2)) // -1
功能
根据字符串查找位置下标
从后向前进行检索 看其是否含有子串
参数
例子
var str = "Lucson";
console.log(str.lastIndexOf("u")) // 1
console.log(str.lastIndexOf("u",2)) // 1
功能
找到一个或者多个正则表达式的匹配
参数
要进行模式匹配的正则表达式
非正则表达式 将其传递给RegExp()构造函数,并转换为正则表达式对象
返回值
例子
var str = "Lucson 1 Lucson 2";
console.log(str.match("1")); // ["1", index: 7, input: "Lucson 1 Lucson 2"]
console.log(str.match(/\d+/g)); // ["1", "2"]
console.log(str.match("99")); // null
功能
检索字符串中与正则表达式匹配的子串
参数
与 match() 一样
返回值
特性
忽略全局标记 g
例子
console.log(str.search("L")); // 0
console.log(str.search(/L/)); // 0
console.log(str.search(/L/g)); // 0
console.log(str.search("z")); // -1
功能
替换一个与正则表达式匹配的子串
参数
特性
如果参数1是字符串则仅进行一次匹配替换
如果使用正则全局匹配则能多次替换
返回值
一个全新的替换后的字符串
例子
var str = "LucsonL";
console.log(str.replace("L","P")); // PucsonL
console.log(str.replace(/L/,"P")); // PucsonL
console.log(str.replace(/L/g,"P")); // PucsonP
console.log(str.replace(/L/g,function(){
return "P";
})); // PucsonP
console.log(str.replace(/qwe/g,"P"));// LucsonL
功能
根据指定分隔符将字符串分割成多个子串,并返回数组
参数
例子
var str = "Lucson";
console.log(str.split(",")) // ["L", "u", "c", "s", "o", "n"]
console.log(str.split(",")) // ["Lucson"]
console.log(str.split("",10)) // ["L", "u", "c", "s", "o", "n"]
console.log(str.split("",2)) // ["L", "u"]
concat()
语法
string.concat(value1,value2,…)
功能
链接字符串
参数
要连接到字符串上的一个或者多个值
返回值
一个全新的字符串
特性
功能与+相同 但是不会影响到原始字符串 而是返回一个全新的字符串
例子
var str = "LucsonL";
console.log(str.concat("123","789"),str); // LucsonL123789 LucsonL
console.log(str.concat("123",[123,456]),str); //LucsonL123123,456 LucsonL
slice()
功能
根据下标截取子串
参数
参数一是开始截取的下标 参数二是结束的下标
省略参数2 则以字符串长度为准
特性
截取的位置是从参数一开始到参数二前一位结束
负值参数与字符串长度相加
也可以作用于数组上
源字符串不受影响
例子
var str = "LucsonL";
console.log(str.slice(0,6)); // Lucson
console.log(str.slice(0,str.length)); // LucsonL
console.log(str.slice(-4,-2)); // so
var arr = [1,2,3,4,5,6,7];
console.log(arr.slice(0,6)); // [1, 2, 3, 4, 5, 6]
console.log(arr.slice(0,str.length)); // [1, 2, 3, 4, 5, 6, 7]
console.log(arr.slice(-4,-2)); // [4, 5]
substring()
特性
负值参数转换为0 不能用作数组 其他和 slice 一致
例子
var str = "LucsonL";
console.log(str.substring(0,6)); // Lucson
console.log(str.substring(0,-1)) //
console.log(str.substring(-1,6)); // Lucson
substr()
功能
截取字符串
参数
参数一负数 和 字符串长度相加
参数二负数转换为0
例子
var str = "LucsonL";
console.log(str.substr(0,6)); // Lucson
console.log(str.substr(0,10)) // LucsonL
console.log(str.substr(-1,6)); // L
trim(),trimLeft(),trimRight()
例子
var str = " Luc sonL ";
console.log(str); // Luc sonL
console.log(str.trim()); //Luc sonL
console.log(str.trimLeft()); //Luc sonL
console.log(str.trimRight()); // Luc sonL
缺陷
无法去除中间空格
localCompare()(了解)
功能
用本地特定顺序比较两个字符串
参数
与原字符串进行比较的字符串
返回值
负数 原字符串 < 参数字符串
0 原字符串 = 参数字符串
正数 原字符串 > 参数字符串
大小写转换
例子
console.log("Lucson".toUpperCase()) // LUCSON
console.log("Lucson".toLocaleUpperCase()) // LUCSON
console.log("Lucson".toLowerCase()) // lucson
console.log("Lucson".toLocaleLowerCase()) // lucson