万字长文深度剖析面向对象的javascript(二)

简介: 万字长文深度剖析面向对象的javascript(二)

this对象


this总是返回一个对象,简单说,就是返回属性或方法“当前”所在的对象。


var book = {
    name :'flydean',
    getName : function (){
        return '书名:'+ this.name;
    }
}
console.log(book.getName());
//书名:flydean


这里this的指向是可变的,我们看一个例子 :


var book = {
    name :'flydean',
    getName : function (){
        return '书名:'+ this.name;
    }
}
var car ={
    name :'car'
}
car.getName = book.getName;
console.log(car.getName());
//书名:car


当 A 对象的方法被赋予 B 对象,该方法中的this就从指向 A 对象变成了指向 B 对象

上面的例子中,我们把book中的getName方法赋值给了car对象,this对象现在就指向了car。


如果某个方法位于多层对象的内部,这时this只是指向当前一层的对象,而不会继承更上面的层。


var book1 = {
    name :'flydean',
    book2: {
        getName : function (){
            return '书名:'+ this.name;
        }
    }
}
console.log(book1.book2.getName());
//书名:undefined


上面的例子中,this是定义在对象中的函数中,如果是在函数中的函数中定义的this,代表什么呢?


var book3 = {
    name :'flydean',
    book4: function(){
        console.log('book4');
        var getName = function (){
            console.log(this); //Window
        }();
    }
}
book3.book4();


如果在函数中的函数中使用了this,那么内层的this指向的是全局的window对象。


所以我们在使用的过程中要避免多层 this。由于this的指向是不确定的,所以切勿在函数中包含多层的this。


如果在全局环境使用this,它指的就是顶层对象window。


数组的map和foreach方法,允许提供一个函数作为参数。这个函数内部不应该使用this。


var book5 ={
    name : 'flydean',
    author : ['max','jacken'],
    f: function (){
        this.author.forEach(function (item) {
            console.log(this.name+' '+item);
        })
    }
}
book5.f();
//undefined max
//undefined jacken


foreach方法的回调函数中的this,其实是指向window对象,因此取不到o.v的值。原因跟上一段的多层this是一样的,就是内层的this不指向外部,而指向顶层对象。


怎么解决呢?我们使用一个中间变量:


var book6 ={
    name : 'flydean',
    author : ['max','jacken'],
    f: function (){
        var that = this;
        this.author.forEach(function (item) {
            console.log(that.name+' '+item);
        })
    }
}
book6.f();
//flydean max
//flydean jacken


或者将this当作foreach方法的第二个参数,固定它的运行环境:


var book7 ={
    name : 'flydean',
    author : ['max','jacken'],
    f: function (){
        this.author.forEach(function (item) {
            console.log(this.name+' '+item);
        },this)
    }
}
book7.f();
//flydean max
//flydean jacken


绑定this的方法


JavaScript提供了call、apply、bind这三个方法,来切换/固定this的指向.


call


函数实例的call方法,可以指定函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数.


var book = {};
var f = function () {
    return this;
}
f()  === this ; //true
f.call(book) === book; //true


上面例子中,如果直接调用f(),那么返回的就是全局的window对象。如果传入book对象,那么返回的就是book对象。


call方法的参数,应该是一个对象。如果参数为空、null和undefined,则默认传入全局对象。


如果call方法的参数是一个原始值,那么这个原始值会自动转成对应的包装对象,然后传入call方法。


var f = function () {
    return this;
}
console.log(f.call(100));
//[Number: 100]


call方法还可以接受多个参数.


func.call(thisValue,arg1,arg2, ...);


call的第一个参数就是this所要指向的那个对象,后面的参数则是函数调用时所需的参数。


call一般用在调用对象的原始方法:


var person =  {};
person.hasOwnProperty('getName');//false
//覆盖person的getName方法
person.getName  = function(){
    return true;
}
person.hasOwnProperty('getName');//true
Object.prototype.hasOwnProperty.call(person,'getName');//false


apply


apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数.


func.apply(thisValue,[arg1,arg2,...])

bind


call和apply是改变this的指向,然后调用该函数,而bind方法用于将函数体内的this绑定到某个对象,然后返回一个新函数.


