返回
编程
分类

abs是函数的名称,并且每个函数执行到return语句时会返回

日期: 2019-11-23 04:34 浏览次数 : 179

语法

一.函数
JS函数有个很大的坑,就是调用时参数可以和定义时不一致,这真是。。。
并且每个函数执行到return语句时会返回,如果没有写return,默认返回undefined
有2种典型的定义函数的方式:
1>.
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}

函数就是最基本的一种代码抽象的方式。

void expr

2>.
var abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};
这种方式abs可以视为指向该函数的变量,因为中JS函数也是一个对象。可以理解为将匿名函数赋给变量abs;

  1. 定义函数
    function abs(x) {
    if (x >=0){
    return x;
    }else{
    return-x;
    }
    }

void运算符的作用是:计算表达式expr,并返回undefined.例子:

调用函数:我们可以用typeof关键字对参数类型进行检查,类似于java的instanceof
function abs(x) {
if (typeof x !== 'number') {
throw 'Not a number';
}
if (x >= 0) {
return x;
} else {
return -x;
}
}

function 指出这是一个函数的定义;
abs是函数的名称;
(x)括号内列出函数的参数,多个参数以逗号分隔;
{...}之间的代码是函数体,可以包含若干语句,也可以没有任何语句.
函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑。
如果没有return语句,函数执行完毕后也会返回结果,只是结果为undefined。
由于JavaScript的函数也是一个对象,上述定义的abs()函数实际上是一个函数对象,而函数名abs可以视为指向该函数的变量。
因此,第二种定义函数的方式如下:
var abs = function (x) {
if (x >=0){
return x;
}else{
return-x;
}
};
这种方式下:function(x){...}是个匿名函数,它没有函数名,但是这个匿名函数赋值给了变量abs,所以通过变量abs就可以调用该函数.
上述两种定义完全等价,注意第二种方式按照完整语法需要在函数体末尾加一个分号;表示赋值语句结束.

> void 0
undefined
> void(0)
undefined

二.arguments关键字
arguments只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array,这意味着我们不定义任何参数也是可以拿到参数的

  1. 调用函数
    调用函数时,按顺序传入参数即可:
    由于JavaScript允许传入任意个参数而不影响调用,因此传入的参数比定义的参数多也没有问题,虽然函数内部并不需要这些参数:
    传入的参数比定义的少也没有问题:
    abs(); // 返回NaN
    此时abs(x)函数的参数x将收到undefined,计算结果为NaN。
    要避免收到undefined,可以对参数进行检查:
    function abs(x) {
    if (typeof x !== 'number') {
    throw 'Not a number';
    }

    if (x >= 0) {
    return x;
    } else {
    return -x;
    }
    }

  2. arguments
    JavaScript 有个免费赠送的关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数.
    arguments类似数组,但它不是一个数组:
    function foo(x){
    alert(x);
    for (var i = 0; i < arguments.length; i++) {
    alert(arguments[i])
    }
    }
    foo(10,20,30);
    利用arguments,你可以获得调用者传入的所有参数。也就是说,即使函数不定义任何参数,还是可以拿到参数的值:
    function abs() {
    // body...
    if (arguments.length === 0) {
    return 0;
    }
    var x = arguments[0];
    return x >= 0 ? x : -x;
    }
    实际上arguments最常用于判断传入参数的个数。你可能会看到这样的写法:
    // foo(a[, b], c)
    // 接收2~3个参数,b是可选参数,如果只传2个参数,b默认为null:
    function foo(a,b,c) {
    // body...
    if (arguments.length === 2) {
    //实际拿到的参数是a和b c为undefined
    c = b;//把b赋值给c
    b = null;//b变为默认值
    }
    //...
    }
    要把中间的参数b变为“可选”参数,就只能通过arguments判断,然后重新调整参数并赋值。

  3. rest
    由于JavaScript函数允许接收任意个参数,于是我们就不得不用arguments来获取所有参数:
    function foo(a,b) {
    var i, rest = [];
    if (arguments.length > 2){
    for (var i = 2; i < arguments.length; i++) {
    rest.push(arguments[i])
    }
    }
    console.log('a = ' + a)
    console.log('b = ' + b)
    console.log(rest)

    }

    为了获取除了已定义参数a、b之外的参数,我们不得不用arguments,并且循环要从索引2开始以便排除前两个参数,这种写法很别扭,只是为了获得额外的rest参数,有没有更好的方法?
    ES6标准引入了rest参数,上面的函数可以改写为:
    function foo(a,b,...rest) {
    console.log('a = ' + a)
    console.log('b = ' + b)
    console.log(rest)
    }
    rest参数只能写在最后,前面用...标示,从运行结果可知,传入的参数先绑定a,b,多余的参数以数组的形式交给变量rest,所以,不需要arguments我们就获取了全部参数.
    如果传入的参数连正常定义的参数都没有填满,rest参数会接受一个空数组,注意不是undefined

