『前端学习笔记』 JavaScript 类与对象

参考视频:2019全新javaScript进阶面向对象ES6

参考文档:ES6入门教程





面向对象特征

  • (抽象)
  • 封装
  • 继承
  • 多态



ES6类


类class

  • 创建类:
  class Person{
    //body
  }
  • 创建对象/实例:
  var x = new Person();

必须使用new

ES6中的类没有变量提升:先定义类,才能实例化。不可颠倒。

  • 添加函数/方法:
  //in class
  myFunction(str){ //4种JS输出
    console.log(str);
    alert(str);
    document.write(str);
    //document.getElementById("myid").innerHTML = str;
    return 0;
  }

不加function
不加,



调用自己:this对象

类对象的共有属性和方法通过this调用。

  • 注意this的指向:
<button>按钮</button>
<script>

  class Person{
    constructor(name) {
      this.btn = document.querySelector("button");
      this.btn.onclick = this.f;
      //加小括号:加载页面后就调用
      //不加小括号:点击按钮触发事件才会调用
    }
    f(){
      console.log(this); //使用this
    }
  }

  var x = new Person();

</script>
  • 代码结果
    在这里插入图片描述

此处this指向当前对象中的按钮,而不是当前对象。

  • 构造器中this指向当前实例对象。
  • 方法中this指向当前调用者对象。



构造器constructor

在使用new实例化时,调用构造器,进行赋值等初始化操作。

不加构造器时,系统会默认添加一个空构造器

构造器唯一(和Java不同)

  • 创建:
  class Person{
    constructor(name, age) {
      this.name = name;
      this.age = age;
    }
  }
  • 通过构造器实例化:
  var x = new Person("myname", 20);
  • 可使用:
  console.log(x.age);
  console.log(x);
  • 代码结果:
    在这里插入图片描述



继承extends

  class Father{
  }
  class Son extends Father{
  }

子类对象可以使用父类已有的属性和方法。

写和父类同名的方法:重写
写和父类不同名方法:扩展


调用父类:super对象

  • 调用父类构造器:
 class Father{
    constructor(name, age) {
      this.name = name;
      this.age = age;
    }
  }
  class Son extends Father{
    constructor(name, age) {
      super(name, age); //调用父类(构造器)
      //super必须放在this前面
      this.name = name;
      this.age = age;
    }
  }
  • 调用父类普通函数:
  class Father{
    say(){
      return "in Father";
    }
  }
  class Son extends Father{
    say(){ //重写
      console.log(super.say()); //调用父类方法
    }
  }



Javascript对象

ES6之前Javascript没有,但是有对象的概念,而且所有事物都是对象。

定义对象

  • 定义对象(使用变量):
  /*对象*/
  var Person={
    /*属性*/
    name:"abc",
    age:30,
    /*方法*/
    echo:function(str){
      alert(str);
    }
  }
  • 定义对象(使用函数作为构造器):
  /*contructor*/
  function Person(nameText, ageText) {
    this.name = nameText;
    this.age = ageText;
    this.f = function(){
      console.log("in function f");
    }
  }
  
  var p = new Person("abc", 30);
  
  document.write(p.name);
  document.write(p.age);
  p.f();



实例成员和静态成员

  function Person(nameText) {
    this.name = nameText; //实例成员
  }

  Person.age = 30; //静态成员

  console.log(new Person("myname").name);
  console.log(Person.age);



prototype原型对象与__proto__原型属性

每一个构造函数都有一个prototype属性(对象),即原型对象

不变的方法可以直接定义在prototype上,让对象实例共享方法。节约内存空间。

  • prototype原型对象(属于构造函数):
  function Person(nameText) {
    this.name = nameText;
  }
  
  Person.prototype.f = function(str){ //原型
    console.log(str);
  }

  var t = new Person("myname");
  t.f(t.name); //调用测试
  1. 代码结果
    在这里插入图片描述
  • __proto__原型属性(属于对象实例):
  function Person(nameText) {
    this.name = nameText;
  }
  
  Person.prototype.f = function(str){ //原型
    console.log(str);
  }

  var t = new Person("myname");
  console.log(t); //打印t对象
  console.log(t.__proto__ === Person.prototype); //t中__proto__与构造函数的prototype是否严格相等
  1. 代码结果(对象属性):
    在这里插入图片描述
  2. 代码结果(严格相等):
    在这里插入图片描述
    足以证明实例对象的原型属性构造函数的原型对象是相同的。


constructor构造函数

