Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

我所理解的 JavaScript #13

Open
bigggge opened this issue Oct 29, 2017 · 0 comments
Open

我所理解的 JavaScript #13

bigggge opened this issue Oct 29, 2017 · 0 comments
Labels

Comments

@bigggge
Copy link
Member

bigggge commented Oct 29, 2017

JavaScript 是一种动态的,基于原型多范式的脚本语言,支持面向过程面向对象函数式编程,命令式声明式的编程风格。比如 C 风格的过程式编程,包括大括号和复杂的 for 语句,以及不太明显的 Scheme/Lisp 风格的函数式编程。

//命令式
var girls = [];
for(var i = 0; i < schools.length; i++){
    girls.push(schools[i].girls)
}
//声明式
var girls = schools.map(s => s.girls);

JavaScript 是简单直接的,你不需要对编程有很多的了解就可以用它来完成工作。事实上,每个人的电脑里都安装了一个 JavaScript 解释器,只需要打开你的浏览器,在控制台输上一段 alert('hello world!'),你就已经在编写 JavaScript 了。

JavaScript 也是一门重要的语言,它与浏览器结合在一起,我们无时无刻不在享受 JavaScript 的魔力,从这里也能获知,JavaScript 是 GitHub 上最为流行的语言。

解释型与编译型

动态类型语言:动态类型语言是指在运行期间才去做数据类型检查的语言

静态类型语言:静态类型语言的数据类型是在编译期间检查的,也就是需要声明所有变量的数据类型

强类型语言:强制数据类型定义的语言

弱类型语言:数据类型可以被忽略的语言, 一个变量可以赋不同数据类型的值

编译型语言:在编译过程中生成目标平台的指令

解释型语言:在运行过程中才生成目标平台的指令

其实,现在已经不适合用解释型和编译型来区分一门语言了,不能说一种语言只能是解释或者只能是编译。比如 C 语言可以说是编译型语言,编译生成的目标文件(机器码)是针对特定 CPU 的。而 Java 虽然是非编译型的,却也有某种编译过程,它们编译生成的通常是平台无关的中间代码(字节码,*.class文件),而虚拟机( Java 虚拟机,JVM)在运行过程中将中间代码翻译成目标平台 (不同 CPU 平台) 的指令。

尽管 JavaScript 通常被认为是一门解释执行的语言,但事实上它也有编译。传统的 JavaScript 引擎是把 JavaScript 代码先编译为字节码,然后再通过解释器执行字节码。而新一代的 JavaScript 引擎为了提高性能,引入了 Java 虚拟机和 C++ 编译器中的众多技术,比如 V8 是运用 JIT (Just-in-time,即时编译) 技术,不通过解释器执行,而且直接编译成运行在 CPU 上的机器码,不过,就在几个月前, V8 新增了一个 Ignition 字节码解释器 ,将默认启动。具体可参考 V8 Ignition:JS 引擎与字节码的不解之缘

JavaScript 的优势

对象字面量

JavaScript 有非常强大的对象字面量表示法。通过列出对象的组成部分,就能创建对象。这种表示法也是 JSON 的灵感来源。

let person = {
  name: 'peter',
  age: 23
}

函数

函数可能是 JavaScript 中设计最出色的部分。函数是一等公民,这意味着可以把函数像其它值一样传递。 一个常见的用法是把匿名函数作为回调函数传递到异步函数中。

函数声明和函数表达式

// 函数声明
foo(); // 正常运行,因为foo在代码运行前已经被创建
function foo() {}

// 函数表达式
foo; // 'undefined'
foo(); // 出错:TypeError
var foo = function() {};

闭包

闭包的本质源自两点,词法作用域函数当作值传递,一个函数被当作值返回时,也就相当于返回了一个通道,这个通道可以访问这个函数词法作用域中的变量。我们可以通过闭包模拟私用变量的特性,也可以用来实现柯里化,一种多参数函数的方法。

const add = R.curry((a, b) => a + b)
add(1, 2) // => 3
const add1 = add(1)
add1(2) // => 3
add1(10) // => 11

高阶函数

高阶函数是指接受或者返回一个函数的函数。因为在 JavaScript 中函数是一等公民,所以高阶函数非常容易实现。比如原生的 Array.map , Array.filter 等方法。函数当做值传递,柯里化,高阶函数等都是 JavaScript 函数式编程的体现。

let numbers = [1, 5, 10, 15];
let doubles = numbers.map( x => x ** 2);

函数重载与重写

JavaScript 不能像其他语言 (如 Java) 一样,可以为一个函数编写两个定义,只要这两个定义的签名 (接受参数的类型和数量) 不同即可。得益于动态弱类型的特性,JavaScript 可以通过检查传入函数中参数的类型和数量,作出不同的反应,来模仿函数的重载。

另外,函数重写是被 JavaScript 原生支持的,对实例对象重写函数也不会影响原型链中的函数。

原型

原型 (prototype) 继承是一个有争议的特性,JavaScript 是唯一一个被广泛使用的基于原型继承的语言,如果你尝试对 JavaScript 使用类的设计模式,将会遇到困难。比如抽象类和接口。

