Javascript 学习笔记(一)

该笔记适合用于复习JS相关内容,以及有一定基础后快速学习JS
内容主要是对知识点的总结,不适合零基础学习
笔记中包含大量的样例代码
笔记主要内容来自于 JavaScript核心基础_讲师(李立超)_JS教程

1.零散知识

编写位置

<!--1.可以将js编写到网页内部的script标签-->
<script>
    alert("哈哈!")
</script>

<!-- 2.可以将js编写外部的js文件中,然后通过script标签进行引入,里面不可再写js代码-->
<script src="./script/script.js"></script>

<!--3.可以将js代码编写到指定属性中-->
<button onclick="alert('你点我干嘛!')">点我一下</button>
<a href="javascript:alert('你被骗了');">超链接</a>

debug

使用debugger在代码中打断点

严格模式

  • 正常模式

    • 默认情况下代码都运行在正常模式中,在正常模式,语法检查并不严格,它的原则是:能不报错的地方尽量不报错
    • 这种处理方式导致代码的运行性能较差
  • 严格模式

    • 在严格模式下,语法检查变得严格
      1. 禁止一些语法
      2. 更容易报错
      3. 提升了性能
  • 在开发中,应该尽量使用严格模式,这样可以将一些隐藏的问题消灭在萌芽阶段,同时也能提升代码的运行性能

<script>
	"use strict" // 全局的严格模式
	function fn(){
    	"use strict" // 函数的严格的模式
	}
</script>

注意事项

  • JS中每条语句都应该以分号结尾,JS中具有自动添加分号的机制,所以如果不写分号解释器会自动添加。部分情况无法解析,必须要手动添加分号
  • 标识符只能含有字母、数字、下划线、$,且不能以数字开头,标识符不能是JS中的关键字和保留字,也不建议使用内置的函数或类名作为变量名
  • 变量中并不存储任何值,而是存储值的内存地址

2.数据类型

数值 Number

  • 在JS中所有的整数和浮点数都是Number类型
  • JS中的数值并不是无限大的,当数值超过一定范围后会显示近似值,所以在JS中进行一些精度比较高的运算时要十分注意
  • Infinity 是特殊的数值,表示无穷;NaN 也是特殊的数值,表示非法的数值
let a = 10
a = 9.98
a = 999 ** 999 // Infinity
a = Infinity
a = 1 - "a" //NaN
a = NaN

大整数 BigInt

  • 大整数用来表示一些比较大的整数
  • 大整数使用n结尾,它可以表示的数字范围是无限大
let bigN = 999n ** 999n
console.log(bigN)

其他进制数字

  • 二进制 0b
  • 八进制 0o
  • 十六进制 0x
let a
a = 0b1010 // 10
a = 0o10 // 8
a = 0xa4 // 164

类型检查

  • typeof用来检查不同的值的类型

  • 它会根据不同的值返回不同的结果

let a = 10
let b = 10n
console.log(typeof a) // number
console.log(typeof b) // bigint

