JS进阶
约 2037 字大约 7 分钟
2026-06-06
手写笔记








一、原型和原型链
1.1 核心基础概念
- Q:原型和原型链的基础是什么?
- A:
- 所有对象都是通过
new函数创建 - 所有的函数也是对象
- 函数中必有
prototype属性 - 所有对象都是引用类型
- 所有对象都是通过
1.2 显式原型prototype
- 所有函数都有一个属性
prototype,称之为函数原型 - 默认情况下,
prototype是一个普通的Object对象 - 默认情况下,
prototype中有一个属性constructor,它也是一个对象,指向构造函数本身这个对象
1.3 隐式原型__proto__
- 所有的对象都有一个属性
__proto__,称之为隐式原型 - 默认情况下,隐式原型指向创建该对象的函数的原型
⚠️ 重要补充:在函数原型中加入成员,可以增强对象的功能;猴子补丁会导致原型污染,使用需谨慎。
1.4 成员访问规则
当访问一个对象的成员时:
- 看该对象自身是否拥有该成员,如果有直接使用
- 在原型链中依次查找是否拥有该成员,如果有直接使用
1.5 原型链特殊点
Function的__proto__指向自身的prototypeObject的prototype的__proto__指向null
二、原型链的应用
2.1 基础方法
⚠️ W3C不推荐使用系统成员
__proto__。
| 方法 | 作用 |
|---|---|
Object.getPrototypeOf(对象) | 获取对象的隐式原型 |
Object.create(对象) | 创建一个新对象,其隐式原型指向指定的对象 |
Object.prototype.isPrototypeOf(对象) | 判断当前对象(this)是否在指定对象的原型链上 |
Object.prototype.hasOwnProperty(属性名) | 判断一个对象自身是否拥有某个属性 |
2.2 常见应用
- 类数组转换为真数组:
Array.prototype.slice.call(类数组) - 实现继承:默认情况下,所有构造函数的父类都是
Object
三、属性描述符
3.1 定义与语法
- 语法:
Object.defineProperty(obj, prop, descriptor) - 作用:精确控制对象属性的行为
3.2 描述符属性
| 属性 | 说明 |
|---|---|
value | 属性的值 |
writable | 属性是否可写 |
get | 获取属性时调用的函数 |
set | 设置属性时调用的函数 |
enumerable | 属性是否可枚举(是否可被遍历) |
configurable | 属性描述符是否可修改,以及属性是否可删除 |
四、执行上下文
4.1 执行上下文概念
Q:什么是执行上下文?
A:一个函数运行之前,创建的一块内存空间,空间中包含有该函数执行所需要的数据,为该函数的执行提供支持。
执行上下文栈(call stack):所有执行上下文组成的内存空间
栈的特点:先进后出,后进先出
全局执行上下文:所有JS代码执行之前,都必须有这个环境
JS引擎始终执行的是栈顶的上下文
4.2 执行上下文的内容
this指向
- 直接调用函数,
this指向全局对象 - 作为函数入参,
this指向全局对象 - 通过对象调用或
new一个函数,this指向调用的对象或新对象
- 直接调用函数,
VO变量对象
Variable Object:VO中记录了该环境中所有声明的参数、变量和函数Global Object:GO,全局执行上下文中的VOActive Object:AO,当前正在执行的上下文中的VO
预编译过程
- A:确定所有形参值以及特殊变量
arguments - B:确定函数中通过
var声明的变量,将它们的值设置为undefined,如果VO中已有该名称,则直接忽略 - C:确定函数中通过函数声明声明的函数,将它们的值设置为指向函数对象,如果VO中已有该名称,则覆盖
- A:确定所有形参值以及特殊变量
💡 当一个上下文中的代码执行的时候,如果上下文不存在某个属性,则会从之前的上下文寻找。
五、作用域链
5.1 作用域链的形成
- VO中包含一个额外的属性,该属性指向创建该VO的函数本身
- 每个函数在创建时,会有一个隐藏属性
[[scope]],它指向创建该函数时的AO - 当访问一个变量时,会先查找自身VO中是否存在,如果不存在,则依次查找
[[scope]]属性
💡 某些浏览器会优化作用域链,函数的
[[scope]]中只保留要用到的数据。
六、事件循环
6.1 异步概念
异步:某些函数不会立即执行,需要等到某个时机成熟后才会执行,该函数又叫做异步函数。
6.2 浏览器的线程
- JS执行线程:负责执行JS代码
- 渲染线程:负责渲染页面
- 计时器线程:负责计时
- 事件监听线程:负责监听事件
- http网络线程:负责网络通信
6.3 事件队列与事件循环
- 事件队列:一块内存空间,用于存放时机到达的异步函数。当JS引擎空闲(执行栈没有可执行的上下文),它会从事件队列中拿出第一个函数执行。
- 事件循环(event loop):是指函数在执行栈、宿主线程、事件队列中的循环移动。
七、函数高级操作
7.1 继承
this.myPlugin.inherit = (function () {
var Temp = function () { }
return function (son, father) {
Temp.prototype = father.prototype;
son.prototype = new Temp();
son.prototype.constructor = son;
son.prototype.uber = father.prototype;
}
})();7.2 克隆
this.myPlugin.clone = function (obj, deep) {
if (Array.isArray(obj)) {
if (deep) {
// 深度克隆
var newArr = [];
for (var i = 0; i < obj.length; i++) {
newArr.push(this.clone(obj[i], deep));
}
return newArr;
}
else {
return obj.slice(); // 复制数组
}
}
else if (typeof obj === "object") {
var newObj = {};
for (var prop in obj) {
if (deep) {
// 深度克隆
newObj[prop] = this.clone(obj[prop], deep);
}
else {
newObj[prop] = obj[prop];
}
}
return newObj;
}
else {
// 函数、原始类型
return obj; // 递归的终止条件
}
}7.3 函数防抖
this.myPlugin.debounce = function (callback, time) {
var timer;
return function () {
clearTimeout(timer); // 清除之前的计时
var args = arguments; // 利用闭包保存参数数组
timer = setTimeout(function () {
callback.apply(null, args);
}, time);
}
}7.4 函数节流
this.myPlugin.throttle = function (callback, time, immediately) {
if (immediately === undefined) {
immediately = true;
}
if (immediately) {
var t;
return function () {
if (immediately) {
if (!t || Date.now() - t >= time) { // 之前没有计时 或 距离上次执行的时间已超过规定的值
callback.apply(null, arguments);
t = Date.now(); // 得到的当前时间戳
}
}
}
}
else {
var timer;
return function () {
if (timer) {
return;
}
var args = arguments; // 利用闭包保存参数数组
timer = setTimeout(function () {
callback.apply(null, args);
timer = null;
}, time);
}
}
}7.5 柯里化函数
this.myPlugin.curry = function (func) {
// 得到从下标1开始的参数
var args = Array.prototype.slice.call(arguments, 1);
var that = this;
return function () {
var curArgs = Array.from(arguments); // 当前调用的参数
var totalArgs = args.concat(curArgs);
if (totalArgs.length >= func.length) {
// 参数数量够了
return func.apply(null, totalArgs);
}
else {
// 参数数量仍然不够
totalArgs.unshift(func);
return that.curry.apply(that, totalArgs);
}
}
}7.6 函数管道
this.myPlugin.pipe = function () {
var args = Array.from(arguments);
return function (val) {
return args.reduce(function (result, func) {
return func(result);
}, val);
}
}八、核心总结
- 原型和原型链:所有对象都有
__proto__,所有函数都有prototype;成员访问沿原型链向上查找,Object.prototype.__proto__指向null。 - 原型链应用:通过
Object.getPrototypeOf等方法操作原型,实现继承和类数组转换,避免直接修改__proto__。 - 执行上下文:函数执行前创建,包含
this指向和VO变量对象;执行上下文栈遵循先进后出原则。 - 作用域链:由函数创建时的
[[scope]]属性形成,变量查找沿作用域链向上进行。 - 事件循环:JS是单线程的,异步函数由浏览器其他线程处理,时机成熟后进入事件队列,等待JS引擎空闲时执行。
- 函数高级操作:掌握继承、克隆、防抖、节流、柯里化、函数管道的实现原理和应用场景,是JS进阶的核心能力。
