弄懂Sass 3.5的匿名函数

对博客上最新发布的Sass版本感到困惑?我也是。

Sass 3.5.0-RC.1标记了一种新的数据类型:匿名函数。在候选发布公告中,用了四个段落篇幅描述了匿名函数大量的细节,而不显示任何代码。由于并未真正理解它的含义,所以决定深入了解它。

匿名函数

候选版本上面写着:

可通过传函数名到get-function($name)中得到一个匿名函数

这说明 get-function($name)返回的是一个匿名函数。

匿名函数是什么?

在计算机科学中,据说编程语言如果把函数当做一等公民来对待,那么它就有了匿名函数。-维基百科

听起来不错。好样的,functions,你得到了极大的提升。

然后,文中提到:

你可以在用来传递函数名的地方传递一个匿名函数给call()

这样做是有道理的,但仍缺乏几个例子。我当时想回答这样一个问题:“get-function($name)应该用在什么地方以及为什么要这样使用”

首先来看看从哪里开始。

在小于3.5的Sass版本中调用函数

两个选项:

my-function($arguments)

这是调用函数的经典方式。没什么值得惊讶的。

@function my-function() {
    @return ‘Hello, world.’;
}
my-function();// -> ‘Hello, world.’

或者使用call()

你或许对 call()方法不熟悉,这很正常。大多数开发者不需要用到它,因为它主要对库开发人员有用。

我们传递了一个函数名到call()方法,从而调用了该函数。

@function my-function() {
    @return ‘Hello, world.’;
}
call(‘my-function’); // -> ‘Hello, world.’

重要信息:Sass 3.5不支持这个选项。

所有目前用到传递字符串作为函数参数的样式表应该改用传递匿名函数代替。为此,  用字符串调用call()已被否决。 ** 实际上在4.0之前不会被废弃,它已没太大用处。但我们强烈建议用户立即切换到get-function()**。

例子:

@function foo($x) {
    @return $x;
}
foo('bar'); // -> 'bar'
// DEPRECATED: WILL BREAK IN Sass 4.0.0
call('foo', 'bar'); // -> 'bar'

我们来看看Sass 3.5.0及更高版本是如何处理选项2(call())方法的

在Sass 3.5及更高版本调用函数

在Sass 3.5中,你需要使用get-functioncall()传递一个匿名函数来调用函数。

my-function($arguments)

这依然有效,不必惊慌。

call(get-function(‘my-function’), $arguments)

现在您需要传一个匿名函数到call()方法而不是一个字符串:

@function foo($x) {
    @return $x;
}
h1 {
   content: call(
      get-function('foo'),
      'It works :)'
    );
}
h2 {
  content: call(
    get-function(foo),
      '(even without quotes)'
  );
 }
// call-get-function.scss
h1 { content: "It works :)"; }
h2 { content: "(even without quotes)"; }

call($my-function, $arguments)

没错,你还可以将函数指派给一个变量。

@​function my-function() {
    @​return ‘Great!’;
}
$my-function: get-function(my-function);// New in Sass 3.5.0!
call($my-function); // -> Great!

看一个简单的示例:

@function foo($x) {
    @return $x;
}
$foo: get-function(foo);
h1 {
  content: call($foo, 'bar');
}

不幸的是,$my-function()$foo('bar')将不起作用。编译将会失败,得到以下错误:

Error: get-function(“foo”) isn’t a valid CSS value.

乍一看,我认为可以在Sass中写 $a(b)是一件好事,但可能存在我没考虑到的影响。在未来版本中将如何发展,让我们拭目以待。

编写兼容所有Sass版本的代码

如你的mixin,library,或者framework需要支持多版本的Sass,有能写出兼容Sass 3.3以及更新的和未来版本的代码的办法。

使用function-exists

可以使用function-exists($name)判断get-function是否可用(意味着应传递一个匿名函数到call()方法)。如不可用,回退到旧版本的call语法(传递字符串):

@function foo($x) {
    @return $x;
}
h1 {
  @if (function-exists('get-function')) {
    content: call(get-function('foo'), 'Displays in Sass 3.5.0 and up');
  } @else {
    content: call('foo', 'Displays in Sass 3.3.x and 3.4.x');
   }
 }

// Unfortunately assigning a function to a variable
// can't be polyfilled for Sass 3.3.x and 3.4.x
$foo: get-function(foo);
h1 { content: call($foo, 'bar'); }
// -> el { content: get-function(foo)("bar"); }

使用safe-get-function

我合并了一个 safe-get-function 的工具,在Sass旧版本和未来版本中都有效,所以你现在就可以在代码中使用get-function,为Sass 3.5和4.0做好准备。

// Simplified version of safe-get-function
// Full code: https://github.com/kaelig/sass-safe-get-function
@function safe-get-function($name) {
    @if function-exists('get-function') {
        @return get-function($name);
    } @else {
    @return $name;
   }
}
@function foo($x) { @return $x; }
h1 {
    content: call(safe-get-function('foo'), 'Works in all versions of Sass!');
}

safe-get-function()现可在npm上使用:

npm install sass-safe-function

可以在GitHub下载:https://github.com/kaelig/sass-safe-get-function

总结

即将发布的3.5版本并无革新性的变化,但我对在Sass 4.0版本的这些特性和新的模块系统感到兴奋,并非一切都在一个全局作用域内(这是一个重大变化)。

如果你的库或框架使用了call()方法,现在不失为一个好时机创建一个新的兼容Sass 3.5的分支,升级你的代码。使用call(safe-get-function($name)) 代替 call($name)

如果你不是一个Sass库开发者,这些改变或许对你并没影响,但希望这篇文章让以后的Sass版本看起来没那么可怕。

想玩玩get-function?我早已备好了一个仓库: https://github.com/kaelig/sass-first-class-functions,玩得开心。

扩展阅读

本文根据@Kaelig的《Making sense out of Sass 3.5 first-class functions》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://medium.com/@kaelig/sass-first-class-functions-6e718e2b5eb0#.bvcd7frl9

薄荷

前端开发。喜欢看书,喜欢音乐。Let's share what we have。

如需转载,烦请注明出处:http://www.w3cplus.com/preprocessor/sass-first-class-functions.html

返回顶部