01.call函数的实现
function foo() {
console.log('函数被执行了', this); => {
}
}
// 系统的call函数
foo.call({
});
// 需要给foo添加自己的call函数,如果是直接写出foo.hycall(),不具备通用性,换成另外的函数不适用,所以把它添加到函数的原型上,变成通用的,任何函数的可以使用
Function.prototype.hycall = function (thisArg, ...restParameters) {
// ...restParameters 这个剩余参数 不管有没有参数都返回一个空数组
// console.log('hycall函数被执行了');
//在这里可以去执行调用的那个函数(foo)
// 问题:的可以获取到是哪一个函数执行了hycall
// 1.获取需要被执行的函数 -- 重点
var fn = this;
// fn();//这里直接调用相当于是独立函数调用
// fn.call(thisArg) //但是这样实现不太好,我们本身写的这个函数就是call,
// 所以我们可以fn函数添加到这个thisArg这个传进来的参数上,然后进行调用
// 2.对thisArg转成对象类型(防止它传入的是非对象类型) -- 重点
// 加上一个判断条件,系统的call函数 当为null和undefined时默认绑定window
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
// 3.调用被执行的函数 -- 重点
thisArg.fn = fn;
// 这里是展开运算符 restParameters
var result = thisArg.fn(...restParameters);
delete thisArg.fn;
// 4.将最终结果返回出去 -- 重点
return result;
}
// 自己是写的函数hycall方法
// 默认进行隐式绑定(这里隐式绑定调用了函数,所以要想拿到foo,直接可以使用this)
var result = sum.hycall({
name: 'why' }, 20, 30, 40, 50);
console.log(result);
// 发现传入非对象类型的时候报错,无法添加函数对象,这时候需要把非对象类型转成对象类型,在转的过程,需要判断一下是否为null和undefined,null和undefined默认设置指向全局window
// 因为系统的call就是这样的null和undefine的默认指向window
sum.hycall('123');
sum.hycall(1);
02.ES6的剩余参数补充:
// reste parameters
function sum(...restParameters) {
// => 函数接收参数的时候是剩余参数
console.log(restParameters);
}
sum(10)
sum(10, 20)
sum(10, 20, 30)
sum(10, 20, 30, 40, 50)
// 站看运算符 spread
var names = ['abc', 'cba', 'nba'];
var newNames = [...names]
// console.log(newNames);
function foo(name1, name2, name3) {
console.log(name1, name2, name3);
}
// 相当于把names展开传到foo的里面去 =>这里是扩展运算符
foo(...names)
03.apply函数的实现
// 自己实现apply
Function.prototype.hyApply = function (thisArg, argArray) {
// 1.获取需要调用的函数
var fn = this;
// 2.处理绑定的thisArg
thisArg = thisArg ? Object(thisArg) : window
thisArg.fn = fn;
// 3.执行函数
let result = ''
// if (!argArray) { // argArray是没有值(没有传参数)
// result = thisArg.fn(...argArray)
// } else {// 有传参数
// result = thisArg.fn(...argArray)
// }
argArray = (argArray !== null && argArray !== undefined) ? argArray : []
// argArray = argArray || []
// 相当于...undefined undefined是不能被迭代的
thisArg.fn(...argArray)
delete thisArg.fn;
// 4.返回结果
return result;
}
function sum(num) {
console.log('sum函数被执行了', this, num);
return num
}
// sum.apply({}, 10)
// 两种情况:一种是只有一个参数是不行的,还有一种是没有参数
sum.hyApply(0, [20])
04.bind函数的实现
// 自己实现的bind函数
Function.prototype.hyBind = function (thisArg, ...argArray) {
// 1.获取到真实需要调用函数
var fn = this //相当于 function sum(){} thisArgs相当于传进来的this指向参数
// 2.处理thisArg的绑定
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
// 这里返回一个函数
function proxyFn(...args) {
// 3.将函数放到thisArg中进行调用
thisArg.fn = fn;
// 特殊:对两个传入的参数进行合并
const finalArgs = [...argArray, ...args]
var result = thisArg.fn(...finalArgs);
delete thisArgf.fn;
// 4.返回结果
return result;
}
return proxyFn
}
function sum(num1, num2) {
console.log('sum函数被调用了', this, num1, num2);
return num1 + num2;
}
// 系统默认的bind函数
// var bar = sum.bind({}, 20, 1)
// var bar = sum.bind({})
// console.log(bar(30, 20));;
// var bar = sum.bind({}, 10)
// console.log(bar(30));
var bar = sum.hyBind('abc', 10)
var result = bar(20);
console.log(result);
05.arguments基本使用
// arguments是一个对应于 传递给函数的参数的类数组(array-like)对象
// array-like意味着他不是一个数组类型,而不是一个对象类型:
// 但是它却拥有数组的一些特性,比如说length, 比如可以通过index索引来访问;
// 但是他却没有数组的一些方法,比如forEach、map等;
/**
*var ao = {
num1:undefined,
num2:undefined,
argumetns:{}
}
*/
function foo(num1, num2, num3) {
// 类数组对象中(长得像是一个数组,本质上是一个对象):arguments
console.log(arguments);
// 常见的对arguments的操作是三个
// 1.获取参数的长度
console.log(arguments.length);
// 2.根据索引值来获取某一个参数
console.log(arguments[2]);
console.log(arguments[3]);
console.log(arguments[4]);
// 3.callee获取当前arguments所在的函数
console.log(arguments.callee);
// console.log(arguments.callee());//不能调用,调用了就是递归 没有结束条件就会造成页面卡死
}
foo(10, 20, 30, 40, 50)
06.arguments转array的方式
function foo(num1, num2) {
// console.log(arguments);
// 1. 自己遍历
// var newArr = [];
// for (let i = 0; i < arguments.length; i++) {
// newArr.push(arguments[i] * 10)
// }
// console.log('newArr=', newArr);
// 2.argumetns转成数组类型
// 2.1. 自己遍历arguments中所有的元素
// 2.2. 将arguments转成array
// 我们把这个slice的this指向argumetns
// 我们把这个this(argumetns)放入到一个可迭代的、可遍历的元素,如果这里没有传长度的话,
// 就会把它全部放入到一个数组里面,最终给他返回
var newArr2 = Array.prototype.slice.call(arguments)
console.log('newArr2=', newArr2);
var newArr3 = [].slice.call(arguments);
console.log('newArr3=', newArr3);
// 2.3. ES6的语法
var newArr4 = Array.from(arguments);
console.log('newArr4=', newArr4);
var newArr5 = [...arguments]
console.log('newArr5=', newArr5);
}
foo(10, 20, 30, 40, 50)
// // 在Function的原型中添加了一个aaa函数
// Function.prototype.aaa = function () { }
// function foo() { }
// // 存在一个函数就可以调用aaa
// foo.aaa();
// 如果说压根就没有这个函数对象呢,我们也想要去调用aaa,我们就可以去拿Function.prototype.aaa
// Array.prototype.slice = function(){ }
// var nums = [1, 2, 3, 4];
// nums.slice()//是可以直接调用
// Array中的slice实现
Array.prototype.hyslice = function (start, end) {
console.log(this);
var arr = this;
start = start || 0;
end = end || arr.length
var newArr = [];
for (var i = start; i < end; i++) {
newArr.push(arr[i])
}
return newArr;
}
// var newArray = Array.prototype.hyslice.call(['aaa', 'bbb', 'cccc', 'dddd'])
// console.log(newArray);
// var names = ['aaa', 'bbb', 'cccc', 'dddd'];
// names.slice(1, 2)
07.箭头函数中没有arguments
var name = 'arguments'
// 1.案例一:
var foo = () => {
// console.log(name);
console.log(arguments);
}
foo();
//在浏览器中是没有argumetns
// 在node中是偶argumetns的,为什么?
// - 在node中一个js文件会被当成一个模块,然后这个模块会被包裹在一个函数里面
// - 然后去执行这个函数 .call({},ad,sd,fads) ,后面这些参数就是argumetns,这个参数也放到了全局的arguments
function fn(num1, num2) {
console.log(arguments);
}
fn(1, 2)
// 2.案例二:
function foo() {
var bar = () => {
console.log(arguments);
}
return bar;
}
var fn = foo(123);
fn();
// 案例三:
// 箭头函数就是没有arguments
var foo = (num1, num2, ...args) => {
console.log(args);
}
foo(10, 20, 30, 405, 80)