手写call方法
手写call思路:对象通过 Object.attributes 来访问它的属性.这时给对象添加一个属性,该属性指向需要绑定对象的函数。
通过Object.attributes去调用函数,函数中的this 指向了调用它的对象Object. 最后将属性从对象中移除。
1. object.f = this
2. object.f()
3. delete object.f;
Function.prototype.myCall = function(context) {
const self = context || window;
let arg = Array.prototype.slice.call(arguments,1)
self.f = this;
self.f(...arg);
delete self.f;
}
// 测试
function getUser(age){
console.log(this.name);
console.log(age)
}
let user = {
name: 'Jason'
}
getUser.myCall(user,24)
- argument类数组转换为数组的方法
//方法一
let arg = Array.prototype.slice.call(argment,1)
//方法二
let arg = Array.prototype.concat.apply([],arguments)
//方法三
let arg = Array.from(arguments)
// 方法四
let arg = [...arguments]
- ...展开语法传递参数
Function.prototype.myCall = function(context, ...item) {
const self = context || window;
self.f = this;
self.f(...item);
delete self.f;
}
// 测试
function getUser(age){
console.log(this.name);
console.log(age);
}
let user = {
name: 'Jason'
}
getUser.myCall(user,24)
如上代码中的 const self = this || window 是用指定传入的对象为null时,默认为window对象
手写apply方法
apply与call的实现方式相同,apply只能出入两个参数, 第一个参数为绑定的this对象,第二个参数为一个数组,作为函数的参数。
Function.prototype.myApply = function(context, arr) {
const self = context || window;
if(!Array.isArray(arr)){
throw new TypeError("传入的参数类型不正确,传入一个数组");
}
self.f = this;
self.f(...arr);
delete self.f;
}
// 测试
function getAge(age){
console.log(age)
}
getAge.myApply(null, 24)
*arguments 实现apply可传递多个参数(其实的是一个伪数组对象)
Function.prototype.myApply = function(context) {
const self = context || window;
let arg = Array.prototype.slice.call(arguments,1)
if(!Array.isArray(arg)){
throw new TypeError("传入的参数类型不正确,传入一个数组");
}
self.f = this;
self.f(...arg);
delete self.f;
}
// 测试
function getAge(age){
console.log(age)
}
getAge.myApply(null, 24)
- ...展开语法实现apply传递多个参数(其实传入了一个数组)
Function.prototype.myApply = function(context,...item) {
const self = context || window;
if(!Array.isArray(item)){
throw new TypeError("传入的参数类型不正确,传入一个数组");
}
self.f = this;
self.f(...item);
delete self.f;
}
// 测试
function getAge(age){
console.log(age)
}
getAge.myApply(null, 24)
手写bind方法
bind与call,apply 不同在于函数执行后将创建一个新函数返回。bind函数可传入两个参数,第一个参数this绑定的对象,
第二个参数是一个数组或者类数组对象,第二个参数将作为实参在新函数执行时被传入。
Function.prototype.myBind = function(context){
const obj = context || window;
const self = this;
let arg = Array.prototype.slice.call(arguments, 1);
return function(){
let arg2 = Array.prototype.slice.call(arguments, 1);
self.apply(obj, arg.concat(arg2));
}
}
如上mybind创建的新函数作为普通函数调用时this指向你所绑定的对象。当做为构造函数通过new去创建实例对象时this绑定的对象就
会被忽略了。因为构造函数中的会隐式创建一个实例对象,this指向这个实例对象。而不再是指向你所指定的对象。
Function.prototype.myBind = function(context){
const obj = context || window;
const self = this;
let arg = Array.prototype.slice.call(arguments, 1);
const newFun = function(){
let arg2 = Array.prototype.slice.call(arguments, 1);
if(this instanceof newFun) {
self.apply(this, arg.concat(arg2));
} else {
self.apply(obj, arg~~~~.concat(arg2));
}
}
//支持 new 创建对象时,实例__proto__指向绑定对象函数的prototype
newFun.prototype = this.prototype
return newFun;
}
// 测试
let user = {
name: 'Jason',
age: 23,
}
function Fun(school) {
this.school = school;
console.log(this.name);
console.log(this.age);
console.log(this.school);
}
let fun = Fun.myBind(user, '江南大学');
// this -> user
fun()
// this -> 对象实例
let obj = new fun();
console.log(obj.__proto__ === Fun.prototype) // ture
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。