JavaScript权威指南前篇内容

107 阅读7分钟

初读js权威指南犀牛书

1. 目录

  • 第三章-值、类型、变量
  • 第四章-表达式与操作符
  • 第五章-语句
  • 第六章-对象
  • 第十二章-迭代器与生成器

第三章-值、类型、变量

  • 对象到原始值的转换
/**
 * 结论
 *
 * 两个比较类似的方法
 * toString()
 * valueOf()
 *
 * toString: 将返回对象的字符串表示;
 *                                             5 ==> '5'
 *                                         'abc' ==> 'abc'
 *                                     [1, 2 ,3] ==> '1,2,3'  数组的每个元素将转换为字符串,在使用逗号分隔符将它们连接起来
 *                    { name: '杨志文', age: 18 } ==> '[object Object]'
 *                                       函数     ==>  '源码的字符串表示'
 *
 *           这种 { } 对象除外,它将表示为 '[object Object]' 这个字符串
 *
 *
 * valueOf: 大体可以认为把对象转换为代表对象的原始值 默认情况下 返回对象本身 (数据类型 log打印的表现形式)
 */
 
const bool = new Boolean(true);
console.log(bool);
console.log(bool.toString());
console.log(bool.valueOf());

const string = new String("asd");
console.log(string);
console.log(string.toString());
console.log(string.valueOf());

const string2 = new String([
  1,
  2,
  [32131],
  { name: "sda" },
  3,
  (a) => {
    return a;
  },
]);
console.log(string2);
console.log(string2.toString());
console.log(string2.valueOf());

const num = new Number(321321312);
console.log(num);
console.log(num.toString());
console.log(num.valueOf());

const arr = [
  1,
  2,
  [32131],
  { name: "sda" },
  3,
  (a) => {
    return a;
  },
];
console.log(arr);
console.log(arr.toString());
console.log(arr.valueOf());

function fn() {
  console.log(1231);
}
console.log(fn);
console.log(fn.toString());
console.log(fn.valueOf());

const obj = {
  name: "杨志文",
  age: 18,
  likes: ["苹果", "香蕉"],
};
console.log(obj);
console.log(obj.toString());
console.log(obj.valueOf());

console.log(Number([1])); // 1
console.log(Number('1,2,3')); // NaN
console.log(parseInt('1,2,3')); // 1
console.log(Number('')); // 0
console.log(Number(['bbc'])); // NaN
  • 变量声明
/**
 * 通过 var 关键词 声明的
 *  变量提升
 *  实现为全局对象的属性
 *  不可删除
 *
 *
 * 未经关键字 var let const 声明的变量
 *  全局变量,可以删除
 */


// 不可删除
var abc = "abc";
console.log(window);
delete window.abc;
console.log(window);

function fn() {
  // 可以删除
  a = "a";
}
fn()
delete window.a;

console.log(window);

第五章-语句

  • for-in循环
/**
 * for-in循环 后面可以是任意对象,这个语法是一开始就有的,for-of是新增的
 */

// for( variable in object )
//     statement

/**
 * 执行for-in循环时,会求值 object 表达式 如果为 nudefined 或者 null 会跳过循环转移到下一个语句
 * 在每次迭代前,都会求值 variable 表达式,并将属性名字赋值给他
 * 
 * for-in循环不会枚举对象的所有属性,比如符号属性
 *  对于名字是字符串的属性,它只会遍历可枚举的属性,js内置方法不可枚举
 *  继承的可枚举属性也可以被for-in循环枚举 所以这样子 用for-in循环可能会出现意外
 *  好的选择是 基于 Object.keys()的for-of循环
 * 
 * 如果 for/in循环的循环体删除一个尚未被枚举的属性,则该属性不会再被枚举
 * 如果循环体在对象上又定义了新属性,则新属性可能会也可能不会被枚举(关于for-in对象枚举属性的顺序)
 */
  • for-of循环
