javascript红宝书学习(一)

106 阅读6分钟

1,javascript的组成

1,核心(ECMAScript):由 ECMA-262 定义并提供核心功能
2,文档对象模拟器(DOM):提供与网页内容交互的方法和接口
3,浏览器对象模拟器(BOM):提供与浏览器交互的方法和接口。

image.png

关于ECMAScript

ECMAScript,即 ECMA-262 定义的语言,Web 浏览器只是 ECMAScript 实现可能存在的一种宿主环境(host environment)。宿主环境提供 ECMAScript 的基准实现和与环境自身交互必需的扩展,包含部分
语法
类型
语句
 关键字
 保留字
 操作符
 全局对象

关于dom

DOM 通过创建表示文档的树,让开发者可以随心所欲地控制网页的内容和结构。使用 DOM API, 可以轻松地删除、添加、替换、修改节点。
规范由:DOM Core和DOM HTML

关于BOM

BOM 主要针对浏览器窗口和子窗口(frame),不过人们通常会把任何特定于浏览器的 扩展都归在 BOM 的范畴内。比如,下面就是这样一些扩展
 弹出新浏览器窗口的能力;
 移动、缩放和关闭浏览器窗口的能力;
 navigator 对象,提供关于浏览器的详尽信息;
 location 对象,提供浏览器加载页面的详尽信息;
 screen 对象,提供关于用户屏幕分辨率的详尽信息;
 performance 对象,提供浏览器内存占用、导航行为和时间统计的详尽信息;
 对 cookie 的支持;
 其他自定义对象,如 XMLHttpRequest 和 IE 的 ActiveXObject。

2,基础语法学习

1,关于变量

var 在 ECMAScript 的所有版本中都可以使用,而 const 和 let 只能在 ECMAScript 6 及更晚的版本中使用。
1,关于var的作用域
使用 var 操作符定义的变量会成为包含它的函数的局部变量,也就是在方法体通过var创建的变量,方法外是无法访问和使用的。

 function test() {
    var message = "hi"; // 局部变量 
    }
    test();
    console.log(message); // 报错

2,关于let的声明

let的作用域是基于块作用域,而var的作用域是基于函数的

if (true) {
  let age = 26;
  console.log(age); // 有定义
}
console.log(age);  // 没有定义

let不允许在一个块作用域两次定义

if (true) {
  let age = 26;
  let age = 26;  // SyntaxError
  console.log(age); 
}

在for循环的遍历中,如果出现异步的方式进行声明,var会导致有问题,正常理解用var应该打印0,1,2,3,4。实际上会打印5,5,5,5,5
原因:是因为在退出循环时,迭代变量保存的是导致循环退出的值。在之后执行超时,逻辑时,所有的 i 都是同一个变量,因而输出的都是同一个最终值。

    for (var i = 0; i < 5; ++i) {
    setTimeout(() => console.log(i), 0)
    }      

3,关于const声明

const 的行为与 let 基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量,且 尝试修改 const 声明的变量会导致运行时错误。其实可以理解为const何final很像

const age = 26;  
age = 36; // TypeError: 给常量赋值,报错
// const 也不允许重复声明  
const name = 'Matt';  
const name = 'Nicholas'; // SyntaxError

总结 const,let,var

var的作用域是基于函数的,很容易造成问题,在ES6后,尽量使用const和let,优先使用const,如果当前的变量有变化的话要用let。

数据类型

ES6后,一共包含7种数据类型,Undefined、Null、Boolean、Number、 String 和 Symbol。6个基础,还有一种复杂数据类型叫 Object。
 "undefined"表示值未定义;
 "boolean"表示值为布尔值;
 "string"表示值为字符串;
 "number"表示值为数值;:判断是否为数值的(isNaN())
 "object"表示值为对象(而不是函数)或 null;
 "function"表示值为函数;
 "symbol"表示值为符号

3,变量,作用域,内存

1,原始值和引用值

