美文网首页
【JS学习笔记】第5章

【JS学习笔记】第5章

作者: 饥人谷_Vomx | 来源:发表于2017-04-02 21:37 被阅读0次

RegExp类型

ECMAScript通过RegExp类型支持正则表达式。
var expression = /pattern / flags;
pattern 模式就是正则表达式。

一个正则表达式是一个模式与3个标准的组合体(i、g、m)
m多行模式,即到达一行文本末时还会继续还会继续查找下一行中是否存在与与模式匹配的项。

每个元字符在正则表达式中都有一种或多种特殊用途,因此如果想要匹配字符串中包含的这些字符,就必须进行转义。

var pattern1 = /[bc]at/i;//匹配第一个"bat"或"cat",不区分大小写
var pattern2 = /\[bc\]at/i;//匹配第一个"[bc]at",不区分大小写
var pattern1 =/.at/gi;//匹配以“at”结尾的3个字符的组合,不区分大小写
var pattern2=/\.at/gi;//匹配所有".at",不区分大小写

另外一种是构造函数,接受2个参数
var pattern1 = /[bc]at/i;
var pattern2 = new RegExp("[bc]at","i");

RegExp 实例方法

RegExp对象的主要方法是exec(),该方法是专门为捕获组设计的。接受一个参数,即要应用模式的字符串,返回包含第一个匹配信息的数组;或者在没有匹配项的情况下返回null。返回的数组是Array的实例,它包含2个属性:index(匹配项在字符串中的位置)和input(表示应用正则表达式的字符串)。在数组中,第一项是与整个模式匹配的字符串,其他项是与模式中的捕获组匹配的字符串(如果没有捕获组,该数组只包含一项)

捕获组是指正则表达式中子表达式匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用。

var text = "mom and dad and baby";
var pattern = /mom( and dad ( and baby )?)?/gi;
var matches = pattern.exec(text);
alert(matches.index);//0
alert(matches.input);//"mom and dad and baby"
alert(matches[0]);//"mom and dad and baby"
alert(matches[1]); //"and dad and baby"
alert(matches[2]);//"and baby"

对于exec()方法而言,即使在模式中设置了全局标志,每次也只会返回一个匹配项,不设置全局标志,在同一个字符串上多次调用exec()每次始终返回第一个匹配项的信息。设置全局标志,每次调用exec()都会在字符串中继续查找新匹配项

var text = "car,bat,sat,fat";
var pattern1 =/.at/;

var matches = pattern1.exec(text);
alert(matches.index);//0
alert(matches[0]);//cat
alert(pattern1.lastIndex);//0

