JavaScript基础知识

内存管理机制

内存可以分为三大区域:

  1. 代码区:存放程序编译后的机器指令

  2. 静态数据区:存放全变变量,静态变量,字符串常量(还可以细分,待了解)

  3. 动态数据区:理解比较粗糙

    • 栈:存放局部变量
    • 堆:存放具体的数据值

在速度上,寄存器>栈>堆。

程序运行的流程是怎样的(内存,CPU)?

前言

学习JavaScript的目的是为了爬虫逆向,所以本篇文章只会记录一些JavaScript基础语法(笔者不会的),逆向过程中常遇到的,或者笔者在学习过程中感到新奇的(因人而异)。由于笔者目前只熟悉python,在学习记录过程中,习惯会去对比两者的区别。

新鲜词汇

  1. 表达式:指一个为了得到返回值的计算式,凡是 JavaScript 语言中预期为值的地方,都可以使用表达式。

  2. 标识符:identifier 指的是用来识别各种值的合法名称,就是变量名或函数名

  3. 提升:提升作用于 变量声明和函数声明,通过提升,将声明移动到当前作用域顶端的默认行为,因此,JavaScript函数能在被声明之前调用。

    console.log(a);
    var a = 123;
    

    上面代码中,由于变量提升,并不会报错,此时a的值为undefined。
    注意:提升只进行声明操作,并没有初始化。(只有使用var定义的变量【作用域?】,function定义的函数才会被提升)

  4. 值传递和引用传递
    python是引用传递,java是值传递

  5. 逗号表达式:在赋值或者函数返回中可见,返回最后一个表达式的计算结果,在js脚本中使用,增加阅读难度。

  6. 区块:使用大括号,将多个相关的语句组合在一起,称为“区块”(block)。
    对于var命令来说,JavaScript 的区块不构成单独的作用域(scope)。

  7. 原生函数 function (){[native code]}:JavaScript 引擎提供的原生函数

  8. eval:eval没有自己的作用域,都在当前作用域内执行。如果使用严格模式,eval内部声明的变量,不会影响到外部作用域。
    eval的别名调用,作用域都是全局作用域

  9. 原始类型值:通过调用valueOf,接着调用toString

数据类型

Js中数据类型分为两种,基本类型和引用类型。String、Number、null、undefined、boolean都是基本类型,其他都是引用类型。对比python中的可变类型和不可变类型。

可以使用typeof,instanceof,Object.prototype.toString,可以确定一个值到底是什么类型。

  1. String

    • btoa():任意值转为 Base64 编码
    • atob():Base64 编码转为原来的值
    • \ 反斜杆,包括\uxxx,\x7a,\265
  2. Number

    • Number:强制转换,要比parseInt函数严格很多。基本上,只要有一个字符无法转成数值,整个字符串就会被转为NaN。
    • parseInt:将字符串转为整数(逐个转换),还可以用于进制转换。
    • parseFloat:将字符串转为浮点数
    • isNaN:用于判断NaN,NaN不和任何值相等包括它自己
  3. null/undefinded

    null == undefined  ==> true
    null === undefined ==> false
    Number(null)  ==> 0
    Number(undefined)  ==> NaN
    

    null == undefined 为true 这两者值是相等的,数据类型不等。
    null表示不存在,undefined表示未定义

  4. boolean

    在Js中,空数组[]、空对象{},都表示为True。

  5. Object:
    对象所有键都是字符串,如果是数值,会自动转为字符串

    • Object.keys():查看一个对象本身的所有属性
    • delete:删除指定属性,继承的属性不可删除
    • hasOwnProperty:判断是否为对象自身属性
    • for...in循环:用来遍历一个对象的全部属性,配合hasOwnProperty,可以得到所有对象自身
  6. Array:typeof运算符认为数组的类型就是对象,可以使用isinstance判断

    • arr.shift:把数组第一个元素删除,并返回该元素的值
    • length:length属性是可写的,清空数组的一个有效方法,就是将length属性设为0
    • 空位:
  7. map

  8. set

  9. function:

    • name:函数名称
    • length:返回函数预期传入的参数个数,即函数定义之中的参数个数
    • toString:返回一个字符串,内容是函数的源码

定义变量的三种方式

