数据类型

JavaScript 是 弱类型 语言,但并不是没有类型,JavaScript可以识别下面 7 种不同类型的值:

基本数据类型

  1. Boolean
  2. Number
  3. String
  4. null
  5. undefined
  6. Symbol

Object

  1. Array
  2. RegExp
  3. Date
  4. Math
  5. ...

可以使用 typeof 判断数据类型,操作符返回一个字符串,但并非返回的所有结果都符合预期

  1. typeof false // "boolean"
  2. typeof .2 // "number"
  3. typeof NaN // "number"
  4. typeof '' // "string"
  5. typeof undefined // "undefined"
  6. typeof Symbol() // "symbol"
  7. typeof new Date() // "object"
  8. typeof [] // "object"
  9. typeof alert // "function"
  10. typeof null // "object"
  11. typeof not_defined_var // "undefined"

变量

在应用程序中,使用变量来来为值命名。变量的名称称为 identifiers

声明

  1. 使用关键字 var :函数作用域
  2. 使用关键字 let :块作用域 (block scope local variable)
  3. 直接使用:全局作用域
  1. var global_var = 1;
  2. function fn () {
  3. var fn_var = 2;
  4. if(fn_var > 10){
  5. let block_var = 3;
  6. global_var2 = 4;
  7. }
  8. }

只声明不赋值,变量的默认值是 undefined

const 关键字可以声明不可变变量,同样为块作用域。对不可变的理解在对象上的理解需要注意

  1. const num = 1;
  2. const obj = {
  3. prop: 'value'
  4. };
  5. num = 2; // Uncaught TypeError: Assignment to constant variable.
  6. obj['prop'] = 'value2';
  7. obj = []; // Uncaught TypeError: Assignment to constant variable.

变量提升

JavaScript中可以引用稍后声明的变量,而不会引发异,这一概念称为变量声明提升(hoisting)

  1. console.log(a); // undefined
  2. var a = 2;

等同于

  1. var a;
  2. console.log(a);
  3. a = 2;

函数

一个函数就是一个可以被外部代码调用(或者函数本身递归调用)的 子程序

定义函数

  1. 函数声明
  2. 函数表达式
  3. Function 构造函数
  4. 箭头函数
  1. function fn(){}
  2. var fn = function(){}
  3. var fn = new Function(arg1, arg2, ... argN, funcBody)
  4. var fn = (param) => {}

arguments

  1. arguments:  一个包含了传递给当前执行函数参数的类似于数组的对象
  2. arguments.length: 传给函数的参数的数目
  3. arguments.caller: 调用当前执行函数的函数
  4. arguments.callee: 当前正在执行的函数
  1. function foo() {
  2. return arguments;
  3. }
  4. foo(1, 2, 3); // Arguments[3]
  5. // { "0": 1, "1": 2, "2": 3 }

rest

  1. function foo(...args) {
  2. return args;
  3. }
  4. foo(1, 2, 3); // Array[3]
  5. // [1, 2, 3]
  6. function fn(a, b, ...args){
  7. return args;
  8. }
  9. fn(1, 2, 3, 4, 5); // Array[3]
  10. // [3, 4, 5]

default

函数的参数可以在定义的时候约定默认值

  1. function fn (a = 2, b = 3) {
  2. return a + b;
  3. }
  4. fn(2, 3); // 5
  5. fn(2); // 5
  6. fn(); // 5

对象

JavaScript 中对象是可变 键控集合 (keyed collections)

定义对象

  1. 字面量
  2. 构造函数
  1. var obj = {
  2. prop: 'value',
  3. fn: function(){}
  4. };
  5. var date = new Date();

构造函数

构造函数和普通函数并没有区别,使用 new 关键字调用就是构造函数,使用构造函数可以 实例化 一个对象

函数的返回值有两种可能

  1. 显式调用 return 返回 return 后表达式的求值
  2. 没有调用 return 返回 undefined
  1. function People(name, age) {
  2. this.name = name;
  3. this.age = age;
  4. }
  5. var people = new People('Byron', 26);

构造函数返回值

  1. 没有返回值
  2. 简单数据类型
  3. 对象类型

前两种情况构造函数返回构造对象的实例,实例化对象正是利用的这个特性

第三种构造函数和普通函数表现一致,返回 return 后表达式的结果