> void 4+7 // 由于void比+优先级更高,所以该表达式被解析为(void 4)+7
NaN
> void(4+7)
undefined

'use strict'
function foo(x) {
console.log('x = ' + x); // 10
for (var i=0; i<arguments.length; i++) {
console.log('arg ' + i + ' = ' + arguments[i]); // 10, 20, 30
}
}
foo(10, 20, 30);

5.小心return语句JavaScript引擎有一个在行末自动添加分号的机制,这可能让你栽到return语句的一个大坑:
function foo() {
return { name: 'foo' };
}
如果把return语句拆成两行:
function foo() {
return
{ name: 'foo' };
}
foo(); // undefined
要小心了,由于JavaScript引擎在行末自动添加分号的机制,上面的代码实际上变成了:
function foo() {
return; // 自动添加了分号,相当于return undefined;
{ name: 'foo' }; // 这行语句已经没法执行到了
}
所以正确的多行写法是:
function foo() {
return{
name:'foo'
};
}

> var x;
> x = 3;
3
> void(x = 5);
undefined
> x
5

function abs() {
if (arguments.length === 0) {
return 0;
}
var x = arguments[0];
return x >= 0 ? x : -x;
}

=================
变量

void是个运算符,而不是函数,它不能被重新定义,如果自定义一个void函数,会抛出异常,像下面这样:

abs(); // 0
abs(10); // 10
abs(-9); // 9

  1. 变量提升:
    JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量'提升'到函数的顶部,但不会提升变量赋值:
    'use strict';
    function foo() {
    var x = 'Hello, ' + y;
    alert(x);
    var y = 'Bob';
    }
    foo();
    虽然是strict模式,但语句var x = 'Hello, ' + y;并不报错,原因是变量y在稍后申明了。但是alert显示Hello, undefined,说明变量y的值为undefined。这正是因为JavaScript引擎自动提升了变量y的声明,但不会提升变量y的赋值。
    对于上述foo()函数,JavaScript引擎看到的代码相当于:
    function foo() {
    var y; // 提升变量y的申明
    必威官网亚洲体育 ,var x = 'Hello, ' + y;
    alert(x);
    y = 'Bob';
    }
    由于JavaScript的这一怪异的“特性”,我们在函数内部定义变量时,请严格遵守“在函数内部首先申明所有变量”这一规则。最常见的做法是用一个var申明函数内部用到的所有变量:
    function foo() {
    var
    x = 1, // x初始化为1
    y = x + 1, // y初始化为2
    z, i; // z和i为undefined
    // 其他语句:
    for (i=0; i<100; i++) {
    ...
    }
    }

>function void(expr) { // 这里会报错
return undefined;
}
SyntaxError: Unexpected token void

arguments的常见用法是用来判断参数个数,如下:

