01-JavaScript 高级进阶 第二天

1.今日目标

  1. 原型
  2. 函数定义的三种方式 了解
  3. 函数的原型链
  4. 函数和对象的原型链关系
  5. 函数的4种调用方式

2.定义函数的三种方式

  1. 函数声明
  2. 函数表达式
  3. 构造函数Function

函数声明

常规的方式

  1. fn();//函数声明可以先调用,在声明
  2. function fn(参数..){
  3. console.log("这是函数声明")
  4. return 返回值
  5. }

函数表达式

  1. const fn = function() {
  2. console.log("这是函数表达式");
  3. }
  4. fn();//函数表达式必须先声明,再调用

构造函数Function

函数也可以看成对象

  1. var fn1 = new Function("a1", "a2", "alert(a1+a2)");
  2. fn1(1,2);

3.原型 prototype -重难点

原型上存放函数

  1. 解决了同一个 say 浪费 内存的问题
  2. 解决了污染全局变量的问题
  1. function createStudent(name, age) {
  2. this.name = name;
  3. this.age = age;
  4. }
  5. // 将刚才的全局函数say 直接挂载到 构造函数的原型上 即可
  6. // prototype 是个对象 每一个构造函数都会内置有的. 我们称之为原型
  7. createStudent.prototype.say = function () {
  8. console.log(this.name);
  9. }
  10. const obj = new createStudent("悟能", 83);
  11. const obj1 = new createStudent("悟能1", 84);
  12. console.log(obj.say === obj1.say); // true

原型解释

  • 原型的单词是 prototype, 原型的这个名字是行业内共同认可的名字。
  • 原型本质是一个对象,理解为 JavaScript 自动帮我们添加的
  • 原型是 JavaScript 自动帮我们在定义构造函数的时候添加的
  • 所有构造函数的实例,共享一个原型
  • 原型上一般是挂载函数

图示

day02 - 图1

4.原型 proto

  1. 实例的 proto 属性 等于 构造函数的 prototype
    1. p1.__proto__ === Person.prototype // true
  1. 不过由于不同浏览器的兼容性问题,我们使用的时候,都只会使用 构造函数的prototype

  2. 实例的 proto 只是为了方便我们开发的时候查看数据,是不会手动修改和操作它的。

5.原型的关系

所有的构造函数都是Function的实例

Array 和 Person 和 Date 等都是 Function的实例

day02 - 图2

Function 和 Object的关系

有人说 JavaScript 是作者花了7天时间写出来的产物 - 不完美

  1. console.log(Object.prototype===Function.prototype.__proto__)

day02 - 图3

Object的顶端呢?

接近顶峰了

  1. console.log(Object.prototype.__proto__ === null);

day02 - 图4

最终的原型链

day02 - 图5

6.作用域

变量起作用的区域

  1. 存在全局变量和局部变量
  2. 全局变量可以在任意地方使用
  3. 而局部变量只能用在 它所在的花扩号的区域

思考

  1. let num = 0;
  2. switch (num) {
  3. case 1:
  4. let name = "小白"
  5. console.log(name);
  6. break;
  7. case 2:
  8. let name = "小黑"
  9. console.log(name);
  10. break;
  11. default:
  12. break;
  13. }

学习一下谷歌浏览器的调试使用

  1. debugger 和 谷歌浏览器的调试使用

day02 - 图6

7.this与函数的四种调用模式

根据函数内部this的指向不同,可以将函数的调用模式分成4种

  1. 函数调用模式
  2. 方法调用模式
  3. 构造函数调用模式
  4. 上下文调用模式(借用方法模式)

函数调用模式

如果一个函数不是一个对象的属性时,就是被当做一个函数来进行调用的。此时this指向了window

  1. function fn(){
  2. console.log(this);// 指向window
  3. }
  4. fn();

方法调用模式