prototype

  1. 每个函数都有一个 prototype 的对象属性,对象内有一个 constructor 属性,默认指向函数本身
  2. 每个对象都有一个 __proto__ 的属性,属相指向其父类型的 prototype
  1. function Person(name) {
  2. this.name = name;
  3. }
  4. Person.prototype.print = function () {
  5. console.log(this.name);
  6. };
  7. var p1 = new Person('Byron');
  8. var p2 = new Person('Casper');
  9. p1.print();
  10. p2.print();

this 和作用域

作用域可以通俗的理解

  1. 我是谁
  2. 我有哪些马仔

其中我是谁的回答就是 this

马仔就是我的局部变量

this 场景

普通函数

  1. 严格模式:undefined
  2. 非严格模式: 全局对象
    1. Node: global
    2. 浏览器: window

构造函数:对象的实例

对象方法:对象本身

call & apply

  1. fn.call(context, arg1, arg2, …, argn)
  2. fn.apply(context, args)
  1. function isNumber(obj) {
  2. return Object.prototype.toString.call(obj) === '[object Number]';
  3. }

Function.prototype.bind

bind 返回一个新函数,函数的作用域为 bind 参数

  1. function fn() {
  2. this.i = 0;
  3. setInterval(function () {
  4. console.log(this.i++);
  5. }.bind(this), 500)
  6. }
  7. fn();

() => {}

箭头函数是 ES6 提供的新特性,是简写的 函数表达式,拥有词法作用域和 this

  1. function fn() {
  2. this.i = 0;
  3. setInterval(() => {
  4. console.log(this.i++);
  5. }, 500)
  6. }
  7. fn();

继承

在 JavaScript 的场景,继承有两个目标,子类需要得到父类的:

  1. 对象的属性
  2. 对象的方法
  1. function inherits(child, parent) {
  2. var _proptotype = Object.create(parent.prototype);
  3. _proptotype.constructor = child.prototype.constructor;
  4. child.prototype = _proptotype;
  5. }
  6. function People(name, age) {
  7. this.name = name;
  8. this.age = age;
  9. }
  10. People.prototype.getName = function () {
  11. return this.name;
  12. }
  13. function English(name, age, language) {
  14. People.call(this, name, age);
  15. this.language = language;
  16. }
  17. inherits(English, People);
  18. English.prototype.introduce = function () {
  19. console.log('Hi, I am ' + this.getName());
  20. console.log('I speak ' + this.language);
  21. }
  22. function Chinese(name, age, language) {
  23. People.call(this, name, age);
  24. this.language = language;
  25. }
  26. inherits(Chinese, People);
  27. Chinese.prototype.introduce = function () {
  28. console.log('你好,我是' + this.getName());
  29. console.log('我说' + this.language);
  30. }
  31. var en = new English('Byron', 26, 'English');
  32. var cn = new Chinese('色拉油', 27, '汉语');
  33. en.introduce();
  34. cn.introduce();

ES6 class 与继承

  1. "use strict";
  2. class People{
  3. constructor(name, age){
  4. this.name = name;
  5. this.age = age;
  6. }
  7. getName(){
  8. return this.name;
  9. }
  10. }
  11. class English extends People{
  12. constructor(name, age, language){
  13. super(name, age);
  14. this.language = language;
  15. }
  16. introduce(){
  17. console.log('Hi, I am ' + this.getName());
  18. console.log('I speak ' + this.language);
  19. }
  20. }
  21. let en = new English('Byron', 26, 'English');
  22. en.introduce();

语法

label statement

  1. loop:
  2. for (var i = 0; i < 10; i++) {
  3. for (var j = 0; j < 5; j++) {
  4. console.log(j);
  5. if (j === 1) {
  6. break loop;
  7. }
  8. }
  9. }
  10. console.log(i);

语句与表达式

  1. var x = { a:1 };
  2. { a:1 }
  3. { a:1, b:2 }

立即执行函数

  1. ( function() {}() );
  2. ( function() {} )();
  3. [ function() {}() ];
  4. ~ function() {}();
  5. ! function() {}();
  6. + function() {}();
  7. - function() {}();
  8. delete function() {}();
  9. typeof function() {}();
  10. void function() {}();
  11. new function() {}();
  12. new function() {};
  13. var f = function() {}();
  14. 1, function() {}();
  15. 1 ^ function() {}();
  16. 1 > function() {}();

