JS中的引用类型

Posted 劳埃德·福杰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS中的引用类型相关的知识,希望对你有一定的参考价值。

目录

引用类型是把数据和功能组织到一起的结构。对象被认为是某个特定引用类型的实例。

1.基本引用类型 

①Date

let now = new Date(); //不传参,创建的对象将保存当前日期和时间

要基于其他日期和时间创建日期对象,必须传入其毫秒表示(UNIX 纪元 1970 年 1 月 1 日午夜之后的毫秒数) 

Date.parse():接收一个表示日期的字符串参数,尝试将这个字符串转换为表示该日期的毫秒
数。传入的字符串不是日期,函数返回NaN
Date.UTC() :也返回日期的毫秒表示 
日期格式化

②RegExp类型

③function类型 

函数实际上是对象。每个函数都是Function类型的实例,函数名实际上是一个指向函数对象的指针。 

// 创建函数
// 函数声明
function sum (num1, num2) 
    return num1 + num2;

// 函数表达式
let sum = function(num1, num2) 
    return num1 + num2;
;
// 可以,但不推荐
let sum = new Function("num1", "num2", "return num1 + num2"); 

函数声明:解析器会率先读取函数声明,并使其在执行任何代码之前可用
函数表达式:必须等到解析器执行到它所在的代码行,才会被解释执行 

没有重载 

在其他语言比如 Java 中,一个函数可以有两个定义,只要签名(接收参数的类型和数量)不同就行。而ECMAScript 函数没有签名,因为参数是由包含零个或多个值的数组表示的。 

function addSomeNumber(num) 
    return num + 100;

function addSomeNumber(num) 
    return num + 200;

let result = addSomeNumber(100); // 300,第二个定义覆盖了第一个定义

函数内部特殊对象: arguments 和 this
arguments包含调用函数时传入的所有参数,该对象有一个 callee 属性,是一个指向 arguments 对象所在函数的指针。

function factorial(num) 
    if (num <= 1) 
        return 1;
     else 
        return num * arguments.callee(num - 1);  // arguments.callee 指向正在执行的函数
    

//传统方法:这个函数要正确执行就必须保证函数名是factorial,从而导致了紧密耦合。
// 使用arguments.callee 就可以让函数逻辑与函数名解耦 。
function factorial(num) 
    if (num <= 1) 
        return 1;
     else 
        return num * factorial(num - 1);
    

this 引用的是把函数当成方法调用上下文对象(在网页的全局上下文中调用函数时, this 指向 windows )

window.color = 'red';
let o = 
    color: 'blue'
;
function sayColor() 
    console.log(this.color);

sayColor(); // 'red'
o.sayColor = sayColor;
o.sayColor(); // 'blue'

函数是对象,因此有属性和方法。每个函数都有两个属性: length和 prototype
length 属性保存函数定义的命名参数的个数, prototype 保存一些共用方法,这意味着 toString() 、 valueOf() 等方法实际上都保存在prototype 上,由所有实例共享。

function sayName(name) 
    console.log(name);

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

console.log(sayName.length); // 1
console.log(sum.length); // 2

apply() 和 call() 

apply()接收两个参数:函数内this的值和一个参数数组。第二个参数可以是Array的或arguments对象。
call() 与apply() 的作用一样,只是传参的形式不同。第一个参数跟 apply() 一样,也是 this值,而剩下要传的参数要一个一个列出来。

// 函数传参
function sum(num1, num2) 
    return num1 + num2;

function callSum1(num1, num2) 
    return sum.apply(this, arguments); // 传入arguments对象,这里等于window,因为是在全局作用域中调用的

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

function callSum(num1, num2) 
    return sum.call(this, num1, num2);

console.log(callSum1(10, 10)); // 20
console.log(callSum2(10, 10)); // 20
console.log(callSum(10, 10)); // 20
// 控制函数调用上下文
window.color = 'red';
let o = 
    color: 'blue'
;
function sayColor() 
    console.log(this.color);

