亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

JS高級知識入門教程

概述

本文深入探讨了JS高级数据类型与对象,包括基本类型和引用类型的详细解释及操作示例。文章进一步介绍了JS高级函数特性,如闭包、高阶函数及Promise与async/await的使用。此外,还涵盖了面向对象编程、调试与错误处理以及异步编程的相关知识,旨在全面提高对JS高级知识的理解和应用。

JS高级数据类型与对象

JS中的基本数据类型与引用类型

在JavaScript中,数据可以分为两种类型:基本类型和引用类型。基本类型包括NumberStringBooleanNullUndefinedSymbol,引用类型则是Object,包括数组(Array)、日期(Date)、函数(Function)等。

基本类型

基本类型存储在栈中,直接存储数据值,数据的复制是值的复制。例如:

let x = 1;
let y = x; // y将值1赋值给x
x = 2;
console.log(x); // 输出:2
console.log(y); // 输出:1

在这个例子中,xy都是Number类型的基本类型,当x的值被修改为2时,y的值没有改变,仍然是1。

引用类型

引用类型存储在堆中,存储的是指向对象的指针,数据的复制是引用的复制。例如:

let x = [1, 2, 3];
let y = x; // y指向x的地址
x.push(4);
console.log(x); // 输出:[1, 2, 3, 4]
console.log(y); // 输出:[1, 2, 3, 4]

在这个例子中,xy都指向同一个数组对象,当x的数组添加一个元素后,y也指向了包含新元素的数组。

对象的创建与操作

在JavaScript中,对象可以通过字面量、构造函数等方式创建。同时,对象可以通过点操作符.或者方括号操作符[]来访问和修改属性值。

对象字面量

使用字面量创建对象是最简单直接的方式。

let person = {
    name: "张三",
    age: 25,
    greet: function() {
        console.log("Hello, my name is " + this.name);
    }
};
person.greet(); // 输出:"Hello, my name is 张三"

构造函数

构造函数是一种特殊类型的函数,用于创建对象实例。

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.greet = function() {
        console.log("Hello, my name is " + this.name);
    }
}
let person = new Person("张三", 25);
person.greet(); // 输出:"Hello, my name is 张三"

在使用构造函数时,必须使用关键字new来创建对象实例。

ES6新数据类型介绍(Set、Map等)

ES6引入了新的数据结构SetMap,提供了更高效的数据操作。

Set

Set是一种集合数据结构,集合内的元素是唯一的。

let set = new Set();
set.add(1); // 添加元素
set.add(2);
set.add(3);
set.add(1); // 重复添加,不会重复添加
console.log(set.size); // 输出:3
console.log(set.has(1)); // 输出:true
set.delete(1); // 删除元素
console.log(set.has(1)); // 输出:false

更复杂的使用场景:

let set = new Set([1, 2, 3, 3, 1]);
console.log(set); // Set(3) {1, 2, 3}

Map

Map是一种键值对集合,相比ObjectMap可以使用任意类型的键,包括对象。

let map = new Map();
map.set("name", "张三");
map.set("age", 25);
console.log(map.get("name")); // 输出:"张三"
console.log(map.size); // 输出:2
map.delete("age"); // 删除键值对
console.log(map.size); // 输出:1

更复杂的使用场景:

let map = new Map();
map.set("name", "张三");
map.set("age", 25);
console.log(map.get("name")); // 输出:"张三"
console.log(map.size); // 输出:2
map.delete("age"); // 删除键值对
console.log(map.size); // 输出:1
JS高级函数特性

函数作为第一类对象

在JavaScript中,函数是第一类对象,可以像普通对象一样赋值给变量、作为参数传递给函数、从其他函数返回,甚至可以作为另一个函数的属性。

function greet(name) {
    return "Hello, " + name;
}

let greetFunction = greet;
console.log(greetFunction("张三")); // 输出:"Hello, 张三"

let functions = [greet, greetFunction];
console.log(functions[0]("张三")); // 输出:"Hello, 张三"

闭包的概念与应用

闭包是JavaScript的一个重要特性,涉及到函数内部的词法环境。当一个函数被返回,并且返回的函数引用了外部函数的局部变量,那么这个返回的函数就是一个闭包。