/**
 * for of 循环 专门用于可迭代对象
 *      现在只需要知道 数组,字符串,集合,映射都是可迭代的就行,他们都是一组或者一批元素可以使用 for-of
 * 注意:
 *      数组的迭代是实时的,在每次执行循环体之前,都会把数组的下一个元素赋值给元素变量,因此在循环体内 push语句,会无限循环
 * 
 * 常规对象 默认是不可迭代的
 *      使用 for-of会报错,因此可以使用for-in 或者Object.keys()/values()/entries()
 * 
 * 注意:
 *      这个不是实时的
 */

第六章-对象

  • 继承
/**
 * 属性赋值 会查询原型链只为确定是否允许赋值
 * 注意:
 * 如果o继承了一个名为x的只读属性,则不允许赋值,不过,如果允许赋值,则只会在原始对象上创建或者设置属性,而不会修改原型链中的对象
 * 查询属性时会用到原型链,而设置属性时不影响原型链是一个重要的js特性
 * 
 * 属性赋值要么失败要么在原始对象上创建或设置属性的规则有一个例外。
 *      如果o继承了属性x,而该属性是一个通过设置方法定义的访问器属性,那么就会调用,该设置方法而不会在o上创建新的属性x,要注意,会在对象o上而不是
 * 在定义该属性的原型对象上掉用设置方法。以你如果这个设置方法定义了别的属性,那也会在o上定义同样的属性,但容然不会修改原型链
 */

const obj = {};
console.log(obj);
Object.defineProperty(obj, "name", {
  value: "yzw",
  configurable: false,
});
console.log(obj);

const newObj = Object.create(obj);
newObj.age = 18;
newObj.name = "杨志文"; // 赋值失败
console.log(newObj.name);
console.log(newObj);

属性

  • 属性测试
/**
 * 属性测试
 * 
 * in 操作符 要求左边是一个属性名,右边是一个对象,如果对象有包含相应名字的自有属性或继承属性,将返回true (可枚举)
 * 
 * hasOwnProperty() 方法,用于测试对象是否有给定名字的属性,对继承的属性返回 false
 * 
 * propertyIsEnumerable()方法细化了hasOwnProperty()方法, 如果该属性是自有属性且这个属性的 enumerable特性为true,这个方法会返回true
 */
  • 属性枚举
/**
 * 属性枚举
 * 
 * in 指定对象的每个可枚举 自有属性或继承属性
 * 
 * Object.keys()  返回对象可枚举自有属性名的数组。 不包括 不可枚举属性,继承属性, 名字是符号的属性
 * 
 * Object.getOwnPropertySymbols() 返回名字是符号的自有属性 无论是否可枚举
 * 
 * Object.getOwnPropertyNames() 与 Object.keys()类似,但也会返回不可枚举的自有属性,只要他们的名字是字符串
 * 
 * Reflect.ownKeys() 返回所有属性名 包括可枚举属性与不可枚举属性,以及字符串和符号属性
 */
  • 属性枚举顺序
/**
 * 属性枚举顺序
 * 
 * 先列出名字为非负整数的字符串属性,按照数值顺序从最小到最大,这条规则意味着数组和类数组对象属性会按照顺序被枚举
 * 
 * 在列出类数组索引的所有属性之后,在列出所有剩下的字符串的名字(包括看起来像负数或浮点数的名字)的属性,这些属性按照他们添加到对象的先后顺序列出,对于在对象字面量中定义的属性,按照他们在字面量中出现的顺序列出
 * 
 * 最后,名字为符号对象的属性按照他们添加到对象的先后顺序列出
 * 
 *      for-in循环的枚举顺序并不像上述枚举函数那么严格,但通常会按照上面描述的顺序枚举属性,然后在沿原型链上溯,以同样的顺序枚举每个原型对象的属性,
 *  不过要注意,如果已有同名属性被枚举过了,甚至有一个同名属性是不可枚举的,那这个属性就不会枚举。
 */
