ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

原型拓展方法+继承

2021-09-29 21:35:31  阅读:108  来源: 互联网

标签:function console log 继承 拓展 原型 prototype


原型拓展方法+继承

扩展原型上的方法

数组indexOf的扩展

// console.log(Array.prototype.indexOf);
// 在标准浏览器返回函数,在IE8及下返回undefined

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (val, index) {
        index = typeof index === 'undefined' ? 0 : index;
        for (var i = index; i < this.length; i++) {
            if (this[i] === val) {
                return i;
            }
        }
        return -1;
    }
}

var arr = [3, 4, 2, 3, 3, 4];
console.log(arr.indexOf(3)); // 0
console.log(arr.indexOf(3, 1)); // 3

字符串trim的扩展

// 字符串的trim

// 在标准浏览器下返回函数,在IE8及以下返回undefined
// console.log(String.prototype.trim);

// 扩展IE8及以下原型上的trim

if (!String.prototype.trim) {
    String.prototype.trim = function () {
        var re = /^\s+|\s+$/g;
        return this.replace(re, '');
    }
}
var str = '    平头哥   ';
console.log('(' + str.trim() + ')');

call与apply与bind

  • 函数.call(新的this指向, 参数1, 参数2, …)
  • 函数.apply(新的this指向, [参数1, 参数2, …])
  • 函数.bind(新的this指向, 参数1, 参数2, …)

作用:call与apply都是调用函数,而bind不会调用函数,都修改函数中的this的指向。

区别:call与bind的后续参数是以一个参数列表传入,而apply的后续参数是以一个数组传入

共同点:修改函数中的this,第一个参数都是新的this指向,都有返回值,call与apply返回值就是函数返回值,而bind返回值为由指定的 this 值和初始化参数改造的原函数拷贝,因为bind不会调用函数。

function fn(a, b) {
    console.log(this);
    console.log(a, b);
}

fn(3, 5);
fn.call(document, 5, 6);
fn.apply(document, [7, 8]);

var f = fn.bind(document,5,6);
f();

// --------------------------------
// 如果第一个参数是null 和 undefined,则this指向window
fn.call(undefined, 5, 6);
// 找出数组的最大值
var arr = [4, 6, 2, 6, 5, 8, 4, 7, 3];
// Math.max(4, 6, 2, 6, 5, 8, 4, 7, 3)
console.log(Math.max.apply(Math, arr));

继承

原型链继承

  • 原型链继承:将父的实例赋给子的原型

  • 如何用一句话实现继承:将父的实例赋给子的原型。

  • 不足:

    1、如果父级中有引用类型,创建的子级会一改全改

    2、constructor本来应该指向自己的构造函数,但是却指向了父级的构造函数

// 父类(学生类)
function Student() {
    this.job = '学生';
    this.ah = ['打游戏', '睡觉', '找平头妹'];
}
Student.prototype.showJob = function () {
    console.log(this.job);
}

// ----------------------------------------
// 子类(小学生)
function SmallStudent(name) {
    this.name = name; // 子自己添加的
}
SmallStudent.prototype = new Student(); // 继承了父的属性和方法

// 原型链继承:将父的实例赋给子的原型
// 如何用一句话实现继承:原型链继承
// 不足:
// 1、如果父级中有引用类型,创建的子级会一改全改属性
// 2、constructor本来应该指向自己的构造函数,但是却指向了父级的构造函数
//解决问题1、手动改变constructor指向
SmallStrudent.prototype.construcor = SmallStrudent;


// -------------------------------------
var s1 = new SmallStudent('zs');
console.log(s1);
console.log(s1.name);
console.log(s1.job);
console.log(s1.ah);
s1.showJob();
console.log(s1.constructor); // Student,本来应该指向SmallStudent

s1.ah.push('画画'); // 修改s1的爱好,后面创建的s2也会改变

var s2 = new SmallStudent('ls');
console.log(s2);
console.log(s2.ah); // ["打游戏", "睡觉", "找平头妹", "画画"]

在这里插入图片描述

对象冒充(call)继承

  • 对象冒充继承:在子的构造函数中,调用父类的构造函数,并用call改this指向
  • 不足:不能继承原型上的方法。
// 父类(学生类)
function Student() {
    this.job = '学生';
    this.ah = ['打游戏', '睡觉', '找平头妹'];
}
Student.prototype.showJob = function () {
    console.log(this.job);
}

// ----------------------------------------
// 子类(小学生)
function SmallStudent(name) {
    Student.call(this); // 继承了父类构造函数中的属性
    this.name = name; // 加上我自己的属性
}

// 对象冒充继承:在子类的构造函数中,调父类的构造函数,并用call改this指向
// 好处:解决了原型链继承引用类型一改全改属性的问题
// 问题:只是继承了父类的属性,而没有继承父类原型上的方法

// -----------------------------------
var s1 = new SmallStudent('zs');
s1.ah.push('画画');
console.log(s1);


var s2 = new SmallStudent('ls');
console.log(s2);

在这里插入图片描述

组合继承(已能实现但浪费性能)

  • 组合继承:对象冒充+原型链
  • 对象冒充继承属性
  • 原型链继承方法
// 父类(学生类)
function Student() {
    this.job = '学生';
    this.ah = ['打游戏', '睡觉', '找平头妹'];
}
Student.prototype.showJob = function () {
    console.log(this.job);
}