2.全局作用域
不在任何函数内定义的变量就具有全局作用域。实际上,JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性:
'use strict';
var course = 'Learn JavaScript';
alert(course); // 'Learn JavaScript'
alert(window.course); // 'Learn JavaScript'
因此,直接访问全局变量course和访问window.course是完全一样的。
由于函数定义有两种方式,以变量方式var foo = function () {}定义的函数实际上也是一个全局变量,因此,顶层函数的定义也被视为一个全局变量,并绑定到window对象:
'use strict';

译者注:在Firefox中,上面的代码只有在严格模式下才会报错,其他的关键字和保留关键字作为函数声明的函数名时也一样.

// foo(a[, b], c)
// 接收2~3个参数,b是可选参数,如果只传2个参数,b默认为null:
function foo(a, b, c) {
if (arguments.length === 2) {
// 实际拿到的参数是a和b,c为undefined
c = b; // 把b赋给c
b = null; // b变为默认值
}
// ...
}

function foo() {
    alert('foo');
}

foo(); // 直接调用foo()
window.foo(); // 通过window.foo()调用
我们每次直接调用的alert()函数其实也是window的一个变量:

>function void(expr) { // 没有报错,但不会真正声明一个void函数
return undefined;
}

三.rest参数,(ES6)新增:rest参数只能参数额写在最后,前面用...标识,从运行结果可知,传入的参数先绑定a、b,多余的参数以数组形式交给变量rest,所以,不再需要arguments我们就获取了全部参数。

这说明JavaScript实际上只有一个全局作用域。任何变量(函数也视为变量),如果没有在当前函数作用域中找到,就会继续往上查找,最后如果在全局作用域中也没有找到,则报ReferenceError错误。

>function void(expr) { // 严格模式下会报错
"use strict";
return undefined;
}
SyntaxError: redefining void is deprecated

function foo(a, b, ...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}

  1. 名字空间
    全局变量会绑定到window上,不同的JavaScript文件如果使用了相同的全局变量,或者定义了相同名字的顶层函数,都会造成命名冲突,并且很难被发现。
    减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中。例如:
    // 唯一的全局变量MYAPP:
    var MYAPP = {};
    // 其他变量:
    MYAPP.name = 'myapp';
    MYAPP.version = 1.0;
    // 其他函数:
    MYAPP.foo = function () {
    return 'foo';
    };
    把自己的代码全部放入唯一的名字空间MYAPP中,会大大减少全局变量冲突的可能。
    许多著名的JavaScript库都是这么干的:jQuery,YUI,underscore等等。
  2. 局部作用域
    由于JavaScript的变量作用域实际上是函数内部,我们在for循环等语句块中是无法定义具有局部作用域的变量的:
    'use strict';

>function class(expr) { // class也是个保留关键字
"use strict";
return undefined;
}
SyntaxError: redefining class is deprecated

foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]

function foo() {
for (var i=0; i<100; i++) {
//
}
i += 100; // 仍然可以引用变量i
}

void的三种用途.

foo(1);
// 结果:
// a = 1
// b = undefined
// Array []

为了解决块级作用域,ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量:
'use strict';

本文剩余的部分讲讲void运算符的三种用途:

四.变量的作用范围与解构赋值
代码说话,我觉得一看就懂:
1>
'use strict';
function foo() {
var x = 1;
x = x + 1;
}
x = x + 2; // ReferenceError! 无法在函数体外引用变量x

function foo() {
var sum = 0;
for (let i=0; i<100; i++) {
sum += i;
}
i += 1; // SyntaxError
}

  1. void 0代替``undefined
  2. 书签小程序
  3. 在链接中执行JavaScript代码

2>
function foo() {
var x = 1;
x = x + 1;//2
}

  1. 常量
    由于var和let申明的是变量,如果要申明一个常量,在ES6之前是不行的,我们通常用全部大写的变量来表示“这是一个常量,不要修改它的值”:
    var PI = 3.14;
    ES6标准引入了新的关键字const来定义常量,const与let都具有块级作用域:
    'use strict';
    const PI = 3.14;
    PI = 3; // 某些浏览器不报错,但是无效果!
    PI; // 3.14

