[JavaStript学习记录] 二.面向对象 (loading...)

news/2024/7/19 14:33:25 标签: javascript, js, 前端

---- 本系列仅为个人学习总结,基于阮一峰大佬的《>>JavaScript 教程<<》---

目录

一.new 命令

作用: 执行构造函数,返回一个实例对象

若不使用new命令,直接调用构造函数会怎样?

补充: 

new命令简化的内部流程,

new.target属性

Object.creat()方法

二.this 关键字

设计目的:在函数体内部,指代函数当前的运行环境

>> this本质  <<

注意点

Ⅰ.避免多层 this

Ⅱ.避免数组处理方法中的 this

//Ⅲ.避免回调函数中的 this

>> ※绑定 this 的方法 <<

三.对象的继承

四.Object 对象的相关方法

五.严格模式


 典型的面向对象编程语言(比如 C++ 和 Java),都有“类”(class)这个概念。所谓“类”就是对象的模板,对象就是“类”的实例。但是,JavaScript 语言的对象体系,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype)

JavaScript 语言使用构造函数(constructor)作为对象的模板。所谓”构造函数”,就是专门用来生成实例对象的函数。它就是对象的模板,描述实例对象的基本结构。一个构造函数,可以生成多个实例对象,这些实例对象都有相同的结构。

构造函数的特点:

  1. 函数体内部使用了this关键字,代表了所要生成的对象实例
  2. 生成对象的时候,必须使用new命令

一.new 命令

作用: 执行构造函数,返回一个实例对象

javascript">var Vehicle = function () {
  this.price = 1000;
};

var v = new Vehicle();
v.price // 1000


new命令执行时,构造函数内部的this,就代表了新生成的实例对象

new命令本身就可以执行构造函数,所以后面的构造函数可以带括号,也可以不带括号, 但是为了表示这里是函数调用,推荐使用括号。

若不使用new命令,直接调用构造函数会怎样?

此时

  • 构造函数变成了普通函数,并不会生成实例对象
  • this代表了全局对象
javascript">var Vehicle = function (){
  this.price = 1000;
};

var v = Vehicle();
v // undefined
price // 1000 ,(全局变量)

原本this在最外层代码中便是全局对象, 即

 

补充

        博客园 / ~_~ / >>全局对象和this指针<<

        以及阮一峰老师的文章 >>JavaScript 的 this 原理<<

  • 为了保证构造函数必须与new命令一起使用,一个解决办法是,构造函数内部使用严格模式,即第一行加上use strict。这样的话,一旦忘了使用new命令,直接调用构造函数就会报错。 
javascript">function Animal(age){
    'use strict';
    this._age = age;
};

var cat = Animal(); 
//Uncaught TypeError: Cannot set property '_age' of undefined
    at Animal

var dog = new Animal(22);
dog._age //22
  • 另一个解决办法,构造函数内部判断是否使用new命令,如果发现没有使用,则直接返回一个实例对象。 
javascript">function Animal(age){
    if(!(this instanceof Animal)){
        return new Animal(age);
    }
    this._age=age;
};

var cat = Animal(11); 
cat._age;//11

var dog = new Animal(22);
dog._age //22

new命令简化的内部流程,

可以用下面的代码表示

javascript">function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ params) {
  // 将 arguments 对象转为数组
  var args = [].slice.call(arguments);
  // 取出构造函数
  var constructor = args.shift();
  // 创建一个空对象,继承构造函数的 prototype 属性
  var context = Object.create(constructor.prototype);
  // 执行构造函数
  var result = constructor.apply(context, args);
  // 如果返回结果是对象,就直接返回,否则返回 context 对象
  return (typeof result === 'object' && result != null) ? result : context;
}

// 实例
var actor = _new(Person, '张三', 28);

new.target属性

函数内部可以使用new.target属性。如果当前函数是new命令调用,new.target指向当前函数,否则为undefined, 使用这个属性,可以判断函数调用的时候,是否使用new命令。

javascript">function f() {
  if (!new.target) {
    throw new Error('请使用 new 命令调用!');
  }
  // ...
}

f() // Uncaught Error: 请使用 new 命令调用!

