这是一篇杂乱的编程题练习
call封装一个bind
先说下call,apply,bind干嘛用的:
他们都是用来改变this指向的,call,apply只是传的参数方式不同,并且是立即执行,返回一个值。bind()则返回的是一个函数,需要触发才可以执行,bind的好处是可以把转变this指向的功能封装成函数,方便复用。
语法:
call(context,arg1,arg2…)
context是this对象,context==null || context == undefined
context === window
apply(context,[arg1,arg2…])
eg1 一个例子来看call和apply的区别:
var arr = [3,4,2];
var maxCall = Math.max.call(null,arr[0],arr[1],arr[2]);
var maxApply = Math.max.apple(null,arr);
eg2 一个例子来看绑定的this值和参数的使用场景。
var obj = {
msg : "hello"
}
function fn(firstName,lastName) {
return this.msg + firstName + lastName;
}
fn.call(obj,'hu','ting');
eg3 一个例子看bind的使用
var obj = {
msg : "hello"
}
function fn(firstName,lastName) {
return this.msg + firstName + lastName;
}
var fnBind = fn.bind(obj,['hu','ting']);
console.log(fnBind);
eg4 bind参数的使用
function fn(a, b, c) {
console.log(a, b, c);
}
var fn1 = fn.bind(null, 'Dot');
fn('A', 'B', 'C'); // A B C
fn1('A', 'B', 'C'); // Dot A B
fn1('B', 'C'); // Dot B C
fn.call(null, 'Dot'); // Dot undefined undefined
call 是把第二个及以后的参数作为 fn 方法的实参传进去,
而fn1方法的实参实则是在 bind 中参数的基础上再往后排。
eg4 有些浏览器没有bind方法,用call实现一个bind;
function bind() {
if(!Function.prototype.bind) {
Function.prototype.bind = function () {
var self = this,
context = [].shift.call(arguments),//保存上下文;
arg = [].slice.call(arguments);//保存参数;
return self.apply(context, [].concat.call(arg,[].slice.call(arguments)));
}
}
}
bind、call、apply的常用场景
eg1 将类数组转化成数组
[].prototype.slice.apply(arrayLike);
eg2 数组追加
var a1 = [1,2,3];
var a2 = [4,5,6];
var a3 = a1.push.apply(a1,a2);
eg3 判断类型
function isArray(obj) {
return Object.prototype.toSting.call(obj) == ['Object','Array'];
//[].prototype.toString() == ['Object','Array'];
}
eg4 利用call和apply做继承
function Person(name,age) {
this.name = name;
this.age = age;
this.sayName = function() {
console.log(this.name);
}
}
function female() {
Person.apply(this,arguments);
}
var p = new female('hyt');
p.sayName();
快速排序
1、以中间数为基准;
2、遍历数组,比基准小的放左边,比基准大的放右边;
3、递归函数执行第二步,直至区间只剩一个数;
function sort(arr){
var mid = Math.floor(arr.length/2);//找到中间的数作为基准;
var left = [];
var right = [];
var midVal = arr.splice(mid,1);//删除数组中间数,并把中间数赋值给midVal;
if (arr.length <= 1) {
return arr;
}
for (var i = 0; i < arr.length; i++) {
if (arr[i] < midVal) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
//递归执行第二步;
return sort(left).concat(midVal,sort(right));
}
var arr1 = [1,3,6,8,4,9,0,2];
sort(arr1);
函数柯里化
柯里化的作用
事件绑定的时候检测应该用dom几的方式,柯里化的话,只需要检测一次,返回一个新的函数来进行事件绑定(我觉得所有需要判断的地方,如果判断条件在一次访问中不改变的话,都可以写成柯里化的形式,从而达到只进行一次判断的效果)
利用柯里化的思想,可以自己写一个bind函数,延迟执行某个函数,(在一些文章中看到回调函数可以借助这个,还不是很理解,有待之后补充)
函数防抖和call封装bind,有什么联系吗?为什么两个考题经常一起出现啊?
想不明白为啥call封装bind,函数防抖两个问题总是一起出现,看代码共同处都用到了apply,转换this指向。它们和curry又有什么联系吗?还是说我应该研究一下apply转换this指向都有哪些具体的场景呢?
咖啡厅要关门了,今天就简单写到这儿吧!
function debounce(fn,delay) {
var last;
return function() {
var context = this;
clearTimeout(last);
setTimeout(() => {
return fn.apply(context,arguments);
},delay);
}
}
去除数组中的item元素,返回一个新数组。
function remove(array,item) {
var arr = [];
for(var i = 0; i < array.length; i++) {
if(array[i] !== item) {
arr.push(array[i]);
}
}
return arr;
}
remove([1,1,2,3,4],3);
reduce(有时间可以用reduce来实现一个排队发送请求的需求);
arr.reduce(callback[, initialValue])
var arr = [1,2,3,5,4];
arr.reduce((pre,cur) => {
return pre + cur;
});
slice(slice可以用来复制一个新的数组~)
function remove (arr) {
var newArr = arr.slice(0);
//splice方法可以复制一个数组
for (let i of arr) {
if(newArr[i] === item) {
newArr.splice(i,1);
}
}
return newArr;
}
remove([1,2,3,3,4],4);
获取data中所有性别是女的平均年龄 (待完成)
data{
province: [
{'湖北' :
[
{'sex': 'male','age': 10},
{'sex':'female','age': 20}
]
},
{'湖南' :
[
{'sex': 'male','age': 10},
{'sex':'female','age': 20}
]
}
]
}
var p = data.province;
console.log(p);