当一个函数被保存为对象的一个属性时,我们称之为一个方法。当一个方法被调用时,this被绑定到当前对象

  1. const obj = {
  2. sayHi:function(){
  3. console.log(this);//在方法调用模式中,this指向调用当前方法的对象。
  4. }
  5. }
  6. obj.sayHi();

构造函数调用模式

如果函数是通过new关键字进行调用的,此时this被绑定到创建出来的新对象上。

  1. function Person(){
  2. console.log(this);
  3. }
  4. Person();//this指向什么?
  5. var p = new Person();//this指向什么?

方法借用模式

也叫上下文模式,分为 apply 与 call

call

call方法可以调用一个函数,并且可以指定这个函数的this指向

  1. const RichWumon = {
  2. name: "富婆",
  3. say: function () {
  4. console.log(this.name, " 我要重金求子");
  5. }
  6. }
  7. const obj = {
  8. name: "屌丝"
  9. }
  10. RichWumon.say(); // 富婆
  11. RichWumon.say.call(obj); // 屌丝

call应用

  1. 将伪数组转成数组
  1. let divs = document.querySelectorAll('div');
  2. // let divs = document.body.children;
  3. console.log(divs);
  4. function change(nodelist) {
  5. console.log(Object.prototype.toString.call(nodelist));
  6. return Array.prototype.slice.call(nodelist);
  7. }

apply

就是apply()方法接受的是一个包含多个参数的数组。而call()方法接受的是若干个参数的列表

可以利用apply 将 刚才的call 的代码修改一下

  1. const RichWumon = {
  2. name: "富婆",
  3. say: function () {
  4. console.log(this.name, " 我要重金求子");
  5. }
  6. }
  7. const obj = {
  8. name: "屌丝"
  9. }
  10. RichWumon.say(); // 富婆
  11. RichWumon.say.apply(obj); // 屌丝

apply应用

1.简化log方法

  1. // 简化log方法
  2. function log() {
  3. console.log.apply(console, arguments);
  4. }

bind方法

bind()方法创建一个新的函数, 可以绑定新的函数的this指向

  1. var name = '张三';
  2. function Fn(){
  3. this.age = 1;
  4. console.log(this.name + this.age);
  5. }
  6. Fn(); // 张三 1
  7. // 返回值:新的函数
  8. // 参数:新函数的this指向,当绑定了新函数的this指向后,无论使用何种调用模式,this都不会改变。
  9. let obj = {
  10. name:'小强',
  11. }
  12. const newFn = Fn.bind(obj);
  13. newFn(); // 小强 1

8.this的指向

  • 单独使用,this 指向全局对象
    1. console.log(this); // window
  • 函数中的 this 指向全局对象

    1. function show(){
    2. console.log(this); // window
    3. }
    4. show();
  • 在函数内部,this 的指向在函数定义的时候是不能确定的,只有函数执行的时候才能确定
    1. const a = 18;
    2. const obj = {
    3. a: 19,
    4. b: {
    5. a: 20,
    6. c: function () {
    7. console.log(this.a); // 20
    8. }
    9. }
    10. }
    11. obj.b.c();
  • 在方法中,this 指代该调用方法的对象
    1. const obj ={
    2. name:"小白",
    3. say:function(){
    4. console.log(this); // {name:"小白"}
    5. }
    6. }
  1. // 箭头函数自己没有this
  2. // 箭头函数的this是确定的,况且永远不变
  3. // 箭头函数中的this指向 创建这个箭头函数所在对象 的上下文
  4. let obj = {
  5. name: 'jack',
  6. say: function () {
  7. return () => {
  8. console.log(this) // obj
  9. }
  10. }
  11. }
  12. let fn = obj.say()
  13. fn() // obj {name: "jack", say: ƒ}
  14. let newobj = {}
  15. newobj.fun = fn
  16. newobj.fun() // obj {name: "jack", say: ƒ}
  17. let rose = {
  18. name: 'rose'
  19. }
  20. fn.call(rose) // obj {name: "jack", say: ƒ} 无法改变