js高级
EC和作用域链
代码段
一个script标签就是一个代码段 每一个代码段之间是彼此独立的,如果上面的代码段报错了,是不会影响下面的代码段 在一张页面中,可以有多个代码段
js
var a = 110;
console.log(a);
// 使用了一个没有声明的变量,就会报错:c is not defined
// console.log(c);
// ReferenceError 引用错误
// 对于引用错误来说,同一个代码段如果报了引用错误,错误下面的代码就停止执行
console.log(a);
// 报错了 b is not defined
console.log(b);
var a = 110;
console.log(a);
// 使用了一个没有声明的变量,就会报错:c is not defined
// console.log(c);
// ReferenceError 引用错误
// 对于引用错误来说,同一个代码段如果报了引用错误,错误下面的代码就停止执行
console.log(a);
// 报错了 b is not defined
console.log(b);
预解析
JS代码在执行时,是分两个阶段:
- 预解析 也叫预编译
- 代码执行 就一行一行执行 只有等到预解析结束后,才会进行代码执行 说白了,就是浏览器把你的JS代码进行加工后,再去执行,这个加工的过程,就是所谓的预编译
预解析期间做了什么?
- 声明要提升 加var的变量要提升,提升的是声明,没有赋值,function声明的函数整体要提升 提升到了代码段最前面
- 如果在函数内部的局部变量,就提升到函数内部的最前面 特别需要注意:加var的变量,仅仅是提升声明,函数提升的不仅是声明,还有赋值
js
console.log(a);
var a = 110;
console.log(a);
// 这里只所以能调用,原因是函数整体都提升
fn();
function fn(){
console.log("我是一个函数");
}
console.log(a);
var a = 110;
console.log(a);
// 这里只所以能调用,原因是函数整体都提升
fn();
function fn(){
console.log("我是一个函数");
}
js
// 这里会报错 g is not funciton
// 加var的变量提升的仅仅是声明,没有提升赋值
// g的值是und und()直接报错了
// TypeError: g is not a function
g();
// 函数表达式
// 本质是一个变量 var是用来声明变量的
// 这个变量的值是函数 函数也是一种数据
var g = function(){
console.log("g....");
};
// 这里会报错 g is not funciton
// 加var的变量提升的仅仅是声明,没有提升赋值
// g的值是und und()直接报错了
// TypeError: g is not a function
g();
// 函数表达式
// 本质是一个变量 var是用来声明变量的
// 这个变量的值是函数 函数也是一种数据
var g = function(){
console.log("g....");
};
js
// i是全局变量,还是局部变量?
// 答:全局变量
console.log(i);
for(var i=0; i<10; i++){};
console.log(i);
// i是全局变量,还是局部变量?
// 答:全局变量
console.log(i);
for(var i=0; i<10; i++){};
console.log(i);
js
// a是全局变量
var a = 666;
fn()
function fn() {
// 函数内部加var的变量,也要提升
// 提升到函数内部的最前面
var b = 777;
console.log(a); // und
console.log(b); // 777
console.log(c); // und
var a = 888; // 局部变量
var c = 999;
}
// a是全局变量
var a = 666;
fn()
function fn() {
// 函数内部加var的变量,也要提升
// 提升到函数内部的最前面
var b = 777;
console.log(a); // und
console.log(b); // 777
console.log(c); // und
var a = 888; // 局部变量
var c = 999;
}
js
// 预编译:
// 提升:
// var value要提升 value的值是und
// value函数整体要提升
// 如果变量名函数名一样,变量提升了,函数也提升了,提升后,只可能存在一个名字
// 当函数也提升后,value的值从之前的und就变成了函数
console.log(value);
var value = 123;
function value() {
console.log("我是value函数...");
}
console.log(value);
// 预编译:
// 提升:
// var value要提升 value的值是und
// value函数整体要提升
// 如果变量名函数名一样,变量提升了,函数也提升了,提升后,只可能存在一个名字
// 当函数也提升后,value的值从之前的und就变成了函数
console.log(value);
var value = 123;
function value() {
console.log("我是value函数...");
}
console.log(value);
js
// 提升:加var的变量,和 funtion声明的函数
// ReferenceError: a is not defined
console.log(a);
a = 666;
console.log(a); // 报了一个引用错误,下面的代码,就不会执行了
// 提升:加var的变量,和 funtion声明的函数
// ReferenceError: a is not defined
console.log(a);
a = 666;
console.log(a); // 报了一个引用错误,下面的代码,就不会执行了
js
function fn() {
// ReferenceError: a is not defined
console.log(a);
a = 666;
console.log(a);
}
fn();
console.log(a);
function fn() {
// ReferenceError: a is not defined
console.log(a);
a = 666;
console.log(a);
}
fn();
console.log(a);
js
function fn() {
a = 110;
}
// ReferenceError: a is not defined
console.log(a);
function fn() {
a = 110;
}
// ReferenceError: a is not defined
console.log(a);
js
function fn() {
// 没有加var的变量,都是全局变量,
// 全局变量,在函数内外都可以访问
a = 110;
}
fn();
console.log(a); // 110
function fn() {
// 没有加var的变量,都是全局变量,
// 全局变量,在函数内外都可以访问
a = 110;
}
fn();
console.log(a); // 110
js
gn()
function gn() {
// k是局部变量
var k = 123;
console.log(k);
}
// k is not def 引用错误
console.log(k);
gn()
function gn() {
// k是局部变量
var k = 123;
console.log(k);
}
// k is not def 引用错误
console.log(k);
代码执行产生EC和GO
内存中分很多区:我们需要掌握两个区
- 栈区: 存储基本数据类型
- 栈区: 存储引用数据类型,地址存储在栈区 JS代码分两类:
- 全局代码: 默认进入script标签,就会执行全局代码
- 函数代码: 一个函数就是一个局部的函数代码
ECG,EC,ECS
- ECG(全局的执行上下文):全局代码执行时,就会产生全局的执行上下文(Execution Context Globl)
- EC:每当调用一个函数,就产生一个局部的执行上下文
- ECS:执行上下文产生,都需要放到一个栈中,这个栈叫执行上下文栈(Execution Context Stack) 当函数调用完毕,函数的EC就要出栈的,当ECG执行完毕,ECG也要出栈
- EC的作用:给代码提供数据,代码中需要的数据,都从EC中的找
GO
- JS代码在执行时,会在堆内存中创建一个全局对象,Global Object 在浏览器中,这个GO,说白了,就是Window,是一个全局对象,我们常用的js内置对象都挂载到GO上 如:Date, Array, String, Number, setTimeout, alert....
声明的全局变量和在全局代码中写的函数,都会挂载到GO上
js
// a和b位于全局代码中
var a = 1;
var b = 2;
function fn(){
// c和d是位于局部代码中的
var c = 3;
var d = 4;
}
// fn();
var a = 110;
var b = 220;
console.log(window.a);
console.log(window.b);
function fn() {
console.log("fn...");
}
console.log(window.fn());
var GO = {
String,
Date,
setTimeout,
alert,
// ......
a,
b,
fn
// .....
}
// a和b位于全局代码中
var a = 1;
var b = 2;
function fn(){
// c和d是位于局部代码中的
var c = 3;
var d = 4;
}
// fn();
var a = 110;
var b = 220;
console.log(window.a);
console.log(window.b);
function fn() {
console.log("fn...");
}
console.log(window.fn());
var GO = {
String,
Date,
setTimeout,
alert,
// ......
a,
b,
fn
// .....
}
js
// GO:包含人家内置的属性,和 我们自己定义的全局变量和全局函数
// EC的作用:给代码提供数据的
var n = 110;
console.log(n); // 找n 去ECG中的找 ECG中有VO,说白了,就是GO
console.log(window.n); // 直接去GO中找,有,找到了
m = 220;
console.log(m); // 找m 去ECG中的找 GO中有m 找到了220
// console.log(x); // 找x 去ECG中的找 找不到 报错了 x is not defiend
console.log(name); // 找name
// GO:包含人家内置的属性,和 我们自己定义的全局变量和全局函数
// EC的作用:给代码提供数据的
var n = 110;
console.log(n); // 找n 去ECG中的找 ECG中有VO,说白了,就是GO
console.log(window.n); // 直接去GO中找,有,找到了
m = 220;
console.log(m); // 找m 去ECG中的找 GO中有m 找到了220
// console.log(x); // 找x 去ECG中的找 找不到 报错了 x is not defiend
console.log(name); // 找name
js
function fn(a){
console.log(a);
}
fn(100);
console.log(a);
function fn(a){
console.log(a);
}
fn(100);
console.log(a);
js
var a = 1;
var b = "hello";
function fn(){
console.log("fn...");
}
var arr = ["a","b","c"];
var obj = {name:"wc",age:18}
var a = 1;
var b = "hello";
function fn(){
console.log("fn...");
}
var arr = ["a","b","c"];
var obj = {name:"wc",age:18}
js
var arr = [11, 22];
function fn(arr) {
arr[0] = 100;
arr = [666];
arr[0] = 0;
console.log(arr);
}
fn(arr);
console.log(arr);
var arr = [11, 22];
function fn(arr) {
arr[0] = 100;
arr = [666];
arr[0] = 0;
console.log(arr);
}
fn(arr);
console.log(arr);
执行上下文练习题
js
var a = 1;
var b = 1;
function gn() {
console.log(a, b);
var a = b = 2; // var a = 2; b = 2;
// var a = 2, b = 2; // var a = 2; var b = 2;
console.log(a, b);
}
gn();
console.log(a, b);
var a = 1;
var b = 1;
function gn() {
console.log(a, b);
var a = b = 2; // var a = 2; b = 2;
// var a = 2, b = 2; // var a = 2; var b = 2;
console.log(a, b);
}
gn();
console.log(a, b);
js
var a = 1;
var obj = { uname: "wangcai" }
function fn() {
var a2 = a;
obj2 = obj;
a2 = a;
obj.uname = "xiaoqiang";
console.log(a2);
console.log(obj2);
}
fn();
console.log(a);
console.log(obj);
var a = 1;
var obj = { uname: "wangcai" }
function fn() {
var a2 = a;
obj2 = obj;
a2 = a;
obj.uname = "xiaoqiang";
console.log(a2);
console.log(obj2);
}
fn();
console.log(a);
console.log(obj);
js
// 加var的同名变量,只会提升一个
// var a = 1;
// var a = 2;
// var a = 3;
// console.log(a);
var a;
a = 1;
a = 2;
a = 3;
console.log(a);
// 加var的同名变量,只会提升一个
// var a = 1;
// var a = 2;
// var a = 3;
// console.log(a);
var a;
a = 1;
a = 2;
a = 3;
console.log(a);
js
// 变量先提升 a: und
// 函数再提升 fn a()
// 提升完后赋值,赋值为1
var a = 1;
function a() {
console.log("a...");
}
console.log(a);//1
// 变量先提升 a: und
// 函数再提升 fn a()
// 提升完后赋值,赋值为1
var a = 1;
function a() {
console.log("a...");
}
console.log(a);//1
- 在JS中函数是一等公民
js
function a() {
console.log("a...");
}
var a;
console.log(a);// a() {}
function a() {
console.log("a...");
}
var a;
console.log(a);// a() {}
js
var a;
function a() {
console.log("a...");
}
console.log(a);// a() {}
var a;
function a() {
console.log("a...");
}
console.log(a);// a() {}
js
var a = 10;
// 把栈区中a对应的数据10 copy一份给b
// a和b分别对应两个内存空间 没有关系
var b = a;
console.log(a, b);
b = 1;
console.log(a, b);
var a = 10;
// 把栈区中a对应的数据10 copy一份给b
// a和b分别对应两个内存空间 没有关系
var b = a;
console.log(a, b);
b = 1;
console.log(a, b);
js
var a = [1, 2];
var b = a;
console.log(a, b);
b = [3, 4];
console.log(a, b); // [1,2] [3,4]
var a = [1, 2];
var b = a;
console.log(a, b);
b = [3, 4];
console.log(a, b); // [1,2] [3,4]
js
var a = [1, 2];
var b = a;
console.log(a, b);
b[0] = 110;
console.log(a, b); // [110,2] [110,2]
var a = [1, 2];
var b = a;
console.log(a, b);
b[0] = 110;
console.log(a, b); // [110,2] [110,2]
js
var a = [1, 2];
var b = [1, 2];
console.log(a == b);
console.log(a === b);
var a = [1, 2];
var b = [1, 2];
console.log(a == b);
console.log(a === b);
js
var a = 110;
var b = 110;
console.log(a == b);
var a = 110;
var b = 110;
console.log(a == b);
js
var a = [1, 2];
var b = a;
console.log(a == b);//true
console.log(a === b);//true
var a = [1, 2];
var b = a;
console.log(a == b);//true
console.log(a === b);//true
js
console.log(a, b);
var a = b = 2; // var a = 2; b = 2;
console.log(a, b);
var a = b = 2; // var a = 2; b = 2;
js
var a = { m: 666 };
var b = a;
b = { m: 888 };
console.log(a.m); // 666 这里是整体给b赋值 若 b.m = 888 则a.m输入888
var a = { m: 666 };
var b = a;
b = { m: 888 };
console.log(a.m); // 666 这里是整体给b赋值 若 b.m = 888 则a.m输入888
js
var a = { n: 12 };
var b = a;
b.n = 13;
console.log(a.n); // 13
var a = { n: 12 };
var b = a;
b.n = 13;
console.log(a.n); // 13
js
console.log(a);
a = 111;//caught ReferenceError: a is not defined
console.log(a);
a = 111;//caught ReferenceError: a is not defined
js
var m = 1;
n = 2;
console.log(window.m);
console.log(window.n);
var m = 1;
n = 2;
console.log(window.m);
console.log(window.n);
js
function fn() {
var a = 111;
}
fn();
console.log(a);//is not defined
console.log(window.a);
function fn() {
var a = 111;
}
fn();
console.log(a);//is not defined
console.log(window.a);
js
var a = -1;
// ++a a的值是0 ++a整体的值是0
// a++ a的值是0 a++整体的值是-1
if (++a) {
console.log("666");
} else {
console.log("888");
}
var a = -1;
// ++a a的值是0 ++a整体的值是0
// a++ a的值是0 a++整体的值是-1
if (++a) {
console.log("666");
} else {
console.log("888");
}
js
console.log(a, b);// und und
if (true) {
var a = 1;
} else {
var b = 2;
}
console.log(a, b);// 1 und
console.log(a, b);// und und
if (true) {
var a = 1;
} else {
var b = 2;
}
console.log(a, b);// 1 und
js
var obj = {
name: "wc",
age: 18
}
// in 是一个运算符,判断一个属性是否是一个对象的属性
// 不管是私有属性,还是公有属性
console.log("name" in obj);
console.log("score" in obj);
var obj = {
name: "wc",
age: 18
}
// in 是一个运算符,判断一个属性是否是一个对象的属性
// 不管是私有属性,还是公有属性
console.log("name" in obj);
console.log("score" in obj);
js
var a;
console.log(a);
if ("a" in window) {
a = 110;
}
console.log(a);
var a;
console.log(a);
if ("a" in window) {
a = 110;
}
console.log(a);
js
console.log(a);// var没有块局作用域
if ("a" in window) {
var a = 110;
}
console.log(a);// 110
console.log(a);// var没有块局作用域
if ("a" in window) {
var a = 110;
}
console.log(a);// 110
js
var a = 100;
function fn() {
console.log(a);
return
var a = 110;
}
fn();
var a = 100;
function fn() {
console.log(a);
return
var a = 110;
}
fn();
js
var n = 100;
function foo() {
n = 200;
}
foo()
console.log(n);
var n = 100;
function foo() {
n = 200;
}
foo()
console.log(n);
js
function fn() {
var a = b = 100;
}
fn();
console.log(a);
console.log(b);
function fn() {
var a = b = 100;
}
fn();
console.log(a);
console.log(b);
js
var n = 100;
function fn() {
console.log(n);
}
function gn() {
var n = 200;
console.log(n);
fn(); //这里执行的fn实际父级作用域是全局作用域
jn()
function jn (){
console.log(n)
}
}
gn() // 200 100 200
console.log(n);
var n = 100;
function fn() {
console.log(n);
}
function gn() {
var n = 200;
console.log(n);
fn(); //这里执行的fn实际父级作用域是全局作用域
jn()
function jn (){
console.log(n)
}
}
gn() // 200 100 200
console.log(n);
深入变量
加var的变量和不加var的变量的区别
- 加var的变量在预编译期间会提升,不加var的变量在预编译期间不会提升。
- 不管是否加var,只要是全局变量,在非严格模式下,都会挂载到GO上
- 加var的变量,可以做全局变量,也可以做局部变量,没有加var只能做全局变量。做项目时,不要使用var,更不要使用没有加var的变量。
js
console.log(a);
var a = 110;
console.log(a);
console.log(window.a);
// console.log(b);
b = 666;
console.log(window.b);
console.log(a);
var a = 110;
console.log(a);
console.log(window.a);
// console.log(b);
b = 666;
console.log(window.b);
let(const)声明变量(常量)
- 1)声明的变量不能修改
- 2)使用const声明变量时,必须赋值,不然会报语法错误
- 3)const声明的变量也不会提升
- 4)const和{}也可以形成块级作用域
- 5)const声明的变量也不会挂载到GO上
- 总结: 在项目中,定义变量使用let,定义常量,使用const
js
// ReferenceError: Cannot access 'a' before initialization
// a没有初始化(赋值),是不能访问的
// 理解成:使用let声明的变量是没有提升
// 理解成:使用let声明的变量提升了,但是没有赋值,没有赋值是不能直接访问的
console.log(a);
let a = 110;
// ReferenceError: Cannot access 'a' before initialization
// a没有初始化(赋值),是不能访问的
// 理解成:使用let声明的变量是没有提升
// 理解成:使用let声明的变量提升了,但是没有赋值,没有赋值是不能直接访问的
console.log(a);
let a = 110;
js
// let+{}可以形成块级作用域
if(true){
// let + {} 形成块级作用域
// 块级作用域中定义的变量,只能在块中使用
// 出了这个块,就不能使用了
let c = 110;
}
console.log(c);
// let+{}可以形成块级作用域
if(true){
// let + {} 形成块级作用域
// 块级作用域中定义的变量,只能在块中使用
// 出了这个块,就不能使用了
let c = 110;
}
console.log(c);
js
// 使用let声明的变量,并不会挂载到GO上
let a = 110;
console.log(window.a);
// 使用let声明的变量,并不会挂载到GO上
let a = 110;
console.log(window.a);
js
// SyntaxError: Identifier 'a' has already been declared
let a = 1;
let a = 2;
console.log(a);
// SyntaxError: Identifier 'a' has already been declared
let a = 1;
let a = 2;
console.log(a);
js
function fn(a){
// 形参相当于函数内部定义的局部变量
// VO:AO已经有a
// SyntaxError: Identifier 'a' has already been declared
let a = 110;
}
fn();
// 项目开发中,基本上都是清一色的let
// let是ES6中提出来,弥补了var声明变量的缺点
function fn(a){
// 形参相当于函数内部定义的局部变量
// VO:AO已经有a
// SyntaxError: Identifier 'a' has already been declared
let a = 110;
}
fn();
// 项目开发中,基本上都是清一色的let
// let是ES6中提出来,弥补了var声明变量的缺点
js
const PI = 3.14;
PI = 666; // TypeError: Assignment to constant variable.
console.log(PI);
const PI = 3.14;
PI = 666; // TypeError: Assignment to constant variable.
console.log(PI);
js
// SyntaxError: Missing initializer in const declaration
const PI;
PI = 3.14;
console.log(PI);
// SyntaxError: Missing initializer in const declaration
const PI;
PI = 3.14;
console.log(PI);
练习题
js
console.log(fn) // 打印出 und
// window.fn(); // 报错 und()
console.log(window.fn);
if ("fn" in window) {
// 如果条件成立,进来的第1件事,就是fn赋值
fn(); // fn...
// 函数们于if条件中
// 在最新版本的浏览器中,不会提升整体,仅仅是提升fn函数名
// 就提升到了代码段的最前面
function fn() {
console.log("fn...");
}
}
fn();
console.log(fn) // 打印出 und
// window.fn(); // 报错 und()
console.log(window.fn);
if ("fn" in window) {
// 如果条件成立,进来的第1件事,就是fn赋值
fn(); // fn...
// 函数们于if条件中
// 在最新版本的浏览器中,不会提升整体,仅仅是提升fn函数名
// 就提升到了代码段的最前面
function fn() {
console.log("fn...");
}
}
fn();
js
fn();
function fn() { console.log(1); }
fn();
function fn() { console.log(2); }
fn();
var fn = function () { console.log(3); }
fn();
function fn() { console.log(4); }
fn();
function fn() { console.log(5); }
fn();
fn();
function fn() { console.log(1); }
fn();
function fn() { console.log(2); }
fn();
var fn = function () { console.log(3); }
fn();
function fn() { console.log(4); }
fn();
function fn() { console.log(5); }
fn();
js
var a = 12; b = 13; c = 14;
function fn(a){
console.log(a,b,c);
a = 100;
b = 200;
console.log(a,b,c);
}
b = fn(10);
console.log(a,b,c);
var a = 12; b = 13; c = 14;
function fn(a){
console.log(a,b,c);
a = 100;
b = 200;
console.log(a,b,c);
}
b = fn(10);
console.log(a,b,c);
js
var ary = [12, 13]; // [100, 13]
function fn(ary) {
console.log(ary); // [12,13]
ary[0] = 100;
ary = [100]; // 让函数内部的ary指向新堆
ary[0] = 0; // 让新堆的第1个元素变成0
console.log(ary); // [0]
}
fn(ary);
console.log(ary); // [100,13]
var ary = [12, 13]; // [100, 13]
function fn(ary) {
console.log(ary); // [12,13]
ary[0] = 100;
ary = [100]; // 让函数内部的ary指向新堆
ary[0] = 0; // 让新堆的第1个元素变成0
console.log(ary); // [0]
}
fn(ary);
console.log(ary); // [100,13]
js
function fn(){
function gn(){
console.log("gn...");
}
// return了一个地址
return gn;
}
let res = fn();
res();
function fn(){
function gn(){
console.log("gn...");
}
// return了一个地址
return gn;
}
let res = fn();
res();
js
function fn() {
return function() {
console.log("gn...");
}
}
let res = fn();
res();1
function fn() {
return function() {
console.log("gn...");
}
}
let res = fn();
res();1
js
// 闭包:一个不能被回收的栈内存,就可以称为闭包
// 作用:
// 1)保护 保护EC中的变量,外界不能直接访问
// 2)保存 可以让我们像使用全局变量那样使用局部变量,延长变量的生命周期
var i = 0;
function A() {
var i = 10;
function x() {
console.log(i);
}
return x;
}
var y = A();
y();
function B() {
var i = 20;
y();
}
B();
// 闭包:一个不能被回收的栈内存,就可以称为闭包
// 作用:
// 1)保护 保护EC中的变量,外界不能直接访问
// 2)保存 可以让我们像使用全局变量那样使用局部变量,延长变量的生命周期
var i = 0;
function A() {
var i = 10;
function x() {
console.log(i);
}
return x;
}
var y = A();
y();
function B() {
var i = 20;
y();
}
B();
高阶函数
一个函数,它的参数是函数,或者它的返回值是函数,那么这个函数叫高阶函数。
js
// fn函数,接收一个函数
function fn(func){
// func是一个地址,也指向gn对应的堆
func();
}
function gn(){
console.log('gn...');
}
// gn是一个地址
fn(gn);
// fn函数,接收一个函数
function fn(func){
// func是一个地址,也指向gn对应的堆
func();
}
function gn(){
console.log('gn...');
}
// gn是一个地址
fn(gn);
js
// 需求:封装一个计算器函数,接收三个参数
// 前两个参数是两个普通数据,第三个参数是一个函数(+,-,*)
function add(num1,num2){return num1+num2}
function sub(num1,num2){return num1-num2}
function mul(num1,num2){return num1*num2}
// calc函数就是一个高阶函数
function calc(num1,num2,func){
return func(num1, num2)
}
console.log(calc(1,2,add));
console.log(calc(1,2,sub));
console.log(calc(1,2,mul));
// 需求:封装一个计算器函数,接收三个参数
// 前两个参数是两个普通数据,第三个参数是一个函数(+,-,*)
function add(num1,num2){return num1+num2}
function sub(num1,num2){return num1-num2}
function mul(num1,num2){return num1*num2}
// calc函数就是一个高阶函数
function calc(num1,num2,func){
return func(num1, num2)
}
console.log(calc(1,2,add));
console.log(calc(1,2,sub));
console.log(calc(1,2,mul));
产生闭包
- 从形式上看: 闭包就是两个函数嵌套,里面的函数引用了外面函数的变量
- 定义: 一个不能被释放的栈空间就是一个闭包 -作用:
- 1)保存:延长了函数内部局部变量的生命周期
- 2)保护:闭包中的变量说白了,还是局部变量,外界是不能访问的
- 有人还样理解:有了闭包,我们可以像使用全局变量那样使用局部变量
js
function fn(count){
return function add(num){
return count + num;
}
}
console.log(count);
let gn5 = fn(5);
console.log(gn5(5));
console.log(gn5(50));
function fn(count){
return function add(num){
return count + num;
}
}
console.log(count);
let gn5 = fn(5);
console.log(gn5(5));
console.log(gn5(50));
js
// 一个函数的参数是函数 或 返回值是函数,这个函数就叫高阶函数
// 高阶函数
function fn(func){
func()
}
function gn(){
console.log("gn...");
}
fn(gn);
// 一个函数的参数是函数 或 返回值是函数,这个函数就叫高阶函数
// 高阶函数
function fn(func){
func()
}
function gn(){
console.log("gn...");
}
fn(gn);
js
let arr = [10,20];
// map 对数组中的元素进行加工
let newArr = arr.map(function(item){
console.log(item);
return item * item
})
console.log(newArr);
let arr = [10,20];
// map 对数组中的元素进行加工
let newArr = arr.map(function(item){
console.log(item);
return item * item
})
console.log(newArr);
js
Array.prototype.mlmap = function (fn) {
// this是什么?答:this是arr
let newArray = [];
for (let i = 0; i < this.length; i++) {
// this[i] 表示数组中的每一项
let res = fn(this[i], i)
newArray.push(res)
}
return newArray;
}
let arr = [10, 20];
let newArr = arr.mlmap(function (item, index) {
return item * item
})
console.log(newArr);
Array.prototype.mlmap = function (fn) {
// this是什么?答:this是arr
let newArray = [];
for (let i = 0; i < this.length; i++) {
// this[i] 表示数组中的每一项
let res = fn(this[i], i)
newArray.push(res)
}
return newArray;
}
let arr = [10, 20];
let newArr = arr.mlmap(function (item, index) {
return item * item
})
console.log(newArr);
js
Array.prototype.mlmap = function (fn) {
// this表示数组
let newArr = [];
for (let i = 0; i < this.length; i++) {
newArr.push(fn(this[i], i))
}
return newArr;
}
let arr = [10, 20];
let newArr = arr.mlmap(function (item, index) {
return item * item
})
console.log(newArr);
Array.prototype.mlmap = function (fn) {
// this表示数组
let newArr = [];
for (let i = 0; i < this.length; i++) {
newArr.push(fn(this[i], i))
}
return newArr;
}
let arr = [10, 20];
let newArr = arr.mlmap(function (item, index) {
return item * item
})
console.log(newArr);
js
Array.prototype.mlfind = function(fn){
for(let i=0; i<this.length; i++){
let res = fn(this[i]);
if(res){
// 如果找到了满足条件的第1上元素
return this[i]
}
}
}
let arr = [1,2,3,4,5,6,7,8,9,10];
let res = arr.mlfind(function(item){
return item>6;
});
// 7 find返回满足条件的第1个元素
console.log(res);
Array.prototype.mlfind = function(fn){
for(let i=0; i<this.length; i++){
let res = fn(this[i]);
if(res){
// 如果找到了满足条件的第1上元素
return this[i]
}
}
}
let arr = [1,2,3,4,5,6,7,8,9,10];
let res = arr.mlfind(function(item){
return item>6;
});
// 7 find返回满足条件的第1个元素
console.log(res);
js
Array.prototype.mlfilter = function(fn){
let newArr = [];
for(let i=0; i<this.length; i++){
let res = fn(this[i]);
if(res){
newArr.push(this[i])
}
}
return newArr;
}
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let res = arr.filter(function (item) {
return item > 6;
});
console.log(res);
Array.prototype.mlfilter = function(fn){
let newArr = [];
for(let i=0; i<this.length; i++){
let res = fn(this[i]);
if(res){
newArr.push(this[i])
}
}
return newArr;
}
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let res = arr.filter(function (item) {
return item > 6;
});
console.log(res);
内置的高阶函数
我们需要掌握数组中内置的高阶函数,数组中内置的高阶函数,非常重要,特别是后面写项目的过程。
js
let nums = [19,20,9,30,12,15,50];
// 需要把里面偶数项过滤出来
let newArr = [];
// 命令式编程
for(let i=0; i<nums.length; i++){
if(nums[i] % 2 == 0){
newArr.push(nums[i])
}
}
console.log(newArr);
let nums = [19,20,9,30,12,15,50];
// 需要把里面偶数项过滤出来
let newArr = [];
// 命令式编程
for(let i=0; i<nums.length; i++){
if(nums[i] % 2 == 0){
newArr.push(nums[i])
}
}
console.log(newArr);
js
let nums = [19, 20, 9, 30, 12, 15, 50];
// 使用高阶函数,找出偶数项
// filter 过滤 filter是人家内置好的一个高阶函数,我们只需要去调用
// 函数调用时,写的参数都是实参
// function filter(func){ func(item) }
// 声明式编程 filter天生自带遍历功能
// filter的返回值是一个过滤完的新数组
let newArr = nums.filter(function(item,index){
// item表示数组中的每一项
// console.log(item,index);
// return 后面跟一个条件,当某一项条件为true时,就会把这一项过滤出来
return item % 2 == 0;
});
console.log(newArr);
let nums = [19, 20, 9, 30, 12, 15, 50];
// 使用高阶函数,找出偶数项
// filter 过滤 filter是人家内置好的一个高阶函数,我们只需要去调用
// 函数调用时,写的参数都是实参
// function filter(func){ func(item) }
// 声明式编程 filter天生自带遍历功能
// filter的返回值是一个过滤完的新数组
let newArr = nums.filter(function(item,index){
// item表示数组中的每一项
// console.log(item,index);
// return 后面跟一个条件,当某一项条件为true时,就会把这一项过滤出来
return item % 2 == 0;
});
console.log(newArr);
js
// 手写filter
let nums = [19, 20, 9, 30, 12, 15, 50];
let newArr = nums.filter(function (item, index) {
// item > 20是过滤条件
return item > 20;
});
console.log(newArr);
// 手写filter
let nums = [19, 20, 9, 30, 12, 15, 50];
let newArr = nums.filter(function (item, index) {
// item > 20是过滤条件
return item > 20;
});
console.log(newArr);
js
// 手写map
let nums = [19, 20, 9, 30, 12, 15, 50];
// map 本意:地图的意思 计算机中:映射
// map天生自带遍历功能
// map可以把数组中的每一个老元素,映射成新元素
// map是对数组中的每一项进行加工
// map返回一个加工后的新数组
let newArr = nums.map(function(item){
// console.log(item);
return item * 10
})
console.log(newArr);
// 手写map
let nums = [19, 20, 9, 30, 12, 15, 50];
// map 本意:地图的意思 计算机中:映射
// map天生自带遍历功能
// map可以把数组中的每一个老元素,映射成新元素
// map是对数组中的每一项进行加工
// map返回一个加工后的新数组
let newArr = nums.map(function(item){
// console.log(item);
return item * 10
})
console.log(newArr);
js
let nums = [19, 20, 9, 30, 12, 15, 50];
// forEach是专门用来遍历数组的
let res = nums.forEach(function(item){
console.log(item);
})
console.log(res);
let nums = [19, 20, 9, 30, 12, 15, 50];
// forEach是专门用来遍历数组的
let res = nums.forEach(function(item){
console.log(item);
})
console.log(res);
js
let nums = [19, 20, 9, 30, 12, 15, 50];
// find是查找数组中是否有某一个元素,如果找到返回这个元素
// 如果找不到,返回 und
let res = nums.find(function(item){
return item == 300
})
console.log(res); // 30
let nums = [19, 20, 9, 30, 12, 15, 50];
// find是查找数组中是否有某一个元素,如果找到返回这个元素
// 如果找不到,返回 und
let res = nums.find(function(item){
return item == 300
})
console.log(res); // 30
js
let nums = [19, 20, 9, 30, 12, 15, 50, 30];
// findIndex是查找数组中某个元素的第1次出现的位置索引
// 如果找不到,返回-1
let res = nums.findIndex(function (item) {
return item == 300
})
console.log(res);
let nums = [19, 20, 9, 30, 12, 15, 50, 30];
// findIndex是查找数组中某个元素的第1次出现的位置索引
// 如果找不到,返回-1
let res = nums.findIndex(function (item) {
return item == 300
})
console.log(res);
js
let names = [
{name:"wc",age:10},
{name:"xq",age:13},
{name:"z3",age:16},
{name:"w5",age:28},
];
// 返回找到的那个元素
let res = names.find(function(item){
return item.name === "z3"
})
console.log(res.age);
let names = [
{name:"wc",age:10},
{name:"xq",age:13},
{name:"z3",age:16},
{name:"w5",age:28},
];
// 返回找到的那个元素
let res = names.find(function(item){
return item.name === "z3"
})
console.log(res.age);
闭包练习题
js
var i = 20;
function fn() {
i -= 2;
var i = 10;
return function (n) {
console.log((++i) - n);
}
}
var f = fn();
f(1);
f(2);
fn()(3);
console.log(i);
var i = 20;
function fn() {
i -= 2;
var i = 10;
return function (n) {
console.log((++i) - n);
}
}
var f = fn();
f(1);
f(2);
fn()(3);
console.log(i);
js
let a = 0;
b = 0;
function A(a) {
A = function (b) {
alert(a + b++);
}
alert(a++)
}
A(1);
A(2);
let a = 0;
b = 0;
function A(a) {
A = function (b) {
alert(a + b++);
}
alert(a++)
}
A(1);
A(2);
js
var t = (function (i) {
return function () {
alert(i *= 2)
}
})(2);
t(5);
var t = (function (i) {
return function () {
alert(i *= 2)
}
})(2);
t(5);
js
// 2分钟~
var n = 0;
function a() {
var n = 10;
function b() {
n++;
console.log(n);
}
b();
return b;
}
var c = a();
c();
console.log(n);
// 2分钟~
var n = 0;
function a() {
var n = 10;
function b() {
n++;
console.log(n);
}
b();
return b;
}
var c = a();
c();
console.log(n);
vue
<template>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</template>
<script>
let lis = document.getElementsByTagName("li");
// for(let i=0; i<lis.length; i++){
// lis[i].onclick = function(){
// console.log(i+1);
// }
// }
// 闭包有两个作用:1)保存 2)保护
for (var i = 0; i < lis.length; i++) {
; (function (i) {
lis[i].onclick = function () {
console.log(i + 1);
}
})(i);
}
</script>
<template>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</template>
<script>
let lis = document.getElementsByTagName("li");
// for(let i=0; i<lis.length; i++){
// lis[i].onclick = function(){
// console.log(i+1);
// }
// }
// 闭包有两个作用:1)保存 2)保护
for (var i = 0; i < lis.length; i++) {
; (function (i) {
lis[i].onclick = function () {
console.log(i + 1);
}
})(i);
}
</script>
立即调用函数表达式(Immediately Invoked Function Expression)[IIFE]
- 正确IIFE写法(5种)
js
;(function fn(){})()
;(function fn(){}())
+function fn(){}()
-function fn(){}()
!function fn(){}()
function fn(){
console.log("fn...");
}
// 不叫立即调用
// 叫先去声明一个函数,后面去调用
// 所谓的立即调用是指在声明的同时,立马调用
fn();
;(function fn(){})()
;(function fn(){}())
+function fn(){}()
-function fn(){}()
!function fn(){}()
function fn(){
console.log("fn...");
}
// 不叫立即调用
// 叫先去声明一个函数,后面去调用
// 所谓的立即调用是指在声明的同时,立马调用
fn();
js
(function fn() {
console.log("fn...");
})();
(function fn() {
console.log("fn...");
}());
+function fn() {
console.log("fn...");
}()
-function fn() {
console.log("fn...");
}()
// 不行
*function fn() {
console.log("fn...");
}()
!function fn() {
console.log("fn...");
}()
(function fn() {
console.log("fn...");
})();
(function fn() {
console.log("fn...");
}());
+function fn() {
console.log("fn...");
}()
-function fn() {
console.log("fn...");
}()
// 不行
*function fn() {
console.log("fn...");
}()
!function fn() {
console.log("fn...");
}()
js
let obj = {
name: "wc",
age: 100
}
;(function () {
console.log("mn....");
}())
let obj = {
name: "wc",
age: 100
}
;(function () {
console.log("mn....");
}())
练习题
js
console.log(fn); // und
// 1 == 1 true
if (1 == 1) {
// 进入来的第一件事,是给fn赋值
console.log(fn); // fn函数
function fn() {
console.log("ok");
}
}
console.log(fn); // fn函数
console.log(fn); // und
// 1 == 1 true
if (1 == 1) {
// 进入来的第一件事,是给fn赋值
console.log(fn); // fn函数
function fn() {
console.log("ok");
}
}
console.log(fn); // fn函数
js
console.log(num); // und
console.log(fn); // und
// 0 -0 "" und null NaN ===> false
// 其它的统一转化成true
if ([]) { // []转成true
// 进来的第一件事是给fn赋值
fn() // "a"
var num = 100;
function fn() {
console.log("a")
}
}
console.log(fn); // fn函数
console.log(num); // und
console.log(fn); // und
// 0 -0 "" und null NaN ===> false
// 其它的统一转化成true
if ([]) { // []转成true
// 进来的第一件事是给fn赋值
fn() // "a"
var num = 100;
function fn() {
console.log("a")
}
}
console.log(fn); // fn函数
js
function fn(i) {
return function (n) {
console.log(n + (++i));
}
}
var f = fn(2);
f(3);
fn(5)(6);
fn(7)(8);
f(4);
function fn(i) {
return function (n) {
console.log(n + (++i));
}
}
var f = fn(2);
f(3);
fn(5)(6);
fn(7)(8);
f(4);
js
// GO中有一个foo 值是hello
var foo = "hello";
// IIFE 没有函数需要
// IIFE,即使有函数名,函数名在外面也是不能使用的
(function (foo) { // foo是形参 形参相当于函数内部的局部变量
console.log(foo); // "hello"
// foo || "word" foo是"hello"
var foo = foo || "word";
console.log(foo); // hello
})(foo); // foo是"hello"
console.log(foo);
// GO中有一个foo 值是hello
var foo = "hello";
// IIFE 没有函数需要
// IIFE,即使有函数名,函数名在外面也是不能使用的
(function (foo) { // foo是形参 形参相当于函数内部的局部变量
console.log(foo); // "hello"
// foo || "word" foo是"hello"
var foo = foo || "word";
console.log(foo); // hello
})(foo); // foo是"hello"
console.log(foo);
js
var a = 9;
function fn() {
a = 0;
return function (b) {
return b + a++;
}
}
var f = fn();
console.log(f(5));
console.log(fn()(5));
console.log(f(5));
console.log(a);
var a = 9;
function fn() {
a = 0;
return function (b) {
return b + a++;
}
}
var f = fn();
console.log(f(5));
console.log(fn()(5));
console.log(f(5));
console.log(a);
js
let obj = { // {x:0,y:[1,2]}
x: 1, // 100
y: [10, 20] // [10, 30, 40]
};
let obj2 = obj;
let obj3 = {
...obj2 // x:200 y:[10,30,40] y:{x:0,y:[1,2]}
};
obj2.x = 100;
obj2.y[1] = 30;
obj3.x = 200;
obj3.y[2] = 40;
obj = obj3.y = {
x: 0,
y: [1, 2]
};
console.log(obj, obj2, obj3);
let obj = { // {x:0,y:[1,2]}
x: 1, // 100
y: [10, 20] // [10, 30, 40]
};
let obj2 = obj;
let obj3 = {
...obj2 // x:200 y:[10,30,40] y:{x:0,y:[1,2]}
};
obj2.x = 100;
obj2.y[1] = 30;
obj3.x = 200;
obj3.y[2] = 40;
obj = obj3.y = {
x: 0,
y: [1, 2]
};
console.log(obj, obj2, obj3);
js
// let a = {
// num:0,
// valueOf:function(){
// // console.log("valueOf...");
// return ++a.num
// }
// };
let a = {
num: 0,
valueOf: function () {
return a.num++
},
toString: function () {
// console.log("valueOf...");
return ++a.num
}
};
// a和别人作比较时,会自动调用valueOf和toString
// 如果a是一个对象,对象中有自己的valueOf或toStirng,就会调用自己的valueOf或toStirng
if (a == 1 && a == 2 && a == 3) {
console.log('OK');
}
// let a = {
// num:0,
// valueOf:function(){
// // console.log("valueOf...");
// return ++a.num
// }
// };
let a = {
num: 0,
valueOf: function () {
return a.num++
},
toString: function () {
// console.log("valueOf...");
return ++a.num
}
};
// a和别人作比较时,会自动调用valueOf和toString
// 如果a是一个对象,对象中有自己的valueOf或toStirng,就会调用自己的valueOf或toStirng
if (a == 1 && a == 2 && a == 3) {
console.log('OK');
}
js
// 12.5 ==> 0进制 不转 12
// 100 ==> 1进制 NaN
// 0013 ==> 以0打头 8进制数据 先转成10进制 11 转2进制 3
// "27px" ===> 转3进制 2
// 456 ===> 转4进制 NaN
let arr = [12.5, 100, 0013, '27px', 456];
arr = arr.map(parseInt);
console.log(arr);
// 12.5 ==> 0进制 不转 12
// 100 ==> 1进制 NaN
// 0013 ==> 以0打头 8进制数据 先转成10进制 11 转2进制 3
// "27px" ===> 转3进制 2
// 456 ===> 转4进制 NaN
let arr = [12.5, 100, 0013, '27px', 456];
arr = arr.map(parseInt);
console.log(arr);
js
(function b() {
console.log(b);
})();
// IIFE中的函数名在外界是得不到的
console.log(b);
(function b() {
console.log(b);
})();
// IIFE中的函数名在外界是得不到的
console.log(b);
js
(function b() {
// 说明把110确实赋值给了b b的值是110
c = b = 110;
console.log(c); // 110
})();
(function b() {
// 说明把110确实赋值给了b b的值是110
c = b = 110;
console.log(c); // 110
})();
js
(function b() {
// IIFE的函数名b 和 函数体中的b是同一个b
// IIFE中的函数名b,在函数体内是不能修改的
c = b = 110;
console.log(b);
console.log(c);
})();
(function b() {
// IIFE的函数名b 和 函数体中的b是同一个b
// IIFE中的函数名b,在函数体内是不能修改的
c = b = 110;
console.log(b);
console.log(c);
})();
js
(function b() {
var b = 110;
console.log(b);
})();
(function b() {
var b = 110;
console.log(b);
})();
js
(function b() {
b = 110;
console.log(b);
})();
(function b() {
b = 110;
console.log(b);
})();
js
var b = 10;
(function b() {
"use strict"
// TypeError: Assignment to constant variable.
b = 20;
console.log(b);
})();
console.log(b);
var b = 10;
(function b() {
"use strict"
// TypeError: Assignment to constant variable.
b = 20;
console.log(b);
})();
console.log(b);
this绑定
默认绑定
js
// this到底是什么?
// 本意是这个的意思
// this到底是什么和你书写的位置没有关系,和调用方式有关系
// this是在产生EC时,动态绑定的
function fn(){
console.log(this);
}
// fn();
// let obj = {name:"wc"};
// fn.call(obj)
// let obj2 = {name:"xq",fn:fn};
// obj2.fn();
// this到底是什么?
// 本意是这个的意思
// this到底是什么和你书写的位置没有关系,和调用方式有关系
// this是在产生EC时,动态绑定的
function fn(){
console.log(this);
}
// fn();
// let obj = {name:"wc"};
// fn.call(obj)
// let obj2 = {name:"xq",fn:fn};
// obj2.fn();
js
function fn(){
console.log(this);
}
// 独立函数调用
// 在浏览器中,独立函数调用,函数内部的this表示window
fn();
function fn(){
console.log(this);
}
// 独立函数调用
// 在浏览器中,独立函数调用,函数内部的this表示window
fn();
js
function fn() {
console.log(this); // window
}
function gn(){
console.log(this); // window
fn(); // 独立函数调用
}
function kn(){
console.log(this); // window
gn(); // 独立函数调用
}
// 独立函数调用
kn();
function fn() {
console.log(this); // window
}
function gn(){
console.log(this); // window
fn(); // 独立函数调用
}
function kn(){
console.log(this); // window
gn(); // 独立函数调用
}
// 独立函数调用
kn();
js
let obj = {
name:"wc",
fn:function(){
console.log(this);
}
}
let gn = obj.fn;
gn(); // 独立函数调用
let obj = {
name:"wc",
fn:function(){
console.log(this);
}
}
let gn = obj.fn;
gn(); // 独立函数调用
js
function fn(){
console.log(this);
}
var obj = {
name:"wc",
fn:fn
}
var gn = obj.fn;
gn(); // 独立函数调用
function fn(){
console.log(this);
}
var obj = {
name:"wc",
fn:fn
}
var gn = obj.fn;
gn(); // 独立函数调用
js
function fn(){
function gn(){
console.log(this);
}
return gn;
}
let kn = fn();
kn(); // 独立函数调用
function fn(){
function gn(){
console.log(this);
}
return gn;
}
let kn = fn();
kn(); // 独立函数调用
隐式绑定
js
function fn(){
console.log(this);
}
let obj = {
name:"wc",
fn:fn
}
// 不叫独立的函数调用
// 是通过obj打点去调用的
// fn中的this表示什么,就看点前面是什么
// 点前面是obj,this就是obj
obj.fn();
function fn(){
console.log(this);
}
let obj = {
name:"wc",
fn:fn
}
// 不叫独立的函数调用
// 是通过obj打点去调用的
// fn中的this表示什么,就看点前面是什么
// 点前面是obj,this就是obj
obj.fn();
js
var obj = {
name: "wc",
running: function () {
// this 表示obj obj.name
console.log(this.name + "在跑步...");
},
coding: function () {
console.log(this.name + "在打代码...");
}
}
// 隐式绑定
// 你看一个函数中的this是什么,就看谁去调用了这个函数
// obj打点去调用了,函数中的this表示obj
obj.running();
obj.coding();
var obj = {
name: "wc",
running: function () {
// this 表示obj obj.name
console.log(this.name + "在跑步...");
},
coding: function () {
console.log(this.name + "在打代码...");
}
}
// 隐式绑定
// 你看一个函数中的this是什么,就看谁去调用了这个函数
// obj打点去调用了,函数中的this表示obj
obj.running();
obj.coding();
js
let obj = {
name:"wc",
fn:function(){
console.log(this);
}
}
let obj2 = {
name:"xq",
gn:obj.fn
};
obj2.gn();
let obj = {
name:"wc",
fn:function(){
console.log(this);
}
}
let obj2 = {
name:"xq",
gn:obj.fn
};
obj2.gn();
显示绑定
js
// 在JS中,函数有多处角色
// 1)角色一:普通函数
// 2)角色二:对象中的方法
// 3)角色三:对象(一切都是对象) 对象是属性的无序集合
// 函数也是一个对象,对象是属性的无序集合,内部有非常多的默认属性或方法,我们需要掌握三个,call,apply,bind
function fn(){
console.log("fn...");
}
fn();
let obj = {
// 可以把对应中的函数称为方法
running:function(){
console.log("running...");
}
}
function gn(){
console.log("gn...");
}
gn.a = 1;
gn.b = 2;
gn.c = 3;
console.log(gn.a);
console.log(gn.b);
console.log(gn.c);
// dir表示以对象有形式打印出函数
console.dir(gn);
// 在JS中,函数有多处角色
// 1)角色一:普通函数
// 2)角色二:对象中的方法
// 3)角色三:对象(一切都是对象) 对象是属性的无序集合
// 函数也是一个对象,对象是属性的无序集合,内部有非常多的默认属性或方法,我们需要掌握三个,call,apply,bind
function fn(){
console.log("fn...");
}
fn();
let obj = {
// 可以把对应中的函数称为方法
running:function(){
console.log("running...");
}
}
function gn(){
console.log("gn...");
}
gn.a = 1;
gn.b = 2;
gn.c = 3;
console.log(gn.a);
console.log(gn.b);
console.log(gn.c);
// dir表示以对象有形式打印出函数
console.dir(gn);
js
function fn(){
// console.log("fn...");
console.log(this);
}
let obj = {name:"wc"}
// 函数也是对象,call是它内部的一个方法
// 我们直接去调用这个方法
// 此方法,可以让我们显示地绑定this
// call的作用:1)显示绑定this 2)让fn执行
fn.call(obj); // 显示绑定函数中的this
// 独立地函数调用 this表示window
// fn();
function fn(){
// console.log("fn...");
console.log(this);
}
let obj = {name:"wc"}
// 函数也是对象,call是它内部的一个方法
// 我们直接去调用这个方法
// 此方法,可以让我们显示地绑定this
// call的作用:1)显示绑定this 2)让fn执行
fn.call(obj); // 显示绑定函数中的this
// 独立地函数调用 this表示window
// fn();
js
function fn(num1,num2) {
// console.log("fn...");
console.log(this, num1+num2);
}
let obj = { name: "wc" }
// call传参:从第2个参数起,传递的参数就会传递给函数
// call的作用:1)显示绑定this 2)让函数执行 3)也可以传递
fn.call(obj,666,111);
// 独立地函数调用 this表示window
// fn(1,2);
function fn(num1,num2) {
// console.log("fn...");
console.log(this, num1+num2);
}
let obj = { name: "wc" }
// call传参:从第2个参数起,传递的参数就会传递给函数
// call的作用:1)显示绑定this 2)让函数执行 3)也可以传递
fn.call(obj,666,111);
// 独立地函数调用 this表示window
// fn(1,2);
js
function fn(num1, num2) {
console.log(this, num1 + num2);
}
let obj = { name: "wc" }
// apply的作用和call一样,只不过传参的方式不一样
// apply的话,需要把参数放到一个数组中
fn.apply(obj, [666, 111]);
function fn(num1, num2) {
console.log(this, num1 + num2);
}
let obj = { name: "wc" }
// apply的作用和call一样,只不过传参的方式不一样
// apply的话,需要把参数放到一个数组中
fn.apply(obj, [666, 111]);
js
function fn(num1, num2) {
console.log(this, num1 + num2);
}
let obj = { name: "wc" }
// bind的作用:1)显示绑定this 2)也可以传参 但是不会让函数执行,call和apply都会让函数执行 3)bind返回绑定this之后的新函数
let newFn = fn.bind(obj, 666, 111);
newFn();
function fn(num1, num2) {
console.log(this, num1 + num2);
}
let obj = { name: "wc" }
// bind的作用:1)显示绑定this 2)也可以传参 但是不会让函数执行,call和apply都会让函数执行 3)bind返回绑定this之后的新函数
let newFn = fn.bind(obj, 666, 111);
newFn();
js
// 显示绑定:
// 1)call fn.call(obj,1,2) 显示绑定this 让fn执行 也能传参
// 2)apply fn.apply(obj,[1,2]) 显示绑定this 让fn执行 参数放数组中
// 3)bind fn.bind(obj,1,2) 显示绑定this 返回绑定this后的新函数 也能传参
// 显示绑定:
// 1)call fn.call(obj,1,2) 显示绑定this 让fn执行 也能传参
// 2)apply fn.apply(obj,[1,2]) 显示绑定this 让fn执行 参数放数组中
// 3)bind fn.bind(obj,1,2) 显示绑定this 返回绑定this后的新函数 也能传参
js
function fn() {
console.log(this);
}
// String {'hello'} 是一个对象
// 会把hello包装成一个对象
// fn.call("hello");
// 如果绑定到und上,实际是绑定到了window上
// fn.call(undefined);
// 如果绑定到null上,实际是绑定到了window上
fn.call(null)
function fn() {
console.log(this);
}
// String {'hello'} 是一个对象
// 会把hello包装成一个对象
// fn.call("hello");
// 如果绑定到und上,实际是绑定到了window上
// fn.call(undefined);
// 如果绑定到null上,实际是绑定到了window上
fn.call(null)
new绑定
js
// 在JS中,函数有多种角色:
// 角色一:普通函数
// 角色二:对象中的方法
// 角色三:函数也是对象
// 角色四:函数也是类(构造函数/构造器),通常情况下,首字母大写
// 定义一个类,叫Person,构造器,构造函数
function Person() {
// new做了什么?
// 1)在函数内部创建一个对象
// 2)把函数内的this绑定到了对象上
// 3)函数执行
// 4)返回这个对象(new完后,肯定是得到一个对象)
}
// new一个类,得到一个对象 new是一个运算符
let p1 = new Person();
console.log(p1);
// 在JS中,函数有多种角色:
// 角色一:普通函数
// 角色二:对象中的方法
// 角色三:函数也是对象
// 角色四:函数也是类(构造函数/构造器),通常情况下,首字母大写
// 定义一个类,叫Person,构造器,构造函数
function Person() {
// new做了什么?
// 1)在函数内部创建一个对象
// 2)把函数内的this绑定到了对象上
// 3)函数执行
// 4)返回这个对象(new完后,肯定是得到一个对象)
}
// new一个类,得到一个对象 new是一个运算符
let p1 = new Person();
console.log(p1);
js
function Person() {
this.name = "wc";
this.age = 100;
}
// new一个类,得到一个对象 new是一个运算符
let p1 = new Person();
console.log(p1);
function Person() {
this.name = "wc";
this.age = 100;
}
// new一个类,得到一个对象 new是一个运算符
let p1 = new Person();
console.log(p1);
js
function Person(name,age) {
this.name = name;
this.age = age;
}
// new一个类,得到一个对象 new是一个运算符
let p1 = new Person("xq",100);
console.log(p1);
// 每new一次就创建出一个新的对象,new了100次,创建出100个对象
let p2 = new Person("z3",123);
console.log(p2);
function Person(name,age) {
this.name = name;
this.age = age;
}
// new一个类,得到一个对象 new是一个运算符
let p1 = new Person("xq",100);
console.log(p1);
// 每new一次就创建出一个新的对象,new了100次,创建出100个对象
let p2 = new Person("z3",123);
console.log(p2);
内置函数绑定
js
// 定时器中的this表示window
setTimeout(function(){
console.log(this);
},2000);
// 定时器中的this表示window
setTimeout(function(){
console.log(this);
},2000);
vue
<template>
<button id="btn">点我</button>
</template>
<script>
let btn = document.getElementById("btn");
btn.onclick = function(){
// 监听器中的this表示事件源
console.log(this);
}
</script>
<template>
<button id="btn">点我</button>
</template>
<script>
let btn = document.getElementById("btn");
btn.onclick = function(){
// 监听器中的this表示事件源
console.log(this);
}
</script>
js
// 内置函数中也可以访问this
let names = ["wc","xq"];
names.forEach(function(item){
console.log(item);
console.log(this);
},{
name:"666"
})
// 内置函数中也可以访问this
let names = ["wc","xq"];
names.forEach(function(item){
console.log(item);
console.log(this);
},{
name:"666"
})
绑定的优先级
js
let obj = {
name: "wc",
fn: function () {
console.log(this);
}
}
// 隐式绑定
obj.fn();
let obj = {
name: "wc",
fn: function () {
console.log(this);
}
}
// 隐式绑定
obj.fn();
js
// 显示绑定优先级高于隐式绑定
function fn() {
console.log(this);
}
let obj = {
name: "wc",
// 显示绑定
fn: fn.bind({ name: "xq" })
}
// 隐式绑定
obj.fn();
// 显示绑定优先级高于隐式绑定
function fn() {
console.log(this);
}
let obj = {
name: "wc",
// 显示绑定
fn: fn.bind({ name: "xq" })
}
// 隐式绑定
obj.fn();
js
// new绑定优先级高于隐式绑定
let obj = {
name: "wc",
fn: function () {
console.log(this);
}
}
let res = new obj.fn();
// new绑定优先级高于隐式绑定
let obj = {
name: "wc",
fn: function () {
console.log(this);
}
}
let res = new obj.fn();
js
// new绑定优先级高于bind
function fn(){
console.log(this);
}
// bind返回一个绑定this之后的新函数
let gn = fn.bind({name:"wc"})
// gn(); // this表示{name:"wc"}
new gn();
// new绑定优先级高于bind
function fn(){
console.log(this);
}
// bind返回一个绑定this之后的新函数
let gn = fn.bind({name:"wc"})
// gn(); // this表示{name:"wc"}
new gn();
js
// new绑定 不能和call与apply比较
function fn() {
console.log(this);
}
let res = fn.call({ name: "wc" })
console.log(res);
new res();//报错
// new绑定 不能和call与apply比较
function fn() {
console.log(this);
}
let res = fn.call({ name: "wc" })
console.log(res);
new res();//报错
箭头函数
js
var foo = function(num1,num2){
return num1+num2;
}
console.log(foo(1,2));
var foo = function(num1,num2){
return num1+num2;
}
console.log(foo(1,2));
js
var foo = (num1, num2)=>{
return num1 + num2;
}
console.log(foo(1, 2));
var foo = (num1, num2)=>{
return num1 + num2;
}
console.log(foo(1, 2));
js
// 如果形参只有1个,那么()可以不写
var foo = num1 => {
return num1**2;
}
console.log(foo(2));
// 如果形参只有1个,那么()可以不写
var foo = num1 => {
return num1**2;
}
console.log(foo(2));
js
// 如果函数体中只有一条语句,{}和return 都可以不写
var foo = num1 => num1 ** 2;
console.log(foo(2));
// 如果函数体中只有一条语句,{}和return 都可以不写
var foo = num1 => num1 ** 2;
console.log(foo(2));
js
// 如果函数体中只有一条语句
// 没有reutrn,{}也是可以不写的
var foo = num1 => console.log(num1 ** 2);
console.log(foo(2));
// 如果函数体中只有一条语句
// 没有reutrn,{}也是可以不写的
var foo = num1 => console.log(num1 ** 2);
console.log(foo(2));
js
// 如果函数体中只有一条语句
// 并且返回一个对象 删除return 和 {},
// 对象的{}会当成函数的{}
// 如果没有形参 ()不能省
var foo = () => ({ a: 666 })
console.log(foo());
// 如果函数体中只有一条语句
// 并且返回一个对象 删除return 和 {},
// 对象的{}会当成函数的{}
// 如果没有形参 ()不能省
var foo = () => ({ a: 666 })
console.log(foo());
箭头函数中的this
js
console.log(this);
// 箭头函数中的this需要往向找一层
var gn = ()=>{
console.log(this);
}
var obj = {
name:"wc"
}
// 显示绑定
gn.call(obj)
console.log(this);
// 箭头函数中的this需要往向找一层
var gn = ()=>{
console.log(this);
}
var obj = {
name:"wc"
}
// 显示绑定
gn.call(obj)
js
let fn = ()=>{
console.log(this);
}
fn.call("hello");
fn.call({});
let fn = ()=>{
console.log(this);
}
fn.call("hello");
fn.call({});
js
var obj = {
name:"wc",
fn:()=>{
console.log(this);
}
}
obj.fn();
var obj = {
name:"wc",
fn:()=>{
console.log(this);
}
}
obj.fn();
js
setTimeout(()=>{
console.log(this);
},2000)
setTimeout(()=>{
console.log(this);
},2000)
this练习题
js
function fn(){
console.log(this);
}
fn(); // 独立函数调用
window.fn(); // 隐式绑定
function fn(){
console.log(this);
}
fn(); // 独立函数调用
window.fn(); // 隐式绑定
js
let obj = {
name: "wangcai",
age: 100,
run: function () {
console.log(this)
console.log("run....")
}
}
obj.run()
let obj = {
name: "wangcai",
age: 100,
run: function () {
console.log(this)
console.log("run....")
}
}
obj.run()
js
// IIFE中this表示window
;(function(){
console.log(this);
})()
// IIFE中this表示window
;(function(){
console.log(this);
})()
js
let btn = document.getElementById("btn");
function fn() {
return function () {
console.log(this);// 事件源
}
}
btn.onclick = fn();
let btn = document.getElementById("btn");
function fn() {
return function () {
console.log(this);// 事件源
}
}
btn.onclick = fn();
js
let wc = {
name: "wangcai",
age: 100,
eat: function () {
console.log("eat...")
console.log(this);
}
}
let xxx = wc.eat;
xxx();
let wc = {
name: "wangcai",
age: 100,
eat: function () {
console.log("eat...")
console.log(this);
}
}
let xxx = wc.eat;
xxx();
js
var num = 10;
var obj = {
num: 20
}
obj.fn = (function (num) {
this.num = num * 3;
num++;
console.log(num);
return function (n) {
this.num += n;
num++;
console.log(num)
}
})(obj.num);
var fn = obj.fn;
fn(5)
console.log(window.num);
var num = 10;
var obj = {
num: 20
}
obj.fn = (function (num) {
this.num = num * 3;
num++;
console.log(num);
return function (n) {
this.num += n;
num++;
console.log(num)
}
})(obj.num);
var fn = obj.fn;
fn(5)
console.log(window.num);
js
// 21 22 60 60 30
var num = 10; // 60
var obj = {
num: 20 // 30
}
obj.fn = (function (num) {
this.num = num * 3;
num++;
console.log(num); // 21
return function (n) { // 10
this.num += n;
num++; // 22
console.log(num) // 22
}
})(obj.num);
obj.fn(10);
console.log(num)
console.log(window.num)
console.log(obj.num)
// 21 22 60 60 30
var num = 10; // 60
var obj = {
num: 20 // 30
}
obj.fn = (function (num) {
this.num = num * 3;
num++;
console.log(num); // 21
return function (n) { // 10
this.num += n;
num++; // 22
console.log(num) // 22
}
})(obj.num);
obj.fn(10);
console.log(num)
console.log(window.num)
console.log(obj.num)
js
(function () {
var a = 1;
var obj = {
a: 10,
f: function () {
a *= 2; // a是外面的 里面的需要obj.a
}
}
obj.f()
alert(obj.a + a);
})()
(function () {
var a = 1;
var obj = {
a: 10,
f: function () {
a *= 2; // a是外面的 里面的需要obj.a
}
}
obj.f()
alert(obj.a + a);
})()
js
(function () {
var a = 1;
var obj = {
a: 10,
f: function () {
this.a *= 2; // this是obj
console.log(this.a)
}
}
obj.f()
})()
(function () {
var a = 1;
var obj = {
a: 10,
f: function () {
this.a *= 2; // this是obj
console.log(this.a)
}
}
obj.f()
})()
js
var name = "window";
var Wangcai = {
name: "Wangcai",
show: function () {
console.log(this.name);
},
f: function () {
var fun = this.show;
fun(); // 独立函数调用
}
}
Wangcai.f();
var name = "window";
var Wangcai = {
name: "Wangcai",
show: function () {
console.log(this.name);
},
f: function () {
var fun = this.show;
fun(); // 独立函数调用
}
}
Wangcai.f();
js
let fullname = "language";
let obj = {
fullname: "javascript",
props: {
getFullName: function () {
return this.name;
}
}
}
// 隐式绑定 点前面是obj.props getFullName中的this表示props
console.log(obj.props.getFullName());
let fullname = "language";
let obj = {
fullname: "javascript",
props: {
getFullName: function () {
return this.name;
}
}
}
// 隐式绑定 点前面是obj.props getFullName中的this表示props
console.log(obj.props.getFullName());
js
let fullname = "language";
let obj = {
fullname: "javascript",
props: {
fullname: "hello",
getFullName: function () {
return this.fullname;
}
}
}
console.log(obj.props.getFullName());
let fullname = "language";
let obj = {
fullname: "javascript",
props: {
fullname: "hello",
getFullName: function () {
return this.fullname;
}
}
}
console.log(obj.props.getFullName());
js
var fullname = "language";
var obj = {
fullname: "javascript",
props: {
fullname: "hello",
getFullName: function () {
return this.fullname;
}
}
}
let qq = obj.props.getFullName;
console.log(qq()); // 独立函数调用
var fullname = "language";
var obj = {
fullname: "javascript",
props: {
fullname: "hello",
getFullName: function () {
return this.fullname;
}
}
}
let qq = obj.props.getFullName;
console.log(qq()); // 独立函数调用
js
let fullname = "language";
var obj = {
fullname: "javascript",
props: {
fullname: "hello",
getFullName: function () {
return this.fullname;
}
}
}
let qq = obj.props.getFullName;
console.log(qq()); // undefined 独立函数调用
let fullname = "language";
var obj = {
fullname: "javascript",
props: {
fullname: "hello",
getFullName: function () {
return this.fullname;
}
}
}
let qq = obj.props.getFullName;
console.log(qq()); // undefined 独立函数调用
js
let obj = {
fn: (function () {
console.log(this); // window IIFE中this表示win
return function () {
console.log(this);
}
})()
}
obj.fn(); // 隐式绑定 this obj
let obj = {
fn: (function () {
console.log(this); // window IIFE中this表示win
return function () {
console.log(this);
}
})()
}
obj.fn(); // 隐式绑定 this obj
js
let obj = {
fn: (function () {
console.log(this); // window IIFE中this表示win
return function () {
console.log(this);
}
})()
}
let qq = obj.fn;
qq();
let obj = {
fn: (function () {
console.log(this); // window IIFE中this表示win
return function () {
console.log(this);
}
})()
}
let qq = obj.fn;
qq();
对象(object)
js
// Object叫类 在JS中也叫构造器,也叫构造函数
// new是一个运算符 new一个类,得到一个对象
// 对象是属性有无序集合,属性分两类:
// 1)私有属性
// 2)公有属性
let obj = new Object();
obj.name = "wc";
obj.age = 18;
obj.coding = function(){
console.log("coding...");
}
console.log(obj.name);
console.log(obj.age);
obj.coding();
// Object叫类 在JS中也叫构造器,也叫构造函数
// new是一个运算符 new一个类,得到一个对象
// 对象是属性有无序集合,属性分两类:
// 1)私有属性
// 2)公有属性
let obj = new Object();
obj.name = "wc";
obj.age = 18;
obj.coding = function(){
console.log("coding...");
}
console.log(obj.name);
console.log(obj.age);
obj.coding();
js
// 通过字面最的形式创建对象
let obj = {
name:"xq",
age:18,
running:function(){
console.log("runing...");
}
}
console.log(obj.name);
console.log(obj.age);
console.log(obj.running());
// 通过字面最的形式创建对象
let obj = {
name:"xq",
age:18,
running:function(){
console.log("runing...");
}
}
console.log(obj.name);
console.log(obj.age);
console.log(obj.running());
js
// Number 类
// new一个类得到一个对象
// 对象就存储在堆区 n1指向那个堆
let n1 = new Number();
console.log(n1); // Number {0}
let n2 = 220; // 220不是对象 字面量
let n3 = 3.1415926;
console.log(n3);
// n3不是对象,为什么可以打点调用toFixed?
// n3在打点的瞬间会包装成一个对象,就可以调用toFixed方法
// 调用结束,就还原成了基本数据类型
console.log(n3.toFixed(2));
// Number 类
// new一个类得到一个对象
// 对象就存储在堆区 n1指向那个堆
let n1 = new Number();
console.log(n1); // Number {0}
let n2 = 220; // 220不是对象 字面量
let n3 = 3.1415926;
console.log(n3);
// n3不是对象,为什么可以打点调用toFixed?
// n3在打点的瞬间会包装成一个对象,就可以调用toFixed方法
// 调用结束,就还原成了基本数据类型
console.log(n3.toFixed(2));
js
let s1 = new String("hello");
console.log(s1); // String {'hello'}
let s2 = "world";
console.log(s2.toUpperCase());
let s1 = new String("hello");
console.log(s1); // String {'hello'}
let s2 = "world";
console.log(s2.toUpperCase());
js
let b = new Boolean();
console.log(b); // Boolean {false}
let b2 = false;
let b = new Boolean();
console.log(b); // Boolean {false}
let b2 = false;
js
let obj = new Object();
console.log(obj);
let obj = new Object();
console.log(obj);
js
// 数组也是特殊的对象 对象中的键是索引
// 正方形也是矩形
let arr = new Array(1,2);
console.log(arr);
// 数组也是特殊的对象 对象中的键是索引
// 正方形也是矩形
let arr = new Array(1,2);
console.log(arr);
js
let d1 = new Date();
console.log(d1.getFullYear());
let d1 = new Date();
console.log(d1.getFullYear());
js
let f1 = new Function("a","b","return a+b");
console.log(f1(1,2));
let f1 = new Function("a","b","return a+b");
console.log(f1(1,2));
js
// TypeError: Math is not a constructor
// Math这个类不能new
// 不能new的类,叫单体内置类
let d = new Math();
console.log(d);
// TypeError: Math is not a constructor
// Math这个类不能new
// 不能new的类,叫单体内置类
let d = new Math();
console.log(d);
js
// 得到一个伪数组 伪数组不是数组 是对象
// ["a","b","c"] {0:"a",1:"b",2:"c"}伪数组
console.log(Array.isArray(document.getElementsByTagName("li")));
let lis = document.getElementsByTagName("li");
console.log(lis[0]);
// 一个真实的DOM元素,本质就是一个对象
// 这个对象中的属性非常多,操作这个对象,性能就非常低
// jq死了,jq操作的是DOM元素,操作DOM元素性能就低
// vue react操作的是虚拟DOM元素,虚拟DOM中的属性就没有那么多
console.dir(lis[0]);
// 得到一个伪数组 伪数组不是数组 是对象
// ["a","b","c"] {0:"a",1:"b",2:"c"}伪数组
console.log(Array.isArray(document.getElementsByTagName("li")));
let lis = document.getElementsByTagName("li");
console.log(lis[0]);
// 一个真实的DOM元素,本质就是一个对象
// 这个对象中的属性非常多,操作这个对象,性能就非常低
// jq死了,jq操作的是DOM元素,操作DOM元素性能就低
// vue react操作的是虚拟DOM元素,虚拟DOM中的属性就没有那么多
console.dir(lis[0]);
js
// instanceof 用来判断一个对象是否属于某个类
function Person(name,age){
this.name = name;
this.age = age;
}
let p = new Person("wc",18);
console.log(p instanceof Person); // true
// instanceof 用来判断一个对象是否属于某个类
function Person(name,age){
this.name = name;
this.age = age;
}
let p = new Person("wc",18);
console.log(p instanceof Person); // true
js
function ok(){
console.log("ok....");
}
ok.a = 1;
ok.b = 2;
ok.c = 3;
console.dir(ok);
function ok(){
console.log("ok....");
}
ok.a = 1;
ok.b = 2;
ok.c = 3;
console.dir(ok);
js
// console.log(window);
console.log(console);
console.log("hello")
console.info("hello")
console.dir('hello')
console.warn('hellw')
console.table('hello')
console.error("hello")
// console.log(window);
console.log(console);
console.log("hello")
console.info("hello")
console.dir('hello')
console.warn('hellw')
console.table('hello')
console.error("hello")
js
// 集合:操作集合
// 说到操作:增删改查 CRUD create read update delete
let obj = {
name:"wc",
age:100,
run:function(){
console.log("run...");
}
};
// 通过打点访问对象中的属性
console.log(obj.name);
console.log(obj.age);
// 通过[]去获取对象中的属性
console.log(obj["name"]);
console.log(obj["age"]);
let xx = "name";
// []中可以放变量 变量的值可以是属性名 键
// 有些情况下,访问一个对象中的属性,只能通过[]
console.log(obj[xx]);
console.log("-------------");
for(let key in obj){
console.log(key);
console.log(obj[key]);
}
// 集合:操作集合
// 说到操作:增删改查 CRUD create read update delete
let obj = {
name:"wc",
age:100,
run:function(){
console.log("run...");
}
};
// 通过打点访问对象中的属性
console.log(obj.name);
console.log(obj.age);
// 通过[]去获取对象中的属性
console.log(obj["name"]);
console.log(obj["age"]);
let xx = "name";
// []中可以放变量 变量的值可以是属性名 键
// 有些情况下,访问一个对象中的属性,只能通过[]
console.log(obj[xx]);
console.log("-------------");
for(let key in obj){
console.log(key);
console.log(obj[key]);
}
js
// 对象中的键是什么类型?
// 答:字符串,我们没有添加引号,没有添加引号,也是字符串类型
// 键能不能是其它类型?
// 答:能
let obj1 = {
123: "wc",
true: 100,
undefined: function () {
console.log("run...");
}
};
console.log(obj1[123]);
console.log(obj1[true]);
console.log(obj1.true);
console.log(obj1.undefined());
console.log(obj1[undefined]());
// 对象中的键是什么类型?
// 答:字符串,我们没有添加引号,没有添加引号,也是字符串类型
// 键能不能是其它类型?
// 答:能
let obj1 = {
123: "wc",
true: 100,
undefined: function () {
console.log("run...");
}
};
console.log(obj1[123]);
console.log(obj1[true]);
console.log(obj1.true);
console.log(obj1.undefined());
console.log(obj1[undefined]());
js
let obj = {
name: "wc",
age: 100,
run: function () {
console.log("run...");
}
};
console.log(obj.length); // undefined
// 能不能使用for循环遍历对象 ?
for(let i=0;i<obl.length;i++){}//次循环不会进去
// 遍历对象使用for in
for(let key in obj){
console.log(obj[key]);
}
let obj = {
name: "wc",
age: 100,
run: function () {
console.log("run...");
}
};
console.log(obj.length); // undefined
// 能不能使用for循环遍历对象 ?
for(let i=0;i<obl.length;i++){}//次循环不会进去
// 遍历对象使用for in
for(let key in obj){
console.log(obj[key]);
}
js
// for循环 forEach for of for in
let arr = ["wc","xq","jj"];
for(let i=0; i<arr.length; i++){
console.log(arr[i]);
}
arr.forEach(item=>console.log(item))
for(let item of arr){
console.log(item);
}
for(let key in arr){
console.log(arr[key]);
}
const boj = {name:'wgh',age:'18'};
[].push.apply(boj,[1,2,3])
console.log(boj);//{0: 1, 1: 2, 2: 3, name: 'wgh', age: '18', length: 3}
console.log(boj.push);//undefined
// for循环 forEach for of for in
let arr = ["wc","xq","jj"];
for(let i=0; i<arr.length; i++){
console.log(arr[i]);
}
arr.forEach(item=>console.log(item))
for(let item of arr){
console.log(item);
}
for(let key in arr){
console.log(arr[key]);
}
const boj = {name:'wgh',age:'18'};
[].push.apply(boj,[1,2,3])
console.log(boj);//{0: 1, 1: 2, 2: 3, name: 'wgh', age: '18', length: 3}
console.log(boj.push);//undefined
js
let obj = {
name:"wc",
age:18
}
obj.age = 28; // 改
console.log(obj.age);
let obj = {
name:"wc",
age:18
}
obj.age = 28; // 改
console.log(obj.age);
js
let obj = {
name: "wc",
age: 18
}
delete obj.age
console.log(obj.age);//undefined
let obj = {
name: "wc",
age: 18
}
delete obj.age
console.log(obj.age);//undefined
创建对象的方式
js
// 通过字面量的形式创建对象的缺点:
// 1)有大量的重复代码
// 2)内存空间浪费
let wc = {
name: "wangcai",
age: 11,
height: 188,
address: "bj",
coding: function () { console.log("coding..."); },
eating: function () { console.log("eating..."); }
}
let xq = {
name: "xiaoqiang",
age: 18,
height: 168,
address: "bj",
coding: function () { console.log("coding..."); },
eating: function () { console.log("eating..."); }
}
let jj = {
name: "jiajia",
age: 25,
height: 158,
address: "zz",
coding: function () { console.log("coding..."); },
eating: function () { console.log("eating..."); }
}
// 通过字面量的形式创建对象的缺点:
// 1)有大量的重复代码
// 2)内存空间浪费
let wc = {
name: "wangcai",
age: 11,
height: 188,
address: "bj",
coding: function () { console.log("coding..."); },
eating: function () { console.log("eating..."); }
}
let xq = {
name: "xiaoqiang",
age: 18,
height: 168,
address: "bj",
coding: function () { console.log("coding..."); },
eating: function () { console.log("eating..."); }
}
let jj = {
name: "jiajia",
age: 25,
height: 158,
address: "zz",
coding: function () { console.log("coding..."); },
eating: function () { console.log("eating..."); }
}
js
// 工厂函数 产出对象
function createPerson(name,age,height,address){
let p = {};
p.name = name;
p.age = age;
p.height = height;
p.address = address;
p.coding = function(){ console.log("coding...");}
return p;
}
let wc = createPerson("wangcai",11,180,"bj"); wc.coding();
let xq = createPerson("xiaoqiang", 12, 160, "zz"); xq.coding();
let jj = createPerson("jiajia", 16, 170, "bj"); jj.coding();
// wc xq jj都是字面量对象
// 期望不同的对象,有不同类
console.log(wc instanceof Object);
console.log(xq instanceof Object);
console.log(jj instanceof Object);
// 工厂函数 产出对象
function createPerson(name,age,height,address){
let p = {};
p.name = name;
p.age = age;
p.height = height;
p.address = address;
p.coding = function(){ console.log("coding...");}
return p;
}
let wc = createPerson("wangcai",11,180,"bj"); wc.coding();
let xq = createPerson("xiaoqiang", 12, 160, "zz"); xq.coding();
let jj = createPerson("jiajia", 16, 170, "bj"); jj.coding();
// wc xq jj都是字面量对象
// 期望不同的对象,有不同类
console.log(wc instanceof Object);
console.log(xq instanceof Object);
console.log(jj instanceof Object);
js
// new做了什么:
// 在构造器内部创建一个新的对象
// 这个对象内部的prototype属性会被赋值为该构造函数的prototype属性;
// 让构造器中的this指向这个对象
// 执行构造器中的代码
// 如果构造器没有返回对象,则返回上面的创建出来的对象
// 函数在JS有多种角色
// 其中一种角色就是构造器
function Fn(){
console.log("fn...");
// 1)创建一个新的对象
// 2)让函数中的this绑定到这个新对象上 new绑定
// 3)执行类(函数)中的代码
// 4)返回上面的新对象
}
// new一个构造器(类)
// let f = new Fn();
// console.log(f);
// console.log(f instanceof Fn);
// new做了什么:
// 在构造器内部创建一个新的对象
// 这个对象内部的prototype属性会被赋值为该构造函数的prototype属性;
// 让构造器中的this指向这个对象
// 执行构造器中的代码
// 如果构造器没有返回对象,则返回上面的创建出来的对象
// 函数在JS有多种角色
// 其中一种角色就是构造器
function Fn(){
console.log("fn...");
// 1)创建一个新的对象
// 2)让函数中的this绑定到这个新对象上 new绑定
// 3)执行类(函数)中的代码
// 4)返回上面的新对象
}
// new一个构造器(类)
// let f = new Fn();
// console.log(f);
// console.log(f instanceof Fn);
js
// 使用构造器的形式创建对象
// 缺点:也会造成内存空间浪费
// 问:有没有更加优雅的方式去创建对象?
// 答:有 构造器+原型对象的形式
function Person(name,age,height,address){
this.name = name;
this.age = age;
this.height = height;
this.address = address;
this.coding = function(){console.log(this.name + " coding");}
}
let wc = new Person("wangcai", 11, 180, "bj");
wc.coding();
let xq = new Person("xiaoqiang", 12, 160, "zz")
xq.coding();
let jj = new Person("jiajia", 16, 170, "bj");
jj.coding();
// 使用构造器的形式创建对象
// 缺点:也会造成内存空间浪费
// 问:有没有更加优雅的方式去创建对象?
// 答:有 构造器+原型对象的形式
function Person(name,age,height,address){
this.name = name;
this.age = age;
this.height = height;
this.address = address;
this.coding = function(){console.log(this.name + " coding");}
}
let wc = new Person("wangcai", 11, 180, "bj");
wc.coding();
let xq = new Person("xiaoqiang", 12, 160, "zz")
xq.coding();
let jj = new Person("jiajia", 16, 170, "bj");
jj.coding();
练习题
js
// 调用一个函数,参数的个数是不固定
// ...args 形式来接收 rust参数
// params 参数 是一个数组,数组中收集了所有的实参
let fn = function (...params) {
// console.log(Array.isArray(params));
return function gn(...args) {
params = params.concat(args);
let total = 0;
params.forEach(item=>total += item);
return total;
}
}
console.log(fn(1, 2)(3));
console.log(fn()(1,2,3));
console.log(fn(1,2,3)());
// fn()(1,2,3)
// fn(1, 2, 3)
// fn(1)(2,3)
// let res = fn(1, 2)(3);
// console.log(res);
// 调用一个函数,参数的个数是不固定
// ...args 形式来接收 rust参数
// params 参数 是一个数组,数组中收集了所有的实参
let fn = function (...params) {
// console.log(Array.isArray(params));
return function gn(...args) {
params = params.concat(args);
let total = 0;
params.forEach(item=>total += item);
return total;
}
}
console.log(fn(1, 2)(3));
console.log(fn()(1,2,3));
console.log(fn(1,2,3)());
// fn()(1,2,3)
// fn(1, 2, 3)
// fn(1)(2,3)
// let res = fn(1, 2)(3);
// console.log(res);
js
window.val = 1; // 2 4
var json = {
val: 10, // 20
dbl: function () {
this.val *= 2;
}
}
json.dbl();//json.val = 20
var dbl = json.dbl;
dbl(); //win.val = 2 独立函数调用
json.dbl.call(window);//win.val = 4
alert(window.val + json.val);//24
window.val = 1; // 2 4
var json = {
val: 10, // 20
dbl: function () {
this.val *= 2;
}
}
json.dbl();//json.val = 20
var dbl = json.dbl;
dbl(); //win.val = 2 独立函数调用
json.dbl.call(window);//win.val = 4
alert(window.val + json.val);//24
js
let obj = {
fn: (function () {
return function () {
console.log(this);
}
})()
};
obj.fn(); //{fn: ƒ} 隐式绑定
let fn = obj.fn;
fn(); //Window 独立函数调用
let obj = {
fn: (function () {
return function () {
console.log(this);
}
})()
};
obj.fn(); //{fn: ƒ} 隐式绑定
let fn = obj.fn;
fn(); //Window 独立函数调用
js
(function () {
var val = 1;
var json = {
val: 10,
dbl: function () {
console.log(this);//{val: 10, dbl: ƒ}
val *= 2;
(function (){
console.log(this);//Window
})()
}
};
json.dbl();
console.log(json.val + val);//12
})();
(function () {
var val = 1;
var json = {
val: 10,
dbl: function () {
console.log(this);//{val: 10, dbl: ƒ}
val *= 2;
(function (){
console.log(this);//Window
})()
}
};
json.dbl();
console.log(json.val + val);//12
})();
原型和原型链
一切都是对象 对象是属性的无序集合 操作集合 CRUD 函数有多种角色:
- 角色一:普通函数
- 角色二:对象的方法
- 角色三:普通对象
- 角色四:类(构造函数,构造器) 只要是一个对象,它的身上必定有一个属性,叫__proto__,__proto__是属性名,叫隐式原型,对象的值是一个对象
js
// obj是一个对象 对象是属性的无序集合
// 属性分两类:
// 1)私有属性
// 2)公有属性 沿着__proto__找到的属性都是公有属性
let obj = {
name: "wc", // 私有属性
}
console.log(obj);
// obj是一个对象 对象是属性的无序集合
// 属性分两类:
// 1)私有属性
// 2)公有属性 沿着__proto__找到的属性都是公有属性
let obj = {
name: "wc", // 私有属性
}
console.log(obj);
js
let obj = {
name:"wc",
age:18
}
console.log(obj);
// obj打点找hasOwnProperty,自己私有属性没有,就沿着__proto__去公有属性上找
// 只有找到了这个属性或方法,才能使用这个属性或方法
// hasOwnProperty 判断一个属性是否是私有属性
console.log(obj.hasOwnProperty('name')); // true
console.log(obj.hasOwnProperty('age')); // true
console.log(obj.hasOwnProperty('address')); // false
console.log(obj.hasOwnProperty('hasOwnProperty')); // false
// console.log(obj.wangcai);
// 总结:
// a.b 找a,先去自己的EC中找a,如果找不到,就去父的EC中找,如果还找不到,就去
// 父的父的中找,直到找到ECG,如果还找不到,报 a is not defined
// 这个查找机制,叫作用域链
// 找b,先找自己的私有属性,如果找不到,就沿__proto__去公有属性中找
// 如果公有属性一直找不到,得到und,因为查找一个对象上不存在的属性,
// 得到und,叫原型链
let obj = {
name:"wc",
age:18
}
console.log(obj);
// obj打点找hasOwnProperty,自己私有属性没有,就沿着__proto__去公有属性上找
// 只有找到了这个属性或方法,才能使用这个属性或方法
// hasOwnProperty 判断一个属性是否是私有属性
console.log(obj.hasOwnProperty('name')); // true
console.log(obj.hasOwnProperty('age')); // true
console.log(obj.hasOwnProperty('address')); // false
console.log(obj.hasOwnProperty('hasOwnProperty')); // false
// console.log(obj.wangcai);
// 总结:
// a.b 找a,先去自己的EC中找a,如果找不到,就去父的EC中找,如果还找不到,就去
// 父的父的中找,直到找到ECG,如果还找不到,报 a is not defined
// 这个查找机制,叫作用域链
// 找b,先找自己的私有属性,如果找不到,就沿__proto__去公有属性中找
// 如果公有属性一直找不到,得到und,因为查找一个对象上不存在的属性,
// 得到und,叫原型链
js
let obj = {
name: "wc",
age: 18
}
// __proto___对应的值是一个对象,这个对象,叫原型对象
console.log(obj.__proto__);
// obj.__proto__ 对应的是原型对象
// hasOwnProperty 相对于原型对象来说,是私有属性
obj.__proto__.hasOwnProperty("name")
// 原型对象,也是对象,只要是一个对象,身上都有一个__proto__
// 如果一直找下去,就找到了null
// console.log(obj.__proto__.__proto__);
let obj = {
name: "wc",
age: 18
}
// __proto___对应的值是一个对象,这个对象,叫原型对象
console.log(obj.__proto__);
// obj.__proto__ 对应的是原型对象
// hasOwnProperty 相对于原型对象来说,是私有属性
obj.__proto__.hasOwnProperty("name")
// 原型对象,也是对象,只要是一个对象,身上都有一个__proto__
// 如果一直找下去,就找到了null
// console.log(obj.__proto__.__proto__);
js
let arr = ["wc","xq"];
console.log(arr);
// 为什么可以点push
// push不是arr的私有属性,肯定是它的公有属性
arr.push("jj")
console.log(arr);
let arr = ["wc","xq"];
console.log(arr);
// 为什么可以点push
// push不是arr的私有属性,肯定是它的公有属性
arr.push("jj")
console.log(arr);
js
let arr = ["wc", "xq"];
console.log(arr);
// 找valueOf
// console.log(arr.__proto__.__proto__);
// arr.abcdef
let arr = ["wc", "xq"];
console.log(arr);
// 找valueOf
// console.log(arr.__proto__.__proto__);
// arr.abcdef
js
// in 判断是否有这个属性,不管是公有还是私有
// hasOwnProperty 判断是否是私有
let arr = [];
// in是用来判断一个属性是否属于某个对象
// 不管是私有还是公有
console.log("push" in arr); // true
// in 判断是否有这个属性,不管是公有还是私有
// hasOwnProperty 判断是否是私有
let arr = [];
// in是用来判断一个属性是否属于某个对象
// 不管是私有还是公有
console.log("push" in arr); // true
js
// 每个对象身上都有一个__proto__属性
// __proto__叫隐式原型
//
// 每个构造器(类)上都有一个叫prototype属性
// prototype叫显示原型
//
// 显示原型和隐式原型指向同一个对象
// 每个对象身上都有一个__proto__属性
// __proto__叫隐式原型
//
// 每个构造器(类)上都有一个叫prototype属性
// prototype叫显示原型
//
// 显示原型和隐式原型指向同一个对象
js
function fn(){
console.log("fn...");
}
console.dir(fn);
function fn(){
console.log("fn...");
}
console.dir(fn);
js
// arr1是对象 对象身上都有一个隐式原型
// Array是类,也叫构造器,本质就是函数
// 函数身都都一个显示原型
let arr1 = new Array("wc", "xq");
let arr2 = new Array("jj");
console.log(Array.prototype == arr1.__proto__); // true
console.log(Array.prototype == arr2.__proto__); // true
console.log(arr1.__proto__.__proto__ == Object.prototype); // true
console.log(arr1.__proto__.__proto__.__proto__); // null
let obj1 = new Object()
// arr1是对象 对象身上都有一个隐式原型
// Array是类,也叫构造器,本质就是函数
// 函数身都都一个显示原型
let arr1 = new Array("wc", "xq");
let arr2 = new Array("jj");
console.log(Array.prototype == arr1.__proto__); // true
console.log(Array.prototype == arr2.__proto__); // true
console.log(arr1.__proto__.__proto__ == Object.prototype); // true
console.log(arr1.__proto__.__proto__.__proto__); // null
let obj1 = new Object()
js
// 构造器
function Person(name,age){
this.name = name;
this.age = age;
}
let p = new Person("wc",18);
console.log(p.__proto__.constructor == Person); // true
// 构造器
function Person(name,age){
this.name = name;
this.age = age;
}
let p = new Person("wc",18);
console.log(p.__proto__.constructor == Person); // true
js
let num = new Number(110);
console.log(num.__proto__.constructor == Number);
// 1)一切都是对象
// 2)对象是属性的无序集合
// 3)属性分公有属性和私有属性
// 4)每个对象身上都有一个__proto__属性,叫隐式原型
// 5)每个函数身上都有一个prototype属性,叫显示式原型
// 6)对象的隐式原型和函数的显示原型,指向一个对象,叫原型对象
// 7)每一个原型对象身上有一个constructor属性,指向函数本身
let num = new Number(110);
console.log(num.__proto__.constructor == Number);
// 1)一切都是对象
// 2)对象是属性的无序集合
// 3)属性分公有属性和私有属性
// 4)每个对象身上都有一个__proto__属性,叫隐式原型
// 5)每个函数身上都有一个prototype属性,叫显示式原型
// 6)对象的隐式原型和函数的显示原型,指向一个对象,叫原型对象
// 7)每一个原型对象身上有一个constructor属性,指向函数本身
原型链习题
js
function Fn() {
this.x = 10;
this.y = 20;
this.getX = function () {
console.log(this.x)
}
}
Fn.prototype.getX = function () {
console.log(this.x)
}
Fn.prototype.getY = function () {
console.log(this.y)
}
let f1 = new Fn();
f1.getX();
f1.getY();
function Fn() {
this.x = 10;
this.y = 20;
this.getX = function () {
console.log(this.x)
}
}
Fn.prototype.getX = function () {
console.log(this.x)
}
Fn.prototype.getY = function () {
console.log(this.y)
}
let f1 = new Fn();
f1.getX();
f1.getY();
js
function Fn(num) {
this.x = this.y = num;
}
Fn.prototype = {
x: 20,
sum: function () {
console.log(this.x + this.y)
}
}
Fn.prototype.constructor = Fn;
let f1 = new Fn(10)
console.log(f1.sum === Fn.prototype.sum)
f1.sum();
Fn.prototype.sum();
console.log(f1.constructor)
function Fn(num) {
this.x = this.y = num;
}
Fn.prototype = {
x: 20,
sum: function () {
console.log(this.x + this.y)
}
}
Fn.prototype.constructor = Fn;
let f1 = new Fn(10)
console.log(f1.sum === Fn.prototype.sum)
f1.sum();
Fn.prototype.sum();
console.log(f1.constructor)
js
function Person(){
}
// 没有new,叫函数调用
// Person() 在你眼中就是一个值 返回值
// und
let p = Person();
function Person(){
}
// 没有new,叫函数调用
// Person() 在你眼中就是一个值 返回值
// und
let p = Person();
js
// Person是函数
// 函数有N种角色:
// 角色一:普通函数
// 角色二:方法
// 角色三:普通对象
// 角色四:类 推荐函数名大写 构造器
function Person() {
// 1)在Person函数中创建一个空对象 {} 0x666 {a:1,b:2,c:3}
// 2)this绑定 this = 0x666; this指向 上面的对象
this.a = 1;
this.b = 2;
this.c = 3;
// 3)执行Person函数中的代码
// 4)返回对象 返回0x666
}
// 把Person当成了一个对象 给这个对象身上添加xxx属性 值是ok
Person.xxx = "ok";
// new也是运算符 这个运算符的结果是对象
// 只要你敢new,出来的100%是对象
let p = new Person(); // p是0x666
// Person是函数
// 函数有N种角色:
// 角色一:普通函数
// 角色二:方法
// 角色三:普通对象
// 角色四:类 推荐函数名大写 构造器
function Person() {
// 1)在Person函数中创建一个空对象 {} 0x666 {a:1,b:2,c:3}
// 2)this绑定 this = 0x666; this指向 上面的对象
this.a = 1;
this.b = 2;
this.c = 3;
// 3)执行Person函数中的代码
// 4)返回对象 返回0x666
}
// 把Person当成了一个对象 给这个对象身上添加xxx属性 值是ok
Person.xxx = "ok";
// new也是运算符 这个运算符的结果是对象
// 只要你敢new,出来的100%是对象
let p = new Person(); // p是0x666
js
function Fn() {
let a = 1;
this.a = a;
}
Fn.prototype.say = function () {
this.a = 2;
}
Fn.prototype = new Fn();
let f1 = new Fn();
Fn.prototype.b = function () {
this.a = 3;
}
console.log(f1.a)
f1.say();
console.log(f1.a)
f1.b();
console.log(f1.a)
function Fn() {
let a = 1;
this.a = a;
}
Fn.prototype.say = function () {
this.a = 2;
}
Fn.prototype = new Fn();
let f1 = new Fn();
Fn.prototype.b = function () {
this.a = 3;
}
console.log(f1.a)
f1.say();
console.log(f1.a)
f1.b();
console.log(f1.a)