JavaScript 是 弱类型 语言,但并不是没有类型,JavaScript可以识别下面 7 种不同类型的值:
- Undefined
- Null
- Boolean
- String
- Number
- Symbol
- Object
- The List and Record Specification Type
- The Completion Record Specification Type
- The Reference Specification Type
- The Property Descriptor Specification Type
- The Lexical Environment and Environment Record Specification Types
- Data Blocks
- Array 2. RegExp 3. Date 4. Math 5. ...
可以使用
typeof
判断数据类型,操作符返回一个字符串,但并非返回的所有结果都符合预期
typeof false
// "boolean"
typeof .2
// "number"
typeof NaN
// "number"
typeof ''
// "string"
typeof undefined
// "undefined"
typeof Symbol()
// "symbol"
typeof new Date()
// "object"
typeof []
// "object"
typeof alert
// "function"
typeof null
// "object"
typeof not_defined_var
// "undefined"
在应用程序中,使用变量来来为值命名。变量的名称称为 identifiers
- 使用关键字
var
:函数作用域 - 使用关键字
let
:块作用域 (block scope local variable) - 直接使用:全局作用域
var global_var = 1;
function fn () {
var fn_var = 2;
if(fn_var > 10){
let block_var = 3;
global_var2 = 4;
}
}
const num = 1;
const obj = { prop: 'value' }; num = 2;
// Uncaught TypeError: Assignment to constant variable.
obj['prop'] = 'value2'; obj = [];
// Uncaught TypeError: Assignment to constant variable.
JavaScript中可以引用稍后声明的变量,而不会引发异,这一概念称为变量声明提升(hoisting)
console.log(a);
// undefined var a = 2;
等同于
var a;
console.log(a);
a = 2;
一个函数就是一个可以被外部代码调用(或者函数本身递归调用)的 子程序
- 函数声明
- 函数表达式
- Function 构造函数
- 箭头函数
function fn(){}
var fn = function(){}
var fn = new Function(arg1, arg2, ... argN, funcBody)
var fn = (param) => {}
- arguments: 一个包含了传递给当前执行函数参数的类似于数组的对象
- arguments.length: 传给函数的参数的数目
arguments.caller: 调用当前执行函数的函数arguments.callee: 当前正在执行的函数
function foo() {
return arguments;
}
foo(1, 2, 3);
// Arguments[3]
// { "0": 1, "1": 2, "2": 3 }
function foo(...args) {
return args;
}
foo(1, 2, 3);
// Array[3]
// [1, 2, 3]
function fn(a, b, ...args){
return args;
}
fn(1, 2, 3, 4, 5);
// Array[3]
// [3, 4, 5]
function fn (a = 2, b = 3) { return a + b; } fn(2, 3); // 5 fn(2); // 5 fn(); // 5
JavaScript 中对象是可变 键控集合
(keyed collections)
- 字面量
- 构造函数
var obj = { prop: 'value', fn: function(){} };
var date = new Date();
构造函数和普通函数并没有区别,使用 new
关键字调用就是构造函数,使用构造函数可以实例化 一个对象
函数的返回值有两种可能
- 显式调用
return
返回return
后表达式的求值 - 没有调用
return
返回undefined
function People(name, age) { this.name = name; this.age = age; } var people = new People('Byron', 26);
构造函数返回值
- 没有返回值
- 简单数据类型
- 对象类型
前两种情况构造函数返回构造对象的实例,
实例化对象正是利用的这个特性 第三种构造函数和普通函数表现一致,返回
return
后表达式的结果
- 每个函数都有一个
prototype
的对象属性,对象内有一个constructor
属性,默认指向函数本身 - 每个对象都有一个
__proto__
的属性,属相指向其父类型的prototype
function Person(name) { this.name = name; }
Person.prototype.print = function () { console.log(this.name); };
var p1 = new Person('Byron');
var p2 = new Person('Casper');
p1.print(); p2.print();
作用域可以通俗的理解
- 我是谁
- 我有哪些马仔
其中我是谁的回答就是
this
马仔就是我的局部变量
普通函数
- 严格模式:
undefined
- 非严格模式: 全局对象 1. Node:
global
2. 浏览器:window
构造函数:对象的实例 对象方法:对象本身
- fn.call(context, arg1, arg2, …, argn)
- fn.apply(context, args)
function isNumber(obj) {
return Object.prototype.toString.call(obj) === '[object Number]';
}
bind
返回一个新函数,函数的作用域为 bind
参数
function fn() {
this.i = 0;
setInterval(function () {
console.log(this.i++);
}.bind(this), 500)
}
fn();
箭头函数是 ES6 提供的新特性,是简写的 函数表达式,拥有词法作用域和 this
值
function fn() {
this.i = 0;
setInterval(() => {
console.log(this.i++);
},500)
}
fn();
在 JavaScript 的场景,继承有两个目标,子类需要得到父类的:
- 对象的属性
- 对象的方法
function inherits(child, parent) {
var _proptotype = Object.create(parent.prototype);
_proptotype.constructor = child.prototype.constructor;
child.prototype = _proptotype;
}
function People(name, age) {
this.name = name;
this.age = age;
}
People.prototype.getName = function () {
return this.name;
}
function English(name, age, language) {
People.call(this, name, age);
this.language = language;
} inherits(English, People);
English.prototype.introduce = function () {
console.log('Hi, I am ' + this.getName());
console.log('I speak ' + this.language);
}
function Chinese(name, age, language) {
People.call(this, name, age);
this.language = language;
} inherits(Chinese, People);
Chinese.prototype.introduce = function () {
console.log('你好,我是' + this.getName());
console.log('我说' + this.language);
}
var en = new English('Byron', 26, 'English');
var cn = new Chinese('色拉油', 27, '汉语');
en.introduce();
cn.introduce();
"use strict";
class People{
constructor(name, age){
this.name = name;
this.age = age;
}
getName(){
return this.name;
}
}
class English extends People{
constructor(name, age, language){
super(name, age);
this.language = language;
}
introduce(){
console.log('Hi, I am ' + this.getName());
console.log('I speak ' + this.language);
}
}
let en = new English('Byron', 26, 'English');
en.introduce();
loop: for (var i = 0; i < 10; i++) {
for (var j = 0; j < 5; j++) {
console.log(j);
if (j === 1) {
break loop;
}
}
}
console.log(i);
var x = { a:1 };
{ a:1 }
{ a:1, b:2 }
( function() {}() );
( function() {} )();
[ function() {}() ];
~ function() {}();
! function() {}();
+ function() {}();
- function() {}();
delete function() {}();
typeof function() {}();
void function() {}();
new function() {}();
new function() {};
var f = function() {}();
1, function() {}();
1 ^ function() {}();
1 > function() {}();
高阶函数是把函数当做参数或者返回值是函数的函数
[1, 2, 3, 4].forEach(function(item){ console.log(item); });
闭包由两部分组成
- 函数
- 环境:函数创建时作用域内的局部变量
function makeCounter(init) {
var init = init || 0;
return function(){
return ++init;
}
}
var counter = makeCounter(10);
console.log(counter());
console.log(counter());
for (var i = 0; i < doms.length; i++) {
doms.eq(i).on('click', function (ev) {
console.log(i);
});
}
for (var i = 0; i < doms.length; i++) {
(function (i) {
doms.eq(i).on('click', function (ev) {
console.log(i);
});
})(i);
}
function eventBinderGenerator() {
if (window.addEventListener) {
return function (element, type, handler) {
element.addEventListener(type, hanlder, false);
}
}
else {
return function (element, type, handler) {
element.attachEvent('on' + type, handler.bind(element, window.event));
}
}
}
var addEvent = eventBinderGenerator();
一种允许使用部分参数生成函数的方式
function isType(type) {
return function(obj){
return Object.prototype.toString.call(obj) === '[object '+ type +']';
}
}
var isNumber = isType('Number');
console.log(isNumber(1));
console.log(isNumber('s'));
var isArray = isType('Array');
console.log(isArray(1));
console.log(isArray([1, 2, 3]));
function f(n) {
return n * n;
}
function g(n) {
return n * 2;
}
console.log(f(g(5)));
function pipe(f, g) {
return function () {
return f.call(null, g.apply(null, arguments));
}
}
var fn = pipe(f, g);
console.log(fn(5));
- 尾调用是指某个函数的最后一步是调用另一个函数
- 函数调用自身,称为递归
- 如果尾调用自身,就称为尾递归 递归很容易发生"栈溢出"错误(stack overflow)
function factorial(n) {
if (n === 1) return 1;
return n * factorial(n - 1);
}
factorial(5)
// 120
function factorial(n, total) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
factorial(5, 1) // 120
function currying(fn, n) {
return function (m) {
return fn.call(this, m, n);
};
}
function tailFactorial(n, total) {
if (n === 1) return total;
return tailFactorial(n - 1, n * total);
}
const factorial = currying(tailFactorial, 1);
factorial(5);
// 120
Function.prototype.uncurry = function () {
return this.call.bind(this);
};
var push = Array.prototype.push.uncurry();
var arr = [];
push(arr, 1);
push(arr, 2);
push(arr, 3);
console.log(arr);