JavaScript基础
1、控制台输出
- console里面的内容方法非常丰富,你可以在控制台输入 console,然后就可看到
- console.warn:输出警告信息
- console.error:输出错误信息
- console.assert:参一为boolean、参二为输出信息,当参一为false时输出错误信息
- console.debug:用于调试信息
- console.table:以table形式输出
- console.time() & console.timeEnd():计算代码执行时间
- console.trace():输出函数调用栈(用于调试调用资源)
- console.clear:清空控制台所有输出
- console.(console.memory):查看当前内存的使用情况
2、Javascript的数据类型
-
JS的数组的判断方法(数组本质上是特殊类型的对象)
typeof([1]) // Object Array.isArray([1]) // true console.log([1] instanceof Array) //true
-
基本数据类型的变量是放在栈内存(stack)里面的,包括变量的标识符和变量的值
-
引用数据类型的值是放在堆内存(Heap)里面的(Object)
- 栈内存存放引用数据变量的标识符和引用的内存地址
- 堆内存存放变量值的对象内容
-
将任何数据转化为布尔值:!!
3、JavaScript的对象
-
访问对象除了person.name还有person[“name”]
-
使用[]访问,中括号访问会把动态变量转换为实际的变量
-
当所取得键名是一个特殊的字符串时,只能用[ ]不能用 .
var person={ name:'张三', "sex":'男' } var x=name; person.x //会到对象里寻找属性名为x的属性值,为undefined person[x] //会把x转化为name到对象里寻找,为张三 person.sex //为undefined person["sex"] //为男
-
-
同一个对象出现相同的属性名,那么属性值会以最后一个出现的为准(覆盖)–> 联系展开运算符的使用
4、Javascript的函数
- 局部变量会在函数执行之后被删除,全局变量会在页面关闭之后被删除
- 如果把值赋给了尚未声明的变量,该值自动作为window的一个属性,可配置,可删除
- 如果变量在函数里面未声明就赋值也会变成全局变量(非严格模式)
- 所有全局变量都归属于window对象
- **高内聚是说模块内部要高度聚合,低耦合是说模块与模块之间的藕合度要尽量低。**前者是说模块内部的关系,后者是说模块与模块间的关系。(严于律己,宽以待人)
5、JavaScript字符串
- 反斜杠(\)是一个转义字符。 转义字符将特殊字符转换为字符串字符,可以用于转义撇号,换行,引号,等其他特殊字符。
- 字符串的常用方法
- concat():返回拼接后字符串
- indexOf():返回查找的第一个目标字符串的索引
- replace():正则替换
- slice():返回提取的片段
- split():分割字符串为数组
- trim():移除首尾空白
- 模板字符串支持多行文本,而无需使用特殊的转义字符
6、JavaScript for 循环
-
for/in 用来遍历对象(遍历较慢,不利于性能)
for (x in person) // x 为属性名 { txt=txt + person[x]; }
-
for/of(来自ES6)用来遍历数组、字符串、Map、Set,不能直接遍历普通对象
const fruits = ['apple', 'banana', 'orange']; // 数组 for (const fruit of fruits) { console.log(fruit); } const str = 'hello'; // 字符串 for (const char of str) { console.log(char); } const map = new Map(); // Map对象 map.set('name', '张三'); map.set('age', 30); for (const [key, value] of map) { console.log(`${key}: ${value}`); } const set = new Set([1, 2, 3]); // Set对象 for (const num of set) { console.log(num); }
7、JavaScript的typeof
-
typeof null的结果为object,undefined和null值相等但类型不同
typeof undefined // undefined typeof null // object null === undefined // false null == undefined // true
-
null:主动释放一个变量引用的对象,表示一个变量不再指向任何对象地址
- 何时使用:当使用完一个比较大的对象时,需要对其进行释放内存时,设置为 null
-
垃圾回收站–>专门释放对象内存的一个程序
- 在底层,后台伴随当前程序同时运行;引擎会定时自动调用垃圾回收器
- 当一个对象没有被任何变量引用时会被释放
8、JavaScript的类型转换
-
NaN:number
- 用于本来要返回数值的操作数但未返回数值的情况
- NaN与任何值都不相等,包括NaN本身
- isNaN() 方法来判断某个数值是否是NaN这个特殊的数
-
Date、Array、null:object。判断具体类型可以通过instanceof
-
转换为string的全局方法
- String()
- toString()
-
转换为number的全局方法
- Number()
- 一元运算符+可将变量转换为number类型,如果是转换不了为数字的变量,则结果为NaN
- parseInt()和parseFloat()
-
string与number做加法运算–>number会隐式转换为string
-
string与number做减法运算–>string会隐式转换为number
-
可以使用typeof判断变量是否存在
if(typeof x != undefined){...} // 替换下面这种方法 if(x){...} // 如果a为undefined的话会报错
9、JavaScript 正则表达式
-
语法格式:/正则表达式主体/可选修饰符
-
字符串方法search:用于检索字符串的指定子字符串,返回其起始索引
var n = str.search(/Runoob/i); // 参数为字符串或正则表达式
-
字符串方法replace:用于替换字符串的指定子字符串,返回新的字符串
var txt = str.replace(/microsoft/i,"Runoob");// 替换microsoft为Runoob
-
text()方法为正则表达式的方法,用于检测字符串是否含有该正则的文本,返回Boolean
/e/.text("The best things in life are free!")
10、JavaScript调试
- 设置断点,在每个断点上都会停止执行代码,方便我们检查变量的此时的值,检查完毕可以重新执行代码
- debugger关键字用于停止执行JS,效果与断点一致
11、JavaScript变量提升(Hoisting)
-
声明提升:函数声明和变量声明总是在代码执行前会被解释器悄悄地被"提升"到方法体的最顶部。
-
变量声明提升:变量只有声明部分会提升,赋值(初始化)部分则保留在原地。
var x = 5; // 初始化 x var y = 7; // 初始化 y (x和y本来就在顶部,不需要提升) elem = document.getElementById("demo"); // 查找元素 elem.innerHTML = x + " " + y; // 显示 :5 7 var x = 5; // 初始化 x elem = document.getElementById("demo"); // 查找元素 elem.innerHTML = x + " " + y; // 显示:x undefined var y = 7; // 初始化 y // 这里声明部分(var y)提升了,但是初始化(y=7)不会提升
-
函数声明提升
- 使用函数function foo(){…}:函数声明和初始化都会提升
- 使用表达式var foo= function (){…}:仅提升声明部分,表达式被留在原地
-
ES6 引入的
let
和const
也有提升,但表现不同 - 它们存在"暂时性死区"- 暂时性死区:从作用域开始到
let
/const
变量声明语句执行之前的区域,在这期间访问该变量会抛出错误
- 暂时性死区:从作用域开始到
-
JavaScript 严格模式(strict mode)不允许使用未声明的变量。
12、JavaScript严格模式
-
严格模式通过在脚本或函数的头部添加 use strict; 表达式来声明。
-
在函数内部声明是局部作用域 (只在函数内使用严格模式)
x = 3.14; // 不报错(此时函数外部严格模式无效) myFunction(); function myFunction() { "use strict"; y = 3.14; // 报错 (y 未定义) }
-
严格模式下,禁止this指向全局对象
function f(){ return !this; } // 返回false,因为"this"指向全局对象,"!this"就是false function f(){ "use strict"; return !this; } // 返回true,因为严格模式下,this的值为undefined,所以"!this"为true。
-
因此,使用构造函数时,如果忘了加new,this不再指向全局对象,而是报错
// 情况一: function f() { "use strict"; this.a = 1; } f(); // ❌ TypeError: Cannot set property 'a' of undefined // 情况二: function f() { "use strict"; this.a = 1; } const obj = new f(); // ✅ 正常执行 console.log(obj.a); // 1
- 严格模式下,普通函数调用时
this
是undefined
(非严格模式下是window
–>被提升) new
操作符会使this
指向一个新创建的空对象,无论是否严格模式
- 严格模式下,普通函数调用时
13、JavaScript的误区
- JavaScript 中的所有数据都是以 64 位浮点型数据(float) 来存储
- JavaScript 的 **自动分号插入(ASI)**让return默认只作用于本行内容,需要作用于多行时可以使用括号包裹、使用模板字符串、数组、对象等
- 许多程序语言都允许使用名字来作为数组的索引。使用名字来作为索引的数组称为关联数组(或哈希)。但是JavaScript 不支持使用名字来索引数组,只允许使用数字索引。
14、JavaScript表单
-
JavaScript实现表单验证
<form name="myForm" action="demo_form.php" onsubmit="return validateForm()" method="post"> 名字: <input type="text" name="fname"> <input type="submit" value="提交"> </form> <script> function validateForm() { // document.forms就可以获取表单啦! var x = document.forms["myForm"]["fname"].value; if (x == null || x == "") { alert("需要输入名字。"); return false; } } </script> // document.forms["myForm"]根据表单的name得到表单
-
浏览器也会支持HTML的表单验证的自动验证,如果有字段为空,required属性会阻止表单提交
-
HTML5 提供了一些内置的表单验证功能,例如
required
、pattern
、min
、max
等属性。
15、JavaScript的this
-
一个区别:在面向对象里面,this指当前对象的一个引用,但是在JavaScript里面,this的指向并不是不变的
-
this 的值取决于函数的调用方式,而不是定义位置
-
全局环境中,this指向全局对象(浏览器指向window、Node环境指向global)
-
普通函数this指向全局对象(不需要关注普通函数定义的位置,只要它不是对象的直接方法就行)
const obj = { name: '张三', greet: function() { setTimeout(function() { console.log('你好,我是' + this.name); }, 100); } }; obj.greet(); // 输出 "你好,我是undefined"(因为回调函数的this指向window) // 在定时器里面的那个函数并不是对象的方法,所以this没有指向该对象,而是指向全局对象
-
在严格模式下,在函数中的this为undefined,单独使用this的话依旧指向全局对象
-
函数作为对象的方法调用时,this指向调用该方法的具体对象
-
使用new调用构造函数时,this指向新创建的实例
-
在DOM事件处理函数中,this指向触发事件的元素
-
箭头函数没有this,他会捕获所在上下文的this
-
-
在JavaScript中函数也算是对象,是对象就有方法,apply和call是函数对象异常强大的两个方法,他们允许显式切换函数执行的上下文环境(context),即this绑定的对象
var person1 = { fullName: function(greeting,punctuation) { return greeting + ', ' + this.name + punctuation; //本来this指向person1 } } var person2 = { name:'张三' } // call使this指向person2 person1.fullName.call(person2,'你好','!'); // "你好张三!"
- func.call(thisArg, arg1, arg2, …):参数一为指定的this,后续参数为函数的参数列表
- func.apply(thisArg, [argsArray]):参数一为指定的this,后续参数为包含参数的数组
16、JavaScript JSON
-
JSON数据格式通常用于服务端向网页传输数据,全称 JavaScript Object Notation
-
JSON 格式在语法上与创建 JavaScript 对象代码是相同的。所以两者很容易互相转化
{"sites":[ {"name":"Runoob", "url":"www.runoob.com"}, {"name":"Google", "url":"www.google.com"}, {"name":"Taobao", "url":"www.taobao.com"} ]}
-
转化方法
- JSON.parse():JSON—>JavaScript对象
- JSON.stringify():JavaScript—>JSON
17、JavaScript void
-
特殊的表达式,主要用于阻止默认行为(如链接跳转)而不执行任何操作
// 阻止链接跳转 <a href="javascript:void(0)" onclick="myFunction()">点击执行JS但不跳转</a> // 比 href="#" 更好(不会滚动到页面顶部) // 阻止默认提交表单 <form onsubmit="javascript:void(0); return false;"> <button type="submit">提交</button> </form> // 作为无副作用的占位符 const result = condition ? doSomething() : void(0);
JavaScript函数、类
1、函数定义
-
不同形式函数的存储位置
// 函数表达式 var x = function(a, b) { return a * b };// 这也是匿名函数 // 存储在变量x的值中 // 函数提升只提升声明,不提升函数体 // 函数声明 function multiply(a, b) { return a * b } // 存储在当前作用域的变量环境中,相当于 => var multiply= function(){...} // 函数可以整体提升(声明+函数体),可提前调用 // 立即执行函数 (function(a, b) { return a * b })(2, 3); // 不存储于任何变量中 // 执行后函数对象会被垃圾回收(除非返回的值被其他变量引用)
-
函数同样可以通过内置的 JavaScript 函数构造器(Function())定义
var myFunction = new Function("a", "b", "return a * b"); // 但是建议尽量少用new
-
toString() 方法可以将整个函数作为一个字符串返回
-
箭头函数的匿名自调用为 (()=>{})() ,箭头函数的this默认绑定外层的this
2、JavaScript函数参数
-
显式参数(Parameters):函数定义时声明的命名参数
-
隐式参数通过(arguments)访问,是一个类数组,包含所有传入的参数
function sum() { let total = 0; for(let i = 0; i < arguments.length; i++) { total += arguments[i]; } return total; } console.log(sum(1, 2, 3)); // 6 //arguments.length为函数实参个数 //arguments.callee引用函数自身
-
箭头函数没有arguments,arguments只接收调用函数时传入的参数,不接收默认值
3、JavaScript函数调用
-
this代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。随着函数使用场合的不同,this 的值会发生变化。但是有一个总的原则,那就是this指的是,调用函数的那个对象
-
一个函数的this如果指向全局对象的话,那么调用这个函数也可以用:window.函数名()
- 所以区分是不是指向window,看一下能不能使用window.函数名()调用即可
-
如果函数调用前使用了 new 关键字, 则是调用了构造函数。就像创建了新的函数,但实际上 JavaScript 函数是重新创建的对象。构造函数的调用会创建一个新的对象。新对象会继承构造函数的属性和方法。下面是一个实例
// 定义一个构造函数 function myFunction(arg1, arg2) { this.firstName = arg1; this.lastName = arg2; } // 使用new关键字 调用构造函数 就像是创建了一个新的对象 var x = new myFunction("John","Doe"); x.firstName; // 返回 "John"
-
一个有趣的函数:调取页面所有图片的url
[].map.call(document.getElementsByTagName('img'), function (img){ return img.src;})
4、JavaScript闭包
// 一个闭包函数
var add = (function (){
var count=0;
return function (){count+=1}
})
add()
add()
add() //此时count=3
-
以上自我调用函数只执行一次。设置计数器为 0。并返回函数表达式存储在变量add中,add变量可以作为一个函数调用,并且可以访问上一层作用域的count。这个就叫做JavaScript闭包,它使函数拥有私有变量变成可能。闭包是一种保护私有变量的机制,它在函数执行时创建一个私有作用域,从而保护内部的私有变量不受外界干扰。直观地说,闭包就像是一个不会被销毁的栈环境。闭包就是一个函数引用另一个函数的变量,致使被引用的变量不会被回收,因此可以用来封装成一个私有变量。这是优点也是缺点,不必要的闭包只会增加内存消耗
-
闭包三要素
- 外层函数
- 外部变量(count)
- 内层函数(引用外层函数的外部变量count)
-
闭包允许你创建真正的私有变量(数据封装)
function createCounter() { let count = 0; // 私有变量 return { increment: function() { count++; }, getCount: function() { return count; } }; } const counter = createCounter(); counter.increment(); console.log(counter.getCount()); // 1 console.log(counter.count); // undefined(无法直接访问)
-
闭包使得函数可以"记住"并访问其词法作用域中的变量,即使函数在其词法作用域之外执行
function makeGreeter(greeting) { return function(name) { return `${greeting}, ${name}!`; }; } const sayHello = makeGreeter("Hello"); const sayHi = makeGreeter("Hi"); console.log(sayHello("Alice")); // "Hello, Alice!" console.log(sayHi("Bob")); // "Hi, Bob!"
-
闭包是实现模块模式的基础,可以创建独立的、可复用的代码单元
const calculator = (function() { let memory = 0; function add(a, b) { return a + b; } function store(value) { memory = value; } function recall() { return memory; } return { add, store, recall }; })(); console.log(calculator.add(2, 3)); // 5 calculator.store(10); console.log(calculator.recall()); // 10
-
闭包可以帮助你减少全局变量的使用,防止命名冲突
// 不使用闭包(污染全局) let count = 0; function increment() { count++; } // 使用闭包(不污染全局) const counter = (function() { let count = 0; return { increment: function() { count++; }, getCount: function() { return count; } }; })();
-
闭包使得函数可以返回函数,这是函数式编程的基础
function multiplyBy(factor) { return function(number) { return number * factor; }; } const double = multiplyBy(2); const triple = multiplyBy(3); console.log(double(5)); // 10 console.log(triple(5)); // 15
-
闭包在异步编程中非常有用,可以保留回调函数执行时所需的上下文
function setupButtons() { for (var i = 1; i <= 3; i++) { (function(index) { document.getElementById(`btn-${index}`) .addEventListener('click', function() { console.log(`Button ${index} clicked`); }); })(i); } }
-
闭包可以用来缓存昂贵的计算结果,提高性能,实现缓存和记忆化
function createMemoizedFibonacci() { const cache = {}; return function fib(n) { if (n in cache) return cache[n]; if (n <= 1) return n; cache[n] = fib(n - 1) + fib(n - 2); return cache[n]; }; } const fib = createMemoizedFibonacci(); console.log(fib(10)); // 55(快速返回,因为有缓存)
-
缺点:闭包会保持对私有变量的引用,导致内存无法释放,并且创建大量闭包可能影响性能
-
解决思路:在闭包里面返回一个函数是让引用变量指向null
5、JavaScript 类
-
类的构造方法constructor在实例化时自动调用,用于初始化类对象属性
-
类继承使用extends关键字(底层依旧依赖于原型继承)
- super()方法用于调用父类的构造函数
- 继承基类的派生类拥有基类的属性和方法(需调用super方法初始化基类属性)
-
下面是不使用extends继承,而是直接使用原型继承的过程
// 定义一个构造函数 function Animal(name) { this.name = name; } // 可以给构造函数的原型上添加一些属性方法 Animal.prototype.eat = function() { console.log(this.name + " is eating."); }; // 定义另一个构造函数 function Dog(name, breed) { // 调用Animal类的构造方法,使用call方法使Animal对象的this指向Dog对象 // 并传入参数调用Animal构造函数的构造方法 Animal.call(this, name); // 定义Dog对象自身的属性 this.breed = breed; } // 下一步需要建立原型链,让 Dog 继承 Animal // 以Animal.prototype为原型创建一个新对象 // 将 Dog的prototype 指向这个新对象,建立原型链 Dog.prototype = Object.create(Animal.prototype); // 这个时候Dog.prototype.constructor指向的是Animal // 我们需要手动改变它的指向,使其指向Dog,完成原型继承 Dog.prototype.constructor = Dog; Dog.prototype.bark = function() { console.log(this.name + " is barking."); }; var dog = new Dog("Buddy", "Labrador"); dog.eat(); // 调用从 Animal 继承的方法 dog.bark(); // 调用 Dog 的方法
-
类中我们可以使用 getter 和 setter 来获取和设置值,getter 和 setter 都需要在严格模式下执行
-
类中添加 getter 和 setter 使用的是 get 和 set 关键字
-
虽然get和set是方法,但是使用时不需要加 ()
-
getter/setter 方法的名称不能与属性的名称相同,建议使用**下划线 _ **区分
class Runoob { constructor(name) { this._sitename = name; } set sitename(x) { this._sitename = x; } get sitename() { return this._sitename; } } let noob = new Runoob("教程"); noob.sitename = "RUNOOB"; // 相当于调用了set方法 document.getElementById("demo").innerHTML = noob.sitename; // 调用get方法
-
-
函数声明和类声明之间的一个重要区别在于, 函数声明会提升,类声明不会
-
static修饰的静态方法
-
使用 static 关键字修饰的方法,又叫类方法,属于类的,不会给到实例化对象上,在实例化对象之前可以通过 类名.方法名 调用静态方法。
-
静态方法不能在实例化的对象上调用,只能在类中调用
class Runoob { constructor(name) { this.name = name; } static hello() { return "Hello!!"; } } let noob = new Runoob("Runoob"); // 可以在类中调用 'hello()' 方法 document.getElementById("demo").innerHTML = Runoob.hello(); // 不能通过实例化后的对象调用静态方法 // document.getElementById("demo").innerHTML = noob.hello(); // 以上代码会报错
-
如果想要在实例化的对象中调用静态方法,可以将该对象作为参数传递给类的静态方法
class Runoob { constructor(name) { this.name = name; } static hello(x) { return "Hello " + x.name; } } let noob = new Runoob("Runoob"); document.getElementById("demo").innerHTML = Runoob.hello(noob);
-
6、JavaScript构造函数和普通函数
- 构造函数通常以大写字母开头,通过
new
关键字调用,用于创建对象实例- 通常会在内部操作
this
,并可能通过this
添加属性/方法 - 通常会有原型对象(
prototype
),用于共享方法 - 默认返回新创建的对象(即
this
),除非显式返回一个对象
- 通常会在内部操作
- 普通函数通常以小写字母开头,一般直接调用,或作为方法调用
- 可能没有
this
操作,或直接返回结果 - 一般不需要原型,返回
undefined
或显式指定的值
- 可能没有
- 如果函数通过
new
调用,内部的this
会指向新创建的对象;否则this
指向全局对象(非严格模式)或undefined
(严格模式)。
7、JavaScript new
-
new 是 JavaScript 中用于实例化对象的关键操作符,它基于构造函数创建对象实例
-
使用new之后发生的事情:
- 创建一个对象
- 设置原型:将新对象的 [[Prototype]](即 __ proto __)链接到构造函数的 prototype 属性
- 绑定this
- 执行构造函数–> 初始化数据
- 返回对象
-
手动实现 new 关键字的作用
function myNew(constructor, ...args) { // 1. 创建新对象并设置原型 const obj = Object.create(constructor.prototype); // 2. 执行构造函数并绑定 this const result = constructor.apply(obj, args); // 3. 处理返回值 return result instanceof Object ? result : obj; } // 使用示例 const p = myNew(Person, '李四', 30);
-
实例化构造函数时忘记使用new会造成全局污染(因为此时this会指向window)
解决方案:使用ES6的class语法,强制使用new来实例化对象
-
缺点:new创建的对象比普通对象更加笨重(需要维护原型链),且V8引擎对普通对象的优化更好
-
工厂函数
// 简单工厂函数 function createPerson(name, age) { return { name, age, greet() { console.log(`Hello, I'm ${this.name}`); } }; } const person = createPerson('张三', 25); person.greet(); // "Hello, I'm 张三" //不使用 new 关键字 //不依赖于 this 绑定 //不涉及原型继承 //直接返回一个新对象
JavaScript DOM
1、DOM 简介
-
当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)
-
通过id、标签名、类名查找元素
document.getElementById("intrp") // 通过id document.getElementsByTagName("p") // 通过标签名,可查找多个 document.getElementsByClassName("intro") // 通过类名,可查找多个
-
使用标签名和类名查找多个HTML元素时会返回一个伪数组,无法使用真数组方法。可以使用数组原型配合 slice 方法,利用 call,apply,bind 方法将伪数组转为真数组
var x=document.getElementById("main"); var y=x.getElementsByTagName("p"); console.log(x)//在控制台我们可以看到原型proto为NodeList,是伪数组 console.log(y)//在控制台我们可以看到原型proto为htmlcollection,是伪数组 //伪数组转为真数组的三个方法 // 获取数组原型的slice方法,将该方法的this指向y,相当于是y调用了slice方法 console.log(Array.prototype.slice.call(y)) // slice方法不传参会返回完整的数组副本 console.log(Array.prototype.slice.apply(y)) console.log(Array.prototype.slice.bind(y)()) //在控制台我们可以看到原型proto为Array(0),是真数组
-
HTMLCollection 对象类似包含 HTML 元素的一个伪数组
- 由getElementsByTagName() 方法返回
-
NodeList 对象
- 由**getElementsByClassName()或querySelectorAll()**返回
-
伪数组是指具有数字索引和 length 属性,但不具备数组方法的对象
arguments
对象(函数内部的参数对象)也是伪数组
2、DOM HTML
-
document.write() 可用于直接向 HTML 输出流写内容
- 对不要在文档(DOM)加载完成之后使用 document.write()。这会覆盖该文档。
- 如需要使用,应该在页面加载过程中使用
-
修改 HTML 内容的最简单的方法是使用 innerHTML 属性
-
如需改变 HTML 元素的属性,请使用:
// document.getElementById(id).属性=新属性值 document.getElementById("image").src="landscape.jpg
-
如需改变 HTML 元素的样式,请使用:
// document.getElementById(id).style.property=新样式
document.getElementById("p2").style.color="blue";
document.getElementById("p2").style.fontFamily="Arial";
document.getElementById("p2").style.fontSize="larger";
3、DOM 事件
-
onload 和 onunload 事件会在用户进入或离开页面时被触发
-
onchange 事件常结合对输入字段的验证来使用
-
onmouseover 和 onmouseout 事件可用于在用户的鼠标移至 HTML 元素上方或移出元素时触发函数
-
onmousedown, onmouseup 以及 onclick 构成了鼠标点击事件的所有部分
-
对于onclick事件写法: οnclick=函数名+(),这是因为onclick 的值是一个 JavaScript 代码字符串,所以你可以直接写代码,需要加括号
-
addEventListener添加事件句柄(注意:不需要使用 “on” 前缀)
// 直接向DOM添加事件 document.getElementById("intro").onclick=function(){...} // 添加事件句柄 document.getElementById("myBtn").addEventListener("click", function(){...}); // 当需要传递参数时,可以使用匿名函数里面调用需要参数的函数 element.addEventKistener("mouseup",function(){myFun(a,b)})
- 可以使用
element.removeEventListener("mousemove", myFunction)
方法来移除事件的监听 - 完整写法:
element.addEventListener(event, function, useCapture)
,useCapture可选参数默认为false,此时为冒泡传递,改为true时为捕获传递 - addEventListener() 方法添加的事件句柄不会覆盖已存在的事件句柄
- 可以使用
-
在 事件冒泡 中,内部元素的事件会先被触发,然后再触发外部元素
-
在 事件捕获 中,外部元素的事件会先被触发,然后才会触发内部元素的事件
4、DOM 元素
-
创建新的HTML元素节点—**appendChild()**方法
-
如果我们需要将新元素添加到开始位置,可以使用 insertBefore() 方法
-
移除旧的HTML元素节点—**removeChild()**方法
-
创建新的元素节点:document.createElement(“标签名”)
-
创建新的文本节点:document.createTextNode(“文本内容”)
<div id="div1"> <p id="p1">这是一个段落。</p> <p id="p2">这是另外一个段落。</p> </div> <script> var para = document.createElement("p"); // 创建新元素 var node = document.createTextNode("这是一个新的段落。"); // 创建元素的文本节点 para.appendChild(node); // 将文本节点添加到元素中 var p1 = document.getElementById("p1") var element = document.getElementById("div1"); element.removeChild(p1) // 移除元素节点 element.appendChild(para); // 将元素节点添加到元素中 </script>
-
DOM 需要清楚您需要删除的元素,以及它的父元素,所以如果你只想要写要删除的元素,你可以这样:
var child = document.getElementById("p1"); child.parentNode.removeChild(child); // 先得到父元素节点,再移除节点
-
替换节点方法replaceChild(新节点,旧节点)
JavaScript高级
1、JavaScript对象
-
在JavaScript中,所有事物都可以被包装为对象
-
Object 构造函数创建一个对象包装器,该参数从 Object.prototype 继承属性和方法
-
JavaScript 是面向对象的语言,但 JavaScript 不使用类。JavaScript 基于 prototype,而不是基于类的。
-
当你尝试访问一个基本类型的属性或方法时,JavaScript 会自动临时地将这个基本类型的值转换为对应的包装对象,以便可以调用该对象上的属性和方法。这种转换是自动进行的,通常被称为**“装箱”**。一旦属性和方法的使用完毕,这个临时对象就会被销毁(拆箱),值又恢复为其原始的基本类型
let str = "Hello"; console.log(str.length); // 输出 5 //在上面的代码中,str 是一个字符串基本类型的值。当我们尝试访问 str.length 时,JavaScript 会临时地将 str 转换为一个 String 对象,以便可以访问 length 属性。一旦 length 被获取,这个临时的 String 对象就会被销毁,str 仍然保持为字符串基本类型。
-
频繁的装箱和拆箱可能会影响性能
2、JavaScript prototype
-
**原型(prototype)**为函数对象提供了继承和共享属性的机制
- prototype是函数对象的内置属性,通过(_ _ proto _ _)访问
- 作用是实现属性和方法的共享,从而减少内存的占用
- 原型是一个对象,它是其他对象的模板或蓝图
- 所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例
-
对象通过**原型链(prototype chain)**来实现继承
-
所有的 JavaScript 对象都会从另一个 prototype(原型对象)中继承属性和方法
-
当一个对象试图访问一个属性或方法时,如果在该对象自身没有找到,JavaScript 会沿着原型链向上查找,直到找到对应的属性或方法,或者达到原型链的顶端
null
为止// 修改对象自己的原型,这样可以影响到所有基于该原型创建的对象 Person.prototype.属性 = 属性值 // 访问一个对象外面的原型 console.log(Person.__proto__) // 打印的是对象Person的原型对象
-
-
Object.create 方法
-
该方法允许你创建一个新对象,并将其原型设置为指定的对象
let Person = Object.create(Object) // 创建一个对象Person,设置其原型为Object
-
-
利用prototype来使代码更加简洁:使用构造器(函数体)定义属性,使用原型对象(prototype)定义方法。
如此,构造器只包含属性定义,而方法则分装在不同的代码块,使代码更具可读性
3、JavaScript Number 对象
-
在JavaScript中,数字不分为整数类型和浮点型类型,所有的数字都是由 浮点型类型(64位浮点格式)
-
最大值为(Number.MAX_VALUE),最小值为(Number.MIN_VALUE),无穷大为Infinity
-
如果前缀为 0,则 JavaScript 会把数值常量解释为八进制数,如果前缀为 0 和 “x”,则解释为十六进制数
-
可以使用 toString() 方法 输出16进制、8进制、2进制
var myNumber=128; myNumber.toString(16); // 返回 80 myNumber.toString(8); // 返回 200 myNumber.toString(2); // 返回 10000000
-
Number对象的常用方法
- parseInt:将字符串转换为整数
- parseFloat:将字符串转化为浮点数
- isNaN:判断是否为NaN
- toFixed:返回指定小数位数的表示形式
4、JavaScript String 对象
-
字符串使用 indexOf() 来定位字符串中某一个指定的字符首次出现的位置,如没找到则返回-1
-
replace() 方法在字符串中用某些字符替换另一些字符,返回新的字符串
-
字符串使用split()函数分割之后转为数组
-
Javascript 中可以使用反斜线(\)的转义功能插入特殊符号
-
手写trim( )方法:
if(typeof(String.prototype.trim) === "undefined") // 先判断有没有这个属性 { String.prototype.trim = function() // 把该方法写在String的原型上 { return String(this).replace(/^\s+|\s+$/g, ''); }; }
5、JavaScript 对象系统的核心机制
-
prototype(原型)属性
- 只有函数拥有该属性,就是说protptype是Function对象的一个属性
- prototype是用于保存对象的共享属性和方法的,原型的属性和方法并不会影响函数本身的属性和方法
- 当函数作为构造函数时,实例的_ _proto __ 会指向构造函数的prototype
-
_ _proto__属性
-
所有对象都有_ _proto__属性
-
用于构成原型链,实现继承
-
Object.getPrototypeOf(obj):获取obj的prototype
const obj = {}; console.log(obj.__proto__ === Object.prototype); // true console.log(Object.getPrototypeOf(obj)===Object.prototype) //true console.log(Object.getPrototypeOf(obj)===obj.__proto__)
-
-
constructor属性
-
一个对象的prototype属性内保存着这个对象的共享属性和方法,里面有一个共享属性叫做constructor,该属性会指回该对象,如下:
function Person() {} console.log(Person.prototype.constructor === Person); // true
-
-
三者关系图
实例对象
{
_ proto_: --------> 构造函数的 prototype 对象
} {
constructor: --> 构造函数本身
_ _proto _ _: ----> 再往上一级的原型 (如 Object.prototype)
}function Person(name) { this.name = name; } // 1. 构造函数默认会有 prototype 属性,指向内部 console.log(Person.prototype); // { constructor: Person } // 2. 创建实例 const john = new Person('John'); // 3. 实例的 __proto__ 指向其构造函数的 prototype,即指向外部 console.log(john.__proto__ === Person.prototype); // true // 4. 原型对象的 constructor 指回构造函数,即跳回自己本身 console.log(Person.prototype.constructor === Person); // true // 5. 原型对象本身也是对象,也有 __proto__ console.log(Person.prototype.__proto__ === Object.prototype); // true // 6. Object.prototype 是最顶层的原型 console.log(Object.prototype.__proto__); // null
JavaScript BOM
1、JavaScript Window
-
BOM全称浏览器对象模型(Browser Object Model )
-
所有浏览器都支持 window 对象。它表示浏览器窗口。所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员,甚至 HTML DOM 的 document 也是 window 对象的属性之一
window.document.getElementById("header");
-
Window 尺寸
var w=window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; var h=window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; // 使用||可以确保兼容不同的浏览器
-
window.open() - 打开新窗口
window.close() - 关闭当前窗口
window.moveTo() - 移动当前窗口
window.resizeTo() - 调整当前窗口的尺寸 -
全局变量不能通过 delete 操作符删除;而 window 属性上定义的变量可以通过 delete 删除
2、JavaScript Window Screen
- window.screen 对象包含有关用户屏幕的信息
- screen.availWidth - 可用的屏幕宽度
- screen.availHeight - 可用的屏幕高度
3、JavaScript Window Location
- window.location 对象用于获得当前页面的地址 (URL),并把浏览器重定向到新的页面
- location.hostname 返回 web 主机的域名
- location.pathname 返回当前页面的路径和文件名
- location.port 返回 web 主机的端口 (80 或 443)
- location.protocol 返回所使用的 web 协议(http: 或 https:)
- location.href 返回当前页面的 URL
- location.assign 加载 URL 指定的新的 HTML 文档
4、JavaScript Window history
- window.history 对象包含浏览器的历史
- history.back() 方法加载历史列表中的前一个 URL
- history forward() 方法加载历史列表中的下一个 URL
5、JavaScript Window Navigator
-
window.navigator 对象包含有关访问者浏览器的信息
<script> txt = "<p>浏览器代号: " + navigator.appCodeName + "</p>"; txt+= "<p>浏览器名称: " + navigator.appName + "</p>"; txt+= "<p>浏览器版本: " + navigator.appVersion + "</p>"; txt+= "<p>启用Cookies: " + navigator.cookieEnabled + "</p>"; txt+= "<p>硬件平台: " + navigator.platform + "</p>"; txt+= "<p>用户代理: " + navigator.userAgent + "</p>"; txt+= "<p>用户代理语言: " + navigator.language + "</p>"; document.getElementById("example").innerHTML=txt; </script>
6、JavaScript 弹窗
- window.alert:警告框
- window.confirm:确认框,返回boolean
- window.prompt:提示框,返回输入值
7、JavaScript 计时事件
- window.setInterval:间隔指定的毫秒数不停地执行指定的代码
- clearInterval() 方法用于停止 setInterval() 方法执行的函数代码
- window.setTimeout:在指定的毫秒数后执行指定代码
- clearTiemout()清理
8、JavaScript Cookie
-
Cookie 用于存储 web 页面的用户信息
-
当浏览器从服务器上请求 web 页面时, 属于该页面的 cookie 会被添加到该请求中。服务端通过这种方式来获取用户的信息。
-
JavaScript 可以使用 document.cookie 属性来创建 、读取、及删除 cookie
//Cookie 以名/值对形式存储 username=John Doe //JavaScript 中,创建 cookie 如下所示: document.cookie="username=John Doe"; //您还可以为 cookie 添加一个过期时间(以 UTC 或 GMT 时间)。默认情况下,cookie 在浏览器关闭时删除: document.cookie="username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT"; //您可以使用 path 参数告诉浏览器 cookie 的路径。默认情况下,cookie 属于当前页面。 document.cookie="username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT; path=/";