找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1835

积分

0

好友

226

主题
发表于 2025-12-25 05:50:30 | 查看: 28| 回复: 0

一、微信小程序

1. 微信小程序文件结构

一个典型的微信小程序项目包含以下核心文件:

  • WXML:用于描述页面结构的文件,类似于 HTML。
  • WXSS:样式文件,用于描述 WXML 中组件的样式。
  • JS:逻辑处理文件,负责处理页面数据、交互以及网络请求。
  • JSON:配置文件,用于进行小程序的页面注册、设置页面标题或配置底部 tabBar。

此外,项目根目录下还存在三个特殊的应用级文件:

  • app.json必须存在,是小程序的全局配置文件。它负责注册页面、配置网络超时时间、设置窗口背景色、导航栏样式以及默认标题等。
  • app.js必须存在,用于监听并处理小程序的生命周期函数、声明全局变量。
  • app.wxss:可选文件,用于配置所有页面的公共 CSS 样式。

2. 事件传值

在小程序中,可以通过给 WXML 元素添加 data-* 属性来传递自定义数据。在事件处理函数中,可以通过 e.currentTarget.dataset 对象或页面的 onload 函数参数来获取这些值。需要注意的是,data- 后面的属性名不能包含大写字母,并且不能直接存放对象。

3. WXSS 与 CSS 区别

WXSS 在大部分特性上遵循 CSS 标准,但也存在一些区别:

  1. 图片引入:WXSS 中的背景图片需使用网络地址(外链)。
  2. 选择器限制:WXSS 中没有 body 元素选择器。
  3. 样式导入:WXSS 提供了 @import 语句来导入外部样式表。

4. 关联微信公众号确定用户唯一性

当小程序需要与关联的微信公众号共享用户身份时,可以调用 wx.getUserInfo 接口,并将参数 withCredentials 设为 true。成功后会返回一个包含加密用户信息的 encryptedData 字段,其中包含可用于唯一标识用户的 union_id。开发者需要将这个加密数据传递给后端服务器,由后端使用微信提供的会话密钥进行对称解密,从而获得 union_id

5. 微信小程序与 Vue 区别

尽管微信小程序的开发模式与 Vue 有些相似,但在细节上存在显著差异:

对比维度 微信小程序 Vue
生命周期 相对简单,有 onLoad, onShow, onReady 拥有完整的生命周期钩子函数,如 created, mounted, updated
数据绑定 使用 {{}} 语法 同样使用 {{}} 语法,但在模板中更常用 :v-bind
显示/隐藏 使用 wx:ifhidden 属性 使用 v-ifv-elsev-show 指令
事件绑定 使用 bindtapcatchtap(阻止冒泡) 使用 v-on:event@event 语法糖
双向绑定 需要手动通过事件获取表单元素的值 使用 v-model 指令实现数据的自动双向绑定

二、Webpack

1. 打包体积优化思路

为了减少最终打包产物的体积,可以采取以下策略:

  • 提取第三方库:使用 DllPluginexternals 配置将稳定的第三方库(如 react, lodash)单独分离或通过 CDN 引入。
  • 代码压缩:使用 TerserWebpackPlugin(或 UglifyJsPlugin)对 JS 代码进行混淆和压缩。
  • 启用 Gzip:在服务器端配置 Gzip 压缩,对传输的资源进行压缩。
  • 按需加载:使用 import() 动态导入语法或 require.ensure(Webpack 旧版本)实现路由或组件的按需加载。
  • 优化 Source Map:在生产环境选择合适的 devtool 配置(如 source-map),在开发环境选择更快的选项(如 eval-cheap-module-source-map)。
  • CSS 分离:使用 MiniCssExtractPlugin 将 CSS 从 JS 中提取出来,单独打包成文件。
  • 移除冗余插件:检查并移除生产环境不必要的插件。

2. 打包效率优化

