blog

関数の照合

i. つまり、2つの数値を足す元の実装では、1つの括弧で2つの引数を渡さなければなりませんでした。 関数巡回を使うと、各呼び出しは1つのパラメータを渡すだけで、無名関数を返し、それを呼び出すために別の...

May 6, 2020 · 9 min. read
シェア

I.

関数コリエリゼーションとは?複数の引数を取る関数を単一の引数を取る関数に変換すること。

別の関数を返す関数

function sum(x){
 return function(y){
 return x+y
 }
}
sum(1)(2) //3

普通のメソッドです:

function sum(x,y){
 return x+y
}

つまり、2つの数値の足し算を実装するには、1つの括弧で2つの引数を渡さなければならないことがわかります。

関数カーニングを使えば、1回の呼び出しで1つの引数を渡し、無名関数を返し、それをもう1つの引数で呼び出し、最終的な結果を得ます。

つの数値を足す場合も同様です:

function sum(x){
 return function(y){
 return function(z){
 return x+y+z
 }
 }
}
console.log(sum(1)(2)(3)) //6

II. Object.defineProperty

その設定可能なオプションは何ですか?

まず、このメソッドを使用して、オブジェクトに新しいプロパティを追加したり、既存のプロパティを変更したりすることができます。

構文Object.defineProperty(obj, prop, descriptor)

obj: 属性を定義するオブジェクト

prop: 追加または修正するプロパティの名前

descriptor: オブジェクト、プロパティ記述子

データ記述子

値の書き込み可能、書き込み不可能の2つの設定可能なオプションがあります。

Object.defineProperty(obj,'a',{
 value:1,
 writable:true
})

value は属性の値です。

writable は、属性が書き込み可能かどうかを示します。指定しない場合、デフォルトはfalseで、これはobj.aを変更できないことを意味します。しかし、指定した場合、エラーは発生しませんが、変更できないだけで、次にaの値を読み取るときには1のままです。

アクセス記述子

ゲッター関数とセッター関数によって記述されるプロパティ

var bValue = 38;
Object.defineProperty(o, "b", {
 get() { return bValue; },
 set(newValue) { bValue = newValue; },
});

両方のタイプの記述子に共通する設定オプション

enumerable

この属性は、この属性の enumerable キー値が true の場合のみ、オブジェクトの列挙プロパティに表示されます。デフォルトはfalseです。

プロパティが列挙可能かどうかは、for(let key in obj) でそのプロパティをループ・オーバーできるかどうか、および Object.keys() が列挙可能かどうかで示されます。tureの場合、両方の操作でプロパティが取得されます。falseの場合は、プロパティを取得しません。

configurable

オブジェクトの属性を削除できるかどうか、valueとwriteableプロパティ以外のプロパティを変更できるかどうかを示します。設定されていない場合、デフォルトは false です。

データ記述子を見てください:

let obj={}
Object.defineProperty(obj,'a',{
 value:1,
 enumerable:true,
})
Object.defineProperty(obj,'b',{
 value:2,
})
Object.defineProperty(obj,'c',{
 value:3,
})
Object.defineProperty(obj,'d',{
 value:4,
 enumerable:true,
})
for(let key in obj){
 console.log(key)
}
console.log(Object.keys(obj))
// 
"a"
"d"
["a", "d"]

データ記述子を見てください。 バインドイベントでは、@click和@click.native有什么区别

@click

はイベントをhtml要素にバインドするためのものです。

@click.native

は、ネイティブ・イベントをコンポーネントにバインドします。click.nativeは、コンポーネントのルート要素のネイティブイベントをリスンします。

例:親コンポーネントA、子コンポーネントB

// 親コンポーネント
<template>
 <B @click="c"/>
</template>
methods:{
 c(){}
}

子コンポーネントをリッスンする場合、@clickとだけ書くと、Bをクリックしてもイベントcはトリガーされず、リッスンできません。

一つの解決策は、子コンポーネントの要素で@clickイベントをリッスンし、クリックされたらa関数をトリガーし、aで$emitを使って手動でクリック関数をトリガーし、@clickを使って親コンポーネントをリッスンし、次に子コンポーネントのボディをリッスンすることです。