function createCounter() {
    let count = 0; // 局部变量
    function counter() {
        count++;
        return count;
    }
    return counter;
}

let counter = createCounter();
console.log(counter()); // 输出:1
console.log(counter()); // 输出:2

更复杂的应用场景:

function createCounter() {
    let count = 0;
    function counter() {
        count++;
        return count;
    }
    return counter;
}

let counter = createCounter();
console.log(counter()); // 输出:1
console.log(counter()); // 输出:2

高阶函数与回调函数详解

高阶函数是指接受一个或多个函数作为参数,或者返回一个函数的函数。回调函数是作为参数传递给其他函数的函数,通常在某个事件触发时执行。

function executeAsync(callback) {
    setTimeout(function() {
        console.log("异步执行完成");
        callback(); // 执行回调函数
    }, 1000);
}

executeAsync(function() {
    console.log("回调执行");
}); // 输出:"异步执行完成",然后输出:"回调执行"

更复杂的应用场景:

function executeAsync(callback) {
    setTimeout(() => {
        console.log("异步执行完成");
        callback();
    }, 1000);
}

executeAsync(() => {
    console.log("回调执行");
});

promise与async/await使用

Promise是ES6引入的新特性,用于处理异步操作的完成状态和结果。async/await是对Promise的语法糖,使得异步代码看起来更像同步代码。

Promise

let promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("异步操作完成");
    }, 1000);
});

promise.then(result => {
    console.log(result); // 输出:"异步操作完成"
});

更复杂的用例:

let promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("异步操作完成");
    }, 1000);
});

promise.then(result => {
    console.log(result); // 输出:"异步操作完成"
});

async/await

async function fetchAsync() {
    let result = await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("异步操作完成");
        }, 1000);
    });
    console.log(result); // 输出:"异步操作完成"
}

fetchAsync();

更复杂的用例:

async function fetchAsync() {
    let result = await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("异步操作完成");
        }, 1000);
    });
    console.log(result); // 输出:"异步操作完成"
}

fetchAsync();
JS面向对象编程

类与原型链的理解

在ES5中,原型链用于实现继承关系,每个构造函数都有一个prototype属性,指向一个原型对象。在ES6中,引入了新的class语法,使得面向对象编程更加简洁。

ES5原型链

function Person(name) {
    this.name = name;
}
Person.prototype.greet = function() {
    console.log("Hello, " + this.name);
};

let person = new Person("张三");
person.greet(); // 输出:"Hello, 张三"

ES6类

class Person {
    constructor(name) {
        this.name = name;
    }

    greet() {
        console.log("Hello, " + this.name);
    }
}

let person = new Person("张三");
person.greet(); // 输出:"Hello, 张三"

更复杂的应用场景:

class Person {
    constructor(name) {
        this.name = name;
    }

    greet() {
        console.log("Hello, " + this.name);
    }
}

let person = new Person("张三");
person.greet(); // 输出:"Hello, 张三"

继承的实现方式对比

在ES5中,继承通常通过原型链实现,或者使用构造函数委托。在ES6中,使用class关键字可以更直观地实现继承。

ES5原型链继承

function Person(name) {
    this.name = name;
}
Person.prototype.greet = function() {
    console.log("Hello, " + this.name);
};

function Student(name, grade) {
    Person.call(this, name); // 调用父构造函数
    this.grade = grade;
}
Student.prototype = Object.create(Person.prototype); // 继承原型
Student.prototype.constructor = Student; // 修复构造函数

let student = new Student("李四", "一年级");
student.greet(); // 输出:"Hello, 李四"
console.log(student.grade); // 输出:"一年级"

更复杂的应用场景:

function Person(name) {
    this.name = name;
}
Person.prototype.greet = function() {
    console.log("Hello, " + this.name);
};

function Student(name, grade) {
    Person.call(this, name); // 调用父构造函数
    this.grade = grade;
}
Student.prototype = Object.create(Person.prototype); // 继承原型
Student.prototype.constructor = Student; // 修复构造函数

let student = new Student("李四", "一年级");
student.greet(); // 输出:"Hello, 李四"
console.log(student.grade); // 输出:"一年级"

