这个内部原型函数等于窗口而不是对象实例

Dis*_*tum 4 javascript this browserify typescript

在下面的代码中HeadDirective.prototype.link,this等于全局window对象而不是HeadDirective实例.我的理解是this原型函数内部的值是包含对象本身.

var HeadDirective = (function () {
    function HeadDirective($rootScope, $compile) {
        this.$rootScope = $rootScope;
        this.$compile = $compile;
        this.restrict = 'E';
    }
    HeadDirective.prototype.link = function (scope, elem) {
        var html = '<link rel="stylesheet" ng-repeat="cssUrl in routeStyles" ng-href="{{cssUrl}}" />';
        elem.append(this.$compile(html)(scope));
        scope.routeStyles = [];
        this.$rootScope.$on('$routeChangeStart', function (e, next, current) {
            if (next && next.$$route && next.$$route.css) {
                if (!Array.isArray(next.$$route.css)) {
                    next.$$route.css = [next.$$route.css];
                }
                angular.forEach(next.$$route.css, function (sheet) {
                    scope.routeStyles.push(sheet);
                });
            }
        });
        this.$rootScope.$on('$routeChangeSuccess', function (e, next, current) {
            if (current && current.$$route && current.$$route.css) {
                if (!Array.isArray(current.$$route.css)) {
                    current.$$route.css = [current.$$route.css];
                }
                angular.forEach(current.$$route.css, function (sheet) {
                    scope.routeStyles.splice(scope.routeStyles.indexOf(sheet), 1);
                });
            }
        });
    };
    return HeadDirective;
})();

directives.directive('head', [
    '$rootScope', '$compile', function ($rootScope, $compile) {
        return new HeadDirective($rootScope, $compile);
    }]);
Run Code Online (Sandbox Code Playgroud)

上面的代码是从以下TypeScript生成的:

class HeadDirective implements ng.IDirective {

    constructor(private $rootScope: ng.IRootScopeService, private $compile: ng.ICompileService) {}

    link(scope: IScope, elem: JQuery): void {
        var html = '<link rel="stylesheet" ng-repeat="cssUrl in routeStyles" ng-href="{{cssUrl}}" />';
        elem.append(this.$compile(html)(scope));
        scope.routeStyles = [];
        this.$rootScope.$on('$routeChangeStart', (e: ng.IAngularEvent, next?: IRoute, current?: IRoute): any => {
            if(next && next.$$route && next.$$route.css){
                if(!Array.isArray(next.$$route.css)){
                    next.$$route.css = [next.$$route.css];
                }
                angular.forEach(next.$$route.css, (sheet: string) => {
                    scope.routeStyles.push(sheet);
                });
            }
        });
        this.$rootScope.$on('$routeChangeSuccess', (e: ng.IAngularEvent, next?: IRoute, current?: IRoute): any => {
            if(current && current.$$route && current.$$route.css){
                if(!Array.isArray(current.$$route.css)){
                    current.$$route.css = [current.$$route.css];
                }
                angular.forEach(current.$$route.css, (sheet) => {
                    scope.routeStyles.splice(scope.routeStyles.indexOf(sheet), 1);
                });
            }
        });
    }

    restrict = 'E';
}

directives.directive('head', ['$rootScope','$compile', ($rootScope: ng.IRootScopeService, $compile: ng.ICompileService): ng.IDirective =>{
    return new HeadDirective($rootScope, $compile);
}]);
Run Code Online (Sandbox Code Playgroud)

根据最新的TypeScript语言规范:

this表达式中的类型取决于引用发生的位置:

  • 在构造函数中,实例成员函数,实例成员访问器或实例成员变量初始this值设定项属于包含类的类实例类型.
  • 在静态成员函数或静态成员访问器中,类型this是包含类的构造函数类型.
  • 在函数声明或标准函数表达式中,this类型为Any.
  • 在全局模块中,this类型为Any.

在所有其他上下文中,引用它是一个编译时错误.

TypeScript语言规范非常清楚.在成员函数内部(编译成原型函数),this引用类实例.这显然不是我所看到的.

有任何想法吗?Browserify会干扰this吗?

Fen*_*ton 5

this关键字是非常情境.例如,如果事件调用方法,this则将是事件目标的对象.

您可以通过调整变量或使用JavaScript (或)方法绑定范围来解决问题.thiscallapplythis

简短的例子......这是前提:

class MyClass {
    constructor(private myProp: string) {

    }

    myMethod() {
        alert(this.myProp);
    }
}

var myClass = new MyClass('Test');

// 'Test'
myClass.myMethod();

// undefined
window.setTimeout(myClass.myMethod, 1000);
Run Code Online (Sandbox Code Playgroud)

解决方案One - Arrow语法

在TypeScript中,箭头语法将摆动this为一个_this自动调用的变量,并替换箭头函数中的用法...所以这将解决undefined上面的问题,而是警告Test.

class MyClass {
    constructor(private myProp: string) {

    }

    public myMethod = () => {
        alert(this.myProp);
    }
}
Run Code Online (Sandbox Code Playgroud)

解决方案二 - 调用方法

您可以使用该call方法将上下文替换为this您喜欢的任何对象,在下面的示例中,我们将其重置为myClass实例.

无论您是编写TypeScript还是纯JavaScript,这都有效...而第一个解决方案实际上是TypeScript解决方案.

window.setTimeout(function() { myClass.myMethod.call(myClass) }, 1000);
Run Code Online (Sandbox Code Playgroud)

或者更短(要清楚,这里使用箭头函数与范围无关 - 它只是一个较短的语法箭头函数只影响范围,如果你有this内部):

window.setTimeout(() => myClass.myMethod.call(myClass), 1000);
Run Code Online (Sandbox Code Playgroud)

  • 规范描述了您引用的部分中`this`关键字的*编译时类型*,而不是值.因为TypeScript在运行时具有与JavaScript相同的`this`语义,所以总是有可能最终得到'错误'的值. (2认同)