数组
splice
// 参数1: 从什么位置开始, 参数2: 需要替换多少个元素, 参数3开始: 新的内容
let arr = ["a", "b", "c"];
let arrtmp = arr.splice(1, 2, "d", "e");
arrtmp = ["b", "c"]
arr = ["a", "d", "e"]
unshift
在数组最前面添加一条数据,会将新增内容之后当前数组的长度返回
shift
删除数组最前面一条数据,并且将删除的数据返
pop
删除数组最后一条数据,并且将删除的数据返回
清空数组
arr = [];
arr.splice(0, arr.length)
数组转换为字符串
arr.toString();
arr.toLocaleString()
join
concat
reverse
let arr = [1, 2, 3, 4, 5]
arr.reverse() // [5, 4, 3, 2, 1]
slice
截取数组中指定范围内容,包头不包尾(包含起始位置, 不包含结束的位置)
let arr = [1, 2, 3, 4, 5]
let res = arr.slice(1, 3) // [2, 3]
indexOf
方法如果找到了指定的元素, 就会返回元素对应的位置;如果没有找到指定的元素, 就会返回-1;
let arr = [1, 2, 3, 4, 5]
arr.indexOf(3) // 4
findIndex
// findIndex方法: 定制版的indexOf, 找到返回索引, 找不到返回-1
let value = arr.findIndex(function (currentValue, currentIndex, currentArray) {
// 判断函数体,要返回值
});
Array.prototype.myFindIndex = function (fn) {
for(let i = 0; i < this.length; i++){
let result = fn(this[i], i, this);
if(result){
return i;
}
}
return -1;
}
let ages = [3, 10, 18, 20];
function checkAdult(age) {
return age >= 18;
}
ages.findIndex(checkAdult); // 2
find
// find方法需要传递一个回调函数,如果找到了就返回找到的元素, 如果找不到就返回undefined
let value = arr.find(function (currentValue, currentIndex, currentArray) {
// 判断函数体,要返回值具体数值,否则结果undefined
});
let ages = [3, 10, 18, 20];
function checkAdult(age) {
return age >= 18;
}
ages.find(checkAdult); // 18
// 自己实现
Array.prototype.myFind = function (fn) {
for(let i = 0; i < this.length; i++){
let result = fn(this[i], i, this);
if(result){
return this[i];
}
}
return undefined;
}
foreach
Array.prototype.myForEach = function (fn) {
for(let i = 0; i < this.length; i++){
fn(this[i], i, this);
}
};
let arr = [1, 3, 5, 7, 9];
arr.myForEach(function (currentValue, currentIndex, currentArray) {
console.log(currentValue, currentIndex, currentArray);
});
/*
1 0 Array(5)
3 1 Array(5)
5 2 Array(5)
7 3 Array(5)
9 4 Array(5)
*/
lastIndexOf
includes
let arr = [1, 2, 3, 4, 5]
let res = arr.includes(3); // true
filter
let arr = [1, 2, 3, 4, 5];
// 将满足条件的元素添加到一个新的数组中
let newArray = arr.filter(function (currentValue, currentIndex, currentArray) {
// console.log(currentValue, currentIndex, currentArray);
if(currentValue % 2 === 0){
return true;
}
});
console.log(newArray); // [2, 4]
// 手写filter
Array.prototype.myFilter = function (fn) {
let newArray = [];
for(let i = 0; i < this.length; i++){
let result = fn(this[i], i, this);
if(result){
newArray.push(this[i]);
}
}
return newArray;
}
map
let arr = [1, 2, 3, 4, 5];
// 将满足条件的元素映射到一个新的数组中
let newArray = arr.map(function (currentValue, currentIndex, currentArray) {
// console.log(currentValue, currentIndex, currentArray);
if(currentValue % 2 === 0){
return currentValue;
}
});
console.log(newArray); // [undefined, 2, undefined, 4, undefined]
// 手写map
Array.prototype.myMap = function(fn) {
let newArray = new Array(this.length);
newArray.fill(undefined);
for (let i = 0; i < this.length; ++i) {
let result = fn(this[i], i, this)
if (result !== undefined) {
tmpArr.push(result)
}
}
return newArray
}
let arr = [1,2,3,4]
let resultArr = arr.myMap((item) => {
return item % 2
})
console.log(resultArr) // [1, undefined, 1, undefined]
sort
小的排前面:
如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。
如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前
注意点: 如果元素是字符串类型, 那么比较的是字符串的Unicode编码
arr.sort(function (a, b) {
if(a > b){
return -1;
}else if(a < b){
return 1;
}else{
return 0;
}
// 规律: 如果数组中的元素是数值类型
// 如果需要升序排序, 那么就返回a - b;
// 如果需要降序排序, 那么就返回b - a;
// return a - b;
// return b - a;
});
let arr = ["1234", "21", "54321", "123", "6"];
arr.sort(function (str1, str2) {
return str2.length - str1.length;
});
console.log(arr); // ["54321", "1234", "123", "21", "6"]
// 原理
function sort(arr, fn) {
for (var i = 0; i < arr.length - 1; i++) {
for (var j = 0; j < arr.length - 1 - i; j++) {
if (fn(arr[j], arr[j + 1]) > 0) {
var temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
}
}
}
return arr
}
var arr = [6, 64, 5, 1, 8]
console.log(
// 形参,传递函数
sort(arr, function (a, b) {
return b - a
})
) // [ 64, 8, 6, 5, 1 ]
reduce
let arr = [1, 3, 5];
let res = arr.reduce(function (initValue, curValue, curIndex, arrValue) {
console.log(initValue, curValue, curIndex, arrValue);
return initValue + curValue;
}, 100);
console.log(res);
/*
100 1 0 [1, 3, 5]
101 3 1 [1, 3, 5]
104 5 2 [1, 3, 5]
109
*/
字符串
slice
let str = "abcdef";
let subStr = str.slice(1, 3); // bc
substring
let str = "abcdef";
let subStr = str.substring(1, 3); // bcd
substr
let str = "abcdef";
let subStr = str.substr(1, 3); // bcd
split
let str = "1-3-5";
let arr = str.split("-"); // ["1", "3", "5"]
join
let arr = [1, 3, 5];
let str = arr.join("-"); // "1-3-5"
endsWith
// 判断是否以指定字符串结尾 ES6
let str = "meihao.jpg";
let result = str.endsWith("png"); // false
类型
基本类型:字符串类型string / 数值类型number / 布尔类型boolean / 空类型null / 未定义类型undefined
引用类型:Object
三大对象
"本地对象"/"内置对象"/"宿主对象"
宿主:宿主就是指JavaScript运行环境, js可以在浏览器中运行, 也可以在服务器上运行(nodejs)。
本地对象
与宿主无关,无论在浏览器还是服务器中都有的对象,就是ECMAScript标准中定义的类(构造函数)。在使用过程中需要我们手动new创建;例如:Boolean、Number、String、Array、Function、Object、Date、RegExp
等。
内置对象
与宿主无关,无论在浏览器还是服务器中都有的对象,ECMAScript已经帮我们创建好的对象。在使用过程中无需我们手动new创建;例如:Global(encodeUR,encodeURLComponent)、Math、JSON
。
宿主对象
对于嵌入到网页中的JS来说,其宿主对象就是浏览器, 所以宿主对象就是浏览器提供的对象,包含: Window和Document等。所有的DOM和BOM对象都属于宿主对象。
函数
默认值
function getSum(a = "hello", b = getDefault()) {
console.log(a, b); // hello world
}
getSum();
function getDefault() {
return "world"
}
作用域链
全局作用域称之为0级作用域, 定义函数开启的作用域就是1级/2级/3级/...作用域, JavaScript会将这些作用域链接在一起形成一个链条, 这个链条就是作用域链.
0 ---> 1 ----> 2 ----> 3 ----> 4
变量在作用域链查找规则: 先在当前找, 找到就使用当前作用域找到的; 如果当前作用域中没有找到, 就去上一级作用域中查找; 以此类推直到0级为止, 如果0级作用域还没找到, 就报错.
预解析
浏览器在执行JS代码的时候会分成两部分操作:预解析以及逐行执行代码
浏览器不会直接执行代码, 而是加工处理之后再执行; 这个加工处理的过程, 我们就称之为预解析.
预解析规则
将变量声明和函数声明提升到当前作用域最前面,将剩余代码按照书写顺序依次放到后面。通过let定义的变量不会被提升(不会被预解析)。
工厂函数
工厂函数就是专门用于创建对象的函数, 我们就称之为工厂函数。
let obj = {
name: "zs",
age: 44,
say: function () {
console.log("hello world");
}
};
function createPerson(myName, myAge) {
let obj = new Object();
obj.name = myName;
obj.age = myAge;
obj.say = function () {
console.log("hello world");
}
return obj;
}
let obj1 = createPerson("zs", 44);
构造函数
function Person() {
// let obj = new Object(); // 系统自动添加的
// let this = obj; // 系统自动添加的
this.name = arguments[0];
this.age = arguments[1];
this.say = function () {
console.log("hello world");
}
// return this; // 系统自动添加的
}
/*
1.当我们new Person("zs", 34);系统做了什么事情
1.1会在构造函数中自动创建一个对象
1.2会自动将刚才创建的对象赋值给this
1.3会在构造函数的最后自动添加return this;
*/
let obj1 = new Person("zs", 34); // 创建对象所有属性都是单独拷贝一份,会导致构造函数里面的方法有多个拷贝
function Person() {
this.name = arguments[0]
this.age = arguments[1]
}
Person.prototype = {
say: function() {
console.log('say')
}
}
let obj = new Person('zs', 12)
console.log(obj)
prototype
特点:
1 存储在prototype中的方法可以被对应构造函数创建出来的所有对象共享
2 prototype中除了可以存储方法以外, 还可以存储属性
3 prototype如果出现了和构造函数中同名的属性或者方法, 对象在访问的时候, 访问到的是构造函中的数据
prototype中一般情况下用于存储所有对象都相同的一些属性以及方法, 如果是对象特有的属性或者方法, 要存储到构造函数中
1.每个"构造函数"中都有一个默认的属性, 叫做prototype, prototype属性保存着一个对象, 这个对象我们称之为"原型对象".
2.每个"原型对象"中都有一个默认的属性, 叫做constructor, constructor指向当前原型对象对应的那个"构造函数".
3.通过构造函数创建出来的对象我们称之为"实例对象", 每个"实例对象"中都有一个默认的属性, 叫做__proto__, __proto__指向创建它的那个构造函数的"原型对象".
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
let obj1 = new Person("zs", 18);
console.log(Person.prototype);
console.log(Person.prototype.constructor);
console.log(Person.constructor.name);
Function函数
1.JavaScript中函数是引用类型(对象类型), 既然是对象,
所以也是通过构造函数创建出来 有prototype属性
"Function函数"的prototype属性指向"Function原型对象"
3.JavaScript中只要"原型对象"就有constructor属性
"Function原型对象"的constructor指向它对应的构造函数
4.Person构造函数是Function构造函数的实例对象, 所以也有__proto__属性
Person构造函数的__proto__属性指向"Function原型对象"
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
let obj1 = new Person("lnj", 34);
console.log(Function);
console.log(Function.prototype);
console.log(Function.prototype.constructor);
console.log(Function === Function.prototype.constructor); // true
console.log(Person.__proto__);
console.log(Person.__proto__ === Function.prototype); // true
Object函数
1. JavaScript函数是引用类型(对象类型), 所以Function函数也是对象
2. "Function构造函数"也是一个对象, 所以也有__proto__属性,"Function构造函数"__proto__属性指向"Function原型对象"。
3. JavaScript中还有一个系统提供的构造函数叫做Object,只要是函数都是"Function构造函数"的实例对象。
4. 只要是对象就有__proto__属性, 所以"Object构造函数"也有__proto__属性,"Object构造函数"的__proto__属性指向创建它那个构造函数的"原型对象"。
5. 只要是构造函数都有一个默认的属性,叫做prototype,prototype属性保存着一个对象,这个对象我们称之为"原型对象"
6. 只要是原型对象都有一个默认的属性, 叫做constructor,constructor指向当前原型对象对应的那个"构造函数"。
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
let obj1 = new Person("lnj", 34);
console.log(Function.__proto__); // ƒ () { [native code] }
console.log(Function.__proto__ === Function.prototype); // true
console.log(Object); // ƒ Object() { [native code] }
console.log(Object.__proto__); // ƒ () { [native code] }
console.log(Object.__proto__ === Function.prototype); // true
console.log(Object.prototype); // Object
console.log(Object.prototype.constructor); // ƒ Object() { [native code] }
console.log(Object.prototype.constructor === Object); // true
console.log(Object.prototype.__proto__); // null
原型链
1.对象中__proto__组成的链条我们称之为原型链.
2.对象在查找属性和方法的时候, 会先在当前对象查找; 如果当前对象中找不到想要的, 会依次去上一级原型对象中查找; 如果找到Object原型对象都没有找到, 就会报错.
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
Person.prototype = {
// 注意点: 为了不破坏原有的关系, 在给prototype赋值的时候, 需要在自定义的对象中手动的添加constructor属性, 手动的指定需要指向谁
constructor: Person,
}
let obj1 = new Person("zs", 34);
bind-call-apply
bind方法作用
修改函数或者方法中的this为指定的对象, 并且会返回一个修改之后的新函数给我们
注意点: bind方法除了可以修改this以外, 还可以传递参数, 只不过参数必须写在this对象的后面
call方法作用
修改函数或者方法中的this为指定的对象, 并且会立即调用修改之后的函数
注意点: call方法除了可以修改this以外, 还可以传递参数, 只不过参数必须写在this对象的后面
apply方法作用
修改函数或者方法中的this为指定的对象, 并且会立即调用修改之后的函数
注意点: apply方法除了可以修改this以外, 还可以传递参数, 只不过参数必须通过数组的方式传递
继承
function Person(name, age) {
this.name = name
this.age = age
}
function Student(name, age, score) {
this.score = score
Person.call(this, name, age, score)
}
let stu = new Student('zs', 18, 100)
console.log(stu) // Student {score: 100, name: "zs", age: 18}
Class
function Person(myName, myAge) {
// 实例属性
this.name = myName;
this.age = myAge;
// 实例方法
this.say = function () {
console.log(this.name, this.age);
}
// 静态属性
Person.num = 666;
// 静态方法
Person.run = function () {
console.log("run");
}
}
let p = new Person("zs", 18);
p.say();
console.log(p); // Person {name: "zs", age: 18, say: ƒ}
console.log(Person.num) // 666
// es6开始有了class
class Person{
// 当我们通过new创建对象的时候, 系统会自动调用构造函数constructor
// 实例属性
constructor(myName, myAge){
this.name = myName;
this.age = myAge;
}
// 实例方法
say(){
console.log(this.name, this.age);
}
// 静态属性
static num = 666;
// 静态方法
static run() {
console.log("run");
}
}
let p = new Person("zs", 18);
Person.run();
class Person{
constructor(myName, myAge){
this.name = myName;
this.age = myAge;
this.hi = function () {
console.log("hi");
}
}
run(){
console.log("run");
}
}
Person.prototype.type = "人";
Person.prototype.say = function () {
console.log(this.name, this.age);
};
let p = new Person("zs", 34);
console.log(p.__proto__) // {type: "人", say: ƒ, constructor: ƒ, run: ƒ}
继承 extends
class Person{
constructor(myName, myAge){
// this = stu;
this.name = myName; // stu.name = myName;
this.age = myAge; // stu.age = myAge;
}
say(){
console.log(this.name, this.age);
}
}
/*
1 在子类后面添加extends并指定父类的名称
2 在子类的constructor构造函数中通过super方法借助父类的构造函数
*/
class Student extends Person{
constructor(myName, myAge, myScore){
// 相当于在子类中通过call/apply方法借助父类的构造函数
// Person.call(this, myName, myAge);
super(myName, myAge);
this.score = myScore;
}
study(){
console.log("day day up");
}
}
let stu = new Student("zs", 18, 98);
stu.say(); // zs 18
class Person{
constructor(name, age) {
this.name = name
this.age = age
}
say() {
console.log(this.name, this.age)
}
}
class Student extends Person{
constructor(name, age, score) {
super(name, age)
this.score = score
}
run() {
console.log('run')
}
}
let stu = new Student('zs', 18, 90)
stu.say() // zs 18
typeof
获取对象类型
typeof new Object() // object
let p = new Person();
p.constructor.name // Person
typeof p // object
instanceof
instanceof
用于判断 "对象" 是否是指定构造函数的 "实例", 只要构造函数的原型对象出现在实例对象的原型链中都会返回true。
function Person(myName) {
this.name = myName;
}
function Student(myName, myScore) {
Person.call(this, myName);
this.score = myScore;
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
let stu = new Student();
console.log(stu instanceof Person); // true
isPrototypeOf
isPrototypeOf
用于判断 一个对象是否是另一个对象的原型,只要调用者在传入对象的原型链上都会返回true。
function Person(myName) {
this.name = myName;
}
function Student(myName, myScore) {
Person.call(this, myName);
this.score = myScore;
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
let stu = new Student();
console.log(Person.prototype.isPrototypeOf(stu)); // true
hasOwnProperty
判断某一个对象是否拥有某一个属性,只会在当前对象中查找, 不会去原型对象中查找
class Person{
name = null;
age = 0;
}
Person.prototype.height = 0;
let p = new Person();
// in的特点: 只要类中或者原型对象中有, 就会返回true
console.log("name" in p); // true
console.log("width" in p); // false
console.log("height" in p); // true
// 特点: 只会去类中查找有没有, 不会去原型对象中查找
console.log(p.hasOwnProperty("name")); // true
console.log(p.hasOwnProperty("height")); // false
深拷贝
function depCopy(target, source) {
for(let key in source){
let sourceValue = source[key];
if(sourceValue instanceof Object){
let subTarget = new sourceValue.constructor;
target[key] = subTarget;
depCopy(subTarget, sourceValue);
}else{
target[key] = sourceValue;
}
}
}
遍历
for(let value of arr){
console.log(value);
}
for(let key in arr){ // 遍历无需对象,不要用来遍历数组
console.log(arr[key]);
}
// forEach方法会自动调用传入的函数,每次调用都会将当前遍历到的元素和当前遍历到的索引和当前被遍历的数组传递给这个函数
arr.forEach(function (currentValue, currentIndex, currentArray) {
console.log(currentValue, currentIndex, currentArray);
});