作用域:在ES6之前只分为全局作用域和函数作用域,ES6新增了块作用域。
局部:在函数内部定义的变量作用域为局部(只在函数体内存在),当函数执行完成,变量销毁。
全局:在函数外部声明的变量作用域为全局。
块作用域:{},在if语句块内,在循环体内,let定义变量,const定义常量

  • var:var定义的变量可以修改,不作用于块级作用域(在块内重新定义变量,会修改原来的值),如果不初始化,会输出undefined。

  • let:let作用于块级作用域,可以在块内重新定义var定义过的变量,而不会改变原来的值,如果不初始化,会输出undefined。

  • cons:const定义的变量不可以修改(对象属性,数组元素可以修改,但是该变量的指针已经绑定这个对象,不可修改,不可重新绑定其他对象,类似python中的不可变数据类型),必须初始化。作用于块级作用域

函数

1. 定义函数的三种方式

  1. 函数声明
function funname(param){
  return param;
}

使用函数声明定义的函数,不管函数处于js脚本什么位置,在js脚本运行时,该函数会被预先加载,也就是说,可以在函数被声明之前调用函数。

  1. 函数表达式--变量赋值
const funname = funtion(param){
  return param;
}
// 通过函数构造器 来定义函数
var haha = new Function('a','b','return a+b')
  1. 匿名函数
(function(param){return param}('hello world'))

2. 函数的参数

  1. arguments:接收所有参数
    由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。这就是arguments对象的由来。

    arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。

    虽然arguments很像数组,但它是一个对象。

  1. rest:接收除了定义之外的所有参数
function haha(a,b,...rest){
}
haha(1,2,3,4,5);
a = 1;
b = 2;
rest = [3,4,5];

3. 闭包

闭包的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在。

标准库

  1. Object
    JavaScript 的所有其他对象都继承自Object对象,即那些对象都是Object的实例。
    Object本身是一个函数,可以当作工具方法使用,将任意值转为对象
    静态方法,定义在object对象本身的属性方法。动态方法,定义在object.prototype对象上的。
    • Object.keys:返回该对象自身的(而不是继承的)所有属性名,只返回可枚举的属性。

    • Object.getOwnPropertyNames:还可返回不可枚举的属性

    • Object.getOwnPropertyDescriptor():获取某个属性的描述对象。

    • Object.defineProperty():通过描述对象,定义某个属性。

    • Object.defineProperties():通过描述对象,定义多个属性。

    • Object.create():该方法可以指定原型对象和属性,返回一个新的对象。

    • Object.getPrototypeOf():获取对象的Prototype对象。

    • Object.prototype.toString():返回当前对象对应的字符串形式。

    • Object.prototype.hasOwnProperty():判断某个属性是否为当前对象自身的属性,还是继承自原型对象的属性。

    • Object.prototype.isPrototypeOf():判断当前对象是否为另一个对象的原型。

运算符

  1. 位运算符号

    • &: 按位进行与运算,两位同时为1才为1
      0101 & 0001 ==》 0001
    • |: 或运算,只要有一位为1就为1
      0101 | 0001 ==》0101
    • ^: 异或运算,相同为0不同为1
      0101 ^ 0001 ==》0100
    • ~:按位取反
      ~0101 ==》 1010
  2. 逻辑运算符

    • || 逻辑或:在条件判断中,两个只要有一个为true,结果就为true
      在return返回中,如果左边为true,返回左边结果,否则返回右边结果

    • && 逻辑与:在条件判断中,两个都为true,结果才为true
      在return返回中,如果左边为true,返回右边结果,否则返回左边结果

    • ?:三元运算符
      一个例子:var votable = (age<18) ? "太年轻":"足够成熟";
      先判断左边表达式,如果为true,返回“太年轻”,否则返回‘足够成熟’

  3. == 和 ===

    • ==:相等运算符,在比较的时,如果类型不同,会发生类型转换,再比较数值
    • ===:严格相等运算符,不发生类型转换,如果类型不同,直接为False
  4. 算术运算符
    加法运算符存在重载,其它运算符所有运算子一律转为数值,再进行相应的数学运算。

    '3' + 4 + 5 // "345"
    3 + 4 + '5' // "75"
    
  5. 取反运算符!
    用于将布尔值变为相反值,对于非布尔值,取反运算符会将其转为布尔值。如果!!相当于对该对象进行布尔值转换。

面向对象编程

