科里化函数
将多参函数变成单参函数
function curry(func, ...args){
return function(...subArgs){
const totalArgs = [...args, ...subArgs];
if(totalArgs.length >= func.length){
//参数够了
return func(...totalArgs);
} else {
// 参数不够
return curry(func,...totalArgs);
}
}
}
函数防抖和函数节流
节流是在规定的时间内,只运行一次函数。与函数防抖的不同是,防抖要等到不触发这个事件后多少时间,才运行函数。
function debounce(callback,time){
let timer;
return function(){
clearTimeout(timer);
timer = setTimeout(()=>{
callback.apply(null, arguments)
}, time)
}
}
function throttle(callback, time){
let timer;
return function(){
if(timer) return;
timer = setTimeout(()=>{
callback.apply(null, arguments);
timer = null;
},tiem)
}
}
call,apply,bind
Function.prototype.call = function(context, ...args){
context = context || window;
const flag = Symbol('fn');
context[flag] = this;
context[flag](...args);
delete context[flag];
}
Function.prototype.apply = function(context, args){
context = context || window;
const flag = Symbol('fn');
context[flag] = this;
context[flag](...args);
delete context[flag];
}
Function.prototype.bind = function(context, ...args){
context = context || window;
const flag = Symbol('fn');
context[flag] = this;
return function(..._args){
args = args.contat(_args);
context[flag](...args);
delete context[flag];
}
}
jsonp
jsonp只能用于get请求
严重影响服务器的正常响应格式
CORS跨域:access-control-allow-origin: my.com
function jsonp(url){
const script = document.creatElement('script');
script.url = url;
document.body.appendChild(script);
script.onload = function(){
// script元素加载完毕后移除
script.remove();
}
}
function callback(data){
console.log(data);
}
jsonp('URL');
ajax
function ajax({
data = {},
type = 'get',
async = true,
url,
success,
error
}) {
let xhr = null;
if (window.XMLHttpRequest) {
// 非IE
xhr = new XMLHttpRequest();
} else {
// IE浏览器
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
if (type === 'post') {
xhr.open(type, url, async);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencode');
const data = toDate(data);
xhr.send(data);
} else {
xhr.open(type, url + '?' + toData(data), async);
xhr.send();
}
xhr.onreadstatechange = function () {
if (xhr.readstate === 4 && xhr.status === 200) {
if (success) {
success(JSON.parse(xhr.responseText));
}
} else {
if (error) {
error(xhr.status);
}
}
}
}
function toData(obj={}){
const res = [];
for (const i in obj) {
let str = i + '=' + obj[i];
res.push(str);
}
return res.join('&');
}
扁平化数组
function flat(arr) {
let res = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
res = res.concat(flat(arr[i]));
} else {
res = res.concat(arr[i]);
}
}
return res;
}
const a = [1, [2, [3, 4]]];
console.log(flat(a));
// [ 1, 2, 3, 4 ]
克隆
function clone(obj, deep) {
if (Array.isArray(obj)) {
if (deep) {
var newArr = [];
for (var i = 0; i < obj.length; i++) {
newArr.push(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] = clone(obj[prop], deep);
} else {
newObj[prop] = obj[prop];
}
}
return newObj;
} else {
//原始类型
return obj;
}
}
new操作符具体做了什么
- 创建一个新的空对象
- 空对象的隐式原型(proto)指向函数的原型
- 改变函数上下文到新对象(改变this的指向)
- 对构造函数返回值有处理(返回原始类型就忽略返回空对象,返回引用类型则返回该引用类型)
根据上面四点,我们一起来验证下现有new的工作原理是不是这样。
1. 创建一个新的空对象
function Foo(){
}
console.log(new Foo()); // Foo {}
2. 空对象的隐式原型(proto)指向函数的原型
function Foo(){
}
console.log(new Foo().__proto__ === Foo.prototype); // true
3. 改变函数上下文到新对象(改变this的指向)
function Foo(){
console.log(this);
this.name = 'test';
}
Foo(); // 打印全局对象
new Foo(); // 打印 Foo {}
4. 对构造函数返回值有处理
返回原始类型
function Foo(){
return '111';
}
console.log(new Foo()); // Foo {}
返回引用类型
function Foo(){
return [1,2];
}
console.log(new Foo()); // [ 1, 2 ]
function myNew(fn, ...args) {
// 1. 创建一个新的空对象
const obj = {};
// 2. 将对象的隐式原型指向函数原型
obj.__proto__ = fn.prototype; // Object.setPrototypeOf(obj, fn.prototype);
// 3. 将对象作为函数的上下文
const result = fn.apply(obj, args);
// 4. 判断函数返回值的类型
return result instanceof Object ? result : obj;
}
function Foo(name, age) {
this.name = name;
this.age = age;
}
console.log(myNew(Foo, 'Mynew', 18));// Foo { name: 'Mynew', age: 18 }