Skip to content

Commit a28bdf0

Browse files
committed
圣杯继承
1 parent 1bcd197 commit a28bdf0

File tree

3 files changed

+200
-31
lines changed

3 files changed

+200
-31
lines changed

docs/blog/js.md

Lines changed: 103 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -515,61 +515,96 @@ zhangsan.testStuFunc(); // this is a testStuFunc
515515

516516
> 参考答案:
517517
>
518-
> 柯里化(*currying*)又称部分求值。一个柯里化的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。
518+
> 柯里化(currying)又称部分求值。一个柯里化的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。
519519
>
520520
> 举个例子,就是把原本:
521521
>
522-
> *function(arg1,arg2)* 变成 *function(arg1)(arg2)*
523-
> *function(arg1,arg2,arg3)* 变成 *function(arg1)(arg2)(arg3)*
524-
> *function(arg1,arg2,arg3,arg4)* 变成 *function(arg1)(arg2)(arg3)(arg4)*
522+
> function(arg1,arg2) 变成 function(arg1)(arg2)
523+
> function(arg1,arg2,arg3) 变成 function(arg1)(arg2)(arg3)
524+
> function(arg1,arg2,arg3,arg4) 变成 function(arg1)(arg2)(arg3)(arg4)
525525
>
526526
> 总而言之,就是将:
527527
>
528-
> *function(arg1,arg2,…,argn)* 变成 *function(arg1)(arg2)…(argn)*
528+
> function(arg1,arg2,…,argn) 变成 function(arg1)(arg2)…(argn)*
529+
530+
:::tip 柯里化
531+
```js
532+
/*
533+
在案例中,curry函数接受一个函数fn作为参数,返回一个新的函数curried。
534+
curried函数在调用时会检查传入的参数数量是否大于或等于原始函数fn的参数数量(arity),
535+
如果是,则直接调用原始函数;否则,返回一个新的函数,该函数接受剩余的参数(rest),
536+
并将之前传入的参数(args)与剩余参数合并后调用curried函数。通过这种方式,实现函数柯里化。
537+
*/
538+
539+
const curry = (fn) => {
540+
const arity = fn.length;
541+
return function curried(...args) {
542+
if (args.length >= arity) {
543+
return fn.apply(this, args);
544+
} else {
545+
return function (...rest) {
546+
return curried.apply(this, args.concat(rest));
547+
};
548+
}
549+
};
550+
}
551+
const getURL = (protocol, domain, path) => {
552+
return protocol + "://" + domain + "/" + path;
553+
}
554+
const myurl = getURL('http', 'mysite', 'home.html');
555+
const myurl2 = getURL('http', 'mysite', 'about.html');
556+
console.log('myurl', myurl);
557+
console.log('myurl2', myurl2);
529558

559+
// 减少重复传递不变的部分参数
560+
const superGetURL = curry(getURL)('https', 'mysite');
561+
const myurl3 = superGetURL('detail.html')
530562

563+
console.log('myurl3', myurl3);
564+
```
565+
:::
531566

532-
### 15. *promise.all* 方法的使用场景?数组中必须每一项都是 *promise* 对象吗?不是 *promise* 对象会如何处理 ?
567+
### 15. promise.all 方法的使用场景?数组中必须每一项都是 promise 对象吗?不是 promise 对象会如何处理 ?
533568