高阶函数

高阶函数是把函数当做参数或者返回值是函数的函数

回调函数

  1. [1, 2, 3, 4].forEach(function(item){
  2. console.log(item);
  3. });

闭包

闭包由两部分组成

  1. 函数
  2. 环境:函数创建时作用域内的局部变量
  1. function makeCounter(init) {
  2. var init = init || 0;
  3. return function(){
  4. return ++init;
  5. }
  6. }
  7. var counter = makeCounter(10);
  8. console.log(counter());
  9. console.log(counter());

典型错误

  1. for (var i = 0; i < doms.length; i++) {
  2. doms.eq(i).on('click', function (ev) {
  3. console.log(i);
  4. });
  5. }

  1. for (var i = 0; i < doms.length; i++) {
  2. (function (i) {
  3. doms.eq(i).on('click', function (ev) {
  4. console.log(i);
  5. });
  6. })(i);
  7. }

惰性函数

  1. function eventBinderGenerator() {
  2. if (window.addEventListener) {
  3. return function (element, type, handler) {
  4. element.addEventListener(type, hanlder, false);
  5. }
  6. } else {
  7. return function (element, type, handler) {
  8. element.attachEvent('on' + type, handler.bind(element, window.event));
  9. }
  10. }
  11. }
  12. var addEvent = eventBinderGenerator();

柯里化

一种允许使用部分参数生成函数的方式

  1. function isType(type) {
  2. return function(obj){
  3. return Object.prototype.toString.call(obj) === '[object '+ type +']';
  4. }
  5. }
  6. var isNumber = isType('Number');
  7. console.log(isNumber(1));
  8. console.log(isNumber('s'));
  9. var isArray = isType('Array');
  10. console.log(isArray(1));
  11. console.log(isArray([1, 2, 3]));
  1. function f(n) {
  2. return n * n;
  3. }
  4. function g(n) {
  5. return n * 2;
  6. }
  7. console.log(f(g(5)));
  8. function pipe(f, g) {
  9. return function () {
  10. return f.call(null, g.apply(null, arguments));
  11. }
  12. }
  13. var fn = pipe(f, g);
  14. console.log(fn(5));

尾递归

  1. 尾调用是指某个函数的最后一步是调用另一个函数
  2. 函数调用自身,称为递归
  3. 如果尾调用自身,就称为尾递归

递归很容易发生"栈溢出"错误(stack overflow)

  1. function factorial(n) {
  2. if (n === 1) return 1;
  3. return n * factorial(n - 1);
  4. }
  5. factorial(5) // 120

但对于尾递归来说,由于只存在一个调用记录,所以永远不会发生"栈溢出"错误

  1. function factorial(n, total) {
  2. if (n === 1) return total;
  3. return factorial(n - 1, n * total);
  4. }
  5. factorial(5, 1) // 120

柯里化减少参数

  1. function currying(fn, n) {
  2. return function (m) {
  3. return fn.call(this, m, n);
  4. };
  5. }
  6. function tailFactorial(n, total) {
  7. if (n === 1) return total;
  8. return tailFactorial(n - 1, n * total);
  9. }
  10. const factorial = currying(tailFactorial, 1);
  11. factorial(5) // 120

反柯里化

  1. Function.prototype.uncurry = function () {
  2. return this.call.bind(this);
  3. };

push 通用化

  1. var push = Array.prototype.push.uncurry();
  2. var arr = [];
  3. push(arr, 1);
  4. push(arr, 2);
  5. push(arr, 3);
  6. console.log(arr);