面向对象编程,在python中有类的概念,类是对象的模板,对象是类的实例(不要局限于class 这个字眼)。但是,在JavaScript 语言的对象体系,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype)。在ES6中新增class。

构造函数

JavaScript 语言使用构造函数(constructor)作为对象的模板。所谓”构造函数”,就是专门用来生成实例对象的函数。它就是对象的模板,描述实例对象的基本结构。一个构造函数,可以生成多个实例对象,这些实例对象都有相同的结构。为了与普通函数区别,构造函数名字的第一个字母通常大写。

构造函数的有两个特点:

  • 函数体内部使用了this关键字,代表了所要生成的对象实例。
  • 生成对象的时候,必须使用new命令。

关于new命令:

使用new命令运行构造函数,返回一个新对象(必须)。执行流程:

  1. 创建一个空对象,作为将要返回的对象实例。

  2. 将这个空对象的原型,指向构造函数的prototype属性。

  3. 将这个空对象赋值给函数内部的this关键字。

  4. 开始执行构造函数内部的代码。

构造函数的缺点

function Dog(name,age){
    this.name = name;
    this.age = age;
    this.say = function(){
        console.log('wawawa')
    }
}
var dog1 = new Dog('哈士奇',1.5)
var dog2 = new Dog('金毛',2.4)

console.log(dog1.say == dog2.say)

上面的例子中,结果为什么为false?
在使用构造函数创建对象时,每创建一个对象都会开辟一块新的内存空间,也就是每个dog对象都有一个say方法,随着对象的增多,造成内存的浪费也就更多。上面这些不重要,重点是下面,理解prototype

原型prototype

prototype:原型。每个构造函数的创建出来的时候,系统都会自动的给这个构造函数创建并且关联一个空的对象,这个空的对象,就叫原型。

关键点

  • 每一个构造函数创建出来的对象,都会默认和构造函数的原型对象关联。

  • 当调用对象的方法或者属性时,会在当前对象内查找,如果没有找到,就会去它关联的原型对象查找

  • 也就是说,在原型对象中创建的属性和方法,会被这个构造函数创建出来的对象所共享

  • 访问原型方式 -------- 构造函数名.prototype

function Dog(name,age){
    this.name = name;
    this.age = age;
}
Dog.prototype.say = function(){
        console.log('wawawa')
    }

var dog1 = new Dog('哈士奇',1.5)
var dog2 = new Dog('金毛',2.4)

console.log(dog1.say == dog2.say)

一般情况下,不会把属性放在原型中,只会把方法放在原型中。

__proto__

通过构造函数创建出来的对象可用通过 proto 访问原型

dog1.__proto__ === Dog.prototype

constructor属性

constructor:构造函数,原型的constructor属性指向和原型关联的构造器函数。
每个对象都有这个属性,可以通过``obj.constructor.name`获取该对象的数据类型(创建它的构造器函数名称,父类名称)

dog1.constructor.prototype == dog1.__proto__

每一个对象都有constructor属性,有proto属性,prototype只属于构造器函数

继承

  1. object.create()

ES6的proxy

proxy:在爬虫中使用,达到监控的目的,对象属性的获取和设置,补充环境

获取CSSStyleDeclaration对象

在逆向头条的时候,提示 cant not set fontsize of undefined,调试的时候发现,这里的undefined就是一个CSSStyleDeclaration对象,首先是createElement一个span标签,使用innerHTML插入内容,使用element.style创建一个CSSStyleDeclaration对象,给这个对象fontsize设置值。

//方法1:
let CSSStyleDeclaration = dom.style
  
//方法2:
let CSSStyleDeclaration = getComputedStyle(element, [pseudoElt])

//方法3:
let CSSStyleDeclaration = CSSStyleRule.style

Ajax

浏览器中所有请求都基于XmlRequest对象
async JavaScript and xml
onreadystatechange

ajaxhook
everythinghook

常见语法和函数

  1. a++ 和 ++a
    a++ 先执行表达式,在进行自增
    ++a 先自增,在执行表达式

  2. setInteval 和 setTimeout
    setInteval:指定周期(毫秒)来调用函数或计算表达式
    setTimeout:用于在指定的毫秒数后调用函数或计算表达式。

  3. String.fromCharCode(97) = 'a'

  4. charCodeAt('\',0) 返回指定位置字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数。

参考文章

阮一峰es6
JavaScript进阶
ES6系列之proxy

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342