matches = pattern1.exec(text);
alert(matches.index);//0
alert(matches[0];//cat
alert(matches.lastIndex);//0


var pattern2=/.at/g;
var matches = pattern2.exec(text);
alert(matches.index);//0
alert(matches[0]);//cat
alert(pattern2.lastIndex);//3


matches = pattern.exec(text);
alert(matches.index);//5
alert(matches[0]);//bat
alert(matches.lastIndex);//8

另外一个方法test()

它接受一个字符串参数,在模式与该参数匹配的情况下返回true.否则返回false。
在只想知道目标字符串与某个模式是否匹配,但不需要知道其文本内容的情况下,这个方法非常方便。

var text = "000-00-0000";
var pattern = /\d{3}-\d{2}-\d{4}/;

if (pattern.test(text)){
    alert("The pattern was matched.");
}

构造函数的属性

RegExp构造函数包含一些属性,这些属性适用于作用域中的所有正则表达式,并且基于所执行的最近一次正则表达式操作而变化。
如果用短属性名,由于大部分不是有效的ECMAScript标识符,就必须通过方括号来访问。

var text = "this has been a short summer";
var pattern = /(.)hort/g;

if (pattern.test(text)){
   alert(RegExp.input);//this has been a short summer
    alert(RegExp.$_);
   alert(RegExp.leftContext);//this has been a
   alert(RegExp["$`"]);
   alert(RegExp.rightContext);//summer
   alert(RegExp["$' "])
   alert(RegExp.lastMatch);//short
   alert(RegExp["$&"])
   alert(RegExp.lastParen);//s  lastParen=最近一次匹配的捕获组
   alert(RegExp["$+"])
   alert(RegExp.multiline);//false
   alert(RegExp["$*"])

多达9个用于存储捕获组的构造函数属性。RegExp.$1、RegExp.$2.....分别存储第一个、第二、第九个匹配的捕获组,在调用exec() 或test() 方法时,这些属性会被自动填充。

var text = "this has been a short summer";
var pattern = /(..)or(.)/g;
if(pattern.test(text)){
   alert(RegExp.$1);//sh
   alert(RegExp.$2);//t
}

参考:http://www.cnblogs.com/snandy/p/3662423.html


function 类型

每个函数都是function类型的实例,具有属性和方法。
函数是对象,因此函数名是一个指向函数对象的指针,不会与某个函数绑定。

function sum(num1,num2){
     return num1 + num2;
}//函数声明语法

var sum =function(num1,num2){
   return num1 + num2;
}//将变量sum初始化为一个函数,function关键词后面没有函数名,因为在使用函数表达式定义函数时,没有必要使用函数名-通过变量sum即可引用函数。

var sum = new Function("num1","num2","return num1+ num2");
//function构造函数,接受任意数量的参数,最后一个参数为函数体。
//不推荐这种方式,因为会导致解析2次代码(第一次解析常规ECMAScript代码,第二次是解析传入构造函数中的字符串),从而影响性能
//不过这种方式对于理解函数是对象,函数名是指针的概念是非常直观的。

函数声明与函数表达式

alert(sum(10,10));
function sum(num1,num2){
     return num1+num2;
}

以上函数正常运行。因为在代码开始执行之前,解析器就已经通过一个名为函数声明提升(function declaration hoisting)的过程,读取并将函数声明添加执行环境中。对代码求值时,JavaScript引擎在第一遍会声明函数并将它们放到源代码树的顶部。但改为函数表达式就会导致错误。

alert(sum(10,10));
var sum =function (num1,num2){
     return num1+num2;
}

作为值的函数

function callSomeFunction(someFunction,someArgument){
     return someFunction(someArgument);
}

function add10(num){
     return num+10;
}

var result1 = callSomeFunction(add10,10);
alert(result1);//20

function getGreeting(name){
    return "Hello, " +name;
}

var result2 = callSomeFunction(getGreeting,"Nicholas");
alert(result2); //"Hello,Nicholas"

函数可以作为一个参数传递给另一个函数,也可以作为一个函数的结果返回。上例中,第一个参数someFunction是一个函数,第二个参数someArgument是传递给该函数的一个值。

function createComparisonFunction(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:"Zachary",age:28},{name: "Nicholas", age:29}];
data.sort(createComparisonFunction("name"));
alert(data[0].name);//Nicholas

data.sort(createComparisonFunction("age"));
alert(data[0].name);//Zachary;

一个对象数组,根据某个属性对数组进行排序,但需要一种方式指明按照哪个属性来排序,为此,需要定义一个函数,接受一个属性名,然后根据这个属性名来创建一个比较函数。

函数内部属性

函数内部有2个特殊对象,arguments和this.
arguments是一个类数组对象,包含传入函数中的所有参数,主要用于保存函数参数,这个对象有一个callee属性,是一个指针,指向拥有这个arguments对象的函数。

耦合是指两个或两个以上的体系或两种运动形式间通过相互作用而彼此影响以至联合起来的现象。 解耦就是用数学方法将两种运动分离开来处理问题,常用解耦方法就是忽略或简化对所研究问题影响较小的一种运动,只分析主要的运动。

function factorial(num){//定义阶乘函数一般都要用到递归算法,如果函数名称不会变化的话,这样定义没有问题。但这个函数的执行与函数名factorial仅仅耦合在了一起。为了消除耦合,可以使用arguments.callee.
   if (num<=1){
         return 1;
     } else{
         return num * factorial(num-1);
      }
 }

function factorial(num){
   if (num<=1){
    return 1;
} else {
    return num *arguments.callee(num-1);
  }
}//这个函数中,没有引用函数名factorial。

var trueFactorial =factorial;
factorial = function() {
     return 0;
};
alert(trueFactorial(5));//120
alert(factorial(5));//0

递归算法,其实说白了,就是程序的自身调用。
递归算法所体现的“重复”一般有三个要求:
  (1) 是每次调用在规模上都有所缩小(通常是减半);
  (2) 是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);
  (3) 是在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。

函数调用只有一种形式:func.call(context, p1, p2)

IMG_8127.JPG
http://stackoverflow.com/questions/7056925/how-does-array-prototype-slice-call-work
另一个函数对象的属性是caller ,保存着调用当前函数的函数的引用。
function outer(){
    inner();
}

function inner(){
      alert(inner.caller);
}

outer();

因为outer()调用了inner(),所以inner.caller指向了outer()。为了实现更松散的耦合,可以把inner.caller改为arguments.callee.caller

函数的属性和方法

函数是对象,所以也有属性和方法。2个属性:length表示接受的命名参数的个数。另一个是this,https://zhuanlan.zhihu.com/p/23804247

每个函数包含2个非继承而来的方法:apply()和call(),这2个方法的用途是在特定的作用域中调用函数,实际上等于设置函数体内this对象的数值。apply()方法接收2个参数,一个是在其中运行函数的作用域,另一个是参数数组(可以是参数数组,也可以是 Array 的实例)。call()的不同之处是第二个参数是直接的参数,逐个列举出来。(this,num1,num2)

