尼采般地抒情

公告栏

此网站主题为本人手写主题,主题还在开发中……


作者:尼采般地抒情

站点信息

文章数目:240
已运行时间:
目录
  1. 原始值和引用值
  2. 体系一:原型
    1. 构造函数原型
    2. 对象原型
    3. constructor 构造函数
    4. 原型链和成员查找机制
    5. 原型体系中的继承
  3. 体系二:类(class)【ES6】
    1. 创建+继承+使用
  4. 对象:一系列创建
    1. 字面量
    2. 模式工厂
    3. 构造函数
    4. 原型模式
  5. 对象:Object 内置方法使用
    1. 对象迭代
    2. Object.defineProperty
  6. 面向对象设计:tab 栏切换
    1. 功能需求
    2. 案例准备
    3. 切换
    4. 添加
    5. 删除
    6. 编辑

尼采般地抒情

尼采般地抒情

公告栏

此网站主题为本人手写主题,主题还在开发中……


作者:尼采般地抒情

站点信息

文章数目:240
已运行时间:
对于实现面向对象这一块,JavaScript可谓是我见过最恶心的一门语言,现在发现之前学的C++或是Java简直不要太正规…… JavaScript首先在ES6没有出来之前,利用一个叫原型的一系列机制来用一段很长的代码来实现类的继承,说白了就是在函数里面默认给你加个一个叫原型的对象属性,再利用一系列指向来完成所谓的继承。在ES6之后,才有了形式上的类class及其对象,以及一个单词extends就搞定的继承,虽说搞定,但这里面的机制还是原型相关知识,记录学习一下。 不管是原型也好,新加的class也罢,就一个目的——**为了实现面向对象**。从两个体系来展开详述。

原始值和引用值

这里面 Java 和 JavaScript 都是只有引用的概念,但是在 C/C++里面,就有指针的概念
image.png

体系一:原型

构造函数原型

每个构造函数里面都有一个属性,这个属性叫 prototype,指向另一个对象(有什么用?在后面原型链就会发现有用了),并且这个属性是一个对象,叫做构造函数原型

这样可以解决一个问题,就是创建不同实例,这些事例所用的方法都是同一个内存下的方法,实现共享

image.png

对象原型

每个对象里面都有proto属性,这个叫对象原型,这个玩意指向构造函数的 prototype 对象

proto对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype

constructor 构造函数

  1. 对象原型( proto)和构造函数(prototype)原型对象里面都有一个属性 constructor 属性 ,constructor 我们称为构造函数,因为它指回构造函数本身
  2. constructor 主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。
  3. 一般情况下,对象的方法都在构造函数的原型对象中设置。如果有多个对象的方法,我们可以给原型对象采取对象形式赋值,但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor   就不再指向当前构造函数了。此时,我们可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。

原型链和成员查找机制

image.png

原型体系中的继承

call 方法可以改变一个函数的指向

  1. 继承父构造函数里面的属性
// 1. 父构造函数
function Father(uname, age) {
  // this 指向父构造函数的对象实例
  this.uname = uname;
  this.age = age;
}
// 2 .子构造函数
function Son(uname, age, score) {
  // this 指向子构造函数的对象实例
  // 3.使用call方式实现子继承父的属性
  Father.call(this, uname, age);
  this.score = score;
}
var son = new Son("刘德华", 18, 100);
console.log(son);
  1. 继承方法
// 1. 父构造函数
function Father(uname, age) {
  // this 指向父构造函数的对象实例
  this.uname = uname;
  this.age = age;
}
Father.prototype.money = function () {
  console.log(100000);
};
// 2 .子构造函数
function Son(uname, age, score) {
  // this 指向子构造函数的对象实例
  Father.call(this, uname, age);
  this.score = score;
}
// Son.prototype = Father.prototype;  这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
Son.prototype = new Father();
// 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
Son.prototype.constructor = Son;
// 这个是子构造函数专门的方法
Son.prototype.exam = function () {
  console.log("孩子要考试");
};
var son = new Son("刘德华", 18, 100);
console.log(son);

体系二:类(class)【ES6】

在 ES6 中新增加了类的概念,可以使用 class 关键字声明一个类,之后以这个类来实例化对象。类抽象了对象的公共部分,它泛指某一大类(class)对象特指某一个,通过类实例化一个具体的对象。其创建的方式和之前学过的语言很类似。
在 ES6 中类没有变量提升,所以必须先定义类,才能通过类实例化对象

创建+继承+使用

// 奥特曼类
class Aoteman {
  // 构造函数里面放共有属性、方法
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  Ability(abi) {
    console.log(this.name + " can " + abi);
  }
}

// 假奥特曼类 继承 奥特曼
class Jia extends Aoteman {
  constructor(x, y) {
    // 继承父类的构造函数
    super(x, y);
    // 方便写自己的函数
    this.x = x;
    this.y = y;
  }
  // 自己内部的函数
  Chuiniu() {
    console.log(this.x + " chuiniu");
  }
}

// 创建迪迦对象
let dijia = new Aoteman("dijia", 100);
console.log(dijia);
dijia.Ability("X-ray");
let dijia_jia = new Jia("dijia_jia", 50);
dijia_jia.Ability("xxx");
dijia_jia.Chuiniu();

image.png

对象:一系列创建

字面量

属性和方法的调用:
属性可以用”.”和[“属性名”]来调用
方法用”.”来调用

模式工厂

new 一个空对象,let obj = new Object();
然后利用”.”的方式给其添加属性和方法
内置的 Object()构造函数
image.png

构造函数

构造函数:是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 运算符一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。