const abc = Symbol("abc");
const obj = {
  "-100": "-100",
  hobbies: ["苹果"],
  [Symbol("abc")]: "Symbol('abc')",
  "-60": -60,
  name: "杨志文",
  age: 18,
  100: 100,
  0: 0,
};
obj[12] = '阿苏孤独啊事故'
console.log(obj);

console.log(Object.keys(obj));
for (const key in obj) {
    console.log(key);
}

// ['0', '12', '100', '-100', 'hobbies', '-60', 'name', 'age']

  • Object.creat()
/**
 *  Object.create()用于创建一个新对象,使用其第一个参数作为新对象的原型, 还可以接受第二个参数,用于描述新对象的属性,这个参数属于高级特性
 *  提示 如果 第一个参数为 null 该对象不会继承任何的东西,toString()都没有
 * 
 *  如果想创建一个 普通的控对象
 *  Object.create(Object。prototype)
 * 
 *  用途:
 *  Object.creat()的一个用途是防止对象被某个第三方库意外修改
 *  这种情况下,不要把对象直接传给库函数,而要传入一个继承自它的对象,
 *  如果函数读取这个对象的属性,可以读取到继承的属性,而如果它要设置这个对象的属性,则修改不会影响原始对象
 *
 * 
 */

第十二章-迭代器与生成器

  • 迭代器原理
// const person = ["章三", "莉丝", "王武"];
// console.log(person);
// console.log(person[Symbol.iterator]());
// const iterator = person[Symbol.iterator]();
// console.log(...iterator);
// for (let result = iterator.next(); !result.done; result = iterator.next()) {
//   console.log(result);
//   console.log(result.value);
// }

/**
 * Range类
 */

class Range {
  constructor(from, to) {
    this.from = from;
    this.to = to;
  }

  has(val) {
    return val >= this.from && val <= this.to;
  }

  toString() {
    return `${this.from}-${this.to}`;
  }

  // 迭代器
  [Symbol.iterator]() {
    let nextVal = this.from;
    let last = this.to;
    // 返回迭代器对象
    return {
      abc: "123,",
      // 迭代器对象 有一个 next 方法
      next() {
        // next方法返回 一个 done属性和value属性
        return {
          done: nextVal > last ? true : false,
          value: nextVal <= last ? nextVal++ : undefined,
        };
      },
      return() {
        console.log("提前退出");
        return {};
      },
      // 迭代器对象本身也可以迭代
      [Symbol.iterator]() {
        console.log(this);
        return this;
      },
    };
  }

  // 生成器
  [Symbol.iterator]() {
  }
}

const range = new Range(1, 10);
console.log(range);
console.log(range.has(1231));
console.log(range.has(10));
console.log(range.toString());
// }
const iterator = range[Symbol.iterator]();
console.log(iterator);
for (let result = iterator.next(); !result.done; result = iterator.next()) {
  if (result.value === 5) {
    break;
  }
  console.log(result.value);
  console.log(result);
}

  • 生成器原理
function* oneDigitPrimes() {
  yield 2;
  yield 3;
  yield 5;
  yield 7;
  yield 99;
}

let primes = oneDigitPrimes();
// 生成器有 Symbol.iterator 方法 因此也是可迭代的对象
let iterator = primes[Symbol.iterator]();
console.log(iterator);
console.log(primes);
// console.log([...primes]);
for (let key of primes) {
  console.log(key);
}
class Range {
  constructor(from, to) {
    this.from = from;
    this.to = to;
  }

  has(val) {
    return val >= this.from && val <= this.to;
  }

  toString() {
    return `${this.from}-${this.to}`;
  }

  // 生成器函数 让这个类的实例可迭代
  *[Symbol.iterator]() {
    for (let start = this.from; start <= this.to; start++) {
      yield start;
    }
  }
}
const range = new Range(1, 100);
console.log(range);
console.log([...range]);