用途1: 用void 0代替undefined

function bar() {
var x = 'A';
x = x + 'B';//AB
}

6.方法:在一个对象中绑定函数,称为这个对象的方法

void 0或者v``oid(0)总是等于u``ndefined,只有一个例外:undefined被重新赋值的时候:

3>
function foo() {
var x = 1;
function bar() {
var y = x + 1; // bar可以访问foo的变量x!
}
var z = y + 1; // ReferenceError! foo不可以访问bar的变量y!
}

var xioming = {
    name:'小明',
    birth:1990,
    age:function () {
        var y = new Data().getFullYear();
        return y - this.birth;
    }
};
xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年调用是27,明年调用就变成28了

绑定到对象上的函数称为方法,和普通函数也没啥区别,但是它在内部使用了一个this关键字,在一个方法内部,this是一个特殊变量,它始终指向当前对象
JavaScript的函数内部如果调用了this,那么这个this到底指向谁?
答案是,视情况而定!
如果以对象的方法形式调用,比如xiaoming.age(),该函数的this指向被调用的对象,也就是xiaoming,这是符合我们预期的。
如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window。
坑爹啊!
更坑爹的是,如果这么写:
var fn = xiaoming.age; // 先拿到xiaoming的age函数
fn(); // NaN 
要保证this指向正确,必须用obj.xxx()的形式调用!
有些时候,喜欢重构的你把方法重构了一下:
'use strict';

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        function getAgeFromBirth() {
            var y = new Date().getFullYear();
            return y - this.birth;
        }
        return getAgeFromBirth();
    }
};

xiaoming.age(); // Uncaught TypeError: Cannot read property 'birth' of undefined
结果又报错了!原因是this指针只在age方法的函数内指向xiaoming,在函数内部定义的函数,this又指向undefined了!(在非strict模式下,它重新指向全局对象window!)
修复的办法也不是没有,我们用一个that变量首先捕获this:
'use strict';

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var that = this; // 在方法内部一开始就捕获this
        function getAgeFromBirth() {
            var y = new Date().getFullYear();
            return y - that.birth; // 用that而不是this
        }
        return getAgeFromBirth();
    }
};

xiaoming.age(); // 25
用var that = this;,你就可以放心地在方法内部定义其他函数,而不是把所有语句都堆到一个方法中。

> function a(undefined) { return undefined; } //这里的undefined是个局部变量
> a("hello")
’hello’

变量提升:
'use strict';
function foo() {
var x = 'Hello, ' + y;
console.log(x); //Hello, undefined
var y = 'Bob';
}

  1. apply

> undefined = "foo"; //这个undefined实际上是window.undefined
> console.log(undefined);
foo

foo();

虽然在一个独立的函数调用中,根据是否是strict模式,this指向undefined或window,不过,我们还是可以控制this的指向的!

void不用担心被重新赋值:

因此,在函数内部定义的我们可以理解为局部变量,不在任何函数内定义的变量就具有全局作用域,JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性:course和访问window.course是一样的

要指定函数的this指向哪个对象,可以用函数本身的apply方法,它接收两个参数,第一个参数就是需要绑定的this变量,第二个参数是Array,表示函数本身的参数。

> function b() { var void = function() {}; return void(0); }
missing variable name
function b() { var void = function() {}; return void(0); }
.......................^

我们可以这么写:

用apply修复getAge()调用:
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};

> void = "foo";
syntax error
void = "foo";
......^

// 定义唯一的全局变量MYAPP:
var MYAPP = {};

xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空