534569
> 参考答案:
535570
>
536-
> ***promise.all(promiseArray)*** 方法是 *promise* 对象上的静态方法,该方法的作用是将多个 *promise* 对象实例包装,生成并返回一个新的 *promise* 实例。
571+
> promise.all(promiseArray) 方法是 promise 对象上的静态方法,该方法的作用是将多个 promise 对象实例包装,生成并返回一个新的 promise 实例。
537572
>
538-
> 此方法在集合多个 *promise* 的返回结果时很有用。
573+
> 此方法在集合多个 promise 的返回结果时很有用。
539574
>
540-
> 返回值将会按照参数内的 *promise* 顺序排列,而不是由调用 *promise* 的完成顺序决定。
575+
> 返回值将会按照参数内的 promise 顺序排列,而不是由调用 promise 的完成顺序决定。
541576
>
542-
> ***promise.all* 的特点**
577+
> promise.all 的特点
543578
>
544-
> 接收一个*Promise*实例的数组或具有*Iterator*接口的对象
579+
> 接收一个Promise实例的数组或具有Iterator接口的对象
545580
>
546-
> 如果元素不是*Promise*对象,则使用*Promise.resolve*转成*Promise*对象
581+
> 如果元素不是Promise对象,则使用Promise.resolve转成Promise对象
547582
>
548-
> 如果全部成功,状态变为*resolved*,返回值将组成一个数组传给回调
583+
> 如果全部成功,状态变为resolved,返回值将组成一个数组传给回调
549584
>
550-
> 只有有一个失败,状态就变为 *rejected*,返回值将直接传递给回调 *all( )*的返回值,也是新的 *promise* 对象
585+
> 只有有一个失败,状态就变为 rejected,返回值将直接传递给回调 all( )的返回值,也是新的 promise 对象
551586
552587

553588

554-
### 16. *this* 的指向哪几种 ?
589+
### 16. this 的指向哪几种 ?
555590

556591
> 参考答案:
557592
>
558-
> 总结起来,*this* 的指向规律有如下几条:
593+
> 总结起来,this 的指向规律有如下几条:
559594
>
560-
> - 在函数体中,非显式或隐式地简单调用函数时,在严格模式下,函数内的 *this* 会被绑定到 *undefined* 上,在非严格模式下则会被绑定到全局对象 *window/global* 上。
561-
> - 一般使用 *new* 方法调用构造函数时,构造函数内的 *this* 会被绑定到新创建的对象上。
562-
> - 一般通过 *call/apply/bind* 方法显式调用函数时,函数体内的 *this* 会被绑定到指定参数的对象上。
563-
> - 一般通过上下文对象调用函数时,函数体内的 *this* 会被绑定到该对象上。
564-
> - 在箭头函数中,*this* 的指向是由外层(函数或全局)作用域来决定的。
595+
> - 在函数体中,非显式或隐式地简单调用函数时,在严格模式下,函数内的 this 会被绑定到 undefined 上,在非严格模式下则会被绑定到全局对象 window/global 上。
596+
> - 一般使用 new 方法调用构造函数时,构造函数内的 this 会被绑定到新创建的对象上。
597+
> - 一般通过 call/apply/bind 方法显式调用函数时,函数体内的 this 会被绑定到指定参数的对象上。
598+
> - 一般通过上下文对象调用函数时,函数体内的 this 会被绑定到该对象上。
599+
> - 在箭头函数中,this 的指向是由外层(函数或全局)作用域来决定的。
565600
566601

567602

568-
### 17. *JS* 中继承实现的几种方式
603+
### 17. JS 中继承实现的几种方式
569604

