标签:javascript

JavaScript ( JS ) 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言,基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式和声明式(如函数式编程)风格。

读 2020 年 Javascript 趋势报告展望 ES2020

2021年1月14日,Javascript 2020趋势调查报告发布了。调查结果来自137个国家的23,765名开发者,涵盖了开发者对Javascript特性、技术、工具等的使用和想法。下面来一起看看这份报告,并加深对Javascript的认识,在新的一年里提升一个档次。

十个拥有丰富UI组件的JavaScript开发框架

如今,网上有各种各样的 JavaScript 框架用来简化 Web 应用开发。这些框架都提供了一些核心的特性,例如 DOM 操作,动画,事件处理以及 Ajax 交互,但不是都带有 UI 组件。今天这篇文章向大家推荐的10个 JavaScript 框架提供了丰富的 Web UI 组件,帮助你构建一致,可靠以及高度交互的漂亮用户界面。

构建WEB项目的 25 个HTML建议

HTML是WEB应用程序的骨架,尽管非常容易上手,但仍有很多需要注意的规则,可能因为没有遵循这些规则导致WEB应用程序的实践受到影响,现在对于项目开发,很多规则是可以通过程序来自动完成,对于初学者还是有必要了解一下。

JavaScript 数组展平方法: flat() 和 flatMap()

作为一门主流的WEB编程语言,JavaScript 不断发展,添加新的语法、功能或抽象,帮助开发人员轻松解决复杂的问题。如数组展平过去需要自己编写方法来实现,而从 ES2019 中开始引入了一种扁平化数组的新方法,可以展平任何深度的数组,这个方法就是 flat() 。而说起 flat() 的方法,就不得不顺便说下 flatMap()。

JavaScript 中的 .forEach() 和 for...of

.forEach() 方法被认为是 JavaScript 中的高阶函数,其工作方式是为列表中的每个元素传入当前元素、索引和列表(正在循环的整个数组),用更专业的术语来说就是对于迭代器的每次调用,函数都会接收三个参数(元素、索引、列表)调用。

在 JavaScript 中创建私有成员

面向对象编程语言中的 private 关键字是一个访问修饰符,可用于使属性和方法只能在声明的类中访问。这使得隐藏底层逻辑变得容易,这些底层逻辑应该被隐藏起来,并且不应该与类的外部交互。

JavaScript数据结构之Object

Object 定义一组属性的无序集合,可以将其想象成一张散列表,其中的内容就是一组名/值对,值可以是数据或者函数。 而数组是一个有序集合,为了保证元素排列有序,相比 Object 来说会占用更多的内存空间。

JavaScript数据结构之Number

Number 是JavaScript的基本数据结构,是对应数值的应用类型。要创建一个 Number 对象,就使用 Number 构造函数并传入一个数值。在 JavaScript 中没有其他语言这么多的数字类型。

JSON 和JavaScript 介绍与区别

JSON 是 JavaScript Object Notation 的缩写。 JSON JavaScript 也是如此吗?不完全是。 JSON 是一种独立于任何编程语言的数据格式,源自于 JavaScript。大部分现代编程语言都包含可以生成和解析 JSON 数据的方法。

2023 年可以考虑学习的 10 种编程语言

如果职业发展或改变职业的计划完全要求掌握一门编程语言,可能想知道该学哪一种语言。毕竟,学习这门语言需要时间,所以需要做出正确的选择,特别对于刚出社会的毕业生。 在做出决定时,应该牢记几个考虑因素,如愿意解决的难度级别、已经拥有的与现有编码技能相匹配的编程语言知识,或者学习顶级编程语言的原因。

使用OpenAI ChatGPT 进行了编码尝试

ChatGPT 是一种以类似聊天的方式进行交互的人工智能网络,从名字上看起来像是另一个“聊天机器人”,但实际上已经远超聊天的范畴了,当要求它编写一些代码时,结果相等震撼,它可以写出一些意想不到的连贯代码,而这些代码对于开发者很有启发。

简述JavaScript异步函数 async/await

ES7 引入的 async/await 是对 JavaScript 异步编程的一种改进,它提供了使用同步样式代码异步访问资源的选项,而不会阻塞主线程。但是,要很好地使用它有点棘手。在本文中,将从不同的角度探索 async/await,并展示如何正确有效地使用它们。

简述JavaScript键盘事件

JavaScript 中的事件,当用户或浏览器尝试操作页面时,就会发生事件来处理 JavaScript 与HTML的交互。正如大家所知,JavaScript 与HTML一起工作,因此,页面加载、单击按钮、最小化窗口、单击鼠标、敲打键盘等发生的一切都是事件。就像在单击按钮时向用户显示任何消息一样,这是通过事件发生的。

复习前端:JavaScript V8 引擎机制

V8 是谷歌推出的开源 JavaScript 引擎,它是用 C++ 编写的,支持 Google Chrome、Chromium 网络浏览器和 NodeJS,它负责与环境交互并生成字节码来运行程序。 V8 和其他引擎之间最显着的区别是它的即时 (JIT) 编译器。

关于 JavaScript 定时器

JavaScript 定时器是实现循环行为甚至触发延迟操作的好功能。无论有什么基于时间的逻辑,定时器都可以提供支持。在 JavaScript 中有两个定时器函数:setTimeout 和 setInterval 。接下来看看有哪些定时器以及它们是如何工作的。

理解 GraphQL 类型系统

作为一种为灵活性而设计的 API 技术,GraphQL 是 API 的开发人员和消费者以及他们背后的组织的强大推动者。GraphQL 实现的所有细节和功能都在 GraphQL Schema 中列出。为了编写一个有效的 GraphQL schema,必须理解好 GraphQL 类型系统。

ES6 如何将 Set 转化为数组

Set 是 ES6 中新增的一种集合类型,类似于数组,但其成员的值是唯一的,即不会重复。关于Set,可以阅读《JavaScript中的Set数据操作:交集、差集、交集、对称差集》。Set 对象是一个构造函数,可以使用 new 关键字来创建一个 Set 实例。

JavaScript 对象管家 Proxy