字符串 String

  • 在JS中使用单引号或双引号来表示字符串
  • 转义字符,与C语言中的差不多
  • 模板字符串,使用反单引号` 来表示模板字符串,可以跨行使用,模板字符串中可以嵌入变量
let name = "Jack"
let str = `他说:“${name},你好!”`
let str2 = "\"You're a fraud!\" He shounted."

布尔值 Boolean

空值 Null

  • 空值表示空对象
  • 使用typeof检查一个空值时会返回"object"(历史遗留bug,实际上无意义),因此使用typeof无法检查空值

未定义 Undefined

  • 当声明一个变量而没有赋值时,它的值就是Undefined

  • Undefined类型的值只有一个就是 undefined

符号 Symbol

  • 用来创建一个唯一的标识
let c = Symbol() // 调用Symbol()创建一个符号
console.log(typeof c) // symbol

总结

JS中原始值一共有七种:Number, BigInt, String, Boolean, Null, Undefined, Symbol。七种原始值是构成各种数据的基石,原始值在JS中是不可变类型,一旦创建就不能修改。

3.类型转换

转换为字符串

  1. 调用toString()方法将其他类型转换为字符串 var.toString()
  2. 调用String()函数将其他类型转换为字符串 String(var)

对于拥有toString()方法的值调用String()函数时,实际上就是在调用toString()方法。对于null,则直接转换为"null",对于undefined,直接转换为"undefined"。

let a // undefined
a = 10 // 10
a = 666n // 666
a.toString()
console.log(a)

转换为数值

  1. 使用Number()函数来将其他类型转换为数值 Number(var)
  • 字符串:
    • 如果字符串是一个合法的数字,则会自动转换为对应的数字
    • 如果字符串不是合法数字,则转换为NaN
    • 如果字符串是空串或纯空格的字符串,则转换为0
  • 布尔值:
    • true转换为1,false转换为0
  • null 转换为 0
  • undefined 转换为 NaN
  1. 专门用来将字符串转换为数值的两个方法
  • parseInt()将一个字符串转换为一个整数 parseInt(var)

    • 解析时,会自左向右读取一个字符串,直到读取到字符串中所有的有效的整数

    • 也可以使用parseInt()来对一个数字进行取整

  • parseFloat()将一个字符串转换为一个浮点数 parseFloat(var)

    • 解析时,会自左向右读取一个字符串,直到读取到字符串中所有的有效的小数
let a = '123' // 123
a = 'abc' // NaN
a = '3.14' // 3.14
a = parseInt(a) // 3
a = '   ' // 0
a = null // 0
a = undeinfed // NaN
console.log(Number(a))

let b = '123px' //123
b = 'xp321' //NaN
b = '123.456' // 123
console.log(parseInt(b))

let c = '192.168.0.1' // 192.168
c = '123px' // 123
console.log(parseFloat(c))

转换为布尔值

1.使用Boolean()函数来将其他类型转换为布尔值

  • 数字:
    • 0NaN 转换为false
    • 其余是true
  • 字符串:
    • 空串转换为false
    • 其余是true
  • nullundefined都转换为false
  • 对象会转换为true
  • 所有表示空性的没有的错误的值都会转换为false0NaN、空串、nullundefinedfalse

总结

转换为字符串

  • 显式转换 String(var),var.toString()

  • 隐式转换 var + ""

转换为数值

  • 显式转换 Number()

  • 隐式转换 +var

转换为布尔值

  • 显式转换 Boolean()

  • 隐式转换 !!var

4.运算符

算数运算符

加减乘除模幂 + - * / % **

JS是一门弱类型语言,当进行运算时会通过自动的类型转换来完成运算

  • 当任意一个值和字符串做加法运算时,它会先将其他值转换为字符串,然后再做拼串的操作
  • 可以利用这一特点来完成类型转换,可以通过任意类型 + 一个空串的形式来将其转换为字符串,其原理和String()函数相同,但使用起来更加简洁。
let a = 10 - '5' // 10 - 5
a = 9 + true // 9 + 1
a = 5 + null // 5 + 0
a = 6 - undeifned // 6 - NaN

let b = '1' + 2 // '1' + '2'
b = 314 + '' // "314"

赋值运算符

等,加减乘除模幂等 = += -= *= /= %= **=

空赋值 ??=,只有当变量的值为nullundefined时才会对变量进行赋值

一元运算符

正负 +-

加加减减 ++ --,和C语言一致

当我们对非数值类型进行正负运算时,会先将其转换为数值然后再运算

let a = -233

let b = '123'
b = +b // b = Number(b)

逻辑运算符

与或非 && || !

  • 如果对一个非布尔值进行取反,它会先将其转换为布尔值然后再取反

  • 与或是短路运算符,对于非布尔值进行与运算,它会转换为布尔值然后运算

  • 与运算的返回值:

    • 如果第一个值为false,则直接返回第一个值
    • 如果第一个值为true,则返回第二个值
  • 或运算的返回值:

    • 如果第一个值为true,则直接返回第一个值
    • 如果第一个值为false,则返回第二个值
let result
//true && true  -> true
result = 1 && 2 // 2 
//true && false -> false
result = 1 && 0 // 0
//false && true -> false 
result = 0 && 2 // 0
//false && false -> false 
result = 0 && NaN // 0

result = 1 || 2 // 1
result = "hello" || NaN // "hello"
result = NaN || 1 // 1
result = NaN || null // null

关系运算符

大小于,大小等于 > < >= <=

  • 当对非数值进行关系运算时,它会先将前转换为数值然后再比较
  • 当关系运算符的两端是两个字符串,它不会将字符串转换为数值,而是逐位的比较字符的Unicode编码,利用这个特点可以对字符串按照字典序排序
  • 注意比较两个字符串格式的数字时一定要进行类型转换
let result
result = 5 < "10" // true        
result = "1" > false // true        
result = "a" < "b" // true        
result = "z" < "f" // false        
result = "abc" < "b" // true
result = "12" < "2" // true
result = +"12" < "2" // false

相等运算符

==

  • 相等运算符,用来比较两个值是否相等

  • 使用相等运算符比较两个不同类型的值时,它会将其转换为相同的类型(通常转换为数值)然后再比较,类型转换后值相同也会返回true

    • nullundefined进行相等比较时会返回true

    • NaN不和任何值相等,包括它自身

===

  • 全等运算符,用来比较两个值是否全等

  • 它不会进行自动的类型转换,如果两个值的类型不同直接返回false

  • nullundefined进行全等比较时会返回false

!=

  • 不等,用来检查两个值是否不相等

  • 会自动的进行类型转换

!==

  • 不全等,用来检查两个值是否不全等

  • 不会自动的进行类型转换

let result =  1 == '1' // true
result = true == "1" // true
result = NaN == NaN // false
result = 1 === "1" // false
result = null === undefined // false

条件运算符

condition ? expression1 : expression2,同C语言

5.流程控制

代码块

使用 {} 来创建代码块,代码块可以用来对代码进行分组

let 和 var

  • 在JS中,使用let声明的变量具有块作用域,在代码块中声明的变量无法在代码块的外部访问
  • 使用var声明的变量,不具有块作用域
  • let必须先声明再使用,否则报Uncaught ReferenceError xxx is not defined。var可以在声明前访问,只是会报undefined
  • let变量不能重复声明,var可以
{
     let a = 8;   // a变量只在花括号内有效
     var b = 9;
}
     // console.log(a); // ReferenceError: a is not defined
     console.log(b);  // 9

function func(){
  var x = 6
  console.log(x)
}
// console.log(x) // Uncaught ReferenceError: x is not defined

流程控制

if-else switch for while do-while break continue同或类似C语言

提升

变量的提升

  • 使用var声明的变量,它会在所有代码执行前被声明,所以我们可以在变量声明前就访问变量

函数的提升

  • 使用函数声明创建的函数,会在其他代码执行前被创建,所以我们可以在函数声明前调用函数
// console.log(b) // Uncaught ReferenceError: Cannot access 'b' before initialization
let b = 10

fn() // 可以执行成功
function fn(){
	alert("我是fn函数~")
}

// fn2() //不能执行成功
var fn2 = function(){
    alert("我是fn2函数~")
}

console.log(a) // Undefined
var a = 10

6.对象

对象和属性

属性名

  • 通常属性名就是一个字符串,所以属性名可以是任何值,没有什么特殊要求

  • 但是如果属性名太特殊了,不能直接使用,需要使用[]来设置,虽然如此,但是还是强烈建议属性名也按照标识符的规范命名

属性值

  • 对象的属性值可以是任意的数据类型,也可以是一个对象

in 运算符

  • 用来检查对象中是否含有某个属性

  • 语法 attribute in obj

  • 如果有返回true,没有返回false

let obj = Object()
obj.name = "Jack"
obj.age = 18
obj.gender = "Male"
let w = 'weight'
obj[w] = '60kg'
let symbl = Symbol()
obj[symbl] = 'Attribute added by Symbol'
console.log(obj)
//{name: 'Jack', age: 18, gender: 'Male', weight: '60kg', Symbol(): 'Attribute added by Symbol'}
let str = JSON.stringify(obj)
console.log(str)
//{"name":"Jack","age":18,"gender":"Male","weight":"60kg"}
console.log(obj[symbl]) //Attribute added by Symbol
console.log("name" in obj)

对象字面量

  • 可以直接使用{} 来创建对象

  • 使用{}所创建的对象,可以直接向对象中添加属性

  • 语法:

    {
        变量,
        属性名:属性值,
        [属性名/变量]:属性值,
        "属性名":属性值
    }
    
let mySymbol = Symbol()
let name = "Jack"
let attr = "str"
let obj = {
	name, 
	age:18,
	["gender"]:"男",
	[mySymbol]:"特殊的属性",
	innerObj:{
		a:1,
		b:true
	},
	[attr]:"I'm Jack",
	"Tom":"Hello Tom."
}
let str=JSON.stringify(obj)
console.log(str)
//{"name":"Jack","age":18,"gender":"男","innerObj":{"a":1,"b":true},"str":"I'm Jack","Tom":"Hello Tom."}

枚举属性

for-in语句

for(let Attribute in Object){}

并不是所有的属性都可以枚举,使用符号添加的属性不可枚举

let obj = {
	name:'Jack',
	age:18,
	gender:"M",
	address:"UK",
	[Symbol()]:"Test Attr" // 符号添加的属性是不能枚举的
}
for(let propName in obj){
	console.log(propName, obj[propName])
}
/*
name Jack
age 18
gender M
address UK
*/

可变类型

对象属于可变类型

对象创建完成后,可以任意的添加删除修改对象中的属性

注意:

  • 当对两个对象进行相等或全等比较时,比较的是对象的内存地址
  • 如果有两个变量同时指向一个对象,通过一个变量修改对象时,对另外一个变量也会产生影响
  • const声明只是禁止变量被重新赋值,对对象的属性修改没有任何影响
let obj = {name:"Jack", age:"18"}
let obj2 = Object()
let obj3 = Object()
console.log(obj2 == obj3) // false
let obj4 = obj
obj4.name = "Rose"
console.log(JSON.stringify(obj)) // {"name":"Rose","age":"18"}
console.log(obj === obj4) // true

方法

当一个对象的属性指向一个函数,那么我们就称这个函数是该对象的方法,调用函数就称为调用对象的方法

let obj = {
    name:"Jack",
    introduce(){
        console.log("I am", this.name)
    },
    greet(name_){
        console.log("Hello,", name_)
    },
    farewell:function(name_){
        console.log("Goodbye,", name_)
    }
}
obj.introduce() // I am Jack
obj.greet("Rose") // Hello, Rose
obj.farewell("Rosy") // Goodbye, Rosy

Window对象

  • 在浏览器中,浏览器为我们提供了一个window对象,可以直接访问

  • window对象代表的是浏览器窗口,通过该对象可以对浏览器窗口进行各种操作,除此之外window对象还负责存储JS中的内置对象和浏览器的宿主对象

  • window对象的属性可以通过window对象访问,也可以直接访问

  • 函数就可以认为是window对象的方法

7.函数

基本概念

  • 函数也是一个对象

  • 它具有其他对象所有的功能

  • 函数中可以存储代码,且可以在需要时调用这些代码

  • 使用typeof检查函数对象时会返回function

function fact(n){
    let ret=1
    for(let i=1;i<=n;i++)
        ret*=i
    return ret
}
console.log(fact(5)) // 120

函数的定义方式

  • 函数声明

  • 函数表达式

  • 箭头函数

  • // 1
    function func(){
        
    }
    // 2
    const var_ = function(){
        
    }
    // 3
    () => {
        
    }
    
function fn(){
    console.log("函数声明所定义的函数~")
}
const fn2 = function(){
    console.log("函数表达式")
}
const fn3 = () => {
    console.log("箭头函数")
}
const fn4 = () => console.log("箭头函数")

console.log(typeof fn) //fn-fn4全是function
console.log(typeof fn2)
console.log(typeof fn3)
console.log(typeof fn4)

函数参数

无需声明变量类型,其他类似C语言

// 当箭头函数中只有一个参数时,可以省略()
const fn = a => {
	console.log("a =", a);
}

// 定义参数时,可以为参数指定默认值
// 默认值,会在没有对应实参时生效
const fn2 = (a=10, b=20, c=30) => {
    console.log("a =", a);
    console.log("b =", b);
    console.log("c =", c);
}
fn2(233,666) // a=233 b=666 c=30

对象作为参数,传递实参时,传递并不是变量本身,而是变量中存储的值

  • 修改变量时,只会影响当前的变量

  • 修改对象时,如果有其他变量指向该对象则所有指向该对象的变量都会受到影响

function changeName(obj){
    obj.name = 'Not ' + obj.name
}
let obj = {name:'Jack'}
changeName(obj)
console.log(obj) // {name: 'Not Jack'}

函数作为参数,函数也是一个对象(一等函数),别的对象能做的事情,函数也可以

function fn(a){
    console.log("type of a:", typeof a)
	console.log("a =", a)
}
fn(function(){
	console.log("我是匿名函数~")
})
fn(()=>console.log("我是箭头函数"))
/*
type of a: function
a = ƒ (){
	console.log("我是匿名函数~")
}
type of a: function
a = ()=>console.log("我是箭头函数")
*/

函数的返回值

  • 在函数中,可以通过return关键字来指定函数的返回值

  • 任何值都可以作为返回值使用(包括对象和函数之类)

  • 如果return后不跟任何值,则相当于返回undefined

  • 如果不写return,那么函数的返回值依然是undefined

  • 箭头函数的返回值可以直接写在箭头后,如果直接在箭头后设置对象字面量为返回值时,对象字面量必须使用()括起来

const sum = (a, b) => a + b
const fn = () => ({name:"Jack"})

作用域

作用域指的是一个变量的可见区域

作用域有两种:

  • 全局作用域

    • 全局作用域在网页运行时创建,在网页关闭时消耗
    • 所有直接编写到script标签中的代码都位于全局作用域中
    • 全局作用域中的变量是全局变量,可以在任意位置访问
  • 局部作用域

    • 块作用域是一种局部作用域

    • 块作用域在代码块执行时创建,代码块执行完毕它就销毁

    • 在块作用域中声明的变量是局部变量,只能在块内部访问,外部无法访问

    • 函数作用域也是一种局部作用域

    • 函数作用域在函数调用时产生,调用结束后销毁

    • 函数每次调用都会产生一个全新的函数作用域

    • 在函数中定义的变量是局部变量,只能在函数内部访问,外部无法访问

作用域链:

  • 当我们使用一个变量时,JS解释器会优先在当前作用域中寻找变量

  • 如果找到了则直接使用,如果没找到,则去上一层作用域中寻找,找到了则使用

  • 如果还没找到,则继续去上一层寻找,以此类推

  • 如果一直到全局作用域都没找到,则报错 xxx is not defined

立即执行函数(IIFE)

  • 立即是一个匿名的函数,并它只会调用一次

  • 可以利用IIFE来创建一个一次性的函数作用域,避免变量冲突的问题

(function(){
    let a = 10
    console.log(111)
})();   //此处自动添加分号机制不起作用,注意需要分号
(function(){
    let a = 20
    console.log(222)
}())
// 111
// 222

this

  • 函数在执行时,JS解析器每次都会传递进一个隐含的参数,这个参数就叫做this
  • this会指向一个对象,this所指向的对象会根据函数调用方式的不同而不同
    1. 以函数形式调用时,this指向的是window
    2. 以方法的形式调用时,this指向的是调用方法的对象
  • 通过this可以在方法中引用调用方法的对象
function fn() {
    console.log(this === window)
    console.log(this)
}
const obj1 = {name:'Jack'}
obj1.inFun = fn
const obj2 = {name:'Rose', inFun:fn}
const obj3 = {
    name:'Tom',
    inFun:function(){
        console.log(this, this.name)
    }
}

window.fn() // true Window {...}
obj1.inFun() // false {name: 'Jack', inFun: ƒ}
obj2.inFun() // false {name: 'Rose', inFun: ƒ}
obj3.inFun() // {name: 'Tom', inFun: ƒ} 'Tom'
  • 箭头函数没有自己的this,它的this由外层作用域决定,箭头函数的this和它的调用方式无关
function fn1() {
    console.log(this)
}
const fn2 = () => console.log(this)
const obj = {
    name:'Jack',
    fn1, // fn1:fn1
    fn2,
    inFun(){ // inFun:function(){
        console.log(this)
        const inFun2 = () => {
            //这里的this和函数外的this相同
            console.log('In Infun',this)
        }
        inFun2()
    }
}

fn2() // Window {...}
obj.fn1() // {name: 'Jack', fn1: ƒ, fn2: ƒ, inFun: ƒ}
obj.fn2() // Window {...}
obj.inFun()
/*
{name: 'Jack', fn1: ƒ, fn2: ƒ, inFun: ƒ}
In Infun {name: 'Jack', fn1: ƒ, fn2: ƒ, inFun: ƒ}
*/

高阶函数

如果一个函数的参数或返回值是函数,则这个函数就称为高阶函数

将函数作为参数,意味着可以对另一个函数动态的传递代码

function someFn() {
    return "hello"
}
function outer(cb){
    return () => {
        console.log("记录日志~~~~~")
        const result = cb()
        return result
    }
}
let result = outer(someFn)
console.log(result)

function test(){
    console.log("test~~~~")
    return "test"
}
let newTest = outer(test)
console.log("A ",newTest)
console.log("B ",newTest())

闭包

闭包就是能访问到外部函数作用域中变量的函数

当我们需要隐藏一些不希望被别人访问的内容时就可以使用闭包

构成闭包的要件:

  1. 函数的嵌套
  2. 内部函数要引用外部函数中的变量
  3. 内部函数要作为返回值返回
function outer(){
    let num = 0 // 位于函数作用域中
    return () => { //返回值是undefined
        num++
        console.log(num)
    }
}

const newFn = outer()
const Fn2 = outer()
newFn() // 1
newFn() // 2
Fn2()   // 1
newFn() // 3
Fn2()   // 2
console.log(newFn)
/*
() => { //返回值是undefined
        num++
        console.log(num)
    }
*/
console.log(newFn()) 
// 4
// undefined

闭包的生命周期:

  1. 闭包在外部函数调用时产生,外部函数每次调用都会产生一个全新的闭包

  2. 在内部函数丢失时销毁(内部函数被垃圾回收了,闭包才会消失)

注意事项:

  • 闭包主要用来隐藏一些不希望被外部访问的内容,这就意味着闭包需要占用一定的内存空间
  • 相较于类来说,闭包比较浪费内存空间(类可以使用原型而闭包不能),需要执行次数较少时,使用闭包,需要大量创建实例时,使用类

递归

类似C语言

可变参数

  • arguments是函数中又一个隐含参数

  • arguments是一个类数组对象(伪数组),和数组相似,可以通过索引来读取元素,也可以通过for循环变量,但是它不是一个数组对象,不能调用数组的方法

  • arguments用来存储函数的实参,无论用户是否定义形参,实参都会存储到arguments对象中,可以通过该对象直接访问实参

function f1(){
    console.log(arguments)
}
f1() // Arguments [callee: ƒ, Symbol(Symbol.iterator): ƒ]
f1('Jack', 1914) // Arguments(2) ['Jack', 1914, callee: ƒ, Symbol(Symbol.iterator): ƒ]

function sum(a,b){
    let ret = 0
    console.log(a,b)
    for(let i=0; i<arguments.length; i++){
        console.log(arguments[i])
        ret += arguments[i]
    }
	for(let v of arguments)
        console.log(v)
    return ret
}
sum(233,66)
console.log('sum =',sum(3,7,8,9,10))

可变参数,在定义函数时可以将参数指定为可变参数

  • 可变参数可以接收任意数量实参,并将他们统一存储到一个数组中返回
  • 可变参数的作用和arguments基本是一致,但是也具有一些不同点:
    1. 可变参数的名字可以自己指定
    2. 可变参数就是一个数组,可以直接使用数组的方法
    3. 可变参数可以配合其他参数一起使用
function sum(...arr){
    return num.reduce((a,b)=>a+b,0)
}
function func(a,b,...args){
    for(let v of args)
        console.log(v)
    console.log(args)
}
console.log(sum(1,2,3,4)) // 10
console.log(func(11,22,33,44,55))
/*
33
44
55
[33, 44, 55]
*/

call & apply

根据函数调用方式的不同,this的值也不同:

  1. 以函数形式调用,thiswindow
  2. 以方法形式调用,this是调用方法的对象
  3. 构造函数中,this是新建的对象
  4. 箭头函数没有自己的this,由外层作用域决定
  5. 通过callapply调用的函数,它们的第一个参数就是函数的this

函数.call()
函数.apply()

  • callapply除了可以调用函数,还可以用来指定函数中的this
  • callapply的第一个参数,将会成为函数的this
  • 通过call方法调用函数,函数的实参直接在第一个参数后一个一个的列出来
  • 通过apply方法调用函数,函数的实参需要通过一个数组传递
function fn(arg1,arg2){
    console.log(arg1,arg2)
    console.log('Fn this is',this)
}
const obj = {
    name:'Jack',
    fn
}
fn.call(obj,'abc',233) // this 是 obj
fn.apply(console,[233,'abc']) // this 是 console

bind

通过bind返回的函数,thisbind第一个参数决定(无法修改)

bind()是函数的方法,可以用来创建一个新的函数

  • bind可以为新函数绑定this
  • bind可以为新函数绑定参数

箭头函数没有自身的this,它的this由外层作用域决定,也无法通过call applybind修改它的this

箭头函数中没有arguments

function func(a,b){
    console.log(a,b)
    console.log(this)
}
const obj1 = {name:'Jack'}
const obj2 = {name:'Rose'}
const f1 = func.bind(obj1)
const f2 = func.bind(obj2,929,676)

f1() // undefined undefined {name:'Jack'}
f1(114,514) // 114 514 {name:'Jack'}
f2() // 929 676 {name:'Rose'}
f2(114,514) // 929 676 {name:'Rose'}

8.面向对象

使用Object创建对象的问题:

  1. 无法区分出不同类型的对象

  2. 不方便批量创建对象

  1. 类是对象模板,可以将对象中的属性和方法直接定义在类中定义后,就可以直接通过类来创建对象

  2. 通过同一个类创建的对象,我们称为同类对象,可以使用instanceof来检查一个对象是否是由某个类创建,如果某个对象是由某个类所创建,则我们称该对象是这个类的实例

  3. 类的定义

    class 类名 {} // 类名要使用大驼峰命名
    const 类名 = class {}  
    
  4. 通过类创建对象 new 类()

类的属性

类的方法

类的构造函数

  • 在类中可以添加一个特殊的方法constructor

  • 该方法我们称为构造函数(构造方法)

  • 构造函数会在我们调用类创建对象时执行

class Person{
// 类的代码块,默认就是严格模式,
// 类的代码块是用来设置对象的属性的,不是什么代码都能写
    constructor(argX, argY){
      this.argX = argX
      this.argY = argY
    }
    arg1 //没赋值的实例属性,默认值为undefined
    arg2
    name = "Jack" // Person的实例属性name
    age = 18      // 实例属性只能通过实例访问
    static test = "test静态属性" // 使用static声明的属性,是静态属性(类属性) Person.test
    introduce(){
        console.log('I am',this.name)
    }
    static testFn(){
        console.log('I\'m static')
        console.log(this)
    }
}
const p1 = new Person()
const p2 = new Person('Rose', 233)
console.log(p1)
// Person {arg1: undefined, arg2: undefined, name: 'Jack', age: 18, argX: undefined, …}
console.log(JSON.stringify(p1))
// {"name":"Jack","age":18}
console.log(p2)
// Person {arg1: undefined, arg2: undefined, name: 'Jack', age: 18, argX: 'Rose', …}
console.log(JSON.stringify(p2))
// {"name":"Jack","age":18,"argX":"Rose","argY":233}
console.log(Person.test) // test静态属性
p1.introduce() // I am Jack
Person.testFn()
// I'm static
/*
class Person{
// 类的代码块,默认就是严格模式,
...
*/

封装

  • 对象就是一个用来存储不同属性的容器

  • 对象不仅存储属性,还要负责数据的安全

  • 直接添加到对象中的属性,并不安全,因为它们可以被任意的修改

  • 如何确保数据的安全:

    1. 私有化数据,将需要保护的数据设置为私有,只能在类内部使用

    2. 提供settergetter方法来开放对数据的操,属性设置私有,通过getter setter方法操作属性带来的好处:

      1. 可以控制属性的读写权限
      2. 可以在方法中对属性的值进行验证
  • 封装主要用来保证数据的安全

  • 实现封装的方式:

    1. 属性私有化 加#
    2. 通过gettersetter方法来操作属性
class Person{
// 实例使用#开头就变成了私有属性,私有属性只能在类内部访问
// 私有属性需要先声明才能使用
    #name
    #age
    constructor(name, age) {
		this.#name = name
		if(typeof age === 'number' && age>0)
            this.#age = age
        else this.#age = 0
	}
    introduce(){
        console.log("I'm", this.name)
    }
    getName(){ // getter方法,用来读取属性
        return this.#name
    }
    setName(name){ // setter方法,用来设置属性
        this.#name = name
    }
    getAge(){
        return this.#age
    }
    setAge(age){
        if(typeof age === 'number' && age>0)
            this.#age = age
		else console.log('Not valid')
    }
}
const p1 = new Person('Jack',18)
p1.setName('Rose')
p1.setAge(-11)
p1.setAge('11')
console.log(p1)
/*
Not valid
Not valid
Person {#name: 'Rose', #age: 18}
*/

多态

  • 在JS中不会检查参数的类型,所以这就意味着任何数据都可以作为参数传递

  • 要调用某个函数,无需指定的类型,只要对象满足某些条件即可

  • 如果一个东西走路像鸭子,叫起来像鸭子,那么它就是鸭子

  • 多态为我们提供了灵活性

class Man{
    constructor(name){
        this.name = name
    }
}
function printName(obj){
    str = 'Hello '
    if(obj instanceof Man){
        str = 'Hello Mr.'
    }
    console.log(str + obj.name)
}

const m = new Man('White')
printName(m) // Hello Mr.White

继承

  • 可以通过extends关键来完成继承

  • 当一个类继承另一个类时,就相当于将另一个类中的代码复制到了当前类中(简单理解)

  • 继承发生时,被继承的类称为 父类(超类),继承的类称为 子类

  • 通过继承可以减少重复的代码,并且可以在不修改一个类的前提对其进行扩展

  • 通过继承可以在不修改一个类的情况下对其进行扩展

  • OCP 开闭原则:程序应该对修改关闭,对扩展开放

class Animal{
    constructor(name){
        this.name = name
    }
    introduce(){
        console.log("I am animal")
    }
}
class Dog extends Animal{
    // 在子类中,可以通过创建同名方法来重写父类的方法
    introduce(){
        console.log("I am dog, a kind of animal")
    }
}
class Cat extends Animal{
    // 重写构造函数
    constructor(name, age){
        // 重写构造函数时,构造函数的第一行代码必须为super()
        super(name) // 调用父类的构造函数
        this.age = age
    }
    introduce(){
        // 调用一下父类的sayHello
        super.introduce() // 在方法中可以使用super来引用父类的方法
        console.log("Meow~ meow~")
    }
}

const dog = new Dog('Goru')
const cat = new Cat('Diona',12)
dog.introduce() // I am dog, a kind of animal
cat.introduce() // I am animal Meow~ meow~
console.log(dog) // Dog {name: 'Goru'}
console.log(cat) // Cat {name: 'Diona', age: 12}

对象的结构

  1. 对象自身
    • 直接通过对象所添加的属性,位于对象自身中
    • 在类中通过 x = y 的形式添加的属性,位于对象自身中
  2. 原型对象(prototype)
    • 对象中还有一些内容,会存储到其他的对象里(原型对象)
    • 在对象中会有一个属性用来存储原型对象,这个属性叫做__proto__
    • 原型对象也负责为对象存储属性
      • 当我们访问对象中的属性时,会优先访问对象自身的属性
      • 对象自身不包含该属性时,才会去原型对象中寻找
    • 会添加到原型对象中的情况:
      • 在类中通过xxx(){}方式添加的方法,位于原型中
      • 主动向原型中添加的属性或方法
  3. 访问一个对象的原型对象
对象.__proto__
Object.getPrototypeOf(对象)
  1. 原型对象中的数据:

    1. 对象中的数据(属性、方法等)
    2. constructor (对象的构造函数)
  2. 原型链

    • 读取对象属性时,会优先读取对象自身属性,如果对象中有,则使用,没有则去对象的原型中寻找

    • 如果原型中有,则使用,没有则去原型的原型中寻找直到找到Object对象的原型(Object的原型没有原型(为null))

    • 如果依然没有找到,则返回undefined

    • 所有的同类型对象它们的原型对象都是同一个,也就意味着,同类型对象的原型链是一样的

    • Person对象的原型链:p对象 --> 原型 --> 原型 --> null
      Object对象的原型链:obj对象 --> 原型 --> null
      
class Person{
    name
    introduce(){
        console.log('I am',this.name)
    }
}
class Man extends Person{
    weight
}
const p = new Person()
const m = new Person()
console.log(Object.getPrototypeOf(p) === p.__proto__) // true
console.log(p.__proto__) // Object { f introdce() ...}
console.log(p.__proto__.__proto__) // Object { f Object() ...}
console.log(p.__proto__.__proto__.__proto__) // null
console.log(m.__proto__)
/*
{constructor: ƒ, introduce: ƒ}
	constructor: class Person
	introduce: ƒ introduce()
	[[Prototype]]: Object
*/

const obj = new Object() // obj = {}
console.log(obj.__proto__) // Object { f Object() ...}
console.log(obj.__proto__.__proto__) // null

除了通过__proto__能访问对象的原型外,还可以通过类的prototype属性,来访问实例的原型

class Person{
    name
}
Person.prototype.introduce = () => {
    console.log("It is person")
}
class Dog {}

const p1 = new Person()
const p2 = new Person()
console.log(p1.__proto__)
console.log(Person.prototype)
console.log(p.__proto__ === Person.prototype) // true
// 通过对象修改原型,向原型中添加方法,修改后所有同类实例都能访问该方法 不要这么做
// p.__proto__.run = () => {
//     console.log('我在跑~')
// }
// p.__proto__ = new Dog() // 直接为对象赋值了一个新的原型 不要这么做

instanceof

用来检查一个对象是否是一个类的实例

instanceof检查的是对象的原型链上是否有该类实例

只要原型链上有该类实例,就会返回true

Object是所有对象的原型,所以任何和对象和Object进行instanceof运算都会返回true

class Animal {}
class Dog extends Animal {}
const dog = new Dog()
const ani = new Animal()
console.log(dog instanceof Dog) // true
console.log(dog instanceof Animal) // true
console.log(dog instanceof Object) // true
console.log(ani instanceof Dog) // false

in

使用in运算符检查属性时,无论属性在对象自身还是在原型中,都会返回true

对象.hasOwnProperty(属性名) (不推荐使用) 用来检查一个对象的自身是否含有某个属性

Object.hasOwn(对象, 属性名) 用来检查一个对象的自身是否含有某个属性

class Person{
    name
    func(){}
}
const p = new Person()

console.log("name" in p) // true
console.log("func" in p) // true

console.log(Object.prototype.hasOwnProperty("hasOwnProperty")) // true

console.log(Object.hasOwn(p, "func")) //fasle
console.log(Object.hasOwn(p.__proto__, "func")) //true

*旧类

早期JS中,直接通过函数来定义类

  • 一个函数如果直接调用Xxx() 那么这个函数就是一个普通函数

  • 一个函数如果通过new调用new Xxx()那么这个函数就是一个构造函数

//用立即函数包起来
var Person = (function () {
    function Person(name, age){
        // 在构造函数中,this表示新建的对象
        this.name = name
        this.age = age
        // this.sayHello = function(){
        //     console.log(this.name)
        // }
    }
    // 向原型中添加属性(方法)
    Person.prototype.sayHello = function () {
        console.log(this.name)
    }
    // 静态属性
    Person.staticProperty = "xxx"
    // 静态方法
    Person.staticMethod = function () {}
    return Person
})()

const p = new Person("Jack", 18)

// console.log(p)
var Animal = (function(){
    function Animal(){

    }
    return Animal
})()

var Cat = (function(){
    function Cat(){

    }
    // 继承Animal
    Cat.prototype = new Animal()
    return Cat
})()

var cat = new Cat()
console.log(cat)

new运算符

当使用new去调用一个函数时,这个函数将会作为构造函数调用,使用new调用函数时,将会发生这些事:

  1. 创建一个普通的JS对象(Object对象 {}), 为了方便,称其为新对象
  2. 将构造函数的prototype属性设置为新对象的原型
  3. 使用实参来执行构造函数,并且将新对象设置为函数中的this
  4. 如果构造函数返回的是一个非原始值,则该值会作为new运算的返回值返回(千万不要这么做)如果构造函数的返回值是一个原始值或者没有指定返回值,则新的对象将会作为返回值返回
    通常不会为构造函数指定返回值
function MyClass(){
  // var newInstance = {}
  // newInstance.__proto__ = MyClass.prototype
}
var mc = new MyClass()
console.log(mc)
/*
MyClass{
	[[Prototype]]: Object
}
*/

9.数组

基本介绍

  • 数组也是一种复合数据类型,在数组可以存储多个不同类型的数据

  • 数组中存储的是有序的数据,数组中的每个数据都有一个唯一的索引,可以通过索引来操作获取数据

  • 数组中存储的数据叫做元素

  • 索引(index)是一组大于0的整数

  • 创建数组,可以通过Array()来创建数组,也可以通过[]来创建数组

  • 向数组中添加元素
    语法:
    数组[索引] = 元素

  • 读取数组中的元素
    语法:
    数组[索引]
    - 如果读取了一个不存在的元素,不好报错而是返回undefined

  • length

    • 获取数组的长度
    • 获取的实际值就是数组的最大索引 + 1
    • 向数组最后添加元素:
      数组[数组.length] = 元素
    • length是可以修改的
const arr = [1, 2, 3, 4]
const arr2 = new Array()
arr2[0] = 1
arr2[1] = 'Jack'
arr2[2] = () => {}
arr2[3] = {name:'Jack'}

console.log(arr)
console.log(arr2)
console.log(arr.length)

遍历数组

let arr = [1,14,5,1,4]

for(let i=0; i<arr.length; i++){
    console.log(arr[i])
}
for(let val of arr){
    console.log(val)
}

数组的方法

  • Array.isArray()
    • 用来检查一个对象是否是数组
  • array.at(index)
    • 可以根据索引获取数组中的指定元素
    • at可以接收负索引作为参数arr.at(-i) === arr[arr.length-i]
  • array.concat(array...)
    • 用来连接两个或多个数组
    • 非破坏性方法,不会影响原数组,而是返回一个新的数组
console.log(Array.isArray({name:'Jack'})) // false
console.log(Array.isArray([1,2,3])) // true

const arr = ['Jack', 'Rose', 'Tom', 'Jerry']
console.log(arr.at(1)) // Rose
console.log(arr.at(-2)) // Tom

const arr2 = ['杰克', '汤姆']
let tmp = arr.concat(arr2)
console.log(tmp) // ['Jack', 'Rose', 'Tom', 'Jerry', '杰克', '汤姆']
tmp = arr.concat([1,2], arr2, [{name:'Jcak'}])
console.log(tmp) // ['Jack', 'Rose', 'Tom', 'Jerry', 1, 2, '杰克', '汤姆', {…}]
  • array.indexOf(element,postion)

    • 获取元素在数组中第一次出现的索引
    • 参数:要查询的元素,查询的起始位置
  • array.lastIndexOf(element,postion)

    • 获取元素在数组中最后一次出现的位置
    • 返回值:找到了则返回元素的索引,没有找到返回-1
  • array.join(operator)

    • 将一个数组中的元素连接为一个字符串
    • 参数:指定一个字符串作为连接符
  • array.slice(start, end)

    • 用来截取数组(非破坏性方法)
    • 参数:截取的起始位置(包括该位置),截取的结束位置(不包括该位置,可以是负值)
    • 如果将两个参数全都省略,则可以对数组进行浅拷贝(浅复制)
let arr = [1,2,3,4,3]

let pos = arr.indexOf(3)
console.log(pos) // 2
pos = arr.indexOf(3,3)
console.log(pos) // 4
pos = arr.lastIndexOf(3)
console.log(pos) // 4
pos = arr.lastIndexOf(3,3)
console.log(pos) // 2

let str = arr.join(' + ')
console.log(str) // 1 + 2 + 3 + 4 + 3

let a = arr.slice(0,2)
console.log(a) // [1, 2]
a = arr.slice(2)
console.log(a) // [3, 4, 3]
a = arr.slice(1,-1)
console.log(a) // [2, 3, 4]
a = arr.slice()
console.log(a) // [1, 2, 3, 4, 3]
  • array.push(...element)
    • 向数组的末尾添加一个或多个元素,并返回新的长度
  • array.pop()
    • 删除并返回数组的最后一个元素
  • array.unshift(...element)
    • 向数组的开头添加一个或多个元素,并返回新的长度
  • array.shift()
    • 删除并返回数组的第一个元素
  • array.splice(start, number, ...element)
    • 可以删除、插入、替换数组中的元素
    • 参数:删除的起始位置,删除的数量,要插入的元素
    • 返回值:返回被删除的元素
  • array.reverse()
    • 反转数组
  • array.sort(function(arg1,arg2))
    • sort用来对数组进行排序(会对改变原数组)
    • sort默认会将数组升序排列(sort默认会按照Unicode编码进行排序,所以如果直接通过sort对数字进行排序,可能会得到一个不正确的结果)
    • 参数:可以传递一个回调函数作为参数,通过回调函数来指定排序规则,回调函数返回值为负数,不改变两个变量顺序,为正数,改变两变量顺序,(a, b) => a - b升序,(a, b) => b - a降序
  • array.forEach(function(element,index,array))
    • 用来遍历数组
    • 它需要一个回调函数作为参数,这个回调函数根据数组中元素数量被调用多次,每次调用,都会将数组中的数据作为参数传递
  • array.filter(function(element))
    • 将数组中符合条件的元素保存到一个新数组中返回
    • 需要一个回调函数作为参数,会为每一个元素去调用回调函数,并根据返回值来决定是否将元素添加到新数组中
    • 非破坏性方法,不会影响原数组
  • array.map(function(element))
    • 根据当前数组生成一个新数组
    • 需要一个回调函数作为参数,回调函数的返回值会成为新数组中的元素
    • 非破坏性方法不会影响原数组
  • array.reduce(function(arg1,arg2), init_val)
    • 可以用来将一个数组中的所有元素整合为一个值
    • 参数:回调函数,通过回调函数来指定合并的规则,可选参数,初始值
const arr1 = [0,1,2,3,4]
console.log(arr1.splice(1,3,['Jack','Rose'])) // [1,2,3]
console.log(arr1) // [0, Array(2), 4]

const arr2 = [1,14,51,4,23,3]
arr2.sort()
console.log(arr2) // [1, 14, 23, 3, 4, 51]
arr2.sort((a,b)=>b-a)
console.log(arr2) // [51, 23, 14, 4, 3, 1]

const arr3 = [1,2,3,4]
arr3.forEach((a,i,arr)=>{
    arr[i] = a*a
})
console.log(arr3) // [1, 4, 9, 16]

const arr4 = ['Jack', 'Jacky', 'Tom', 'Jerry', 'Mike']
let tmp1 = arr4.filter( val=>{
	return val[0] === 'J'    
})
console.log(tmp1) // ['Jack', 'Jacky', 'Jerry']

const arr4 = [1,4,9,16,233]
let tmp2 = arr4.map( val=>{
    return val**0.5
})
console.log(tmp2) // [1, 2, 3, 4, 15.264337522473747]

const arr5 = [2,4,6,8,10]
let tmp3 = arr5.reduce((a,b)=>{
    return a+b
},10000)
console.log(tmp3) // 10030

对象的复制

复制必须要产生新的对象

当调用slice时,会产生一个新的数组对象,从而完成对数组的复制

const arr = [0,1,2,3]
const arr2 = arr // 不是复制
arr[0] = 'changed'
console.log(arr2) // ['changed', 1, 2, 3]

const arr3 = arr.slice()
arr[1] = 'Jack'
console.log(arr3) // ['changed', 1, 2, 3]

console.log(arr === arr2) // true
console.log(arr === arr3) // false
  • 深拷贝(shallow copy)
    • 通常对对象的拷贝都是浅拷贝
    • 浅拷贝顾名思义,只对对象的浅层进行复制(只复制一层)
    • 如果对象中存储的数据是原始值,那么拷贝的深浅是不重要
    • 浅拷贝只会对对象本身进行复制,不会复制对象中的属性(或元素)
  • 深拷贝(deep copy)
    • 深拷贝指不仅复制对象本身,还复制对象中的属性和元素
    • 因为性能问题,通常情况不太使用深拷贝
const arr = [
    {name:'Jack', age:18},
    {name:'Rose', age:16}
]
const arr2 = arr.slice() // 浅拷贝
arr[0].name = 'Tom'
console.log(arr2[0].name) // Tom

const arr3 = structuredClone(arr) // 专门用来深拷贝的方法
arr[1].name = 'Jerry'
console.log(arr3[1].name) // Rose
  • ...(展开运算符)
    • 可以将一个数组中的元素展开到另一个数组中或者作为函数的参数传递
    • 通过它也可以对数组进行浅复制
  • 对象的复制
  • Object.assign(目标对象, 被复制的对象)
  • 将被复制对象中的属性复制到目标对象里,并将目标对象返回
  • 也可以使用展开运算符对对象进行复制
const arr = [0,1,2,3]
const arr2 = [...arr]
console.log(arr === arr2) // false

const obj = {name:'Jack', age:18}
const obj2 = {address:'US', age: 16}
Object.assign(obj2,obj)
console.log(obj2) // {address: 'US', age: 18, name: 'Jack'}
const obj3 = {name:'杰克', ...obj, age:28}
// 将obj中的属性在新对象中展开,相同名称的属性,后面的覆盖前面的
console.log(obj3) // {name: 'Jack', age: 28}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript:定义行为和动作 (基于对象和事件驱动的客户端脚本语言;也是一种广泛应用于客户端Web开发的脚本语言) 基于对象:网页中的一切元素都是假象!不需要new,即可直接使用 事件驱动:JavaScript的执行都是由事件引发 解释执行:先读到的先执行,后读到的会替代先读的 可以使用任何文本编辑工具编写 JavaScript 代码,然后由浏览器解释执行。 JavaScript常用于实现如下功能: |--控制文档的外观和内容; |--对浏览器的控制; |--与 HTML 表单的交互; |--与用户的交互; |--执行计算等。 1.单击事件:定义在按钮的开始标签中 语法:onclick="js语句" 弹出警告:alert(‘字符串’) 强调:1.js区分大小写 2.字符串单双引号不区分 [removed]标签:页面中专门集中编写JavaScript的区域 js的方法定义:function方法名([参数列表]){ 方法体 [return 返回值] } 注意:js中的方法可以直接写在代码中,不需要“类”包裹 使用方法:方法名()-->方法调用-->立即执行 2.js文件:网页外专门保存js脚本的文件--推荐 强调:HTML、CSS、JS都要使用UTF-8编码保存(window系统) 使用js文件引入网页:[removed][removed] 强调:一旦定义src属性则其中的代码失效 解释执行:语句也可以直接写在js文件中,边解释边执行 3.***调试*** |--①.只有在执行时,才会报错 |--②.错误信息,浏览器页面看不到--没效果 | 解决:控制台--(工具-->JavaScript控制台或F12) | 包含错误信息;指向错误位置的超链接 |--③.打桩:在指定变量位置输出变量或对象的内容 console.log(内容);-->出现在控制台-->日志 4.变量:js中的变量不需要提前指定类型,由赋值时动态决定 所有的变量都用var声明 5.数据类型: |--String(字符串类型) |--Number(数字类型) |--Boolean(布尔类型)0、-0、null、""、false/undefined或NaN,则该对象设置为false。其余都可以当true 6.数据类型的隐式转换: |--数字 + 字符串:数字转换为字符串 |--数字 + 布尔值:true转换为1,false转换为0 |--字符串 + 布尔值:布尔值转换为字符串true或false |--布尔值 + 布尔值:布尔值转换为数值1或0 7.数据类型转换函数 :(方法前不需要对象调用的:全局函数) |--toString():转换成字符串。所有数据类型均可转换为 string 类型; |--parseInt():强制转换成整数。如果不能转换,则返回 NaN(not a number); |--parseFloat():强制转换成浮点数。如果不能转换,则返回 NaN(Not a Number) |--typeof():查询数值当前类型。 |--isNaN():判断是否为数字。返回 true:不是数字/false:是数字 | |--isNan(""):对空字符串不验证,直接返回false | |--如果输入的是字符串类型的数字,返回false--不能判断数据类型,只判断内容 | |--如果输入的是boolean,返回false。因为boolean可以和number类型直接做计算 | |--和任何数字计算都得NaN;和任何数字作比较都得false |--注:[removed]();节点输出,即在当前位置输出括号里的内容 *凡是从页面上进入js的都是字符串类型 8.查找元素:抓住根节点,就等于抓住整棵树 网页的根节点:document对象 要找元素,必须利用document对象(当前网页文件) 精确查找某个ID的元素:document.getElementById(id名); 9.null和undefined: |--null:一个特殊的值,表示“无值”--空对象。数据类型为Object |--undefined:表示声明了变量但从未赋值或者对象属性不存在 10.双等号(==)和全等号(===): |--“==”为确定两个运算数是否相等,“==”运算符会进行类型转换。转换后运算数相等就返回true,否则返回false |--“===”不执行类型转换,即,只有在无需类型转换运算数就相等的情况下,才返回true,否则返回false |--附:if(null)、if(defined)、if(NaN)都相当于if(false) -----猜数字游戏----- 失去焦点时,判断猜对猜错 获得焦点:onfocus 失去焦点:onblur 当事件就发生在获得内容的当前元素上: this直接获得当前内容对象。可以代替当前对象完成一切操作,拥有当前对象的所有属性 前端优化:js中最好用三目运算代替if else 11.String: |--查找:x.indexOf(‘关键字’[,开始位置下标]) | 每次只查找第一次出现的位置 |--替换:x.replace(‘关键字’[,‘替换内容’])--不会修改原x字符串 | 每次只替换第一次找到的 |--查找和替换所有:while循环 | |--String 对象的常用方法有: |--x.toLowerCase()、x.toUpperCase():大小写转换方法; |--x.charAt(index):返回指定位置的字符; |--x.charCodeAt(index):返回指定位置字符的Unicode编码; |--x.indexOf(findstr,index)、x.lastIndexOf(findstr,index): 获取指定字符; |--x.substring(start, end): 获取子字符串; |--x.replace(findstr,tostr):替换子字符串; |--x.split(bystr): 拆分子字符串。 |--String与正则表达式 |--str.match(regExp);--查找str中匹配正则表达式的关键字 | 返回:如果没找到,返回null。若找到,返回1个数组,数组的每个元素是每个找到的匹配关键 | |--str.replace(regExp,"替换值")--替换str中所有匹配的关键字 | 强调:replace方法不改变元字符串,只能返回新字符串。必须用变量接收新字符串 | |--js中正则表达式语法:/正则表达式/[属性后缀]--其中属性后缀,g:全局匹配 i:忽略大小写(仅英文有效) 如果不适用模式匹配方式,将执行原文匹配 结果:如果正则表达式写错,也将执行原文匹配 12.Array笔试题:js中数组声明方式: A new Array(7) B new Array(7,‘a’,true) C [7,'a',true]--js中所有[]都表示数组 D []--实例化一个空数组对象 实例化空数组:var arr=[]; 特点:元素个数不限定,元素类型不限制 13.Array 对象的常用方法: |--1.join()方法--用于把数组中的所有元素放入一个字符串   | eparato表示要使用的分隔符。如果省略该参数,则使用逗号作为分隔符 |--2.toString()方法--可把数组转换为字符串,并返回结果 |--3.concat()方法--用于连接两个或多个数组,该方法不会改变现有的数组 |--4.slice()方法--截取元素。根据给定的范围可从已有的数组中返回选定的元素 14.Function:js中一切都是对象,连方法都是1个对象!! 笔试题:js中方法定义集中方式: A:function compare(a,b){return a-b;}---*可以任意地方声明方法* B:var compare=function(a,b){return a-b;} ---| --其实方法名也是方法对象的变量名;等号右边其实就是1个匿名方法对象 |--*必须在传递之前声明方法对象* C:var compare=new Function('a','b','return a-b') ---| --其实js底层就是new Function;构造函数中的参数都是字符串 结论:所有的方法都是function类型的。 15.JavaScript中的所有事物都是对象,分为三类: |--简单对象:String、Number、Boolean |--组合对象:Array、Math、Date |--复杂对象:Function、Regex、Object等 16.Array排序: |--升序:function compare(a,b){return a-b;} |--降序:function compare(a,b){return b-a;} 比较器用法:arr.sort(比较器方法名); 遍历:for(var i=0;i<arr.length;i++)--等同Java Array倒转:arr.reverse();用于颠倒数组中元素的顺序 17.Array元素操作: |--arr.push(x);向数组增加1个新元素x(位于数组最后位置) |--arr.splice(开始位置,删除几个[,x1,x2,x3...]) |--arr.indexOf(x) 返回x在数组中的下标---经常用于判断元素是否存在。如返回-1,x则不在数组中 18.Number对象: |--x.toFixed(num):可把Number四舍五入为指定小数位数(num:0-20)的数字 |--x.toString():用于把一个 Number 对象转换为一个字符串,并返回结果 19.正则表达式对象:(专门用于查找和验证) reg.test(‘要验证的完整字符串’)匹配返回true,否则返回false 强调:如果正则表达式使用了^和$,必须完整匹配才行。反之则部分匹配 20.Date对象:(计算方法:先get,再计算,最后set回去) |--1.每个分量上都有一对get/set方法 |--2.命名:get|set年月日,单数;get|set时分秒,复数(s) |--3.除了日期从1开始到31结束外,其余都从0开始到-1结束 |--Date对象的常用方法 |--1.获取日期数据 getDate()、getDay()、getFullYear()等 |--2.修改日期数据 setDate()、setDay()、setFullYear()等 |--3.获取日期格式的字符串 toString()、toLocaleTimeString()、toLocaleDateString()等 21.argument参数:所有方法都隐藏的一个数组对象 作用:不设置任何的形参的情况下,自动接收所有传入参数 arguments.length:获得参数个数 arguments[i]:获得每个参数--都要判断和类型转换 22.全局函数:不用任何对象点(.)就可以调用--可用于所有的 JavaScript 对象 常用的全局函数有:parseInt/parseFloat、isNaN、eval、decodeURI/encodeURI等。 encodeURI和decodeURI: |--encodeURI:可把字符串作为 URI 进行编码 |--decodeURI:decodeURI()函数可对encodeURI()函数编码过的 URI 进行解码 eval() 函数可计算某个字符串,并执行其中的的JavaScript代码 23.BOM:操作浏览器窗口的对象模型。 --即浏览器对象模型 ,用来访问和操纵浏览器窗口,使 JavaScript 有能力与浏览器“对话” DOM:操作网页中元素对象的对象模型--即文档对象模型,用来操作文档 window对象的常用属性: |--document:窗口中显示的 HTML 文档对象 |--history:本次浏览过窗口的历史记录 | --前进:history.go(1);后退:history.go(-1);刷新:history.go(0); |--location:窗口文件地址对象(地址栏) |--event:事件对象 |--screen:屏幕对象 |--name:窗口名称 |--opener:打开当前窗口的 window 对象 |--navigator:有关浏览器的信息 |--cookieEnable:判断当前浏览器是否启用cookie |--userAgent:获得浏览器的名称和版本号 window 对象的常用方法有: |--alert();--警告框--只能点确认 |--confirm();确认框--可以选择确认或取消 |--prompt();对话框--用于显示可提示用户进行输入 |--window.open('url'[,'name']):打开1个选项卡 |--window.close():关闭当前选项卡 24.定时器:凡是网页中自动动态的效果都是用计时器实现的 |--周期性定时器:每隔一个时间段自动执行一次,循环执行 | |--setInterval() 启动-->用于启动一个周期性定时器 | 语法:timer=setInterval(方法名,间隔毫秒数) |--clearInterval() 停止-->用于停止一个周期性定时器 语法:timer=clearInterval(timer) |--1次性定时器:先等待一段时间,再自动执行一次,自动结束 |--setTimeout() 启动-->用于启动一个一次性定时器 |--clearTimeout() 停止-->用于停止一个一次性定时器 附: |--表单控件,读写内容:.value |--普通html元素,要想读写开始标签和结束标签之间的内容:[removed] 计时器:1.做什么事:方法; 2.一个变量:存计时器的线程号 3.何时启动计时器:事件 25.document:1.代表当前网页文档; 2.所有网页元素的根元素; 3.查找和操作元素,都要依靠document; 节点:nodeName--标签名或属性名 DOM操作样式:对象.className属性 等效于<标签class=""> DOM树:当前节点向上:txtObj[removed]() 向下:txtObj.getElementByTagName() 26.表单中查找控件对象:document.getElementsByName('name属性') DOM增加新节点:两种方法 创建新节点:document.creatElement('标签名') --此时新元素对象仅在内存中游离,页面看不见! 添加新节点:找到父元素! |--appendChild() 方法只能将新节点作为某节点的最后一个子节点 | --此时新元素追加到了父元素的末尾 |--parentNode.insertBefore()(新元素对象,A)--其中A为新元素要插入位置的后一位元素 DOM删除元素:node.removeChild(childNode)--node为父节点,childNode为要删除的节点 27.HTML DOM Select和Option对象: select对象:代表HTML表单中的一个下拉列表,每个<select> 标签即表示一个 Select 对象 |--属性: |--options:返回包含<select>元素中所有<option>的一个数组,每个元素对应一个<option>标签,索引从0开始 |--selectedIndex:设置或返回下拉列表中被选选项的索引号 |--size:设置或返回下拉列表中一次显示显示的选项数 |--方法: |--add(option):用于向<select>添加一个<option>元素。 |--remove(index):从下拉列表删除选项 Select对象有事件onChange当改变选择时调用的事件句柄。Select对象的onChange属性引用了一个事件句柄函数。当用户选 中一个选项,或者取消了对一个选项的选定时,就会调用该句柄。这个事件不会指定新的选项是什么,必须通过Select对象的 selectedIndex属性,或者各个Option对象的selected属性来确定这一点。 option对象:代表HTML表单中下拉列表中的一个选项,每个<option>标签表示一个Option对象 |--创建:var o = new Option(text,value); |--属性: |--index:返回下拉列表中选项的索引位置 |--text:设置或返回选项的文本值; |--value:设置或返回选项的值; |--selected:设置或返回选项的 selected 属性的值,该属性设置选项的当前状态,如果为 true,则该选项被选中 28.table对象: rows数组:表中所有行对象 方法:var row=table.iusertRow(i);--返回刚添加的新行 table.deleteRow(i); --i:行的下标。如果i取-1,即在表格末尾追加一行 tableRow对象: cells数组:当前行中所有单元格的对象 方法:var 刚添加的新单元格=tr.iusertCell(i); tr.deleteCell(i); tableCell对象:取单元格内容--td[removed] 29.事件冒泡: |--1.由外向内,捕获事件:记录哪级元素有什么事件 |--2.由内向外,冒泡执行:按记录的顺序由内向外执行 取消冒泡: |--1.获得事件对象!--event onclick="func(event)"--其中event和this都是关键字,表示事件对象 func(e)--此时e就是事件对象 |--2.取消冒泡:e.cancelBubble=true; 何时用:如果大量子元素拥有相同事件,应将相同事件统一定义在1个父元素上1次即可

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值