提升 Webpack 构建速度可以从这些方面入手:

  • 增量构建与热更新:在开发环境充分利用 Webpack 的缓存和模块热替换(HMR)功能。
  • 简化开发构建:在开发环境中跳过提取 CSS、计算文件哈希等耗时操作。
  • 合理配置 Loader:通过 testincludeexclude 精确指定 Loader 的作用范围,避免不必要的文件处理。
  • 启用 Loader 缓存:为 babel-loader 等转换开销大的 Loader 开启缓存 (cacheDirectory: true)。
  • 使用新特性与插件
    • 并行处理:使用 thread-loader 将耗时的 Loader 放在独立线程中运行。
    • 缓存:使用 cache-loader 或 Webpack 5 自带的持久化缓存。
    • 预编译:使用 DllPlugin 将不常变动的第三方库提前打包。

3. Loader 编写

Loader 本质上是一个 Node.js 模块,它导出一个函数。当 Webpack 需要转换某种类型的资源时,就会调用这个函数。在函数内部,可以通过 this 上下文访问 Webpack 提供的 Loader API。

// reverse-txt-loader.js
module.exports = function(src) {
  // 这是一个简单的示例:将文本内容反转
  var result = src.split('').reverse().join('');
  // Loader 需要返回一个 JS 模块代码字符串
  return `module.exports = '${result}'`;
}

// 在 webpack.config.js 中使用
module.exports = {
  module: {
    rules: [
      {
        test: /\.txt$/,
        use: ['./path/reverse-txt-loader']
      }
    ]
  }
};

4. Webpack Plugin 与优化

构建过程优化

  • 减少编译范围:使用 ContextReplacementPlugin(用于限定某些库的语言包)、IgnorePlugin(忽略某些模块)。
  • 并行压缩:配置 TerserWebpackPlugin 开启多进程并行压缩。
  • 预编译链接库:使用 DllPluginDllReferencePlugin 组合,将第三方库提前编译好,提升后续构建速度。

输出产物优化

  • Tree Shaking:在生产模式下默认启用,移除未使用的代码。
  • Scope Hoisting:使用 ModuleConcatenationPlugin(生产模式默认启用)将模块提升到一个作用域内,减少函数声明和内存开销。
  • 拆包与缓存:使用 SplitChunksPlugin 智能拆分公共代码和第三方库,并配合 [contenthash] 实现长期缓存。

三、编程题

1. 通用事件侦听器函数

// event(事件)工具集
markyun.Event = {
  // 绑定事件 (兼容IE)
  addEvent: function(element, type, handler) {
    if (element.addEventListener) {
      element.addEventListener(type, handler, false);
    } else if (element.attachEvent) {
      element.attachEvent('on' + type, function() {
        handler.call(element);
      });
    } else {
      element['on' + type] = handler;
    }
  },
  // 移除事件
  removeEvent: function(element, type, handler) {
    if (element.removeEventListener) {
      element.removeEventListener(type, handler, false);
    } else if (element.detachEvent) {
      element.detachEvent('on' + type, handler);
    } else {
      element['on' + type] = null;
    }
  },
  // 阻止事件冒泡
  stopPropagation: function(ev) {
    if (ev.stopPropagation) {
      ev.stopPropagation();
    } else {
      ev.cancelBubble = true;
    }
  },
  // 取消事件默认行为
  preventDefault: function(event) {
    if (event.preventDefault) {
      event.preventDefault();
    } else {
      event.returnValue = false;
    }
  },
  // 获取事件目标元素
  getTarget: function(event) {
    return event.target || event.srcElement;
  }
};

2. 判断对象是否为数组

function isArray(arg) {
  if (typeof arg === ‘object’) {
    return Object.prototype.toString.call(arg) === ‘[object Array]’;
  }
  return false;
}

3. 冒泡排序

var arr = [3, 1, 4, 6, 5, 7, 2];
function bubbleSort(arr) {
  for (var i = 0; i < arr.length - 1; i++) {
    for (var j = 0; j < arr.length - i - 1; j++) {
      if (arr[j + 1] < arr[j]) {
        var temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
    }
  }
  return arr;
}
console.log(bubbleSort(arr));

4. 快速排序

var arr = [3, 1, 4, 6, 5, 7, 2];
function quickSort(arr) {
  if (arr.length == 0) {
    return [];
  }
  var cIndex = Math.floor(arr.length / 2);
  var c = arr.splice(cIndex, 1);
  var l = [];
  var r = [];
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] < c) {
      l.push(arr[i]);
    } else {
      r.push(arr[i]);
    }
  }
  return quickSort(l).concat(c, quickSort(r));
}
console.log(quickSort(arr));