__proto__prototype都含有一个constructor属性,指回构造函数本身。

  • 构造函数属性:
  function Person(nameText) {
    this.name = nameText;
  }
  
  Person.prototype.f = function(str){ //原型
    console.log(str);
  }

  var t = new Person("myname");
  console.log(t.__proto__);
  console.log(Person.prototype);
  1. 代码结果:
    在这里插入图片描述
  • 构造函数属性测试:
  function Person(nameText) {
    this.name = nameText;
  }

  Person.prototype.f = function(str){ //原型
    console.log(str);
  }

  var t = new Person("myname");
  console.log(t.__proto__.constructor);
  console.log(Person.prototype.constructor);
  1. 代码结果
    在这里插入图片描述
  • 使用constructor指回构造函数1:
  function Person(nameText) {
    this.name = nameText;
  }

  Person.prototype = { //原型,一次性添加多个函数
    f1: function (str) {
      console.log(str);
    },
    f2: function (str) {
      alert(str);
    }
    //相对于单次添加函数Person.prototype.f(){},会覆盖掉constructor!
  }

  console.log(Person.prototype.constructor); //批量添加原型后,构造函数

  Person.prototype.constructor = Person; //手动指回
  console.log(Person.prototype.constructor); //批量添加原型并手动指回后,构造函数
  1. 代码结果
    在这里插入图片描述
  • 使用constructor指回构造函数2:
  function Person(nameText) {
    this.name = nameText;
  }

  Person.prototype = { //原型,一次性添加多个函数
    constructor: Person, //手动指回
    f1: function (str) {
      console.log(str);
    },
    f2: function (str) {
      alert(str);
    }
    //相对于单次添加函数Person.prototype.f(){},会覆盖掉constructor!
  }

  console.log(Person.prototype.constructor); 
  1. 代码结果:
    在这里插入图片描述

原型链

  • (constructor、prototype、实例对象)三者关系
    在这里插入图片描述
  • 原型链
    -在这里插入图片描述
  1. 函数原型对象prototype也有__proto__属性,和Object对象的prototype严格相等。
  function Person(nameText) {
    this.name = nameText;
  }

  console.log(Person.prototype.__proto__ === Object.prototype);
  1. 代码结果:true

  2. Object对象的prototype中的__proto__属性指向null

  console.log(Object.prototype.__proto__);
  1. 代码结果:null


基于原型链的成员查找机制

在这里插入图片描述


this指向问题

  • 一般情况下,this指向调用者。
  • 构造函数中,this指向实例对象
  function Person(nameText) {
    this.name = nameText; //this指向对象实例
  }
  • 函数原型中,this指向实例对象
  function Person(nameText) {
    this.name = nameText; 
  }

  Person.prototype.f = function(){
    console.log(this); //this指向对象实例
  }

  var t = new Person("myname");
  t.f(); //调用
  1. 代码结果:
    在这里插入图片描述


使用原型对象扩展内置对象

  • 打印Array原型对象:
  console.log(Array.prototype);
  1. 代码结果:
    在这里插入图片描述
    在这里插入图片描述
  • 为Array类添加新函数(求和):
  Array.prototype.sum = function () {
    var res = 0;
    var len = this.length;
    for(let i = 0; i < len; i++){
      res += this[i];
    }
    return res;
  }

  t = [1, 2, 3];
  console.log(t.sum());



继承

ES6之前通过构造函数原型函数实现组合继承

call方法

调用指定函数。
修改函数运行时this指向。

  • 调用函数:
  function f() {
    console.log("my function");
  }

  f.call(); //显式调用函数
  • 改变指向:
  1. this指向默认window
  function f() {
    console.log(this); //调用者:window
  }

  f.call();
  1. 代码结果
    在这里插入图片描述
  2. 使this指向新对象:
  function f() {
    console.log(this); //调用者:window
  }

  var newobject = {age: 20};

  f.call(newobject); //更改调用者
  1. 代码结果
    在这里插入图片描述
  2. 使this指向新对象(增加新参数):
  function f(x, y) {
    console.log(this); //调用者:window
  }

  var newobject = {age: 20};

  f.call(newobject, 1, 2); //第一个参数更改调用者,后续为普通参数



继承父类属性:构造函数

通过call()将父类型的this指向子类型的this

  function Father(name) { //父类
    this.name = name;
  }

  function Son(name) { //子类
	Father.call(this, name); //父类的this变成了子类的this,再添加参数
	this.age = age; //新加属性
  }

  var t = new Son("myname");
  console.log(t.name); //验证


继承父类属性:原型对象

  • 指向父类原型:
  function Father(name) { //父类
    this.name = name;
  }
  Father.prototype.getName = function(){ //父类原型
	return this.name;
  }

  function Son(name) { //子类
	Father.call(this, name); //父类的this变成了子类的this
  }
  Son.prototype = Father.prototype; //子类原型指向父类原型

  var t = new Son("myname");
  console.log(t.getName()); //验证

