目录
(3)、 Object.create() 方法创建一个对象(原型)
(1)、Object.length 和 Object.prototype 属性
(3)、Object.defineProperty() 和 Object.defineProperties()
(4)、Object.getOwnPropertyDescriptor()
(5)、Object.getOwnPropertyNames()
(7)、Object.getOwnPropertySymbols()
(8)、Object.setPrototypeOf() 和 Object.getPrototypeOf()
(14)、Object.preventExtensions()
(1)、Object.prototype.constructor 属性
(2)、Object.prototype.hasOwnProperty()——判断对象中是否有某个属性(★★★★★)
(3)、Object.prototype.isPrototypeOf()
(4)、Object.prototype.propertyIsEnumerable()
(5)、Object.prototype.toLocaleString() 和 Object.prototype.toString()
(6)、Object.prototype.valueOf()
7、如何将两个字符串以“key: value”的格式放进一个对象里?
(1)、instanceof 操作符 检测数组(IE8及其以下)
(2)、Array.isArray() 方法 检测数组(IE9+)
(1)、push() 方法能够在数组末尾添加任意个项,并返回新的数组的长度。
(2)、pop() 方法能够在数组末尾移除最后一项,并返回该项,同时数组长度减1。
(1)、push() 方法能够在数组末尾添加任意个项,并返回新的数组的长度。
(2)、shift() 方法能够在数组前端移除第一项,并返回该项,同时数组长度减1。
12、位置方法——indexOf() 和 lastIndexOf()
13、迭代方法——filter()、forEach()、map()、every() 和 some()
(5)、深入探索 filter()、forEach()、map()、every() 和 some() 方法
14、归并方法——reduce() 和 reduceRight()
(3)、reduce() 和 reduceRight() 方法的深入探索
(4)、深入探索 call()、apply() 和 bind() 方法
(1)、“字符”方法——charAt() 和 charCodeAt()
(4)、字符串截取——slice() 、substr() 和 substring()
(5)、字符串位置方法——indexOf() 和 lastIndexOf()
(7)、字符串大小写转换——toLowerCase()、toLocaleLowerCase()、toUpperCase() 和 toLocaleUpperCase()
(8)、字符串的模式匹配方法(字符串的正则方法)——match、replace、search 和 split
(9)、比较两个字符串在字符表中的先后顺序——localCompare() 方法
(1)、最小值和最大值——Math.min() 和 Math.max()
前言
注意:本文涉及 JS 原型与原型链的地方较繁杂,故单开一篇记此。
JavaScript 的基本数据类型
ES6 新增的引用类型
引用类型包括哪些?
- Object(对象)、Array(数组)、Funtion(函数)、RegExp(正则)、Date(日期);
- 三个基本包装类型:Boolean、Number、String;
- 两个内置对象:Global、Math(数学计算)。
【拓展】基本包装类型
为了便于操作基本类型值,JavaScript 定义了 3 个特殊的引用类型:Boolean、Numbe 和 String。
基本类型值不是对象,因此从逻辑上讲,它们不应该有方法,但是它们确实有方法,究其原因,这些基本类型值在后台被自动包装了一番,举个例子:
var str = "hello";
var s2 = str.substring(2);
console.log(s2); // llo
在后台,其实经历了一下三步操作:
- 创建一个 Sting 类型的实例;
- 在实例上调用指定的方法;
- 销毁这个实例。
var str = "hello";
var s1 = new String(str);
var s2 = s1.substring(2);
s1.null;
console.log(s2); // llo
经过此番处理,基本类型值就变得和对象一样了——能够像对象一样调用方法了。
而且,上面这三步操作也分别适用于 Boolean 和 Number 类型值。
一、Object 类型
1、Object 实例的创建方式
(1)、Object 构造函数法创建一个对象
var person = new Object();
person.name = "marry";
person.age = "18";
(2)、对象字面量表示法创建一个对象(广泛使用)
var person = {
name: "marry",
age: 18
}
(3)、 Object.create() 方法创建一个对象(原型)
var person = Object.create({}, {
age: {
value: 18
},
getAge: {
value: function () {
return this.foo;
},
enumerable: false
}
});
2、访问对象属性的两种方法
(1)、点表示法
var person = {
name: "marry"
}
console.log(person.name); // marry
(2)、方括号表示法
var person = {
name: "marry"
}
console.log(person["name"]); // marry
如果属性名中包含会导致语法错误的字符,或者属性名使用的是关键字或保留字,使用方括号表示法就不会报语法错误了。例如:
var person = {
"first name": "marry"
}
console.log(person["first name"]); // marry
由于 “first name” 中包含一个空格,所以不能使用点表示法来访问它。可是,属性名中是允许包含非字母非数字的,这个时候就必须使用方括号表示法来访问它们了。
除非必须使用方括号表示方来访问属性,否则建议使用点表示法来访问对象。
3、Object 构造函数
Object构造函数,会根据给定的参数创建对象,具体有以下情况:
- 如果给定值是 null 或 undefined,将会创建并返回一个空对象;
- 如果传进去的是一个基本类型的值,则会构造其包装类型的对象;
- 如果传进去的是引用类型的值,仍然会返回这个值,经他们复制的变量保有和源对象相同的引用地址;
- 当以非构造函数形式被调用时,Object 的行为等同于 new Object()。
(1)、对象的属性描述符
对象的属性描述符包括两种:数据描述符 和 存取描述符。一个描述符只能是这两者其中之一,不能同时是两者。
这两种描述符都是对象,它们共享以下可选键值(默认值是指在使用 Object.defineProperty() 定义属性时的默认值):
- configurable:(默认为 false)当且仅当该键值为 true 时,该属性 的描述符才能够被改变,并且允许 该属性 可以从对应对象中被删除。
- enumerable:(默认为 false)当且仅当该键值为 true 时,该属性 才会出现在对象的枚举属性中。
- value:(默认为 undefined)该属性 的值。可以是任何有效的 JavaScript 值(数字,对象,函数等)。
- writable:(默认为 false)当且仅当该键值为 true 时,该属性 的值,也就是上面的 value,才能被赋值运算符改变。
- get:(默认为 undefined)该属性的 getter 函数,当访问该属性时,会调用此函数。该函数返回值将被用作属性的值。如果没有 getter 则为默认值 undefined。
- set:(默认为 undefined)该属性的 setter 函数,当该属性的值被修改时,会调用此函数。该函数接受一个参数(也就是被赋予的新值)。如果没有 setter 则为默认值 undefined。
拥有布尔值的键 configurable、enumerable 和 writable 的默认值都是 false。
属性值和函数的键 value、get 和 set 字段的默认值为 undefined。
两种描述符可拥有的键值对比:
configurable | enumerable | value | writable | get | set | |
---|---|---|---|---|---|---|
数据描述符 | 可以 | 可以 | 可以 | 可以 | 不可以 | 不可以 |
存取描述符 | 可以 | 可以 | 不可以 | 不可以 | 可以 | 可以 |
使用案例详见 Object.defineProperty() 的使用案例。
4、Object 构造函数之 原型上的属性和方法
(1)、Object.length 和 Object.prototype 属性
Object.length:值为 1。
Object.prototype:指向对象的原型。可以为所有 Object 类型的对象添加属性或方法。
(2)、Object.create()
该方法可以用来创建一个新对象,并返回该对象。
语法:
Object.create(proto,[propertiesObject])
- proto:新创建对象的原型对象。
- propertiesObject:可选的。一个要定义其 可枚举属性 或 修改的属性描述符 的对象, 为新创建的对象添加指定的属性值和对应的属性描述符。
【注意】:如果 propertiesObject参数是 null 或非原始包装对象,则抛出一个 TypeError 异常。
(3)、Object.defineProperty() 和 Object.defineProperties()
1⃣️、Object.defineProperty():在一个对象上定义新的属性或修改现有属性,并返回该对象。
语法:
Object.defineProperty(obj, prop, descriptor)
- obj:要定义属性的对象。
- prop:要定义或修改的属性的名称或 Symbol 。
- descriptor:要定义或修改的属性描述符。
【注意】:在ES6中,由于 Symbol类型的特殊性,用Symbol类型的值来做对象的key与常规的定义或修改不同,Object.defineProperty 是定义key为Symbol的属性的方法之一。
2⃣️、Object.defineProperties():同上。
语法:
Object.defineProperties(obj, props)
- obj:在其上定义或修改属性的对象。
- props:要定义其可枚举属性或修改的属性描述符的对象。(数据描述符和访问器描述符详见 Object.create() 的 propertiesObject 参数)
Object.defineProperties本质上定义了obj 对象上props的可枚举属性相对应的所有属性。
举个例子:
var obj = {};
Object.defineProperties(obj, {
'property1': {
value: true,
writable: true
},
'property2': {
value: 'Hello',
writable: false
}
// etc. etc.
});
(4)、Object.getOwnPropertyDescriptor()
该方法返回指定对象上一个 自有属性 对应的属性描述符。(自有属性:直接赋予该对象的属性,不需要从原型链上进行查找的属性)
语法:
Object.getOwnPropertyDescriptor(obj, prop)
- obj:需要查找的目标对象
- prop:目标对象内属性名称
(5)、Object.getOwnPropertyNames()
该方法返回一个数组,它包含了指定对象所有的 可枚举 或 不可枚举 的 属性名(但不包括 Symbol 值作为名称的属性名)。
语法:
Object.getOwnPropertyNames(obj)
【拓展】:
- 获取一个对象的非Symbol的所有属性:使用
Object.getOwnPropertyNames 方法。
- 只获取可枚举属性:查看
Object.keys
或用for...in
循环(还会获取到原型链上的可枚举属性,不过可以使用hasOwnProperty()
方法过滤掉)。 - 只获取不可枚举的属性:使用 Array.prototype.filter() 方法,从所有的属性名数组(使用
Object.getOwnPropertyNames()
方法获得)中去除可枚举的属性(使用Object.keys()方法获得),剩余的属性便是不可枚举的属性了。
(6)、Object.keys()
该方法返回一个包含所有给定对象 自身可枚举属性名称 的数组。数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。
语法:
Object.keys(obj)
【注意】:Object.keys()方法在 ES5 和 ES6 中使用的区别:
在ES5里,如果此方法的参数不是对象(而是一个原始值),那么它会抛出 TypeError。在ES6中,非对象的参数将被强制转换为一个对象。
Object.keys("foo");
// TypeError: "foo" is not an object (ES5 code)
Object.keys("foo");
// ["0", "1", "2"] (ES2015 code)
(7)、Object.getOwnPropertySymbols()
该方法返回一个数组,它包含了指定对象自身的所有 Symbol 属性。
语法:
Object.getOwnPropertySymbols(obj)
所有的对象在初始化的时候不会包含任何的 Symbol,除非你在对象上赋值了 Symbol 否则 Object.getOwnPropertySymbols() 只会返回一个空的数组。
(8)、Object.setPrototypeOf() 和 Object.getPrototypeOf()
1⃣️、Object.setPrototypeOf():
该方法方法设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或 null。
语法:
Object.setPrototypeOf(obj, prototype)
- obj:要设置其原型的对象。
- prototype:该对象的新原型(一个对象 或 null)。
【注意】:更改对象的 [[Prototype]]在浏览器和 JavaScript 引擎上都是一个很慢的操作,如果你关心性能,你应该避免设置一个对象的 [[Prototype]]。你可以使用 Object.create()来创建带有你想要的[[Prototype]]的新对象,来避免更改 [[Prototype]。
2⃣️、Object.getPrototypeOf():该方法返回指定对象的 原型对象。如果没有继承属性,则返回 null。
语法:
Object.getPrototypeOf(object)
【注意】:Object.getPrototypeOf(Object) 不是 Object.prototype
- Object.getPrototypeOf( Object )是把Object这一构造函数看作对象,返回的是函数对象的原型,也就是 Function.prototype。
var obj = new Object();
Object.getPrototypeOf( Object ); // ƒ () { [native code] }
Object.getPrototypeOf( Function ); // ƒ () { [native code] }
Object.getPrototypeOf( Object ) === Function.prototype; // true
- Object.prototype是构造出来的对象的原型。
var obj = new Object();
Object.prototype === Object.getPrototypeOf( obj ); // true
Object.prototype === Object.getPrototypeOf( {} ); // true
(9)、Object.isExtensible()
该方法用来判断一个对象是否是可扩展。
语法:
Object.isExtensible(obj)
默认情况下,对象是可扩展的:即可以为他们添加新的属性。以及它们的 __proto__ 属性可以被更改。Object.preventExtensions,Object.seal 或 Object.freeze 方法都可以标记一个对象为不可扩展(non-extensible)。
【注意】Object.isExtensible() 方法在 ES5 和 ES6 中使用的区别:
在 ES5 中,如果参数不是一个对象类型,将抛出一个 TypeError 异常。在 ES6 中, non-object 参数将被视为一个不可扩展的普通对象,因此会返回 false 。
Object.isExtensible(1);
// TypeError: 1 is not an object (ES5 code)
Object.isExtensible(1);
// false (ES6 code)
(10)、Object.freeze()
该方法可以冻结一个对象。如果指定的属性存在于对象上,则返回该被冻结的对象,否则返回 undefined。
一个被冻结的对象再也不能被修改(即没有getter或setter组件的访问器的属性)。
语法:
Object.freeze(obj)
(11)、Object.isFrozen()
该方法判断对象是否已经冻结。
语法:
Object.isFrozen(obj)
【注意】:Object.isFrozen() 方法在 ES5 和 ES6 中使用的区别:
在 ES5 中,如果参数不是一个对象类型,将抛出一个TypeError异常。在 ES6 中,非对象参数将被视为一个冻结的普通对象,因此会返回true。
Object.isFrozen(1);
// TypeError: 1 is not an object (ES5 code)
Object.isFrozen(1);
// true (ES2015 code)
(12)、Object.isSealed()
该方法判断对象是否已经密封。
语法:
Object.isSealed(obj)
【注意】:Object.isSealed() 方法在 ES5 和 ES6 中使用的区别:
在ES5中,如果这个方法的参数不是一个对象(一个原始类型),那么它会导致TypeError。在ES6中,非对象参数将被视为是一个密封的普通对象,只返回true。
Object.isSealed(1);
// TypeError: 1 is not an object (ES5 code)
Object.isSealed(1);
// true (ES2015 code)
(13)、Object.seal()
该方法用来封闭一个对象,防止其他代码删除对象的属性。
语法:
Object.seal(obj)
【注意】
- 对比 Object.freeze() 和 Object.seal():
使用 Object.freeze() 冻结的对象中的 现有属性值 是不可变的。用 Object.seal() 密封的对象可以改变其 现有属性值。
- Object.seal()方法在 ES5 和 ES6 中使用的区别:
在 ES5 中,如果这个方法的参数不是一个(原始)对象,那么它将导致 TypeError。在 ES6 中,非对象参数将被视为已被密封的普通对象,会直接返回它。
Object.seal(1);
// TypeError: 1 is not an object (ES5 code)
Object.seal(1);
// 1 (ES2015 code)
(14)、Object.preventExtensions()
该方法用来防止对象的任何扩展。
不可扩展对象的原型是不可变的。
语法:
Object.preventExtensions(obj)
【注意】:Object.preventExtensions() 方法在 ES5 和 ES6 中使用的区别:
在 ES5 中,如果参数不是一个对象类型(而是原始类型),将抛出一个TypeError异常。在 ES6 中,非对象参数将被视为一个不可扩展的普通对象,因此会被直接返回。
Object.preventExtensions(1);
// TypeError: 1 is not an object (ES5 code)
Object.preventExtensions(1);
// 1 (ES2015 code)
5、Object 构造函数之 实例上的属性和方法
(1)、Object.prototype.constructor 属性
此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串。其所指引的函数,用于创建一个对象的原型。对原始数据类型来说,如1,true和"test",该值只可读。
打印一个对象的构造函数:
function Tree(name) {
this.name = name;
}
var theTree = new Tree("Redwood");
console.log(theTree.constructor);
使用案例:改变对象的 constructor 和 改变函数的 constructor
【注意】:手动设置或更新构造函数可能会导致不同且有时令人困惑的后果。为了防止它,只需在每个特定情况下定义构造函数的角色。在大多数情况下,不使用构造函数,并且不需要重新分配构造函数。
(2)、Object.prototype.hasOwnProperty()——判断对象中是否有某个属性(★★★★★)
该方法返回一个布尔值 ,表示某个对象是否含有指定的属性,而且此属性非原型链继承的。
语法:
obj.hasOwnProperty(prop)
- prop:要检测的属性的 String 字符串形式表示的名称,或者 Symbol。
【注意】:
即使属性的值是 null 或 undefined,只要属性存在,hasOwnProperty 依旧会返回 true。
var o = new Object();
o.propOne = null;
o.hasOwnProperty('propOne'); // 返回 true
o.propTwo = undefined;
o.hasOwnProperty('propTwo'); // 返回 true
使用案例:
(3)、Object.prototype.isPrototypeOf()
返回一个布尔值,表示指定的对象是否在本对象的原型链中。
语法:
prototypeObj.isPrototypeOf(object)
【注意】:如果 prototypeObj 为 undefined 或 null,会抛出 TypeError。
(4)、Object.prototype.propertyIsEnumerable()
返回一个布尔值,判断指定属性是否可枚举(此方法可以确定对象中指定的属性是否可以被 for...in 循环枚举),内部属性设置参见 ECMAScript [[Enumerable]] attribute 。
语法:
obj.propertyIsEnumerable(prop)
- prop:需要测试的属性名。
(5)、Object.prototype.toLocaleString() 和 Object.prototype.toString()
- toLocaleString( )返回对象的字符串表示,该字符串与执行环境的地区对应;
- toString( )返回对象的字符串表示;
语法:
obj.toLocaleString();
obj.toString()
举一些例子:
var a = 6666;
a.toLocaleString(); //"6,666"
a.toString(); //"6666"
var d = new Date();
console.log(d.toLocaleString()); //2018/1/4 下午10:32:18
console.log(d.toString()); //Thu Jan 04 2018 22:32:18 GMT+0800 (中国标准时间)
(6)、Object.prototype.valueOf()
返回指定对象的原始值。
你很少需要自己调用valueOf方法;当遇到要预期的原始值的对象时,JavaScript会自动调用它。
语法:
object.valueOf()
6、对象字面量
对象字面量可以传递可选参数:一般,命名参数虽然容易处理,但在有多个可选参数的情况下就会显得不够灵活。最好的办法是:
- 必需值-使用命名参数;
- 可选值-使用对象字面量来封装多个可选参数。
function displayInfo(args){
var output = "";
if(typeof args.name === "string"){
output += args.name + "";
}
if(typeof args.age === "number"){
output += "," + args.age + "\n";
}
console.log(output);
}
displayInfo({
name: "Marry",
age: 18
}); // Marry,18
displayInfo({
name: "Jack"
}); // Jack
在这个例子中,函数displayInfo()接受一个名为args的参数。这个参数可能带有一个名为name或age的属性,也可能这两个属性都有或者都没有,但函数都可以正常执行。
【拓展】js 数据类型——typeof 操作符与 instanceof 操作符
7、如何将两个字符串以“key: value”的格式放进一个对象里?
var obj = {};
var name = "a";
var value = "111";
if(name.length){
obj[name] = value;
}
console.log(obj); // {a: "111"}
8、对象的可枚举属性
对象的可枚举属性:其自身定义的属性,而不是其原型链上的枚举属性。
js 获取对象内属性的个数以及获取对象的属性和方法(Object.keys()、Object.getOwnPropertyNames()、for...in...对比)
js ES6 Iterator 遍历器与 for、for...of、for await...of、for...in 和 forEach 循环语句
9、深拷贝与浅拷贝
二、Array类型
1、js数组的特点
与其他语言不同,JavaScript中的数组有两个特点:
- 每一项都可以保存任何类型的数据;
- 数组的大小可以随着数据的添加自动增长。
2、创建数组的两种方式
(1)、Array 构造函数法
var color1 = new Array(); // 使用构造函数法创建一个数组
var color4 = Array(); // 使用构造函数法创建一个数组时,可以省略new关键字
var color2 = Array(3); // 创建一个包含3项的数组
var color3 = Array("red"); // 创建一个包含1项的数组,这一项的值是字符串red
(2)、数组字面量表示法
var color = []; // 创建一个空数组
var color = ["red", "blue", "black"]; // 创建一个包含3项的数组,每一项的值依次是字符串red、blue、black
3、数组的 length 属性
只要是数组,就一定有length属性。
length属性是可读可写的:
- 通过 “读” 一个数组的length属性,能够得知该数组的 长度;
- 通过 “写” 一个数组的length属性,能够 向数组中添加项 或 从数组的末尾移除项 。
var colorsArr = ["red", "blue", "black"];
console.log(colorsArr.length); // 3
colorsArr.length = 4;
console.log(colorsArr[3]); // undefined
在上述代码中,数组colorsArr一开始包含3项,所以length属性是3。然后,把它的length属性设置成4,可是这个数组不存在位置3(colorsArr[3]),所以访问这个位置的值就得到了特殊值undefined。
var colorsArr = ["red", "blue", "black"];
colorsArr.length = 2;
console.log(colorsArr); // ["red", "blue"]
在上述代码中,数组colorsArr一开始包含3项,所以length属性是3。然后,将其length属性设置为2,这样会移除最后一项(位置为2的哪一项),结果在访问colorsArr[2]就会显示undefined了。
var colorsArr = ["red", "blue", "black"];
colorsArr[colorsArr.length] = "gray"; // (在位置3)添加一个值为字符串gray的项
colorsArr[colorsArr.length] = "green"; // (在位置4)添加一个值为字符串green的项
利用 length 属性可以方便地在数组末尾添加新项。在上述代码中,由于数组的最后一项的引索始终是 length-1, 因此,下一个新项的位置就是 length-1。每当在数组的末尾添加一项后,其 length 属性都会自动加一来更新自身的值。
4、检测数组
- IE8及其以下版本用 instanceof 操作符;
- IE9+用Array.isArray() 方法。
(1)、instanceof 操作符 检测数组(IE8及其以下)
if (value instanceof Array){
// 对数组的操作
}
(更多 instanceof 操作符的运用,请戳:js 数据类型——typeof 操作符与 instanceof 操作符)。
为什么会尽量摒弃 instanceof 操作符检测数组呢?
instanceof 操作符存在一个经典问题——“确定某个对象是不是数组”:
具体来说,instanceof 操作符的问题在于,使用它的前提条件是,它假定只有一个全局执行环境。如果网页中包含多个框架,那实际上就存在两个以上不同的全局执行环境,从而存在两个以上不同版本的 Array 构造函数。如果你从一个框架向另一个框架传入一个数组,那么就会导致传入的数组与在第二个框架中原声创建的数组分别具有各自不同的构造函数,那么这个时候就会产生一个疑问——“这个传入的数组竟然更本框架的构造函数不同,那么它是数组呢,还是对象呢”。
(2)、Array.isArray() 方法 检测数组(IE9+)
if (Array.isArray(value)){
// 对数组的操作
}
其他主流浏览器都支持 Array.isArray() 方法。
5、栈方法
push() 和 pop() 方法,可以像栈一样管理数组。栈是一种LIFO(Last-In-First-Out,后进先出)的数据结构,最新添加的项最早被移除。
(1)、push() 方法能够在数组末尾添加任意个项,并返回新的数组的长度。
(2)、pop() 方法能够在数组末尾移除最后一项,并返回该项,同时数组长度减1。
6、队列方法
shift() 和 push() 方法,可以像队列一样管理数组。队列是一种FIFO(First In-First-Out,先进先出)的数据结构,最新添加的项最后被移除。
(1)、push() 方法能够在数组末尾添加任意个项,并返回新的数组的长度。
(2)、shift() 方法能够在数组前端移除第一项,并返回该项,同时数组长度减1。
拓展:unshift() 方法
顾名思义,unshift() 与 shift() 方法的用途相反:从数组前端添加任意个项,并返回新的数组的长度。因此,用 unshift() 和 pop() 方法,可以从反方向来模拟队列,即在数组的前端添加项,在数组的末尾移除项。
7、排序方法——sort() 和 reverse()
sort() 和 reverse() 方法,可以直接用来重排序数组。
(1)、sort()
- 默认情况下,sort() 方法按升序排列数组项,即最小的值位于最前面,最大的至位于最后面。
- sort() 方法可以接收一个(可选的)参数,这个参数必须是函数,以实现更灵活的排序方案。
①、为了实现排序,sort() 方法会调用每个数组项的 toString() 方法,然后比较得到的字符串,以确定如何排序。即使数组中的每一项都是数值,sort() 方法比较的也是字符串。
var arr = [1,3,6,4,2,5];
arr.sort();
alert(arr); // 1,2,3,4,5,6
②、 sort() 方法可以接受一个比较函数作为参数,以实现更灵活的排序方案。
升序排列的函数封装:
function compare(value1, value2) {
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
}
var arr = [1,3,6,4,2,5];
arr.sort(compare);
alert(arr); // 1,2,3,4,5,6
// 或者
function sortNumber(a, b) {
return b - a;
}
var arr = [1,3,6,4,2,5];
arr.sort(sortNumber);
alert(arr); // 1,2,3,4,5,6
降序排列的函数封装:
function compare(value1, value2) {
if (value1 < value2) {
return 1;
} else if (value1 > value2) {
return -1;
} else {
return 0;
}
}
var arr = [1,3,6,4,2,5];
arr.sort(compare);
alert(arr); // 6,5,4,3,2,1
// 或者
function sortNumber(a, b) {
return a - b;
}
var arr = [1,3,6,4,2,5];
arr.sort(sortNumber);
alert(arr); // 6,5,4,3,2,1
(2)、reverse() 方法能够反转数组
var arr = [1,3,6,4,2,5];
arr.reverse();
alert(arr); // 5,2,4,6,3,1
(3)、更多的数组排序
8、拼接数组——concat()
- concat() 方法,首先会创建当前数组的一个副本,然后将接收到的参数拼接到这个副本的末尾,最后返回新构建的数组。
- 在没有传参的情况下,concat() 方法只是复制数组,并返回副本。
- 如果传递给 concat() 方法的是一个或多个数组,则该方法会将这些数组中的每一项都添加到结果数组中。
var colorsArr = ["red", "blue", "black"];
var colorsArr2 = colorsArr.concat(1, 2, ["小明", "小红", [18, 21]]);
console.log(colorsArr2); // ["red", "blue", "black", 1, 2, "小明", "小红", Array(2)]
【注意】concat 和 扩展运算符 拼接数组时,都是按先后顺序在原数组后拼接的,不会打乱原数据的顺序。
9、数组转字符串——join() 和 toString()
(1)、join()——把数组中的所有元素放入一个字符串
[1, 2, 3].join('');// "123"
(2)、toString()——把数组直接转为一个字符串
数组是对象的一种特殊表现形式,因为所有的对象都具有 toLocaleString()、toString()、valueOf() 方法,所以数组也具有这些方法。数组继承的 toLocaleString()、toString()、valueOf() 方法,在默认情况下都会以逗号分割字符串的形式返回数组项。推荐使用 toString() 方法。
var colorsArr = ["red", "blue", "black"];
alert(colorsArr); // red,blue,black
alert(colorsArr.valueOf()); // red,blue,black
alert(colorsArr.toString()); // red,blue,black
alert(colorsArr.toLocaleString()); // red,blue,black
拓展:toLocaleString() 方法经常也会返回与 toString() 和 valueOf() 方法相同的值,但并不总是如此。当它们内部的返回值不同时,调用它们时就会得到不同的结果。
var person1 = {
toLocaleString: function () {
return 'hello';
},
toString: function () {
return "你好";
}
};
var person2 = {
toLocaleString: function () {
return 'world';
},
toString: function () {
return "世界";
}
};
var people = [person1, person2];
alert(people); // 你好,世界
alert(people.toString()); // 你好,世界
alert(people.toLocaleString()); // hello,world
10、数组截取——slice()
- slice() 方法截取当前数组中的一部分,作为新数组返回,不改变原数组;
- slice() 方法可以接受一个或两个参数:要返回项的 起始位置 和 结束位置;
- 若只有一个参数,slice() 方法返回:从该参数指定位置开始,到数组末尾的所有项。
- 若有两个参数,slice() 方法返回:起始位置 和 结束位置之间的项。
var colorArr = ["red", "blue", "black", "gray", "green"];
var colorArr2 = colorArr.slice(1);
var colorArr3 = colorArr.slice(1,3);
console.log(colorArr); // ["red", "blue", "black", "gray", "green"]
console.log(colorArr2); // ["blue", "black", "gray", "green"]
console.log(colorArr3); // ["blue", "black"]
若要更深入的学习 slice() 方法,请戳: js slice 和 splice 方法的深入理解
11、数组删除、插入 与 替换——splice()
splice() 方法有多种用法,对于数组的项,splice() 方法可以:删除、插入 与 替换。
- splice() 方法的返回值:始终都会返回一个 包含从原始数组中删除的项的新数组,改变原数组。
(1)、删除
- splice() 方法可以删除任意数量的项。
- 需要2个参数:要删除的第一项的位置 和 要删除的项数。
var colorArr = ["red", "blue", "black"];
var colorArr2 = colorArr.splice(0, 2);
console.log(colorArr); // ["black"]
console.log(colorArr2); // ["red", "blue"]
(2)、插入(添加)
- 可以向指定位置插入任意数量的项。
- 需要三个参数:起始位置、0(要删除的项数) 和 要插入的项。
var colorArr = ["red", "blue", "black"];
var colorArr2 = colorArr.splice(1, 0, "yello", "orange");
console.log(colorArr); // ["red", "yello", "orange", "blue", "black"]
console.log(colorArr2); // []
(3)、替换
- 可以向指定位置插入任意数量的项。
- 需要三个参数:起始位置、要删除的项数 和 要插入的项。
var colorArr = ["red", "blue", "black"];
var colorArr2 = colorArr.splice(1, 1, "yello", "orange");
console.log(colorArr); // ["red", "yello", "orange", "black"]
console.log(colorArr2); // ["blue"]
若要更深入的学习 splice() 方法,请戳: js slice 和 splice 方法的深入理解
12、位置方法——indexOf() 和 lastIndexOf()
位置方法包括 indexOf() 和 lastIndexOf() 方法。
- 除IE8及其以下版本的浏览器,其他主浏览器都支持 indexOf() 和 lastIndexOf() 方法。
- indexOf() 和 lastIndexOf() 方法,都接收2个参数:要查找的项 和 (可选的)表示查找起点位置的索引。
- indexOf() 和 lastIndexOf() 方法,都返回要查找的项在数组中的位置,或者在没找到的情况下返回-1。
(1)、indexOf() 方法
从数组的前端(位置0)开始向后查找。
var numArr = [2,5,2,3,6,8];
console.log(numArr.indexOf(2)); // 0
console.log(numArr.indexOf(7)); // -1
console.log(numArr.indexOf(2, 2)); // 2
(2)、lastIndexOf() 方法
从数组的末尾开始向前查找。
var numArr = [2,5,2,3,6,8];
console.log(numArr.lastIndexOf(2)); // 2
console.log(numArr.lastIndexOf(7)); // -1
console.log(numArr.lastIndexOf(2, 2)); // 2
13、迭代方法——filter()、forEach()、map()、every() 和 some()
迭代方法包括5个:filter()、forEach()、map()、every() 和 some() 方法。
- 每个方法都接收2个参数:要在每一项上运行的函数 和 (可选的)运行函数的作用域对象——影响 this 的值。
- 传入这些方法中的函数会接收3个参数:数组项的值、该项在数组中的位置 和 数组对象本身。
- IE8及以下版本的浏览器不支持这些方法。
(1)、filter() 方法
- filter() 方法使用指定的函数测试数组中所有的项,并创建一个包含所有通过测试的项的新数组,如果都没通过就返回一个空数组。
- filter() 方法不会对空数组进行检测。
- filter() 方法不改变原数组。
let numArr = [1,2,3,4,5,4,3,2,1];
let filterResult1 = numArr.filter((item, index)=>{
return item<3;
})
console.log(filterResult1); // [1, 2, 2, 1]
(2)、map() 方法
- map() 方法使用指定的函数测试数组中所有的元素,并返回每次函数调用的结果组成的新数组。
- map() 不会对空数组进行检测。
- map() 方法不改变原数组。
let numArr = [1,2,3,4,5,4,3,2,1];
let mapResult1 = numArr.map((item, index)=>{
return item * 2;
})
console.log(mapResult1); // [2, 4, 6, 8, 10, 8, 6, 4, 2]
(3)、forEach() 方法
- forEach() 方法使用指定的函数测试数组中所有的元素,没有返回值。
- forEach() 方法本质上与for循环迭代数组一样。
let numArr = [1,2,3,4,5,4,3,2,1];
numArr.forEach((item, index)=>{
// 对数组的一些操作
})
(4)、every() 和 some()方法
every() 和 some()方法都用于检查数组中的项是否满足某个条件:
- every() 方法使用指定的函数测试数组中所有的项,在数组的所有项都满足该条件时,才返回true,否则返回false;
- some() 方法使用指定的函数测试数组中所有的项,只要数组中有一项满足条件,就返回true,都不满足才返回false。
// every() 方法
let numArr = [1,2,3,4,5,4,3,2,1];
let everyResult1 = numArr.every((item, index)=>{
return item>0;
})
let everyResult2 = numArr.every((item, index)=>{
return item>2;
})
console.log(everyResult1); // true
console.log(everyResult2); // false
// some() 方法
let numArr = [1,2,3,4,5,4,3,2,1];
let someResult1 = numArr.some((item, index)=>{
return item<0;
})
let someResult2 = numArr.some((item, index)=>{
return item<2;
})
console.log(someResult1); // false
console.log(someResult2); // false
(5)、深入探索 filter()、forEach()、map()、every() 和 some() 方法
深入探索 filter()、forEach()、map()、every() 和 some() 方法,请戳:js forEach、map、filter、every、some 方法的深刻理解
14、归并方法——reduce() 和 reduceRight()
归并方法包括:reduce() 和 reduceRight() 方法。
- reduce() 和 reduceRight() 方法都接收2个参数:数组每一项都要调用的函数 和 (可选的)作为归并基础的初始值。
- 传入这些方法中的函数会接收4个参数:前一个值、当前值、项的索引 和 数组对象。
- reduce() 和 reduceRight() 方法都改变原数组。
(1)、reduce() 方法
reduce() 方法从数组的第一项开始,遍历到最后。
let numArr = [1,2,3,4,5];
let sum1 = numArr.reduce((prev, cur, index, array)=>{
return prev + cur;
});
console.log(sum1); // 15
上述代码,第一次执行回调函数时,prev 是1,cur 是2。第二次执行时,prev 是3(1 加 2 的结果),cur 是3(数组 numArr 中的第三项)。以此类推,累加直至数组最后一项,最后返回结果。
let numArr = [1,2,3,4,5];
let sum2 = numArr.reduce((prev, cur, index, array)=>{
return prev + cur;
}, 100);
console.log(sum2); // 115
上述代码,制定了初始值位100,所以,第一次执行回调函数时,prev 是100,cur 是1。第二次执行时,prev 是101,cur 是2。以此类推,累加直至数组最后一项,最后返回结果。
(2)、reduceRight() 方法
reduceRight() 方法从数组的最后一项开始,向前遍历到第一项。
let numArr = [1,2,3,4,5];
let sum = numArr.reduceRight((prev, cur, index, array)=>{
return prev + cur;
});
console.log(sum); // 15
上述代码,第一次执行回调函数时,prev 是5,cur 是4。第二次执行时,prev 是9(5 加 4 的结果),cur 是3(数组 numArr 中的第三项)。以此类推,累加直至数组最后一项,最后返回结果。
(3)、reduce() 和 reduceRight() 方法的深入探索
reduce() 和 reduceRight() 方法的深入探索:js reduce 和 reduceRight 方法的深入理解_青蛙king的博客-CSDN博客
15、数组去重的 9 种方法
数组去重的 9 种方法,请戳:js 数组去重_青蛙king的博客-CSDN博客
16、数组的扁平化
数组的扁平化 6 种方法,请戳这里:数组的扁平化_青蛙king的博客-CSDN博客
三、Date 类型
1、获取本地时间
var date = new Date();
console.log(date.toString()); // "Wed Nov 21 2019 16:15:45 GMT+0800 (中国标准时间)"
2、获取时间戳
var time = new Date().getTime();
console.log(time); // 1574842752647
3、Date对象的方法归纳
Date对象中的具体方法主要可以分为两大类:
- 一类是获取时间的方法(set系列方法)。
- 一类是设置时间的方法(get系列方法)。
(1)、get系列方法
get获取 | 方法 | 作用 |
年 | getFullYear() | 通过Date对象获取四位数字表示的年份 |
月 | getMonth() | 通过Date对象获取一年中第几个月份,取值是0-11 |
日 | getDate() | 通过Date对象获取一个月中的某一天,取值是1-31 |
周几 | getDay() | 通过初始化的Date对象获取一周中的第几天,取值是0(周日)- 6(周六) |
时 | getHours() | 通过初始化的Date对象获取小时数,取值是0-23 |
分 | getMinutes() | 通过初始化的Date对象获取分钟数,取值是0-59 |
秒 | getSeconds() | 通过初始化的Date对象获取秒数,取值是0-59 |
毫秒 | getMilliseconds() | 通过初始化的Date对象获取毫秒数,取值是0-999 |
获取某个时间戳 | getTime() | 获取从1970年1月1日到通过初始化Date对象的毫秒数 |
(2)、set系列方法
set设置 | 方法 | 作用 |
年 | setFullYear(yyyy) | 通过Date对象设置四位数字表示的年份yyyy |
月 | setMonth(mm) | 通过Date对象设置一年中第几个月份mm |
日 | setDate(dd) | 通过Date对象设置一个月中的某一天dd |
时 | setHours(hh) | 通过初始化的Date对象设置小时数hh |
分 | setMinutes(mm) | 通过初始化的Date对象设置分钟数mm |
秒 | setSeconds(ss) | 通过初始化的Date对象设置秒数ss |
毫秒 | setMilliseconds(ms) | 通过初始化的Date对象设置毫秒数ms |
设置某个时间戳 | setTime(ms) | 设置从1970年1月1日到通过初始化Date对象的毫秒数ms |
4、如何获取指定日期时间?
自己封装一个函数:
function writeCurrentDate(date, format, connect) {
var Y = date.getFullYear(); //得到年份
var M = date.getMonth() + 1;//得到月份
var D = date.getDate();//得到日期
var WN = date.getDay();//得到周几
var HH = date.getHours();//得到小时
var MM = date.getMinutes();//得到分钟
var SS = date.getSeconds();//得到秒
var MS = date.getMilliseconds();//获取毫秒
// 小于0就前面补零
if (M < 10) M = "0" + M;
if (D < 10) D = "0" + D;
if (HH < 10) HH = "0" + HH;
if (MM < 10) MM = "0" + MM;
if (SS < 10) SS = "0" + SS;
if (MS < 100) MS = "0" + MS;
// 一周列表
var arr_week = new Array("星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六");
var W = arr_week[WN];
return {
time: Y + "年" + M + "月" + D + "日" + " " + HH + ":" + MM + ":" + SS + ":" + MS + " " + W,
Y: Y,
M: M,
D: D,
HH: HH,
MM: MM,
SS: SS,
MS: MS,
W: W
};
}
var date = new Date();
var formatDate = writeCurrentDate(date);
alert(formatDate);
四、RegExp 类型
更多关于“正则表达式 RegExp 对象”请戳这里。
常用的正则表达式请戳这里。
1、正则表达式的语法
var expression = /pattern/flags;
pattern 为正则表达式。
flags 为标志(表明正则表达式的行为),正则表达式有3个标志:
- g: 表示全局模式,被应用于所有字符串,并非发现一个就停止
- i: 表示不区分大小写
- m: 表示多行模式,会换行进行匹配
2、正则表达式的创建
(1)、字面量法
var pattern = /[bc]at/g;
(2)、构造函数法
用 构造函数法 创建正则表达式,需要传2个参数:正则表达式 (pattern)和 标志(flags),这两个参数都是字符串。
var pattern = new RegExp("[bc]at", "g");
3、元字符必须转义
(1)、正则表达式中的 元字符
正则表达式中的 元字符 包括:
\ 转义字符
. 匹配除换行符以外的任意字符
^ 匹配字符串的开始位置
$ 匹配字符串的结束位置
* 重复任意次, 相当于{0,}
? 重复0次或1次, 相当于{0,1}
+ 重复1次或更多次, 相当于{1,}
{n} 重复n次
{n,} 重复n次或者大于n次
{n,m} 重复n到m次
\d 匹配0-9的数字,相当于[0-9]
\D 匹配除了0-9的任意字符
\w 匹配0-9、a-z、A-Z、_ 的数字或字符,相当于[0-9a-zA-Z_]
\W 匹配不是字母、数字、下划线的字符
\s 匹配任意不可见字符, 包括空格、制表符、换行符等
\S 匹配任意可见字符
\b 匹配单词的边界
\t 匹配制表符
\n 匹配换行
x | y x或者y
[xyz] x、y、z中的任意一个 例:[abc] 可以匹配add中的a
[^xyz] 除了xyz中的任意一个字符 例:[abc] 可以匹配add中的dd
[a-z] 匹配a-z中的任意一个字符
[^a-z] 匹配除了a-z中的任意一个字符
() 将括号里面的字符作为整体进行匹配, 括号里面的内容是一个子表达式或者叫分组
(2)、正则表达式中使用的元字符必须转义。
// 匹配第一个“bat”或“cat”,不区分大小写
var pattern1 = /[bc]at/i;
// 匹配第一个“[bc]at”,不区分大小写
var pattern1 = /\[bc\]at/i;
4、正则的属性
(1)、lastIndex 属性
正则表达式对象的方法(exec 和 test 两个方法)使用时,要特别注意它的lastIndex属性。
lastIndex 属性:表示正则表达式开始下一次查找的索引位。
var regexp = /abcd/g;
var str = 'abcdefg';
alert(regexp.test(str)); //true
alert(regexp.test(str)); //false
alert(regexp.test(str)); //true
上述代码,第一次查找的时候总是为0的,第一次查找完了的时候会把lastIndex的值设为匹配到得字符串的最后一个字符的索引位置加1,第二次查找的时候会从lastIndex这个位置开始,后面的以此类推。如果没有找到,则会把lastIndex重置为0。要注意的是,lastIndex属性只有在有全局标志正则表达式中才有作用,如果我们把上面代码中正则表达式的g标志去掉,那么三次弹出的就都是true了。
var regexp = /abcd/;
var str = 'abcdefg';
alert(regexp.test(str)); //true
alert(regexp.test(str)); //true
alert(regexp.test(str)); //true
(2)、source 属性
source 属性:返回正则表达式的正文。
/abc/ig.source
// "abc"
5、正则的实例方法
JavaScript 中,正则表达式的使用方式有两种:
- 正则表达式对象的方法:
- exec(str) 方法
- test(str) 方法
- 字符串对象的方法:
- match(regexp) 方法
- replace(regexp) 方法
- search(regexp) 方法
- split(search) 方法
当作为正则表达式对象的方法使用时,要特别注意它的lastIndex属性。
(1)、exec() 方法
语法:
RegExpObject.exec(string);
- exec() 方法用于检测一个字符串是否匹配某个模式,如果字符串中有匹配的值返回包含该匹配值的数组,否则返回 null。
- exec() 方法接收一个字符串参数,返回包含第一个匹配项信息的数组,这个数组包含两个属性:index 和 input。
- index 表示匹配项在字符串中的位置,input 表示应用正则表达式的字符串。
- exec() 方法,不但能检测出目标字符串与某个模块是否匹配,而且还能得到匹配的内容。
var str1 = "Hello world!";
var patt1 = /Hello/g;
var result1 = patt1.exec(str1);
console.log("返回值: " + result1); // Hello
console.log(result1.index); // 0
console.log(result1.input); // Hello world!
console.log(result1[0]); // Hello
console.log(result1[1]); // undefined
var str2;
patt2 = /learn/g;
result2 = patt2.exec(str2);
console.log("返回值: " + result2); // null
(2)、test() 方法
语法:
RegExpObject.test(string);
- test() 方法,只能检测出目标字符串与某个模块是否匹配,如果字符串中有匹配的值返回 true ,否则返回 false,却不知道其文本内容。
var str = "000-00-0000";
var pattern = /\d{3}-\d{2}-\d{4}/;
if(pattern.test(str)){
// str 与 pattern 正则表达式匹配
}
(3)、match() 方法
match() 方法与 RegExp 的 exec() 方法一样,用来获取与正则表达式相匹配的字符串,最后返回一个由所有符合正则表达式的字符串组成的数组。不同的是:
- match() 方法只接收一个参数,要么是一个正则表达式,要么是一个 RegExp 对象。
- exec() 方法只接收一个参数,字符串。
var text = "cat, bat, sat, fat";
var pattern = /.at/;
var matches = text.match(pattern);
console.log(matches); // ["cat", index: 0, input: "cat, bat, sat, fat", groups: undefined]
var execs = pattern.exec(text);
console.log(execs); // ["cat", index: 0, input: "cat, bat, sat, fat", groups: undefined]
(4)、search() 方法
- search() 方法与match() 方法一样,接收一个参数,这个参数:要么是一个正则表达式,要么是一个 RegExp 对象。
- search() 方法返回字符串中第一个匹配项的索引。如果没有找到匹配项,就返回-1。
- search() 方法始终是从字符串开头向后(从左向右)查找。
var text = "cat, her, yes, son";
var pos1 = text.search(/at/);
var pos2 = text.search(/er/);
console.log(pos1); // 1
console.log(pos2); // 6
(5)、replace() 方法
- replace() 方法返回替换子字符串后的字符串。
- replace() 方法接收2个参数:一个 RegExp 对象(或者一个不会被转换成正则表达式的字符串) 和 一个字符串(或者一个函数)。
- 如果第一个参数是字符串,只会替换第一个子字符串;
- 如果想替换所有子字符串,唯一的办法是:第一个参数是正则表达式(RegExp 对象),而且要指定全局(g)标志。
var text = "cat, bat, sat, fat";
var res1 = text.replace("at", "ond");
var res2 = text.replace(/at/g, "ond");
console.log(res1); // "cond, bat, sat, fat"
console.log(res2); // "cond, bond, sond, fond"
- replace() 方法的第二个参数也可以是函数。
- 在只有一个匹配项(即与模式匹配的字符串)时,会向这个函数传递三个参数:模式的匹配项、模式匹配项在字符串中的位置 和 原始字符串。
- 在正则表达式中定义了多个捕获组的时,函数依然接收三个参数,不过参数依次是:模式的匹配项(第一个捕获组的匹配项、第二个捕获组的匹配项、第三个捕获组的匹配项……)、模式的匹配项在字符串中的位置 和 原始字符串。
使用函数作为第二个参数,可以实现更加精准的子字符串替换操作:
function fn (text) {
return text.replace(/[<>"&]/g, function(match, pos, originalText){
switch (match) {
case "<":
return "<";
case ">":
return ">";
case "\"":
return "&";
case "&":
return "&qout";
}
})
}
console.log(fn("<p class=\"aaa\">Hello world!</p>")); // <p class=&aaa&>Hello world!</p>
(6)、split() 方法
- split() 方法基于指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中返回。
- split() 方法最多接收2个参数:分隔符 和 (可选的)指定数组的大小
- 分隔符可以是字符串,也可以是一个 RegExp 对象(这个方法不会将字符串看成正则表达式)。
var colorText = "red,blue,green,yellow";
console.log(colorText.split(",")); // ["red", "blue", "green", "yellow"]
console.log(colorText.split(",", 2)); // ["red", "blue"]
console.log(colorText.split(/[^\*]+/)); // ["", "*", "*", "*", ""]
注意: split() 方法对正则表达式的支持因浏览器而异,在使用正则表达式时,一定要在各种浏览器上多做一些测试。
五、Function 类型
- javaScript 函数,不介意传递多少个参数,不介意传入的参数是什么类型。
- 函数实际上是对象,每个函数都是 Function 类型的实例,与其他引用类型一样具有对象的属性和方法。
- 因为函数是对象,所以 函数名 实际上是一个指向函数对象的 指针,所以函数名也是一个变量,一个函数的存储地址。
1、函数的定义方法
(1)、函数声明法
function fn () {
// 函数体
}
(2)、函数表达式法
var fn = function(){
// 函数体
}
(3)、构造函数法(不提倡)
var fn = new Function();
2、函数声明与函数表达式的区别
- 解析器会先读取函数声明,使得函数声明在执行任何代码之前可用;
- 至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被调用。
console.log(fn1(10, 10)); // 20
function fn1 (num1, num2) {
return num1 + num2;
}
console.log(fn2(10, 10)); // fn2 is not a function
var fn2 = function(num1, num2){
return num1 + num2;
}
3、作为值的函数(★★★)
因为函数名是一个变量,所以,不仅可以把一个函数当做参数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回。
/**
* 定义一个名为callSomeFunction的函数,接收2个参数:
* @ someFunction:是一个函数;
* @ someArgument:是要传递给函数 someFunction() 的一个值
**/
function callSomeFunction (someFunction, someArgument) {
return someFunction(someArgument);
}
function add10(num){
return num + 10;
}
var result1 = callSomeFunction(add10, 10);
console.log(result1); // 20
function getGreeting(name){
return 'Hello,' + name;
}
var result2 = callSomeFunction(getGreeting, 'Marry');
console.log(result2); // Hello,Marry
实际应用:
①、问题:月考成绩出来了,要求根据科目分数和总分分数,分别对学生进行排名,得到每科的第一名,和总成绩的第一名,分别颁奖。
②、需求分析:这是一个根据某个对象属性对对象数组进行排序的问题。
在根据某个对象属性对数组进行排序时,传递给数组 sort() 方法的比较函数要接受2个参数,即要比较的值。可是,我们需要一种方式来指明按照哪个属性来排序。要解决这个问题,可以把比较函数进一步封装成能接收一个属性名作为参数的函数:
定义一个函数,它接收一个属性名参数,然后根据这个属性名来创建一个比较函数。
③、代码实现:
function createCompareFunction (propertyName) {
return function (obj1, obj2) {
var value1 = obj1[propertyName];
var value2 = obj2[propertyName];
if (value1 < value2) {
return 1;
} else if (value1 > value2) {
return -1;
} else {
return 0;
}
}
}
var schoolReport = [
{
name: 'Marry',
Chinese: 66,
Mathematics: 21,
total: 87
},
{
name: 'Bluse',
Chinese: 88,
Mathematics: 92,
total: 180
},
{
name: 'Lily',
Chinese: 98,
Mathematics: 72,
total: 170
}
];
// 按语文成绩排名,输出第一名
schoolReport.sort(createCompareFunction("Chinese"));
console.log(schoolReport[0].name); // Lily
// 按数学成绩排名,输出第一名
schoolReport.sort(createCompareFunction("Mathematics"));
console.log(schoolReport[0].name); // Bluse
// 按总成绩排名,输出第一名
schoolReport.sort(createCompareFunction("total"));
console.log(schoolReport[0].name); // Bluse
4、函数内置对象
(1)、arguments 对象
①、arguments 对象包含着传入函数中的所有参数,它的主要用途就是保存函数的参数。
②、arguments 对象是一个类数组对象,具有数组的特性
- arguments 对象可以通过数组的 方括号语法 访问它的每一个元素;
- arguments 对象具有数组的 length 属性。
function fn () {
let msg = `我是${arguments[0]}, 我今年${arguments[1]}岁了。`;
let lenth = arguments.length;
console.log([msg, length]);
}
fn('marry', 18); // ["我是marry, 我今年18岁了。", 2]
// 以上函数的实现等同于
function fn2 (arg0, arg1) {
let msg = `我是${arg0}, 我今年${arg1}岁了。`;
let lenth = arguments.length;
console.log([msg, length]);
}
fn2('marry', 18); // ["我是marry, 我今年18岁了。", 2]
③、arguments 对象的 callee 属性
- arguments 对象的 callee 属性是一个指针,该指针指向拥有这个 arguments 对象的函数。
- 严格模式下,访问 arguments.callee 会报错。
经典案例:阶乘函数
function factorial (num) {
if (num <= 1) {
return 1;
} else {
return num * factorial(num - 1);
}
}
定义阶乘函数一般都要用到递归算法。如上代码,在函数有名字,而且名字以后也不会变得情况下,这样定义没有问题。但问题是这个函数的执行与函数名 factorial 仅仅耦合在了一起。为了消除这种紧密的耦合现象,就可以用argument.callee。
function factorial (num) {
if (num <= 1) {
return 1;
} else {
return num * arguments.callee (num - 1);
}
}
重写后,没有再引用函数名 factorial。这样,无论引用函数时使用的是什么名字,都可以保证正常完成递归调用。
总结:递归时最好使用 arguments.callee 属性。
(2)、this 对象
this 对象是在函数运行时,才会基于函数的执行环境被指定,this 永远指向最后调用它的那个对象。
this的几种使用情况:
- 在全局环境下直接执行函数,this 指向 window 对象 。
- 当函数作为某个对象的方法被调用,this 指向这个对象。
- 作为构造函数调用(通过这个函数,new 一个新对象)时,this 就指这个新对象。
- 调用 call() 或 apply() 方法来动态改变this指向,this 指向传入 call() 或 apply() 方法的对象。
- ES6 的箭头函数都不能改变 this 的指向(也就是说,箭头函数能保护 this 的指向不会发生改变)。
①、在全局环境下直接执行函数,this 指向 window 对象
var a = 111;
function fn(){
var b = 222;
console.log([a, b]); // [111, 222]
}
fn();
this 永远指向最后调用它的那个对象,在全局环境直接执行函数,相当于 window 对象调用了该函数(window.fn();),所以 this 指向window 对象。
②、当函数作为某个对象的方法被调用,this 指向这个对象
var b = 222;
var obj = {
a: 111,
fn: function(){
console.log(this.a); // 111
console.log(this.b); // undefined
}
}
obj.fn();
this 永远指向最后调用它的那个对象,所以 this 指向 obj 对象。
③、作为构造函数调用(通过这个函数,new 一个新对象)时,this 就指这个新对象
var subClass = new TestClass();
subClass.name = 'cn';
console.log(subClass.name); // cn
var TestClass = function(){
this.name = '111';
}
var subClass1 = new TestClass();
console.log(subClass1.name); // 111
④、调用 call() 或 apply() 方法来动态改变this指向,this 指向传入 call() 或 apply() 方法的对象
var obj1 = {
a: 111
};
var obj2 = {
a: 222,
fn: function(){
console.log(this.a); // 111
}
}
obj2.fn.call(obj1);
本来是“this 永远指向最后调用它的那个对象”,可是这里函数 fn 用了 call() 方法,call() 方法 this 指向其参数对象,所以,这里 this 指向 obj1。
关于 call() 或 apply() 方法,这里点到为止,具体的讲解请继续往下看。
⑤、ES6 的箭头函数都不能改变 this 的指向(也就是说,箭头函数能保护 this 的指向不会发生改变)
var b = 222;
var obj = {
a: 111,
fn: ()=>{
console.log(this.a); // undefined
console.log(this.b); // 222
}
}
obj.fn();
与 ② 对比一下,不难发现,我只是把函数改成了箭头函数,this指向就不一样了。为什么呢?因为箭头函数都能保证 this 的指向不会发生改变。在上述代码中,在没创建 obj 对象里的箭头函数之前,this 指向 window 对象,所以,即使创建了 obj 对象里的 箭头函数,由于箭头函数的特性,this 还是指向 window 对象。所以,访问不到 obj 对象里的属性 a,但能访问到全局变量 b。
5、函数内置属性
因为函数是对象,所以函数也继承了对象的属性和方法。每个函数都包含2个属性:length 和 prototype。
(1)、length 属性
- length 属性表示函数希望接收的命名参数的个数。
function fn1 (name) {
alert(name);
}
function fn2 (num1, num2) {
alert(num1 + num2);
}
alert(fn1.length); // 1
alert(fn2.length); // 2
上述代码,fn1 函数定义了一个参数,因此其 length 值是1。类似的,fn2 函数定义了两个参数,结果其 length 是2。
拓展: 函数内置的 length属性 与 函数内置对象 arguments 对象的 length 属性的区别
- 函数内置的 length属性的作用是 “表示函数希望接收的命名参数的个数” ;
- 函数内置对象 arguments 对象的 length 属性表示 “调用函数时,实际传入参数的个数” ;
function fn1 (name) {
console.log(arguments.length); // 0
}
function fn2 (num1, num2) {
console.log(arguments.length); // 0
}
console.log(fn1.length); // 1
console.log(fn2.length); // 2
fn1();
fn2();
(2)、prototype 属性(有待日后扩充)
- JavaScript 的 prototype 原型对象指的就是构造函数的 prototype 属性。
- prototype 属性保存了引用类型的所有实例方法,诸如 toString()、toLocaleString() 和 valueOf() 等方法实际上都保存在 prototype 属性名下,可以通过各自的实例对象访问这些方法。
- prototype 属性是不可枚举的。
更多请戳这里:js 原型与原型链_青蛙king的博客-CSDN博客
6、函数内置方法
函数的内置方法都保存在其 prototype 属性上,包括 toString()、toLocaleString() 和 valueOf() 等方法,下面着重介绍一下函数独有的3个方法:
- 函数独有的3个方法:call() 、apply() 和 bind() 方法。
- call()、apply() 和 bind() 方法都是用来改变函数执行时的上下文(this),可借助它们实现继承。
- 调用 call()、apply() 和 bind() 方法 的必须是个函数。
(1)、apply() 方法
- apply() 方法接收2个参数:运行函数的作用域(也叫上下文执行环境) 和 一个参数数组
function sum(num1, num2){
return num1 + num2;
}
function fn1(num1, num2){
return sum.apply(this, arguments);
}
function fn2(num1, num2){
return sum.apply(this, [num1, num2]);
}
console.log(fn1(10, 10)); // 20
console.log(fn2(10, 10)); // 20
由于arguments是类数组,所以arguments也可以哦。
(2)、call() 方法
call() 和 apply() 方法唯一区别是参数不一样,call() 方法是 apply() 方法的语法糖。
- call() 方法也接收2个参数:运行函数的作用域(也叫上下文执行环境) 和 一个参数列表
function sum(num1, num2){
return num1 + num2;
}
function fn(num1, num2){
return sum.call(this, num1, num2);
}
console.log(fn(10, 10)); // 20
(3)、bind() 方法
bind() 方法与 call() 和 apply() 方法都可以改变上下文执行环境,不同的是,bind() 方法返回一个新函数,只有等这个新函数被调用才可以改变函数执行时的上下文(this),而 apply() 和 call() 方法是立即调用,立即就能改变 this 指向的。
- bind() 方法接收2个参数:运行函数的作用域(也叫上下文执行环境) 和 一个参数列表
- 浏览器 IE8 及其以下版本不支持 bind() 方法。
var color = "red";
var obj = {
color: "blue"
}
function fn(){
console.log(this.color); // blue
}
var objColor = fn.bind(obj);
objColor();
(4)、深入探索 call()、apply() 和 bind() 方法
深入探索 call()、apply() 和 bind() 方法,请戳:https://blog.csdn.net/mChales_Liu/article/details/102497060
7、JavaScript 函数没有重载
JavaScript 函数 没有重载,后面的函数只会覆盖前面同名的函数。
function fn (num) {
return num + 100;
}
function fn (num) {
return num + 200;
}
var res = fn(100); // 300
8、严格模式对函数的限制
- 不能出现两个命名参数相同的情况。
- 不能把函数命名为 eval 或 arguments。
- 不能把参数命名为 eval 或 arguments。
- 严格模式下,访问 arguments.callee 会报错。
- 在全局环境下直接执行函数,this 不再指向window 对象,此时 this 会返回 undefined ,必须显示的通过 window 对象调用函数,其 this 才会指向 window 对象。
9、js 函数进阶
js 函数声明与函数表达式、递归与闭包https://blog.csdn.net/mChales_Liu/article/details/103625344
函数式编程与面向对象编程https://blog.csdn.net/mChales_Liu/article/details/106530145
六、Boolean 类型(不建议使用)
Boolean 类型是与布尔值对应的引用类型。要创建 Boolean 对象,可以在调用 Boolean 构造函数时向其中传入 true 或 false 值。
Boolean 类型重写了 valueOf()、toLocaleString() 和 toString() 方法。
Boolean 对象 不建议使用,因为在使用 typeof 和 instanceof 操作符测试基本类型布尔值与引用类型布尔值时,返回值完全不同。
- typeof 操作符对基本类型布尔值返回 “boolean”,对引用类型布尔值返回 “object”。
- instanceof 操作符对基本类型布尔值返回 false,对引用类型布尔值返回 true。
【拓展】js 数据类型——typeof 操作符与 instanceof 操作符
七、Number 类型(不建议使用)
Number 类型是与数值对应的引用类型。要创建 Number 对象,可以在调用 Number 构造函数时向其中传递相应的数值。
Number 类型重写了 valueOf()、toLocaleString() 和 toString() 方法。
Number 对象 不建议使用,因为在使用 typeof 和 instanceof 操作符测试基本类型数值与引用类型数值时,返回值完全不同。
- typeof 操作符对基本类型数值返回 “number”,对引用类型布尔值返回 “object”。
- instanceof 操作符对基本类型数值返回 false,对引用类型布尔值返回 true。
【拓展】js 数据类型——typeof 操作符与 instanceof 操作符
Number 类型提供了一些将 数值转化为字符串 的方法:
1、toFixed() 方法
toFixed() 方法:按照指定的小数位,四舍五入,最后返回小数的字符串表示。
var num1 = 10.004;
var num2 = 10.005;
var floatStr1 = num1.toFixed(2);
var floatStr2 = num2.toFixed(2);
console.log([floatStr1, floatStr2]); // ["10.00", "10.01"]
2、toExponential() 方法
toExponential() 方法:按照指定的小数位,返回以指数表示法的数值的字符串形式。
var num = 10;
console.log(num.toExponential(1)); // "1.0e+1"
3、toPrecision() 方法
toPrecision() 方法用来:指定的精度返回该数值对象的字符串表示,四舍五入到参数指定的显示数字位数。
toPrecision() 方法返回:指定长度的数值字符串。
var num = new Number(13.3714);
var n = num.toPrecision(2);
console.log(n); // 13
八、String 类型
String 类型是与字符串对应的引用类型。要创建 String 对象,可以在调用 String 构造函数时向其中传入字符串数值。
String 类型重写了 valueOf()、toLocaleString() 和 toString() 方法。
1、String 类型的属性——length
String 类型的每个实例都有一个 length 属性。
var strValue = "hello";
console.log(strValue.length); // 5
2、String 类型的方法
(1)、“字符”方法——charAt() 和 charCodeAt()
1⃣️、charAt() 方法
返回指定位置的字符。
var strValue = "hello world";
console.log(strValue.charAt(1)); // "e"
拓展:JavaScript 中,用方括号加数字索引同样能实现与 charAt() 方法类似的功能:
var strValue = "hello world";
console.log(strValue[1]); // "e"
2⃣️、charCodeAt() 方法
返回指定位置的字符的字符编码(unicode编码)
var strValue = "hello world";
console.log(strValue.charCodeAt(1)); // "101"
(2)、字符串重复——repeat()
repeat() 方法字符串复制指定次数。
var str = '- ';
var result = str.repeat(6);
console.log(result); // _ _ _ _ _ _
(3)、字符串拼接——concat()
concat() 方法将一个或多个字符串拼接起来,返回一个新字符串,不改变原字符串。
var str = "hello";
var result = str.concat(" world");
console.log(result); // "hello world"
(4)、字符串截取——slice() 、substr() 和 substring()
- slice() 方法
- substr() 方法
- substring() 方法
1⃣️、slice() 方法
slice() 方法接收两个参数:
- 参数一:截取的开始位置。若参数是负数,就从字符串的尾部开始算起,即 -1 指字符串的最后一个字符,-2 指倒数第二个字符,以此类推。
- 参数二:(可选)截取的结束位置的下一位。若未指定此参数,则将字符串的末尾作为结束位置。
slice() 方法遇到参数一大于参数二时,其结果为“”。在遇到负值参数时,会将负值与字符串的长度相加。
slice() 方法返回一个新字符串,不改变原字符串。
var str = "hello world";
str.slice(3); // 'lo world'
str.slice(3, 7); // 'lo w'
str.slice(7, 3); // ''
str.slice(-3); // 'rld'
str.slice(3, -4); // 'lo w'
str.slice(-4, 3); // ''
str.slice(-3, -7); // ''
str.slice(-7, -3); // 'o wo'
2⃣️、substring() 方法
substring() 方法接收两个参数:
- 参数一:截取的开始位置。
- 参数二:(可选)截取的结束位置的下一位。若未指定此参数,则将字符串的末尾作为结束位置。
substring() 方法遇到参数1大于参数2时,会将参数1与参数2换位;在遇到负值参数时,会将负值转化为0。所以当两个都是负值时无效。
substring() 方法返回一个新字符串,不改变原字符串。
var str = "hello world";
str.substring(3); // 'lo world'
str.substring(3, 7); // 'lo w'
str.substring(7, 3); // 'lo w'
str.substring(-3); // 'hello world'
str.substring(3, -4); // 'hel'
str.substring(-4, 3); // 'hel'
str.substring(-3, -7); // ''
str.substring(-7, -3); // ''
3⃣️、substr() 方法
substr() 方法接收两个参数:
- 参数一:截取的开始位置。若参数是负数,就从字符串的尾部开始算起,即 -1 指字符串的最后一个字符,-2 指倒数第二个字符,以此类推。
- 参数二:(可选)截取的位数。必须为正数才有效。若未指定此参数,则将字符串的末尾作为结束位置。
substr() 方法在遇到负值参数时,参数1会将其与字符串长度相加,参数2会将其转换为0。
substr() 方法返回一个新字符串,不改变原字符串。
var str = "hello world";
str.substr(3); // 'lo world'
str.substr(3, 7); // 'lo wl'
str.substr(7, 3); // 'orl'
str.substr(-3); // 'rld'
str.substr(3, -4); // ''
str.substr(-4, 3); // 'orl'
str.substr(-3, -7); // ''
str.substr(-7, -3); // ''
(5)、字符串位置方法——indexOf() 和 lastIndexOf()
indexOf() 和 lastIndexOf() 方法都是:从一个字符串中搜索给定的子字符串,然后返回子字符串的位置,如果没有找到该子字符串,就返回-1。
1⃣️、indexOf() 方法
从左向右搜索子字符串。
2⃣️、lastIndexOf() 方法
从右向左搜索子字符串。
var str = "hello world";
console.log(str.indexOf("o")); // 4
console.log(str.lastIndexOf("o")); // 7
console.log(str.lastIndexOf("z")); // -1
console.log(str.indexOf("z")); // -1
(6)、去除前后的空格——trim() 方法
trim() 方法会创建一个字符串的副本,删除前后的所有空格,然后返回结果。
var str = " hello world ";
var trimStr = str.trim();
console.log(trimStr); // "hello world"
(7)、字符串大小写转换——toLowerCase()、toLocaleLowerCase()、toUpperCase() 和 toLocaleUpperCase()
- toLowerCase() 方法
- toLocaleLowerCase() 方法
- toUpperCase() 方法
- toLocaleUpperCase() 方法
var str = "hello world";
console.log(str.toLocaleUpperCase()); // "HELLO WORLD"
console.log(str.toUpperCase()); // "HELLO WORLD"
console.log(str.toLocaleLowerCase()); // "hello world"
console.log(str.toLowerCase()); // "hello world"
toLowerCase() 和 toUpperCase() 方法受地区限制,toLocaleLowerCase() 和 toLocaleUpperCase() 方法不受限。
(8)、字符串的模式匹配方法(字符串的正则方法)——match、replace、search 和 split
- match(regexp) 方法
- replace(regexp) 方法
- search(regexp) 方法
- split(search) 方法
详情参见本文的:js 引用类型_青蛙king的博客-CSDN博客
(9)、比较两个字符串在字符表中的先后顺序——localCompare() 方法
localCompare() 方法用来比较两个字符串在字符表中的先后顺序,返回值视三种情况而定:
- 如果在字母表中字符串排在参数字符串之前,则返回一个负数(一般返回数值-1);
- 如果字符串等于参数字符串,则返回数值0;
- 如果在字母表中字符串排在参数字符串之后,则返回一个正数(一般返回数值1);
var str = "hello";
console.log(str.localeCompare('world')); // -1
console.log(str.localeCompare('hello')); // 0
console.log(str.localeCompare('boy')); // 1
(10)、String.fromCharCode() 方法
- fromCharCode() 方法是一个 String 构造函数的静态方法,直接由 String 调用。
- fromCharCode() 方法接收一个或多个字符编码(Unicode 编码),将它们转为一个字符串。本质上与 charCodeAt() 方法的操作相反。
console.log(String.fromCharCode(104, 101, 108, 108, 111)); // "hello"
(11)、HTML 方法(仅了解,不推荐使用)
早期JavaScript动态格式化HTML的方法:
anchor(name): 输出结果 <a name = "name" >string</a>
big(): 输出结果 <big>string</big>
bold(): 输出结果 <b>string</b>
fixed() :输出结果 <tt>string</tt>
fontcolor(): 输出结果 <font color = “color” >string </font>
fontsize(): 输出结果 <font size= “size” >string </font>
italics(): 输出结果 <i>string</i>
link(url): 输出结果 <a herf = "url">string</a>
small(): 输出结果 <small>string</small>
strike(): 输出结果 <strike>string</strike>
sub(): 输出结果 <sub>string</sub>
sup(): 输出结果 <sup>string</sup>
九、Global 对象
所有全局定义的属性和方法都属于 Global 对象。
Global 对象有很多方法,比如isNaN()、isFinite()、parseInt() 以及 parseFloat() 方法。除此之外,Global 对象还包括其他一些方法。
1、Global 对象的几个方法
(1)、URI 编码方法
Global 对象通过 encodeURI() 和 encodeURIComponent() 方法可以对 URI(通用资源标识符)进行编码。与之相对的,Global 对象通过 decodeURI() 和 decodeURIComponent() 方法可以对 URI(通用资源标识符)进行解码。
--> encodeURI() 和 encodeURIComponent() 方法
有效的 URI 编码中不能包含某些字符,例如空格。encodeURI() 和 encodeURIComponent() 方法采用 UTF-8 编码替换所有无效的字符,从而让浏览器能够接受和理解。
- encodeURI() 方法能够对整个 URI(例如,青蛙king的博客_weixin79893765432..._CSDN博客-JavaScript,Vue.js,微信小程序领域博主)进行编码。encodeURI() 不会对本身属于 URI 的特殊字符进行编码,例如冒号、正斜杠、问号和井字号。
- encodeURIComponent() 方法能够对 URI 的某一段(例如前面 URI 中的 mChales_Liu)进行编码。encodeURIComponent() 会对它发现的任何非标准字符进行编码。
var uri = "https://blog.csdn.net/mChales Liu?charCode#enough.html";
console.log(encodeURI(uri)); // https://blog.csdn.net/mChales%20Liu?charCode#enough.html
console.log(encodeURIComponent(uri)); // https%3A%2F%2Fblog.csdn.net%2FmChales%20Liu%3FcharCode%23enough.html
上述代码,使用 encodeURI() 方法编码后的结果是只有空格被替换成了 %20,其他字符都原封不动。而使用 encodeURIComponent() 方法则会导致所有的非字母数字字符被对应的 UTF-8 编码替换了。
--> decodeURI() 和 decodeURIComponent() 方法
- decodeURI() 方法只能对 encodeURI() 方法替换的字符进行解码。
- decodeURIComponent() 方法只能对 encodeURIComponent() 方法替换的字符进行解码。
var uri = "https%3A%2F%2Fblog.csdn.net%2FmChales%20Liu%3FcharCode%23enough.html";
console.log(decodeURI(uri)); // https%3A%2F%2Fblog.csdn.net%2FmChales Liu%3FcharCode%23enough.html
console.log(decodeURIComponent(uri)); // https://blog.csdn.net/mChales Liu?charCode#enough.html
上述代码,使用decodeURI() 方法解码时只把 %20 变成了空格,其他字符原封不动。而使用decodeURIComponent() 方法则会把所有特殊字符的编码都替换成了原来的字符。
(2)、eval() 方法(了解)
- eval() 方法只接收1个参数:字符串。它会将传入的参数当做实际的 JavaScript 语句来解析,然后把执行结果插入到原位置。如果参数不是字符串,则直接返回该参数。
- eval() 方法的参数是一个对象(例如,{})时,对象声明语法“{}”并不能返回一个值,需要用括号括起来才会返回值。
- eval() 方法只能在非严格模式中进行使用,在use strict中是不允许使用这个方法的。
- 虽然 eval() 的功能非常强大,但在实际使用中用到它的情况并不多。
eval("console.log('hello')"); // "hello"
eval("function fn(a, b){ console.log(a + b); }");
fn(2, 3); // 5
2、Global 对象的属性
属性 | 说明 |
---|---|
undefined | 特殊值 undefined |
NaN | 特殊值 NaN |
Infinity | 特殊值 Infinity |
Object | 构造函数 Object |
Array | 构造函数 Array |
Function | 构造函数 Function |
Boolean | 构造函数 Boolean |
String | 构造函数 String |
Number | 构造函数 Number |
Date | 构造函数 Date |
RegExp | 构造函数 RegExp |
Error | 构造函数 Error |
EvalError | 构造函数 EvallError |
RangeError | 构造函数 RangeError |
ReferanceError | 构造函数 ReferenceError |
SyntaxError | 构造函数 SyntaxError |
TypeError | 构造函数 TypeError |
URIError | 构造函数 URIError |
3、Global 对象与 window 对象
JavaScript 中虽然没有指出如何才能直接访问 Global 对象,不过,Web 浏览器提供了一个 window 对象作为全局对象 Global 对象的实现。因此,全局作用域中声明的所有变量和方法(函数),都是 window 对象的属性。访问 window 对象就相当于访问了 Global 对象。
var color = "red";
function fn(){
alert(window.color);
}
window.fn(); // "red"
十、Math 对象
1、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的平方根 |
Math.SQRT2 | 2的平方根 |
2、Math 对象的方法
(1)、最小值和最大值——Math.min() 和 Math.max()
min() 和 max() 方法用于确定一组数值中的最小值和最大值。这两个方法都可以接收任意多个数值参数。
var max = Math.max(3, 54, 21, 16);
console.log(max); // 54
var min = Math.min(3, 54, 21, 16);
console.log(min); // 3
要找到数组中的最小值或最大值,可以借助 apply() 方法来实现:
var value = [3, 54, 21, 16];
var min = Math.min.apply(Math, value);
var max = Math.max.apply(Math, value);
console.log([min, max]); // [3, 54]
上述代码,关键是把 Math 对象作为 apply() 方法的第一个参数,从而正确地设置了 this 的值,然后,将任何数组作为 apply() 方法的第二个参数。
(2)、舍入方法(取整)
--> Math.ceil() 方法:向上舍入。
--> Math.round() 方法:标准舍入。
--> Math.floor() 方法:向下舍入。
console.log(Math.ceil(25.5)); // 26
console.log(Math.ceil(25.1)); // 26
console.log(Math.round(25.5)); // 26
console.log(Math.round(25.1)); // 25
console.log(Math.floor(25.5)); // 25
console.log(Math.floor(25.1)); // 25
(3)、取随机数——Math.random()
Math.random() 方法返回大于等于 0 小于 1 的一个随机数。
如何从某个整数范围内随机选取一个值?
值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能值)
例如:在 2 到 10 之间随机选取一个整数。
var num = Math.floor(Math.random() * 9 + 2);
(4)、Math 对象的其他方法
方法 | 说明 |
---|---|
Math.abs(num) | 返回 num 的绝对值 |
Math.exp(num) | 返回 Math.E 的 num 次幂 |
Math.log(num) | 返回 num 的自然对数 |
Math.pow(num, power) | 返回 num 的 power 次幂 |
Math. sqrt(num) | 返回 num 的平方根 |
Math.acos(x) | 返回 x 的反余弦值 |
Math.asin(x) | 返回 x 的反正弦值 |
Math.atan(x) | 返回 x 的反正切值 |
Math.atan2(y, x) | 返回 y/x 的反正切值 |
Math.cos(x) | 返回 x 的余弦值 |
Math.sin(x) | 返回 x 的正弦值 |
Math.tan(x) | 返回 x 的正切值 |
十一、ES6 引用类型的新特性
请戳这里:js ES6 引用类型的新特性_青蛙king的博客-CSDN博客