前端(十四):原型、call、apply、this

简介: 原型、call、apply、this

原型

原型链相关

  • Person.prototype -- 原型
    Person.prototype.lastName = 'Lee';
    function Person(params) {
         
         
      this.lastName = "Zhang";
    }
    var person = new Person();
    console.log(person.lastName); // Zhang 就近原则
    
function Person(){
   
    this.name = 'Lee'}
function Car(){
   
    this.name = 'Car' }
var car = new Car()
console.log(car.constructor); // ƒ Car(){ this.name = 'Car' } 访问构造car的构造函数
car.constructor = Person; // 修改constructor构造函数
console.log(car.constructor); // ƒ Person(){ this.name = 'Lee'}

__proto__

Person.prototype.name = 'Lee';
function Person(){
   
   }
var person = new Person();
// 下面这种写法相当于创建了一个prototype对象,而实际的原型在 __proto__ 上,即 
// function Person(){ /* var this = {__proto__: Person.prototype */ }}
Person.prototype = {
   
    
    name: 'ProsperLee'
}
console.log(person.name); // Lee
// ===>
// Person.prototype = { name: 'Lee' }
// __proto__ = Person.prototype;
// Person.prototype = { name: 'ProsperLee' };
// Person.prototype.name = 'Lee';
function Person(){
   
   }
