• 02 重学js-原型链,this指向及改变this指向


     一.原型链

     

     构造函数原型prototype,每一个构造函数都有一个原型对象,我们可以把那些不变的方法 直接定义再prototype对象上,这样所有的实例就可以共享这些方法

        1.原型是什么:是一个对象,prototype对象  2.原型的作用是:共享方法,公共属性定义到构造函数里,公共的方法定义到原型对象上节约内存

     1.1 prototype原型对象(显示原型)和__proto__对象原型(隐式原型)

     

    1. function Star(name) {
    2. this.name = name
    3. }
    4. Star.prototype.sing = function () { //一般情况,我们的公共属性定义到构造函数里,公共的方法定义到原型对象上节约内存
    5. console.log('唱歌');
    6. }
    7. let ldh = new Star('刘德华')
    8. ldh.sing()
    9. let zxy = new Star('张学友')
    10. zxy.sing()
    11. console.dir(Star)// 有prototype
    12. console.log(ldh.sing === zxy.sing) // true
    13. // 为什么ldh实例能调用Star构造函数中的sing方法 因为ldh这个对象上有一个隐式原型__proto__指向的是我们的构造函数
    14. console.dir(ldh); // 对象身上系统自动添加了__proto__指向的是我们的构造函数的prototype
    15. console.log(ldh.__proto__ === Star.prototype) // true ,方法的查找如果lad对象上有sing就执行,如果ldh没有sing就去构造函数的prototype上查找,因为__proto__指向prototype

     1.2 constructor 主要是记录对象引用的那个构造函数,这个对象是那个构造函数创建出来的,指回了构造函数

    1. console.log(ldh.__proto__) // 有constructor这个属性
    2. console.log(Star.prototype) // 有constructor这个属性
    3. console.log(ldh.__proto__.constructor) //指向的是Star
    4. console.log(Star.prototype.constructor) //指向的是Star
    5. // 很多情况下我们要手动修改constructor的指向,比如我们要定义多个方法sing movie
    6. Star.prototype = {
    7. constructor: Star, // 手动指向
    8. sing: function () {
    9. console.log('唱歌');
    10. },
    11. movie: function () {
    12. console.log('电影');
    13. }
    14. }
    15. console.log(Star.prototype.constructor) *// 指向的是Object,因为赋值的是一个对象导致constructor对覆盖了,故需要手动指向

     二.this指向,this原则是执行的时候决定的,一般都是指向调用者

     2.1 不同情况的this执向

    1.原型对象中的this指向实例对象

    1. function Star(name) {
    2. this.name = name
    3. }
    4. var that
    5. Star.prototype.sing = function () {
    6. console.log('唱歌');
    7. that = this
    8. }
    9. let ldh = new Star('刘德华')
    10. ldh.sing()
    11. console.log(that === ldh)

     2.函数中this指向

    1. function run() {
    2. console.log(this);
    3. }
    4. window.run() // 完整的写法是这样的,window是调用者,普通函数this指向window
    5. var o = {
    6. say() {
    7. console.log(this);
    8. }
    9. }
    10. o.say() //对象方法this 指向的是o这个对象,因为是o调用的
    11. function Start() {
    12. start.prototype.eat = function(){}
    13. }
    14. var ldh = new Start() // 构造函数的this 指向实例对象ldh ,原型对象里面的this 也指向ldh这个实例对象
    15. btn.onclik = function(){
    16. console.log(this);
    17. } // 绑定事件的函数的this 指向btn这个实例
    18. window.setTimeout(()=>{},1000) // this指向window
    19. (function(){console.log(1);})() // 立即执行函数 this指向window

    2.2  call apply bind改变this指向

    1.call()

    call(thisArg,arg1,arg2,...), call 呼叫的意思很直接

    fun.call(thisArg,arg1,arg2,...) //第一个参数是把this指向谁,后面的是其他类型参数

    call的作用 1是调用函数 2是改变this指向

    call主要作用是实现继承 在es5的时候

    1. function run(a,b) {
    2. console.log(this);
    3. console.log(a+b);
    4. }
    5. var o = {
    6. name: 'zhangsan'
    7. }
    8. // run.call() // 这样也能调用函数,没有修改this指向
    9. // run.call(o) // 改变this指向为o
    10. run.call(o,1,2) // 3
    11. function Father(name, age) {
    12. this.name = name,
    13. this.age = age
    14. }
    15. function Son(name, age) {
    16. Father.call(this,name,age) //修改this指向为Son
    17. }
    18. var son = new Son('ldh',18)
    19. console.log(son); // Son {name: "ldh", age: 18}

     2.apply()

    apply(thisArg,[argsArg]),apply字面意思是应用 ,也是很直接的

    fun.apply(thisArg,[argsArg]) //第一个参数是把this指向谁,后面必须写成数组

    apply的作用 1是调用函数 2是改变this指向

    apply主要作用是跟数组 对数组求最大值,数组本身没有求最大值得方法,但是Math有,我们通过apply改变下指向为apply

    1. function run() {
    2. console.log(this);
    3. console.log(arguments); // 12 'pink',如果数组中传入的是number,输出的也是数字型,如果传入的是str那么输出的也会是字符串
    4. }
    5. var o = {
    6. name: 'zhangsan'
    7. }
    8. // run.apply() // 也能调用函数
    9. // run.apply(o) //改变this指向为o
    10. run.apply(o,[12,'pink'])
    11. var arr = [1,543,47,8,686,3]
    12. var max = Math.max.apply(Math,arr) // 改变this指向为Math ,然后第二个参数需传入数组
    13. console.log(max);

    3.bind() 是重点掌握的!!!!

    bind(thisArg,arg1,arg2,...), bind字面意思是绑定 捆绑的意思

    fun.bind(thisArg,arg1,arg2,...) //第一个参数是把this指向谁,后面其他参数类型

    bind的作用 1不会不会不会调用函数 2 是改变this指向 3,会返回一个新的函数

    主要作用是 不需要立即执行的时候我们就需要想到bind这是我们最常用的方式 如一个按钮点击的时候就禁用,三秒之后才会启动

    1. function run (a,b) {
    2. console.log(this);
    3. console.log(a + b);
    4. }
    5. let p = {
    6. name: 'zhangsan'
    7. }
    8. let f = run.bind(p) // 只是改变this指向,不会调用函数
    9. f() //会返回一个新的函数,并以这样的形式调用函数
    10. let f2 = run.bind(p,1,2)
    11. f2()
    12. // 经典
    13. <button>点击</button>
    14. <button class="btn">点击1</button>
    15. <button class="btn">点击2</button>
    16. <button class="btn">点击3</button>
    17. var btn = document.querySelector('button')
    18. btn.onclick = function() {
    19. this.disabled = true // 点击后禁用
    20. // setTimeout(()=>{ // 操 这里是箭头函数无this指向,指向的是上级的this ,上级就是btn实例
    21. // // btn.disabled = false
    22. // this.disabled = false
    23. // },2000)
    24. setTimeout(function(){
    25. // btn.disabled = false // 这样有很多弊端,一旦按钮多一百个之后 ,显然这样写不科学
    26. // this.disabled = false // 此时这里的this,是指向的是window ,启用无效
    27. this.disabled = false
    28. }.bind(this),2000) // 我们需要的是不立即执行,但是需要改变的是this指向,故采用bind,我们这里的bind是写在定时器函数的外部,在btn函数内部,故bind(this)这里的this 指的是当前点击的按钮实例
    29. }
    30. // 点击多个按钮,实现禁用启用
    31. var btn1 = document.querySelectorAll('.btn')
    32. var len = btn1.length // 类似做过dom查询做缓存
    33. for(let i = 0;i<len;i++) {
    34. btn1[i].onclick = function() {
    35. this.disabled = true
    36. setTimeout(function(){
    37. this.disabled = false
    38. }.bind(this),2000)
    39. }
    40. }

     

  • 相关阅读:
    Spring Thymeleaf模版注入分析
    html和css(1)
    提升用户体验的利器:揭秘Spring框架中国际化的奇妙魔力
    Unity 高级程序员应该具备怎样的能力?要怎样成长为 Unity 高级程序员?
    【AcWing】828. 模拟栈
    牛客网:NC41 最长无重复子数组
    redis持久化和Redis事务
    Java 入门-02-人机交互-图形化界面的小故事
    idea build cannot find symbol
    没用的知识增加了,尝试用文心实现褒义词贬义词快速分类
  • 原文地址:https://blog.csdn.net/qq_37550440/article/details/125479039