蓝本和蓝本链实例
缺省的蓝本
function Person(name, age) { this.name = name; this.age = age; } Person.prototype.greet =function() { console.log(`Hello, my name is ${this.name}.`); }; const john = new Person(John, 30); john.greet(); // Hello, my name is John.在那个实例中,他们透过缺省 Person() 建立了两个第一类 john,并透过 Person.prototype 特性为它加进了两个方式 greet()。当他们初始化 john.greet() 时,事实上是先在 john 第一类这类搜寻 greet() 方式,假如找不出则会沿著蓝本链向下搜寻,最后找出了 Person.prototype 中的 greet() 方式并继续执行它。
蓝本
// 缺省 function Person(name, age) { this.name = name; this.age = age; }// 在 Person 的蓝本上加进两个 sayHello() 方式 Person.prototype.sayHello = function() { console.log(`Hello, my name is${this.name}, and I am ${this.age} years old.`); }; // 建立两个 Person 的实例 const person1 = newPerson(Tom, 20); // 初始化 person1 的 sayHello() 方式 person1.sayHello(); // Hello, my name is Tom, and I am 20 years old.在上面的实例标识符中,他们使用缺省 Person 建立了两个 Person 第一类,然后透过在 Person.prototype 上加进 sayHello() 方式,将 sayHello() 方式加进到 Person 的蓝本上,使得 Person 的每个实例都可以访问到那个方式。
蓝本链
// 缺省 function Animal(name) { this.name = name; }// 在 Animal 的蓝本上加进两个 eat() 方式 Animal.prototype.eat = function() { console.log(`${this.name}is eating.`); }; // 缺省 function Dog(name) { this.name = name; } // 将 Dog 的蓝本指向 Animal 的实例 Dog.prototype = new Animal(); // 在 Dog 的蓝本上加进两个 bark() 方式 Dog.prototype.bark = function() { console.log(`${this.name}is barking.`); }; // 建立两个 Dog 的实例 const dog1 = new Dog(Buddy); // 初始化 dog1 的 bark() 方式和 eat() 方式 dog1.bark(); // Buddy is barking. dog1.eat(); // Buddy is eating.在上面的实例标识符中,他们建立了两个缺省 Animal 和 Dog,透过将 Dog 的蓝本指向 Animal 的实例,形成了两个蓝本链。当他们初始化 dog1 的 bark() 方式时,会在 Dog 的蓝本上找出该方式;当他们初始化 dog1 的 eat() 方式时,会在 Animal 的蓝本上找出该方式,这就是蓝本链的实现原理。
蓝本和蓝本链实例
// 缺省 Person function Person(name, age) { this.name = name; this.age = age; } // 为 Person 的蓝本加进两个 sayHello() 方式 Person.prototype.sayHello = function() { console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`); }; // 建立两个 Person 实例 const person1 = new Person(Alice, 25);// 初始化 person1 的 sayHello() 方式 person1.sayHello(); // Hello, my name is Alice and I am 25 years old. // 查看 person1 的蓝本和蓝本链 console.log(person1.__proto__ === Person.prototype); // true console.log(Person.prototype.__proto__ ===Object.prototype); // true console.log(Object.prototype.__proto__); // null在上面的实例中,他们定义了两个缺省 Person,并为 Person 的蓝本加进了两个 sayHello() 方式。然后,他们建立了两个 Person 实例 person1,初始化了它的 sayHello() 方式,并查看了它的蓝本和蓝本链。可以看到,person1 的蓝本是 Person.prototype,Person.prototype 的蓝本是 Object.prototype,而 Object.prototype 的蓝本为 null。
蓝本和蓝本链
建立第一类和蓝本实例
// 使用第一类字面量建立第一类 const obj = { a: 1, b: 2 }; // 使用缺省建立第一类 function Person(name, age) { this.name = name; this.age = age; } const person = new Person(Tom, 18); // 给第一类加进特性 obj.c = 3; Person.prototype.sayHello =function() { console.log(`Hello, my name is ${this.name} and Im ${this.age}years old.`); }; console.log(obj); // { a: 1, b: 2, c: 3 } person.sayHello(); // Hello, my name is Tom and Im 18 years old.蓝本链
实例一: function Animal(name) { this.name = name; } Animal.prototype.eat = function() { console.log(`${this.name} is eating.`); }; function Cat(name) { Animal.call(this, name); } Cat.prototype =Object.create(Animal.prototype); Cat.prototype.constructor = Cat; Cat.prototype.meow =function() { console.log(`${this.name} is meowing.`); }; const kitty = new Cat(Kitty); kitty.eat(); // Kitty is eating. kitty.meow(); // Kitty is meowing.在那个实例中,他们定义了两个缺省 Animal() 和 Cat(),并透过 Cat.prototype =Object.create(Animal.prototype) 将 Cat 的蓝本设置为 Animal 的实例,这样就建立了蓝本链。在那个蓝本链中,kitty 第一类继承了 Animal.prototype 中的 eat() 方式和 Cat.prototype 中的 meow() 方式 实例二// 定义两个动物构造函数 function Animal(name) { this.name = name; } // 给 Animal 的蓝本加进方式 Animal.prototype.sayName = function(){ console.log(`My name is ${this.name}.`); }; // 定义两个狗的缺省 function Dog(name) { Animal.call(this, name); // 初始化 Animal 缺省 } // 继承 Animal 的蓝本 Dog.prototype = Object.create(Animal.prototype); Dog.prototype.constructor = Dog;// 给 Dog 的蓝本加进方式 Dog.prototype.bark = function() { console.log(Woof!); }; const dog = new Dog(Rover); dog.sayName(); // My name is Rover. dog.bark(); // Woof!在上面的实例中,他们透过初始化 Animal 的缺省,实现了对 Dog 的继承,并使用Object.create() 方式来继承 Animal 的蓝本call 和 apply 实例
function greet(greeting) { console.log(`${greeting}, ${this.name}.`); } const john = { name: John }; const jane = { name: Jane}; greet.call(john,Hello); // Hello, John. greet.apply(jane, [Hi]); // Hi, Jane.在那个实例中,他们定义了两个函数 greet(),并分别使用 call() 和 apply() 方式来初始化它。在初始化时,他们将 john 和 jane 第一类作为第两个参数传递给了 call() 和 apply(),这样函数内部的 this 就指向了 john 和 jane 第一类。同时,他们也传递了 greeting 参数作为函数的第二个参数,apply() 方式需要将参数打包成数组传递。
call 实例
function greeting() { console.log(`Hello, my name is ${this.name} and Im ${this.age} years old.`); } const person = { name: Tom, age: 18}; greeting.call(person);// Hello, my name is Tom and Im 18 years old.apply 实例
function add(a, b) { return a + b; } const numbers = [1, 2]; console.log(add.apply(null, numbers)); // 3在上面的实例中,他们透过 call 和 apply 方式来改变函数中的 this 指向,并在 apply 实例中使用了数组作为参数传递给函数。
call 和 apply 实例
// 缺省 Person function Person(name, age) { this.name = name; this.age = age; } // 为 Person 的蓝本加进两个 sayHello() 方式Person.prototype.sayHello =function() { console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`); }; // 构造函数 Student function Student(name, age, major) { Person.call(this, name, age); this.major = major; }// 使用 apply() 方式将 Student 的蓝本设置为 Person 的蓝本 Student.prototype = Object.create(Person.prototype); Student.prototype.constructor = Student;// 建立两个 Student 实例 const student1 = new Student(Bob, 20, Computer Science); // 初始化 student1 的 sayHello() 方式 student1.sayHello(); // Hello, my name is Bob and I am 20 years old. // 查看 student1 的蓝本和蓝本链 console.log(student1.__proto__ === Student.prototype); // true console.log(Student.prototype.__proto__ === Person.prototype);// true console.log(Person.prototype.__proto__ ===Object.prototype); // true console.log(Object.prototype.__proto__); // null在上面的实例中,他们定义了两个缺省 Person,并为 Person 的蓝本加进了两个 sayHello() 方式。然后,他们定义了两个缺省 Student,透过初始化 Person.call() 方式将 Person 的特性继承到 Student 中,并使用 Object.create() 方式将 Student 的蓝本设置为 Person 的蓝本,并将 Student 的 constructor 设置为 Student。最后,他们建立了两个 Student 实例 student1,初始化了它的 sayHello() 方式,并查看了它的蓝本和蓝本链。可以看到,student1 的蓝本是 Student.prototype,Student.prototype 的蓝本是 Person.prototype,Person.prototype 的蓝本是 Object.prototype,而 Object.prototype 的蓝本为 null。
call 和 apply
// 缺省 function Person(name, age) { this.name = name; this.age = age; } // 定义两个 sayHello() 方式 function sayHello() { console.log(`Hello, my name is ${this.name}, and I am ${this.age} years old.`); }// 建立两个 Person 的实例 const person1 = new Person(Tom, 20); // 使用 call() 方式初始化 sayHello() 方式sayHello.call(person1);// Hello, my name is Tom, and I am 20 years old. // 使用 apply() 方式初始化 sayHello() 方式sayHello.apply(person1);// Hello, my name is Tom, and I am 20 years old.在上面的实例标识符中,他们定义了两个 sayHello() 方式,然后使用 call() 和 apply() 方式来初始化该方式,并将 person1 第一类作为参数传入,这样在 sayHello() 方式内部就可以透过 this 访问到 person1 的特性了。需要注意的是,call() 和 apply() 方式的区别在于传入参数的方式不同