570605
> 参考答案:
571606
>
572-
> *JS* 的继承随着语言的发展,从最早的对象冒充到现在的圣杯模式,涌现出了很多不同的继承方式。每一种新的继承方式都是对前一种继承方式不足的一种补充。
607+
> JS 的继承随着语言的发展,从最早的对象冒充到现在的圣杯模式,涌现出了很多不同的继承方式。每一种新的继承方式都是对前一种继承方式不足的一种补充。
573608
>
574609
> 1. 原型链继承
575610
>
@@ -582,7 +617,7 @@ zhangsan.testStuFunc(); // this is a testStuFunc
582617
>
583618
> 2. 借用构造函数继承
584619
>
585-
> - 重点:用 *call( )**apply( )* 将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
620+
> - 重点:用 call( ) 和 apply( ) 将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
586621
> - 特点:
587622
>    - 1、只继承了父类构造函数的属性,没有继承父类原型的属性。
588623
> - 2、解决了原型链继承缺点1、2、3。
@@ -597,15 +632,53 @@ zhangsan.testStuFunc(); // this is a testStuFunc
597632
>
598633
> - 重点:结合了两种模式的优点,传参和复用
599634
> - 特点:
600-
>    - 1、可以继承父类原型上的属性,可以传参,可复用。
601-
>    - 2、每个新实例引入的构造函数属性是私有的。
635+
> - 1、可以继承父类原型上的属性,可以传参,可复用。
636+
> - 2、每个新实例引入的构造函数属性是私有的。
602637
> - 缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
603638
>
604639
> 4. 寄生组合式继承(圣杯模式)
605640
>
606641
> - 重点:修复了组合继承的问题
607642
643+
:::tip 寄生组合式继承
644+
```js
645+
var Person = function (name, age) {
646+
this.name = name;
647+
this.age = age;
648+
}
649+
Person.prototype.test = "this is a test";
650+
Person.prototype.testFunc = function () {
651+
console.log('this is a testFunc');
652+
}
608653

654+
// 子类
655+
var Student = function (name, age, gender, score) {
656+
Person.apply(this, [name, age]); // 盗用构造函数
657+
this.gender = gender;
658+
this.score = score;
659+
}
660+
// 1. 组合继承
661+
// Student.prototype = new Person();
662+
// 2.圣杯模式
663+
Student.prototype = Object.create(Person.prototype);
664+
Student.prototype.constructor = Student;
665+
666+
Student.prototype.testStuFunc = function () {
667+
console.log('this is a testStuFunc');
668+
}
669+
670+
// 测试
671+
var zhangsan = new Student("张三", 18, "", 100);
672+
console.log(zhangsan.name); // 张三
673+
console.log(zhangsan.age); // 18
674+
console.log(zhangsan.gender); //
675+
console.log(zhangsan.score); // 100
676+
console.log(zhangsan.test); // this is a test
677+
zhangsan.testFunc(); // this is a testFunc
678+
zhangsan.testStuFunc(); // this is a testStuFunc
679+
console.log(Student.prototype)
680+
```
681+
:::
609682

610683
### 18. 什么是事件监听
611684

@@ -619,12 +692,12 @@ zhangsan.testStuFunc(); // this is a testStuFunc
619692
>
620693
> 当事件绑定好后,程序就会对事件进行监听,当用户触发事件时,就会执行对应的事件处理程序。
621694
>
622-
> 关于事件监听,*W3C* 规范中定义了 *3* 个事件阶段,依次是捕获阶段、目标阶段、冒泡阶段。
695+
> 关于事件监听,W3C 规范中定义了 3 个事件阶段,依次是捕获阶段、目标阶段、冒泡阶段。
623696
>
624-
> - **捕获**阶段:在事件对象到达事件目标之前,事件对象必须从 *window* 经过目标的祖先节点传播到事件目标。 这个阶段被我们称之为捕获阶段。在这个阶段注册的事件监听器在事件到达其目标前必须先处理事件。
697+
> - 捕获阶段:在事件对象到达事件目标之前,事件对象必须从 window 经过目标的祖先节点传播到事件目标。 这个阶段被我们称之为捕获阶段。在这个阶段注册的事件监听器在事件到达其目标前必须先处理事件。
625698
>
626-
> - **目标** 阶段:事件对象到达其事件目标。 这个阶段被我们称为目标阶段。一旦事件对象到达事件目标,该阶段的事件监听器就要对它进行处理。如果一个事件对象类型被标志为不能冒泡。那么对应的事件对象在到达此阶段时就会终止传播。
627-
> - **冒泡** 阶段:事件对象以一个与捕获阶段相反的方向从事件目标传播经过其祖先节点传播到 *window*。这个阶段被称之为冒泡阶段。在此阶段注册的事件监听器会对相应的冒泡事件进行处理。
699+
> - 目标 阶段:事件对象到达其事件目标。 这个阶段被我们称为目标阶段。一旦事件对象到达事件目标,该阶段的事件监听器就要对它进行处理。如果一个事件对象类型被标志为不能冒泡。那么对应的事件对象在到达此阶段时就会终止传播。
700+
> - 冒泡 阶段:事件对象以一个与捕获阶段相反的方向从事件目标传播经过其祖先节点传播到 window。这个阶段被称之为冒泡阶段。在此阶段注册的事件监听器会对相应的冒泡事件进行处理。
628701
629702