JavaScript 在 ES6 中,引入了一个新的对象类型 Proxy,它可以用来代理另一个对象,并可以在代理过程中拦截、覆盖和定制对象的操作。Proxy 对象封装另一个对象并充当中间人,其提供了一个捕捉器函数,可以在代理对象上拦截所有的操作,包括访问属性、赋值属性、函数调用等等。通过拦截这些操作,可以对代理对象进行定制和控制。

1["1","2","3"].map(parseInt)返回值是多少?

返回值是:[1,NaN,NaN]

parseIntmap函数都是常用的函数,可是 ["1", "2", "3"].map(parseInt) 为何返回不是[1,2,3]却是[1,NaN,NaN]

下面我们先来了解一下parseInt函数的使用方法。

parseInt() 函数

parseInt() 函数解析一个字符串参数,并返回一个指定基数的整数 (数学系统的基础)。

语法

parseInt(string, radix)

参数 描述
string 必需。要被解析的字符串。
radix

可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。

如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。

如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN

返回值

返回解析后的数字。

说明

当参数 radix 的值为 0,或没有设置该参数时,parseInt() 会根据 string 来判断数字的基数。

一下情况返回值为NaN

  • radix 小于 2 或大于 36
  • 第一个非空格字符不能转换为数字。

 

 

 

1JavaScript 怎么定义可变参数的函数

在 JavaScript 中,可以使用 arguments 对象来实现可变参数。 arguments 是一个类数组对象,包含传递给函数的所有参数。可以在函数内部通过访问 arguments 对象来访问所有参数。

以下是一个使用 arguments 对象实现可变参数的示例:

function sum() {
    let total = 0;
    for (let i = 0; i < arguments.length; i++) {
        total += arguments[i];
    }
    return total;
}

console.log(sum(1, 2, 3)); // 6
console.log(sum(4, 5, 6, 7)); // 22

在 ES6 中还可以通过扩展运算符来实现可变参数。

function sum(...numbers) {
    let total = 0;
    for (let i = 0; i < numbers.length; i++) {
        total += numbers[i];
    }
    return total;
}

console.log(sum(1, 2, 3)); // 6
console.log(sum(4, 5, 6, 7)); // 22

 

1JavaScript 如何使用 valueOf 方法

在 JavaScript 中,valueOf() 方法是一个可以被对象调用的方法,用于返回该对象的原始值。它可以被所有对象类型(包括自定义对象)调用,并返回一个原始值,例如字符串、数字、布尔值等。

对象

下面是一个示例,展示了在 JavaScript 中对象使用 valueOf() 方法:

let myObj = {
    name: "Quintion",
    age: 30,
    toString() {
        return `${this.name} 年龄 ${this.age}`;
    },
    valueOf() {
        return this.age;
    },
};

console.log(myObj.toString()); // Quintion 年龄 30
console.log(myObj.valueOf()); // 30

数字

在 JavaScript 中的数字是 Number 类型的实例,具有 valueOf() 方法,返回一个数字对象的原始值。

例如,如果有一个数字对象 num,可以使用 valueOf() 方法获取它的原始值,如下所示:

const num = new Number(42);
console.log(num.valueOf()); // 42

大多数情况下,JavaScript 引擎会自动将数字对象转换为数字类型,因此通常不需要使用 valueOf() 方法来获取数字对象的值。例如:

const num = new Number(42);
const result = num + 10;
console.log(result); // 52

字符串

字符串是 String 类型的实例,也具有 valueOf() 方法,返回一个字符串对象的原始值。

例如,如果有一个字符串对象 str,可以使用 valueOf() 方法获取它的原始值,如下所示:

const str = new String("hello");
console.log(str.valueOf()); // 'hello'

同样,JavaScript 引擎会自动将字符串对象转换为字符串类型,因此不需要使用 valueOf() 方法来获取字符串对象的值。例如:

const str = new String("hello");
const result = str + " world";
console.log(result); // 'hello world'

上面代码 str 会被自动转换为字符串类型,因此可以将它与另一个字符串连接起来。

1JavaScript 中 null 和 undefined 的意义是什么?

在JavaScript中,null 和 undefined 都表示无值(no value)的含义,但是它们在具体使用中有一些不同之处:

  1. undefined 表示未定义,即声明了但未赋值的变量的默认值,或者访问对象不存在的属性时返回的值。例如:const x; console.log(x); 输出 undefined
  2. null 表示空值,即一个变量被明确地赋值为空。例如:const x = null; console.log(x); 输出null

虽然它们都表示无值,但在某些情况下,它们是不等价的。例如,使用双等号(==)比较时,null 和 undefined 会被视为相等的值,但在使用严格相等运算符(===)比较时,它们是不相等的。同时,在使用 typeof 运算符时,null 会被视为一个对象,而 undefined 会被视为未定义的变量。

总结大概如下:

  • null 是一个赋值。这没有任何意义。
  • undefined 表示变量已声明但尚未定义。
  • null是一个对象。undefined 是类型 undefined
  • null !== undefined 但是 null == undefined
1JavaScript 设计模式有哪些?
本系列开始系统性的对 20 多种 JavaScript 设计模式进行简单概述,然后结合 ES6 类的方式来编写实例代码展示其使用方式。

什么是设计模式?

设计模式是软件设计中常见问题的解决方案,这些模式很容易重复使用并且富有表现力。

在软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。它并不直接用来完成代码的编写,而是描述在各种不同情况下,要怎么解决问题的一种方案。面向对象设计模式通常以类别或对象来描述其中的关系和相互作用,但不涉及用来完成应用程序的特定类别或对象。—— 维基百科

有三种模式:创建型模式,结构型模式、行为型模式。

  • 创建型模式:解决与创建对象相关的问题。
  • 结构型模式:处理实体之间的关系,以及它们如何共同组成一个更大的结构。
  • 行为型模式:处理对象如何相互通信和交互。

设计模式系列文章:

1JavaScript 如何实现私有变量?

在 ES6 中,可以使用闭包来模拟私有变量的实现。具体地说,可以使用一个立即执行函数表达式 IIFE 来创建一个函数作用域,在函数作用域内定义私有变量,然后通过返回一个对象,使得外部无法直接访问私有变量。

例如,以下是一个使用闭包实现私有变量的示例:

const Counter = (() => {
    let count = 0; // 私有变量

    return {
        increment() {
            count++;
            console.log(`count: ${count}`);
        },
        reset() {
            count = 0;
            console.log("count reset");
        },
    };
})();

