function go(n) {
// n here is defined!
console.log(n); // Object {a: [1,2,3]}
for (let n of n.a) { // ReferenceError 块作用并未初始化n值,故无n.a
console.log(n);
}
}
go({a: [1, 2, 3]});
//块作用域与函数作用域
var a = 1;
var b = 2;
if (a === 1) {
var a = 11; // the scope is global
let b = 22; // the scope is inside the if-block
console.log(a); // 11
console.log(b); // 22
}
console.log(a); // 11
console.log(b); // 2
/*
map函数总结
不会遍历没有初始化下标的数组(Aarry(10)),若调用将会返回 [ <10 empty items > ]
map一开始遍历就已确定遍历范围,不会改变数组长度,不会改变原数组,返回一个遍历执行回调函数将结果放入数组的新数组
箭头函数勿乱使用,当需要函数需要绑定this的值,不要写回调函数箭头函数中的this无法修改
*/
Array.prototype.myMap = function(callback, context) {
//判断this不能为空
if(this === null || this === undefined){
throw new TypeError('cannot read property map of null or undefined');
}
//判断callback必须是一个函数
if (Object.prototype.toString.call(callback) !== '[object Function]') {
throw new TypeError(callback + 'is not a function');
}
const arr = Object(this);
const len = this.length >>> 0;
//判读数组仅初始化长度为初始化值时的返回情况 判断数组是否初始化了下标
let k = 0;
while(k < len && !( k in arr)){
k++;
}
if(k >= len){
return `[ < ${len} empty items > ]`;
}
var newArr = [];
for (var i = 0; i < len; i++) {
newArr.push(callback.call(context, arr[i], i, arr));
}
return newArr;
};
filter函数
Array.prototype.achieveFilter = function (callback,context){
if(this === null && this === undefined){
throw new TypeError('cannot read property filter of null or undefined');
}
if(typeof callback !== 'function'){
throw new TypeError(callback + 'is not a function');
}
const arr = Object(this);
const len = arr.length >>> 0;
var resArr = [];
for(let i = 0; i < len; i++){
if(callback.call(context,arr[i],i,arr)){
resArr.push(arr[i])
}
}
return resArr;
}
reduce
Array.prototype.achieveReduce = function (callback,initialValue){
//== 宽松相等 null只会和undefined和null相等 先比较类型在比较值 string number string => number number boolean boolean => number进行比较 重点会进行类型转换拿 和对象比较则会调用toPrimitive抽象方法通过valueOf() 或者toString()方法得到值后进行比较
if(this === null && this === undefined){
throw new TypeError('cannot read property of null or undefined');
}
if(typeof callback != 'function'){
throw new TypeError(`${callback} is not a function`);
}
const arr = Object(this);
//初始值存在时下标为0否则为1
let acc = initialValue || arr[0];
let startIndex = initialValue ? 0 : 1;
let k = 0;
//判断是否为空数组 针对Array(10)判断数组是否为空
while(k < arr.length && !(k in arr)){
k++;
}
//判断空数组时候的情况
if(k >= arr.length){
return initialValue ? initialValue : new TypeError('Reduce of empty array with no initial value');
}
for(var i = startIndex; i < arr.length; i++){
acc = callback(acc, arr[i], i, arr);
}
return acc;
}
reduce 递归实现
const reduceHelper = (callback, acc, idx, arr) => {
if (idx === arr.length) return acc;
return reduceHelper(callback, callback(acc, arr[idx], idx, array), idx++, arr);
};
Array.prototype.achieveReduce = function(callback, initialValue) {
if (this == null) {
throw new TypeError('this is not null or undefined');
}
if (typeof callback != 'function') {
throw new TypeError(`${callback} is not function`);
}
const arr = this;
let k = 0;
let acc = initialValue || arr[0];
let startIndex = initialValue ? 0 : 1;
while (k < arr.length && !(k in arr)) {
k++;
}
if (k >= arr.length) {
return initialValue ? initialValue : new TypeError('reduce of arr is not empty and initialValue is undefined');
}
return reduceHelper(callback, acc, startIndex, arr);
};
splice函数
Array.prototype.spliceMy = function(startIndex, deleteCount, ...addValue) {
if (this === null || this === undefined) {
throw new TypeError(`cannot read property 'splice' of null or undefined`);
}
let len,
arr,
deleteArr = [],
addLen = addValue.length,
argsLen;
arr = Object(this);
len = arr.length >>> 0; //取整效果
argsLen = arguments.length;
startIndex = calcStartIndex(startIndex, len); // 计算开始下标合法性 为负为正超出数组长度
deleteCount = calcDeleteCount(deleteCount, startIndex, len, argsLen); //计算删除元素合法性 为负 或者超出数组元素
//计算删除元素数组, 结果返回删除的数组
calcDeleteArr(arr, startIndex, deleteCount, len, deleteArr);
//根据删除和添加的元素移动数组
calcMoveArr(arr, startIndex, deleteCount, len, addLen);
//已将插入数据的位置移动出来,开始插入数据
for (let i = 0; i < addLen; i++) {
arr[i + startIndex] = addValue[i];
}
//密封 configurable:false 不可以添加属性 冰冻 frozen configurable:false writable:false 不可添加属性和修改属性值
if (Object.isSealed(arr) && deleteCount !== addLen) {
throw new TypeError('the arr is sealed');
}
if (Object.isFrozen(arr) && (deleteCount > 0 || addLen > 0)) {
throw new TypeError('the arr is frozen');
}
arr.length = len + addLen - deleteCount;
return deleteArr;
};
//判断起始位置是否合法 如果起始位置为负 则为 startIndex + len ,若负的超过数组长度起始位置为0
function calcStartIndex(startIndex, len) {
if (startIndex < 0) {
return startIndex + len >= 0 ? startIndex + len : 0;
}
return startIndex >= len ? len - 1 : startIndex;
}
//删除长度为负则删除个数为0 删除元素超出数组长度 则删除数组剩下的元素 若果没有传值 也删除剩下的
function calcDeleteCount(deleteCount, startIndex, len, argsLen) {
// if (deleteCount === undefined) return len - startIndex;
if (argsLen === 1) return len - startIndex;
if (deleteCount < 0) {
return 0;
}
return deleteCount > len ? len - startIndex : deleteCount;
}
function calcDeleteArr(arr, startIndex, deleteCount, len, deleteArr) {
for (let i = 0; i < deleteCount; i++) {
deleteArr[i] = arr[i + startIndex]; //删除数组
}
}
function calcMoveArr(arr, startIndex, deleteCount, len, addLen) {
if (deleteCount === addLen) return; // 如果删除数据和添加数据长度一致,则不用移动数组,直接修改相应位置上的值
if (deleteCount > addLen) {
//数据前移deleteCount - len这么个长度
for (let i = startIndex + deleteCount; i < len; i++) {
let fromIndex = i; //需要移动的元素下标
let toIndex = i - (deleteCount - addLen); //计算移动后的下标
arr[toIndex] = arr[fromIndex]; //进行移动
}
//删除多余元素
for (let i = len - 1; i >= len + addLen - deleteCount; i--) {
delete arr[i];
}
} elseif (deleteCount < addLen) {
//后移不用删除元素
for (let i = len - 1; i >= startIndex + deleteCount; i--) {
let fromIndex = i;
let toIndex = i + addLen - deleteCount;
arr[toIndex] = arr[fromIndex];
}
}
}
let arr = [1, 2, 3];
console.log(arr.spliceMy(0, 4));
console.log(arr);
push方法/pop方法
//delete 删除数组时 会删除相应属性,但不会修改数组长度
Array.prototype.pushI = function(...addValues) {
//返回数组长度
let arr = Object(this);
let len = arr.length >>> 0;
for (let i = 0; i < addValues.length; i++) {
arr[i + len] = addValues[i];
}
return len + addValues.length;
};
Array.prototype.popI = function() {
//返回弹出的元素值
let arr = Object(this);
let len = arr.length >>> 0;
if (len === 0) {
return undefined;
}
len--;
let value = arr[len];
delete arr[len]; //delete会删除属性 但不会修改length值
arr.length = len;
return value;
};
sort方法
// sort是结合直接插入排序和快速排序的一种思路
/**
* 1. n < 10 使用直接插入排序
* 2. n < 1000 使用快速排序
* 3. n > 1000 隔200 - 215抽出一个数组成数组,排序后去中位数作为哨兵
*/
every方法
Array.prototype.every = function(callback, context){
let len , arr;
if(this == undefined){
throw new TypeError('cannot read property of null or undefined');
}
if(typeof callback != 'function'){
throw new TypeError(`${callback} is not a function`);
}
arr = Object(this);
let = arr.length >>> 0;
//没有初始化的下标不会执行callback函数
for(let i = 0 ; i < len; i++){
if(i in arr && !callback.call(context, arr[i] , i, arr)){
returnfalse;
}
}
returntrue;
}
some方法
Array.prototype.some = function(callback, context){
let len , arr;
if(this == undefined){
throw new TypeError('cannot read property of null or undefined');
}
if(typeof callback != 'function'){
throw new TypeError(`${callback} is not a function`);
}
arr = Object(this);
let = arr.length >>> 0;
//没有初始化的下标不会执行callback函数
for(let i = 0 ; i < len; i++){
if(i in arr && callback.call(context, arr[i] , i, arr)){
returntrue;
}
}
returnfalse;
}