震惊了,面试官居然问我ES6中class语法糖是怎么实现的

简介: 【10月更文挑战第2天】震惊了,面试官居然问我ES6中class语法糖是怎么实现的

theme: smartblue

前几天面试,突然被面试官问到ES6中class类是如何实现的,我一脸懵逼,这不是类吗,难道让我说js底层如何实现的?这不瞎扯淡吗!

于是我问,我不懂js是用什么实现的,类的底层实现也不懂。

面试官说,其实ES6中的class是js语法糖,完全可以通过构造函数实现!

我一脸懵逼,构造函数??

面试官看我不解,说:其实就是function函数!class就是通过function实现的!

看来我基本功还差的很!当然,最后面试也没过。

记录一下ES6中class语法糖是怎么实现的吧!

构造函数的创建和使用

构造函数的创建

 function Dog(){
   
      //构造函数中的属性
      this.name = "贝贝";
      //构造函数中的方法
      this.bark = function(){
   
          console.log("汪汪汪");
      }
  }
  1. 构造函数一般首字母会大写,为了和普通函数区分
  2. 构造函数的属性和方法前必须加this关键字,指代要生成的对象

构造函数的调用

  • new 就是执行构造函数,返回一个对象,不写new就是普通函数的调用,没有创造对象的能力
function Dog(){
   }
var d1 = new Dog();
var d2 = Dog();
  • 调用函数时,如果不传递参数,()可以不写,如果传递参数就必须写,建议都写上
 function Dog(){
   }
var d1 = new Dog();
var d2 = new Dog;
  • 构造函数中的this,由于和 new 连用的关系,是指向当前实例对象的
 function Dog(){
   
      console.log(this);
  }
  var d1 = new Dog();// this => d1
  var d2 = new Dog();// this => d2

构造函数的return

  function Dog(){
   
      this.name = "贝贝";
      this.bark = function(){
   
          console.log("汪汪汪");
      }
      // return 0;
      // return [];
  }
  var d1 = new Dog();
  console.log(d1);
  • 不写return,返回一个对象

  • return一个基本数据类型,结果不变,依旧返回一个对象

  • return一个复杂数据类型,返回一个复杂数据类型

成员

实例成员

function Star(name){
   
  this.name = name
  this.age = age
  this.sing = function(){
   
  }
}
  • 实例成员是构造函数内部通过this添加的成员
  • 实例成员只能通过实例化的对象来访问
let ldh = new Star("刘德华")
ldh.sing()
  • 不能通过构造函数来访问实例成员
 Star().name          //错误

静态成员

在构造函数本身添加的成员

Star.sex = "男"

静态成员只能通过构造函数来访问

Star.sex

构造函数和原型

原型对象prototype

  • 构造函数通过原型分配的函数是所有对象所共享的
  • js规定。每一个构造函数都有一个prototype属性,,指向另一个对象。prototype是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有
consloe.dir(Star)
  • 我们可以将不变的方法,定义在prototype对象上,实现所有实例共享方法。
function Star(name){
   
  this.name = name
  this.age = age
}
Star.prototype.sing = function(){
   }

一般情况下,公用属性放在构造函数里,公共方法放在原型对象上。

问:什么是原型?原型的作用?

答:一个对象,我们称prototype为原型对象。共享方法。

对象原型proto

对象都会有一个属性proto指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数原型对象的属性和方法,就是因为对象有proto存在

function Star(name){
   
  this.name = name
  this.age = age
}
Star.prototype.sing = function(){
   }
let ldh = new Star("刘德华",18)
consloe.log(ldh)

对象身上会默认添加一个指向prototype原型对象的proto

ldh.__proto__  === Star.prototype   //true

方法的查找规则:先在实例上查找,找不到后在原型链上查找

constructor函数

