资讯专栏INFORMATION COLUMN

JavaScript:万恶的this拿命来(二)

fox_soyoung / 687人阅读

摘要:构造函数对于被实例化的,我们称之为构造函数,及使用关键字调用的,对于它们来说,会被改变,指向实例。上栗子全局赋上属性通过关键字创建实例,改变函数内部指向注解通过这个栗子,我们可以看出,通过创建构造函数的实例,使得的指向改变,指向了实例本身。

用栗子说this
  

Bug年年有,今年特别多
对于JavaScript这么灵活的语言来说,少了this怎么活!

function 函数 this
对于没有实例化的function,我们称之为函数,即没有用new关键字调用的函数,对它们来说,this一律指代全局。

上栗子

var position = "outer";               

function test(){
    position = "inner";           
}

console.log(this.position);     // outer   
test();
console.log(this.position);     // inner

原因:内部未用var声明发生“变量提升”,污染全局变量。
构造函数 this
对于被实例化的function,我们称之为构造函数,及使用new关键字调用的function,对于它们来说,this会被改变,指向实例。

上栗子

var name = "person";               // 全局this赋上属性name

function Person(name){
    this.name = name;

    this.say = function () {
        console.log("My name is "+this.name);
    }

    this.show = function () {
        console.log(this);
    }
}


var william = new Person("william"); //通过new关键字创建实例,改变函数内部this指向

console.log(this.name);          //person

william.say();                   //My name is william

william.show();                  //Person {name: "william", say: ...


注解:通过这个栗子,我们可以看出,通过创建构造函数的实例,使得this的指向改变,指向了实例本身。
原型对象 this
每一个函数对象在创建的时候,都会自动添加一个prototype属性,这个prototype其实是一个指针,指向这个函数的原型对象。

你可以通过prototype指针给这个函数对象的原型对象添加属性,在实例化函数对象后,可以通过this来访问原型对象上的属性。

上栗子

function Person(){
    console.log(this.name);
}

Person.prototype.name = "william";    //给原型对象上赋name属性

var person = new Person();            // 通过this.name访问原型对象上的属性,打印 "william"

这还不够,咱们为函数对象直接添加同名,而不在原型对象上添加

function Person(){
    this.name = "Jack";
    console.log(this.name);
}

Person.prototype.name = "william";

var person = new Person();           // 打印 "Jack"

这里有一个值得注意的地方:

  