Person.prototype = {
   
    // 还没new就做了修改
    name: 'ProsperLee'
}
var person = new Person();
console.log(person.name); // ProsperLee
  • 绝大多数对象的原型链的终点:Object.prototype (Object.create(null)、undefined、null没有原型)
    console.log(Object.prototype); // {...} 原型对象
    console.log(Object.prototype.__proto__); // null
    

    toString重写

  • 系统在 Number、Boolean、String、Array、Function 的原型上重写了本应该在 Object 原型上的 toString 方法
    Object.prototype.toString
    Number.prototype.toString
    Boolean.prototype.toString
    String.prototype.toString
    Array.prototype.toString
    Function.prototype.toString // 函数的源码是什么就返回什么
    // 要访问原型上的toString而不是自身重写的同String方法
    // Object.prototype.toString.call(要访问的对象)
    

    改变this指向:

  • call(指向,传参,传参,···)
    A.call(B,x,y,z,···) 将A的方法植入到B中
  • apply(指向,[传参,传参,···])
    A.apply(B,[x,y,z,···]) 将A的方法植入到B中
    function Person(name,age){
         
         
      this.name = name;
      this.age = age;
    }
    var obj = {
         
         
      name: "Prosper"
    }
    Person.call(obj);
    // ==>
    // function Person(name,age){
         
         
    //     // var this = obj
    //     this.name = name;
    //     this.age = age;
    // }
    console.log(obj); // {name: undefined, age: undefined} 覆盖
    Person.call(obj,'Lee',23);
    console.log(obj); // {name: "Lee", age: 23}
    
  • 练习01:B所要实现的功能涵盖了A要实现的功能,但是B的功能比A的功能强大,B要怎么写
      // A:
      function A(name, age, sex) {
         
         
          this.name = name;
          this.age = age;
          this.sex = sex;
      }
      // B:
      // function B(name, age, sex, tel, grade) {
         
         
      //     this.name = name;
      //     this.age = age;
      //     this.sex = sex;
      //     this.tel = tel; 
      //     this.grade = grade;
      // }
    
  • 答案:
    function B(name, age, sex, tel, grade) {
         
         
      var that = this;
      console.log(that);
      A.call(that, name, age, sex);
      A.apply(that, [name, age, sex]);
      this.tel = tel; 
      this.grade = grade;
    }
    var b = new B('Lee', 23, '男', '182*******32', 'grade'); // new的时候就执行了一次了
    console.log(b); // B {name: "Lee", age: 23, sex: "男", tel: "182*******32", grade: "grade"}
    
  • 练习02:通过call和apply返回数组最大最小值
    var arr = [3, 6, 1, 66, 0, 98];
    // null 因为没有规定要放到哪个对象中,所以随便写
    var minCall = Math.min.call(null,arr[0],arr[1],arr[2],arr[3],arr[4],arr[5]);
    var maxCall = Math.max.call(null,arr[0],arr[1],arr[2],arr[3],arr[4],arr[5]);
    console.log(minCall,maxCall); // 0 98
    var minApply = Math.min.apply(null,arr);
    var maxApply = Math.max.apply(null,arr);
    console.log(minApply,maxApply); // 0 98
    console.log(Math.min(arr[0],arr[1],arr[2],arr[3],arr[4],arr[5]));
    console.log(Math.max(arr[0],arr[1],arr[2],arr[3],arr[4],arr[5]));
    
  • 练习03: test() 和 new test() 结果
    var a = 5;
    function test(){
         
         
      a = 0;
      console.log(a);
      console.log(this);
      console.log(this.a);
      var a;
      console.log(a);
    }
    test(); // 0 window 5 0  --> 没人调用,this指向window
    new test(); // 0 test{} undefined 0  --> 自己调用的,this指向自己的构造成的对象,相当于在函数内 var this = Object.create(test.prototype)
    

    继承发展史

  • 1.传统形式 --> 原型链

    过多的继承了没用的属性

  • 2.构造函数法

    不能继承借用构造函数的原型
    每次构造函数都要多走一个函数

  • 3.共享原型

    不能随便改动自己的原型

  • 4.圣杯模式
    // 3.共享原型
    Father.prototype.lastName = 'Lee';
    function Father(){
         
         }
    function Son(){
         
         }
    function inherit(Target, Origin){
         
         
      Target.prototype = Origin.prototype;
    }
    inherit(Son,Father)
    var son = new Son();
    var father = new Father();
    console.log(son.lastName, father.lastName); // Lee Lee
    // Father.prototype为Father和Son的共享原型,(不足:当Son.prototype.xxx改变Father.prototype.xxx跟着变动)
    // +++++++++++++++++++++++++++++
    // 4.圣杯模式
    Father.prototype.lastName = 'Lee';
    function Father(){
         
         }
    function Son(){
         
         }
    function inherit(Target, Origin){
         
         
      function S(){
         
         }; // 中介
      S.prototype = Origin.prototype; // Origin.prototype为Origin和S的共享原型
      Target.prototype = new S(); // 将S的构造函数赋值给Target.prototype
      Target.prototype.constuctor = Target; // Target继承Origin,Target构造方法归位
      Target.prototype.uber = Origin.prototype; // uber为Target的超类(超级父级)
    }
    inherit(Son,Father);
    var son = new Son();
    var father = new Father();
    console.log(son.lastName, father.lastName); // Lee Lee
    Son.prototype.age = 18;
    console.log(son.age, father.age); // 18 undefined
    // ==> 圣杯模式变式 ==>
    // var inherit = (function (){
         
         
    //     var S = function (){}; // 中介
    //     return function(Target, Origin){
         
         
    //         S.prototype = Origin.prototype; // Origin.prototype为Origin和S的共享原型
    //         Target.prototype = new S(); // 将S的构造函数赋值给Target.prototype
    //         Target.prototype.constuctor = Target; // Target继承Origin,Target构造方法归位
    //         Target.prototype.uber = Origin.prototype; // uber为Target的超类(超级父级)
    //     }
    // }())
    

    连续.fun()

    var obj = {
         
         
      a: function (){
         
          console.log(arguments.callee.name); return this; },
      b: function (){
         
          console.log(arguments.callee.name); return this; },
      c: function (){
         
          console.log(arguments.callee.name); return this; }
    }
    obj.a().b().c()
    
    var obj = {
         
         
      name: 'ProsperLee',
      age: 23,
      __proto__:{
         
         
          lastName: 'Lee',
          name: 'PL'
      }
    }
    for(var key in obj){
         
         
      if(obj.hasOwnProperty(key)){
         
          // 检测key是不是obj自己的属性
          console.log(obj[key]); // ProsperLee 23
      }
      console.log(obj[key]); // 结果 ProsperLee 23 Lee 将__proto__里的内容当成了自己的属性
    }
    // 检测 key 是否存在在 obj 中: key in obj (key为字符串)
    console.log('lastName' in obj); // true
    console.log('abc' in obj); // false
    
    // A instanceof B --> A对象的原型链上有没有B的原型
    console.log({
         
         } instanceof Object); // true
    console.log([] instanceof Object); // true
    Object.prototype.toString.call({
         
         }) // [object Object]
    
    function foo() {
         
          bar.apply(null, arguments) }
    function bar(x) {
         
          console.log(arguments); }
    foo(1, 2, 3, 4, 5) // [1, 2, 3, 4, 5]
    

    this

  • 1.函数预编译过程 this --> window
  • 2.全局作用域里 this --> window
  • 3.call/apply 可以改变函数运行时 this 的指向
  • 4.obj.func(); func() 里面的 this --> obj

    练习

    // 练习01:
    var name = 1;
    var a = {
         
         
      name: 2,
      say: function(){
         
         
          console.log(this.name);
      }
    }
    var fun = a.say;
    fun(); // 1
    a.say(); // 2 
    var b = {
         
         
      name: 3,
      say: function(fun){
         
         
          fun();
      }
    }
    b.say(a.say); // 1
    // var b = {
         
         
    //     name: 3,
    //     say: function(fun){
         
         
    //         // this --> b
    //         fun();
    //     }
    // }
    // 相当于把 a.say 的方法拿到外边来了
    // function fun(){
         
         
    //     console.log(this.name);
    // }
    // var b = {
         
         
    //     name: 3,
    //     say: function(){
         
         
    //         // this --> b
    //         fun()
    //     }
    // }
    // 没人调用 fun() ,故 fun 中 this 指向全局
    b.say = a.say;
    b.say(); // 3
    

