• JS Pro 引用类型


    引用类型的值(对象)其实就是引用类型的一个实例。在ECMAScript里头,引用类型就是用来保存数据和方法的,别的语言称之为"类"(Class)。虽说ECMAScript是面向对象的语言,但在ECMAScript里,缺少面向对象的概念——类和接口。所以,ECMAScript里不能称为类,我们称为:对象定义。

    Object类型

    我们通过new操作符,后面跟一个构造函数来创建对象。构造函数简单来说就是一个用来创建新对象的方法。

    var person = new Object();

    创建对象的2种语法:

    1. 使用new操作符:

    var person = new Object();
    person.name = “Nicholas”;
    person.age = 29;

    2. 对象字面量(属性与值用":"隔开,每一对属性/值用","隔开)——推荐使用该方法,清晰、简洁:

    var person = {
      name : “Nicholas”,
      age : 29
    };

    最好给属性值加上"",如:"name"。

    还有一种特殊的方法:

    var person = {};    //same as new Object()
    person.name = "Nicholas";
    person.age = 29;

    在你创建函数的时候,也可以使用对象字面量来定义。

    你可以使用.或者[]来访问对象属性,如:

    alert(person.name);
    alert(person[name]);

    两者基本相同,当使用[]时,我们可以使用变量来访问该属性。

    Array类型

    在ECMAScript当中的数组和其他语言里的数组,最大的差别在于,任意一个数组里可以包含任意类型的数据。而且ECMAScript的数组的大小是动态的。

    创建数组的两个方法——1. 使用Array构造函数;2. 使用数字字面量表示法(当使用该方法时,不会调用Array构造函数)

    //1st method
    var colors = new Array();
    //And you can omit the new operator in this way 
    var colors = Array();
    
    //2nd method, use []
    var colors = ["red", "blud", "yellow"];

    使用[]访问数组内的元素,从0开始。

    注意:array.length不是只读的,所以可以通过修改length的值,从数组中移除数据,如:

    var colors = [“red”, “blue”, “green”]; //creates an array with three strings
    colors.length = 2;
    alert(colors[2]); //undefined

    可以使用length,往数组的末端添加数据。

    var colors = [“red”, “blue”, “green”]; //creates an array with three strings
    colors[colors.length] = “black”; //add a color (position 3)
    colors[colors.length] = “brown”; //add another color (position 4)

    数组-栈方法(Stack Method):

    栈是后进先出结构(LIFO--Last-In-First-Out),最新添加的项,最早被移除。

    push():接受任意数量的参数,逐个添加到数组末尾,返回修改后数组的长度

    pop():从数组末尾移除最后一项,减少数组的length值,返回移除的项

    数组-队列方法(Queue Method):

    队列数据结构的访问是先进先出(FIFO--First-In-First-Out)。队列在列表的末端添加项,从列表的前段移除项。

    shift():移除数组中的第一个项并返回该值

    unshift():往数组第一位添加项,返回修改后的数组长度

    数组-重排序方法(Reordering Method):

    reverse():纯粹的倒序

    sort():按升序排序——它会调用每一项的String()方法,然后进行比较。因为它是基于字符的比较,所以如果数组内元素为数字时,就会有问题了。

    var values = [0, 1, 5, 10, 15];
    values.sort();
    alert(values); //0,1,10,15,5

    虽然5比10小,但在字符串比较中,10在5的前面,所以最终结果反而被打乱了。

    但你可以通过给sort()传进一个比较函数(compare())来使它输出正确的值。

    function compare(value1, value2) {
        if (value1 < value2) {
        return -1;
    } else if (value1 > value2) {
      return 1;
    } else {
      return 0;
    }
    }
    var values = [0, 1, 5, 10, 15];
    values.sort(compare);
    alert(values); //0,1,5,10,15

    reverse()和sort()都是返回重新排序后的数组。

    数组-操作方法(Manipulation Method):

    concat()函数:基于当前数组的所有项,创建一个新数组。

    var colors = [“red”, “green”, “blue”];
    var colors2 = colors.concat(“yellow”, [“black”, “brown”]);
    alert(colors); //red,green,blue
    alert(colors2); //red,green,blue,yellow,black,brown

    slice()函数:基于当前数组中的一项或多项创建一个新数组。它接收1或2个参数。第一个是起始位置,第二个是结束位置。

    var colors = [“red”, “green”, “blue”, “yellow”, “purple”];
    var colors2 = colors.slice(1);
    var colors3 = colors.slice(1,4);
    alert(colors2); //green,blue,yellow,purple
    alert(colors3); //green,blue,yellow

    concat()和slice()都不会改变原数组的值。

    splice()函数:这个函数可以做3件事情,

      1. 删除元素(提供2个参数,arg[0]: 第一个要删除的元素位置;arg[1]: 总共要删除的元素的个数):splice(0, 2) 删除头两个元素

      2. 插入元素(提供3个或以上参数,arg[0]: 插入的起始位置;arg[1]: 要删除的元素个数(可为0);arg[2~N]:要添加的元素 ):splice(1, 0,  "red", "green")

      3. 替换元素(插入语法的变种:改变删除元素的个数,达到替换的目的):splice(1, 2, "red", "green")

    var colors = [“red”, “green”, “blue”];
    var removed = colors.splice(0,1); //remove the first item
    alert(colors); //green,blue
    alert(removed); //red - one item array
    removed = colors.splice(1, 0, “yellow”, “orange”); //insert two items at position 1
    alert(colors); //green,yellow,orange,blue
    alert(removed); //empty array
    removed = colors.splice(1, 1, “red”, “purple”); //insert two values, remove one
    alert(colors); //green,red,purple,orange,blue
    alert(removed); //yellow - one item array

    正则表达式类型(RegExp Type):

    语法:

    var expression = /pattern/flags;

    Function类型(Function Type):

    每个函数都是Function类型的实例,而且与其他引用类型一样具有属性和方法。由于函数是对象,所以函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。

    定义函数的语法:

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

    或者

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

    使用不带圆括号的函数名是访问函数指针,而非调用函数:

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

    没有重载!

    function addSomeNumber(num){
      return num + 100;
    }
    function addSomeNumber(num) {
      return num + 200;
    }
    var result = addSomeNumber(100); //300

    函数声明与函数表达式的区别:

    函数声明:

    function newFunction() {};

    函数表达式:

    var newFunction = function() {};

    解析器会率先读取函数声明,所以在执行代码前就已经生效(可以访问)。而函数表达式,则必须等到解析器运行到所在代码行才开始解释执行。所以,以下的第一段代码可以运行成功,第二段代码会报错。

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

    函数就是值:

    在ECMAScript里头,函数名称就是一个变量。所以函数可以当作值来使用。也就是说,可以像传递参数一样把一个函数传给另一个函数,而且可以将一个函数作为另一个函数的结果返回。

    注意的是,如果要把函数作为参数传给令一个函数,则不能包括括号,这样才是传递这个函数,如果包含了括号,就是传递函数返回值了。

    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”

    函数内部属性:

    每个函数内部都包含2个特殊对象:arguments和this。

    arguments对象:一个类数组对象,包含传入函数的所有参数。argument对象还包含一个callee属性,该属性是一个指针,指向拥有这个arguments对象的函数。
    我们用递归函数来解释一下这个属性。

    function factorial(num){
      if (num < = 1) {
      return 1;
      } else {
      return num * factorial(num-1)
      }
    }

    上面是一个很经典的递归函数,在函数有名字而且不改变的情况下,肯定是不会有问题。

    下面,我们试一下用arguments.callee这个属性重写上面的函数。

    function factorial(num){
      if (num < = 1) {
      return 1;
      } else {
      return num * arguments.callee(num-1)
      }
    }
    var trueFactorial = factorial;
    factorial
    = function(){   return 0; };
    alert(trueFactorial(
    5)); //120 alert(factorial(5)); //0

    通过使用arguments.callee重写的函数,在调用时就不再是针对factorial这个函数了。如上所示,在使用arguments.callee定义完factorial函数后,我们又定义了一个新的变量(trueFactorial),并赋予factorial的值(就是指向factorial函数的另一个变量);然后我们重新定义了factorial函数,使它返回0。

    由于现在原本的factorial函数体已经和函数名的关系已经解除,它只和调用它的那个函数名相关,所以trueFactorial能够返回正确的值。而factorial现在就只有唯一的返回值:0。

    this对象:this是函数执行时所处的作用域。

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


    函数属性与方法:

    ECMAScript里头的函数其实就是对象,因此函数也有属性和方法。每个函数会有2个属性:length和prototype。

    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中的引用类型而言,prototype就是保存他们所在实例方法的实际位置。(稍后详细解释!)

    每个函数又都包含2个非继承方法:apply()call()。这两个方法的作用都是在特定的作用域中调用函数,实际上等于设置函数体内的this对象的值。

    apply()和call()的第一个参数都是作用域,唯一的不同就是:apply()可以使用arguments对象或者数组形式传递参数,而call()则必须明确列出每一个参数。

    这两个方法最强大的地方在于他们能够扩充函数赖以运行的作用域。我们来重写一下this对象里面的那个例子:

    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

    我们只定义了一个全局函数sayColor(),默认情况下,它的作用域是window,所以,call(this)和call(window)返回的都是red。在最后一行,我们使用call()函数设定运行环境为对象o,所以它返回的值为blue。

    使用call()和apply()方法的最大好处是,不需要与方法有任何的耦合关系。在this函数的例子里,我们首先把sayColor()函数放在对象o中,然后再通过o来调用它。重写后,我们可以直接通过call来设定执行环境。

    函数的继承方法toLocaleString()和toString(),他们总是返回函数的代码。另外,valueOf()也是返回函数的代码。

    基本包装类型:

    3个特殊的引用类型:Boolean,Number和String。这3个都是基本类型,但ECMAScript给他们创建了这些基本包装类型,使我们可以像操作对象一样操作他们(但一般不推荐这么使用)。

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

    s1是一个基本类型值,为什么会有substring方法呢?其实,这背后还隐藏着3步:

    1. 创建String类型对象 s1
    2. 使用s1的substring方法
    3. 把s1设置为null

    var s1 = new String(“some text”);
    var s2 = s1.substring(2);
    s1 = null;

    Number类型

    toFixed():按照指定的小数位返回字符串(会四舍五入);常用于处理货币值。

    var num = 10;
    alert(num.toFixed(2)); //”10.00”
    
    var num = 10.005;
    alert(num.toFixed(2)); //”10.01”

    toExponential():返回指数表示法的数值字符串

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

    toPrecision():根据值来判断使用toFixed()或者toExponential()

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

    由于一位数无法准确表达99,所以将它舍为100,然后使用指数形式显示;2位数时,当然就是99;3位数时,则显示为99.0。

    String类型:

    继承下来的valueOf() , toLocaleString() , and toString()方法,都是返回string的值。

    length属性:返回字符串长度。注意:在ECMAScript里,即使字符串包含双字节字符,每个字符也仍然算一个字符。

    字符方法:

     charAt(): 返回指定位置的字符。

    var stringValue = “hello world”;
    alert(stringValue.charAt(1)); //”e”

     charCodeAt(): 返回指定位置字符的字符编码。

    var stringValue = “hello world”;
    alert(stringValue.charCodeAt(1)); //outputs “101”

    字符串操作方法:

    concat():连接字符串,并返回新的字符串。该方法接受任意个参数,所以你可以使用它一次过连接多个字符串。不过,一般我们可以直接使用"+"来连接字符串。

    var stringValue = “hello “;
    var result = stringValue.concat(“world”);
    alert(result); //”hello world”
    alert(stringValue); //”hello”

    slice(), substr(), substring():接受一个或两个参数,他们的第一个参数都是指起始位置。

    对于slice()和substring()而言,第二个参数是指结束的位置(这个位置不包含在返回的字符串里)

    而substring()的第二个参数,则是表示总共要返回的字符个数。

    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。

    查找字符位置方法:

    indexOf()和lastIndexOf(),他们都是在一个字符串里搜索指定的子字符串,返回子字符串的位置(当找不到时,返回-1)

    indexOf()从前往后找,lastIndexOf()从后往前找。

    它们都接受第二个参数,表示从字符串中的哪个位置开始搜索。indexOf()就是忽略前面的字符,找;lastIndexOf()就是忽略后面字符,往前找。
    通过第二个参数,我们可以找出一个字符串里包含子字符串的位置。

    var stringValue = “Lorem ipsum dolor sit amet, consectetur adipisicing elit”;
    var positions = new Array();
    var pos = stringValue.indexOf(“e”);
    while(pos > -1){
      positions.push(pos);
      pos = stringValue.indexOf(“e”, pos + 1);
    }
    alert(positions); //”3,24,32,35,52”

    字符串改变大小写:
    toLowerCase() , toLocaleLowerCase() , toUpperCase() , and toLocaleUpperCase() .

    字符串模式匹配方法:
    match()方法:该方法的返回值与正则表达式对象的exec()方法一致;它接受一个参数,可以是正则表达式或者RegExp对象。

    var text = “cat, bat, sat, fat”;
    var pattern = /.at/;
    //same as pattern.exec(text)
    var matches = text.match(pattern);
    alert(matches.index); //0
    alert(matches[0]); //”cat”
    alert(pattern.lastIndex); //0

    localCompare()方法:比较两个字符串,并返回-1,0,1。(根据两个字符串的字母先后顺序)

    fromCharCode()方法:接受字符编码, 将其转换为字符。其实就是charCodeAt()的反向方法。

    内置对象:

    ECMAScript里头有2个内置对象:Global和Math,在使用它们前,不需要显式地实例化。

    Global对象:其实,所有在全局作用域中定义的属性和函数,都是Global对象的属性。

    URI-Encoding方法:就是转换URI(Uniform Resource Identifiers)的方法。由于一个合法的URI是不能包含一些特殊字符的,例如空格,所以我们要先对其进行转换再传给浏览器。
    encodeURI():作用于整个URI;encodeURIComponent()则对URI的某一段进行编码。他们的区别在于,encodeURI()不会对本身收URI的特殊字符进行编码,例如冒号、正斜杠、问好和井字符。而encodeURIComponent()则会对所有非标准字符进行编码。

    var uri = “http://www.wrox.com/illegal value.htm#start”;
    //”http://www.wrox.com/illegal%20value.htm#start”
    alert(encodeURI(uri));
    //”http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start”
    alert(encodeURIComponent(uri));

    一般而言,encodeURIComponent()使用会更多,因为我们经常处理的是查询字符串参数,而不是整个URI。
    和这两个方法对应的是decodeURI()和decodeURIComponent()。

    eval()方法:只支持一个参数。当调用eval()方法时,解释器会把参数内的语句当做实际的ECMAScript语句来解析,然后执行。eval()执行的代码可以引用环境中定义的变量。

    eval()方法很强大,但也十分危险,特别实在用它执行用户输入数据的情况下,因为这可能导致代码注入!

    window对象:ECMAScript虽然没有指出如何直接访问Global对象,但在浏览器中,会将全局对象作为window对象加以实现。所以在全局变量中定义的变量和函数,都成为window对象的属性。

    Math对象:可以处理很多计算问题,并且比手工写JavaScript代码效率高。

    min()和max()方法: 可以传递多个参数,返回参数中的最大或最小值。

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

    取整(Rounding)方法:
    Math.ceil() - 往上取舍 (Math.ceil(25.4); //26)
    Math.floor() - 往下取舍 (Math.floor(25.7);  //25)
    Math.round() - 标准取舍(大于0.5往上,小于往下) (Math.round(25.5); //26)

    Math.Random():随机取一个数,0<Math.Random()<1。我们可以通过组合Math.Random()和Math.floor()来生成一个一系列整数随机数,公式如下:

    number = Math.floor(Math.random() * total_number_of_choices + first_possible_value)

    如你要得到一个1到10的随机数:

    var num = Math.floor(Math.random() * 10 + 1);

    如果你想要得到从2到10的随机数,因为你现在一个值为2,而2到10之间只有9个可供选择的整数,所以这个时候的表达式为:

    var num = Math.floor(Math.random() * 9 + 2);

    我们也可以使用一个function来帮我们计算出可选项数和第一个值:

    function selectFrom(lowerValue, upperValue) {
      var choices = upperValue - lowerValue + 1;
      return Math.floor(Math.random() * choices + lowerValue);
    }
    var num = selectFrom(2,10);
    alert(num); //number between 2 and 10, inclusive

    我们还可以把这个函数运用到数组里,使其随机选取一个item。

    引用类型总结:

    在Javascript里,对象被称作引用类型值,而且可以使用一些built-in引用类型来创建特殊的对象。

    • 引用类型与传统面向对象的类相似,但实现方法不同
    • Object是一个基本类型,其他所有引用类型都是从Object继承基本的行为
    • Array类型
    • Date类型
    • RegExp类型
    • 3个基本包装类型:Boolean,Number,String;由于有这3个基本包装类型,所以这些基本类型值可以被当作对象来访问。
    • 2个内置的对象:Global和Math,不需要声明,直接可以用。(Global一般表现为window对象)
  • 相关阅读:
    重学Docker
    rabbitmq基本知识了解
    rabbitmq之mq协议了解
    微信公众平台开发教程(三) 基础框架搭建
    微信公众平台开发教程(二) 基本原理及消息接口
    微信公众平台开发教程(一) 微信公众账号注册流程
    微信公众平台开发教程(十) 订阅号与服务号的区别
    vue cli3.0快速搭建项目详解(强烈推荐)
    vue 3.0 初体验 (项目搭建)
    手把手教你vue3.0项目搭建
  • 原文地址:https://www.cnblogs.com/rexmzk/p/2590269.html
Copyright © 2020-2023  润新知