sayColor.call(this); // red,这里等于window,因为是在全局作用域中调用的
sayColor.call(window); // red
sayColor.call(o); // blue

bind() :创建一个新的函数实例,其 this = 传进来的参数对象

window.color = 'red';
var o = 
    color: 'blue'
;
function sayColor() 
    console.log(this.color);

let objectSayColor = sayColor.bind(o);
objectSayColor(); // blue

toLocaleString() 、toString() :返回函数的代码 
valueOf() :返回函数本身

④原始包装类型:Boolean、Number、String

let s1 = "some text"; 
let s2 = s1.substring(2);
// 原始值本身不是对象,逻辑上不应该有方法
// 所以它后台是这样处理的
let s1 = new String("some text");
let s2 = s1.substring(2);
s1 = null;

引用类型与原始值包装类型的主要区别在于对象的生命周期。
通过 new 创建的引用类型的实例,在执行流离开当前作用域之前一直保存在内存中。
自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁。
这意味着不能在运行时给基本类型值添加属性和方法。

Object 构造函数作为一个工厂方法,能够根据传入值的类型返回相应基本包装类型的实例。

let obj = new Object("some text");
console.log(obj instanceof String); // true

使用 new 调用基本包装类型的构造函数,与调用同名的转型函数并不一样

let value = "25";
let number = Number(value); // 转型函数
console.log(typeof number); // "number"
let obj = new Number(value); // 构造函数
console.log(typeof obj); // "object"

举例

// valueOf()返回基本类型true或false,toString()返回字符串"true"和"false"
let booleanObject = new Boolean(true);

// valueOf()返回基本类型数值,toString()返回数值的字符串形式
let num = 10;
console.log(num.toString()); // "10"
console.log(num.toString(2)); // "1010"
console.log(num.toString(8)); // "12"
console.log(num.toString(10)); // "10"
console.log(num.toString(16)); // "a"
console.log(num.toFixed(2)); // "10.00",指定小数点位数
console.log(num.toExponential(1)); // "1.0e+1",科学计数法
// toPrecision()方法会根据情况返回最合理的输出结果,可能是固定长度,也可能是科学记数法形式。
console.log(num.toPrecision(1)); // "1e+2",因为99不能只用1位数字来精确表示,所以这个方法就将它舍入为100
console.log(num.toPrecision(2)); // "99"
console.log(num.toPrecision(3)); // "99.0"
// valueOf()、toLocaleString()和toString()都返回对象的原始字符串值
let stringObject = new String("hello world");

charAt():返回字符串指定位置的字符
charCodeAt(): 返回字符串指定位置的字符的编码
有的浏览器也支持:方括号+数字索引 访问字符串中的特定字符
concat():拼接字符串

let stringValue = "hello ";
let result = stringValue.concat("world");
console.log(result); // "hello world"

提取子字符串 slice() 、 substr() 和 substring() 

// 对 substr() 而言,第二个参数表示返回的子字符串数量
let stringValue = "hello world";
console.log(stringValue.slice(3)); // "lo world"
console.log(stringValue.substring(3)); // "lo world"
console.log(stringValue.substr(3)); // "lo world"
console.log(stringValue.slice(3, 7)); // "lo w"
console.log(stringValue.substring(3,7)); // "lo w"
console.log(stringValue.substr(3, 7)); // "lo worl"

// slice()将所有负值参数都当成字符串长度加上负参数值。
// substr()将第一个负参数值当成字符串长度加上该值,将第二个负参数值转换为 0
// substring() 方法会将所有负参数值都转换为 0
console.log(stringValue.slice(-3)); // "rld"
console.log(stringValue.slice(3, -4)); // "lo w"
console.log(stringValue.substr(3, -4)); // "" (empty string)
console.log(stringValue.substr(-3)); // "rld"
console.log(stringValue.substring(-3)); // "hello world"
console.log(stringValue.substring(3, -4)); // "hel"