.native修飾子を使うことで、コードがすっきりします。子コンポーネントの内部では、もはやリッスンやトリガを行う必要はありません。親コンポーネント用@click.native、Bをクリックするとイベントハンドラ関数cがトリガされるようにするだけです。

<template>
 <B @click.native="c"/>
</template>

click.self

<div @click.self="c">
 aaa
</div>

この関数は、e.targetが現在の要素である場合にのみトリガーされます。e.targetが現在の要素である場合のみ、この関数はトリガーされます。

. CSS様々な形状の実装

半円

.semi{
 margin:100px;
 width:100px;
 height:100px;
 background:black;
 border-radius:100px 100px 0 0;
 height:50px;
}

まず幅と高さが等しい正方形を描き、角に丸みを付けます。左上と右上は幅と高さの値に等しい丸みを付け、左下と右下は角に丸みを付けません。半円:次に高さを半分にします。

ファン

正方形 = フィレットを追加します。

.shan1{
 margin:50px;
 width:50px;
 height:50px;
 background:black;
 border-radius:50px 0 0 0;
}

角丸の値は幅と高さの値に等しくなります。四分の一セクター。

セクターを実現するために三角形に角丸を追加します。

.shan{
 width:0;
 height:0;
 border-top:50px solid red;
 border-left:50px solid transparent;
 border-right:50px solid transparent;
 border-top-left-radius:50%;
 border-top-right-radius:50%;
}

幅と高さが0の場合、ボーダーで三角形を作ります。そして、三角形に角丸をつけます。

三角形

widthとheightが0なので、borderを追加します。

.shan{
 width:0;
 height:0;
 border-top:50px solid red;
 border-left:50px solid transparent;
 border-right:50px solid transparent;
}
鋭角または鈍角の二等辺三角形は?

鋭角: 上の境界線 > 左右の境界線border-top:100px solid red;

<左右边界>border-top:20px solid red;鈍角:上辺

clip-pathでエッジを描きます。

.shan{
 background:black;
 width:100px;
 height:100px;
 clip-path:polygon(0px 0px,100px 0px,50px 100px);
}

Arc

.semi{
 margin:100px;
 width:100px;
 height:100px;
 background:black;
 border-radius:100px 0 100px 0;
 transform:rotate(45deg);
}

まず正方形で、角は丸く、値は幅と高さです。例えば、左上隅と右下隅。

. 呼び出しの手書き実装,apply,bind

呼び出しの実装

let obj={
 name:' ',
 say(){
 console.log(` ${this.name}`)
 return this.name
 }
}
let obj2={name:' '}
let result=obj.say.call(obj2)

まず、オブジェクト関数であれ普通の関数であれ、呼び出しが関数でなければならないことは明らかです。

call()関数はどのような引数を取るのでしょうか?ケース1:おそらくパラメータを渡さずに呼び出される f() === f.call() ケース2:新しいthisを渡される obj.say.call(obj2) ケース3:thisに加えて、this.thisだけでなく、他の引数のリストも渡されます。obj.say.call(obj2,1,2,3)

要約すると、独自の myCall 関数を定義します。Function.prototype.myCall=function(context){} この関数は、プロトタイプの関数インスタンス: で定義され、最初のパラメータとしてコンテキストを受け取ります。例えば、obj2

最初の判定で、コンテキストが渡されなかったり、未定義またはnullが渡された場合は、windowに変更する必要があります。

どのようにthis関数をobj2に変更するには? obj2に、つまり、contextがプロパティsayを拡張し、contextもメソッドsayを持っているように、そして、context.sayを呼び出すように、say関数のthisは当然コンテキストになります。具体的には、新しい属性のコンテキストが関数sayを指すようにします。thisのmyCall関数は、そのsay関数の呼び出しの外側です。say.myCall() === say.myCall.call(say) sayは関数であり、関数はオブジェクトであり、オブジェクトです。関数呼び出しはthisの暗黙のパスであり、thisはそれに先行するオブジェクトです。というのは

