为了账号安全,请及时绑定邮箱和手机立即绑定
2. 什么是 Vue-Cli

vue-cli 是由 Vue 提供的一个官方 cli,专门为单页面应用快速搭建繁杂的脚手架。它是用于自动生成 vue.js+webpack 的项目模板。

this 使用问题

大部分开发者都会合理、巧妙的运用 this 关键字。初学者容易在 this 指向上犯错,如下面这个 Vue 组件:<div id="app"></div><script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.min.js"></script><script> // 发送post请求 const post = (cb) => { // 假装发了请求并在200ms后返回了服务端响应的内容 setTimeout(function() { cb([ { id: 1, name: '小红', }, { id: 2, name: '小明', } ]); }); }; new Vue({ el: '#app', data: function() { return { list: [], }; }, mounted: function() { this.getList(); }, methods: { getList: function() { post(function(data) { this.list = data; console.log(this); this.log(); // 报错:this.log is not a function }); }, log: function() { console.log('输出一下 list:', this.list); }, }, });</script>这是初学 Vue 的同学经常碰到的问题,为什么这个 this.log() 会抛出异常,打印了 this.list 似乎也是正常的。这其实是因为传递给 post 方法的回调函数,拥有自己的 this,有关内容可以查阅 this章节。不光在这个场景下,其他类似的场景也要注意,在写回调函数的时候,如果在回调函数内要用到 this,就要特别注意一下这个 this 的指向。可以使用 ES6 的箭头函数 或者将需要的 this 赋值给一个变量,再通过作用域链的特性访问即可:<div id="app"></div><script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.min.js"></script><script> // 发送post请求 const post = (cb) => { // 假装发了请求并在200ms后返回了服务端响应的内容 setTimeout(function() { cb([ { id: 1, name: '小红', }, { id: 2, name: '小明', } ]); }); }; new Vue({ el: '#app', data: function() { return { list: [], }; }, mounted: function() { this.getList(); }, methods: { getList: function() { // 传递箭头函数 post((data) => { this.list = data; console.log(this); this.log(); // 报错:this.log is not a function }); // 使用保留 this 的做法 // var _this = this; // post(function(data) { // _this.list = data; // console.log(this); // _this.log(); // 报错:this.log is not a function // }); }, log: function() { console.log('输出一下 list:', this.list); }, }, });</script>这个问题通常初学者都会碰到,之后慢慢就会形成习惯,会非常自然的规避掉这个问题。

5. init 初始化块