Object.creat()方法

构造函数作为模板,可以生成实例对象。但是,有时拿不到构造函数,只能拿到一个现有的对象。我们希望以这个现有的对象作为模板,生成新的实例对象,这时就可以使用Object.creat()方法

javascript">var catA = {
    name : 'mimi',
    age : 2,
    talk: function(){
        console.log('Miao~,my name is '+this.name+'\n');
    }
};

var catB = Object.create(catA);
catB.talk(); // Miao~,my name is mimi
catB.age //2

 对象catAcatB的模板,后者继承了前者的属性和方法

二.this 关键字

设计目的:在函数体内部,指代函数当前的运行环境

javascript">var f = function () {
  console.log(this.x);
}

var x = 1;
var obj = {
  f: f,
  x: 2,
};

// 单独执行
f() // 1

// obj 环境执行
obj.f() // 2

JavaScript 支持运行环境动态切换,也就是说,this的指向是动态的,没有办法事先确定到底指向哪个对象

  • 由于对象的属性可以赋给另一个对象,所以属性所在的当前对象是可变的,即this的指向是可变的。
javascript">var A = {
  name: '张三',
  describe: function () {
    return '姓名:'+ this.name;
  }
};

var B = {
  name: '李四'
};

B.describe = A.describe;
B.describe()
// "姓名:李四"

如果this所在的方法不在对象的第一层,这时this只是指向当前一层的对象,而不会继承更上面的层。

javascript">var a = {
  p: 'Hello',
  b: {
    m: function() {
      console.log(this.p);
    }
  }
};

a.b.m() // undefined

上面代码中,a.b.m方法在a对象的第二层,该方法内部的this不是指向a,而是指向a.b,因为实际执行的是下面的代码。

javascript">var b = {
  m: function() {
   console.log(this.p);
  }
};

var a = {
  p: 'Hello',
  b: b
};

(a.b).m() // 等同于 b.m()

如果要达到预期效果,只有写成下面这样。

javascript">var a = {
  b: {
    m: function() {
      console.log(this.p);
    },
    p: 'Hello'
  }
};

如果这时将嵌套对象内部的方法赋值给一个变量,this依然会指向全局对象。

javascript">var a = {
  b: {
    m: function() {
      console.log(this.p);
    },
    p: 'Hello'
  }
};

var hello = a.b.m;
hello() // undefined

上面代码中,m是多层对象内部的一个方法。为求简便,将其赋值给hello变量,结果调用时,this指向了顶层对象。为了避免这个问题,可以只将m所在的对象赋值给hello,这样调用时,this的指向就不会变。

javascript">var hello = a.b;
hello.m() // Hello

>> this本质  <<

注意点

  • Ⅰ.避免多层 this

javascript">var o = {
  f1: function () {
    console.log(this);
    var f2 = function () {
      console.log(this);
    }();
  }
}

o.f1()
// Object
// Window

★实际执行的是下面的代码

var temp = function () {
  console.log(this);
};

var o = {
  f1: function () {
    console.log(this);
    var f2 = temp();
  }
}

①一个常见的解决方法是在第二层改用一个指向外层this的变量

javascript">var o = {
  f1: function() {
    console.log(this);
    var that = this;
    var f2 = function() {
      console.log(that);
    }();
  }
}

o.f1()
// Object
// Object

②JavaScript 提供了严格模式,也可以硬性避免这种问题。严格模式下,如果函数内部的this指向顶层对象,就会报错。

javascript">var counter = {
  count: 0
};
counter.inc = function () {
  'use strict';
  this.count++
};
var f = counter.inc;
f()
// TypeError: Cannot read property 'count' of undefined

上面代码中,inc方法通过'use strict'声明采用严格模式,这时内部的this一旦指向顶层对象,就会报错。

  • Ⅱ.避免数组处理方法中的 this

javascript">var o = {
  v: 'hello',
  p:['玛卡巴卡','唔西迪西'],
  f: function f() {
    this.p.forEach(function (item) {
      console.log(this.v + ' ' + item);
    });
  }
}

o.f()

>>undefined a1
>>undefined a2