630703

docs/en/function.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,3 +487,62 @@ const sortArray = function (nums) {
487487
sortArray([1, 3, 9, 5, 2, 4, 6])
488488
```
489489
:::
490+
491+
### curry
492+
:::tip curry
493+
494+
```js
495+
/*
496+
In this case, the curry function accepts a function fn as a parameter and returns a new function curried.
497+
When the curried function is called, it checks whether the number of parameters passed in is greater than or equal to the number of parameters (arity) of the original function fn.
498+
If so, it calls the original function directly; otherwise, it returns a new function that accepts the remaining parameters (rest) and merges the previously passed parameters (args) with the remaining parameters before calling the curried function. In this way, function currying is achieved.
499+
*/
500+
501+
const curry = (fn) => {
502+
const arity = fn.length;
503+
return function curried(...args) {
504+
if (args.length >= arity) {
505+
return fn.apply(this, args);
506+
} else {
507+
return function (...rest) {
508+
return curried.apply(this, args.concat(rest));
509+
};
510+
}
511+
};
512+
}
513+
const getURL = (protocol, domain, path) => {
514+
return protocol + "://" + domain + "/" + path;
515+
}
516+
const myurl = getURL('http', 'mysite', 'home.html');
517+
const myurl2 = getURL('http', 'mysite', 'about.html');
518+
console.log('myurl', myurl);
519+
console.log('myurl2', myurl2);
520+
521+
const curry = (fn) => {
522+
const arity = fn.length;
523+
return function curried(...args) {
524+
if (args.length >= arity) {
525+
return fn.apply(this, args);
526+
} else {
527+
return function (...rest) {
528+
return curried.apply(this, args.concat(rest));
529+
};
530+
}
531+
};
532+
}
533+
const getURL = (protocol, domain, path) => {
534+
return protocol + "://" + domain + "/" + path;
535+
}
536+
const myurl = getURL('http', 'mysite', 'home.html');
537+
const myurl2 = getURL('http', 'mysite', 'about.html');
538+
console.log('myurl', myurl);
539+
console.log('myurl2', myurl2);
540+
541+
// Reduce repeated passing of unchanged parameters
542+
const superGetURL = curry(getURL)('https', 'mysite');
543+
const myurl3 = superGetURL('detail.html')
544+
545+
console.log('myurl3', myurl3);
546+
547+
```
548+
:::

docs/function.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,4 +488,41 @@ const sortArray = function (nums) {
488488
};
489489
sortArray([1, 3, 9, 5, 2, 4, 6])
490490
```
491-
:::
491+
:::
492+
493+
### 柯里化
494+
:::tip 柯里化
495+
```js
496+
/*
497+
在案例中,curry函数接受一个函数fn作为参数,返回一个新的函数curried。
498+
curried函数在调用时会检查传入的参数数量是否大于或等于原始函数fn的参数数量(arity),
499+
如果是,则直接调用原始函数;否则,返回一个新的函数,该函数接受剩余的参数(rest),
500+
并将之前传入的参数(args)与剩余参数合并后调用curried函数。通过这种方式,实现函数柯里化。
501+
*/
502+
503+
const curry = (fn) => {
504+
const arity = fn.length;
505+
return function curried(...args) {
506+
if (args.length >= arity) {
507+
return fn.apply(this, args);
508+
} else {
509+
return function (...rest) {
510+
return curried.apply(this, args.concat(rest));
511+
};
512+
}
513+
};
514+
}
515+
const getURL = (protocol, domain, path) => {
516+
return protocol + "://" + domain + "/" + path;
517+
}
518+
const myurl = getURL('http', 'mysite', 'home.html');
519+
const myurl2 = getURL('http', 'mysite', 'about.html');
520+
console.log('myurl', myurl);
521+
console.log('myurl2', myurl2);
522+
523+
// 减少重复传递不变的部分参数
524+
const superGetURL = curry(getURL)('https', 'mysite');
525+
const myurl3 = superGetURL('detail.html')
526+
527+
console.log('myurl3', myurl3);
528+
```

0 commit comments

Comments
 (0)