译者注:通常使用的undefined实际上就是window.undefined(属性名和值的名称相同,window.NaN,window.Infinity也类似),它是一个全局变量,在ES3的引擎上,这个变量可以被修改.而在ES5的引擎上,它是window的只读属性,不能被重新赋值,只是在非严格模式下,该赋值操作会静默失败,而在严格模式下,会抛出异常.

// 定义其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;

另一个与apply()类似的方法是call(),唯一区别是:

Firefox3.6下(只实现了部分ES5特性,在这里算是ES3引擎)

// 定义其他函数:
MYAPP.foo = function () {
return 'foo';
};

apply()把参数打包成Array再传入;

>undefined = true;
>console.log(undefined);
true

局部作用域:
这是普通的方式,
'use strict';
function foo() {
for (var i=0; i<100; i++) {
//
}
i += 100; // 仍然可以引用变量i
}

call()把参数按顺序传入。

Firefox18下(完全实现了ES5)

ES6中新增了一个关键字:let,用let替代var可以申明一个块级作用域的变量:

比如调用Math.max(3, 5, 4),分别用apply()和call()实现如下:
Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5
对普通函数调用,我们通常把this绑定为null。

>(function () {
undefined = true; // 没有报错,但其实没有赋值成功
   console.log(undefined);
})()
undefined

'use strict';
function foo() {
var sum = 0;
for (let i=0; i<100; i++) {
sum += i;
}

  1. 装饰器
    利用apply(),我们还可以动态改变函数的行为。
    JavaScript的所有对象都是动态的,即使内置的函数,我们也可以重新指向新的函数。
    现在假定我们想统计一下代码一共调用了多少次parseInt(),可以把所有的调用都找出来,然后手动加上count += 1,不过这样做太傻了。最佳方案是用我们自己的函数替换掉默认的parseInt():

>(function () {
"use strict";
undefined = true; // 严格模式,为只读属性赋值会抛出异常
})()
TypeError: "undefined" is read-only

console.log(i += 1);   // SyntaxError:

var count = 0;
var oldParsetInt = parseInt;//保存原函数
window.parseInt = function () {
count += 1;
return oldParsetInt.apply(null,arguments);//调用原函数
}

如果你无论如何都担心全局的undefined变量会被别人修改,那就使用void 0.否则,使用让人更容易明白的undefined,因为并不是所有阅读你的代码的人都熟悉``void运算符.

}

===========================
高阶函数:函数的参数可以是另一个函数.

译者注:现在很流行的做法是把自己的代码都写在一个自执行的函数表达式里,函数内部使用一个局部的undefined变量,这样可以保证undefined变量的值是真实的undefined.