对象原型(proto构造函数( prototype 原型对象里面都有一个constructor属性,constructo我们称为构造函数,因为它指向构造函数本身。

function Star(name){
   
  this.name = name
  this.age = age
}
Star.prototype.sing = function(){
   }
let ldh = new Star("刘德华",18)
consloe.log(ldh.__proto__)
consloe.log(Star.prototype)

constructor主要用于记录该对象引用哪个构造函数,它可以让原型对象重新指向原来的构造函数。

很多情况下,我们需要手动利用constructor这个属性指回原来的构造函数

function Star(name){
   
  this.name = name
  this.age = age
}
//很多情况下,我们需要手动利用constructor这个属性指回原来的构造函数
Star.prototype.sing = function(){
   
  consloe.log("唱歌")
}
Star.prototype.movie = function(){
   
  consloe.log("电影")
}
let ldh = new Star("刘德华",18)
consloe.log(ldh.__proto__.constructor)
consloe.log(Star.prototype.constructor)

prototype上的方法比较多,我们可以用对象的形式写

function Star(name){
   
  this.name = name
  this.age = age
}
//很多情况下,我们需要手动利用constructor这个属性指回原来的构造函数
Star.prototype = {
   
   sing:function(){
   
      consloe.log("唱歌")
   },
   movie: function(){
   
      consloe.log("电影")
    }
}

let ldh = new Star("刘德华",18)
consloe.log(ldh.__proto__.constructor)
consloe.log(Star.prototype.constructor)

注意,此时prototype和proto的constructor指向都发生了改变!

这是因为,一开始的prototype是通过“.”方式添加内容,但是第二种方法是直接给prototype进行赋值,导致

导致此时prototype的constructor指向发生了改变!

(有Star构造函数变成了Object,constructor指向构造它的原型函数)

此时打印

consloe.log(ldh.__proto__)
consloe.log(Star.prototype)

也可以发现prototype的constructor方法已经被覆盖没有了。此时,我们需要手动利用constructor这个属性指回原来的构造函数

function Star(name){
   
  this.name = name
  this.age = age
}
//很多情况下,我们需要手动利用constructor这个属性指回原来的构造函数
Star.prototype = {
   
   constructor:Star
   sing:function(){
   
      consloe.log("唱歌")
   },
   movie: function(){
   
      consloe.log("电影")
    }
}

构造函数、实例原型对象之间的关系

原型链

原型对象也有proto

consloe.log(Star.prototype)

通过construtor我们可以知道,Star.prototype.proto指向Object.Prototype

consloe.log(Star.prototype.__proto__ === Object.Prototype)  //true

每个对象的proto就形成了原型链

js的成员查找机制

原型对象this指向

构造函数中,里面的this指向的是对象实例 ldh

拓展内置对象

示例:给数组增加自定义某种功能!

Array.prototype.sum = function(){
   

}

继承

ES6之前没有提供extends继承。我们通过构造函数 + 原型对象模拟实现继承,被称为组合继承。

call方法

1.调用函数;2.并且修改函数运行时的this指向

语法:function.call(thisArg, arg1, arg2, ...)

function eat(){
   
  consloe.log("我想吃")
}

eat.call()

借用构造函数继承父类型属性

核心原理:通过call()把父类型的this指向子类型的this,这样就可以实现子类型继承父类型的属性

//父函数
function Father(name, price) {
   
  //thi指向父构造函数的对象实例
  this.name = name;
  this.price = price;
}
//子构造函数
function Son(name, price) {
   
  //thi指向子构造函数的对象实例
  //将父构造函数当一个普通函数调用,并改变this指向
  Father.call(this, name, price);
  this.age = 18
}

借用构造函数继承父类型方法

使用Son.prototype = Father.prototype

//父函数
function Father(name, price) {
   
  //thi指向父构造函数的对象实例
  this.name = name;
  this.price = price;
}
 Father.prototype.money = function(){
   
   console.log(111111)
 }
//子构造函数
function Son(name, price) {
   
  //thi指向子构造函数的对象实例
  //将父构造函数当一个普通函数调用,并改变this指向
  Father.call(this, name, price);
  this.age = 18
}
Son.prototype = Father.prototype

Son.prototype.study = function(){
   }

这样会导致父函数的原型对象也添加上study方法,修改子对象原型,父对象原型也会改变!这是不可行的!!!!!

我们使用下面的方法实现继承:

Son.ProtoType = new Father()

但注意,此时Son的ProtoType上的construtor已经被覆盖了,所以我们需要将constuctor指回原来的原型对象

Son.prototype.construtor = Son
相关文章
|
5月前
|
前端开发
【面试题】如何使用ES6 ... 让代码优雅一点?
【面试题】如何使用ES6 ... 让代码优雅一点?
|
5月前
|
JavaScript 前端开发
【面试题】 JS手写ES6的Object.create方法
【面试题】 JS手写ES6的Object.create方法
|
5月前
|
设计模式 前端开发 算法
【面试题】 ES6 类聊 JavaScript 设计模式之行为型模式(二)
【面试题】 ES6 类聊 JavaScript 设计模式之行为型模式(二)
|
27天前
|
前端开发 JavaScript
JavaScript 面试系列:如何理解 ES6 中 Generator ?常用使用场景有哪些?
JavaScript 面试系列:如何理解 ES6 中 Generator ?常用使用场景有哪些?
|
1天前
|
存储 前端开发 JavaScript
关于 ES6 中 Promise 的面试题
关于 ES6 中 Promise 的面试题
5 0
|
3月前
|
JSON 前端开发 数据格式
|
5月前
|
索引
【ES6新语法】let、const、var的区别,你学会了面试官没话说
【ES6新语法】let、const、var的区别,你学会了面试官没话说
|
5月前
|
存储 前端开发 JavaScript
前端面试题整理 (ES6篇)
前端面试题整理 (ES6篇)
|
5月前
|
存储 前端开发 JavaScript
ES6 面试题
ES6 面试题
|
5月前
|
前端开发 JavaScript Java
【面试题】 ES6中将非数组转换为数组的三种方法
【面试题】 ES6中将非数组转换为数组的三种方法