在 Java 等面向类的语言中,使用抽象类也被称为继承,是一种强耦合设计,用来描述 is-a 关系,是对一种事物的抽象。而接口通常用来描述对象所共有的行为,是对行为的抽象,是一种 has-a 关系,可以用来实现组合。

接口和抽象类主要有两点作用:

  • 一是通过向上转型来隐藏对象的真正类型,体现对象的多态性。
  • 二是约定对象间的一些行为。

而 JavaScript 是弱类型的,弱类型意味着不需要利用抽象类或者接口对对象做向上转型,对象继承关系也无关紧要。除了基本数据类型外的其他对象都可以天生地被向上转型成 Object 类型。可以说,JavaScript的多态性是与生俱来的

var duck = new Animal()

在动态类型语言的面向对象设计中,鸭子类型的概念至关重要,利用鸭子类型的思想,我们不需要借助父类就能实现面向接口编程。例如,如果一个对象有length属性,可以通过下标存取属性,那么就能当做数组来使用,在

Object.prototype.toString.call([]) === '[object Array]' 被发现之前,我们经常用下面的方式来判断对象是否是一个数组

var isArray = function(obj) {
    return obj && 
      typeof obj === 'object' && 
      typeof obj.length === 'number' && 
      typeof obj.splice === 'function'
}

面向对象 (OOP) 其实是对事物本质的抽象,而 JavaScript 实现这种抽象的方法叫原型

   function Foo () {
        this.value = 12
      }

      Foo.prototype = {
        val: 'val',
        info: {
          name: 'peter',
          age: 15
        },
        method: function () {
          console.log('this.value', this.value)
          console.log('this.foo', this.foo)
        }
      }

      function Bar () {}
      Bar.prototype = new Foo()
      Bar.prototype.foo = 'Hello World'
      Bar.prototype.constructor = Bar

      var b1 = new Bar()
      var b2 = new Bar()
      b1.info.name = 'jack'
      b2.info.name = 'tom'
      b1.foo = 'foo1'
      b1.val = 'b1val'
      b2.value = 'b2value'
      b1.foo // foo1
      b1.val // b1val
      b1.info.name // tom
      b1.info.age // 15
      b1.method() // this.value 12 this.foo foo1
      b2.foo // Hello World
      b2.value // b2value
      b2.info.name // tom
      b2.info.age // 15
      b2.method() // this.value b2value this.foo Hello World

初始值

赋值后


可以看出,当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止。而对象的属性是无法修改其原型链中的同名属性,只会自身创建一个同名的属性并为其赋值。

原型继承的一个最大特性就是灵活,因为原型链上的每一个对象及原型链本身都是可以动态修改的。而类继承需要先定义好类和类之间的继承关系,而很难在运行时动态修改这些已经定义好的东西。

动态性

动态弱类型特性,动态混入,鸭子类型,动态修改原型或原型链,甚至修改原生对象的原型,这些特性都是 JavaScript 丰富表现力的源泉。Java 的一些设计模式虽然保证了代码的稳定性,但有时也禁锢了代码的灵活性。

JavaScript 的缺陷

全局变量

全局变量是在所有作用域中都可见的变量,会使得程序难以管理,不过我们也有缓解这个问题的办法,比如创建一个唯一的全局变量作为你应用的容器,或者使用闭包(内部函数总是可以访问其所在的外部函数中声明的参数和变量)来进行信息隐藏。

作用域

大多数语言都拥有块级作用域,在代码块内定义的变量在代码块外是不可见的。可喜的是,ES6新增了let关键字,它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

typeof

typeof的返回值几乎都是错误的,我们几乎不可能得到正确的结果。

Value               Class      Type
-------------------------------------
"foo"               String     string
new String("foo")   String     object
1.2                 Number     number
new Number(1.2)     Number     object
true                Boolean    boolean
new Boolean(true)   Boolean    object
[1,2,3]             Array      object
new Array(1, 2, 3)  Array      object
new Function("")    Function   function
/abc/g              RegExp     object (function in Nitro/V8)
new RegExp("meow")  RegExp     object (function in Nitro/V8)
{}                  Object     object
new Object()        Object     object

NaN

NaN === NaN // false

==

JavaScript 是弱类型语言,这就意味着,== 操作符会为了比较两个值而进行强制类型转换,而 === 操作符不会。

0 == "" // true
0 === "" // false

参考资料:

JavaScript高级程序设计

JavaScript语言精粹

你不知道的JavaScript

JavaScript设计模式与开发实践

JavaScript 秘密花园

MDN

程序的编译与解释有什么区别?

V8 引擎本用了什么编译技术,使得用 Javascript 与用 C 写出来的代码性能相差无几?

@bigggge bigggge added the JS label Oct 29, 2017
@ALetterSong ALetterSong locked and limited conversation to collaborators Oct 29, 2017
@ALetterSong ALetterSong unlocked this conversation Jan 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant