前端都会去了解的程序员深究JavaScript

Javascript 基础

2015-12-11  本文已影响393人  KeKeMars

语法基础 - 词法

字符集

Unicode字符集, 区分大小写

注释

// /* */

直接量

数字 小数 字符串 布尔值 正则表达式

标识符

字母 下划线 美元符号开始

保留字

break delete case do catch else continue false debugger finally default for function return typeof if switch var in this void instanceof throw while new true with null try
class const enum export extends import super
implements let private public yield interface package protected static
abstract double goto boolean enum implements byte export import char extends int class final interface const float long native static package super private synchronized protected throws public transient short volatile

预定义的全局变量

arguments encodeURI Infinity Array encodeURIComponent isFinite Boolean Error isNaN Date eval JSON decodeURI EvalError Math decodeURIComponent Function NaN Number Object parseFloat parseInt RangeError ReferenceError RegExp String SyntaxError TypeError undefined URIError

分号


语法基础 - 数据结构

undefined是预定义的全局变量, 不是关键字 typeof undefined === "undefined"

原始类型

数字,字符串和布尔值

数字

不区分整数值和浮点数,JavaScript中所有数字均用64位浮点数值标识(IEEE 754)。
取值范围在 ±1.7976931348623157 × 10 308±5 × 10 −324 之间
由于浮点值: 0.3-0.2 !== 0.1

整数

Math类

ES6

function imul(a, b) {
  var ah  = (a >>> 16) & 0xffff;
  var al = a & 0xffff;
  var bh  = (b >>> 16) & 0xffff;
  var bl = b & 0xffff;
  // the shift by 0 fixes the sign on the high part
  // the final |0 converts the unsigned value into a signed value
  return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0);
}
function trunc(x) {
  return x < 0 ? Math.ceil(x) : Math.floor(x);
}

常量

无限值

NaN 不与任何值相等 包括它自己.

Zero

布尔值

true/false
undefined null 0 -0 NaN "" 会转换成 false

字符串

ES5

ES6

对象类型

特殊的对象:
函数 Promise Map Set WeakMap WeakSet Proxy typeof === 'function'

Symbol() typeof === 'symbol'

数组 日期 null typeof === 'object'

全局对象 Math JSON typeof === 'object'

构造函数 Date

包装对象 Number String Boolean Array Function RegExp Error(SyntaxError ReferenceError TypeError)

全局属性 undefined typeof === 'undefined'

全局属性 Infinity typeof === 'number'

特殊对象方法

JSON.parse(text)
JSON.stringify(obj)
Date.now 获取当前时间距1970.1.1 00:00:00的毫秒数

Map

Set

var proxy = Proxy(target, handler);

Symbol()

类型转换

Number parseInt parseFloat
toString String +''
Boolean

类型检测

isNaN() 该函数会尝试将参数值用Number()进行转换,如果结果为“非数值”则返回true,否则返回false。

ES6

操作符

加法运算操作符

乘除、减号运算符、取模运算符

这些操作符针对的是运算,所以他们具有共同性:如果操作值之一不是数值,则被隐式调用Number()函数进行转换。

逻辑操作符(!、&&、||)

关系操作符(<, >, <=, >=)

关系操作符的操作值也可以是任意类型的,所以使用非数值类型参与比较时也需要系统进行隐式类型转换:

相等操作符(==)

相等操作符会对操作值进行隐式转换后进行比较:


语法基础 - 语句

表达式

原始表达式

常量 关键字 变量

对象/数组初始化表达式

函数定义表达式

属性访问表达式

o.x

调用表达式

f(0)
Math.max(x,y,z)
a.sort()

对象创建表达式

new Object()

运算符

算术表达式

关系表达式

=== instanceof

逻辑表达式

三元操作符

赋值表达式

表达式计算

eval('3+2')

其他运算符

typeof
delete
in

delete o.x //删除一个属性
"x" in o => false


语法基础 - 数组

创建数组

数组字面量 var a = [1, 2, 3];
使用构造函数 var a = new Array();

判断数组

数组本质上是object(type of [ ] == 'object');
需要通过判断constructor。
[].constructor //Array

数组长度 arr.length

数组的length属性是可写的。当length属性小于元素个数时,数组中索引值大于length属性的元素会被删掉。

数组元素的添加和删除

数组方法

var a = [1, 2, 3, 4];
var b = a.splice(1,2);//a = 1,4,b = 2,3

ES5

ES6

ECMAScript 5中的数组新方法

var a = [1, 2, 3];
var b = a.map(function(x) {
return x*x;
}); //b = [1,4,9]
var a = [1, 2, 3];
var b = a.filter(function(x){
return x % 2 !== 0;
});//b = [1, 3]
var a = [1, 2, 3];
var b = a.reduce(function(x, y){
return x + y;
}, 0); //b = 6;

类数组对象

通过为对象增加length自增的特性或者其他特性,可以生成一个‘类数组对象’,可以通过length进行遍历。
例如函数的Arguments对象就是这样


语法基础 - 函数

定义

var plus = function (x, y) {}
function plus(x, y) {}

调用

function a(){};
a();
a = {}; a.x = function() {}
a.x();

-通过callapply间接调用函数(改变this)

call 和 apply带有多个参数,call和apply把当前函数的this指向第一个参数给定的函数或对象中,并传递其余所有的参数作为当前函数的参数。
call和apply的不同之处,在于call传递的参数是作为arguments依次传入的, 而apply传递的参数是以一个数组的方式传入的

fn.call(o, 1, 2, 3);
fn.apply(o, [1, 2, 3]);

var O = function () {
    this.foo  = 'hello';
    this.hello = function () {
        return 'world';
    }
};

var fn = function () {
    console.log('call', this);
};

var o = new O();

fn.call(o);//此时fn的this指向o

函数的参数

当传入参数少于函数声明的参数时,留空的参数的值是undefined
Javascript允许传入参数的个数大于声明时制定的参数个数。可以用arguments来访问这些参数
ES6中, 不建议使用arguments建议使用...args代替

arguments还有两个属性,calleecaller

function f(){
    console.log(arguments.callee);//[Function: f]
    console.log(arguments.callee.caller);[Function: g]
    var i;
    for( i = 0; i < arguments.length ; i++) {
        console.log(arguments[i]);
    }
}

function g(){
    f(1,2,3,4,5,6);
}

g();
callee 的重要用法之一是在匿名函数中实现递归

var result = function (x) {
    if (x <= 1) return 1;
    return x * arguments.callee(x - 1);
}(3);

console.log(result);

函数作为值来传递

function square(x) {
    return x * x;
}

var s = square;
s(4);

函数作为命名空间

(function() {

}());

闭包

Javascript函数对象的内部状态不仅包含着函数的代码逻辑,还引用当前的作用域链。
函数对象通过作用域链相互关联起来,函数体内部变量包含在函数作用域内,这就叫闭包。

var scope = 'global scope';
function checkscope() {
    var scope = 'local scope';
    function f() { 
        return scope;
    }
    return f;
}

checkscope()();

函数中的this对象

在一个对象中的this始终引用当前对象,但是在函数中,特别是在闭包中,this有一些特殊的行为。

函数中的this对象始终绑定在函数运行时的上下文环境上。所以在普通模式下调用一个全局函数,this始终指向window(客户端),在严格模式下调用一个全局函数,this始终是undefined

var name = "The Window";
var object = {
    name: "My Object",
    getNameFunc: function () {
        var that = this;
        return function () {
            return that.name;
        };
    },
    getName : function () {
        return this.name;
    }
};

console.log(object.getNameFunc()());
console.log(object.getName());

函数柯里化

函数柯里化是指,把接受多个参数的函数转换成接受一个单一参数的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

var add1 = add.curry(1);
console.log(add1(2));

其中,add是接受两个参数的函数,add调用了curry返回一个只接受一个参数的新函数,之后调用add1便等效于调用add(1, 2);

javascript并不原生支持curry,可以用prototype来模拟

Function.prototype.curry = function () {
    var slice = Array.prototype.slice,
        args = slice.apply(arguments),
        that = this;
    return function () {
        return that.apply(null, args.concat(slice.apply(arguments)));
    };
};


function add(n1, n2) {
    return n1 + n2;
}

var add1 = add.curry(1);
console.log(add1(2));

curry创建了一个新函数,在新函数的闭包中保存了原先传递的参数。

函数的属性和方法


语法基础 - 对象

创建对象

类继承

Javascript对象拥有自有属性和继承属性。

可以使用in或者hasOwnProperty来判断对象中是否存在属性。

var O = {
  x : 1
};

function P() {
  this.y = 2;
}

P.prototype = O;

var t = new P();
console.log(t);
console.log('x' in t);//true
console.log(t.hasOwnProperty('x'));//false

对象属性

属性遍历

for...in 广度优先会遍历到原型链

属性的特性 Object.getOwnPropertyDescriptor()获取对象特定属性的描述符

如果某个对象的属性定义了存取描述符,value 和 writable会被忽略,JavaScript 只会考虑 Getter, Setter, configurable, 和 enumerable。

Object.defineProperty(o, "foo", { writable : false });
var book = {
    _year: 2004,
    edition: 1
};
Object.defineProperty(book, "year", {
    get: function () {
        console.log('get year');
        return this._year;
    },
    set: function (newValue) {
        console.log('set year');
        if (newValue > 2004) {
            this._year = newValue;
            this.edition += newValue - 2004;
        }
    }
});
book.year = 2005;//控制台输出‘set year’
console.log(book.year);//控制台输出‘get year’和year的值

ES5 新增对象方法

ES6

对象方法

对象的Getter/Setter(ES5)

// 通过闭包
var o = {
  a: 7,
  get b() { 
    return this.a + 1;
  },
  set c(x) {
    this.a = x / 2
  }
};

console.log(o.a); // 7
console.log(o.b); // 8
o.c = 50;
console.log(o.a); // 25

// 通过 Object.defineProperty
var d = Date.prototype;
Object.defineProperty(d, "year", {
  get: function() {return this.getFullYear() },
  set: function(y) { this.setFullYear(y) }
});

// 通过函数属性
function Field(val){
    var value = val;
   
    this.getValue = function(){
        return value;
    };
   
    this.setValue = function(val){
        value = val;
    };
}

可执行对象

既可以当作对象来使用(有原型链),也可以当作函数来直接调用

function bar(o) {
    var f = function() { return "Hello World!"; }
    o.__proto__ = f.__proto__;
    f.__proto__ = o;
    return f;
}

var o = { x: 5 };
var foo = bar(o);

console.log(foo());
console.log(foo.x);
console.log(typeof foo);//function

语法基础 - 严格模式

开启严格模式

"use strict"

严格模式具体行为

ReferenceError

创建隐式的全局变量

TypeError

SyntaxError

eval被限制在临时的本地作用域

arguments不再追踪实际参数值变化

函数的动态绑定后的this不做任何修改

即使指定null或undefined,引擎也不会重新指定全局对象作为this

指定基础数据类型时,也不会用包装类进行转换

"use strict";
function fun() { return this; }
// fun() === undefined
// fun.call(2) === 2
// fun.apply(null) === null
// fun.call(undefined) === undefined
// fun.bind(true)() === true

调用堆栈不可被追踪


参考

上一篇 下一篇

猜你喜欢

热点阅读