会出现问题:

  1. 子类原型新添加方法时,会给父类也添加此方法。
  2. 子类的构造器变成了父类的构造器。

  • 指向父类实例:
  function Father(name) { //父类
    this.name = name;
  }
  Father.prototype.getName = function(){ //父类原型
	return this.name;
  }

  function Son(name) { //子类
	Father.call(this, name); //父类的this变成了子类的this
  }
  //Son.prototype = Father.prototype; //子类原型指向父类原型
  Son.prototype = new Father(); //先实例化,再让子类原型指向父类实例对象
  Son.prototype.constructor = Son; //指向父类实例后会失去构造器,重新指回

  var t = new Son("myname");
  console.log(t); //验证
  1. 代码结果:在子类实例的__proto__中的__proto__中找到继承的父类方法。
    在这里插入图片描述


ES6类的本质

  • 测试类的本质:
  1. 测试代码
  class MyClass{}
  console.log(typeof MyClass); //测试类型
  console.log(MyClass.prototype); //测试原型函数
  console.log(MyClass.prototype.constructor); //测试构造器
  var t = new MyClass();
  console.dir(t); //测试实例
  1. 代码结果:
    在这里插入图片描述

  2. 结论:
    类的本质是函数,可理解为构造函数的另一种形式。
    类有原型对象。
    类有构造器。
    实例有__proto__属性。

  • 使用原型为类添加函数:
  1. 测试代码:
  class MyClass{}
  console.log(MyClass.prototype);

  MyClass.prototype.printNew = function(){
	console.log("new!");
  }

含有变量/函数提升。

  1. 代码结果:
    在这里插入图片描述
  • ES6的类是语法糖
    两种方法实现同种功能,更便捷的写法,便是语法糖。


ES5新增方法


数组与字符串方法

参考文档:ECMAScript 5 - JavaScript 5


新的对象属性和方法

  • Object.defineProperty

vue中会用到。

	//定义对象
	var obj = {
		id: 1,
		name: "myname"
	};
	
	//旧的方式
	obj.age = 20; //新增属性
	obj.id = 2; //修改属性
	
	//新的方式
	Object.defineProperty(obj, 'sum', { //新增属性
		value: 100
	});
	Object.defineProperty(obj, 'name',{ //修改属性
		value: "mynametwo", //值,默认undefined
		writable: true, //是否可以被重写/修改,默认false
		enumerable: true, //是否可以被枚举,默认false
		configurable:true //是否可以被删除/修改特性true or false,默认false
	})
	
	//get和set
	Object.defineProperty(obj, "name", {
	  get : function() { return name },
	  set : function(value) { name = value}
	});

  1. writable(可修改):默认false
	var obj = {
		s0: 100
	};
	
	Object.defineProperty(obj, 's1', {
		value: 100
	});
	
	Object.defineProperty(obj, 's2',{
		value: 100, 
		writable: true
	});
	
	//测试
	obj.s0 += 1; //成功,不是通过Object.defineProperty定义的
	obj.s1 += 1; //失败,默认false不允许修改
	obj.s2 += 1; //成功,手动true允许修改
	
	console.log(obj);

  1. enumerable(可枚举/可遍历):默认false
	var obj = {
		s0: 100
	};
	
	Object.defineProperty(obj, 's1', {
		value: 100
	});
	
	Object.defineProperty(obj, 's2',{
		value: 100, 
		enumerable: true
	});
	
	//测试
	console.log(obj);
	console.log(Object.keys(obj));
	//s0成功,不是通过Object.defineProperty定义的
	//s1失败,默认false不允许枚举
	//s2成功,手动true允许枚举

  1. configurable(可删除/修改特性true or false):默认false
	var obj = {
		s0: 100
	};
	
	Object.defineProperty(obj, 's1', {
		value: 100
	});
	
	Object.defineProperty(obj, 's2',{
		value: 100, 
		configurable: true
	});
	
	//测试
	delete obj.s0; //成功,不是通过Object.defineProperty定义的
	delete obj.s1; //失败,默认false不允许删除
	delete obj.s2; //成功,手动true允许删除
	
	console.log(obj);
	var obj = {
		s0: 100
	};
	
	Object.defineProperty(obj, 's1', {
		value: 100
	});
	
	Object.defineProperty(obj, 's2',{
		value: 100, 
		configurable: true
	});
	
	//测试
	Object.defineProperty(obj, 's0', { //成功,不是通过Object.defineProperty定义的
		writable: true,
		enumeralbe: true
	});
	Object.defineProperty(obj, 's1', { //失败(异常),默认false不允许更改特性
		enumeralbe: true
	});
	Object.defineProperty(obj, 's2', { //成功,手动true允许更改特性
		writable: true,
		enumeralbe: true
	});
	
	console.log(obj);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大熊软糖M

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值