Counter.increment(); // 输出 "count: 1"
Counter.increment(); // 输出 "count: 2"
Counter.reset(); // 输出 "count reset"

在上述示例中,count 变量是私有的,外部无法直接访问它,但是可以通过调用返回的对象中的方法来操作它。这里使用了箭头函数和对象字面量来定义返回的对象,使得代码更加简洁。

1JavaScript 如何对 Cookie 进行操作

HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。是WEB项目开发需要涉及的内容。

Cookie操作

如果应用程序是完全客户端 SPA(单页应用程序),可能不需要 cookie,使用 localStorage 可以解决问题。如果是使用 Next.js 或者 Node.js 提供服务器接口需要身份验证 Token 的可以考虑使用 cookie

通常认为 cookie 是复数形式,但事实是它们存储在单个字符串值中,必须对其进行解析才能将它们分解为单独的键/值对

console.log(document.cookie); // _gcl_au=1.1.1660316496.1636468606; _ga=GA1.2.221099298.1636468607; _gid=GA1.2.1474751041.1636468607;

可以通过 ; 拆分字符串来将它们分开,然后映射每个值并使用 = 将其拆分为 ,最终将得到相应的键/值对。下面是一个完整的方法集:

const useCookie = (options = { days: 30, path: "/" }) => {
    const { days: expiresDays, path: cookiePath } = options;

    const set = (name, value) => {
        const exp = new Date();
        exp.setTime(exp.getTime() + expiresDays * 24 * 60 * 60 * 1000);
        const strExpires = exp.toGMTString();
        const cookieValue = escape(value);
        document.cookie = `${name}=${cookieValue};expires=${strExpires};path=${cookiePath}`;
    };
    const get = (name) => {
        let arr;
        const reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
        if ((arr = document.cookie.match(reg))) {
            return unescape(arr[2]);
        } else {
            return null;
        }
    };
    // 删除cookie
    const remove = (name) => {
        document.cookie = name + "=;expires=" + new Date(0).toGMTString();
    };
    // 清除所有 cookie
    const clear = () =>
        document.cookie
            .split(";")
            .forEach(
                (cookie) =>
                    (document.cookie = cookie
                        .replace(/^ +/, "")
                        .replace(
                            /=.*/,
                            `=;expires=${new Date().toUTCString()};path=${cookiePath}}`
                        ))
            );
    /**
     * 获取所有的 cookie
     * @returns
     */
    const all = () =>
        document.cookie
            .split(";")
            .map((item) => item.split("="))
            .reduce(
                (acc, [k, v]) => (acc[k.trim().replace('"', "")] = v) && acc,
                {}
            );
    return {
        set,
        get,
        clear,
        remove,
        all,
    };
};
const cookieHelper = useCookie();
cookieHelper.set("name", "DevPoint");
cookieHelper.set("city", "Shenzhen");
console.log(cookieHelper.get("name")); // DevPoint
console.log(cookieHelper.all()); // { name: "DevPoint", city: "Shenzhen" }
cookieHelper.remove("name");
console.log(cookieHelper.all()); // { city: "Shenzhen" }

出于安全考虑,某些 cookie 可能被标记为 仅 HTTP ,这意味着此类 cookie 不能从客户端的 JavaScript 代码中获取到。

Cookie 安全主要涉及以下两个方面:

防止窃取

攻击者可以通过窃取用户的 Cookie 来实现会话劫持等攻击,因此在设置 Cookie 时应当注意以下安全问题:

  • 在服务器端设置 HttpOnly 属性,防止脚本获取 Cookie。
  • 使用 secure 属性,只允许在 HTTPS 连接中传输 Cookie。
  • 设置 SameSite 属性,防止跨站请求伪造攻击(CSRF)。

防止篡改
攻击者还可以通过修改 Cookie 的值来实现攻击,因此在使用 Cookie 时应当注意以下安全问题:

  • 在服务器端对 Cookie 的值进行加密和签名,防止篡改。
  • 对于关键操作,应当在服务端进行校验,避免因为 Cookie 被篡改而造成安全漏洞。

综上所述,Cookie 安全需要从多个方面进行考虑和防护。

应用开发一般都少不了身份验证,而身份验证机制的稳定性对所有应用程序都变得至关重要。具体选择何种方式进行身份验证可以根据项目及团队情况来衡量,在决定之前需要先理解WEB身份验证常见的两种方式:基于 Cookie 的身份验证和基于令牌(Token)的身份验证。

1JavaScript 如何将字符串转为二进制?

以下是一个将字符串转换为二进制字符串的 JavaScript 函数:

function stringToBinary(string) {
    let binaryString = "";
    for (let i = 0; i < string.length; i++) {
        // 将字符转换为 Unicode 编码
        const charCode = string.charCodeAt(i);
        // 将 Unicode 编码转换为二进制字符串
        const charBinary = charCode.toString(2);
        // 将二进制字符串补齐 8 位
        const paddedCharBinary = charBinary.padStart(8, "0");
        // 将每个字符的二进制字符串拼接到总的二进制字符串中
        binaryString += paddedCharBinary;
    }
    return binaryString;
}

函数接受一个字符串作为参数,返回一个二进制字符串。通过遍历字符串中的每个字符,将其转换为 Unicode 编码,再将 Unicode 编码转换为二进制字符串,最后将每个字符的二进制字符串拼接到总的二进制字符串中。如果一个字符的二进制字符串不足 8 位,函数会在左侧用 0 填充,使其成为 8 位二进制字符串。

使用方法如下:

const chineseString = stringToBinary("全栈工匠");
console.log(chineseString); // 101000101101000110100000001000101110111100101101001100100000
const englishString = stringToBinary("hu");
console.log(englishString); // 0110100001110101
1JavaScript 代码如何实现进制转换?

JavaScript 可以使用以下代码实现进制转换:

1、十进制转二进制

使用 toString() 方法,将十进制数转换为二进制字符串,如下:

const decimalToBinary = (decimalNumber) => decimalNumber.toString(2);

console.log(decimalToBinary(11)); // 1011

2、十进制转八进制

const decimalToOctal = (decimalNumber) => decimalNumber.toString(8);

console.log(decimalToOctal(11)); // 13

