1、写一个方法:不定参数求和
前言:
1、类数组对象: 在javascript中,数组是一个特殊的对象,其property名为正数组,且其length属性会随着数组成员的增减而发生变化,同时又从arry构造函数中继承一些用于进行数组操作的方法,而对于一个普通的对象来说,如果它的所有property名均为正整数,同事也有相应的length属性,那么虽然该对象并不是由Array构造函数所创建的,它依然呈现出数组的行为,在这种情况下,这些对象被称为"类数组对象"
2、Array.from()对一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。
function Sum() {
// 1、获取参数个数---arguments(类数组对象)
// 2、类数组对象转化为数组
// [...arguments]
// Array.from(arguments)
// 3、数组求和
// return eval(Array.from(arguments).join("+"));
return [...arguments].reduce((pre,cur) => {
return pre + cur
})
}
console.log(Sum(1,2,3,4));//10
//arguments
2、创建一个长度为100的数组
-
length=100
-
new Array()
-
Array.from()
注:上面两种拿到的数组,都是empty,没有实际的使用效果; 使用Object.keys()可以拿到数组的index去生成数组
3、手写一个 new
function selfNew(param){
if(typeof param !== 'function') return '要是一个function';
selfNew.target = param;
let newObj = Object.create(param.prototype);
console.log(newObj,'newObjnewObjnewObj');
let arr = [...arguments].slice(1,arguments.length)
console.log(arr, 'arr');
let paramResult = param.apply(newObj, arr);
console.log(paramResult,'paramResultparamResultparamResultparamResult');
var isObject = typeof paramResult === 'object' && paramResult !== null;
var isFunction = typeof paramResult === 'function';
if(isObject || isFunction){
return paramResult;
}
return newObj;
}
function newOperator(ctor){
if(typeof ctor !== 'function'){
throw 'newOperator function the first param must be a function';
}
newOperator.target = ctor;
var newObj = Object.create(ctor.prototype);
console.log(newObj,'newObj-newOperator');
var argsArr = [].slice.call(arguments, 1);
console.log(argsArr,'argsArr-newOperator');
// 重置new.target
newOperator.target = null;
var ctorReturnResult = ctor.apply(newObj, argsArr);
console.log(ctorReturnResult,'ctorReturnResult-newOperator');
var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult !== null;
var isFunction = typeof ctorReturnResult === 'function';
if(isObject || isFunction){
return ctorReturnResult;
}
return newObj;
}
function Student(name, age) {
this.name = name;
this.age = age;
}
Student.prototype.doSth = function() {
console.log(`我是${this.name}`);
};
newStudent = new Student('new',18);
myStudent = selfNew(Student, 'selfNew',18);
operatorStudent = newOperator(Student, 'newOperator',18);
console.log(newStudent,newStudent.doSth(),'newStudent');
console.log(myStudent,myStudent.doSth(),'myStudent');
console.log(operatorStudent,operatorStudent.doSth(),'operatorStudent');
//newOperator方法来自于 https://juejin.cn/post/6844903704663949325
对target进行拦截处理,以防构造函数中含有构造函数,target的指向会有问题
const newOperator = (function () {
const _newStack = [];
function newOperator(ctor) {
// 设定new.target
newOperator.target = ctor;
// 生成新的对象,其隐式原型指向构造函数的原型对象
const obj = Object.create(ctor.prototype);
// 执行构造函数,并返回结果
const result = ctor.apply(
obj,
Array.prototype.slice.call(arguments, 1)
);
// 重置new.target
newOperator.target = null;
// 判断最终返回对象
return (typeof result === "object" && result !== null) ||
typeof result === "function"
? result
: obj;
}
// 设定target的get、set方法
Reflect.defineProperty(newOperator, "target", {
get() {
return _newStack[_newStack.length - 1];
},
set(target) {
if (target == null) {
_newStack.pop();
} else {
_newStack.push(target);
}
},
});
return newOperator;
})();
function B() {
if (newOperator.target === B) {
console.log("new调用 B");
} else {
console.log("非new调用 B");
}
return { balabala: 123 };
}
function A() {
const b = newOperator(B);
if (newOperator.target === A) {
console.log("new调用 A");
} else {
console.log("非new调用 A");
}
}
//此优化为 https://juejin.cn/post/6844903704663949325 网友的评论
4.手写call、apply、bind
call(参数用逗号隔开,不需要自调用)
Function.prototype.myCall = function(context, ...args) {
// 此时this指的是当前调用myCall的函数
if(typeof this !== 'function') return "It's must be a function"
// 绑定的对象是否存在,不存在 this指向window
if(!context) context = window;
// 创建一个唯一的fn作为绑定对象的属性
const fn = Symbol()
// 把this指向fn
context[fn] = this;
// 用其他的参数,调用fn拿到返回值
const result = context[fn](...args)
// 清除对象上的fn属性
delete context[fn]
return result
}
let ceshi = function(name, age, className) {
this.name = name,
this.age = age,
this.className = className
}
let obj = {
name: 'xiaohua',
age: 18
}
let school = {
className: 2,
age: 18
}
ceshi.myCall(obj, '小花','2',6);
ceshi.myCall(school, '3', 12,5);
console.log(obj, school);
apply(参数为数组,不需要自调用)
Function.prototype.myApply = function (context, args) {
// 此时this指的是当前调用myCall的函数
if(typeof this !== 'function') throw "It's must be a function"
// 绑定的对象是否存在,不存在 this指向window
if(!context) context = window;
// 创建一个唯一的fn作为绑定对象的属性
const fn = Symbol()
// 把this指向fn
context[fn] = this;
// 参数: 数组 || 类数组
if (typeof args !== 'object' || !args.length ) throw console.error('参数类型错误');
// 用其他的参数,调用fn拿到返回值 ---参数为类数组对象Array.from(args)
const result = context[fn](...Array.from(args))
// 清除对象上的fn属性
delete context[fn]
return result
}
let ceshi = function(name, age, className) {
this.name = name,
this.age = age,
this.className = className
}
let obj = {
name: 'xiaohua',
age: 18
}
let school = {
className: 2,
age: 18
}
ceshi.myApply(obj,['xiaohuaya',1,2])
ceshi.myApply(school,['shiwoa',2,3])
console.log(obj,school);
bind(参数用逗号隔开,需要自调用)