// ----------------------------------------
// 子类(小学生)
function SmallStudent(name) {
    Student.call(this); // 对象冒充继承
    this.name = name;
}
SmallStudent.prototype = new Student(); // 原型链继承


// 组合继承:原型链继承 + 对象冒充继承
// 问题
// 1、constructor指向不对
// 2、同名的属性会在原型链中出现两次
// 3、父的构造函数会被调用两次


//解决问题1、手动改变constructor指向
SmallStrudent.prototype.construcor = SmallStrudent;

// -------------------------------------------
var s1 = new SmallStudent('zs');
console.log(s1);

在这里插入图片描述

原型链继承图
在这里插入图片描述

寄生组合继承 (继承的标准模式)

// 父类(学生类)
function Student() {
    this.job = '学生';
    this.ah = ['打游戏', '睡觉', '找平头妹'];
}
Student.prototype.showJob = function () {
    console.log(this.job);
}

// ----------------------------------------
// 子类(小学生)
function SmallStudent(name) {
    Student.call(this); // 继承父的属性
    this.name = name; // 添加子类自己的属性(写在继承的后面)
}

// 继承父的原型上的方法
inherits(SmallStudent, Student);

// 添加自己原型上的方法,一定要写在继承的后面
SmallStudent.prototype.showName = function () {
    console.log(this.name);
}

// 寄生组合式继承(继承的标准模式)
// 父的属性和方法要分开继承

// -----------------------------------------
var s1 = new SmallStudent('zs');
console.log(s1);
// console.log(s1.constructor);


// ------------------------------------------
// 寄生组合继承父类原型上方法的封装,原型链继承升级
function inherits(Child, Parent) {
    var F = function () { };
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TqT3xLvi-1632922046848)(C:\Users\Administrator\Desktop\课堂笔记\第二阶段\笔记\image\对象冒充继承.jpg)]

原型链继承升级图

在这里插入图片描述

原型对象引用总结(地址问题)

  • 上图箭头指向谁即谁的地址被引用,如Fun实例.__proto__指向Fun原型,即Fun实例拿到Fun原型的地址。
  • Son.prototype = new Fun(); 表示Son.prototype拿到Fun实例对象的地址,这时采用赋值形式则Son.prototype改变内容则Fun里的内容也会改变,因为地址一样。
  • 而Fun实例.__proto__指向Fun原型,Fun实例拿到Fun原型的地址,则改变Fun实例不会改变Fun原型,因为他们之间用__proto__指向的。如改变Fun实例.__proto__则会改变Fun原型。同理:原型.constructor一样。
  • Fun.prototype = Farther.prototype; 表示

继承应用

判断所有数据类型

var obj = {};
console.log(obj);

//this指向实例对象obj。所以打印[object Object]。
console.log(obj.toString());

//本来直接调用this指向Object原型对象上。所以打印[object Object]。
console.log(Object.prototype.toString());

//改变toString的this指向。使this指向实例对象上。而这个实例对象就是数据类型是由不同构造函数构造的。打印[object 构造函数]。
console.log(Object.prototype.toString.call());

//例:1为Number构造函数的实例对象,所以打印[object Number]。
console.log(Object.prototype.toString.call(1));

面象对象注意事项

实例对象方法的引用方式


function Person() {
    this.uname = '学生';
    this.age = 1;
    this.fn2();//第二种方式。
}
Person.prototype.fn1 = function () {
    console.log(1);
}
Person.prototype.fn2 = function () {
    console.log(2);
}
Person.prototype.fn3 = function () {
    console.log(3);
}

var s1 = new Person();
s1.fn1();//第一种方式。

new.Person().fn3();//第三种方式。

this的指向问题

   this指向为谁调用指向谁,主要看在谁的作用域里。拥有这个作用域的函数被谁调用就指向谁。
- 谁调用了函数,this就指向谁
- this不是在定义的时候确定的,而是在调用的时候确定的

// 1、全局环境下的this: window
         console.log(this);

// 2、事件处理函数中的this:是触发这个事件的元素
         box.onclick = function () {
             console.log(this); // box
         }

        
// 3、定时器中的this: window
         setTimeout(function () {
             console.log(this);
         }, 1000);


// 4、函数直接执行中的this, 非严格模式是window,严格模式下是undefined
        //"use strict"; // 严格模式
         function fn() {
             console.log(this);
         }
        fn();

       
 // 5、call apply

// 6、对象方法内部调用
     var obj = {
      fn: function () {
          console.log(this);
           }
        };
       
      obj.fn(); // obj
        
      var v = obj.fn;
      v(); // window
     
// 7、构造函数中的this:new 出来的哪个对象(实例)
new将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象)。
     
// 8、原型链函数中的this,一般都指实例
因为只能由实例调用使用。   
        
// 9、所有的回调函数里面的this是 window
        move(box, {}, function () { })
这个回调函数是实参在全局作用域里。

法内部调用
var obj = {
fn: function () {
console.log(this);
}
};

  obj.fn(); // obj
    
  var v = obj.fn;
  v(); // window

// 7、构造函数中的this:new 出来的哪个对象(实例)
new将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象)。

// 8、原型链函数中的this,一般都指实例
因为只能由实例调用使用。

// 9、所有的回调函数里面的this是 window
move(box, {}, function () { })
这个回调函数是实参在全局作用域里。




标签:function,console,log,继承,拓展,原型,prototype
来源: https://blog.csdn.net/weiweiweb888/article/details/120556751

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有