JavaScript笔记
0. 对象的分类:
内建对象:由ES标准定义,如:Math String Number Boolean Function Object...
宿主对象:由JS运行环境提供,主要指浏览器,如:DOM BOM
自定义对象:由开发人员新建的对象
1. 删除对象属性:
var obj = new Object(); obj.name = "tom"; obj.age = 20; console.log(obj); delete obj.name; console.log(obj.name);
2. 对象的属性名和属性值
// 特殊属性名可以用[] var obj = new Object(); obj["123"] = 789; obj["nihao"] = "你好"; var n = "123"; var k = "nihao"; console.log(obj[n]); console.log(obj["123"]); // 打印一样 // 属性值可以任意 obj.test = 123; obj.test = "ffm349re"; obj.test = true; obj.test = null; obj.test = undefined; var obj2 = new Object(); obj2.name = "tony"; obj.test = obj2; // in运算符,检查对象是否包含某个属性 console.log(k in obj); console.log("test" in obj); console.log("name" in obj); console.log("name" in obj2);
3. 基本数据类型:String Number Boolean Null Undefined
4. 引用数据类型:Object
5. 对象字面量
var obj3 = {}; // 与var obj3 = new Object();等价 obj3.name = "tom"; obj3 = { // 属性名可以加引号,也可以不加,一般不加,如果属性名特殊,则加 name: "jerry", age: 20 };
6. 函数也是对象,一切皆对象
var fun = new Function(); console.log(typeof fun); // function var fun2 = new Function("console.log('我是一个函数。');"); fun2(); // 调用fun2()
7. 一般函数不按照第六条写,一般写成下面的形式
function fun3() { console.log('我是一个函数。'); } fun3(); // 调用fun3 var fun4 = function () { console.log("我是匿名函数,然后赋值给变量"); }; fun4(); // 调用fun4
8. 函数实参可以是任何值
function sayHello(name) { console.log("hello, " + name); } function fun5(a) { console.log("a = " + a); a("tom"); } fun5(sayHello);
9. 同样,返回值也可以是任何值,包括函数
10. 立即执行函数,只执行一次,没有函数名,相当于执行了匿名函数
(function () { alert("hello..."); })(); (function (a, b) { // alert("hello..."); console.log(a + b); })(12, 34)
11. 对象的属性值可以是任何值,包括函数,其实把函数当作对象一切都好理解,这个时候就把函数称作对象的方法
var obj = new Object(); obj.name = "tom"; obj.age = 23; obj.sayName = function () { console.log(obj.name); }; // 等价于 obj = { name: "tom", age: 23, sayName: function () { console.log(obj.name); } } obj.sayName(); console.log(obj.sayName); console.log(obj.sayName());
12. 枚举对象中的属性
var obj = { name: "James", age: 12, gender: "male", address: "usa" } for (var key in obj) { console.log(key + "-->" + obj[key]); }
13. 作用域
-在JS中🈶️两种作用域:
1. 全局作用域
-直接编写在script标签中的JS代码,都在全局作用域;
-全局作用域在页面打开时创建,在页面关闭时销毁;
-在全局作用域中有一个全局对象window,它代表的是浏览器窗口,由浏览器创建,我们可以直接使用;
-在全局作用域中:
创建的变量都会作为window对象的属性保存;
创建的函数都会作为window对象的方法保存。
-全局作用域中的变量都是全局变量,在页面的任意位置都可以访问到;
var a = 10; function fun() { console.log("我是fun函数。"); } console.log(window.a); window.fun(); window.alert("hello.");
-变量的声明提前:
使用var关键字声明的变量,会在所有的代码执行之前被声明;
但如果声明的变量不是用var,则变量不会被提前声明。
// console.log("k = " + k); // Uncaught ReferenceError: k is not defined // console.log("m = " + m); // m = undefined // var m = 10; // 等价于 var m; console.log("m = " + m); // m = undefined m = 10;
-函数的声明提前:
使用声明式创建的函数function(){},会在所有代码执行之前就被创建;
使用函数表达式创建的函数,不会被提前创建,所以不能在调用之后创建
fun(); // 正常 // 函数声明,会被提前创建 function fun() { console.log("我是fun函数"); } fun2(); // Uncaught TypeError: fun2 is not a function // 函数表达是不会被提前创建 var fun2 = function () { console.log("我是fun2函数"); }
2. 函数作用域
-调用函数时创建函数作用域,函数执行完毕以后,函数作用域被销毁;
-每调用一次函数就会创建一个新的函数作用域,它们之间是互相独立的;
-在函数作用域中可以访问到全局作用域的变量,在全局作用域中无法访问到函数作用域的变量;
-当在函数作用域操作一个变量时,它会先在自身作用域寻找,如果有就直接使用,如果没有就向上一级作用域中寻找;
var a = 10; function fun() { var a = "我是函数a中的变量"; console.log("a = " + a); // a = 我是函数a中的变量 } fun(); console.log("a = " + a); // a = 10 var c = 12; function fun5() { console.log("c = " + c); // c = undefined var c = 10; } fun5(); function fun6() { console.log("c = " + c); // c = 12 c = 10; } fun6(); console.log("c = " + c); // c = 10
-在函数作用域中也有声明提前的特性,在函数里面,使用var声明的变量,会在函数中的所有代码之前被声明;声明式函数也会在所有代码之前被声明,跟在全局一个意思
function fun2() { console.log(a); // undefined var a = 23; } // 等价于 // function fun2() { // var a; // console.log(a); // undefined // a = 23; // } fun2(); function fun3() { fun4(); function fun4() { console.log("I'm fun4"); } } fun3();
-在函数中声明的没有带var的变量,会成为全局变量
function fun7() { d = 13; console.log("d = " + d); // 等价于 console.log("d = " + window.d); } fun7();
14. this,解析器在调用函数时,每次都会传递一个隐含的参数,就是this,谁调用函数,这个this就是谁
-以函数形式调用时,this永远都是window;
-以方法的形式调用时,this就是调用方法的那个对象。
function fun() { console.log(this); } var obj = { name: "Wade", age: 13, say: fun } fun(); // Window obj.say(); // Object { name: "Wade", age: 13, say: fun } function sayName() { console.log(this.name); } var tom = { name: "tom", age: 12, sayName: sayName }; var jerry = { name: "jerry", age: 12, sayName: sayName }; tom.sayName(); // tom jerry.sayName(); // jerry
15. 构造函数就是一个普通的函数,不同的是构造函数习惯上首字母大写
function Person(name, age) { // this代表new出来的那个对象 this.name = name; this.age = age; } var per = new Person("Paul", 15); console.log(per); // Person {name: "Paul", age: 15} console.log(per instanceof Person); // true console.log(per instanceof Object); // true
16. 原型对象相当于一个公共的区域,所有同一个类的实例都可以访问到,我们可以将对象中共有的内容,统一设置到原型对象中
当访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有,就去原型中找,找到就使用;对于方法也是如此。
所以可以将同一类对象的共有的属性和方法添加到原型中
使用in检查对象是否有属性时,为true;用对象的hasOwnProperty()来检查自身是否有属性
function MyClass() { } var mc = new MyClass(); var mc2 = new MyClass(); console.log(MyClass.prototype); console.log(mc.__proto__ == MyClass.prototype); // true console.log(mc2.__proto__ == MyClass.prototype); // true MyClass.prototype.a = 123; console.log(mc.a); // 123 console.log(mc2.a); // 123 console.log(mc.c); // undefined mc.a = "我是mc中的a"; console.log(mc.a); // 我是mc中的a console.log(mc2.a); // 123 MyClass.prototype.sayHello = function () { console.log("hello."); } mc.sayHello(); // hello console.log("a" in mc); // true console.log(mc.hasOwnProperty("a")); // true console.log(mc.hasOwnProperty("d")); // false console.log("hasOwnProperty" in mc); // true console.log("hasOwnProperty" in Object); // true // 原型的原型 console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty")); // true // Object没有原型 console.log(mc.__proto__.__proto__.__proto__); // null
17. toString
function Person(name, age) { this.name = name; this.age = age; } Person.prototype.toString = function () { return "Person[name=" + this.name + ", age=" + this.age + "]"; } var per = new Person("Anthony", 14); console.log(per); // Object { name: "Anthony", age: 14 } console.log(per.toString()); // Person[name=Anthony, age=14]
18. 如果🈶️不再使用的对象,将其设置为null,让GC回收
19. 数组
var arr = new Array(); arr[0] = 12; arr[1] = 16; arr[2] = 43; arr[3] = 13; console.log(typeof arr); // object console.log(arr instanceof Object); // true console.log(arr.length); // 4 console.log(arr); // Array(4) [ 12, 16, 43, 13 ] arr.length = 6; console.log(arr); // Array(6) [ 12, 16, 43, 13, <2 empty slots> ] arr.length = 2; console.log(arr); // Array [ 12, 16 ] arr[5] = 47; console.log(arr); // Array(6) [ 12, 16, <3 empty slots>, 47 ] // 把length = 0;可以让GC回收 arr.length = 0; // 使用字面量创建数组 var arr2 = []; console.log(arr instanceof Array); // true var arr3 = [1, 4, 6, 2, 5, 12]; console.log(arr3); // Array(6) [ 1, 4, 6, 2, 5, 12 ] console.log(arr3.toString()); // 1,4,6,2,5,12 var arr4 = new Array(32, 53, 23); console.log(arr4); // Array(3) [ 32, 53, 23 ] var arr5 = [10]; console.log(arr5.length); // 1 var arr6 = new Array(10); console.log(arr6.length); // 10 // 用new Array()创建数组用的不多,一般都用字面量创建 // 元素类型可以是任意的,包括对象,函数,数组 var obj = { name: "Tony" } var fun = function () { console.log("I'm function"); } var arr_ = [21, 23]; var arr7 = [12, "djew", true, null, undefined, obj, fun, arr_]; console.log(arr7); // Array(8) [ 12, "djew", true, null, undefined, {…}, fun(), (2) […] ] arr7[6](); // I'm function
20. 数组常用方法
var arr = [12, 432, 43]; var res = arr.push(32, 53); // 在数组后面添加元素,返回数组新的长度 console.log(arr); // Array(5) [ 12, 432, 43, 32, 53 ] console.log(arr.length); // 5 console.log(res); // 5 var res2 = arr.pop(); // 删除最后一个元素,返回删除的元素 console.log(arr); // Array(4) [ 12, 432, 43, 32 ] console.log(res2); // 53 var res3 = arr.unshift(98, 86); // 与push相反,在数组前面加,返回新的长度 console.log(arr); // Array(6) [ 98, 86, 12, 432, 43, 32 ] console.log(arr.length); // 6 console.log(res3); // 6 var res4 = arr.shift(); // 与pop相反,删除第一个元素,返回删除的元素 console.log(arr); // Array(5) [ 86, 12, 432, 43, 32 ] console.log(res4); // 98
21. 数组的forEach()方法需要一个函数作为参数,函数包括三个参数,
var arr = [22, 32, 53, 64, 2, 43]; arr.forEach(function (value, index, obj) { console.log(index); console.log(value); console.log(obj instanceof Array); // true console.log(arr == obj); // true });
22. 在调用函数时,浏览器每次都会传递进两个隐含的参数:this,arguments
this:指调用函数的对象;
arguments:一个类数组对象,但不是数组对象,可以通过索引来获取实参。
function fun() { console.log(arguments.length); // 3 console.log(arguments[0]); // 1 console.log(arguments[1]); // 2 console.log(arguments[2]); // true console.log(arguments.callee); // function fun() console.log(arguments.callee == fun); // true console.log(arguments.callee + ""); // 打印出当前的函数 } fun(1, 2, true);
23. 浏览器在加载一个页面时,是按照自上向下的顺序加载的,读取到一行就运行一行,如果将script标签写在head中,在代码执行时,页面还没有加载
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button id="btn">按钮</button> <script> var btn = document.getElementById("btn"); btn.onclick = function () { console.log("click..."); } </script> </body> </html> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script> var btn = document.getElementById("btn"); // btn为null btn.onclick = function () { // 报错 console.log("click..."); } </script> </head> <body> <button id="btn">按钮</button> </body> </html> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script> window.onload = function () { var btn = document.getElementById("btn"); btn.onclick = function () { console.log("click..."); } } </script> </head> <body> <button id="btn">按钮</button> </body> </html>