手写 call
Function.prototype.myCall=function(context){
if(typeof this !== 'function'){
throw new TypeError('not function');
}
// 首先 context 为可选参数,如果不传的话默认上下文为 window
context =context || window
// 接下来给 context 创建一个 fn 属性,并将值设置为需要调用的函数
context.fn=this;
// 因为 call 可以传入多个参数作为调用函数的参数,所以需要将参数剥离出来
let args=[...arguments].slice(1);
// 然后调用函数并将对象上的函数删除
let fullName=context.fn(...args);//核心
delete context.fn;
return fullName;
}
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
person.fullName.myCall(person1, "Seattle", "USA");
//"Bill Gates,Seattle,USA"
apply 的实现也类似,区别在于对参数的处理
Function.prototype.myApply=function(context){
if(typeof this !== 'function'){
throw new TypeError('not function');
}
// 首先 context 为可选参数,如果不传的话默认上下文为 window
context =context || window
// 接下来给 context 创建一个 fn 属性,并将值设置为需要调用的函数
context.fn=this;
// 因为 apply 可以传入参数数组
let fullName;
if(Array.isArray(arguments[1]) && arguments[1].length!==0){
//fullName=context.fn(arguments[1]); 输出:Bill Gates,Seattle,USA,undefined"
fullName=context.fn(...arguments[1]);
}else{
fullName=context.fn();
}
delete context.fn;
return fullName;
}
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
person.fullName.myApply(person1, ["Seattle", "USA"]);
bind使用:
let myWrite=document.write
myWrite()
VM1026:2 Uncaught TypeError: Illegal invocation
at <anonymous>:2:1
(anonymous) @ VM1026:2
myWrite.bind(document)
ƒ write() { [native code] }
Function.prototype.myBind = function (context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
const _this = this
const args = [...arguments].slice(1)
// 返回一个函数
return function F() {
//此处为闭包,注意this:_this = this
// 因为返回了一个函数,我们可以 new F(),所以需要判断
if (this instanceof F) {
//对于 new 的情况来说,不会被任何方式改变 this,所以对于这种情况我们需要忽略传入的 this:不用传context
return new _this(...args, ...arguments)
}
//bind 可以实现类似这样的代码 f.bind(obj, 1)(2),所以需要参数拼接
return _this.apply(context, args.concat(...arguments))
}
}
this.num = 9;
var module = {
num: 81,
getNum: function() { return this.num; }
};
module.getNum(); // 81
var getNum = module.getNum;
getNum(); // 9, 因为在这个例子中,"this"指向全局对象
// 创建一个'this'绑定到module的函数
var boundGetNum = getNum.myBind(module);
boundGetNum(); // 81
81
getNum();
9
bind使用:
function f(y, z){
return this.x + y + z;//x:1 y:2 z:3
}
var m = f.bind({x : 1}, 2);
console.log(m(3));
new
新生成了一个对象
链接到原型
绑定 this
返回新对象
function create() {
let obj = {}//创建空对象
let Con = [].shift.call(arguments)//获取构造函数
obj.__proto__ = Con.prototype//链接原型链
let result = Con.apply(obj, arguments)//绑定 this 并执行构造函数
return result instanceof Object ? result : obj
}