ES6中新增了一个关键字const, 来声明常量:
'use strict';
const PI = 3.14;
PI = 3; // 某些浏览器不报错,但是无效果!
PI; // 3.14

  1. map 由于map()方法定义在JavaScript的Array中,我们调用Array的map()方法,传入我们自己的函数,就得到了一个新的Array作为结果:
  2. reduce 再看reduce的用法。Array的reduce()把一个函数作用在这个Array的[x1, x2, x3...]上,这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算,
    由于map()接收的回调函数可以有3个参数:callback(currentValue, index, array)通常我们仅需要第一个参数,而忽略了传入的后面两个参数。
    parseInt(string, radix)没有忽略第二个参数
    3.filter 过滤器
    和map()类似,Array的filter()也接收一个函数。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。
    filter()接收的回调函数,其实可以有多个参数。通常我们仅使用第一个参数,表示Array的某个元素。回调函数还可以接收另外两个参数,表示元素的位置和数组本身:
    var arr = ['A', 'B', 'C'];
    var r = arr.filter(function (element, index, self) {
    console.log(element); // 依次打印'A', 'B', 'C'
    console.log(index); // 依次打印0, 1, 2
    console.log(self); // self就是变量arr
    return true;
    });
    3.sort Array的sort()方法默认把所有元素先转换为String再排序 sort()方法也是一个高阶函数,它还可以接收一个比较函数来实现自定义的排序。
    比较的过程必须通过函数抽象出来。通常规定,对于两个元素x和y,如果认为x < y,则返回-1,如果认为x == y,则返回0,如果认为x > y,则返回1,
    4.闭包 就是返回函数
    返回的函数在其定义内部引用了局部变量arr,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用,所以,闭包用起来简单,实现起来可不容易。
    返回的函数并没有立刻执行,而是直到调用了f()才执行。我们来看一个例子:
    返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
    如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:
    注意这里用了一个“创建一个匿名函数并立刻执行”的语法:
    (function (x) {
    return x * x;
    })(3); // 9
    理论上讲,创建一个匿名函数并立刻执行可以这么写:
    function (x) { return x * x } (3);
    但是由于JavaScript语法解析的问题,会报SyntaxError错误,因此需要用括号把整个函数定义括起来:
    (function (x) { return x * x }) (3);
    通常,一个立即执行的匿名函数可以把函数体拆开,一般这么写:
    (function (x) {
    return x * x;
    })(3);
    换句话说,闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来。
    5.箭头函数
    ES6标准新增了一种新的函数:Arrow Function(箭头函数)。
    为什么叫Arrow Function?因为它的定义用的就是一个箭头:
    x => x * x
    箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种像上面的,只包含一个表达式,连{ ... }和return都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ ... }和return:
    x => {
    if (x > 0) {
    return x * x;
    }
    else {
    return - x * x;
    }
    }
    如果参数不是一个,就需要用括号()括起来:
    // 两个参数:
    (x, y) => x * x + y * y
    // 无参数:
    () => 3.14
    // 可变参数:
    (x, y, ...rest) => {
    var i, sum = x + y;
    for (i=0; i<rest.length; i++) {
    sum += rest[i];
    }
    return sum;
    }
    如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错:
    // SyntaxError:
    x => { foo: x }
    因为和函数体的{ ... }有语法冲突,所以要改为:
    // ok:
    x => ({ foo: x })
    箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj:
    var obj = {
    birth: 1990,
    getAge: function () {
    var b = this.birth; // 1990
    var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
    return fn();
    }
    };
    obj.getAge(); // 25
    如果使用箭头函数,以前的那种hack写法:
    var that = this;
    就不再需要了。
    由于this在箭头函数中已经按照词法作用域绑定了,所以,用call()或者apply()调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略:

//ES3引擎下
>undefined = true;
>console.log(undefined)
true
>(function (undefined) {
console.log(undefined) //undefined是个参数,但没有传入对应的实参,因此它的值就是真实的undefined
})()
undefined

ES6还引入了解构赋值,可以同时对一组变量进行赋值:

用途2: 书签小程序

'use strict';
// 如果浏览器支持解构赋值就不会报错:
var [x, y, z] = ['hello', 'JavaScript', 'ES6'];
// x, y, z分别被赋值为数组对应元素:
console.log('x = ' + x + ', y = ' + y + ', z = ' + z);

书签小程序(Bookmarklets)是一个能够执行JavaScript代码的URI(译者注:使用JavaScript伪协议).如果一个bookmarklet返回的结果不是undefined,那么当前页面显示的内容会被这个返回值替代.这时候就得用到void运算符.[Webkit内核的浏览器不会有这样的麻烦]:

以及嵌套的解构赋值:
let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
x; // 'hello'
y; // 'JavaScript'
z; // 'ES6'

  • javascript:3+4 会把当前页面的内容替换成7.
  • javascript:void(3+4) 不会改变当前页面的内容.void会“隐藏”掉表达式3+4的结果.

ES6中的解构赋值还可以忽略某些元素:
let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前两个元素,只对z赋值第三个元素
z; // 'ES6'

类似的:

对于对象也可以结构赋值:
'use strict';
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school'
};
var {name, age, passport} = person;
// name, age, passport分别被赋值为对应属性:
console.log('name = ' + name + ', age = ' + age + ', passport = ' + passport);

  • javascript:window.open("http://www.whitehouse.gov/") 会替换掉当前页面的内容.
  • javascript:void window.open("http://www.whitehouse.gov/") 不会改变当前页面的内容.

还可以设置默认值:
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678'
};
// 如果person对象没有single属性,默认赋值为true:
var {name, single=true} = person;
name; // '小明'
single; // true

更复杂的例子:这个bookmarklet可以把当前页面的URL提交到submit.example.com:

解构赋值典型应用场景:
1.交换2个数的值:
var x=1, y=2;
[x, y] = [y, x]

javascript:void window.open("http://submit.example.com/submit?"+encodeURIComponent(document.location.href))

2.获取当前页面的域名和路径:
var {hostname:domain, pathname:path} = location;

这个bookmarklet不会改变当前页面的内容,会在新标签或新窗口中打开页面.

五.对象的方法,例子如下:
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
};
xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年调用是25,明年调用就变成26了

译者注:网上有很多流行的Bookmarklet,通常是导入了另外一个js文件,比如繁体字转换成简体字,比如购物网站比价.

2.在一个方法内部,this是一个特殊变量,它始终指向当前对象,也就是xiaoming这个变量。所以,this.birth可以拿到xiaoming的birth属性。(象java中的this)
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
xiaoming.age(); // 25, 正常结果
getAge(); // NaN

javascript: void(document.body.appendChild(document.createElement("script")).src = "")

but,如果以对象的方法形式调用,比如xiaoming.age(),该函数的this指向被调用的对象,也就是xiaoming,这是符合我们预期的。
如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window。
所以说,弱类型语言还是很坑爹~
因此我们一般调用对象的方法必须用obj.xxx()的形式!

用途3: 在链接中执行JavaScript代码

我们的结论是,this,在非strict模式下,如果在函数定义的外部,它指向全局对象window;在strict模式下,如果在函数定义的外部,它指向undefined;

虽然这种做法是不推荐的,但的确是可行的,例如下面的代码:

六:高阶函数:
JS的函数其实都指向某个变量。既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
'use strict';
function add(x, y, f) {
return f(x) + f(y);
}
var x = add(-5, 6, Math.abs); // 11
console.log(x);

<a href="javascript:void computeResult()">Compute</a>

sort()函数是一个高阶函数,他的运用如下:
'use strict';
var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
if (x < y) {
return -1;
}
if (x > y) {
return 1;
}
return 0;
});
console.log(arr); // [1, 2, 10, 20]

如果函数computeResult()返回undefined(或者没有return语句,也默认返回undefined),则不会有什么事.但如果这个函数返回了其他的值,那么你必须在函数前面添加void运算符来防止它改变当前页面的内容.[Webkit内核的浏览器不会有这样的麻烦].

七.JS的闭包:跳过。。。(暂时不想看)
八.箭头函数(ES6新增):跳过,估计现在遇不到
九.generator(生成器)(ES6新增)引入的新的数据类型:跳过,估计现在遇不到

译者注:更常见的用法是:javascript:void(0),用来阻止链接默认的跳转行为.

十.JS中的包装对象:类似java中int 和 Integer 的关系
var n = new Number(123); // 123,生成了新的包装类型
var b = new Boolean(true); // true,生成了新的包装类型
var s = new String('str'); // 'str',生成了新的包装类型

void expr void运算符的作用是:计算表达式expr,并返回undefined.例子: void 0 undefined void (0 ) undefined void 4+7 // 由于void比+优先级更高,所以该表达...

上面三个变量已经成了object。
总结两点:
1.没事别用什么new String(),new Number()这些骚操作。。。老老实实用变量直接赋值=.=
2.用parseInt()或parseFloat()来转换任意类型到number;

先到这里。。。=.=

  • 上一篇:没有了
  • 下一篇:没有了