5. 计算字符串字节长度

function GetBytes(str) {
  var len = str.length;
  var bytes = len;
  for (var i = 0; i < len; i++) {
    if (str.charCodeAt(i) > 255) bytes++;
  }
  return bytes;
}
alert(GetBytes(“你好,as”));

6. bind 函数实现

// 简化版 bind,仅实现上下文绑定
Function.prototype.bind = function(ctx) {
  var fn = this;
  return function() {
    fn.apply(ctx, arguments);
  };
};

7. 深拷贝函数

// 方法一:为 Object 原型添加方法 (不推荐,会污染全局原型)
Object.prototype.clone = function() {
  var o = this.constructor === Array ? [] : {};
  for (var e in this) {
    o[e] = typeof this[e] === “object” ? this[e].clone() : this[e];
  }
  return o;
}

// 方法二:独立的深拷贝函数
function clone(Obj) {
  var buf;
  if (Obj instanceof Array) {
    buf = [];
    var i = Obj.length;
    while (i—) {
      buf[i] = clone(Obj[i]);
    }
    return buf;
  } else if (Obj instanceof Object) {
    buf = {};
    for (var k in Obj) {
      buf[k] = clone(Obj[k]);
    }
    return buf;
  } else {
    return Obj;
  }
}

8. 点击获取 index(考察闭包)

<ul id=“test”>
  <li>这是第一条</li>
  <li>这是第二条</li>
  <li>这是第三条</li>
</ul>
// 方法一:利用 DOM 对象属性存储索引
var lis = document.getElementById(‘test’).getElementsByTagName(‘li’);
for (var i = 0; i < 3; i++) {
  lis[i].index = i; // 将索引存储在 DOM 元素的自定义属性上
  lis[i].onclick = function() {
    alert(this.index); // 点击时通过 this 访问
  };
}

// 方法二:使用闭包保存索引值
var lis = document.getElementById(‘test’).getElementsByTagName(‘li’);
for (var i = 0; i < 3; i++) {
  lis[i].onclick = (function(a) {
    return function() {
      alert(a); // 内部的匿名函数可以访问外部函数的参数 a
    }
  })(i);
}

9. 代理 console.log 方法

// 单参数版本
function log(msg) {
  console.log(msg);
}

// 多参数版本(使用 apply 传递参数列表)
function log() {
  console.log.apply(console, arguments);
}

10. 输出今天日期

var d = new Date();
var year = d.getFullYear();
var month = d.getMonth() + 1;
month = month < 10 ? ‘0’ + month : month;
var day = d.getDate();
day = day < 10 ? ‘0’ + day : day;
alert(year + ‘-’ + month + ‘-’ + day);

11. 随机选取并排序

var iArray = [];
function getRandom(istart, iend) {
  var iChoice = iend - istart + 1;
  return Math.floor(Math.random() * iChoice + istart);
}
for (var i = 0; i < 10; i++) {
  iArray.push(getRandom(10, 100));
}
iArray.sort(); // 默认按字符串排序,如需按数值排序应使用 iArray.sort((a,b) => a-b)

12. URL 参数提取

function serilizeUrl(url) {
  var result = {};
  url = url.split(“?”)[1];
  var map = url.split(“&”);
  for (var i = 0, len = map.length; i < len; i++) {
    result[map[i].split(“=”)[0]] = map[i].split(“=”)[1];
  }
  return result;
}

13. 清除字符串前后空格

if (!String.prototype.trim) {
  // 兼容旧环境,为 String 原型添加 trim 方法
  String.prototype.trim = function() {
    return this.replace(/^\s+/, “”).replace(/\s+$/, “”);
  };
}
var str = “ \t\n test string “.trim();
alert(str == “test string”); // true

14. 间隔输出数字

for (var i = 0; i < 10; i++) {
  (function(j) {
    setTimeout(function() {
      console.log(j + 1);
    }, j * 1000);
  })(i);
}

15. 判断回文字符串

function run(input) {
  if (typeof input !== ‘string’) return false;
  return input.split(‘’).reverse().join(‘’) === input;
}

16. 数组扁平化

function flatten(arr) {
  return arr.reduce(function(prev, item) {
    return prev.concat(Array.isArray(item) ? flatten(item) : item);
  }, []);
}

