zoukankan      html  css  js  c++  java
  • 《JavaScript高级程序设计》学习笔记(第五章)- 下

    Function类型

    ECMAScript中的函数实际上也是对象。每个函数都是Function类型的实例,并且与其它引用类型一样也具有属性和方法。所以,函数名称实际上也是一个指向函数对象的指针。

    这也就不难理解函数的另一种定义方法,实际就是在声明一个变量:

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

    实际上,函数也能使用构造方法来定义,不过这种方法是不推荐使用的:

        // 最后一个参数会被当成函数体
        var sum = new Function("num1", "num2", "return num1 + num2");
    

    没有重载(深入理解)

    将函数名想象为指针,也就可以理解为什么ECMAScript当中没有函数重载的概念。

        function addSomeNumber(num) { return num + 100; }
        function addSomeNumber(num1, num2) { return num1 + 200; }
        var result = addSomeNumber(100); // 300
    
        // --> 等价于 <--
    
        var addSomeNumber = function(num) { return num + 100; }
        addSomeNumber = function(num1, num2) { return num1 + 200; }
        var result = addSomeNumber(100); // 300
    

    可以看到,当声明两个同名函数时,实际上是第一个函数的变量被后面的所覆盖了,也就无法构成重载。

    函数声明与函数表达式

    在解析器向执行环境加载数据时,对待函数声明和函数表达式是有区别的。解析器会率先读取函数声明,并使其可以在执行任何代码之前可用,而对于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被执行。

        // 运行正确
        alert(sum(10,10));
        function sum(num1, num2){
            return num1 + num2;
        }
    
        // 运行出错
        alert(sum(10,10));
        var sum = function(num1, num2){
            return num1 + num2;
        };
    

    由于第一段代码使用了函数声明,所以解析器会在运行代码之前将其添加到执行环境中,所以可以正确运行。而第二段代码因为是函数表达式,所以在执行第一句的时候,实际上sum函数还未被定义,导致运行出错。

    作为值的函数

    因为ECMAScript当中的函数名本身就是变量,所以函数也可以被当成参数来使用,也可以作为返回值从一个函数中返回。

    函数内部属性

    在函数的内部,有两个特殊的属性:argumentsthis,这两个属性本身也都是引用类型。

    arguments除了保存函数参数的作用,还有一个callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。

        function factorial(num){
            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)
            }
        }
    

    this引用的是执行该函数的环境对象。

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

    当在全局作用域中调用函数时,this引用的是全局对象window。而使用对象调用时,则this指向的是该对象本身。

    关于this以后还会进行详细的讨论。

    ECMAScript 5中还定义了另一个函数属性的对象:caller,这个属性保存了调用当前函数的函数的引用,如果是在全局使用域内,则它的值为null

    函数属性和方法

    因为函数也是对象,所以函数也有属性和方法。每个函数都有两个属性:lengthprototype

    length表示函数希望接收的命名参数的个数。

        function sayName(name){
            alert(name);
        }
    
        function sum(num1, num2){
            return num1 + num2;
        }
    
        function sayHi(){
            alert("hi");
        }
    
        alert(sayName.length); //1
        alert(sum.length); //2
        alert(sayHi.length); //0
    

    prototype是ECMAScript中面向对象一个十分重要的属性,关于这个属性之后会更加详细地讨论。

    除了上面两个属性,每个函数还有两个非继承而来的方法:apply()call(),使用这两个方法可以设置函数内this对象的值。

    apply()方法接收两个参数,一个是在其中运行函数的使用域,别一个是参数数组,可以是Array的实例,也可以是arguments对象。如:

        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()方法与apply()方法类似,区别只在于第二个参数不同,对于call()方法,所以参数都是直接指定,而不是传递数组。

    apply()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
    

    ECMAScript 5还定义了一个bind()方法,这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。

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

    而对于toString()toLocaleString()valueOf()方法,都会返回函数的代码。

    基本包装类型

    我们之前说过,只有引用类型的数据才能添加属性,但是我们却经常对字符串调用各种方法。这是怎么回事呢?实际上,每当我们读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而我们能够调用一些方法来操作这些数据。

    基本包装类型只存在于一行代码的执行瞬间,然后立即被销毁。这也就解释了为什么我们不能为基本类型添加属性和方法,因为对基本包装类型添加的属性,在下一行代码执行的时候就被销毁了。

    我们应该避免显式地创建基本包装类型对象。

    Boolean类型

    Boolean类型是与布尔值对应的引用类型。Boolean类型的实例重写了valueOf()方法,返回基本类型值的truefalse。重写了toString()方法,返回字符串truefalse

    Number类型

    Number是与数字值对应的引用类型。NumbervalueOf()方法也会返回基本类型的数值,而toString()toLocaleString()方法会返回数值对应的字符串。

    Number类型还提供了一些用于数值格式化为字符串的方法。
    toFixed()方法会按照指定的小数返回数值的字符串表示:

        var num = 10;
        alert(num.toFixed(2)); //"10.00"
    

    toExponential()方法会返回以指数表示法表示的数值的字符串形式。

        var num = 10;
        alert(num.toExponential(1)); //"1.0e+1"
    

    对于一个数值来说,toPrecision()方法可能会返回固定大小(fixed)格式,也可能返回指数格式(exponential),具体看哪种格式最合适。

        var num = 99;
        alert(num.toPrecision(1)); //"1e+2"
        alert(num.toPrecision(2)); //"99"
        alert(num.toPrecision(3)); //"99.0"
    

    String类型

    String类型是字符串的对象包装类型。对于String类型的对象,三个继承的方法都直接返回对象所表示的基本字符串值。String类型每个实例都有一个length属性,表示字符串中的字符个数。要注意的是,即使字符串中包含双字节字符,每个字符也仍然算一个字符。

    String类型提供了很多方法,以提供字符串的操作和解析。

    字符方法

    charAt()charCodeAt()用于访问字符串中的特定字符。这两个方法都接收一个参数,即基于0的字符位置。charAt()以字符形式返回给定位置的字符,而charCodeAt()会以字符编码的形式返回。

        var stringValue = "hello world";
    
        alert(stringValue.charAt(1)); //"e"
        alert(stringValue.charCodeAt(1)); // 输出"101"
    

    在ECMAScript 5当中,还可以使用方括号加数字索引来访问字符串,与数组的取值方法类似。

    字符串操作方法

    concat()方法用于将一或多个字符串拼接起来,返回拼接得到的新字符串。

        var stringValue = "hello ";
        var result = stringValue.concat("world", "!");
    
        alert(result); //"hello world!"
        alert(stringValue); //"hello"
    

    实际上,在大多数情况下,字符串拼接使用更多的还是加号操作符(+)。

    ECMAScript还提供了三个用于获取子字符串的方法:slice()substr()substring()。这三个方法可以接受一个或两个参数,第一个参数为指定开始位置,对于slice()substring(),第二个参数是指定子字符串的结束位置,而substr()的第二个参数则是指定字符的个数。

        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"
        alert(stringValue.substring(3,7)); //"lo w"
        alert(stringValue.substr(3, 7)); //"lo worl"
    

    在传递参数为负值的情况下,slice() 方法会将传入的负值与字符串的长度相加, substr() 方法将负的第一个参数加上字符串的长度,而将负的第二个参数转换为 0。最后, substring() 方法会把所有负值参数都转换为 0。

        var stringValue = "hello world";
        alert(stringValue.slice(-3)); //"rld"
        alert(stringValue.substring(-3)); //"hello world"
        alert(stringValue.substr(-3)); //"rld"
        alert(stringValue.slice(3, -4)); //"lo w"
        alert(stringValue.substring(3, -4)); //"hel"
        alert(stringValue.substr(3, -4)); //"" (空字符串)
    

    字符串位置方法

    indexOf()lastIndexOf()可以用于从字符串中查找子字符串,并返回子字符串的位置(如果没有找到,则返回-1)。两个方法区别只在于搜索的起始位置。并且两个方法都可以接受第二个参数,用于指定从哪个位置可以搜索。

    trim()方法

    ECMAScript 5为所有字符串字义了trim()方法。这个方法会创建一个字符串副本,删除前置和后缀的所有空格,然后返回结果。

        var stringValue = " hello world ";
        var trimmedStringValue = stringValue.trim();
        alert(stringValue); //" hello world "
        alert(trimmedStringValue); //"hello world"
    

    字符串大小写转换方法

    toLowerCase()toLocalceLowerCase()toUpperCase()toLocaleUpperCase()用于转换字符串的大小写。

    字符串模式匹配方法

    String类型定义了几个用于在字符串中匹配模式的方法。

    match()RegExpexec()方法本质上是一样的。match()方法接收一个参数,要么是正则字面量,或一个RegExp对象。

        var text = "cat, bat, sat, fat";
        var pattern = /.at/;
    
        //与 pattern.exec(text)相同
        var matches = text.match(pattern);
        alert(matches.index); //0
        alert(matches[0]); //"cat"
        alert(pattern.lastIndex); //0
    

    search()方法用于在字符串中查找符合特定模式的子字符串,并返回子字符串的位置,它接收的参数与match()一样。

        var text = "cat, bat, sat, fat";
        var pos = text.search(/at/);
        alert(pos); //1
    

    String类型还提供了一个用于替换子字符串。这个方法可以接收两个参数:第一个参数可以是一个RegExp对象或者一个字符串(不会被转换为正则表达式),第二个参数可以是一个字符串或者一个函数。如果第一个参数是字符串,则只会替换第一个匹配的子字符串。

        var text = "cat, bat, sat, fat";
        var result = text.replace("at", "ond");
        alert(result); //"cond, bat, sat, fat"
    
        result = text.replace(/at/g, "ond");
        alert(result); //"cond, bond, sond, fond"
    

    第二个参数如果指定一个函数,传递给函数的参数依次是模式的匹配项、各个捕获组的匹配项、匹配项的位置和原始字符串。

    最后一个与模式匹配有关的方法是split(),这个方法可以基本指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中。分隔符可以是一个字符串(不会被转化为正则表达式),也可以是一个RegExp对象。这个方法也可以接收第二个参数,用于指定数组的大小。

        var colorText = "red,blue,green,yellow";
        var colors1 = colorText.split(","); //["red", "blue", "green", "yellow"]
        var colors2 = colorText.split(",", 2); //["red", "blue"]
        var colors3 = colorText.split(/[^\,]+/); //["", ",", ",", ",", ""]
    

    localeCompare()方法

    这个方法比较两个字符串,根据字符编码进行比较返回正数、负数或者0。

    fromCharCode()方法

    String构造函数本身还有一个静态方法:fromCharCode(),这个方法接收一个或多个字符编码,然后将它们转换成一个字符串。

        alert(String.fromCharCode(104, 101, 108, 108, 111)); //"hello"
    

    单体内置对象

    除了上面介绍的内置对象,ECMA-262还定义了两个单体内置对象:GlobalMath

    Global对象

    所以在全局作用域中定义的属性和函数,都是Global对象的属性。在web浏览器当中,这个对象被当作window对象的一部分来实现。Global对象还包含其他一些方法:

    URI编码方法

    encodeURI()encodeURIComponent()方法可以对URI进行编码,它们会以UTF-8编码替换掉无效的字符。其中,encodeURI()用于整个URI,而encodeURIComponent()只用于URI中某一段进行编码。与其对应的两个方法是decodeURI()decodeURIComponent()

    eval()方法

    eval()方法可以将传入的字符串当作ECMAScript语句来执行。通过eval()执行的代码被认为是包含该次调用的执行环境的一部分,因为被执行的代码具有与该执行环境相同的作用域链。

        eval("function sayHi() { alert('hi'); }");
        sayHi();
        eval("var msg = 'hello world'; ");
        alert(msg); //"hello world"
    

    Math对象

    ECMAScript对保存数学公式和信息提供了一个公共位置,即Math对象。

    Math对象的属性

    Math对象包含的属性大都是数学中可能用到的特殊值:

    属性 说明
    Math.E 自然对数的底数,即常量 e 的值
    Math.LN10 10的自然对数
    Math.LN2 2的自然对数
    Math.LOG2E 以2为底 e 的对数
    Math.LOG10E 以10为底 e 的对数
    Math.PI π的值
    Math.SQRT1_2 1/2的平方根(即2的平方根的倒数)
    Math.SQRT2 2的平方根

    min()和max()方法

    这两个方法可以接收任意多个数值参数,并返回所有值的最大值或最小值。

        var max = Math.max(3, 54, 32, 16);
        alert(max); //54
    
        var min = Math.min(3, 54, 32, 16);
        alert(min); //3
    

    舍入方法

    Math.ceil()向上取整,Math.floor()向下取整,Math.round()执行四舍五入方法。

        alert(Math.ceil(25.9)); //26
        alert(Math.ceil(25.5)); //26
        alert(Math.ceil(25.1)); //26
    
        alert(Math.round(25.9)); //26
        alert(Math.round(25.5)); //26
        alert(Math.round(25.1)); //25
    
        alert(Math.floor(25.9)); //25
        alert(Math.floor(25.5)); //25
        alert(Math.floor(25.1)); //25
    

    random()方法

    Math.random()方法返回大于等于0小于1的一个随机数。可以利用这个方法从某个整数范围内随机选择一个值。

        值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)
        // 通用函数
        function selectFrom(lowerValue, upperValue) {
            var choices = upperValue - lowerValue + 1;
            return Math.floor(Math.random() * choices + lowerValue);
        }
    

    其他方法

    Math对象中还包含了其他一些与计算相关的方法,在此就不详细记录,遇到的时候再查阅资料就可以了。

  • 相关阅读:
    又一种Mysql报错注入
    PHP wget 增强脱裤脚本(PDO MYSQL)
    一种少见的跨目录写webshell方法
    过狗一句话
    在myql sqlserver里边怎么快速找到带有关键字的表
    php读取3389脚本
    学习OpenCV,看这些!
    Git 学习看这篇就够了!
    开发工具使用技巧和插件大总结
    (资源整理)带你入门Spark
  • 原文地址:https://www.cnblogs.com/buginux/p/4113285.html
Copyright © 2011-2022 走看看