Git Product home page Git Product logo

interview's Introduction

  • 👋 Hi, I’m @dawson66
  • 👀 I’m interested in ...
  • 🌱 I’m currently learning ...
  • 💞️ I’m looking to collaborate on ...
  • 📫 How to reach me ...

interview's People

Contributors

dawson66 avatar

Watchers

 avatar

interview's Issues

JavaScript继承

原型链继承

function Person() {
  this.name = 'dawson'
}

Person.prototype.getName = function () {
  return this.name;
}

function Student() {}

// 原型链继承:子类构造函数指向父类实例
Student.prototype = new Person();

const student = new Student();

console.log(student.getName());  // dawson

// 引发的问题?

问题

  1. 子类指向的是一个固定的实例对象,即所有Student实例都共享这个Person实例,它们操作的是同一个引用对象。
function Person() {
  this.name = 'dawson';
  this.hobbies = ['backetball', 'football'];
}

Person.prototype.getName = function () {
  return this.name;
}

Person.prototype.addHobbies = function (...args){
  this.hobbies.push(...args);
}

function Student() {}

Student.prototype = new Person();

const student1 = new Student();
const student2 = new Student();
student1.addHobbies('music');
student2.addHobbies('dance');
console.log(student1.hobbies);  // ['backetball', 'football', 'music', 'dance']

  1. 子类创建时,不能向父类传参,因为子类实例化时,父类已经实例化好了。
细想一下,子类实例化时,通用性属性一般super调用父类的构造函数来为子类初始化,然而,子类构造函数原型指向一个固定的对象,怎么也做不到传值的操作!

构造函数继承

function Person(options) {
  this.age = options.age;
  this.name = 'dawson';
  this.hobbies = ['backetball', 'football'];
}

Person.prototype.getName = function () {
  return this.name;
}

Person.prototype.addHobbies = function (...args){
  this.hobbies.push(...args);
}

function Student(options) {
  // 所谓的构造函数继承就是在子类的构造函数中调用父类的构造函数并指定this
  Person.call(this, options)
}

const student1 = new Student({age: 20});
const student2 = new Student({age: 88});
console.log(student1.age);  // 20
console.log(student2.age);  // 88
student1.addHobbies('music');
student2.addHobbies('dance');
console.log(student1.hobbies); // Uncaught TypeError: student1.addHobbies is not a function

// 解决了什么问题?
// 1. 解决了原型链继承的传参问题

// 引发了什么问题?
// addHobbies报错说明原型上没有此方法,即子类未继承父类原型链上的属性和方法;那么你可能会说,可以将方法挂载到属性上而不是原型上,没错,这样是可以的
// 但是会引发一个问题,就是子类每次实例化时都会重复创建相同的方法,如addHobbies,这样就丧失了原型链或者面向对象的意义,因此引出下面思考

// 思考:未继承原型链上的属性,那么我们怎么才能继承父类原型链上的属性呢?

组合继承

function Person(options) {
  this.age = options?.age || 20;
  this.name = 'dawson';
  this.hobbies = ['backetball', 'football'];
}

Person.prototype.getName = function () {
  return this.name;
}

Person.prototype.addHobbies = function (...args){
  this.hobbies.push(...args);
}

function Student(options) {
  Person.call(this, options);
  this.gender = options.gender;
}

// 借用原型继承的优点,子类原型指向父类实例,虽不能传参,但是能够继承原型链上的属性
Student.prototype = new Person();
// 需要修复构造函数指向,Student实例constructor属性需要指向其构造函数
// student1.constructor == Student   Student.prototype.constructor == Student
Student.prototype.constructor = Student;

const student1 = new Student({age: 20, gender: 'male'});
const student2 = new Student({age: 88, gender: 'female'});
console.log(student1);
console.log(student1.age);  // 20
console.log(student2.age);  // 88
student1.addHobbies('music');
student2.addHobbies('dance');
console.log(student1.hobbies); // ['backetball', 'football', 'music']

组合继承已经能够实现对象的继承问题,算是一种解决方案了,但是还不够完美。如果你将student实例打印并查看的话,你会发现,属性不仅在实例中有,在原型对象上也有,因为我们的父类构造函数被调用了两次!那么如何减少一次构造函数的调用呢?


寄生式组合继承

// 寄生式组合继承作为ES6之前的 继承的 较好实现
function Person(options) {
  this.age = options?.age || 20;
  this.name = 'dawson';
  this.hobbies = ['backetball', 'football'];
}

Person.prototype.getName = function () {
  return this.name;
}

Person.prototype.addHobbies = function (...args){
  this.hobbies.push(...args);
}

function Student(options) {
  Person.call(this, options);
  this.gender = options.gender;
}

function F(){

}

// 中间加一层,子类原型指向F实例,F实例原型之乡Person的原型,实现原型链的访问
F.prototype = Person.prototype;
// 这里试想一下,Student.prototype = Person.prototype 行不行? 为何中间非要加一层?
Student.prototype = new F();
// 别忘了,constructor的正确指向
Student.prototype.constructor = Student;


const student1 = new Student({age: 850, gender: 'male'});
const student2 = new Student({age: 88, gender: 'female'});
console.log(student1);
console.log(student1.age);  // 20
console.log(student2.age);  // 88
student1.addHobbies('music');
student2.addHobbies('dance');
console.log(student1.hobbies); // ['backetball', 'football', 'music']

class继承

class Person {
  constructor(options){
    this.age = options?.age || 20;
    this.name = 'dawson';
    this.hobbies = ['backetball', 'football'];
  }

  getName() {
    return this.name;
  }

  addHobbies(...args){
    this.hobbies.push(...args);
  }
}

class Student extends Person {
  constructor(options){
    super(options)
    this.gender = options.gender
  }
}

const student3 = new Student({age: 890, gender: 'male'})
console.log(student3);

JavaScript函数方法bind,call和apply的实现

bind

先来看一个例子

// 例一
var name = 'global'

let obj = {
  name: 'dawson'
}

function getName() {
  return this.name;
}

const copyGetName = getName.bind(obj)
console.log(getName());      // global
console.log(copyGetName());  // dawson

// 例二
function add(a, b, c) {
  return a + b + c;
}
const copyAdd = add.bind(null, 1);
console.log(copyAdd(2, 3));   // 6

结论:

  • 返回一个函数
  • 绑定this
  • 柯里化特性(偏函数)
  • 构造函数特性
// 实现上述三点,第四点是最难的,也请思考!
Function.prototype._bind = function (context) {
  if (typeof this !== 'function') {
    throw new Error('bind只能被函数调用')
  }
  const fn = this;
  const args = Array.prototype.slice.call(arguments, 1);
  return function () {
    const bindArgs = Array.prototype.slice.call(arguments);
    return fn.call(context, ...args, ...bindArgs);
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.