JavaScript 之 构造函数与原型对象

Create by jsliang on 2018-12-11 09:27:44
Recently revised in 2018-12-25 20:43:57


“每个构造函数都有一个原型对象,
原型对象都包含一个指向构造函数的指针,
实例都包含一个指向原型对象的内部指针。”
—— 《JavaScript 高级程序设计》


一 目录

不折腾的前端,和咸鱼有什么区别

目录
一 目录
二 前言
三 正文
3.1 箭头函数
3.2 不能使用箭头函数的场景
3.3 构造函数和原型对象
四 总结


二 前言

返回目录


 在编写学习 Node 基础 中,写到 Node 仿 Express 的时候,我写了这么一段代码:

let Application = () => {
  // ...
}

Application.prototype.get = (path, handle) => {
  // ...
}


 然后代码死活跑不起来,于是我就去问大佬,大佬默默回了句:

  • “构造函数不能用箭头函数呀”

 我一愣:

  • 为什么不能用构造函数?
  • 什么时候我不能使用构造函数?
  • 箭头函数的解释是什么咯?
  • 什么是构造函数?
  • ……

 所以,在下面,咱一一分析这些问题。


三 正文

返回目录


 参考文献:

  1. 箭头函数 | 廖雪峰的官网
  2. 什么时候你不能使用箭头函数? | 简书 - 王仕军
  3. js深入理解构造函数和原型对象 | 博客园 - 快饿死的鱼
  4. 一句话总结JS构造函数、原型和实例的关系 | CSDN - 夜色芜染
  5. 箭头函数 | MDN


3.1 箭头函数

返回目录


 ES6 标准新增了一种新的函数:Arrow Function(箭头函数)。
 为什么叫箭头函数?

x => x * x;

 因为它的定义用的就是一个箭头。上面代码相当于:

function(x) {
  return x * x;
}

 那么,它的作用是什么呢:箭头函数相当于匿名函数,并且简化了函数定义。而箭头函数内部的 this 是词法作用域,由上下文确定:

var obj = {
 birth: 1990,
 getAge: function () {
  var b = this.birth; // 1990
  var fn = function () {
    return new Date().getFullYear() - this.birth; // this 指向 window 或 undefined
  };
  return fn();
 }
};

 在上文的代码中:

return new Date().getFullYear() - this.birth;

 这里的 this 指向 windowundefined,从而使 JavaScript 函数对 this 的绑定没有得到预期的结果。
 那么,我们可以尝试使用箭头函数:

var obj = {
 birth: 1990,
 getAge: function () {
  var b = this.birth; // 1990
  var fn = () => new Date().getFullYear() - this.birth; // this 指向 obj 对象
  return fn();
 }
};
obj.getAge(); // 25

 这就是箭头函数及其大致作用。


3.2 不能使用箭头函数的场景

返回目录


 什么时候不能使用箭头函数呢?

  1. 定义对象方法
  2. 定义原型方法
  3. 定义构造函数
  4. 定义事件回调函数

首先,在定义对象方法中,举例:

const calculator = {
 array: [1, 2, 3],
 sum: () => {
  console.log(this === window); // => true
  return this.array.reduce((result, item) => result + item);
 }
};

console.log(this === window); // => true

// Throws "TypeError: Cannot read property 'reduce' of undefined"
calculator.sum();

 如上,它会报错,因为 this 的指向不对,需要修改为:

const calculator = {
    array: [1, 2, 3],
    sum() {
        console.log(this === calculator); // => true
        return this.array.reduce((result, item) => result + item);
    }
};
calculator.sum(); // => 6


然后,在定义原型方法上,也需要注意不能滥用箭头函数:

function Cat(name) {
  this.name = name;
}

Cat.prototype.sayCatName = () => {
 console.log(this === window); // => true
 return this.name;
};

const cat = new Cat('Mew');
cat.sayCatName(); // => undefined

 这里需要修改为:

function Cat(name) {
    this.name = name;
}

Cat.prototype.sayCatName = function () {
  console.log(this === cat); // => true
  return this.name;
};

const cat = new Cat('Mew');
cat.sayCatName(); // => 'Mew'


接着,在定义事件回调函数时,也需要注意 this 的指向:

const button = document.getElementById('myButton');
button.addEventListener('click', () => {
 console.log(this === window); // => true
 this.innerHTML = 'Clicked button';
});

 修正为:

const button = document.getElementById('myButton');
button.addEventListener('click', function() {
  console.log(this === button); // => true
  this.innerHTML = 'Clicked button';
});


 最后,在定义构造函数上:

const Message = (text) => {
  this.text = text;
};
// Throws "TypeError: Message is not a constructor"
const helloMessage = new Message('Hello World!');

 修正为:

const Message = function(text) {
  this.text = text;
};
const helloMessage = new Message('Hello World!');
console.log(helloMessage.text); // => 'Hello World!'

 综合 3.1 与 3.2 的内容,我们可以清晰明白,虽然使用箭头函数,能够精简代码,并在一定程度上有所帮助。
 但是,我们不能因为追求简洁的代码,而提升我们的代码维护难度和造成多种 bug。
 量力而行才是最好的。


3.3 构造函数和原型对象

返回目录



四 总结

返回目录



知识共享许可协议
jsliang 的文档库梁峻荣 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
基于https://github.om/LiangJunrong/document-library上的作品创作。
本许可协议授权之外的使用权限可以从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处获得。

Copyright © jsliang.top 2019 all right reserved,powered by Gitbook该文件修订时间: 2019-05-18 20:07:38

results matching ""

    No results matching ""