一、new运算符
语法
new constructor[([arguments])]
constructor
一个指定对象实例的类型的类或函数。
arguments
一个用于被 constructor 调用的参数列表。
描述
当代码 new Foo(...)
执行时,会发生以下事情:
- 一个继承自
Foo.prototype
的新对象被创建。 - 使用指定的参数调用构造函数
Foo
,并将this
绑定到新创建的对象。new Foo
等同于new Foo()
,也就是没有指定参数列表,Foo
*不带任何参数调用的情况。 - 由构造函数返回的对象就是
new
表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1创建的对象。(一般情况下,构造函数不返回值,但是用户可以选择主动返回对象,来覆盖正常的对象创建步骤)。
根据上面的条件,我们就可以写代码了
function myNew(constructor, ...args) {
//以构造器原型创建对象
let instance = Object.create(constructor.prototype);
//执行构造器,并把构造器内部的this指向返回的对象
let res = constructor.apply(instance, args);
//如果构造器有返回对象,则使用返回的对象,没有则使用以构造器原型创建对象
return typeof res === "object" ? res : instance;
}
测试代码
let mFunc = myNew(Foo, "张三");
mFunc.work();
console.log(mFunc.name);
二、call/apply方法
call语法
fun.call(thisArg, arg1, arg2, ...)
thisArg
在 fun 函数运行时指定的 this 值。
if(thisArg == undefined|null) this = window,
if(thisArg == number|boolean|string) this == new Number()|new Boolean()| new String()
arg1, arg2, ...
指定的参数列表。
返回值
使用调用者提供的 this
值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined
。
apply语法
func.apply(thisArg, [argsArray])
thisArg
可选的。在 func
函数运行时使用的 this
值。请注意,this
可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 null
或 undefined
时会自动替换为指向全局对象,原始值会被包装。
argsArray
可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func
函数。如果该参数的值为 null
或 undefined
,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。
其实call和apply的区别就是第二个参数,apply第二个参数是一个数组或者类数组。其他的和call一样,性能也一样。所以,自定义功能时,唯一的区别就是传递的参数。
根据上面的条件,我们就可以写代码了
Function.prototype.MyCall = function(context, ...args) {
//获取当前this(调用MyCall的函数),自定义的call方法在函数的原型对象上,所以typeof this =='function'
let mFunc = this;
//创建变量,作为指定this对象(call的第一个参数context)的属性名
let fnKey = "fnKey";
//把当前this(调用MyCall的函数)作为属性值保存到指定this对象(call的第一个参数context)上,属性名为上面定义的fnKey
context[fnKey] = mFunc;
//调用指定this对象(call的第一个参数context)上的当前this(调用MyCall的函数)
let result = context[fnKey](...args);
//执行结束,删除该属性
delete context[fnKey];
return result;
};
Function.prototype.MyApply = function(context, args) {
//获取当前this(调用MyCall的函数),自定义的call方法在函数的原型对象上,所以typeof this =='function'
let mFunc = this;
//创建变量,作为指定this对象(call的第一个参数context)的属性名
let fnKey = "fnKey";
//把当前this(调用MyCall的函数)作为属性值保存到指定this对象(call的第一个参数context)上,属性名为上面定义的fnKey
context[fnKey] = mFunc;
//调用指定this对象(call的第一个参数context)上的当前this(调用MyCall的函数)
let result = context[fnKey](...args);
//执行结束,删除该属性
delete context[fnKey];
return result;
};
测试代码
let obj = {
name: "张三",
id: 1002
};
function TestFunc(name, id) {
this.name = name;
this.id = id;
return {
name: this.name,
id: this.id
};
}
let resCall = TestFunc.MyCall(obj, "abc", 11111);
console.log(obj);
console.log(resCall);
let resApply = TestFunc.MyApply(obj, ["efg", 2222]);
console.log(obj);
console.log(resApply);
三、Object.create()方法
语法
Object.create(proto[, propertiesObject])
proto
新创建对象的原型对象
propertiesObject
可选。如果没有指定为 undefined
,则是要添加到新创建对象的可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应Object.defineProperties()的第二个参数。
返回新的对象,带着指定的原型对象和属性。
这里偷个懒,给新对象添加属性就采用Object.defineProperties()
,不熟悉Object.defineProperties()
可以点击上面蓝色部分查看,里面也有兼容版本polyfill的实现。
根据上面的条件,我们就可以写代码了
Object.prototype.myCreate = function(proto, propertiesObject) {
//判断传入的原型对象
if (typeof proto !== "object" && typeof proto !== "function") {
throw new TypeError("Object prototype may only be an Object");
} else if (proto === null) {
throw new Error(" Object.create不支持第一个参数为null");
}
if (propertiesObject === null) {
throw new Error(" Object.create第二个参数不能为null");
}
//创建一个构造函数
function F() {}
//设置构造函数的原型为新创建对象的原型对象
F.prototype = proto;
//构造器的原型对象的constructor指向自身,防止原型链错乱
F.prototype.constructor = F;
//创建实例对象
let newObj = new F();
//加到新创建对象的可枚举属性
if (typeof propertiesObject != "undefined") {
//这里偷懒,这个API暂时就不自定义
Object.defineProperties(newObj, propertiesObject);
}
return newObj;
};
测试代码
let obj = {};
let propertiesObj = {
property1: {
value: true,
writable: true
},
property2: {
value: "Hello",
writable: false
}
};
console.log(Object.create(obj, propertiesObj));
let myObj = Object.myCreate(obj, propertiesObj);
console.log(myObj);
四、数组的map方法
语法
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
callback
生成新数组元素的函数,使用三个参数:
currentValue
callback 数组中正在处理的当前元素。
index可选
callback 数组中正在处理的当前元素的索引。
array可选
callback map 方法被调用的数组。
thisArg可选
执行 callback 函数时使用的this 值。
返回一个新数组,每个元素都是回调函数的结果。
根据上面的条件,我们就可以写代码了
Array.prototype.MyMap = function (callBack, context) {
// 浅拷贝要遍历的数组
var copyArr = Array.prototype.slice.call(this);
//有就使用,null或者undefined,设定为全局对象
context = context || window;
//调函数的结果
var resultArr = [];
for (let index = 0; index < copyArr.length; index++) {
//是否是自己的属性
if (!copyArr.hasOwnProperty(index)) continue;
//把回调结果放入返回的数组中,回调函数按照上面设置为三个参数
resultArr.push(callBack.call(context, copyArr[index], index, this));
}
return resultArr;
}
测试代码
let arr = [1, 2, { name: '123' }];
arr.MyMap(function(item,index,context){
console.log('item:'+item,"index:"+index);
console.log(this);
},{id:123});
let arr = [1, 2, { name: '123' }];
let newArr= arr.MyMap(function(item,index,context){
console.log('item:'+item,"index:"+index);
console.log(this);
return {name:item}
});
console.log(newArr);
另外,map方法中,对于每一项是浅拷贝。
let arr = [1, 2, { name: '123' }];
arr.map(function (item,index) {
if (typeof item === 'object') {
item.id = 4555;
} else {
item = index;
}
});
console.log(arr);
所以,上面采用浅拷贝就行,浅拷贝和深拷贝有疑惑的,可以阅读一下这篇文章
五、数组的reduce方法
语法
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
callback
执行数组中每个值的函数,包含四个参数:
accumulator
累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。
currentValue
数组中正在处理的元素。
currentIndex可选
数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则为1。
array可选
调用reduce()的数组
initialValue可选
作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。
返回函数累计处理的结果。
根据上面的条件,我们就可以写代码了
Array.prototype.myReduce = function (callBack, initialValue) {
// 浅拷贝要遍历的数组
let copyArr = Array.prototype.slice.call(this);
//提供初始值,从第一项开始,没有提供从第二项开始
let currentIndex = initialValue ? 0 : 1;
let result = initialValue ? initialValue : copyArr[0];
for (let index = currentIndex; index < copyArr.length; index++) {
//调用回调函数,按照上面的设置四个参数
result = callBack.call(null, result, copyArr[index], index, this);
}
return result;
}
下面是测试代码
let redarr = [1, 2, 3, 4, 5];
let result = redarr.reduce(function (accumulator, item) {
return accumulator + item;
}, 10);
console.log(result);
let mResult = redarr.myReduce(function (accumulator, item) {
return accumulator + item;
return
}, 10);
console.log(mResult);
bind方法
语法
function.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg
调用绑定函数时作为this
参数传递给目标函数的值。 如果使用new
运算符构造绑定函数,则忽略该值。当使用bind
在setTimeout
中创建一个函数(作为回调提供)时,作为thisArg
传递的任何原始值都将转换为object
。如果bind
函数的参数列表为空,执行作用域的this
将被视为新函数的thisArg
。
arg1, arg2, ...
当目标函数被调用时,预先添加到绑定函数的参数列表中的参数。
返回一个原函数的拷贝,并拥有指定的this值和初始参数。
根据上面的条件,我们就可以写代码了
Function.prototype.myBind = function(context, ...args) {
//获取当前方法
let _that = this;
//创建返回的函数
let mNewFunc = function(...argsNew) {
//把参数拼接,并改变原函数的this对象,返回原函数的返回值
return _that.apply(context || window, [...args, ...argsNew]);
};
//保证原函数的原型对象上的属性不丢失
mNewFunc.prototype = Object.create(_that.prototype);
return mNewFunc;
};
测试代码
var myName = "999";
let module = {
myName: "上海"
};
function bindFuc(args) {}
bindFuc.myName = "ABCDE";
function textFuc(args) {
console.log("args:", arguments);
console.log("myName:" + this.myName);
}
var boundTextFuc = textFuc.bind(module, "123");
boundTextFuc("145");
var boundTextFuc = textFuc.myBind(module, "123");
boundGetX("145");
instanceof运算符
语法
object instanceof constructor
object
要检测的对象
constructor
某个构造函数
instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
根据上面的条件,我们就可以写代码了
Object.prototype.myInstanceof = function(constructor) {
//获取要检测的对象
let object = this;
//判断constructor是否是对象
if (constructor == null || typeof constructor !== "function") {
return new Error("第二个参数必须为构造函数");
}
//获取验检测对象的原型
let objProto = Object.getPrototypeOf(object);
//循环在检测对象的原型链上查找是否存在constructor.prototype
while (true) {
//排除检测对象是Object.prototype的原型的情况
if (objProto == null) return false;
if (objProto == constructor.prototype) return true;
objProto = Object.getPrototypeOf(objProto);
}
};
测试代码
function TestFunc() {}
let mTestFunc = new TestFunc();
console.log(mTestFunc.myInstanceof(Number),mTestFunc instanceof Number);
console.log(mTestFunc.myInstanceof(Function),mTestFunc instanceof Function);
console.log(mTestFunc.myInstanceof(Object),mTestFunc instanceof Object);
console.log(Function.myInstanceof(Object),Function instanceof Object);
console.log(Object.myInstanceof(Function),Object instanceof Function);