1)、专门定义一个数组,保存原函数的参数
2)、当原函数的参数(数量)不够时,返回一个函数(收集原函数参数的)
3)、当原函数的参数(数量)够了,那么,调用原原函数的调用。
// 1、原函数:
function sum(a, b, c, d) {
return a + b + c + d;
}
// 2、柯里化工具函数
function curry(cb) {
let arr = [];
function fn(...args) {
arr = [...arr, ...args];//收集参数
if (arr.length < cb.length) {// 函数.length 表示的是函数形参的个数
return fn;
} else {
return cb(...arr);
}
}
return fn;
}
// 3、(调用柯里化工具函数)把原函数柯里化
let cSum = curry(sum);
// 4、调用柯里化后的函数。
console.log(cSum(2, 3)(5)(6))
// console.log(cSum(2)(4)(5)(6))
// console.log(cSum(2, 4, 5)(6))
let f01 = cSum(2, 3)(5);// f01是持有 2,3,5的函数
f01(6);//求 2+3+5 + 6
f01(7);//求 2+3+5 +7
// 1)、用构造函数:这种写法,会导致内存中定义了多个相同的函数。浪费了内存
function Doctor(name,dept){
this.name = name;
this.dept = dept;
// 这种写法,会导致内存中定义了多个相同的函数。浪费了内存。
this.seatZhen = function(){
console.log(this.name+"在坐诊………………");
}
}
let d1= new Doctor("宋和叶","神经科");
let d2 = new Doctor("纪朝锋","精神科");
// 2)、用构造函数结合原型(prototype)定义类
function Doctor(name,dept){
this.name = name;
this.dept = dept;
}
// 一个构造函数的原型属性上的属性和方法,可以被它的实例共享
Doctor.prototype.seatZhen = function(){
console.log(this.name+"在坐诊………………");
}
let d1= new Doctor("宋和叶","神经科");
let d2 = new Doctor("纪朝锋","精神科");
d1.seatZhen();
d2.seatZhen();
//ES6中用class:class定义类,是个语法糖。
class Doctor{
constructor(name,dept){
this.name = name;
this.dept = dept;
}
seatZhen(){
console.log(this.name+"在坐诊………………");
}
}
let d1= new Doctor("宋和叶","神经科");
let d2 = new Doctor("纪朝锋","精神科");
d1.seatZhen();
d2.seatZhen();
// 原型(链)继承,必须用ES5的写法。
// 1、父类
function Person(name, sex) {
this.name = name;
this.sex = sex;
}
Person.prototype.eat = function () {
}
// 2、子类1
function Doctor(dept) {
this.dept = dept;
}
// 建立继承关系(原型的方式):子类(构造函数)的原型属性 指向 父类的对象(实例)
Doctor.prototype = new Person("宋和叶", "女");
let d1 = new Doctor("神经科");
console.log(d1.name);
console.log(d1.eat);
let d1 = new Doctor("神经科");
// 3、子类2
function Programmer(lanuage){
this.lanuage = lanuage;
}
Programmer.prototype = new Person("纪朝锋","男");
let p1 = new Programmer("javascript");
p1.name;
p1.eat();
// 1、父类
function Person(name,sex,books){
this.name = name;
this.sex = sex;
this.books = books;
}
Person.prototype.eat = function(str){
console.log(this.name+"在吃"+str+",天在看…………");
}
// 2、子类1
function Doctor(dept){
this.dept = dept;
}
// 建立继承关系(原型的方式):子类(构造函数)的原型属性 指向 父类的对象(实例)
Doctor.prototype = new Person("宋和叶","女",[]);
Doctor.prototype.seatZhen = function(){
console.log(this.name+"在坐诊……");
}
// 不能重新prototype属性
// Doctor.prototype = {
// seatZhen:function(){
// console.log(this.name+"在坐诊……");
// }
// }
let d1 = new Doctor("神经科");
d1.name = "纪朝锋";
let d2 = new Doctor("神经科");
d2.name="党艺华";
d1.eat("油条");
d1.seatZhen();
d2.eat("包子");
1、call和apply都是函数的一个方法(函数)
2、call和apply都是在调用原函数。
3、call和apply是可以改变原函数里的this指向的
4、call和apply的第一个参数就是原函数的this指向
5、call可以把函数和对象解耦(耦合度:依赖程度/关联程度。高内聚,低耦合)
6、call和apply的区别(仅仅只是格式上的区别):
1)、call函数从第二个参数朝后的参数是原函数的参数
2)、apply函数只有两个参数,第二个参数是个数组,数组里是原函数的参数。这样的话, apply第二个参数就可以使用arguments
let person = {
name: "张三疯",
eat: function () {
console.log(this.name + "在吃");
}
}
person.eat();
let dog = {
name: "小黑"
}
person.eat.call(dog);
function eat(str) {
console.log(this.name + "在吃" + str);
}
eat("食物");
let dog = {
name: "小黑"
}
eat.call(dog, "油泼面");//等价于:dog.eat("油泼面");
let doctor = {
name: "张三疯"
}
eat.call(doctor, "方便面");//等价于:doctor.eat("方便面");
eat.apply(doctor, ["油条"])
3、call和apply的区别
eat.call(doctor, "方便面");//等价于:doctor.eat("方便面");
eat.apply(doctor, ["油条"])//等价于:doctor.eat("油条");
function eat(str, song) {
console.log(this.name + "吃着" + str + ",唱着" + song);
}
let dog = {
name: "小黑"
}
function fn01() {
console.log("arguments", arguments);
eat.apply(dog, arguments);
// arguments也是函数的内置对象,该对象是个伪数组(不是数组,
// 但是可以使用数组的length,下标),里面存储着函数的实参
}
fn01("火锅", "最炫民族风");
相同点: bind,call,apply都可以改变this的指向。
不同点:1、bind不会调用原函数,而会产生一个新的函数(bind的返回值是新函数),新函数里的 this是bind时的对象。bind有强烈绑定的意思。只要调用bind,那么对象和函数就永远 绑定起来了。 2、call和apply会调用原函数。
function eat(str){
console.log(this.name+"在吃"+str);
}
let dog = {
name:"小黑"
}
let pig = {
name:"小白"
}
// 1)、bind
let fn01 = eat.bind(dog);//fn01 这个函数,就是dog和eat绑定在一起的函数。只要调用fn01,this必
然是dog
fn01("油泼面");
fn01("狗粮");
let fn02 = eat.bind(pig);//fn02 这个函数,就是pig和eat绑定在一起的函数。只要调用fn02,this必
然是pig
fn02("玉米");
fn02("米饭");
// 2)、call
eat.call(dog,"油泼面");// 如果希望this是dog,那就call dog
eat.call(dog,"狗粮");
eat.call(pig,"玉米");// 如果希望this是pig,那就call pig
eat.call(pig,"米饭");
function Person(name,sex){
this.name = name;
this.sex = sex;
}
// Person.prototype.eat = function(str){
// console.log(this.name+"在吃"+str);
// }
function Doctor(name,sex,dept){
// apply的继承。
let obj = this;
Person.apply(obj,arguments);//没有把所谓的构造函数(Person)当构造函数使用(就当一个普通函数);等价于: this.Person(arguments);
this.dept = dept;
}
let d1 =new Doctor("宋和叶","女","儿科");
let d2 = new Doctor("纪朝锋","男","骨科");
console.log(d1.name);
console.log(d2.name);
d1.eat("油泼面");
把原型(链)继承和call,apply继承结合起来。各自发挥自己的优势。
①原型继承:把父类原型属性上内容(属性和方法)继承下来。
②call和apply继承:把父类构造函数里的属性和方法继承下来。
function Person(name,sex){
if(arguments.length>0){
this.name = name;
this.sex = sex;
}
}
Person.prototype.eat = function(str){
console.log(this.name+"在吃"+str);
}
function Doctor(name,sex,dept){
// call和apply继承:把父类构造函数里的属性和方法继承下来。
Person.apply(this,arguments);
this.dept = dept;
}
// 原型继承:把父类原型属性上内容(属性和方法)继承下来。
Doctor.prototype = new Person();
let d1 =new Doctor("宋和叶","女","儿科");
let d2 = new Doctor("纪朝锋","男","骨科");
console.log(d1.name);
console.log(d2.name);
d1.eat("油泼面");
①继承关系的关键字:extends;
②子类构造函数里必须调用super(),而且必须写在子类构造函数的第一句话
③ES6的这种写法就是个语法糖(换了写法,本质一样)
class Person{
constructor(name,sex){
this.name = name;
this.sex = sex;
}
eat(str){
console.log(this.name+"在吃"+str);
}
}
// extends关键字完成继承关系
class Doctor extends Person{
constructor(name,sex,dept){
// super就是父类
super(name,sex);//这就相当于调用了父类的构造函数。这句话必须放在子类构造函数里的第一句话
this.dept = dept;
}
}
let d1 =new Doctor("宋和叶","女","儿科");
let d2 = new Doctor("纪朝锋","男","骨科");
console.log(d1.name);
console.log(d2.name);
d1.eat("油泼面");
function Person(name, sex) {
if (arguments.length > 0) {
this.name = name;
this.sex = sex;
// this.eat = function(str){
// console.log(this.name+"在吃"+str);
// }
}
}
Person.prototype.eat = function (str) {
console.log(this.name + "在吃" + str);
}
function Doctor(name, sex, dept) {
Person.apply(this, arguments);
this.dept = dept;
}
// Doctor.prototype = new Person();
let d1 = new Doctor("宋和叶", "女", "儿科");
let d2 = new Doctor("纪朝锋", "男", "骨科");
console.log(d1.eat === d2.eat);//如果把eat方法写在构造函数里,那么是false(因为,每次调用构造函数,都会重新定义函数) )
console.log(d1.eat === d2.eat);//如果把eat方法写在原型属性上,那么是true
console.dir(Array);
//继承关系: Array ---> Function --> Object
let arr = new Array(10);
console.dir(arr);
console.log(arr.__proto__ == Array.prototype);
let box = document.getElementById("box"); //box对象是 类 HTMLDivElement 的实例
console.dir(box);
div是 HTMLDivElement的对象,即就是: div属于 HTMLDivElement 类型。
继承关系: HTMLDivElement--> HTMLElement-->Element-->Node-->EventTarget-->Object
console.log(box.constructor===HTMLDivElement);
let t = document.createElement("div");
let t2 = new HTMLDivElement();//不行, 因为 HTMLDivElement,不是真正的构造函数,实际是个接口
01.原型继承的示意图
02.call和apply继承的示意图