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

用栗子说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
– 细说了原型链道理和完成,模拟了继承的设想形式

    原文作者:qianjiahao
    原文地址: https://segmentfault.com/a/1190000002677711
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