解决方法👇👇👇 
-----------------------
法一:使用中间变量固定this
var o={
    v:'hello',
    p:['玛卡巴卡','唔西迪西'],
    f:function f(){
        var that=this;
        this.p.forEach(function(item){console.log(that.v+'  '+item)});
    }
}
o.f()

>>hello  玛卡巴卡
>>hello  唔西迪西

------------------------
法二:将this当作foreach方法的第二个参数,固定它的运行环境
var o = {
  v: 'hello',
  p:['玛卡巴卡','唔西迪西'],
  f: function f() {
    this.p.forEach(function (item) {
      console.log(this.v + ' ' + item);
    }, this);
  }
}

o.f()

>>hello  玛卡巴卡
>>hello  唔西迪西
  • //Ⅲ.避免回调函数中的 this

>> ※绑定 this 的方法 <<

(使用callapplybind这三个方法,来切换/固定this的指向。)

三.对象的继承

四.Object 对象的相关方法

五.严格模式


http://www.niftyadmin.cn/n/816858.html

相关文章

[JavaStript学习记录] 对象的继承

---- 本系列仅为个人学习总结,基于阮一峰大佬的《>>JavaScript 教程<<》--- 目录 一.原型对象 prototypep属性 Constructor属性 二.instanceof 运算符 注意:instanceof只能用于对象&#xff0c;不适用原始类型的值 三.构造函数的继承 第一步: 第二步: 另…

[JavaStript学习记录] 对原型链的一些理解

回忆一下昨天的学习内容,梳理一些疑惑 先写了一个简单的构造函数 function A(){var num0; }var aanew A();查看该函数的实例 为什么实例对象没有prototype属性呢? 下面是经过查证后我的理解 发现 1.aa 是 A 的一个实例,但是不是一个函数&#xff0c;所以没有prototype; A是…

[JavaStript学习记录] 模块/封装私有变量

模块(用软件工程的方法&#xff0c;管理网页的业务逻辑) "立刻执行函数" 为了不暴露私有成员,使用"立刻执行函数",将有关的属性、方法封装在一个函数的作用域中 var m (function () {var count 0;var f1 function () {//...};var f2 function () {/…

2018-2019-1 20165333 《信息安全系统设计基础》第六周学习总结

2018-2019-1 20165333 《信息安全系统设计基础》第六周学习总结 教材内容总结 Unix I/O 打开文件。一个应用程序通过要求内核打开相应的文件&#xff0c;来宣告它想要访问一个I/O设备。Linux shell创建的每个进程开始都有三个打开的文件&#xff1a;标准输入&#xff08;0&…

[JavaScript学习记录] 首次运用于网页,做一个简易利息计算器!!!

目录 事件 错误处理 1.隐藏/显示文字 2.简单的加法计算器 效果: ★★★3.简易利息计算器 效果: ​​​​​​​ 事件 javascript允许html与用户交互的行为 例如:鼠标点击事件 <script> function sayHello{alert(Hello World ppp!); } </script><button …

ubuntu 手动修改分辨率为1920 X 1080 的两种方式

方案一&#xff08;临时性&#xff0c;重启会失效&#xff09;&#xff1a; 1、打开终端。输入&#xff1a;cvt 1920 1080 出现有modeline 的提示。 2、使用 xrandr 创建新的 mode&#xff0c;--newmode 后面跟刚刚 cvt 产生的 modeline 后面的信息&#xff0c;如果去掉“_60.0…

[JavaScript学习记录] BOM小记

浏览器对象模型(Browser Object Model) 浏览器对象包括 Window(窗口) Navigator(浏览器) Screen (客户端屏幕) History(访问历史) Location(浏览器地址) 目录 History Nevigator 弹框 警告框alert​ 确认框conform 输入框 History history.go(-2); //-1表示上次&#xf…

模板:缩点

翻之前记录翻出来缩点的板子 正好今天语文课看tarjan睡着了…… https://www.luogu.org/problemnew/show/P3387 1 #include<iostream>2 #include<cstdio>3 #include<queue>4 using namespace std;5 const int maxn1000010;6 int n, m, cnt, num, s, top;7 in…