说明:

此摘要笔记系列是我最近看《JavaScript高级程序设计(第3版)》随手所记。
里面分条列举了一些我认为重要的、需要记下的、对我有帮助的点,是按照我看的顺序来的。
摘要笔记本身没有系统性,没有全面性可言,写在这里供有一定基础的前端开发者参考交流。
里面的知识点、例子大部分来源于本书,或者延伸出来的,都经过我的测试是对的,但是没办法保证100%正确,如果有人看到错误的地方,希望指出来,谢谢。


1. Math 对象

Math.E // 2.718281828459045 自然对数的底数,即常量 e 的值
Math.PI // 派的值 3.141592653589793
Math.min() // 一组数中的最小值
Math.max() // 一组数中的最大值
// 取得数组中最大值的办法
var arr = [10, 15, 8, 23]
var max = Math.max.apply(Math, arr)
console.log(max) // 23
Math.ceil() // 向上取整
Math.floor() // 向下取整
Math.round() // 四舍五入取整
Math.random() // 返回大于等于0小于1的随机数
Math.abs(num) // 返回 num 的绝对值
Math.log(num) // 返回 num 的自然对数
Math.pow(num, power) // 返回 num 的power次幂
Math.sqrt(num) // 返回 num 的平方根
Math.cos(x) // 返回 x 的余弦值
Math.sin(x) // 返回 x 的正弦值
Math.tan(x) // 返回 x 的正切值
Math.acos(x) // 返回 x 的反余弦值
Math.asin(x) // 返回 x 的反正弦值
Math.atan(x) // 返回 x 的反正切值
Math.atan2(y, x) // 返回 y / x 的反正切值

2. 深度拷贝对象的简单高效办法

var rel = JSON.parse(JSON.stringify(obj))

3. Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象Object.assign(target, ...sources),如:

var obj = {a: 1}
var copy = {b: 3}
var rel = Object.assign(b, obj)
console.log(rel) // {a: 1, b: 3}
copy === rel // true

假如需要深度拷贝的话,仍旧需要使用别的而不是本方法。因为 Object.assign() 拷贝的是在 source 里是对象的属性的引用而不是对象本身。如:

var a = {b: 3, c: {e: 5}}
var rel = Object.assign({}, a)
console.log(rel.c.e) // 5
a.c.e = 8
console.log(rel.c.e) // 8
// 合并 objects
var o1 = {a: 2}
var o2 = {b: 5}
var o3 = {c: 8}
var rel = Object.assign(o1, o2, o3)
console.log(rel) // {a: 2, b: 5, c: 8}
console.log(o1) // {a: 2, b: 5, c: 8}
rel === o1 // true
// 继承属性和不可枚举属性是不能拷贝的
// 原始类型会被包装为 object

4. 对象的属性

ECMAScript 中有两种属性:数据属性和访问器属性

a. 数据属性:数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有4个描述其行为的特性。
[[Configurable]]: 能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。默认 true 。
[[Enumerable]]: 能否通过 for-in 循环返回属性。默认 true 。
[[Writable]]: 能否修改属性的值。默认 true 。
[[Value]]: 包含这个属性的数据值。读取属性的时候从这个位置读;写入属性值的时候,把新值保存在这个位置。默认值 undefined 。

要修改属性默认的特性,需要通过 es5 的 Object.defineProperty() 方法。这个方法接受三个参数,属性所在的对象,属性的名字和一个描述符对象。
其中,描述符 (descriptor) 对象的属性必须是:configurable, enumerable, writable, value. 设置其中一个或多个值,可以修改对应的特性值。如:

var person = {}
Object.defineProperty(person, 'name', {
  writable: false,
  value: 'abc'
})
person.name // 'abc'
person.name = 'wfc' // 严格模式下会报错
person.name // 'abc'

在调用 Object.defineProperty() 方法时,如果不指定,configurable, writable, enumerable 的默认值都是 false。

可以多次调用 Object.defineProperty() 来修改同一个属性,但是在把 configurable 特性设置为 false 之后,
就只能把 writable 从 true 改成 false,其它设置都会报错。

b. 访问器属性

访问器属性不包含数据值,它们会包含一对 getter setter 函数(都不是必须的)。在读取访问器属性时,会调用 getter 函数,这个函数负责返回有效的值;
在写入访问器属性时,会调用 setter 函数并传入新值,这个函负责决定如何处理数据。访问器属性有如下4个特性:

[[Configurable]]: 表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。
对于直接在对象上定义的属性,默认值 true 。
[[Enumerable]]: 表示能否通过 for-in 循环返回属性。对于直接在对象上定义的属性,默认值 true 。
[[Get]]: 在读取属性时调用的函数。默认值 undefined 。
[[Set]]: 在写入属性时调用的函数。默认值 undefined 。

访问器属性不能直接定义,必须使用 Object.defineProperty() 来定义。如:

var book = {
  _year: 2016,
  edition: 1
}
Object.defineProperty(book, 'year', {
  get: function () {
    return this._year
  },
  set: function (newValue) {
    this.edition += 1
    this._year = newValue
  }
})
book.edition // 1
book.year = 2017
book.edition // 2

不必要同时指定 getter setter , 只指定 getter 意味着属性不能写,只指定 setter 意味着属性不能读