四、其他

1. 负载均衡

负载均衡是指将网络流量或工作任务分配到多台服务器上,以避免单台服务器过载,从而提升整体服务的可用性、响应速度和吞吐量。

常见实现方式

  • HTTP 重定向负载均衡:由调度服务器根据策略,通过 HTTP 302 状态码将客户端请求重定向到目标服务器。缺点是增加了客户端的请求延迟,且调度过程对客户端透明性差。
  • DNS 负载均衡:在 DNS 服务器中为一个域名配置多个 IP 地址(A 记录),DNS 服务器根据负载策略返回其中一个 IP。优点是实现简单,但监控性和灵活性较弱。
  • 反向代理负载均衡:客户端将请求发往统一的反向代理服务器(如 Nginx),由代理服务器根据负载均衡算法(轮询、加权、IP Hash等)将请求转发给内部的实际应用服务器。对反向代理服务器的性能和稳定性要求较高。

2. CDN

CDN(内容分发网络)通过在全球各地部署边缘节点服务器,将源站内容缓存到离用户更近的节点上。当用户请求资源时,系统会将其导向到距离最近、响应最快的节点,从而避开互联网主干网的拥堵,实现内容的快速、稳定传输。

3. 内存泄漏

定义:在程序中,已动态分配的堆内存由于某些原因未能被释放或无法释放,导致可用内存不断减少,可能引发性能下降或程序崩溃。

JavaScript 中常见的内存泄漏场景

  • 意外的全局变量:未使用 varletconst 声明的变量会变成全局对象的属性。
  • 被遗忘的定时器或回调函数setInterval 或事件监听器在组件销毁后未被清除。
  • 脱离 DOM 的引用:在 JavaScript 中缓存了某个 DOM 元素的引用,即使该元素已从页面移除,仍无法被垃圾回收。
  • 闭包的不当使用:闭包可以维持函数内局部变量,若不慎引用了不再需要的大对象,会导致其无法释放。

避免策略

  • 严格管理变量作用域,避免不必要的全局变量。
  • 确保在组件销毁或页面卸载时,清理定时器、事件监听器以及异步回调。
  • 谨慎使用闭包,确保其不会长期持有对大对象的引用。
  • 对于复杂的单页应用(SPA),可以使用开发者工具的内存分析功能定期检查。

4. Babel 原理

Babel 是一个 JavaScript 编译器,其主要工作流程如下:

  1. 解析 (Parsing):使用 babylon 解析器将 ES6/ES7 源代码转换成抽象语法树 (AST)
  2. 转换 (Transforming):通过 babel-traverse 遍历 AST,并利用配置好的插件 (Plugins) 对树节点进行增删改,将新的 ES6/ES7 语法转换为 ES5 等目标语法。
  3. 生成 (Generation):最后,由 babel-generator 将转换后的 AST 重新生成为 ES5 代码字符串。

5. JS 自定义事件

在 JavaScript 中创建和触发自定义事件需要三个核心步骤:

  1. 创建事件:使用 document.createEvent(‘Event’) 方法创建一个新的事件对象。
  2. 初始化事件:调用事件对象的 initEvent(type, bubbles, cancelable) 方法,定义事件类型、是否冒泡等属性。
  3. 触发事件:在目标 DOM 元素上调用 dispatchEvent(event) 方法,派发该自定义事件。

6. 前后端路由差别

  • 后端路由:每次路由跳转(即使是页面内的链接点击)都会向服务器发起一次新的 HTTP 请求,服务器根据 URL 返回一个完整的 HTML 页面。这种方式在早期多页应用中常见。
  • 前端路由:在单页应用(SPA)中,路由的切换由 JavaScript 控制。当 URL 变化时,JS 会拦截这个变化,根据路由映射关系动态地操作 DOM(例如显示/隐藏组件,或请求新的数据与模板进行组合),而不会重新加载整个页面。这提供了更流畅的用户体验。



上一篇:ClickHouse大数据集合运算实战:AggregatingMergeTree与groupBitmap优化用户画像分析
下一篇:快手直播遭“万播齐发”攻击:剖析黑客五大核心目的与安全漏洞
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-10 08:51 , Processed in 0.201848 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表