3、十进制转十六进制

const decimalToHex = (decimalNumber) => decimalNumber.toString(16);

console.log(decimalToHex(11)); // b

4、二进制转十进制

const binaryToDecimal = (binaryString) => parseInt(binaryString, 2);

console.log(binaryToDecimal(1011)); // 11

5、八进制转十进制

const octalToDecimal = (binaryString) => parseInt(binaryString, 8);

console.log(octalToDecimal(13)); // 11

6、十六进制转十进制

const hexToDecimal = (binaryString) => parseInt(binaryString, 16);

console.log(hexToDecimal("b")); // 11

7、二进制转十六进制

const binaryToHex = (binaryString) => {
    const decimalNumber = parseInt(binaryString, 2);
    return decimalNumber.toString(16);
};

console.log(binaryToHex(1011)); // b

8、八进制转二进制

const octalToBinary = (octalString) => {
    const decimalNumber = parseInt(octalString, 8);
    return decimalNumber.toString(2);
};

console.log(octalToBinary(13)); // 1011

9、十六进制转二进制

const hexToBinary = (hexString) => {
    const decimalNumber = parseInt(hexString, 16);
    return decimalNumber.toString(2);
};

console.log(hexToBinary("b")); // 1011

10、八进制转十六进制

const octalToHex = (octalString) => {
    const decimalNumber = parseInt(octalString, 8);
    return decimalNumber.toString(16);
};

console.log(octalToHex(13)); // b

下面将上述代码封装成一个类,完整代码如下:

class NumberConverter {
    static decimalToBinary(decimalNumber) {
        return decimalNumber.toString(2);
    }

    static decimalToOctal(decimalNumber) {
        return decimalNumber.toString(8);
    }

    static decimalToHex(decimalNumber) {
        return decimalNumber.toString(16);
    }

    static binaryToDecimal(binaryString) {
        return parseInt(binaryString, 2);
    }

    static octalToDecimal(octalString) {
        return parseInt(octalString, 8);
    }

    static hexToDecimal(hexString) {
        return parseInt(hexString, 16);
    }

    static binaryToHex(binaryString) {
        const decimalNumber = parseInt(binaryString, 2);
        return decimalNumber.toString(16);
    }

    static octalToBinary(octalString) {
        const decimalNumber = parseInt(octalString, 8);
        return decimalNumber.toString(2);
    }

    static hexToBinary(hexString) {
        const decimalNumber = parseInt(hexString, 16);
        return decimalNumber.toString(2);
    }

    static octalToHex(octalString) {
        const decimalNumber = parseInt(octalString, 8);
        return decimalNumber.toString(16);
    }
}

console.log(NumberConverter.decimalToBinary(11)); // 1011
console.log(NumberConverter.decimalToOctal(11)); // 13
1HTML、CSS、JavaScript、PHP、 MySQL 的学习顺序是什么?

关于这个问题,现在应该有新的认知,先回到问题本身,最佳的学习顺序应该是:

学习顺序

  1. HTML:HTML是构建Web页面的基础语言,学习HTML可以熟悉如何创建文本、图像、链接等基本内容,并且组织网页结构,这是WEB交互的基础,有了这个基础才能设计独特的交互效果。
  2. CSSCSS 是用来美化Web页面的样式表语言。通过CSS,可以控制文本、图像、背景、布局等各个方面的样式,让页面更加美观和易于阅读。掌握其基础,在现代WEB开发中建议不用原生 CSS ,而是使用 LESS、SASS 等,其具有变量、基础、函数组织能力可以更好的维护项目。
  3. JavaScript:JavaScript 是一种脚本语言,是用来控制Web页面的交互和动态效果,例如响应用户操作、验证表单、创建动画、处理数据等等。熟练掌握应该是前端开发者应该具备的技能,现代WEB开发中,更多的使用工程化框架来构建,如React、Vue等等。
  4. PHP:PHP是一种服务器端脚本语言,用来处理Web应用程序的数据和逻辑。通过PHP,你可以实现用户注册、登录、发送电子邮件、处理表单数据、连接数据库等功能。这是过去WEB开发架构中常见的后端服务开发技术,现阶段实际上有很多可替代的架构,如Next.js、Node.js、Go等等。
  5. MySQL:MySQL是一种流行的开源关系型数据库管理系统,用来存储和管理Web应用程序的数据。学习MySQL可以让你了解如何创建和管理数据库、存储和查询数据等。

上面提到的应该是过去WEB开发中比较常见技术架构,现在应该有更多的选择,如 HTML+CSS+JavaScript+Node.js+Mongodb;如果是React,则应该是 HTML+CSS+JavaScript+Next.js+Mongodb

当然不管那种技术架构,HTML+CSS+JavaScript 是基础,更高阶的可以往 HTML+CSS+TypeScript 的方向去。

除了上面的这些技能,对于开发者来说,建议掌握 Docker,过去对于开发者来说,环境的配置通常是比较繁琐的,就拿PHP来说,配置开发环境需要安装 Apache、PHP版本,存储需要安装 Mysql,如果掌握了 Docker ,环境配置就变得简单,并且不会污染自己本机的环境。

学习资料推荐

对于HTML和CSS,建议从模仿开始,去阅读一些开源代码和比较不错的HTML模版,从模仿这些模版开始。开始之前可以先看下基础的东西:

CSS权威指南(第四版)(上下册):国际公认的HTML、CSS和Web标准领域的专家全新力作。Web视觉呈现技术。全面阐述CSS的实现方式,深入分析全新的CSS规范。

对于JavaScript,就有很多的书籍,下面书籍自己都阅读学习过了,不多,书籍算是掌握基本功的重要途径,剩下主要提升就是 GitHub。

JavaScript 指南原书第7版犀牛书:在过去的十年中,Node.js 使得 JavaScript 编程可以在 web 浏览器之外进行,Node 的巨大成功意味着 JavaScript 现在也是软件开发人员最常用的编程语言。无论你是从零开始还是已经开始专业地使用 JavaScript,这本书都会帮助你掌握这门语言。

JavaScript程序设计 第4版 第四版 红宝石书:第4版涵盖ECMAScript 2019,全面、深入地介绍了JavaScript开发者必须掌握的前端开发技术,涉及JavaScript的基础特性和特性 。