// 支持 Object.defineProperty() 的浏览器 IE 9+,Firefox 4+, Safari 5+, Opera 12+, Chrome

5. Object.defineProperties() 可以通过描述符一次定义多个属性。这个方法接受两个参数,第一个参数是要添加和修改其属性的对象,

第二个参数是描述符。如:

var book = {}
Object.defineProperties(book, {
  _year: {
    value: 2016,
    writable: true
  },
  edition: {
    value: 1,
    writable: true
  },
  year: {
    get: function () {
      return this._year
    },
    set: function (value) {
      this._year = value
      this.edition += 1
    }
  }
})
// 支持 Object.defineProperties() 的浏览器 IE 9+,Firefox 4+, Safari 5+, Opera 12+, Chrome

6. Object.getOwnPropertyDescriptor() 可以取得指定属性的描述符。接受两个参数,属性所在对象,属性名称。

只能取得实例属性的描述符,要取得原型对象的描述符,要在原型对象上调用这个方法。
如上例中的 book :

Object.getOwnPropertyDescriptor(book, '_year') // {configurable: false, enumerable: false, writable: true, value: 2016}
var rel = Object.getOwnPropertyDescriptor(book, 'year')
console.log(rel)
// {
//   configurable: false,
//   enumerable: false,
//   get: function () {
  //   return this._year
  // },
  // set: function (value) {
  //   this._year = value
  //   this.edition += 1
  // }
// }
typeof rel.get // 'function'
// 支持 Object.getOwnPropertyDescriptor() 的浏览器 IE 9+,Firefox 4+, Safari 5+, Opera 12+, Chrome

7. 关于 OO

function Person (name, age) {
  this.name = name
  this.age = age
  this.sayName = function () {
    console.log(this.name)
  }
}
var ming = new Person('ming', 13)

Person.prototype.constructor === Person // true
ming.constructor === Person // true
Person.constructor === Function // true
Function.constructor === Function // true
Function instanceof Function // true
Function instanceof Object // true

Person.prototype.sayHello = function () {
  console.log('hello')
}
ming.sayHello() // 'hello'
ming.__proto__.constructor === Person // true
ming.__proto__ === Person.prototype // true

8. 构造函数

构造函数与其它函数唯一的区别在于调用方式的不同,不存在定义构造函数的特殊语法。如果不通过 new 操作符来调用,那它跟普通函数没有区别。如上面的例子:

var li = new Person('li', 15)
li.sayName() // 'li'

Person('yang', 18)
window.sayName() // 'yang'

var o = {}
Person.call(o, 'wang', 20)
o.sayName() // 'wang'

9. 原型模式

我们创建的每个函数都有一个 prototype(原型) 属性,这个属性是一个指针,指向一个对象,这个对象的用途是包含所有实例共享的属性和方法。如:

function Person (name, age) {
  this.name = name
  this.age = age
  this.sayName = function () {
    console.log(this.name)
  }
}
Person.prototype.sayHello = function () { console.log('hello') }
var ming = new Person('ming', 12)
var li = new Person('li', 15)
ming.sayHello === li.sayHello // true
ming.sayHello === Person.prototype.sayHello // true

可以通过 isPrototypeOf() 方法来确定对象直接是否存在 原型-实例 关系,如:

Person.prototype.isPrototypeOf(ming) // true

es5 新增方法 Object.getPrototypeOf() 这个方法返回实例的 proto 即实例的构造函数的原型的值,如:

Object.getPrototypeOf(ming) === Person.prototype
// 支持 Object.getPrototypeOf() 的浏览器 IE 9+,Firefox 3.5+, Safari 5+, Opera 12+, Chrome

10. hasOwnProperty() 方法可以检测一个属性是存在于实例中,还是原型中。这个方法只在属性存在于实例中时才返回 true 。in 操作符单独使用,只要能够通过该对象访问给定属性就返回 true, 如上例:

ming.hasOwnProperty('sayHello') // false
'sayHello' in ming // true
ming.hasOwnProperty('sayName') // true
'sayName' in ming // true

ming.sayHello = function () {
  console.log('hello in self')
}
ming.hasOwnProperty('sayHello') // true
'sayHello' in ming // true
delete ming.sayHello
ming.hasOwnProperty('sayHello') // false
'sayHello' in ming // true

ming.hasOwnProperty('sayHello1') // false
'sayHello1' in ming // false

即使将实例属性设置为 undefined / null , hasOwnProperty() in 这两个方法仍然返回 true

function hasPrototypeProperty (object, name) {
  return !object.hasOwnProperty(name) && name in object
}

for-in 循环返回的是所有能够通过对象访问的、可枚举的(enumerable: true)属性,既包括实例中的属性又包括原型中的属性。

11. es5 的 Object.keys() 方法,接受一个对象作为参数,返回实例上所有可枚举属性的字符串组成的数组。如:

var Person = function () {}
Person.prototype.sayHello = function () {
  console.log('hello')
}
var ming = new Person()
ming.name = ming
Object.keys(ming) // ["name"]

Object.getOwnPropertyNames() 方法可以得到所有实例属性,包括不可枚举的。
// 支持 Object.keys() 和 Object.getOwnPropertyNames() 的浏览器 IE 9+,Firefox 4+, Safari 5+, Opera 12+, Chrome

wfc_666
643 声望31 粉丝

专注全栈