indexOf() 和 lastIndexOf() :定位子字符串,没找到,则返回 -1,这两个方法都可以接收可选的第二个参数,表示开始搜索的位置
trim():删除字符串前、后所有空格符
toLowerCase() 、toUpperCase() :转换大小写
toLocaleLowerCase() 和 toLocaleUpperCase() :转换大小写(在基于特定地区实现)
字符串模式匹配方法: match() 
查找模式的字符串方法: search(),
返回模式第一个匹配的位置索引
替换子字符串:replace(),第一个参数可以是一个 RegExp 对象或一个字符串,第二个参数可以是一个字符串或一个函数。
分割字符串:split(),第二个参数指定数组大小限制
比较两个字符串: localeCompare() 

let text = "cat, bat, sat, fat";
let pattern = /.at/;
// 等价于 pattern.exec(text)
let matches = text.match(pattern);
console.log(matches.index); // 0
console.log(matches[0]); // "cat"
console.log(pattern.lastIndex); // 0

let pos = text.search(/at/);
console.log(pos); // 1
let result = text.replace("at", "ond");
console.log(result); // "cond, bat, sat, fat"
result = text.replace(/at/g, "ond");
console.log(result); // "cond, bond, sond, fond"

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

let stringValue = "yellow";
console.log(stringValue.localeCompare("brick")); // 1
console.log(stringValue.localeCompare("yellow")); // 0
console.log(stringValue.localeCompare("zoo")); // -1

⑤单体内置对象

内置对象:“任何由 ECMAScript实现提供、与宿主环境无关,并在 ECMAScript程序开始执行时就存在的对象”,比如 Object 、 Array 、String、Global、Math

Global:“兜底对象”,不属于任何其他对象的属性和方法,最终都是它的属性和方法, isNaN() 、 isFinite() 、 parseInt() 和 parseFloat() ,实际上都是 Global 对象的方法
encodeURI() 和 encodeURIComponent() 给url编码,前者只将空格被替换为 %20 ,后者对所有非字母字符都替换
decodeURI() 和 decodeURIComponent() 给url解码
eval() :这个方法就是一个完整的 ECMAScript 解释器

eval("console.log('hi')"); // 等价于console.log("hi");

 ECMA-262 没有规定直接访问 Global 对象的方式,但浏览器将 window 对象实现为 Global
对象的代理。 所有全局作用域中声明的变量和函数都变成了 window 的属性。

var color = "red";
function sayColor() 
    console.log(window.color);

window.sayColor(); // "red"

Math 对象 

常用属性:Math.PI、Math.E

Math.ceil():向上舍入为最接近的整数 
Math.floor() :向下舍入为最接近的整数
Math.round() :执行四舍五入
Math.fround() :返回数值最接近的单精度(32 位)浮点值表示

console.log(Math.ceil(25.9)); // 26
console.log(Math.floor(25.9)); // 25
console.log(Math.round(25.9)); // 26
console.log(Math.round(25.1)); // 25
console.log(Math.fround(0.4)); // 0.4000000059604645
console.log(Math.fround(0.5)); // 0.5
console.log(Math.fround(25.9)); // 25.899999618530273

Math.random() :返回一个 [0,1)范围内的随机数

Math.max()和Math.min() :

let max = Math.max(3, 54, 32, 16);
console.log(max); // 54
let min = Math.min(3, 54, 32, 16);
console.log(min); // 3

2.集合引用类型 

①Object 

创建 Object 的实例有两种方式。

//使用new操作符
let person = new Object();
person.name = "Nicholas";
person.age = 29;
// 对象字面量
let person = 
    name: "Nicholas",
    age: 29
;

访问对象属性:点语法或中括号,有的时候必须要用中括号(属性名中包含可能会导致语法错误的字符,或者包含关键字/保留字)

person["first name"] = "Nicholas";

②Array

跟其他语言不同的是,JS的数组中的每个槽位可存储任意类型的数据,并且可以动态调整长度(length属性可以改变)。

创建数组