arguments.callee

function test(){
   
   
    console.log(arguments.callee); // function test(){
   
   /* CODE */}
}
// function.caller
function funA(){
   
   
    funB();
}
function funB(){
   
   
    console.log(funB.caller); // function funA(){ funB(); }
}
funA();
var bar = {
   
   a: '002'};
function print(){
   
   
    bar.a = 'a';
    Object.prototype.b = 'b';
    return function inner(){
   
   
        console.log(bar.a);
        console.log(bar.b);
    }
}
print()(); // 'a' 'b'
目录
相关文章
|
前端开发 JavaScript
前端基础 - JavaScript之this关键字
前端基础 - JavaScript之this关键字
43 0
|
3月前
|
前端开发 JavaScript 开发者
揭秘JavaScript魔法三剑客:call、apply、bind,解锁函数新世界,你的前端之路因它们而精彩!
【8月更文挑战第23天】在 JavaScript 的世界里,`call`、`apply` 和 `bind` 这三个方法常常让新手感到困惑。它们都能改变函数执行时的上下文(即 `this` 的指向),但各有特点:`call` 接受一系列参数并直接调用函数;`apply` 则接收一个参数数组,在处理不确定数量的参数时特别有用;而 `bind` 不会立即执行函数,而是创建一个新版本的函数,其 `this` 上下文已被永久绑定。理解这三个方法能帮助开发者更好地运用函数式编程技巧,提升代码灵活性和可维护性。
37 0
|
2月前
|
前端开发 JavaScript C++
详解链表在前端的应用,顺便再弄懂原型和原型链!
该文章深入解析了链表在前端开发中的应用,并详细阐述了JavaScript中的原型和原型链的概念及其工作原理。
|
3月前
|
前端开发 JavaScript
前端必修之一 彻底理解原型和原型链
【8月更文挑战第2天】理解原型和原型链
71 11
|
6月前
|
前端开发 JavaScript
前端 js 经典:原型对象和原型链
前端 js 经典:原型对象和原型链
42 1
|
6月前
|
前端开发 JavaScript
【Web 前端】 js中call、apply、bind有什么区别?
【4月更文挑战第22天】【Web 前端】 js中call、apply、bind有什么区别?
【Web 前端】 js中call、apply、bind有什么区别?
|
6月前
|
JavaScript 前端开发
前端 JS 经典:原型和原型链
前端 JS 经典:原型和原型链
45 0
|
6月前
|
前端开发 JavaScript
【前端面试】this的指向_不爱吃糖的程序媛夏天,web前端面试项目中的问题包括
【前端面试】this的指向_不爱吃糖的程序媛夏天,web前端面试项目中的问题包括
|
6月前
|
前端开发 JavaScript
前端 JS 经典:apply、call、bind
前端 JS 经典:apply、call、bind
94 0
|
6月前
|
前端开发 JavaScript
【Web 前端】说一下this指向?
【4月更文挑战第22天】【Web 前端】说一下this指向?