手写算法: 买卖股票的最佳时机 II
解法一:贪心算法
只算正利润,用当天
var maxProfit = function(prices) {
let result = 0;
for (let i = 1; i < prices.length; i++) {
result += Math.max(prices[i] - prices[i - 1], 0);
}
return result;
};
解法二:动态规划
跟买卖股票的最佳时机思路一样,只是这道题股票可以买卖多次。
那么在计算 dp[i][0]的时候,需要用昨天不持有股票现金 - 今天的股票价格,即dp[i - 1][1] - prices[i]。因为目前不持有股票现金包括之前卖出赚的利润。
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
const len = prices.length;
let dp = new Array(len).fill([0, 0]);
dp[0] = [0, -prices[0]];
console.log(dp);
for (let i = 1; i < len; i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
}
return dp[len - 1][0];
};
手写题
手写 JSON.parse()
/**
* @param {string} str
* @return {object | Array | string | number | boolean | null}
*/
function parse(str) {
const json = eval('(' + str + ')');
if (JSON.stringify(json) === str) {
return json;
}
throw new Error(str);
}
JS 简答题
Hoisting III
var a = 1;
function func() {
a = 2;
console.log(a);
var a;
}
func();
console.log(a);
if (!('b' in window)) {
var b = 1;
}
console.log(b);
解析
看到if {}块就要主要,变量提升问题!!!不要忘记了
// b 变量会被提升,b此时已被定义,暂未赋值
if (false) {
var b;
}
// true, 变量被提升,已经在window作用域下
'b' in windows;
instanceOf
console.log(typeof null);
console.log(null instanceof Object);
console.log(typeof 1);
console.log(1 instanceof Number);
console.log(1 instanceof Object);
console.log(Number(1) instanceof Object);
console.log(new Number(1) instanceof Object);
console.log(typeof true);
console.log(true instanceof Boolean);
console.log(true instanceof Object);
console.log(Boolean(true) instanceof Object);
console.log(new Boolean(true) instanceof Object);
console.log([] instanceof Array);
console.log([] instanceof Object);
console.log((() => {}) instanceof Object);
解析
基础类型都没有instanceof关键字
console.log(typeof null); // "object" - 'null' has "object" type in js (backward compatibility)
console.log(null instanceof Object); // false - 'null' is primitive and doesn't have 'instanceof' keyword
console.log(typeof 1); // "number" - one of js types
console.log(1 instanceof Number); // false - '1' is primitive and doesn't have 'instanceof' keyword
console.log(1 instanceof Object); // false - same as above
console.log(Number(1) instanceof Object); // false - Number(1) === 1 - same as above
console.log(new Number(1) instanceof Object); // true - 'new Number(1)' is object, so it's correct
console.log(typeof true); // "boolean" - one of js types
console.log(true instanceof Boolean); // false - 'true' is primitive and doesn't have 'instanceof' keyword
console.log(true instanceof Object); // false - same as above
console.log(Boolean(true) instanceof Object); // false - Boolean(true) === true - same as above
console.log(new Boolean(true) instanceof Object); // true - 'new Boolean(true)' is object, so it's correct;
console.log([] instanceof Array); // true - '[]' is instanceof Array and Object
console.log([] instanceof Object); // true - '[]' is instanceof Array and Object
console.log((() => {}) instanceof Object); // true - if it's not a primitive it's object. So callback is instanceof object
Implicit Coercion I
console.log(Boolean('false'));
console.log(Boolean(false));
console.log('3' + 1);
console.log('3' - 1);
console.log('3' - ' 02 ');
console.log('3' * ' 02 ');
console.log(Number('1'));
console.log(Number('number'));
console.log(Number(null));
console.log(Number(false));
解析
false, '0', [],这三个在强制转换成数字的时候会成 0减法、乘法,遇到字符串时会先转换成数字类型,再进行计算
Number(value),如果入参无法转换成数字,则返回 NaN
true or false
console.log([] == 0);
console.log([] == false);
console.log(!![]);
console.log([1] == 1);
console.log(!![1]);
console.log(Boolean([]));
console.log(Boolean(new Boolean([])));
console.log(Boolean(new Boolean(false)));
解析
== 与 Boolean()规则不一致, Boolean() 与 ! 规则一致
Boolean()中,如果值为
0, -0, NaN, null, undefined, false, ''(空字符串),都似为 false。其他的值都为 true
console.log(!![]); // !(!true) ==> !false ==> true
console.log([1] == 1); // [1] == 1 ==> 1 == 1 ==> true
console.log(Boolean([])); // Boolean(true) ==> true
console.log(Boolean(new Boolean([]))); // new Boolean([]) ==> 输入出对象为true Boolean(any object) will be true
NaN
console.log(NaN == NaN);
console.log(NaN === NaN);
console.log(Object.is(NaN, NaN));
console.log([NaN].indexOf(NaN));
console.log([NaN].includes(NaN));
console.log(Math.max(NaN, 1));
console.log(Math.min(NaN, 1));
console.log(Math.min(NaN, Infinity));
解析
Array.prototype.includes(),怀疑底层是用 object.is()判断的, 此题返回 trueMath.max(), Math.min(),入参中至少有一个参数无法转换成数字,那么就会返回 NaN
this
const obj = {
a: 1,
b: function() {
console.log(this.a);
},
c() {
console.log(this.a);
},
d: () => {
console.log(this.a);
},
e: (function() {
return () => {
console.log(this.a);
};
})(),
f: function() {
return () => {
console.log(this.a);
};
},
};
console.log(obj.a)
obj.b()
;(obj.b)()
const b = obj.b
b()
obj.b.apply({a: 2})
obj.c()
obj.d()
;(obj.d)()
obj.d.apply({a:2})
obj.e()
;(obj.e)()
obj.e.call({a:2})
obj.f()()
;(obj.f())()
obj.f().call({a:2})
解析
obj.f 是一个普通函数,它返回形成闭包并记住外部函数作用域的箭头函数。
普通函数,this 的值取决于函数的调用方式,即运行时绑定
箭头函数,不提供 this 绑定,它保留封闭词法上下文的 this,即静态绑定
call()、apply() 更改作用域,使用给定的 this 值调用函数。箭头函数不能用 call、apply,因为它没有 this
null and undefined
console.log(JSON.stringify([1, 2, null, 3]));
console.log(JSON.stringify([1, 2, undefined, 3]));
console.log(null === undefined);
console.log(null == undefined);
console.log(null == 0);
console.log(null < 0);
console.log(null > 0);
console.log(null <= 0);
console.log(null >= 0);
console.log(undefined == 0);
console.log(undefined < 0);
console.log(undefined > 0);
console.log(undefined <= 0);
console.log(undefined >= 0);
解析
JSON 没有
undefined的值,它在 JSON 数据类型中被替换成null当
==运用于null或undefined时,不会发生数字转换。null 只等于 null 或 undefined做运算计算时,
null, undefined转换成数字时,null会变成 0, 而undefined会变成 NaN
null == null; // true
null == undefined; // true
null === null; // true
null === undefined; // false
null == 0; // false,== 运算符时,只跟undefined相等
null < 0; // false, 做运算时,null会先变成0再进行比较,0 < 0
undefined == 0; // false, undefined转成数字再进行比较,NaN == 0
Proxy I
const obj = new Map();
const map = new Map();
obj.foo = 1;
map.set('foo', 2);
console.log(obj.foo);
console.log(map.get('foo'));
const proxyObj = new Proxy(obj, {});
const proxyMap = new Proxy(map, {});
console.log(proxyObj.foo);
console.log(proxyMap.get('foo'));
解析
Many built-in objects, for example, Map, Set, Date, Promise and others make use of so-called internal slots. These are like properties but reserved for internal, specification-only purposes. For instance, Map stores items in the internal slot [[MapData]]. Built-in methods access them directly, not via [[Get]]/[[Set]] internal methods. So Proxy can’t intercept that. e.g.
let map = new Map();
let proxy = new Proxy(map, {});
proxy.set('name', 'kk'); // Error
proxy 代理后无法用 get、set 拦截
Increment Operator
let a = 1;
const b = ++a;
const c = a++;
console.log(a);
console.log(b);
console.log(c);
解析
let a = 1;
// ++a,先加再赋值,所以此时b为2
const b = ++a;
// 但是由于a是let属性,所以a要更新, 此时a也为2
console.log(a);
// a++, 是先赋值后加,所以此时b为2
const c = a++;
// 赋值完后,a++, a变为3
console.log(a);