数据结构与算法JavaScript描述:用JavaScript描述数据结构与算法的开山之作,汇聚了作者多年的实战经验。这本实战指南通过丰富的示例,向读者透彻讲解了在JavaScript环境下,如何通过一系列存储机制(包括链表、栈、队列和图)高效地达到编程目的。

除了阅读书籍阅读源代码外,还可以去刷刷算法题。

JavaScript设计模式与开发实践:设计模式是软件设计中经过了大量实际项目验证的可复用的优 秀解决方案,它有助于程序员写出可复用和可维护性高的程序。许多优 秀的JavaScript开源框架都运用了不少设计模式,越来越多的程序员从设计模式中获益,也许是改善了自己编写的某个软件,也许是更好地理解了面向对象的编程思想。

学习设计模式的目的是:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

 

1有哪些短小却令人惊叹的 JavaScript 代码?

每天学习10个实用JavaScript代码片段,加深对 JavaScript 语法的理解,积累代码优化经验。

1、FizzBuzz

下面代码用于实现经典的 FizzBuzz 问题,将1100的数字遍历,如果是3的倍数则输出 Fizz ,如果是5的倍数则输出 Buzz,如果既是3的倍数又是5的倍数则输出 FizzBuzz

const fizzBuzz = () => {
    for (let i = 1; i <= 100; )
        console.log((i % 3 ? "" : "Fizz") + (i % 5 ? "" : "Buzz") || i), i++;
};
console.log(fizzBuzz());

2、斐波那契数列

斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、…… 在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=1,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*),在现代物理、准晶体结构、化学等领域,斐波那契数列都有直接的应用

斐波那契数列通常是面试常见的问题,下面代码是用一个非常简短的递归函数,返回斐波那契数列中第n个数字的值。

const fib = (n) => (n <= 2 ? 1 : fib(n - 1) + fib(n - 2));

const createFibNumber = (count = 10) => {
    const arrayFibs = [];
    for (let i = 0; i < count; i++) {
        arrayFibs.push(fib(i));
    }
    return arrayFibs;
};

console.log(createFibNumber(10)); // [ 1, 1,  1,  2,  3, 5, 8, 13, 21, 34 ]

3、快速排序

下面代码实现了快速排序,通过递归将数组分割成较小和较大的两个子数组,最终将它们合并以获得排序的结果。

const quickSort = (arrayNums) =>
    arrayNums.length
        ? [
              ...quickSort(arrayNums.slice(1).filter((x) => x <= arrayNums[0])),
              arrayNums[0],
              ...quickSort(arrayNums.slice(1).filter((x) => x > arrayNums[0])),
          ]
        : [];

const arrayNumbers = [1, 3, 5, 6, 2, 4, 11, 30, 100, 40];
console.log(quickSort(arrayNumbers)); // [ 1,  2,  3,  4,   5, 6, 11, 30, 40, 100 ]

4、判断是否为回文

下面代码用于判断一个字符串是否为回文,它将字符串转换为一个字符数组并翻转它,然后将它们重新连接起来,并将其与原字符串进行比较。

const isPalindrome = (str) => str == str.split("").reverse().join("");

console.log(isPalindrome("deved")); // true
console.log(isPalindrome("devedev")); // false

5、数组去重

下面代码用于对一个数组进行去重操作,使用ES6中的Set数据结构,将数组转换为一个Set,然后再将其转换为一个数组。

const unique = (arr) => [...new Set(arr)];

const arrayNumbers = [1, 2, 3, 4, 2, 1];
console.log(unique(arrayNumbers)); // [ 1, 2, 3, 4 ]

6、打印九九乘法表

下面代码可以打印出九九乘法表,它通过两个嵌套的for循环遍历每个数字,然后打印出相应的乘法表达式及其结果。

const createNumbers = () => {
    const array = [];
    for (let i = 1; i <= 9; i++)
        for (let j = 1; j <= i; j++)
            array.push(`${j}*${i}=${j * i}${j === i ? "\n" : "  "}`);
    return array.join("");
};
console.log(createNumbers());

输出结果如下:

1*1=1
1*2=2  2*2=4
1*3=3  2*3=6  3*3=9
1*4=4  2*4=8  3*4=12  4*4=16
1*5=5  2*5=10  3*5=15  4*5=20  5*5=25
1*6=6  2*6=12  3*6=18  4*6=24  5*6=30  6*6=36
1*7=7  2*7=14  3*7=21  4*7=28  5*7=35  6*7=42  7*7=49
1*8=8  2*8=16  3*8=24  4*8=32  5*8=40  6*8=48  7*8=56  8*8=64
1*9=9  2*9=18  3*9=27  4*9=36  5*9=45  6*9=54  7*9=63  8*9=72  9*9=81

7、数组求和

下面代码用于对一个数组中的数字进行求和,使用 reduce 方法将数组中的所有数字相加起来,并返回最终的结果。

const sum = (arr) => arr.reduce((acc, current) => acc + current, 0);
console.log(sum([1, 3, 5, 7, 9, 10])); // 35

8、获取URL参数

下面代码用于从URL中获取特定的参数值,使用 URLSearchParams API来获取URL查询参数,并使用get方法获取特定的参数值。

const getParam = (url, name) =>
    new URLSearchParams(new URL(url).search).get(name);

console.log(getParam("https://www.devpoint.cn?name=devpoint", "name")); // devpoint

9、判断一个数字是否为质数

下面代码用于判断一个数字是否为质数,使用一个for循环遍历2到数字的平方根之间的所有数字,并检查它们是否可以整除该数字。

const isPrime = (n) => {
    if (n <= 1) return false;
    for (let i = 2; i <= Math.sqrt(n); i++) {
        if (n % i === 0) return false;
    }
    return true;
};
console.log(isPrime(1)); // false
console.log(isPrime(2)); // true
console.log(isPrime(3)); // true

10、数组扁平化

下面代码用于将一个嵌套的数组扁平化为一个一维数组,使用 reduce 方法递归地遍历嵌套数组,并将其合并为一个新的数组。

const flatten = (arr) =>
    arr.reduce(
        (acc, val) => acc.concat(Array.isArray(val) ? flatten(val) : val),
        []
    );

