「Note」呼び出し、適用、バインド、新規のシミュレーション実装

参照リンク:github.com/mqyqingfeng…

1.電話する

パラメータを渡してすぐに実行します

指定されたこの値といくつかの指定されたパラメーター値を使用して関数またはメソッドを呼び出します。

var foo = { value : 1}
function bar(){
    console.log(this.value)
}
bar.call(foo)// 1
// call 改变了 this 的指向,指向了 foo;
// bar 函数执行了;
复制代码

指定されたこの値を達成するために、シミュレーション手順は次のように分割されます。

  • 関数をオブジェクトのプロパティとして設定します。
  • 関数を実行します。
  • 関数を削除します。
Function.prototype.call = function(context){
    // 获取调用 call 的函数,用 this 可以获取
    console.log(this)// bar(){ console.log( this.value ) }
    context.fn = this
    context.fn()
    delete context.fn
}
// 测试一下
var foo = { value : 1 }
function bar(){
    console.log(this.value)
}
bar.call(foo)// 1,相当于foo.bar()
复制代码

指定されたいくつかのパラメーター値を実装します。

  • Argumentsオブジェクトから値を取得し、最後から2番目の引数を取り、それらを配列に配置します
Function.prototype.call = function(context){
    context.fn = this
    
    var args = [...arguments].slice(1)
    context.fn(...args)
    
    delete context.fn
}
// 测试一下
var foo = { value : 1 }
function bar(name,age){
    console.log(this.value)
    console.log(name)
    console.log(age)  
}
bar.call(foo,'zouyan','18')
// 1
// zouyan
// 18
复制代码

最適化:

  • このパラメーターはnullを渡すことができ、nullの場合、ウィンドウを指していると見なされます。
  • 関数は戻り値を持つことができます。
Function.prototype.call = function(context) {
  var context = context || window
  context.fn = this
  var args = [...arguments].slice(1)
  var result = context.fn(...args)
  delete context.fn
  return result
}
// 测试一下
var value = 2
var foo ={ value : 1 }
function bar(name,age){
    console.log(this.value)
    return{
        value: this.value,
        name: name,
        age:age
    }
}
bar.call(null)// 2
bar.call(foo,'zouyan',18)// {value:1,name:'zouyan',age:'18'}
复制代码

2.適用する

パラメータ配列を渡して、すぐに実行します

Function.prototype.apply = function(context, arr) {
  var context = Object(context) || window
  context.fn = this

  var result
  if (!arr) {
    result = context.fn()
  } else {
    var args = arr || []
    result = context.fn(...args)
  }
  delete context.fn
  return result
}
// 测试一下
var value = 2
var foo ={ value : 1 }
function bar(name,age){
    console.log('value',this.value)
    return{
        value: this.value,
        name: name,
        age:age
    }
}
bar.apply(null)
bar.apply(foo,['zouyan',18])// {value:1,name:'zouyan',age:'18'}
复制代码

3.バインド

手動で実行する必要があるパラメータと戻り関数を渡します

  • bind()メソッドは新しい関数を作成します。
  • 実行時に、bindの最初のパラメーターをこのように渡します。
  • 渡された他のパラメーターは、関数ランタイムのパラメーターとして使用されます。
  • 2つの機能:パラメータを渡すことができる関数を返します。
// 模拟返回函数:
Function.prototype.bind = function(cxt){
    var self = this
    return function(){
        return self.apply(cxt)
    }
}
// 模拟传参
Function.prototype.bind = function(cxt){
    var self = this
    // 获取 bind 函数从第二个参数到最后一个参数
    var args = [].slice.call(arguments, 1)
    return function(){
        // arguments 指 bind 返回的函数传入的参数
        var newArgs = args.concat([].slice.call(arguments))
        return self.apply(cxt, newArgs)
    }
}
复制代码

バインドされた関数は、new演算子を使用してオブジェクトを作成することもできます。これは、元の関数がコンストラクターであるかのように機能します。指定されたこの値は無視され、引数は呼び出し時にモック関数に提供されます。

// 模拟实现构造函数
Function.prototype.bind = function(cxt){
    var self = this
    var args = [].slice.call(arguments, 1)
    var fNOP = function(){}
    var fBound = function(){
        var newArgs = args.concat([].slice.call(arguments))
        return self.apply(this instanceof fNOP ? this : cxt, newArgs)
    }
    fNOP.prototype = this.prototype
    fBound.prototype = new fNOP()
    return fBound
}
// 调用 bind 函数,不是函数则报错
// 兼容
Function.prototype.bind = function(cxt){
    if(typeof this !== "function"){
        throw new Error("is not a function")
    }
    var self = this
    var args = [].slice.call(arguments, 1)// 获取第二个参数到最后一个参数
    var fNOP = function(){}
    var fBound = function(){
        var newArgs = args.concat([].slice.call(arguments)) 
        return self.apply(this instanceof fNOP ? this : cxt, newArgs)
    }
    fNOP.prototype = this.prototype
    fBound.prototype = new fNOP()
    return fBound
}
复制代码

4.新規

  • インスタンスはコンストラクターのプロパティにアクセスできます。
  • インスタンスは、コンストラクタープロトタイプのプロパティにアクセスできます。

実装手順:

  • ①新しいオブジェクトを作成するobj:newの結果は新しいオブジェクトであるため。
  • obj._proto_プロパティはコンストラクタのプロトタイプを指します。インスタンスはプロトタイプのプロパティにアクセスする必要があるためです。
  • ③applyを使用して、objに新しいプロパティを追加します。objにはコンストラクターにプロパティがあるためです。
  • ④戻り値がオブジェクトかどうかを判断すると、オブジェクトを返すオブジェクトです。そうでない場合は、objを返します。コンストラクターに戻り値がある場合があります。
// 模拟实现 new 关键字
function objectFactory() {
    // 步骤 ①
    var obj = new Object(),//存疑,为什么模拟new里面使用new?
    //var obj = Object.create(null),//报错:TypeError
    //var obj = {},//正常
    //var obj = Object.create({}),//正常
    //var obj = Object.create(Object.prototype),//正常
    
    // 步骤 ②
    // 获取构造函数,截取第一个参数;
    // shift 会修改原数组,所以 arguments 会被去除的一个参数;
    Constructor = [].shift.call(arguments);// 等同于 Array.prototype.shift.call(arguments)
    obj.__proto__ = Constructor.prototype; 
    
    var ret = Constructor.apply(obj, arguments); // 步骤 ③
    return typeof ret === 'object' ? ret||obj : obj; // 步骤 ④
};
// 构造函数
function Otaku (name, age) {
    this.name = name;
    this.age = age;
    this.habit = 'Games';
}
Otaku.prototype.strength = 60;
Otaku.prototype.sayYourName = function () {
    console.log('I am ' + this.name);
}
// 模拟创建实例
var person = objectFactory(Otaku, 'Kevin', '18')

console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60
person.sayYourName(); // I am Kevin
复制代码

おすすめ

転載: juejin.im/post/7078569691177812005