ES6类继承

class Person {
    constructor(name) {
        this.name = name;
    }

    greet() {
        console.log("Hello, " + this.name);
    }
}

class Student extends Person {
    constructor(name, grade) {
        super(name); // 调用父构造函数
        this.grade = grade;
    }

    study() {
        console.log(this.name + "正在学习");
    }
}

let student = new Student("李四", "一年级");
student.greet(); // 输出:"Hello, 李四"
console.log(student.grade); // 输出:"一年级"
student.study(); // 输出:"李四正在学习"

更复杂的应用场景:

class Person {
    constructor(name) {
        this.name = name;
    }

    greet() {
        console.log("Hello, " + this.name);
    }
}

class Student extends Person {
    constructor(name, grade) {
        super(name); // 调用父构造函数
        this.grade = grade;
    }

    study() {
        console.log(this.name + "正在学习");
    }
}

let student = new Student("李四", "一年级");
student.greet(); // 输出:"Hello, 李四"
console.log(student.grade); // 输出:"一年级"
student.study(); // 输出:"李四正在学习"

ES6类的使用

ES6的类是对ES5原型链的语法糖,提供了更简洁的继承和类的定义方式。

class Rectangle {
    constructor(width, height) {
        this.width = width;
        this.height = height;
    }

    getArea() {
        return this.width * this.height;
    }
}

let rectangle = new Rectangle(3, 4);
console.log(rectangle.getArea()); // 输出:12

更复杂的应用场景:

class Rectangle {
    constructor(width, height) {
        this.width = width;
        this.height = height;
    }

    getArea() {
        return this.width * this.height;
    }

    getPerimeter() {
        return 2 * (this.width + this.height);
    }
}

let rectangle = new Rectangle(3, 4);
console.log(rectangle.getArea()); // 输出:12
console.log(rectangle.getPerimeter()); // 输出:14
JS调试与错误处理

常见的调试工具介绍

JavaScript的调试通常使用浏览器内置的开发者工具,如Chrome的DevTools。开发者工具提供了一系列工具,包括源代码查看、断点设置、变量查看等。

使用Chrome DevTools

  1. 打开Chrome浏览器,访问任意页面。
  2. 按F12或者右键点击页面元素,选择"检查"。
  3. 在开发者工具中,选择"源代码"标签,可以查看当前页面的源代码。
  4. 在源代码中设置断点,执行到断点位置时会暂停执行,可以查看当前的变量值。

错误对象与try-catch语句

JavaScript中的错误处理通常使用try-catch语句,捕获异常并进行处理。Error对象提供了错误信息。

try {
    let result = null;
    console.log(result.someProperty); // 引发TypeError
} catch (error) {
    console.log("发生错误:" + error.message); // 输出:"发生错误:Cannot read property 'someProperty' of null"
}

更复杂的应用场景:

try {
    let result = null;
    console.log(result.someProperty); // 引发TypeError
} catch (error) {
    console.log("发生错误:" + error.message); // 输出:"发生错误:Cannot read property 'someProperty' of null"
}

调试技巧与最佳实践

  1. 使用console.log输出变量值,查看变量的状态。
  2. 在开发者工具中使用断点,查看执行流程。
  3. 逐步执行代码,观察每一个变量的变化。
  4. 使用debugger关键字,插入断点,控制代码的执行。

更复杂的应用场景:

let num = 0;
function increment() {
    num++;
    console.log("当前值:" + num);
}

increment(); // 输出:"当前值:1"
increment(); // 输出:"当前值:2"
JS异步编程

同步与异步的区别

同步操作是阻塞式的,一个操作完成之后才能进行下一个操作。异步操作是非阻塞式的,可以同时执行多个操作。

同步示例

console.log("开始");
console.log("操作1");
console.log("完成");

异步示例

console.log("开始");
setTimeout(function() {
    console.log("操作1");
}, 1000);
console.log("完成");

更复杂的应用场景:

console.log("开始");
setTimeout(function() {
    console.log("操作1");
}, 1000);
console.log("完成");

setTimeout(function() {
    console.log("操作2");
}, 2000);