console.log(flatten([1, [1, 3], [4, 5, 6], [7, [8, [9]]]])); // [ 1, 1, 3, 4, 5, 6, 7, 8, 9 ]

11、阶乘

下面代码用于计算一个数字的阶乘,使用递归方法,将数字乘以它减一的阶乘。

const factorial = (n) => (n < 2 ? 1 : n * factorial(n - 1));
console.log(factorial(4)); // 24

总结

阅读开源项目是学习提升编码能力最快捷的方式,当然现在可能可以借助 ChatGPT 来生成一些函数,其生成的函数技巧性也很高。

1JavaScript 怎么截取字符串?

在 JavaScript 中,可以使用 substr()slice()substring() 方法截取字符串。

substring()

substring() 方法返回一个字符串在开始索引到结束索引之间的一个子集,或从开始索引直到字符串的末尾的一个子集。语法如下:

str.substring(indexStart[, indexEnd])

参数说明:

  • indexStart:需要截取的第一个字符的索引,该索引位置的字符作为返回的字符串的首字母。
  • indexEnd:可选。一个 0 到字符串长度之间的整数,以该数字为索引的字符不包含在截取的字符串内。

如果 startIndex 大于 endIndex,则会交换它们的位置。来看一段示例代码:

let str = "深耕WEB开发10+年,拥有一颗工匠的心";

console.log(str.substring(7)); // 10+年,拥有一颗工匠的心
console.log(str.substring(0, 5)); // 深耕WEB
console.log(str.substring(7, 5)); // 开发
console.log(str.substring(5, 5)); // 空

substr()

substr() 方法返回一个字符串中从指定位置开始到指定字符数的字符。语法如下:

str.substr(start[, length])

第一个参数是截取开始的位置,第二个参数是截取的长度。如下代码:

let str = "深耕WEB开发10+年,拥有一颗工匠的心";
let result = str.substr(1, 4);
console.log(result); // 耕WEB

上述代码的 1 表示从第二个字符开始截取,4 表示截取的长度为 4 个字符。

substr() 方法在截取字符串时是基于字符位置的,如果截取长度超过了字符串的长度,它会一直截取到字符串的末尾。如果第一个参数是负数,则从字符串的末尾开始计数。

如果可以的话,建议使用 substring() 来取代 substr()

slice()

slice() 方法提取某个字符串的一部分,并返回一个新的字符串,且不会改动原字符串,与 substring() 方法类似。语法如下:

str.slice(startIndex, endIndex)

其中,startIndex 表示要截取的子字符串的起始位置(包含该位置),endIndex 表示要截取的子字符串的结束位置(不包含该位置)。如果只传入 startIndex,则会从该位置一直截取到字符串末尾。如果 startIndex 大于 endIndex,则会返回空字符串。例如:

let str = "深耕WEB开发10+年,拥有一颗工匠的心";

console.log(str.slice(7)); // 10+年,拥有一颗工匠的心
console.log(str.slice(0, 5)); // 深耕WEB
console.log(str.slice(7, 5)); // ""
console.log(str.slice(5, 5)); // ""

substring()substr() 的区别

substring()substr() 都是截取字符串的方法,但它们有以下区别:

  1. 参数不同substring() 方法的第一个参数是起始位置,第二个参数是终止位置(不包括该位置的字符);substr() 方法的第一个参数是起始位置,第二个参数是截取的长度。
  2. 负数处理不同substring() 方法不接受负数参数,如果传入负数,会被自动转换为0substr() 方法可以接受负数参数,表示倒数计数。
  3. 返回值不同substring() 方法返回从起始位置到终止位置之间的字符;substr()方法返回从起始位置开始指定长度的字符。

ES6中新增了 slice() 方法,但它和 substring() 方法非常相似,也是接受起始位置和终止位置作为参数,不同之处是slice() 方法可以接受负数参数,表示从字符串末尾开始计数。substr() 虽然没有被完全遗弃,但还是建议使用 substring() 来取代 substr()

1webassembly 能干什么

WebAssembly(缩写为WASM)是一种二进制格式的代码,它可以在现代Web浏览器中运行。它被设计为一种低级的虚拟机,可以在浏览器中运行高性能的程序,可以通过编译其他语言的代码来实现。

下面是WebAssembly可以做的一些事情:

  • 前端开发:WebAssembly 可以与JavaScript一起使用,以提高Web应用程序的性能。例如,可以使用WebAssembly编写一些计算密集型的算法,以替代JavaScript来提高性能。
  • 游戏开发:可以用于在Web浏览器中运行游戏。它可以提供比JavaScript更快的运行速度和更好的性能,使得在Web浏览器中运行的游戏更加流畅。
  • 跨平台开发:可以在不同的平台上运行,包括Web浏览器、桌面和移动设备。这使得开发人员可以使用相同的代码来创建跨平台应用程序。
  • 数据科学和机器学习:可以用于加速数据科学和机器学习应用程序,使得这些应用程序可以在Web浏览器中运行。

除了上述提到的应用场景,WebAssembly还有以下几个优点:

  • 高性能:WebAssembly代码可以编译成原生代码,因此它可以提供比JavaScript更快的运行速度和更好的性能。这使得它非常适合执行计算密集型的任务,如图形处理、音视频处理和机器学习等。
  • 安全性:WebAssembly是一种沙箱化的执行环境,因此它可以提供比JavaScript更高的安全性。它的指令集是基于栈的,而不是基于寄存器的,这使得它更难受到缓冲区溢出等安全漏洞的攻击。
  • 可移植性:WebAssembly可以在不同的平台上运行,包括Web浏览器、桌面和移动设备。这使得开发人员可以使用相同的代码来创建跨平台应用程序,从而减少了开发时间和成本。
  • 扩展性:WebAssembly可以与现有的Web技术(如JavaScript、CSS和HTML)集成使用,从而可以扩展Web应用程序的功能和性能。

WebAssembly 虽然是一门新的技术,但现在有不少区块链项目在使用,用来编写智能合约,提高智能合约的性能和安全性。