function sum(num1,num2){
     return num1 + num2;
}

function callSum1(num1,num2){
      return sum.apply(this,arguments);//传入 arguments对象
}

function callSum2(num1,num2){
      return sum.apply(this,[num1,num2]);//传入数组
}

alert(callSum1(10,10));//20
alert(callSum2(10,10));//20

真正的作用是扩充作用域:一般是一个函数后面call一个作用域对象。

window.color = "red";
var o = {color:"blue"};
function sayColor(){
  alert(this.color);
}

sayColor();//red
sayColor.call(this);//red
sayColor.call(window);//red
sayColor.call(o);//blue

按引用传递参数,这里的引用指的是对象在内存空间中地址的引用,有可能 2 个变量指向的是同一个内存空间地址。如果将该引用传递到方法中,在方法中把这个引用中的数据改变了,那么指向这个引用的变量的值就都改变了。


基本包装类型

为什么而存在?
为了操作基本类型的值,有3个特殊的引用类型:Boolean、Number、String。
通过包装,具有引用类型的方法和属性,同时也有基本类型的特殊行为。每次读取一个基本类型的值,后台就会创建一个对应的基本包装类型的对象,从而让我们能调用方法来操作数据。基本包装类型的实例调用typeof 返回“object”。转为布尔值时都为true。Boolean(value)

var s1="some text";
var s2=s1.substring(2);

上面的代码过程如下:

var s1 = new String("some text");//创建string类型的一个实例
var s2 = s1.substring(2);//在实例上调用指定的方法
s1 = null //销毁这个实例

引用类型和基本包装类型的区别

var s1 = "some text";
s1.color = "red";
alert(s1.color);//undefined

自动创建的基本包装类型的对象,只存在于一行代码的执行瞬间,然后立即被销毁。用 new 操作符创建的引用类型的实例,在执行流离开当前作用域之前一直都保存在内存中。

把字符串传给 object 构造函数,就会创建string实例;传入数字,就会创建number实例;布尔值,则是布尔值实例。

var obj = new Object("some text");
alert(obj instanceof String);//true

但使用new调用基本包装类型的构造函数,与直接调用同名转型函数是不一样的。

var value = "25";
var number =Number (value);//转型函数
alert(typeof number);//"number"

var obj = new Number(value);//构造函数 显式调用
alert(typeof obj);//"object"
  1. Boolean 类型
    Boolean 类型是与布尔值对应的引用类型。通过构造函数创建一个 boolean 对象:
    var booleanObject = new Boolean(true);

  2. Number类型
    var numberObject = new Number(10);

Number类型还提供了一些用于数值格式化为字符串的方法。
var num = 10;
alert(num.toFixed(2));//"10:00"//指定的小数位

3.String 类型
var stringObject = new String("Hello world");

  • 字符方法——访问特定位置的字符或字符编码
var stringValue ="hello world";
alert(stringValue.charAt(1)); //"e"
alert(stringValue.charCodeAt(1)); //"101",表示e的字符编码
  • 字符串操作方法
    concat()接受任意多个参数,生成一个新的字符串副本,原来字符串不变。

3个基于字符串创建新字符串的方法:slice, substring, substr.都返回被操作字符串的一个子字符串,接受1-2个参数,第一个参数指定子字符串的开始位置,第二个参数表示结束的位置。

var stringValue ="hello world";
alert(stringValue.slice(3));//"lo world"
alert(stringValue.substring(3));//"lo world"
alert(stringValue.substr(3));//"lo world"
alert(stringValue.slice(3,7));//"lo w",7表示子字符串最后一个字符后面的位置
alert(stringValue.substring(3,7));//"lo w",7表示子字符串最后一个字符后面的位置
alert(stringValue.substr(3,7));//"lo worl",7表示字符个数

  • 字符串位置方法
    indexOf()和lastIndexOf()可接受两个参数,第二个参数表示从哪个位置开始搜索
var stringValue = "Lorem ipsum dolor sit amet, consectetur elit";
var positions = new Array();
var pos = stringValue.indexOf("e");//在循环之外,首先找到"e"在字符串中的初始位置

while (pos>-1){//如果一个数组中没有要找的字符,返回值为-1
    positions.push(pos);//把e的初始位置push到数组中
    pos = stringValue.indexOf("e",pos +1);//进入循环后,每次都给indexOf()传递上一次位置加1,确保每次新搜索从上一次找到的子字符串后面开始
}
alert(positions); //"3,24,32,35,52"
  • trim方法
    创建一个副本,去掉前置和后缀所有空格

相关文章

网友评论

      本文标题:【JS学习笔记】第5章

      本文链接:https://www.haomeiwen.com/subject/kbugottx.html