JavaScript 精粹的更多相关文章

  1. JavaScript精粹

    序:好书是需要不断品读的!再读语言精粹,顺便做点笔记. 1.NaN是一个数值,它表示一个不能产生正常结果的运算结果.NaN不等于任何值,包括它自己.检测是否为NaN:  isNaN(number). ...

  2. JS获得css样式即获得元素的计算样式(《Javascript精粹修订版》书摘)

    为HTML文档中的元素指定样式可以有3种方法:使用内嵌样式.在页面的head中对Style进行声明以及外部 CSS 文件.元素的视觉效果往往是由上述3种方式的结合或者其中某一种方式来确定的,但是内嵌样 ...

  3. JavaScript代码检查工具 — JSHint

    静态代码检查是开发工作中不可缺少的一环,毕竟对于程序化的工作人的眼睛是不可靠的,更何况是自己的眼睛看自己的代码.即使最后的运行结果通过,但可能存在一些未定义的变量.定义了但最后没用过的变量.分号有没有 ...

  4. 深入浅出JavaScript函数 v 0.5

    本文的观点是建立在<JavaScript权威指南 6th Ed> <JavaScript高级编程 3th Ed> <JavaScript精粹 2th Ed>之上, ...

  5. JavaScript基本概念(一) v0.5

    摘要:先简单介绍ECMAScript的语法(如果有其他类C的经验,这个很好理解),接着介绍了ECMAScript的数据类型:Number.Boolean.String.Undefined和Null类型 ...

  6. javascript prototype __proto__区别

    An Object's __proto__ property references the same object as its internal [[Prototype]] (often refer ...

  7. JavaScript 再认识(一):Function调用模式对this的影响

    近来,学习了一下<JavaScript精粹>,读到了函数这章,理清了JavaScript中this在不同调用模式下的指向. 1.Function调用模式:Function是JavaScri ...

  8. 标 题: JavaScript真的要一统江湖了

    http://www.newsmth.net/nForum/#!article/Python/125347?p=4 标  题: JavaScript真的要一统江湖了 发信站: 水木社区 (Fri Se ...

  9. javascript prototype原型链的原理

    javascript prototype原型链的原理 说到prototype,就不得不先说下new的过程. 我们先看看这样一段代码: <script type="text/javasc ...

随机推荐

  1. 关于解决python线上问题的几种有效技术

    工作后好久没上博客园了,虽然不是很忙,但也没学生时代闲了.今天上博客园,发现好多的文章都是年终总结,想想是不是自己也应该总结下,不过现在还没想好,等想好了再写吧.今天写写自己在工作后用到的技术干货,争 ...

  2. nw.js桌面软件开发系列 第0.1节 HTML5和桌面软件开发的碰撞

    第0.1节 HTML5和桌面软件开发的碰撞 当我们谈论桌面软件开发技术的时候,你会想到什么?如果不对技术本身进行更为深入的探讨,在我的世界里,有这么多技术概念可以被罗列出来(请原谅我本质上是一个Win ...

  3. junit4进行单元测试

    一.前言 提供服务的时候,为了保证服务的正确性,有时候需要编写测试类验证其正确性和可用性.以前的做法都是自己简单写一个控制层,然后在控制层里调用服务并测试,这样做虽然能够达到测试的目的,但是太不专业了 ...

  4. zookeeper源码分析之二客户端启动

    ZooKeeper Client Library提供了丰富直观的API供用户程序使用,下面是一些常用的API: create(path, data, flags): 创建一个ZNode, path是其 ...

  5. 最长回文子串-LeetCode 5 Longest Palindromic Substring

    题目描述 Given a string S, find the longest palindromic substring in S. You may assume that the maximum ...

  6. [笔记]kubernetes 无法启动问题

    在启动kubernetes的时候报错误. ERROR: timed out for http://localhost:4001/v2/keys/ 原因是无法启动etcd, etcd 监听4001本地端 ...

  7. kali linux下的arp攻击

    这是我第一篇博客,写的不好请谅解 ____________________________(分割线)_______________________________ 在kali linux系统下自带工具 ...

  8. 在将 varchar 值 'xinpian' 转换成数据类型 int 时失败?

    把int类型的值修改为varchar类型的值

  9. SQL 数据优化索引建suo避免全表扫描

    首先什么是全表扫描和索引扫描?全表扫描所有数据过一遍才能显示数据结果,索引扫描就是索引,只需要扫描一部分数据就可以得到结果.如果数据没建立索引. 无索引的情况下搜索数据的速度和占用内存就会比用索引的检 ...

  10. 在Ubuntu下搭建Spark群集

    在前一篇文章中,我们已经搭建好了Hadoop的群集,接下来,我们就是需要基于这个Hadoop群集,搭建Spark的群集.由于前面已经做了大量的工作,所以接下来搭建Spark会简单很多. 首先打开三个虚 ...