下面是一些使用WebAssembly的区块链项目:

  • EOSIO:EOSIO是一个开源的区块链平台,可以用于创建高性能的去中心化应用程序。它使用WebAssembly作为其智能合约的执行引擎,从而提高了智能合约的性能和安全性。
  • NEAR Protocol:NEAR Protocol是一个区块链平台,旨在为开发者提供易于使用、高性能和安全的去中心化应用程序。它使用WebAssembly作为其智能合约的执行引擎,并提供了一些工具和框架来帮助开发者编写和部署WebAssembly智能合约。
  • Solana:Solana是一个高性能的区块链平台,可以处理数千个交易,每秒钟处理数百万个交易。它使用WebAssembly作为其智能合约的执行引擎,从而实现高性能的智能合约执行。
1Python 和 JavaScript 有什么区别?

从 2022 IEEE 编程语言榜单结果来看,Python 再次摘得桂冠 ,前 10 的排名如下:

  1. Python
  2. C
  3. C++
  4. C#
  5. Java
  6. SQL
  7. JavaScript
  8. R
  9. HTML
  10. TypeScript

python

Python 是一种高级编程语言,由 Guido van Rossum 于 1989 年创造。Python 旨在提供一种简单、易于阅读和编写的语言,同时也具备强大的功能和扩展性,可以用于多种应用程序开发,包括 Web 应用程序、游戏开发、数据分析、科学计算等领域。

Python 具有许多特性,包括:

  • 简单易学:其语法简单易懂,容易学习和上手。
  • 可读性强:采用简洁的语法和缩进来表示代码块,使得代码易于阅读和理解。
  • 面向对象:支持面向对象编程,可以定义类和对象,使得代码组织更加清晰和灵活。
  • 丰富的标准库:Python 有一个丰富的标准库,包含了大量的模块和函数,可以方便地完成各种任务。
  • 跨平台性:Python 可以在多种操作系统和平台上运行,包括 Windows、Mac、Linux 等。
  • 强大的第三方库支持:Python 有大量的第三方库和框架,可以方便地扩展和增强 Python 的功能。

随着 ChatGPT 的持续火爆,带飞了整个 AI 行业,而 Python 在人工智能(AI)领域得到了广泛的应用和认可。Python 提供了大量的 AI 库和框架,例如 TensorFlow、PyTorch、Keras、Scikit-learn 等,使得 Python 成为了一个非常流行的人工智能编程语言。

JavaScript

JavaScript 是一种面向对象、动态、弱类型的编程语言,用于在网页浏览器中编写交互式的前端网页应用程序。JavaScript 是一种基于原型、事件驱动、函数式编程范式的语言。

JavaScript 最初由 Netscape 公司的 Brendan Eich 在 1995 年创建,用于给网页增加交互性和动态性。随着 Web 技术的发展,JavaScript 逐渐成为 Web 前端开发的核心语言之一。

JavaScript 与 HTML 和 CSS 一起构成了 Web 技术的三大基石。JavaScript 通过 DOM(文档对象模型)和 BOM(浏览器对象模型)提供了对网页内容和浏览器功能的访问和操作,可以实现各种动态效果、交互式操作和数据处理等功能。

随着 Web 技术的发展,JavaScript 也得到了广泛的应用和发展。JavaScript 不仅可以用于前端开发,也可以用于后端开发、移动应用开发、桌面应用开发等领域。同时,JavaScript 的生态系统非常丰富,有大量的库、框架和工具可以用于开发各种应用程序。

JavaScript 在人工智能(AI)领域的应用相对较少,但也有一些相关的应用场景。JavaScript 主要应用于 Web 前端开发,包括网页应用程序和移动应用程序的开发。在这些应用程序中,JavaScript 主要用于实现交互式操作和数据处理等功能。

随着 Web 技术的发展和 AI 技术的普及,JavaScript 在 AI 领域的应用也在不断扩大。一些 AI 库和框架也提供了 JavaScript 版本,例如 TensorFlow.jsBrain.jsSynaptic.js 等,这些库和框架可以在网页浏览器中直接运行,方便了 Web 前端开发者使用 AI 技术。

Python VS JavaScript

这里只是简单的做个比较,有个认识。两者都是流行的编程语言,但是它们在很多方面也有很大的不同,下面从最基本的知识点出发做个对比。

  • 用途:Python 通常用于后端开发、数据分析、科学计算等领域,而 JavaScript 通常用于前端开发、Web 应用程序、交互式动态效果等领域。
  • 语法:Python 的语法相对简单,易于学习和阅读。Python 采用缩进来表示代码块,而 JavaScript 则使用花括号来表示代码块。
  • 变量:Python 是一种动态类型语言,不需要在代码中显式地声明变量的类型。而 JavaScript 是一种弱类型语言,可以在变量中存储任何类型的值,也可以在代码中显式地声明变量的类型。
  • 函数:Python 和 JavaScript 的函数都是一等公民,可以作为参数传递给其他函数,也可以从函数中返回。但是,Python 中的函数定义需要使用 def 关键字,而 JavaScript 中的函数定义可以使用 function 关键字或箭头函数。
  • 模块:Python 有一个强大的模块系统,可以方便地组织代码和共享代码。JavaScript 也有模块系统,但是在不同的环境下实现有所不同,例如在浏览器中使用 ES6 模块,而在 Node.js 中主要使用 CommonJS。

总的来说,Python 和 JavaScript 在很多方面都有所不同,但它们都是强大的编程语言,具有广泛的用途和应用场景。选择使用哪种语言,取决于具体的需求和项目要求。

1JavaScript 中如何实现一个二叉堆?

在 JavaScript 中,可以通过数组来实现一个二叉堆。二叉堆分为最大堆和最小堆两种类型,本问将以最大堆为例子。

一个二叉堆可以看做是一颗完全二叉树,每个节点的值都大于等于其子节点的值(对于最大堆而言)。因此,在使用数组来实现二叉堆时,可以使用数组下标来表示完全二叉树的节点,并满足以下规则:

  1. 对于任意节点 i,其左子节点的下标为 2i+1,右子节点的下标为 2i+2
  2. 对于任意节点 i,其父节点的下标为 Math.floor((i-1)/2)

接下来,可以使用数组来实现一个最大堆。具体而言,可以定义一个数组 arr 来保存堆的元素,并定义一些方法来实现堆的常见操作,如插入元素、删除堆顶元素等。下面是一个简单的实现示例:

class MaxHeap {
    constructor() {
        this.heap = [];
    }