Function.prototype.myCall=function(context){
 console.log(context)
 if(context===undefined || context===null){context=window}
 let key=Symbol()
 console.log(this)
 context[key]=this
 let args=[...arguments].slice(1)
 let result=context[key](...args)
 delete context[key]
 return result
}

Symbol()は、他のプロパティとの衝突を避けるために、コンテキストのプロパティとしてこのキー変数を使用して、一意のシンボル値を生成します。

引数は擬似配列で、myCallの呼び出しに含まれるcontextのすべての引数です。そのため、contextを除外して残りの引数を取得します。そして、contextを継承したこのメソッドを呼び出します。say関数に戻り値がある場合は、戻り値を取得してそれを返し、拡張プロパティを削除することを忘れないでください。

キー:context[key]=this はmyCall関数を指す新しい属性でcontextをextendsします。関数です。その関数は、myCallのそのthisです。"""

applyの実装

fn.apply(obj2,[1,2,3])がapplyを呼び出す場合、最初の引数は新しいthisで、2番目の引数は項目の配列でなければなりません。配列の各項目はfnの引数です。

つまり、applyの実装は引数の扱い方だけが異なります。

Function.prototype.myApply=function(context){
 if(context===undefined || context===null){context=window}
 let key=Symbol()
 let result
 context[key]=this
 let args=arguments[1] // 
 if(args){
 result=context[key](...args)
 }else{
 result=context[key]()
 }
 delete context[key]
 return result
}

arguments[1]を介して配列の引数を取得し、それがあるかどうかを判断する必要があります。fn.myApply()に引数リストの配列が渡されなければ、argsは未定義です。

bindの実装

bindの基本的な使い方です:

var name=' '
let obj={
 name:' ',
 say(x,y){
 console.log(` ${this.name}, ${x+y}`)
 return this.name
 }
}
let obj2={name:' '}
let newsay=obj.say.bind(obj2,3,4)(1,2) //"私の名前はあああああああああああああああああああああああああああああああああああああ、7"
let newsay=obj.say.bind(obj2,3)(2,1) //"私の名前はああああああ、和は5だ"

関数は bind を呼び出し、新しい関数を返します。bindの呼び出しには引数を渡すことができ、その最初の引数は返される新しい関数にバインドされるthisコンテキストです。つまり、新しい関数が呼ばれた場合、新しい関数のthisがbindの最初の引数となります。this はバインドの最初のパラメータとなります。定義済みのパラメータを後で渡すこともできます。

そうすると、新しい関数はsay関数と同じ機能を持つことになります。新しい関数を呼び出す際にパラメータを渡すこともできます。しかし、もしsayが2つのパラメータしか必要としないのに bindが2つのパラメータを渡し、新しい関数が2つのパラメータで呼び出された場合、 実際に動作するのは最初の2つのパラメータだけです。もし bind が1つだけ渡し、新しい関数が2つ渡すのであれば、実際に動くのは最初の2つだけです。

ですから、両方の引数を取り出す必要があります。

Function.prototype.myBind=function(context){
 if(typeof this !=='function'){return}
 let args=[...arguments].slice(1) // []  [x,x,x]
 let self=this
 return function(){
 let innerArgs=[...arguments]
 return self.apply(context,args.concat(innerArgs))
 }
}

返す新しい関数は、this が指定されたコンテキストであることを除けば bind の前のものです。その他の引数は bind と new 関数の引数のスプライスです。

bindが返すnew関数は、通常の呼び出しに加えてコンストラクタとして呼び出すこともできますが、newを前につけてコンストラクタとして呼び出すこともできます。newで呼び出された場合、self.applyは古い関数を呼び出します。その後に続く最初の引数のコンテキストはbindがバインドするコンテキストではなく、新しい関数を呼び出して得られるインスタンス、let a=new say1()、つまり匿名関数のthis."".そこで、返された new 関数が new

Read next

SwiftyJSONを使ったHandyJSON

クラス HandyJSON,Codable {\n 必須 init { //カスタム

May 6, 2020 · 2 min read