var d = new Date();
console.log(d.getTime()); //1600755862787
var getTime= d.getTime;
console.log(getTime());//TypeError: this is not a Date object.


上面的例子中,getTime方法里面调用了this,如果直接把d.getTime赋值给getTime变量,那么this将会指向全局的window对象,导致运行错误。


我们可以这样修改:


var d = new Date();
console.log(d.getTime()); //1600755862787
var getTime2= d.getTime.bind(d);
console.log(getTime2());


bind比call方法和apply方法更进一步的是,除了绑定this以外,还可以绑定原函数的参数。


var add = function(x,y){
    return x +this.m +  y + this.n;
}
var addObj ={
    m: 10,
    n: 10
}
var newAdd = add.bind(addObj,2);
console.log(newAdd(3));//25


上面的例子中,bind将两个参数的add方法,替换成了1个参数的add方法。


注意,bind每次调用都会返回一个新的函数,从而导致无法取消之前的绑定。

相关文章
|
JavaScript 前端开发 Java
深入JS面向对象(原型-继承)(三)
深入JS面向对象(原型-继承)
90 0
|
JavaScript 前端开发 Java
深入JS面向对象(原型-继承)(一)
深入JS面向对象(原型-继承)
120 0
|
设计模式 JavaScript 前端开发
【JavaScript】深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略
JavaScript的继承机制基于原型链,它定义了对象属性和方法的查找规则。每个对象都有一个原型,通过原型链,对象能访问到构造函数原型上的方法。例如`Animal.prototype`上的`speak`方法可被`Animal`实例访问。原型链的尽头是`Object.prototype`,其`[[Prototype]]`为`null`。继承方式包括原型链继承(通过`Object.create`)、构造函数继承(使用`call`或`apply`)和组合继承(结合两者)。ES6的`class`语法是语法糖,但底层仍基于原型。继承选择应根据需求,理解原型链原理对JavaScript面向对象编程至关重要
278 7
【JavaScript】深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略
|
开发框架 JavaScript 前端开发
JavaScript框架比较与选择:技术深度剖析
【7月更文挑战第23天】选择正确的JavaScript框架是项目成功的关键。React.js、Vue.js、Angular和Svelte等前端框架各有千秋,分别适用于不同的项目需求。同时,Node.js及其后端框架为服务器端开发提供了强大的支持。开发人员应根据项目的复杂性、性能要求、开发周期以及团队技能等因素综合考虑,选择最适合的框架。随着技术的不断发展,未来还将涌现更多优秀的JavaScript框架,为开发者带来更多选择和可能性。
|
前端开发 JavaScript
前端 JS 经典:Class 面向对象
前端 JS 经典:Class 面向对象
83 1
|
存储 JavaScript 前端开发
深度剖析JavaScript中的变量世界:概念、用例与避坑指南
【4月更文挑战第3天】探索JavaScript变量:了解var、let、const的差异,掌握数据类型、用例及避免错误的策略。声明变量时注意作用域和可变性,如var的函数作用域,let和const的块级作用域。理解基本数据类型(Number、String等)和对象类型。示例包括用户输入、计算、控制流程和函数参数。警惕未声明、作用域混淆、类型不匹配和未初始化的错误,遵循最佳实践,如明确命名、避免冗余和适时复用,利用类型检查工具提升代码质量。
338 1
|
JavaScript 前端开发
JavaScript 原型链继承:掌握面向对象的基础
JavaScript 原型链继承:掌握面向对象的基础
|
JavaScript 前端开发 API
在Node.js上使用dojo库进行面向对象web应用开发
请注意,虽然这个例子在Node.js环境中使用了Dojo,但Dojo的许多功能(例如DOM操作和AJAX请求)在Node.js环境中可能无法正常工作。因此,如果你打算在Node.js环境中使用Dojo,你可能需要查找一些适用于服务器端JavaScript的替代方案。
124 0
|
JSON JavaScript 前端开发
深入JS面向对象(原型-继承)(四)
深入JS面向对象(原型-继承)
98 0
|
设计模式 JavaScript 前端开发
深入JS面向对象(原型-继承)(二)
深入JS面向对象(原型-继承)
108 0