    // 插入元素
    insert(value) {
        this.heap.push(value);
        this.bubbleUp(this.heap.length - 1);
    }

    // 删除堆顶元素
    extractMax() {
        const max = this.heap[0];
        const end = this.heap.pop();

        if (this.heap.length > 0) {
            this.heap[0] = end;
            this.sinkDown(0);
        }

        return max;
    }

    // 上浮操作
    bubbleUp(index) {
        const element = this.heap[index];
        while (index > 0) {
            const parentIndex = Math.floor((index - 1) / 2);
            const parent = this.heap[parentIndex];
            if (element <= parent) {
                break;
            }
            this.heap[parentIndex] = element;
            this.heap[index] = parent;
            index = parentIndex;
        }
    }

    // 下沉操作
    sinkDown(index) {
        const left = 2 * index + 1;
        const right = 2 * index + 2;
        let largest = index;

        if (left < this.heap.length && this.heap[left] > this.heap[largest]) {
            largest = left;
        }

        if (right < this.heap.length && this.heap[right] > this.heap[largest]) {
            largest = right;
        }

        if (largest !== index) {
            const temp = this.heap[index];
            this.heap[index] = this.heap[largest];
            this.heap[largest] = temp;
            this.sinkDown(largest);
        }
    }
}

在上述代码中,MaxHeap 类定义了一个数组 heap 来保存堆的元素,同时实现了 insertextractMaxbubbleUpsinkDown 方法,分别用于插入元素、删除堆顶元素、上浮操作和下沉操作。

bubbleUp 方法中,使用循环来不断将新插入的元素上浮,直到满足堆的条件;sinkDown 方法中,首先找出当前节点的左子节点和右子节点,然后将当前节点与两个子节点中的最大值进行比较,如果当前节点的值小于最大值,则交换两个节点的值,并递归进行下沉操作,直到满足堆的条件。

上面定义类的使用方式如下:

const maxHeap = new MaxHeap();

maxHeap.insert(26);
maxHeap.insert(103);
maxHeap.insert(721);
maxHeap.insert(911);
maxHeap.insert(202);

console.log(maxHeap.heap); // [ 911, 721, 103, 26, 202 ]

const max = maxHeap.extractMax();
console.log(max); // 911
console.log(maxHeap.heap); // [ 721, 202, 103, 26 ]

上面代码首先创建了一个最大堆 maxHeap,插入了一些元素。然后,调用 extractMax 方法来删除堆顶元素,得到最大值并打印。最后,打印修改后的堆结构,可以看到堆顶的元素已经被删除并且堆的结构已经满足最大堆的条件。

 

1怎么在 ECMAScript 6 中定义一个类和对象?

在ES6中,可以使用 class 关键字来定义一个类,然后使用 new 关键字创建该类的对象。

下面是一个简单的例子:

// 定义一个Person类
class Person {
    // 构造函数,用于创建Person对象时初始化其属性
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    // 方法,用于返回Person对象的名字
    getName() {
        return this.name;
    }

    // 方法,用于返回Person对象的年龄
    getAge() {
        return this.age;
    }
}

// 创建一个Person对象
const person = new Person("全栈工匠", 30);

// 调用Person对象的方法
console.log(person.getName()); // 全栈工匠
console.log(person.getAge()); // 30

在上面的例子中,首先使用 class 关键字定义了一个 Person 类,该类包含了一个构造函数和两个方法。然后使用 new 关键字创建了一个 Person 对象,并将其赋值给 person 变量。最后,通过调用 person 对象的两个方法来获取该对象的名字和年龄。

值得注意的是,在ES6中类是基于原型的,因此类的方法定义在类的原型对象上。另外,ES6中的类也支持继承,可以通过 extends 关键字来创建一个子类,并且可以使用 super 关键字来调用父类的构造函数和方法。

对象在JavaScript中是一种非常重要的数据类型,它们有很多有用的方法,在平常项目开发中可以使用这些方法容易地处理对象。关于对象推荐阅读下面文章

1JavaScript 编程项目中如何使用 this 指针?

JavaScript中的 this 是一个非常重要的概念,它指向当前执行上下文的对象。由于JavaScript是一门动态语言,this 的指向在运行时才能确定,可能会因为调用方式和执行环境的不同而有所变化。

this 的指向可以通过四种调用方式来决定:

  • 作为函数调用时,this 指向全局对象(浏览器中为window对象,Node.js中为 global 对象)。
  • 作为方法调用时,this 指向调用该方法的对象。
  • 使用 call()apply() 方法调用时,this指向第一个参数传入的对象。
  • 使用new关键字调用构造函数时,this指向新创建的对象。

除了上述四种方式,还有一些特殊情况需要注意,例如箭头函数中的 this 指向是定义函数时的上下文,不会随着调用环境的改变而改变。

总之,JavaScript中的this是一个非常灵活和有用的概念,可以根据不同的调用方式来决定其指向,需要开发者在实际开发中灵活应用。

举一个具体的例子,假设有一个对象 person,它有两个方法 sayHellointroduce

const person = {
    name: "Quintion",
    age: 32,
    sayHello() {
        console.log(`Hello, my name is ${this.name}`);
    },
    introduce() {
        console.log(`I'm ${this.age} years old.`);
    },
};

如果以方法调用的方式调用 sayHello()introduce()

person.sayHello(); // Hello, my name is Quintion
person.introduce(); // I'm 32 years old.

此时 this 分别指向 person 对象,因为这两个方法是在 person 对象中定义的。

如果以函数调用的方式调用 sayHello()introduce()

const sayHello = person.sayHello;
const introduce = person.introduce;

sayHello(); // Hello, my name is undefined
introduce(); // I'm undefined years old.

此时 this 指向全局对象,因为函数调用是在全局上下文中执行的。由于全局对象并没有 nameage 属性,所以输出结果为 undefined

如果将上面的函数使用 call() 方法来调用,如下:

const sayHello = person.sayHello;
const introduce = person.introduce;

sayHello.call(person); // Hello, my name is Quintion
introduce.call(person); // I'm 32 years old.

此时 this 指向 person 对象,因为在 call() 方法的第一个参数中传入了 person 对象。

需要注意的是,如果在严格模式下使用函数调用方式,this 指向的是 undefined,而非全局对象。