一、JS 检测对象类型
1. typeof
- 一般用做区分基本数据类型
typeof 0; //number;
typeof true; //boolean;
typeof undefined; //undefined;
typeof "hello world" //string;
typeof function(){}; //function;
typeof null; //object
typeof {}; //object;
typeof []; //object
2. Object.prototype.toString.call
console.log(Object.prototype.toString.call(new Date)) // [object Date]
console.log(Object.prototype.toString.call(JSON)) // [object JSON]
console.log(Object.prototype.toString.call(Math)) // [object Math]
console.log(Object.prototype.toString.call(new f)) // [object Object]
console.log(Object.prototype.toString.call(f)) // [object Function]
要拿到一个对象的类型字符串,可以这么写:
function type(obj) { return Object.prototype.toString.call(obj).slice(8, -1)}
console.log(type(new Date)); // Date
1和2混用检测
function ifType(val){
let type = typeof val;
if (type !== "object") { // 先进行typeof判断,如果是基础数据类型,直接返回
return type;
}
// 对于typeof返回结果是object的,再进行如下的判断,正则返回结果
return Object.prototype.toString.call(obj).slice(8, -1);
}
3. instanceof
- 一般用来判断数组和对象,无法检测基本数据类型
- new 一个对象,那么这个新对象就是它原型链继承上面的对象了,通过 instanceof 我们能判断这个对象是否是之前那个构造函数生成的对象,这样就基本可以判断出这个新对象的数据类型
var o = { };
var a = ['reg','blue'];
o instanceof Object; // true
o instanceof Array; // false
a instanceof Array; // true
a instanceof Object; // true
let Fn = function () { }
let gs = new Fn()
console.log(gs instanceof Fn); // true
let gcs = new String('Mercedes Gs')
console.log(gcs instanceof String); // true
let str = 'string'
console.log(str instanceof String); // false
手写instanceof
思路分析:
function A() {} var a = new A() console.log(a.__proto__ === A.prototype); // true
- 基本类型直接false
- a._proto_ === A.prototype // true 直接返回 true
- 如果是原型对象没有 while再向原型链想上找 直到null 没有返回false
function myInstanceOf(obj, fn) {
// 基本类型直接false
if (!['function', 'object'].includes(typeof obj) || obj === null) {
return false
}
let objProto = obj.__proto__, fnPrototype = fn.prototype
while (objProto !== fnPrototype) {
// 再到原型对象(fnPrototype)向上的原型链去找 直到null
objProto = objProto.__proto__
if (objProto === null) {
return false
}
}
return true
}
// 测试代码
var a = ['reg', 'blue'];
a instanceof Array; // true
a instanceof Object; // true
console.log(myInstanceOf(a, Array)); // true
console.log(myInstanceOf(a, Object)); // true
4. constructor
- 除了 null 和 undefined,
constructor
可以正确检测出原始类型和对象(引用)类型。- 由于我们可以随意修改
constructor
导致检测结果不准确,所以这种方法是不安全的。
let num = 1
let str = "123"
let bool = false
let arr = [1, 2, 3]
let obj = { name: '张三', age: 22 }
let fn = function () { }
console.log(num.constructor === Number)
console.log(str.constructor === String)
console.log(bool.constructor === Boolean)
console.log(arr.constructor === Array)
console.log(obj.constructor === Object)
console.log(fn.constructor === Function)
String.prototype.constructor = 'aaa'
console.log(str.constructor === String)
二、字符串常用方法
- 获取字符串长度 length
1. 获取字符串指定位置的值
charAt()和charCodeAt()
//charAt 返回指定字符,下标超出范围返回空字符串。 不改变原字符串 参数:下标默认0
const str = 'hello';
console.log(str.charAt(2)); // ? l
console.log(typeof str.charAt(5)); // ? 空字符串
//charCodeAt 返回指定字符的ASCII十进制码
const str = 'hello';
console.log(str.charCodeAt(2)); // ? 108
console.log(str.charCodeAt(5)); // ? NAN
2. 检索字符串是否包含特定序列
2.1 indexOf和lastIndexOf
- indexOf和lastIndexOf 查看字符串是否包含给定的字符串,有返回出现的下标 没有返回-1
- 不管从前往后还是从后往前检索下标始终从左往右
- 参数①检索的val(必传)参数② 从哪开始(可选)
- 参数②取负数都从下标0开始
- indexOf 返回第一次出现的下标;lastIndexOf 返回最后一次出现的下标
- lastIndexOf给参数②则从右向左检索
'Blue Whale'.indexOf('Blue') // 返回 0
'Blue Whale'.indexOf('Blute') // 返回 -1
'Blue Whale'.indexOf('Whale', 0) // 返回 5
'Blue Whale'.indexOf('Whale', 5) // 返回 5
'Blue Whale'.indexOf('Whale', 7) // 返回 -1
'Blue Whale'.indexOf('Whale', -3) // 返回 5
'canal'.lastIndexOf('a'); // 3
'canal'.lastIndexOf('a', 2); // 1
'canal'.lastIndexOf('a', 0); // -1
'canal'.lastIndexOf('x'); // -1
'canal'.lastIndexOf('c', -5); // 0
'canal'.lastIndexOf('c', 0); // 0
2.2 includes
- includes 是否包含子串 返回布尔值 不改变原字符串
- 参数①要查找的字符串; 参数②从那个位置开始查找,默认为 0
const str = "To be, or not to be, that is the question.";
console.log(str.includes("To be")); // true
console.log(str.includes("question")); // true
console.log(str.includes("nonexistent")); // false
console.log(str.includes("To be", 1)); // false
console.log(str.includes("TO BE")); // false
console.log(str.includes("")); // true
2.3 startsWith和endsWith
- startsWith和endsWith 查看是否以给定的字串开头或结尾 返回布尔值 不改变原字符串
- startsWith 参数② 从哪里开始默认0
- endsWith 参数② 到哪里结束
var str = "To be, or not to be, that is the question.";
alert(str.startsWith("To be")); // true
alert(str.startsWith("not to be")); // false
alert(str.startsWith("not to be", 10)); // true
alert(str.startsWith("be", 3)) // true
var str = "To be, or not to be, that is the question.";
alert(str.endsWith("question.")); // true
alert(str.endsWith("to be")); // false
alert(str.endsWith("to be", 19)); // true
alert(str.endsWith("be", 5)); // true
3. 字符串的拼接concat
- 参数可以是多个要拼接的字符串逗号隔开,也可是一个数组
- + 也可以拼接字符串
let hello = 'Hello, '
console.log(hello.concat('Kevin', '. Have a nice day.'))
// Hello, Kevin. Have a nice day.
let greetList = ['Hello', ' ', 'Venkat', '!']
"".concat(...greetList) // "Hello Venkat!"
"".concat({}) // [object Object]
"".concat([]) // ""
"".concat(null) // "null"
"".concat(true) // "true"
"".concat(4, 5) // "45"
4. 字符串截取
4.1 slice
- 截取字符串的一部分, 返回新字符串,不改变原字符串
- 包含起始不包含结束索引的元素
var str1 = 'The morning is upon us.', // str1 的长度 length 是 23。
str2 = str1.slice(1, 8),
str3 = str1.slice(4, -2),
str4 = str1.slice(12),
str5 = str1.slice(30);
console.log(str2); // 输出:he morn
console.log(str3); // 输出:morning is upon u
console.log(str4); // 输出:is upon us.
console.log(str5); // 输出:""
var str = 'The morning is upon us.';
str.slice(-3); // 返回 'us.'
str.slice(-3, -1); // 返回 'us'
str.slice(0, -1); // 返回 'The morning is upon us'
4.2 substring
- 包含起始不包含结束索引的元素
- 如果
indexStart
等于indexEnd
,substring
返回一个空字符串。- 如果省略
indexEnd
,substring
提取字符一直到字符串末尾。
let str = 'Mozilla';
console.log(str.substring(0, 3)); //Moz
console.log(str.substring(1,1)); // ''
console.log(str.substring()); // Mozilla
console.log(str.substring(3,0)); //Moz
4.3 substr
- 截取字符串的一部分, 返回新字符串,不改变原字符串
- 参数①
indexStart
参数②需要截取的个数
var str = "abcdefghij";
console.log("(1,2): " + str.substr(1,2)); // (1,2): bc
console.log("(-3,2): " + str.substr(-3,2)); // (-3,2): hi
console.log("(-3): " + str.substr(-3)); // (-3): hij
console.log("(1): " + str.substr(1)); // (1): bcdefghij
console.log("(-20, 2): " + str.substr(-20,2)); // (-20, 2): ab
console.log("(20, 2): " + str.substr(20,2)); // (20, 2):
5. 字符串替换replace和replaceAll
- 返回替换后的字符串 不改变原字符串
let text = 'cat , bat , sat , fat';
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
console.log('aabbcc'.replaceAll('b', '.')); // aa..cc
6. 字符串分割成数组split
- 参数① 以啥分割 ; 参数② 分割返回元素个数
let color = 'red,blue,yellow,black';
let color1 = color.split(',');
console.log(color1); // ['red', 'blue', 'yellow', 'black']
let color2 = color.split(',', 2);
console.log( color2); // ['red', 'blue']
7. 大小写转换
toLowerCase
大->小toUpperCase
小->大
// console.log('a2c'.toUpperCase()); // A2C
// console.log('D5F'.toLowerCase()); // d5f
8. 去除空格
trim(两端) || trimStart(开头) || trimEnd(末端) 返回新串
let str1 = " aoo ";
let str2 = " boo ";
let str3 = " coo ";
console.log(str1.trim().length); // 3
console.log(str2.trimStart().length); // 4
console.log(str3.trimEnd().length); // 4
三、数组常用方法
1. 元素插入
array.push()
: 末尾添加元素,返回新数组的长度,改变原数组array.unshift()
: 头部添加元素,返回新数组的长度,改变原数组array.splice()
: 任意位置添加元素,返回新数组,改变原数组
splice方法增加元素 参数①插入的位置
;参数②必须是0
;参数③插入的元素
var arr = [1, 2, 3];
var res = arr.push(6, 7, 8);
console.log(res); // ? 6
console.log(arr); // ? [1, 2, 3, 6, 7, 8]
var arr = [1, 2, 3];
var res = arr.unshift(6, 7, 8);
console.log(res); // ? 6
console.log(arr); // ? [6, 7, 8, 1, 2, 3]
var arr = [1, 2, 3, 4, 5, 6, 7];
var res = arr.splice(2, 0, 8, 9);
// var res = arr.splice(2, 0, ...[8, 9]);
console.log(res); // ? []
console.log(arr); // ? [1, 2, 8, 9, 3, 4, 5, 6, 7]
2. 元素删除
array.pop()
: 末尾删除元素,返回被删除的元素,改变原数组array.shift()
: 头部删除元素,返回被删除的元素,改变原数组array.splice()
: 任意删除元素,返回被删除的元素数组,改变原数组
var arr = [1, 2, 3];
var res = arr.pop();
console.log(res); // ? 3
console.log(arr); // ? [1, 2]
var arr = [1, 2, 3];
var res = arr.shift();
console.log(res); // ? 1
console.log(arr); // ? [2, 3]
var res = arr.splice(1); // 只传第一个参数,表示删除的起点 删除的元素包含开始下标元素,到最后一个元素
console.log(res); // ? [2, 3, 4, 5, 6, 7]
console.log(arr); // ? [1]
var res = arr.splice(2, 3); // 两个参数, 从第几个开始删,包含起始元素,第二个参数是删除几个
console.log(res); // ? [3, 4, 5]
console.log(arr); // ? [1, 2, 6, 7]
3. 数组的拼接concat
var arr = [1, 2, 3];
var res = arr.concat(1, [0, 0]); // 多个任意项,可以是数组,可以是单个项
console.log(res); // ? [1, 2, 3, 1, 0, 0]
console.log(arr); // ? [1, 2, 3]
4. 数组的截取slice
- 返回截取的子数组,不改变原数组
- 参数①开始下标,结束下标,返回的数组 [...)
var arr = [1, 2, 3, 6, 7, 8];
var res = arr.slice(1, 4);
console.log(res); // ? [2, 3, 6]
console.log(arr); // ? [1, 2, 3, 6, 7, 8]
5. 查找数组
(1) includes
- 查找数组中是否包含某个元素,返回布尔值,不改变原数组
- 参数①必传,表示要查询的元素,
- 参数②可选,表示从指定位置查起(若为负数,从后查起,负数超过数组长度,则置为 0)
var arr = [1, 2, 3];
var res = arr.includes(2);
console.log(res); // true
console.log(arr); // [1, 2, 3]
(2) find
- 返回满足条件的第一个元素,不再向下查找,没满足条件的返回undefined 不改变原数组
- 参数: callback:function(item, index, array){})
const found = array.find(element => element > 10);
console.log(found); // ? 12
console.log(array); // ? [5, 12, 8, 130, 44]
(3) findIndex
- 返回满足条件的第一个元素的索引,不在向下查找,没满足条件的返回-1 不改变原数组
- 参数: callback:function(item, index, array){})
const array = [5, 12, 8, 130, 44];
const found = array.findIndex(element => element > 10);
console.log(found); // ? 1
console.log(array); // ? [5, 12, 8, 130, 44]
6. 清空数组
- array.length 为 0
- array.splice(0)
- array = []
const colors = ['blue', 'green', 'black'];
colors.length = 0;
colors; // []
const colors = ['blue', 'green', 'black'];
colors.splice(0);
colors; // []
const colors = ['blue', 'green', 'black'];
colors = [];
colors; // []
7. 数组翻转(改变原数组)
var arr = [1, 2, 3, 3, 4, 5, 5, 7, 9]
console.log(arr.reverse()) // ? [9, 7, 5, 5, 4, 3, 3, 2, 1]
console.log(arr) // ? [9, 7, 5, 5, 4, 3, 3, 2, 1]
7. sort(改变原数组)
callback:(a, b) => a - b 口诀: a-b升,b-a降
var arr = [1, 3, 9, 2, 5, 3, 7, 4, 5];
var res1 = arr.sort((a, b) => a - b);
console.log(res1) // ? [1, 2, 3, 3, 4, 5, 5, 7, 9]
var res2 = arr.sort((a, b) => b - a);
console.log(res2) // ? [9, 7, 5, 5, 4, 3, 3, 2, 1]
console.log(arr) // ? [9, 7, 5, 5, 4, 3, 3, 2, 1]
8. join
将数组的所有元素连成一个指定分隔符的
字符串
并返回,不改变原数组
var arr = [1, 2, 3, 3, 4, 5, 5, 7, 9];
console.log(arr.join('-')); // ? '1-2-3-3-4-5-5-7-9'
console.log(arr); // [1, 2, 3, 3, 4, 5, 5, 7, 9]
9. 数组的遍历
(1) for
var arr = [1, 2, 3];
for (let i = 0; i < arr.length; i++) {
// ...
console.log("continue 打断当次循环,进入下次循环");
console.log("break 直接打断循环,跳出循环");
}
(2) forEach (改变元素组)
const array1 = ['a', 'b', 'c'];
array1.forEach((item, index) => console.log(item, index));
(3) for..of
const colors = ['blue', 'green', 'white'];
for (const color of colors) {
console.log(color);
}
(4) map
- 创建由callback返回值组成的新数组,不改变原数组
const array1 = [1, 4, 9, 16];
const map1 = array1.map(x => {
if (x > 4) {
return x * 2
}
return x
});
console.log(map1); // ? [1, 4, 18, 32]
console.log(array1); // ? [1, 4, 9, 16]
(5) Array.from()
let arr = [2, 4, 6];
const result = Array.from(arr, (item) => {
return item * 2
})
console.log(result); // [4, 8, 12]
console.log(arr); // [2, 4, 6]
(6) filter 过滤(不改变原数组)
let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let res = nums.filter(num => num >5);
console.log(res); // [6, 7, 8, 9, 10]
(7) every 不改变原数组
每一个元素是否都满足callback的筛选条件,返回布尔值
let arr = [1, 2, 3, 4, 5]
console.log(arr.every((item, index, array) => item > 3)) // ? false
(8) some 不改变原数组
数组中是否有一个满足callback的筛选条件,返回布尔值
let arr = [1, 2, 3, 4, 5]
console.log(arr.every((item, index, array) => item > 3)) // ? true
(9) reduce 累计相关的数组处理
- 参数①:callback(初始值,当前值,当前索引),
- 参数②可选: 给定初始值,如果不给 处理的数组第一个元素为初始值,当前索引从1开始
// 1. 数组求和
let sum = [0, 1, 2, 3].reduce((accumulator, currentValue) => {
return accumulator + currentValue;
}, 0);
console.log(sum); // ? 6
// 2. 数组去重
let arr = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd'];
let newArr = arr.reduce((acc, current) => {
if (!acc.includes(current)) {
acc.push(current);
}
return acc;
}, []);
console.log(newArr); // ? ['a', 'b', 'c', 'e', 'd']
// 3. 数组扁平化
let flat = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
].reduce((prev, cur, index, array) => {
return [...prev, ...cur];
});
console.log(flat); // [1, 2, 3, 4, 5, 6, 7, 8]
(10) fill 数组填充 改变原数组
- 参数:①填充固定值、②起始位、③终止位
- 填充范围填充给定的值,包含起始位不包含截止位
let arr = [1, 2, 3, 4]
console.log(arr.fill(-1, 1, 3)); // [1, -1, -1, 4]
// 多用于创建指定长度的空数组填充
// let arr1 = new Array(3)
// arr1.fill(1) // arr1 = [1, 1, 1]
Array.from
const emptyObjects = Array.from(Array(4), function () {
return {};
});
console.log(emptyObjects);; // [{}, {}, {}, {}]
(11) flat数组扁平化
用于扁平化数组或去除空项,返回新数组,不改变原数组
let arr1 = [1, 2, [3, 4]];
newArr1 = arr1.flat();
console.log(newArr1); // ? [1, 2, 3, 4]
//使用 Infinity,可展开任意深度的嵌套数组
// let arr3 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
// newArr3 = arr3.flat(Infinity);
// console.log(arr3, newArr3); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 去除空项
let arr4 = [1, 2, , 4, 5];
newArr4 = arr4.flat();
console.log(arr4, newArr4); // ? [1, 2, empty, 4, 5] (4) [1, 2, 4, 5]
四、对象常用方法
1. Object.create()
创建对象
创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。 它接收两个参数,不过第二个可选参数是属性描述符(不常用,默认是
undefined
)。
var anotherObject = {
name: '小明'
};
var myObject = Object.create(anotherObject, {
age: {
value:18,
},
});
// 获得它的原型
Object.getPrototypeOf(anotherObject) === Object.prototype; // true 说明anotherObject的原型是Object.prototype
Object.getPrototypeOf(myObject); // {name: "小明"} // 说明myObject的原型是{name: "若川"}
myObject.hasOwnProperty('name'); // false; 说明name是原型上的。
myObject.hasOwnProperty('age'); // true 说明age是自身的
myObject.name; // '小明'
myObject.age; // 18;
1. Object.assign()
合并对象
- Object.assign(target, ...sources)
target: 接收源对象属性的对象,也是修改后的返回值 sources: 源对象,包含将被合并的属性。
注意: 如果源对象
和目标对象
存在相同
属性,则源对象覆盖目标对象
属性
// 对象的浅拷贝
const obj = { a: 1 };
const copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
// 对象的合并
let target = { name: 'nike', age: '20' }
let source = { address: '郑州', gender: '男', name: 'LLL' }
Object.assign(target, source)
console.log(target) //{name: 'LLL', age: '20', address: '郑州', gender: '男'}
2. hasOwnProperty() 判断自身是否包含检测属性
- obj.hasOwnProperty(prop)
o = new Object();
o.hasOwnProperty('prop'); // 返回 false
o.prop = 'exists';
o.hasOwnProperty('prop'); // 返回 true
delete o.prop;
o.hasOwnProperty('prop'); // 返回 false
3. getOwnPropertyNames() 获取自身所有的属性
- Object.getOwnPropertyNames(obj)
var obj = { name: '张三', age: 18 }
console.log(Object.getOwnPropertyNames(obj));
4. Object.getPrototypeOf() 获取指定对象的原型
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
var point = new Point(2, 3);
console.log(point.__proto__); //{constructor: ƒ, toString: ƒ}
console.log(Object.getPrototypeOf(point)); //{constructor: ƒ, toString: ƒ}
5. Object.freeze() 冻结对象
- 不能添加新属性
- 不能删除已有属性
- 不能修改已有属性的值
- 不能修改原型
- 不能修改已有属性的可枚举性、可配置性、可写性
var obj = {
name: '张三',
age: 18,
address: '上海市'
}
obj.__proto__.habit = '运动'
// 冻结对象
Object.freeze(obj)
// 不能添加新属性
obj.sex = '男'
console.log(obj) // {name: "张三", age: 18, address: "上海市"}
// 不能删除原有属性
delete obj.age
console.log(obj) // {name: "张三", age: 18, address: "上海市"}
// 不能修改已有属性的值
obj.name = '李四'
console.log(obj) // {name: "张三", age: 18, address: "上海市"}
// 不能修改原型
obj.__proto__ = '随便什么值'
console.log(obj.__proto__) // {habit: "运动", constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, …}
// 不能修改已有属性的可枚举性、可配置性、可写性
Object.defineProperty(obj, 'address', { // TypeError: Cannot redefine property: address
enumerable: false,
configurable: false,
writable: true
})