function 构造函数名(形参1,形参2,形参3) {
     this.属性名1 = 参数1;
     this.属性名2 = 参数2;
     this.属性名3 = 参数3;
     this.方法名 = 函数体;
}

let obj = new 构造函数名(实参1,实参2,实参3)
  • 构造函数约定首字母大写
  • 函数内的属性和方法前面需要添加 this ,表示当前对象的属性和方法。
  • 构造函数中不需要 return 返回结果
  • 当我们创建对象的时候,必须用 new 来调用构造函数

原型模式

image.png
下面详述什么是原型

对象:Object 内置方法使用

对象迭代

for...in 语句用于对数组或者对象的属性进行循环操作。
其语法如下: ```js for (变量 in 对象名字) { // 在此执行代码 } ```
  • 语法中的变量是自定义的,它需要符合命名规范,通常我们会将这个变量写为 k 或者 key。书里面建议用 const 来加持。
for (let k in obj) {
  console.log(k); // 这里的 k 是属性名
  console.log(obj[k]); // 这里的 obj[k] 是属性值
}
Object.keys(对象)获取属性名
```javascript var obj = { id: 1, pname: '小米', price: 1999, num: 2000 }; var result = Object.keys(obj) console.log(result)//[id,pname,price,num] ```

Object.defineProperty

Object.defineProperty 设置或修改对象中的属性

Object.defineProperty(对象,修改或新增的属性名,{
        value:修改或新增的属性的值,
        writable:true/false,//如果值为false 不允许修改这个属性值
        enumerable: false,//enumerable 如果值为false 则不允许遍历
    configurable: false  //configurable 如果为false 则不允许删除这个属性 属性是否可以被删除或是否可以再次修改特性
})

面向对象设计:tab 栏切换

功能需求

  1. 点击 tab 栏,可以切换效果.
  2. 点击 + 号, 可以添加 tab 项和内容项.
  3. 点击 x 号, 可以删除当前的 tab 项和内容项.
  4. 双击 tab 项文字或者内容项文字可以修改里面的文字内容

案例准备

  1. 获取到标题元素
  2. 获取到内容元素
  3. 获取到删除的小按钮 x 号
  4. 新建 js 文件,定义类,添加需要的属性方法(切换,删除,增加,修改)
  5. 时刻注意 this 的指向问题

切换

  • 为获取到的标题绑定点击事件,展示对应的内容区域,存储对应的索引
this.lis[i].index = i;
this.lis[i].onclick = this.toggleTab;
  • 使用排他,实现只有一个元素的显示
toggleTab() {
   //将所有的标题与内容类样式全部移除
     for (var i = 0; i < this.lis.length; i++) {
     this.lis[i].className = '';
     this.sections[i].className = '';
     }
   //为当前的标题添加激活样式
     this.className = 'liactive';
    //为当前的内容添加激活样式
     that.sections[this.index].className = 'conactive';
  }

添加

  • 为添加按钮+ 绑定点击事件
this.add.onclick = this.addTab;
  • 实现标题与内容的添加,做好排他处理
addTab() {
    that.clearClass();
    // (1) 创建li元素和section元素
    var random = Math.random();
    var li = '<li class="liactive"><span>新选项卡</span><span class="iconfont icon-guanbi">                </span></li>';
    var section = '<section class="conactive">测试 ' + random + '</section>';
    // (2) 把这两个元素追加到对应的父元素里面
    that.ul.insertAdjacentHTML('beforeend', li);
    that.fsection.insertAdjacentHTML('beforeend', section);
    that.init();
    }

删除

  • 为元素的删除按钮 x 绑定点击事件
this.remove[i].onclick = this.removeTab;
  • 获取到点击的删除按钮的所在的父元素的所有,删除对应的标题与内容
removeTab(e) {
     e.stopPropagation(); // 阻止冒泡 防止触发li 的切换点击事件
     var index = this.parentNode.index;
     console.log(index);
     // 根据索引号删除对应的li 和section   remove()方法可以直接删除指定的元素
     that.lis[index].remove();
     that.sections[index].remove();
     that.init();
     // 当我们删除的不是选中状态的li 的时候,原来的选中状态li保持不变
     if (document.querySelector('.liactive')) return;
     // 当我们删除了选中状态的这个li 的时候, 让它的前一个li 处于选定状态
     index--;
     // 手动调用我们的点击事件  不需要鼠标触发
     that.lis[index] && that.lis[index].click();
 }

编辑

  • 为元素(标题与内容)绑定双击事件
this.spans[i].ondblclick = this.editTab;
this.sections[i].ondblclick = this.editTab;
  • 在双击事件处理文本选中状态,修改内部 DOM 节点,实现新旧 value 值的传递
editTab() {
    var str = this.innerHTML;
    // 双击禁止选定文字
    window.getSelection ? window.getSelection().removeAllRanges() :                     document.selection.empty();
    // alert(11);
      this.innerHTML = '<input type="text" />';
      var input = this.children[0];
      input.value = str;
      input.select(); // 文本框里面的文字处于选定状态
      // 当我们离开文本框就把文本框里面的值给span
      input.onblur = function() {
      this.parentNode.innerHTML = this.value;
      };
      // 按下回车也可以把文本框里面的值给span
      input.onkeyup = function(e) {
      if (e.keyCode === 13) {
      // 手动调用表单失去焦点事件  不需要鼠标离开操作
      this.blur();
      }
    }
}

博客内容遵循: 署名-非商业性使用-禁止演绎 4.0 国际(CC BY-NC-ND 4.0)

本文永久链接: https://www.wztlink1013.com/blog/zfpg9dfgehog/

编辑: 部署: 订阅:

评论区

Twikoo 转换 utterances

最新评论

Loading...