JavaScript高级程序设计——this

前言

本来this应该放在《上下文环境和作用域》中来讲,结果发现自己整理的时候,例子越来越多,所以单独写一篇用于加深理解,以后工作或项目中发现一些this相关问题可以进一步完善文章的例子。

来源:http://www.cduyzh.com/js-this/

this

概念

在函数中this到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了

因为this的取值是执行上下文环境的一部分,每次调用函数,都会产生一个新的执行上下文环境。

构造函数

所谓构造函数就是用来new对象的函数。其实严格来说,所有的函数都可以new一个对象,但是有些函数的定义是为了new一个对象,而有些函数则不是。另外注意,构造函数的函数名第一个字母大写(规则约定)。例如:Object、Array、Function等。

function Foo() {
    this.name = "yzh";
    this.year = 1996;
    console.log(this); //Object { name: "yzh", year: 1998 }
}
var f1 = new Foo();
console.log(f1.name); //yzh
console.log(f1.year); //1996

以上代码中,如果函数作为构造函数用,那么其中的this就代表它即将new出来的对象。

注意,以上仅限newFoo()的情况,即Foo函数作为构造函数的情况。如果直接调用Foo函数,而不是new Foo(),情况就大不一样了。

function Foo() {
    this.name = "yzh";
    this.year = 1996;
    console.log(this); //Object { name: "yzh", year: 1998 }
}
Foo(); //window

函数作为对象的一个属性这种情况下this是window。

如果函数作为对象的一个属性时,并且作为对象的一个属性被调用时,函数中的this指向该对象。

var obj = {
    x: 10,
    fn: function() {
         console.log(this); //Object { x: 10, fn: fn() }
         console.log(this.x); //10
    }
};
obj.fn();

如果fn函数不作为obj的一个属性被调用,会是什么结果呢?以上代码中,fn不仅作为一个对象的一个属性,而且的确是作为对象的一个属性被调用。结果this就是obj对象。

var obj = {
    x: 10,
    fn: function() {
        console.log(this); //window
        console.log(this.x); //undefined
    }
};
var f1 = obj.fn;
f1();

函数用call或者apply调用如上代码,如果fn函数被赋值到了另一个变量中,并没有作为obj的一个属性被调用,那么this的值就是window,this.x为undefined。

为了防止看不懂这块先理解下基础并重要的东西

函数内部属性

在函数内部,有两个特殊的对象:arguments和this.
主要介绍下arguments,它是类数组对象,包含传入函数的所有参数,这个对象还有一个叫callee的属性,该属性为一个指针,指向拥有这个arguments对象的函数。

这个例子主要用于消除函数的执行与同名函数的紧密耦合现象。代码如下:

function factorial(num) {
    if (num <= 1) {
         return 1;
    } else {
         //1.一般的递归算法运用
         // return num * factorial(num - 1);

         //2.更好的做法
         return num * arguments.callee(num - 1);
    }
}
var trueFactorial = factorial; factorial = function() { return 0; }; alert(trueFactorial(5)); //120 alert(factorial(5)); //0

每个函数都包含两个属性:length和prototype.函数属性

length表示函数希望接受的命名参数的个数

function sayName(name){
     alert(name);
}
 
function sum(num1, num2){
     return num1 + num2;
}
 
function sayHi(){
     alert("hi");
}
 
alert(sayName.length); //1
alert(sum.length); //2
alert(sayHi.length); //0

函数方法prototype属性这里不再重复介绍。

每个函数都包含两个非继承而来的方法:apply()和call(),这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内的this对象值

apply()方法接受两个参数:一个是在其中运行函数的作用域,另一个是参数数组。

function sum(num1, num2){
    return num1 + num2;
}
 
function callSum1(num1, num2){
    return sum.apply(this, arguments);
}
 
function callSum2(num1, num2){
    return sum.apply(this, [num1, num2]);
}
 
alert(callSum1(10,10)); //20
alert(callSum2(10,10)); //20

 

callsSum1()执行sum()函数时传入this作为this值(在全局作用域中调用,所以传入的对象为window对象)下面的例子同理。

call()方法与apply()方法差不多,区别在于接受参数的方式不同。简单来说就是:传递给函数的参数必须逐个列举出来。(如果是无参函数就不用传参数)

function sum(num1, num2){
    return num1 + num2;
}
 
function callSum(num1, num2){
    return sum.call(this, num1, num2);
}
 
alert(callSum(10,10)); //20

 

如下代码如果不用函数的方法来实现。传递参数并非两个函数的真正用武之地,真正强大的地方是扩充函数赖以运行的作用域

window.color = "red";
var o = { color: "blue" };
 
function sayColor(){
    alert(this.color);
}
 
sayColor(); //red
 
sayColor.call(this); //red
sayColor.call(window); //red
sayColor.call(o); //blue
window.color = "red";
var o = { color: "blue" };
 
function sayColor(){
    alert(this.color);
}
 
sayColor(); //red
 
o.sayColor = sayColor;
o.sayColor(); //blue

 


如果要输出o对象里的color属性值,必须把sayColor函数赋给对象o并调用 o.sayColor()时,this引用的对象为o 

回归要讲的例子

当一个函数被call和apply调用时,this的值就取传入的对象的值。

var obj = {
    x: 10
};
var fn = function() {
    console.log(this); //Object { x: 10 }
    console.log(this.x); //10
};
fn.call(obj);

在全局环境下,this永远是window,这个应该没有非议。全局 & 调用普通函数

console.log(this === window); //true
var x = 10;
var fn = function() {
    console.log(this); //window
    console.log(this.x); //10
}
fn();

 

注意以下的情况普通函数在调用时,其中的this也都是window。

var obj = {
    x: 10,
    fn: function() {
        function f() {
            console.log(this); //Window
            console.log(this.x); //undefined
        }
        f();
    }
};
obj.fn();

 

函数f虽然是在obj.fn内部定义的,但是它仍然是一个普通的函数,this仍然指向window。 

总结:this指向调用该函数的对象

构造函数的prototype中,this代表着什么

function Fn() {
    this.name = "yzh";
    this.year = 1996;
}
Fn.prototype.getName = function() {
    console.log(this.name);
}
var f1 = new Fn();
f1.getName(); //yzh

在Fn.prototype.getName函数中,this指向的是f1对象。因此可以通过this.name获取f1.name的值

posted @ 2017-05-24 17:34  亦续缘  阅读(234)  评论(0编辑  收藏  举报