当你构造函数中存在和原型对象同名属性方法时,原型对象中的属性或方法会被隐藏,你只会访问到构造函数中的属性或方法`

Object.create this
通过Object.create创建函数对象实例,而不使用new关键字,也就是说它不会去调用构造函数

上栗子

function Person(name){    
    this.name = name;               
    this.showName = function () {
        console.log(this.name + " in constructor");
    }
} //在构造函数中的属性和方法,均同名

Person.prototype.name = "jack";
Person.prototype.showName = function () {
    console.log(this.name + " in prototype");
};
  //在原型对象中的属性和方法,均同名

var william  = new Person("william");
var jack = Object.create(Person.prototype);

william.showName();  // william in constructor

jack.showName();     // jack in prototype


注解:
 - 使用new关键字创造的实例调用了构造函数的属性和方法
 - 使用Object.create创造的实例调用了原型对象的属性和方法
原型链 this
原型链用于实现继承,当没有找到需要属性或方法时,会顺着原型链向上继续寻找。

上栗子

function Father(){
    this.name = "father";
}                              //可以看做"父类"
Father.prototype.showName = function () {
    console.log(this.name);
};

function Son(){
    this.name = "son";
}                              //可以看做"子类"
Son.prototype = new Father();  //这步是关键!

var mike = new Son();
mike.showName();               // son

注解:
 - 首先要强调的是JavaScript中没有"父类","子类","继承"这样的东西,我们只是通过原型链来实现这样的设计模式。

 - 通过这一步
     Son.prototype = new Father();
   我们将"子类"的prototype指针指向了"父类"函数对象
设计模式:继承
 为什么这样就能实现继承呢?

 首先要想明白为什么实例能访问构造函数的原型对象

 在JavaScript中,有一个内部的属性,在火狐,谷歌浏览器中,将这个内部属性暴露了出来,就是它 __proto__

上栗子(浏览器中)

mike.__proto__ // Father {name: "father", showName: function}    
Son.prototype  //Father {name: "father", showName: function}

mike.__proto__ === Son.prototype  // true

通过这个内部属性,我们可以访问到实例的构造函数的原型对象

再来一枚(浏览器中)

mike.__proto__.__proto__      //Father {showName: function}
Father.prototype              //Father {showName: function}

mike.__proto__.__proto__ === Father.prototype  // true

我们现在通过__proto__访问到了"父类"的原型对象!
继承得以实现!

补充一句:

我们可以访问到Son的name属性的值,却访问不到Father的name属性的值,是因为
 - mike是Son的实例(实例能做什么...?)
 - Father中的name没有对外开放,可以看做是私有属性
总结

主要探讨了
- function作为函数、构造函数、原型对象时,this的指代情况
- 扩展了另一种实例化方式Object.create
- 细说了原型链原理和实现,模拟了继承的设计模式

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91494.html

相关文章

  • JavaScript:万恶this命来(一)

    摘要:在脚本中,默认指向一个空对象,并不是指向,也不是指向。举个栗子,在函数执行后,覆盖原先的值我们在外部定义了一个名为的全局变量,它会被默认添加到全局的属性上。总结在不同的执行环境中的默认指代通过省略声明变量导致变量提升现象的发生及预防 侃侃JavaScript中的this this为何如此多变? this总是跟它的执行上下文有关,而在JavaScript总会有开辟新的执行上...

    loostudy 评论0 收藏0
  • JavaScript:万恶 this 命来(三)

    摘要:闭包执行上下文决定了变量作用域而闭包,它其实是一种决策,是一种模式,让我们可以灵活的改变变量作用域。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。只要咱们弄明白闭包,其中的自然跑不掉。 闭包 this 执行上下文决定了变量作用域 而闭包,它其实是一种决策,是一种模式,让我们可以灵活的改变变量作用域。 按惯例,上栗子 var global = glo...

    Cympros 评论0 收藏0
  • 设计模式之状态模式

    摘要:为了实现这个正义偷笑又合理的诉求,你得先学会今天要介绍的设计模式,因为你们公司的这个流程可能就是用今天这个模式设计的。状态模式对开闭原则的支持并不太好,新增状态时,不仅得增加状态类,还得修改原来已经有的状态,让之前的状态切换到新增的状态。一、定义你是否经常请(偷)假(懒)?是不是对公司万恶的请假申请流程深恶痛绝。有没有想过偷偷改造这个万恶的系统,从 申请->项目经理审批->部门审批->老板审...

    zhangke3016 评论0 收藏0
  • 不用 Spring Security 可否?试试这个小而美安全框架

    摘要:写在前面在一款应用的整个生命周期,我们都会谈及该应用的数据安全问题。用户的合法性与数据的可见性是数据安全中非常重要的一部分。 写在前面 在一款应用的整个生命周期,我们都会谈及该应用的数据安全问题。用户的合法性与数据的可见性是数据安全中非常重要的一部分。但是,一方面,不同的应用对于数据的合法性和可见性要求的维度与粒度都有所区别;另一方面,以当前微服务、多服务的架构方式,如何共享Sessi...

    toddmark 评论0 收藏0
  • 异步流程控制:7 行代码学会 co 模块

    摘要:而在中是迭代器生成器,被创造性的拿来做异步流程控制了。当执行的时候,并不执行函数体,而是返回一个迭代器。行代码再看看文章开头的行代码首先生成一个迭代器,然后执行一遍,得到的是一个对象,里面再执行。 广告招人:阿里巴巴招前端,在这里你可以享受大公司的福利和技术体系,也有小团队的挑战和成长空间。联系: qingguang.meiqg at alibaba-inc.com 首先请原谅我的标题...

    tinna 评论0 收藏0

发表评论

0条评论

fox_soyoung

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<