1,原始值就是最简单的数据,引用值:多个值构成的对象
2,原始值复制到新的变量上,是两个值。这里面num1默认为5,num2会复制一个新值,虽然也是5,但是是两个值

    let num1 = 5;
    let num2 = num1;

3,关于引用传递,obj1和obj2是指向同一个对象的,所以obj2是可以获取到name的值

let obj1 = new Object();
let obj2 = obj1;
obj1.name = "Nicholas";
console.log(obj2.name); // "Nicholas"

2,传递参数

基础数据类型传递,其实就是值的复制,可以通过下面发现,count是复制的一个值传递,如果count+10,不会影响命名的count的值

function addCount(count){
    count+10;
}
let count = 10;
addCount(count);
console.log(count); //返回值为10

对象间的引用传递也是基于值传递的,可以发现在作用域内(setName方法),设置的obj新创建一个对象设置name为lisi,但是打印出来的还是zhangsan,说明传递的是obj这个对象的值,而不是引用传递。并且setName执行完成后,对象则会被销毁

function setName(obj){
    obj.name = "zhangsan";
    obj = new Object();
    obj.name = "lisi";
}
let obj = new Object();
setName(obj);
console.log(obj) // 返回{name: 'zhangsan'}

typeof判断基础数据类型的值,对象则用instanceof进行判断

3,内存管理

1,首先垃圾回收方法采用标记清理法。
2,其次在管理内存的时候,当使用v8引擎时,每创建一个类,会有对应的 隐藏类
3,所以基于性能考虑在创建对象是,最好要共享隐藏类。(V8 在将解释后的 JavaScript 代码编译为实际的机器码时会利用“隐藏类”。)

function persion(){
    this.name = 'zhangsan';
}
// 此时,p1和p2是用一个隐藏类型
let p1 = persion();
let p2 = persion();
// 当p2增加属性时,会发现p1和p2不是同一个构造函数,导致需要创建一个隐藏类去监控它
p2.age = 19;
// 所以最好的办法就是在构造器的时候,提前创建好对应的函数
function persion(age){
    this.name = 'zhangsan';
    this.age = age;
}
let p1 = persion();
let p2 = persion(19);

4,最佳实践方式,在不需要用的对象或者属性时,及时设置为null

p1.age = null;
或者:p1 = null;

4,内存泄漏

1,声明全局变量容易导致内存的泄漏,可以得知window本身不被清理,就会永远占用着,解决方法也很简单,增加var,let,const的命令即可。

// 此时的name为全局变量,既可以使用window.name进行获取内容
function setName(){
    name = "lisi";
}
console.log(window.name); // lisi;

2,定时器会造成setInterval方法,只有定时执行,就会不进行收回当前内容
3,使用 JavaScript 闭包很容易在不知不觉间造成内存泄漏

let outer = function() { 10 let name = 'Jake';
return function() {
     return name;
  };
};

4,基本引用类型

先空着

5,集合引用类型

1,Object
2,Array:数组几组创建方式

    let colors = new Array();
    let colors = new Array(20);
    let colors = new Array("red", "blue", "green");
    // 可以通过栈的方式进行获取
    colors.push("black");
    let item = colors.pop(); // 获取的是black
    let queue = colors.shift();
    console.log(queue); // 获取red
    colors.unshift("white");// 在数组头部增加white
    colors.reverse(); // 数组反向排序
    colors.sort(); // 数组正向排序

3,map的学习,关于选择方面:map的删除和插入性能更佳。如果量较大可以考虑用map.

// 初始化
const m1 = new Map([
      ["key1", "val1"],
      ["key2", "val2"],
      ["key3", "val3"]
]);
// 也可以传入空
const m1 = new Map();
// 通过set的方式进行添加
m1.set("name","zhangsan").set("age,"lisi");
// 使用hash或者get的方法进行查找
m1.get("name");
m1.has("name");
// delete和clear进行删除,delete是删除某一个key,clear是删除所有
m1.delete("name");
m1.clear();
console.log(m1.size()); // 0
// 与obejct不同,map可以插入任意类型的key
let function = function() {};
m1.set(function,"function");

4,set的学习和weakSet