与 Java 不同的是在 Kotlin 中还存在 init 初始化块的概念,它属于构造器函数一部分,只是在代码形式看似两者是分离的。如果我们需要在初始化时进行其他的额外操作时,这时候就需要 init 语句块来执行,有个有趣的点需要注意的是,在 init 初始化块中,是可以直接访问构造器函数中参数的。class Bird(val color: String = "green", val age: Int = 3) { //...}//上述代码实际上等同于下面代码class Bird(color: String = "green", age: Int = 3) { val color: String = color val age: String = age}//所以针对没有val修饰构造器函数参数,只能在init初始化块中访问,而一般成员函数是无法访问的class Bird(color: String = "green", age: Int = 3) {//当color没有val修饰 init { println("color: $color")//可以看到在init块中使用构造器函数中的color参数 } fun printInfo() { println(color)//非法访问 }}对于 init 初始化块,是可以存在多个的,它们执行顺序是从上到下依次执行。class Bird(color: String = "green", age: Int = 3) { init { println("color: $color")//init块1 } init { println("age: $age")//init块2 }} //执行的顺序是,先输出init块1中日志再输出init块2中的日志对于 init 初始化块和从构造器同时存在,它们的执行顺序是怎么样的呢?是先执行完所有的 init 初始化块,再执行从构造器函数中代码。可以上述例子修改一下即可:class Bird(color: String = "green", age: Int = 3) { init { println("color: $color")//init块1 } init { println("age: $age")//init块2 } constructor(color: String, age: Int, type: String) : this(color, age) { println("constructor executed") }}fun main() { val smallBird = Bird(color = "blue", age = 8, type = "small")}//输出结果color: blueage: 8constructor executedProcess finished with exit code 0

安装 webpack

执行命令安装 webpack 环境:npm i -D webpack webpack-cli在根目录下新建配置文件 webpack.config.js,输入内容:const path = require('path');module.exports = { mode: 'none', entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, module: { rules: [ { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/, }, ], },};

4. 使用NPM的方法

使用NPM的方法进行安装需要先在本地安装Node环境。3.1、Windows 上安装 Node.js32 位安装包下载地址64 位安装包下载地址下载对应的安装包后,双击安装包,傻瓜式下一步安装就好了。3.2、Mac 上安装 Node.js1、在官方下载网站下载 pkg 安装包,直接点击安装即可。2、使用 brew 命令来安装:brew install nodebrew install node# 查看本地node环境$ node -vv10.16.0在用 Vue 构建大型应用时推荐使用 NPM 安装。当然,仅仅使用npm install是不能完整搭建Vue开发环境的。还需要webpack或 Browserify 等模块打包器配合使用。# 创建项目目录$ mkdir demo# 进入项目文件夹$ cd demo$ npm init -y# 最新稳定版$ npm install vue# 安装指定版本Vue$ npm install vue@2.6.3安装完成后可以查看到demo目录下多了 node_module/vue 文件夹。说明Vue成功安装。

2.2 使用 Webpack

Webpack 是模块化打包工具,它兼容现在很多模块化加载方式,本节课程也主要使用 Webpack 的方式来学习 ES6 的模块化。Webpack 需要一定的学习成本可以在官网 上学习,这里就不进行介绍了,下面给出 webpack.config.js 的配置如下:let path = require("path");let HtmlWebpackPlugin = require("html-webpack-plugin");module.exports = { entry: "./src/index.js", output: { filename: "bundle.js", }, plugins: [ new HtmlWebpackPlugin({ template: './public/index.html' // 模版文件 }) ], module: { rules: [ { test: /\.js$/, use: { loader: "babel-loader", }, }, ], },};

Vue 简介

大家好,今天我们开始一个新专题 — Vue。这个专题我们重点针对如何使用 Vue 开发项目。本文我们主要先介绍一下 Vue 是什么?

3.1 适用问题

首先,在利用动态规划算法之前,我们需要清楚哪些问题适合用动态规划算法求解。一般而言,能够利用动态规划算法求解的问题都会具备以下两点性质:最优子结构: 利用动态规划算法求解问题的第一步就是需要刻画问题最优解的结构,并且如果一个问题的最优解包含其子问题的最优解,则此问题具备最优子结构的性质。因此,判断某个问题是否适合用动态规划算法,需要判断该问题是否具有最优子结构。Tips: 最优子结构的定义主要是在于当前问题的最优解可以从子问题的最优解得出,当子问题满足最优解之后,才可以通过子问题的最优解获得原问题的最优解。重叠子问题: 适合用动态规划算法去求解的最优化问题应该具备的第二个性质是问题的子问题空间必须足够” 小 “,也就是说原问题递归求解时会重复相同的子问题,而不是一直生成新的子问题。如果原问题的递归算法反复求解相同的子问题,我们就称该最优化问题具有重叠子问题。Tips: 在这里,我们需要注意是,与适用动态规划算法去求解的问题具备重叠子问题性质相反,前面我们介绍的分治算法递归解决问题时,问题的子问题都是互不影响,相互独立的,这个也是我们在选用动态规划算法还是分治法解决问题时的一个判断条件。

4. nvue 和 vue 相互通讯

如果使用 vue 就能实现项目需求,并且对项目性能没有很高的要求,我们尽量只使用 vue 来进行开发,不建议使用 nvue 来开发项目。因为 nvue 除了 css 写法受限之外,在 vue 和 nvue 页面混用的项目中,通讯也是一个大问题。下面来看看在 vue 和 nvue 页面混用的项目中,nvue 和 vue 如何相互通讯。

3. indexOf () 的问题

indexOf() 在查询数组中元素时存在一些问题,下面我们就来看看为什么 ES6 要引入 includes() 方法。在 ES5 中使用 indexOf() 方法在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回 -1。但是查找数组时存在一定缺陷,indexOf 不能判断数组中是否有 NaN,对于数组中的空项也不能判断。var arr1 = [,,,,,];var arr2 = [null, undefined, NaN];console.log(arr1[0], arr1[1]) // undefined undefinedarr1.indexOf(undefined) // -1arr2.indexOf(NaN); // -1上面的代码可以看到,在第 1 行中数组的每一项都是空的, 使用 indexOf() 查找返回的结果为 -1,没有查到 undefined 值,但从第 3 行打印的结果可以看到其实空数组的每一项都是 undefined。另外,还有个问题 indexOf() 不能解决,数组中有 NaN 时查询不了,返回的结果也是 -1。ES6 的includes() 可以完美解决上面的问题,看如下示例:[,,,,,].includes(undefined) // true[null, undefined, NaN].includes(NaN)] // true从上面的代码可以看出,使用 includes() 查询可以得到正确的结果。indexOf 返回的是数值型的,而 includes 返回的是布尔型的,方便逻辑判断。如下实例:var arr = ['imooc', 'ES6', 'wiki'];if (arr.includes('ES6')) { // todo}if (arr.indexOf('ES6') !== -1) { // todo}

6. ABA 问题

ABA 问题描述:假设有两个线程,线程 1 和线程 2,线程 1 工作时间需要 10 秒,线程 2 工作需要 2 秒;主内存值为 A,第一轮线程 1 和线程 2 都把 A 拿到自己的工作内存;第 2 秒,线程 2 开始执行,线程 2 工作完成把 A 改成了 B ;第 4 秒,线程 2 把 B 又改成了 A,然后就线程 2 进入休眠状态;第 10 秒,线程 1 工作完成,看到期望为 A 真实值也是 A 认为没有人动过,其实 A 已经经过了修改,只不过又改了回去,然后线程 1 进行 CAS 操作。ABA 问题解决:为了解决这个问题,在每次进行操作的时候加上一个版本号或者是时间戳即可。

过拟合问题

在我们之前的学习之中,我们或多或少都会遇到一些训练时间的问题。比如“训练时间越长是不是最后的结果就会越好?”等问题。答案当然是否定的,这是因为在训练的过程之中会遭遇到“过拟合”的问题,这是一种随着训练时间不断加长而产生的问题,那么这节课我们就来学习一下什么是过拟合,同时了解一下 TensorFlow 之中的避免过拟合的简单的方法。这节课之中,我们使用之前学习过的猫狗分类的例子进行示例演示。

2. 定位问题SQL

定位 MySQL 的问题 SQL,主要有两种方法,查看当前线程(show processlist)和慢日志。一般来说,当前发生的问题用到 show processlit,事后分析用到慢日志。

4. Vue 的优点

那么 Vue 有哪些优点呢?Vue 是一个轻量级框架。Vue 的体积只有几十 kb,非常轻量;Vue 简单易学,对新手友好度高;双向数据绑定。Vue 提供了双向数据绑定 v-model 的语法糖,让我们可以避免 DOM 操作;组件化开发。我们可以把页面拆分成大大小小的组件,这样大大提高了代码的可复用率和可读性。

分号导致的问题

在 JavaScript 中分号是可选的,解释器会自动对分号进行补全。如果选择不写分号,需要注意一些使用上的问题。不写分号,相当于将插入分号的权利递交给解释器,对于某些情况,可能会出现非预期的效果:

Sublime Text 常见问题

本章节主要介绍了几个日常开发过程中经常碰到的问题,可能每个人碰到的不一样,这里仅供参考。如果大家有碰到其他问题可以上网查阅相关资料。

2.2 yarn init

解释:初始化项目或者文件夹使用场景:当你想初始化一个项目,或者文件夹,并生成 package.json 文件时,使用此命令。具体使用:我们初始化一个示例项目,执行: yarn init默认配置项我们直接 enter 默认,运行结果如下:此时,我们就使用 yarn,初始化了一个项目

1. 问题的产生

访问关系数据库的传统方式是:拼接 SQL 语句。例如,向数据库中插入一条数据,根据要插入的数据拼接一条 SQL INSERT 语句,下面的 Python 程序使用 SQL 语句向数据库中插入一条学生的信息:sno = '20201916'name = '张三'age = 20gender = 'male'sql = 'INSERT INTO students(sno, name, age, gender) VALUES("%s", "%s", %d, "%s")' % (sno, name, age, gender)rows = cursor.execute(sql)在第 5 行,Python 程序使用字符串运算符 % 根据参数 sno、name、age 和 gender 最终生成一条 SQL 语句:INSERT INTO students(sno, name, age, gender) VALUES("", "张三", 20, "male");随着项目越来越大,通过拼接 SQL 语句访问数据库存在如下的问题:1. 繁琐易错在上面的例子中,第 5 行代码用于拼接 INSERT 语句,INSERT 语句需要插入 4 个字段,该行代码较长,无法在一行显示。在实际的软件开发中,INSERT 语句可能需要插入 10 个以上的字段,那么拼接 INSERT 语句的代码则非常的繁琐易错。下面的 SQL 语句来自于一个实际的项目:sql = "INSERT INTO Flights(FlightID, AircraftModel, RegisterID, Direction, ExpectApronTime, RunwayID, ApronID, AirwayID, TaxiwayTimes, AirwayTimes, Rank) VALUES('%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', %d)" % (flightID, aircraftModel, registerID, direction, expectApronTime, runwayID, apronID, airwayID, taxiwayTimes, airwayTimes, rank)要插入的数据包含有 11 个字段,造成 SQL 语句非常的冗长,需要在多行中才能完全显示,程序的可读性极差。2. SQL 语句重复利用率低越复杂的 SQL 语句条件越多、代码越长,在实际的项目中,会出现很多很相近的 SQL 语句。3. Web 安全漏洞直接使用 SQL 语句存在有 Web 安全漏洞的问题:通过把 SQL 命令插入到页面请求的查询字符串,最终达到欺骗服务器执行恶意的 SQL 命令。下面的 SQL 语句根据页面请求中的用户名和密码查询数据库:username = 从页面请求中获取用户名password = 从页面请求中获取密码sql = 'select * from users where username = "%s" and password = "%s"' % (username, password)在第 3 行的 SELECT 语句中,where 条件进行权限检查,只有 username 和 password 与数据库表 users 中的数据匹配时,才返回有效数据,因此,只有用户输入正确的用户名和密码才可以获取数据。这条 SQL 语句存在有安全漏洞,假设用户在页面中输入的用户名为 admin"# (共 7 个字符,前 5 个字符是 admin,后面 2 个字符是 " 和 #),密码为 123456,则最终拼接的 SQL 语句如下:select * from users where username = "admin"#" and password = "123456"在 SQL 中,# 是行注释,因此上述 SQL 语句相当于:select * from users where username = "admin"只要数据库表 users 中有 admin 这条记录,执行该条 SQL 语句就会返回数据,这样对 password 的检查就彻底失效了。

2. 什么是背包问题?

假设我们一共有 n 种物品,每种物品 i 的价值为 vi,重量为 wi,我们有一个背包,背包的容量为 c(最多可以放的物品重量不能超过 c),我们需要选择物品放入背包中,使得背包中选择的物品中总价值最大,在这里每个物品可以只选择部分。这便是我们常说的背包问题背包问题是一种常见的可以用贪心算法进行求解的问题,接下来,就让我们看看如何利用贪心算法解决背包问题。

4.1 let 及 const 常见问题

在工作中经常会遇到 var、let 及 const 以下几个问题:什么是变量提升?什么是暂时性死区?var、let 及 const 区别?这些问题在上面的讲解中都有提到过,这里我们总结一下:

3.2 isNaN () 的问题

默认情况全局下存在方法 isNaN () 用了判断是否为 NaN 值,它要求接收的是数值类型的参数,但是当参数不是 Number 类型, isNaN 函数会首先尝试将这个参数转换为数值,然后才会对转换后的结果是否是 NaN 进行判断。实例:isNaN(NaN); // trueisNaN(undefined); // trueisNaN('undefined')// trueisNaN({}); // trueisNaN(true); // falseisNaN(null); // falseisNaN(37); // false// stringsisNaN("37"); // false: 可以被转换成数值37isNaN("37.37"); // false: 可以被转换成数值37.37isNaN("37,5"); // trueisNaN('123ABC'); // true: parseInt("123ABC")的结果是 123, 但是Number("123ABC")结果是 NaNisNaN(""); // false: 空字符串被转换成0isNaN(" "); // false: 包含空格的字符串被转换成0// datesisNaN(new Date()); // falseisNaN(new Date().toString()); // trueisNaN("imooc") // true: "blabla"不能转换成数值 // 转换成数值失败, 返回NaN结合上面 NaN 是如何产生的例子的结果可以看出,使用 isNaN 来判断返回的是 true,这显然不是我们想要的结果。针对这样的问题,ES6 做了修补,下面我们看 ES6 中的 isNaN 方法。

2.2 带来的问题

因为应用程序可能依赖特定版本的包,当系统中存在多个项目时,可能会出现冲突。例如:有两个项目:项目 A 和 项目 B;项目 A 依赖于 redis-3.5.3;项目 B 依赖于 redis-3.0.0。如果,需要同时进行两个项目的开发,则必须:开发项目 A 时,卸载系统中现有的 redis 包,安装 redis-3.5.3;开发项目 B 时,卸载系统中现有的 redis 包,安装 redis-3.0.0。在两个项目之间切换时,用户需要频繁的安装和卸载 redis 包,显然是很不合理的。那么,这种不合理应该如何解决呢?在 Python 开发中有个神器叫做 virtual 就是专门用来解决问题的,下面我们就来看下 virtual 这个神器到底神在哪里?

5. Postman 安装问题解决

下面会列举一些 Postman 在安装时的常见问题。但是因环境的差异,你所遇到的问题在下面可能并没有列举,如果遇见这种情况你可以去Postman 社区论坛 上看一下别的用户发布的关于安装问题的帖子,如果还是不能解决的话,你也可以发布一个新的帖子来寻求帮助。

3. 使用插件

通过全局方法 Vue.use () 使用插件。它需要在你调用 new Vue () 启动应用之前完成:Vue.use(MyPlugin)new Vue({ // ...组件选项})也可以传入一个可选的选项对象:Vue.use(MyPlugin, { someOption: true })Vue.use 会自动阻止多次注册相同插件,即使多次调用也只会注册一次该插件。Vue.js 官方提供的一些插件 (例如 vue-router) 在检测到 Vue 是可访问的全局变量时会自动调用 Vue.use ()。然而在像 CommonJS 这样的模块环境中,你应该始终显式地调用 Vue.use ():// 用 Browserify 或 webpack 提供的 CommonJS 模块环境时var Vue = require('vue')var VueRouter = require('vue-router')// 不要忘了调用此方法Vue.use(VueRouter)awesome-vue 集合了大量由社区贡献的插件和库。

4. 常见问题

一般我们比较常见的问题就是安装 sass 或者 node-sass 特别慢导致安装失败,由于国内网络的限制我们需要切换 gem 和 npm 源。切换 gem 源使用如下命令:gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/// 查看 gem 源gem sources -l使用 npm 安装 node-sass 过慢的话我们可以使用 cnpm 来替换 npm ,或者使用如下命令切换 npm 源:npm install -g mirror-config-china --registry=http://registry.npm.taobao.org

2.RabbitMQ 集群常见问题介绍

在我们搭建好 RabbitMQ 集群之后,无论我们采用哪种搭建方式,我们本身都需要知道一些集群中容易出现的问题,这样我们在遇到集群出现问题的时候,我们才不会那么慌张。问题一:集群宕机集群宕机这一问题,是无论搭建什么样的集群,都是比较容易出现的一种问题,这种问题出现的频率高,同时,也是最容易修复的一种问题。那么什么是集群宕机呢?集群宕机其实指的就是我们的 RabbitMQ 集群,所在的服务器节点,由于种种原因导致我们的 RabbitMQ Server 服务非自然停止,或意外退出的一种现象。如果我们的 RabbitMQ Server 宕机了,就表明,我们的 RabbitMQ 集群中有一个或多个 RabbitMQ Server 服务节点不能够再继续提供服务了,那么所有有关 RabbitMQ Server 服务的请求都要在正常运行的服务节点上进行处理,可想而知,这种情况下,RabbitMQ 服务器所承受的压力有多大。上述是集群宕机之后所造成的一个直接结果,还有一种间接结果也是非常致命的,那就是由于集群节点服务的宕机,用户请求只能在可用的集群节点上进行处理,如果这个节点的服务器配置较低,那么很可能由于处理请求数量的激增,导致这个节点的服务器直接崩掉,也就是直接关机,或者服务器不再返回任何响应,这种情况也是比较严重的。问题二:集群间通信延迟集群间通信延迟也是比较容易出现的一种问题,这种问题我们从字面意思上来看,基本上可以知道个大概。集群间通信延迟问题,指的就是,RabbitMQ 集群中的一个节点向另一个节点传递数据,或者从另一个节点中获取数据时,目标节点不能及时将所需数据进行返回,导致的请求节点出现长时间等待的一种现象。那么集群间通信延迟问题造成的直接影响就是,用户的数据不能同步更新,导致用户看到的数据是不准确的,这极大影响了用户的使用体验。集群间通信延迟问题造成的间接影响就是,如果我们的目标节点迟迟不能返回响应数据,就会导致请求节点一直等待,那么位于请求节点上后续的用户请求就不能得到处理,这就是请求阻塞现象。问题三:集群数据文件丢失集群数据文件丢失问题相对而言,出现的频率较低,但是我们应该也要进行简单的了解。集群数据文件丢失问题,指的就是,位于服务器上的 RabbitMQ Server 节点突然出现的一种服务器磁盘数据丢失现象, 这种问题不出现还好,一旦出现,一般都是致命性的问题,往往恢复的时间也是最长的。集群数据文件丢失问题的出现,会直接影响用户无法打开我们的项目或应用,给用户造成非常严重的体验问题,同时,也会间接导致用户关键数据的丢失,造成我们的项目或者应用用户的一个流失。以上三种问题类型,是 RabbitMQ 集群中比较常见的三种问题类型,无论出现哪种问题,我们都应该知道一个大概的解决措施,或者恢复方案,下面让我们先来分析一下产生这三种问题的常见原因。

6. 线程安全问题

谈到线程安全问题,我们先说说什么是共享资源。共享资源:所谓共享资源,就是说该资源被多个线程所持有或者说多个线程都可以去访问该资源。线程安全问题是指当多个线程同时读写一个共享资源并且没有任何同步措施时,导致出现脏数据或者其他不可预见的结果和问题。对于线程安全问题,在进行实际的开发操作过程中,我们要分析一下几点内容,确保多线程环境下的线程安全问题。确定是否是多线程环境:多线程环境下操作共享变量需要考虑线程的安全性;确定是否有增删改操作:多线程环境下,如果对共享数据有增加,删除或者修改的操作,需要谨慎。为了保证线程的同步性,必须对该共享数据进行加锁操作,保证多线程环境下,所有的线程能够获取到正确的数据。如生产者与消费者模型,售票模型;多线程下的读操作:如果是只读操作,对共享数据不需要进行锁操作,因为数据本身未发生增删改操作,不会影响获取数据的准确性。

3. 贪心算法求解背包问题

首先,这里我们考虑背包的容量为 30,并给出这个问题中我们考虑到的各类物品及对应的重量和价值,如下:物品 n (i)12345 重量 w (i)105151020 价值 v (i)2030152510回顾一下我们在贪心算法介绍中提到的,能够应用贪心算法求解的问题需要满足两个条件:最优子结构和贪心选择,接下来,我们就具体来看看在背包问题中的最优子结构和贪心选择分别是什么。首先,如果一个问题的最优解包含其子问题的最优解,则此问题具备最优子结构的性质。问题的最优子结构性质是该问题是否可以用贪心算法求解的关键所在。对于背包问题,很显然它是满足最优子结构性质的,因为一个容量为 c 的背包问题必然包含容量小于 c 的背包问题的最优解的。其次,我们需要考虑在背包问题中,我们应该按照什么样的贪心选择进行选取。很显然,如果要使得最终的价值最大,那么必定需要使得选择的单位重量的物品的价值最大。所以背包问题的贪心选择策略是:优先选择单位重量价值最大的物品,当这个物品选择完之后,继续选择其他价值最大的物品。这里的背包问题可以用贪心算法实现,是因为背包选择放入的物品可以进行拆分,即并不需要放入整个物品,可以选择放入部分物品,我们这样的背包选择问题为部分背包问题(可以只选择物品的部分),与之对应的另一种背包问题为 0-1 背包问题,这个时候整个物品不可以拆分,只可以选择放入或者不放入,0-1 背包问题用贪心算法并不能求得准确的解,需要用动态规划算法求解。背包问题求解详解:在这里,我们按照优先选择单位重量价值最大的物品,所以第一步需要计算单位每个物品的单位价值,如下:unitValue(1) = 20/10 = 2unitValue(2) = 30/5 = 6unitValue(3) = 15/15 = 1unitValue(4) = 25/10 = 2.5unitValue(5) = 10/20 = 0.5所以我们有:unitValue(2) > unitValue(4) > unitValue(1) > unitValue(3) > unitValue(5)当考虑背包的容量为 30 时, 我们发现可以按照物品的单位价值进行依次放入,直至背包容量放满或者物品放完为止,放入的过程如下:物品类型放入重量背包使用容量背包剩余容量 25525410151511025535300按照如上步骤我们简单分析了一下背包问题的求解过程,接下来,我们看一下如何用代码实现背包问题。

对象属性访问问题

对象的属性在访问的时候,务必要关心属性是否真的存在。特别是服务端返回的数据,如果碰到数据出错,就可能造成页面无反应、白屏等问题:const getList = async () => { // 假装拿了服务端的数据,并返回了 return { code: 1, data: { list: null, page: 1, count: 1111, }, };};getList() .then((res) => { // 取出数据 const { data } = res; const { list, page, count } = data; list.forEach(() => { // 处理一些业务 }); // 抛错:TypeError: Cannot read property 'forEach' of null // alert 不会执行 alert('获取数据成功'); });上面这段代码,执行是会报错的,因为 list 是 null,并不是期望的数组,这样就导致了代码无法正常执行下去。所以在使用的时候,最好可以判断或者处理一下不可靠的数据。// 使用 if 判断// ...if (list) { list.forEach(() => { // 处理一些业务 });} else { // ...}// ...// 提供一个默认值const { list = [], page, count } = data;list.forEach(() => { // 处理一些业务});// ...// 提供一个默认值const { list, page, count } = data;(list || []).forEach(() => { // 处理一些业务});// ...方法还有很多,还可以封装一个函数专门用来取对象属性的值,目的就是要代码变得更加可靠,防止一些可能会造成重要后果的异常。如在 react 组件中,如果 render 函数中抛出了错误没有处理,就可能导致组件或者页面白屏。新的 ECMAScript 标准提供了可选链和双问号操作符来更好的处理这个问题。const object = { a: { b: 2, c: { d: 3, }, },};const f = object.a?.b?.c?.d?.e?.f ?? 10;console.log(f); // 输出:10关于这个知识点不再展开,可以参考 ES6+ 相关的 Wiki。简单的说,在访问对象属性的时候,如果数据源不可靠,一定要做好处理异常的准备。

浮点数精度问题

有关浮点数的精度是一个老生常谈的问题了。面试题中这个知识点出现的频率非常高:0.1 + 0.2 === 0.3 // false其中可以参阅 数字 章节。这个问题很少会有面试官进一步的进行考察,如 “怎样让计算结果正确”,最常见的解决方案有两个:计算过程中将数字转成整数计算使用第三方库第一个方案很好理解,将 0.1 与 0.2 扩大 10 倍,相加后再相除就得到了正确的结果:((0.1 * 10) + (0.2 * 10)) / 10 === 0.3 // true如果存在两位小数,则同时放大 100倍,计算后再缩小 100倍 就可以了。第二个方案可以有很多选择,这里列出了几个常用的第三方库:bignumber.jsmath.jsbig.js

首页上一页1234567下一页尾页
直播
查看课程详情
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号