持续更新中。。。
更多资源尽在前端资源合集
判断类型
- typeof
console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof "str"); // string
console.log(typeof undefined); // undefined
console.log(typeof []); // object
console.log(typeof {}); // object
console.log(typeof function() {}); // function
console.log(typeof null); // object
console.log(typeof Symbol()); // symbol
- instanceof
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log("str" instanceof String); // false
console.log([] instanceof Array); // true
console.log(function() {} instanceof Function); // true
console.log({} instanceof Object); // true
- Object.prototype.toString.call()
var toString = Object.prototype.toString;
console.log(toString.call(2)); //[object Number]
console.log(toString.call(true)); //[object Boolean]
console.log(toString.call("str")); //[object String]
console.log(toString.call([])); //[object Array]
console.log(toString.call(function() {})); //[object Function]
console.log(toString.call({})); //[object Object]
console.log(toString.call(undefined)); //[object Undefined]
console.log(toString.call(null)); //[object Null]
console.log(toString.call(new Map())); //[object Map]
console.log(toString.call(new Set([1, 3]))); //[object Set]
console.log(toString.call(new Date())); //[object Date]
console.log(toString.call(new RegExp("."))); //[object RegExp]
console.log(toString.call(Symbol())); //[object Symbol]
通用方法
var type = function(data) {
var toString = Object.prototype.toString;
var dataType =
data instanceof Element
? "element" // 为了统一DOM节点类型输出
: toString
.call(data)
.replace(/\[object\s(.+)\]/, "$1")
.toLowerCase();
return dataType;
};
实现 call apply bind
mycall
Function.prototype.mycall = function(thisArg, ...args) {
if (typeof this !== "function") {
throw new TypeError("Error");
}
var self = this,
fn = Symbol("fn");
thisArg = thisArg || window;
thisArg[fn] = self;
var result = thisArg[fn](...args);
delete thisArg[fn];
return result;
};
var o = { a: 1 };
function f(x, y) {
console.log(this.a, x, y);
}
f.mycall(o, 2, 3);
myapply
Function.prototype.myapply = function(thisArg, args) {
if (typeof this !== "function") {
throw new TypeError("Error");
}
var self = this,
fn = Symbol("fn");
thisArg = thisArg || window;
thisArg[fn] = self;
var result = thisArg[fn](...args);
delete thisArg[fn];
return result;
};
var o = { a: 1 };
function f(x, y) {
console.log(this.a, x, y);
}
f.myapply(o, [2, 3]);
mybind
// Function.prototype.mybind = function(thisArg) {
// if (typeof this !== "function") {
// throw TypeError("Bind must be called on a function");
// }
// // 拿到参数,为了传给调用者
// const args = Array.prototype.slice.call(arguments, 1),
// // 保存 this
// self = this,
// // 构建一个干净的函数,用于保存原函数的原型
// nop = function() {},
// // 绑定的函数
// bound = function() {
// // this instanceof nop, 判断是否使用 new 来调用 bound
// // 如果是 new 来调用的话,this的指向就是其实例,
// // 如果不是 new 调用的话,就改变 this 指向到指定的对象 o
// return self.apply(
// this instanceof nop ? this : thisArg,
// args.concat(Array.prototype.slice.call(arguments))
// );
// };
// // 箭头函数没有 prototype,箭头函数this永远指向它所在的作用域
// if (this.prototype) {
// nop.prototype = this.prototype;
// }
// // 修改绑定函数的原型指向
// bound.prototype = new nop();
// return bound;
// };
Function.prototype.mybind = function(context = window, ...outerArg) {
let _this = this;
return function(...innerArg) {
return _this.apply(context, outerArg.concat(innerArg));
};
};
var o = { a: 1 };
function f(x, y) {
console.log(this.a, x, y);
}
var g = f.mybind(o, 2);
g(3);
组合函数
组合函数指的是将代表各个动作的多个函数合并成一个函数
function componse(...funcs) {
return function() {
var result = funcs[0].apply(this, arguments);
for (var i = 1; i < funcs.length; i++) {
result = funcs[i].call(this, result);
}
return result;
};
}
function f1(x) {
return x + 1;
}
function f2(x) {
return x * 2;
}
var f = componse(f1, f2);
f(1); // 4
柯里化
简单说就是把多形参的函数转换为可以一个一个接收参数的函数,即如下
add(x,y) => curryAdd(x)(y)
function curry(f) {
var total = f.length;
var args = [];
return function() {
args.push(...arguments);
if (args.length < total) {
return arguments.callee;
} else {
var res = f.apply(this, args);
args = []; // 需要清理args
return res;
}
};
}
function add(x, y) {
return x + y;
}
var curryAdd = curry(add);
curryAdd(1)(2); // 3
curryAdd(1, 2); // 3
防抖
防抖:任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行。
场景: 搜索输入框
function debounce(fn) {
let timeout = null;
return function() {
clearTimeout(timeout);
timeout = setTimeout(() => {
fn.call(this, arguments);
}, 1000);
};
}
节流
节流:指定时间间隔内只会执行一次任务。
场景:1. 监听滚动条 2. 监听点击按钮
function throttle(fn) {
let canRun = true;
return function() {
if (!canRun) {
return;
}
canRun = false;
setTimeout(() => {
fn.call(this, arguments);
canRun = true;
}, 1000);
};
}
深拷贝
乞丐版
const target = {
field1: 1,
field2: undefined,
field3: {
child: "child"
},
field4: [2, 4, 8]
};
target.target = target;
function clone(obj, map = new Map()) {
if (typeof obj === "object") {
let result = obj instanceof Array ? [] : {};
if (map.get(obj)) {
return map.get(obj);
}
map.set(obj, result);
for (let key in obj) {
result[key] = clone(obj[key], map);
}
return result;
} else {
return obj;
}
}
clone(target);
这个方法的问题是:
- 不能拷贝 null Date 等对象
- 不能拷贝 Symbol 属性
- 会拷贝原型链上的属性
- 不会拷贝不可枚举的属性
豪华版
目标可以完全深拷贝以下对象(不包括原型链上的属性)
var oo = {
oa: 1
};
var f = function() {};
var o = {
a: 1,
b: {
a: 1
},
c: undefined,
d: new Date(),
e: null,
[f]: 1,
r: RegExp("."),
[Symbol()]: "1",
g: Symbol("g")
};
o.__proto__ = oo;
o.o = o;
Object.defineProperty(o, "p", {
value: 1
});
难点:
- 拷贝 Map Set 等复杂对象
- 如何拷贝 Symbol 属性
- 如何拷贝不可枚举的属性
- 如果对象有个属性是循环引用,如上述的 o.o
- 如何保留正则 日期对象等属性值
- 如何保留 undefined
// 类型整合
const mapTag = "[object Map]";
const setTag = "[object Set]";
const arrayTag = "[object Array]";
const objectTag = "[object Object]";
const boolTag = "[object Boolean]";
const dateTag = "[object Date]";
const errorTag = "[object Error]";
const numberTag = "[object Number]";
const regexpTag = "[object RegExp]";
const stringTag = "[object String]";
const symbolTag = "[object Symbol]";
const deepTag = [mapTag, setTag, arrayTag, objectTag];
// 判断原始类型和引用类型
function isObject(target) {
const type = typeof target;
return target !== null && (type === "object" || type === "function");
}
// 获取克隆对象的类型
function getType(target) {
return Object.prototype.toString.call(target);
}
// 初始化要克隆的对象
function getInit(target) {
const Ctor = target.constructor;
return new Ctor();
}
// loadsh使用的遍历迭代器
function arrayEach(array, iteratee) {
let index = -1;
const length = array.length;
while (++index < length) {
if (iteratee(array[index], index, array) === false) {
break;
}
}
return array;
}
// 克隆其他不可遍历类型
function cloneOtherType(targe, type) {
const Ctor = targe.constructor;
switch (type) {
case boolTag:
case numberTag:
case stringTag:
case errorTag:
case dateTag:
return new Ctor(targe);
case regexpTag:
return cloneReg(targe);
case symbolTag:
return cloneSymbol(targe);
default:
return null;
}
}
// 克隆Symbol
function cloneSymbol(targe) {
return Symbol.prototype.valueOf.call(targe);
}
// 克隆正则
function cloneReg(targe) {
const reFlags = /\w*$/;
// const result = new targe.constructor(targe.source, reFlags.exec(targe))
const result = new targe.constructor(targe);
result.lastIndex = targe.lastIndex;
return result;
}
function deepClone(value, map = new WeakMap()) {
let cloneValue, type;
// 判断引用数据类型
if (!isObject(value)) {
return value;
}
// 初始化
type = getType(value);
if (deepTag.includes(type)) {
cloneValue = getInit(value);
} else {
return cloneOtherType(value, type);
}
// 防止循环引用
if (map.get(value)) {
return map.get(value);
}
map.set(value, cloneValue);
// 克隆set
if (type === setTag) {
value.forEach(value => {
cloneValue.add(deepClone(value, map));
});
return cloneValue;
}
// 克隆map
if (type === mapTag) {
value.forEach((value, key) => {
cloneValue.set(key, deepClone(value, map));
});
return cloneValue;
}
// 克隆对象和数组
const props = type === arrayTag ? undefined : Reflect.ownKeys(value);
arrayEach(props || value, (val, key) => {
if (props) {
key = val;
}
cloneValue[key] = deepClone(value[key], map);
});
return cloneValue;
}
var oo = {
oa: 1
};
var f = function() {};
var o = {
a: 1,
b: {
a: 1
},
c: undefined,
d: new Date(),
e: null,
[f]: 1,
r: RegExp("."),
[Symbol()]: "1",
g: Symbol("g")
};
o.__proto__ = oo;
o.o = o;
Object.defineProperty(o, "p", {
value: 1
});
deepClone(o);
实现 new
new 操作会执行以下操作
1. 创建一个全新的对象。
2. 这个新对象会被执行 [[Prototype]] 连接。
3. 这个新对象会绑定到函数调用的 this。
4. 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。
function _new() {
let target = {}; //创建的新对象
//第一个参数是构造函数
let [constructor, ...args] = [...arguments];
//执行[[原型]]连接;target 是 constructor 的实例
target.__proto__ = constructor.prototype;
//执行构造函数,将属性或方法添加到创建的空对象上
let result = constructor.apply(target, args);
if (result && (typeof result == "object" || typeof result == "function")) {
//如果构造函数执行的结构返回的是一个对象,那么返回这个对象
return result;
}
//如果构造函数返回的不是一个对象,返回创建的新对象
return target;
}
数组去重
不同的方法 得到的结果不大一样,这个看需求了
var array = [
1,
1,
"1",
"1",
null,
null,
undefined,
undefined,
new String("1"),
new String("1"),
/a/,
/a/,
NaN,
NaN
];
// function unique(arr) {
// var ret = []
// for (var i = 0; i < arr.length; i++) {
// for (var j = 0, l = ret.length; j < l;j++) {
// if (ret[j] === arr[i]) {
// break;
// }
// }
// if (j === ret.length) {
// ret.push(arr[i])
// }
// }
// return ret
// } // [1, "1", null, undefined, String, String, /a/, /a/, NaN, NaN]
// function unique(arr) {
// var ret = []
// for (var i = 0; i < arr.length; i++) {
// var index = ret.indexOf(arr[i])
// if (index === -1) {
// ret.push(arr[i])
// }
// }
// return ret
// } // [1, "1", null, undefined, String, String, /a/, /a/, NaN, NaN]
// function unique(arr) {
// var sortedArr = arr.sort()
// var seen
// var ret = []
// for (var i = 0; i < sortedArr.length; i++) {
// if (!i || seen !== arr[i]) ret.push(sortedArr[i])
// seen = sortedArr[i]
// }
// return ret
// } // [/a/, /a/, 1, "1", String, String, NaN, NaN, null, undefined]
// function unique(arr) {
// var ret = []
// return arr.filter(item => {
// if (ret.indexOf(item) > -1) return false
// return ret.push(item)
// })
// } // [1, "1", null, undefined, String, String, /a/, /a/, NaN, NaN]
// function unique(arr) {
// var sortedArr = arr.sort()
// return sortedArr.filter((item, index, array) => {
// if (!index || item !== array[index - 1]) return true
// })
// } // [/a/, /a/, 1, "1", String, String, NaN, NaN, null, undefined]
// function unique(arr) {
// return Array.from(new Set(arr))
// } // [1, "1", null, undefined, String, String, /a/, /a/, NaN]
// function unique(arr) {
// return [...new Set(arr)]
// } // [1, "1", null, undefined, String, String, /a/, /a/, NaN]
// function unique (arr) {
// const seen = new Map()
// return arr.filter((a) => !seen.has(a) && seen.set(a, 1))
// } // [1, "1", null, undefined, String, String, /a/, /a/, NaN]
// function unique(arr) {
// var map ={}
// var ret = []
// for(var i = 0; i< arr.length; i++) {
// if (!map[typeof arr[i] + arr[i]]) {
// map[typeof arr[i] + arr[i]] = true
// ret.push(arr[i])
// }
// }
// return ret
// } // [1, "1", null, undefined, String, /a/, NaN]
function unique(array) {
var obj = {};
return array.filter(function(item, index, array) {
return obj.hasOwnProperty(typeof item + item)
? false
: (obj[typeof item + item] = true);
});
} // [1, "1", null, undefined, String, /a/, NaN]
unique(array);
展平数组
// 递归思想
var arr = [1, 2, [3, 4], [5, [6, 7], 8], 9];
function flat(arr) {
var ans = [];
for (var i = 0; i < arr.length; i++) {
if (!Array.isArray(arr[i])) ans.push(arr[i]);
else {
let res = flat(arr[i]);
ans = ans.concat(res);
}
}
return ans;
}
console.log(flat(arr));
function flat(arr, reuslt = []) {
arr.forEach(item => {
if (item instanceof Array) flat(item, reuslt);
else reuslt.push(item);
});
return reuslt;
}
flat([1, 2, 3, [1, 2, [1.4], [1, 2, 3]]]);
var arr = [1, [[2, 3], 4], [5, 6]];
var flat = function*(a) {
var length = a.length;
for (var i = 0; i < length; i++) {
var item = a[i];
if (typeof item !== "number") {
yield* flat(item);
} else {
yield item;
}
}
};
for (var f of flat(arr)) {
console.log(f);
}
// 1, 2, 3, 4, 5, 6
function* iterTree(tree) {
if (Array.isArray(tree)) {
for (let i = 0; i < tree.length; i++) {
yield* iterTree(tree[i]);
}
} else {
yield tree;
}
}
const tree = ["a", ["b", "c"], ["d", "e"]];
[...iterTree(tree)];
// es6
[1, [2, [3]]].flat(Infinity);
实现斐波那契数列
function* fibonacci() {
let [prev, curr] = [0, 1];
for (;;) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
for (let n of fibonacci()) {
if (n > 1000) break;
console.log(n);
}
实现延迟器
目标是实现一个延迟多少时间再执行之后操作的函数
function timeout(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
// 或
// async function timeout(ms) {
// await new Promise((resolve) => {
// setTimeout(resolve, ms);
// });
// }
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint("hello world", 50); // 50 毫秒以后,输出hello world
限制构造函数只能通过 new 调用
方法一:通过 new.target 限制
function F(name) {
if (new.target !== undefined) {
this.name = name;
} else {
throw new Error("必须使用 new 命令生成实例");
}
}
方法二:通过 class
class F {
constructor(name) {
this.name = name;
}
}
不能独立使用、必须继承后才能使用的类
class Shape {
constructor() {
if (new.target === Shape) {
throw new Error("本类不能实例化");
}
}
}
class Rectangle extends Shape {
constructor(length, width) {
super();
// ...
}
}
var x = new Shape(); // 报错
var y = new Rectangle(3, 4); // 正确
实现对象继承
ES5
function A() {
this.name = "Father";
}
function B() {
this.age = 32;
}
B.prototype = new A(); // Father函数改变自己的prototype指向
var b = new B();
function A() {
this.name = "Father";
}
function B() {}
// B 的实例继承 A 的实例
Object.setPrototypeOf(B.prototype, A.prototype);
// B 继承 A 的静态属性
Object.setPrototypeOf(B, A);
const b = new B();
ES6
class A {
name = "Father";
}
class B extends A {
constructor(props) {
super(props);
}
}
var b = new B();
设置原型的方法
function A() {
this.name = "Father";
}
function B() {}
B.prototype = Object.create(A.prototype);
// 等同于
B.prototype.__proto__ = A.prototype;
// 等同于
Object.setPrototypeOf(B.prototype, A.prototype);
实现 enum
// enum color { Red, Green, Orange }
// 等价于
var color;
(function(color) {
color[(color["Red"] = 0)] = "Red";
color[(color["Green"] = 1)] = "Green";
color[(color["Orange"] = 2)] = "Orange";
})(color || (color = {}));
let a = color.Red;
console.log(color[0]); // Red
console.log(a); // 0
对象格式化
格式化对象 大写变为小写
// 格式化对象 大写变为小写
let o = {
a: 1,
b: {
c: 2,
D: {
E: 3
}
}
};
function keysLower(obj) {
if (obj instanceof Object === false) return obj;
let result = {};
Object.keys(obj).forEach(key => {
result[key.toLowerCase()] = keysLower(obj[key]);
});
return result;
}
keysLower(o);
为对象实现 for...of...
function* objectEntries() {
let propKeys = Object.keys(this);
for (let propKey of propKeys) {
yield [propKey, this[propKey]];
}
}
let jane = { first: "Jane", last: "Doe" };
jane[Symbol.iterator] = objectEntries;
for (let [key, value] of jane) {
console.log(`${key}: ${value}`);
}
// first: Jane
// last: Doe
实现 thunkify
thunkify 将多参数函数替换成一个只接受回调函数作为参数的单参数函数
用于 Generator 函数的自动流程管理
function thunkify(fn) {
return function() {
var args = new Array(arguments.length);
var ctx = this;
for (var i = 0; i < args.length; ++i) {
args[i] = arguments[i];
}
return function(done) {
var called;
args.push(function() {
if (called) return;
called = true;
done.apply(null, arguments);
});
try {
fn.apply(ctx, args);
} catch (err) {
done(err);
}
};
};
}
function f(a, b, callback) {
var sum = a + b;
callback(sum);
callback(sum);
}
var ft = thunkify(f);
var print = console.log.bind(console);
ft(1, 2)(print);
// 3
写一个网络请求
发送 http 请求
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject) {
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(
function(json) {
console.log("Contents: " + json);
},
function(error) {
console.error("出错了", error);
}
);
实现请求 5 秒未返回,就超时
const p = Promise.race([
fetch("/resource-that-may-take-a-while"),
new Promise(function(resolve, reject) {
setTimeout(() => reject(new Error("request timeout")), 5000);
})
]);
p.then(console.log).catch(console.error);
实现并发、串发请求
串发,可以看到依次打印 A,B,C
function request(filename) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(filename);
resolve(filename);
}, Math.random() * 500);
});
}
// 方法一
async function a() {
let docs = ["A", "B", "C"];
for (var filename of docs) {
await request(filename);
}
}
// 方法二
// async function a() {
// let docs = ['A','B','C']
// await docs.reduce(async (pre, cur)=> {
// await pre
// await request(cur)
// }, undefined)
// }
a().then(res => res);
并发,同时发出请求,ABC 随机打印
function request(filename) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(filename);
resolve(filename);
}, Math.random() * 500);
});
}
// 方法一
// async function a() {
// let docs = ['A','B','C']
// let promises = docs.map(filename=>request(filename))
// for(var promise of promises) {
// await promise
// }
// }
// 方法二
async function a() {
let docs = ["A", "B", "C"];
let promises = docs.map(filename => request(filename));
await Promise.all(promises);
}
a().then(res => res);
实现 jsonp
function addScriptTag(src) {
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function() {
addScriptTag("http://example.com/ip?callback=foo");
};
function foo(data) {
console.log("Your public IP address is: " + data.ip);
}
实现图片懒加载
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.container {
width: 600px;
margin: 0 auto;
}
.imgbox {
width: 600px;
height: 300px;
background-color: #bbb;
/* margin-top: 1000px; */
margin-bottom: 20px;
}
.imgbox img {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div class="container">
<div class="imgbox">
<img
src=""
data-src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/1/14/16fa30af939c81c4~tplv-t2oaga2asx-image.image"
alt=""
/>
</div>
<div class="imgbox">
<img
src=""
data-src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/1/14/16fa30af939c81c4~tplv-t2oaga2asx-image.image"
alt=""
/>
</div>
<div class="imgbox">
<img
src=""
data-src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/1/14/16fa30af939c81c4~tplv-t2oaga2asx-image.image"
alt=""
/>
</div>
<div class="imgbox">
<img
src=""
data-src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/1/14/16fa30af939c81c4~tplv-t2oaga2asx-image.image"
alt=""
/>
</div>
<div class="imgbox">
<img
src=""
data-src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/1/14/16fa30af939c81c4~tplv-t2oaga2asx-image.image"
alt=""
/>
</div>
<div class="imgbox">
<img
src=""
data-src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/1/14/16fa30af939c81c4~tplv-t2oaga2asx-image.image"
alt=""
/>
</div>
<div class="imgbox">
<img
src=""
data-src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/1/14/16fa30af939c81c4~tplv-t2oaga2asx-image.image"
alt=""
/>
</div>
<div class="imgbox">
<img
src=""
data-src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/1/14/16fa30af939c81c4~tplv-t2oaga2asx-image.image"
alt=""
/>
</div>
</div>
<script>
var $window = window,
$container = document.querySelector(".container");
$window.onload = $window.onscroll = function() {
var $imgboxs = $container.children;
[...$imgboxs].forEach($item => {
if ($item.classList.contains("loaded")) return;
var $img = $item.querySelector("img"),
clientRect = $item.getBoundingClientRect(), // NOTE: 这里用item的高度,因为img还没有宽高
$A = clientRect.top + clientRect.height,
$B = window.innerHeight;
if ($A <= $B) {
console.log("loaded");
$img.src = $img.dataset["src"];
$item.classList.add("loaded");
}
});
};
</script>
</body>
</html>
打印 0-9
错误解法
for (var i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i);
}, 500);
}
以下是正确解法
setTimeout 传参
for (var i = 0; i < 10; i++) {
setTimeout(
i => {
console.log(i);
},
500,
i
);
}
let 块作用域
for (let i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i);
}, 500);
}
闭包
for (let i = 0; i < 10; i++) {
(() => {
setTimeout(() => {
console.log(i);
}, 500);
})();
}
闭包
for (let i = 0; i < 10; i++) {
setTimeout(
(i => {
return () => console.log(i);
})(i),
500
);
}
bind
for (let i = 0; i < 10; i++) {
var fn = i => console.log(i);
setTimeout(fn.bind(this, i), 500);
}
实现 a==1&&a==2&&a==3 为 true
方法一
var a = {
n: 0,
toString() {
this.n++;
return this.n;
}
};
if (a == 1 && a == 2 && a == 3) {
console.log("ok");
}
方法二
var a = [1, 2, 3];
a.toString = a.shift;
if (a == 1 && a == 2 && a == 3) {
console.log("ok");
}
方法三
只有这种三等才为 true,a === 1 && a === 2 && a === 3
Object.defineProperty(window, "a", {
get() {
this.value ? this.value++ : (this.value = 1);
return this.value;
}
});
if (a === 1 && a === 2 && a === 3) {
console.log("ok");
}
输出什么
let obj = {
2: 3,
3: 4,
length: 2,
push: Array.prototype.push
};
obj.push(5);
console.log(obj); // { '2': 5, '3': 4, length: 3, push: [Function: push] }
obj.push(6);
console.log(obj); // { '2': 5, '3': 6, length: 4, push: [Function: push] }
obj.push(7);
console.log(obj); // { '2': 5, '3': 6, '4': 7, length: 5, push: [Function: push] }