// 使用 Array 构造函数
let colors = new Array();
let colors = new Array(3); // 创建一个包含 3 个元素的数组
let names = new Array("Greg"); // 创建一个只包含一个元素,即字符串"Greg"的数组
let colors = Array(3); // 可以省略 new 操作符

// 数组字面量
let colors = ["red", "blue", "green"]; // 创建一个包含 3 个元素的数组
let names = []; // 创建一个空数组
let values = [1,2,]; // 创建一个包含 2 个元素的数组

当一个值放在超出当前数组大小的位置上,数组会重新计算其长度 

let colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组
colors[99] = "black"; // 添加一种颜色(位置 99 )
alert(colors.length); // 100

判断一个对象是不是数组:value instanceof Array(如果网页里有多个框架可能有问题)、Array.isArray(value)(推荐)
数组转字符串: 
toLocaleString() 、 toString() 和 valueOf() 
上面的方法默认都用逗号作分隔符,join() 方法可自定义字符串分隔符

let colors = ["red", "green", "blue"];
alert(colors.join(",")); // red,green,blue
alert(colors.join("||")); // red||green||blue

栈方法
push() :接收任意数量的参数,并将它们添加到数组末尾,返回数组的最新长度。
pop() :删除数组的最后一项,同时减少数组的 length 值,返回被删除的项。

队列方法 
push()同上
shift() :删除数组的第一项并返回它,数组长度减 1
unshift() :在数组开头添加任意多个值,返回新的数组长度(unshift和shift组合可模拟栈,和pop组合可以模拟队列)

排序
reverse():反向排序
sort():默认升序,也可接收一个比较函数

// 如果第一个参数应该排在第二个参数前面,就返回负值
// 如果两个参数相等,就返回 0
// 如果第一个参数应该排在第二个参数后面,就返回正值
// 这样理解:compare函数返回正数,value1和value2才交换
function compare(value1, value2) 
    if (value1 < value2) 
        return -1;
     else if (value1 > value2) 
        return 1;
     else 
        return 0;
    

concat() : 连接数组。如果传入一个或多个数组,则 concat() 会把这些数组的每一项都添加到结果数组。如果参数不是数组,则直接把它们添加到结果数组末尾。

let colors = ["red", "green", "blue"];
let colors2 = colors.concat("yellow", ["black", "brown"]);
console.log(colors2); // ["red", "green", "blue", "yellow", "black", "brown"]

slice():分割数组

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

splice() 
删除。
需传 2 个参数:要删除的第一个元素的位置和要删除的元素数量。
插入。需传 3 个参数:开始位置、0(要删除的元素数量)和要插入的元素,可以在数组中指定的位置插入元素。第三个参数之后还可以传第四个、第五个参数,乃至任意多个要插入的元素 。
替换。 传入 3 个参数:开始位置、要删除元素的数量和要插入的任意多个元素。要插入的元素数量不一定跟删除的元素数量一致。

indexOf() 、 lastIndexOf():接收两个参数:要查找的元素和一个可选的起始搜索位置,返回目标元素的索引。没找到返回-1。

迭代方法
every() :对数组每一项都运行传入的函数,如果对每一项函数都返回 true ,则这个方法返回 true 
filter() :对数组每一项都运行传入的函数,函数返回 true 的项会组成数组之后返回。
forEach() :对数组每一项都运行传入的函数,没有返回值。
map() :对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组。
some() :对数组每一项都运行传入的函数,如果有一项函数返回 true ,则这个方法返回 true 。

归并方法 
reduce() 和 reduceRight() 。这两个方法都会迭代数组的所有项,并在此基础上构建一个最终返回值。 reduce() 方法从数组第一项遍历到最后一项。而 reduceRight() 从最后一项遍历至第一项。

以上是关于JS中的引用类型的主要内容,如果未能解决你的问题,请参考以下文章

Plotly.js:锁定 y 轴以避免负值

[JS]string.substr(start,length)

js中的基本类型和引用类型

JS中的引用类型

js中的基本类型和引用类型

js中的基本类型和引用类型