简单的回调函数与回调地狱

回调函数是一种处理异步操作的方式,但是过多的嵌套会导致回调地狱。

回调地狱示例

setTimeout(function() {
    console.log("操作1");
    setTimeout(function() {
        console.log("操作2");
        setTimeout(function() {
            console.log("操作3");
        }, 1000);
    }, 1000);
}, 1000);

更复杂的应用场景:

setTimeout(function() {
    console.log("操作1");
    setTimeout(function() {
        console.log("操作2");
        setTimeout(function() {
            console.log("操作3");
        }, 1000);
    }, 1000);
}, 1000);

Promise与async/await的使用场景

Promise和async/await是处理异步操作的更好方式,使得代码更清晰。

Promise示例

let promise1 = new Promise(function(resolve, reject) {
    setTimeout(function() {
        resolve("操作1");
    }, 1000);
});

promise1.then(function(result) {
    console.log(result); // 输出:"操作1"
    return result + "操作2";
}).then(function(result) {
    console.log(result); // 输出:"操作1操作2"
});

更复杂的用例:

let promise1 = new Promise(function(resolve, reject) {
    setTimeout(function() {
        resolve("操作1");
    }, 1000);
});

promise1.then(function(result) {
    console.log(result); // 输出:"操作1"
    return result + "操作2";
}).then(function(result) {
    console.log(result); // 输出:"操作1操作2"
});

async/await示例

async function fetchAsync() {
    let result = await new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve("操作1");
        }, 1000);
    });
    console.log(result); // 输出:"操作1"
    return result + "操作2";
}

fetchAsync().then(function(result) {
    console.log(result); // 输出:"操作1操作2"
});

更复杂的用例:

async function fetchAsync() {
    let result = await new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve("操作1");
        }, 1000);
    });
    console.log(result); // 输出:"操作1"
    return result + "操作2";
}

fetchAsync().then(function(result) {
    console.log(result); // 输出:"操作1操作2"
});
性能优化与最佳实践

性能优化常用方法

  1. 减少DOM操作次数,减少页面重绘和重排。
  2. 使用事件代理,减少事件绑定。
  3. 使用requestAnimationFrame进行动画。
  4. 使用Image对象预加载图片。

减少DOM操作次数

let div = document.getElementById("myDiv");
let content = "";
for (let i = 0; i < 100; i++) {
    content += "<p>内容" + i + "</p>";
}
div.innerHTML = content; // 整体更新DOM节点

更复杂的应用场景:

let div = document.getElementById("myDiv");
let content = "";
for (let i = 0; i < 100; i++) {
    content += "<p>内容" + i + "</p>";
}
div.innerHTML = content; // 整体更新DOM节点

使用事件代理

document.getElementById("parent").onclick = function(event) {
    if (event.target.tagName === "A") {
        console.log("点击了链接");
    }
};

更复杂的应用场景:

document.getElementById("parent").onclick = function(event) {
    if (event.target.tagName === "A") {
        console.log("点击了链接");
    }
};

代码优化技巧

  1. 使用严格模式,避免隐式类型转换等潜在问题。
  2. 避免全局变量,使用模块化的方式组织代码。
  3. 使用缓存,减少重复计算。
  4. 使用惰性加载,按需加载代码。

使用严格模式

"use strict";
let variable = 1;
console.log(variable); // 输出:1

更复杂的应用场景:

"use strict";
let variable = 1;
console.log(variable); // 输出:1

避免内存泄漏的方法

内存泄漏主要发生在引用不再需要的对象。常见的内存泄漏原因包括闭包、全局变量、未清除的定时器等。

解决内存泄漏的示例

function createLeak() {
    let intervalId = setInterval(function() {
        console.log("内存泄漏");
    }, 1000);

    // 清除定时器
    setTimeout(function() {
        clearInterval(intervalId);
    }, 10000);
}

createLeak();

更复杂的应用场景:

function createLeak() {
    let intervalId = setInterval(function() {
        console.log("内存泄漏");
    }, 1000);

    // 清除定时器
    setTimeout(function() {
        clearInterval(intervalId);
    }, 10000);
}

createLeak();
點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消