文章目录
目录
1.原型prototype
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<!--(一个互指的关系)
1.函数的prototype属性(图)
* 每个函数都有个prototype属性,它默认指向一个object空对象(即:原型对象,反正就是空壳方法)
* 原型对象中有一个属性constructor,它指向函数对象
2.给原型对象添加属性(一般都是方法)
* 作用:函数的所有 实例对象 自动拥有原型中的属性(方法)
-->
<script type="text/javascript">
/*每个函数都有一个prototype属性,他会默认指向一个object空对象(即:原型对象,反正就是空壳方法)*/
console.log(Date.prototype,typeof Date.prototype)//显示object
function Fun(){//快捷修改名字,alt+shift+r
}
console.log(Fun.prototype)//默认指向一个object空对象(没有我们的属性)
//原型对象中有个constructor,它指向函数对象
//举例:函数中的prototype.constructor指向函数data
console.log(Date.prototype.constructor===Date)
console.log(Fun.prototype.constructor===Fun)
//给原型对象添加属性(一般是方法)===>实例对象可以访问
Fun.prototype.test = function(){
console.log('test()')
}
</script>
</body>
</html>
2.显示原型链和隐式原型链
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
1. 每个函数function都有一个prototype,既显示原型(属性)
2. 每个实例对象都有一个__proto__,可称为隐式原型(属性)
3. 对象的隐式原型的值为其对应构造函数的显示原型的值
4. 内存结构(图)
5. 总结:
* 函数的prototype属性:在定义函数时自动添加的,默认值是一个空的object对象
* 对象的__proto__属性:创建对象时自动添加的,默认值为构造函数的prototype属性值
* 程序员能直接操作显示原型,但不能直接操作隐式原型(ES6之前)
-->
<script type="text/javascript">
//一、函数定义构造函数
function Fu(){
}
//1. 每个函数function都有一个prototype,既显示原型
console.log(Fn.prototype)//prototype,什么时候才能加 函数定义的时候就有了
//2. 每个实例对象都有一个__proto__,可称为隐式原型
//二、创建实例对象
var fn = new Fn()//内部语句:(fn)this.__proto__ = Fn.prototype
console.log(fn.__proto__)// __proto__ fn对象 的时候就有了
//3. 对象的隐式原型的值为其对应构造函数的显示原型的值
console.log(Fn.prototype===fn.__proto__))//显示为true
//四、4. 给原型添加方法
Fn.prototype.test = function(){
console.log('这是在原型中添加的test()方法')
}
//五、调用 给原型添加方法
fn.test();
//小型套娃环节
</script>
<!--总结:prototype和__proto__为引用变量,存放的都是地址值,并且值为一样的,所以共同指向原型
. 意思为:找到,访问
-->
</body>
</html>
3.原型链
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>原型链</title>
</head>
<body>
<!--
1. 原型链(图解)
*访问一个对象的属性时
* 先在自身属性中查找,找到返回
* 如果没有,再沿着__proto__这条链向上查找,找到返回
* 如果最终没有找到,返回undefined
* 别名:隐式原型链
* 作用:查找对象的属性(方法)
2. 构造函数/原型/实体对象的关系(图解)
3. 构造函数/原型/实体对象的关系2(图解)
-->
<script type="text/javascript">
//创建构造函数
function Fn(){
this.test1 = function(){
console.log('test1()')
}
}
Fn.prototype.test2 = function(){
console.log('test2()')
}
var fn = new Fn()
fn.test1()
fn.test2()
console.log(fn.toString())
</script>
</body>
</html>
4.原型链的属性问题
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
1. 读取对象的属性值时;会自动到原型链中查找
2. 设置对象的属性值时;不会查找原型链,如果当前对象没有此属性,直接添加属性并没有设置其值
3. 方法一般定义在原型中,属性一般通构造函数定义在对象本身上
-->
</body>
<!--<script type="text/javascript">
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.setName = function(name){
this.name = name;
}
person.prototype.sex = '男';
var p1 = new Person('Tom',12)
p1.setName('jack')
console.log(p1.name,p1.age,p1.sex)
p1.sex='女'
console.log(p1.name,p1.age,p1.sex)
var p2 = new Person('Bob',23)
console.log(p2.name,p2.age,p2.sex)
</script>
-->
<script type="text/javascript">
function Fn(){
}
Fn.prototype.a = 'xxx'
var fn1 = new Fn()
console.log(fn1.a,fn1)
//原型上的属性 实例对象自动可见
var fn2 = new Fn()
fn2.a = 'yyy'
console.log(fn1.a,fn2.a,fn2)// xxx(查找原型链上的属性) yyy(设置属性)
function Person(name , age){
this.name = name
this.age = age
}
//在原型链上面设置一个方法
Person.prototype.setName = function(name){
this.name = name
}
//创建对象实例
var p1 = new Person('Tom', 12)
p1.setName('Bob')
var p2 = new Person('jack', 12)
p2.setName('cat')
console.log(p2)
//属于同一个实例对象所以隐式原型都一样
console.log(p1.__proto__===p2.__proto__)//true
</script>
</html>
5.原型链的补充
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--实现继承(继承实际的方法)主要是依靠原型链来实现-->
<!--
原型链的基本思路:
1.利用原型让一个引用类型继承另一个引用类型的属性和方法
每个构造函数都有一个原型对象(var nan = new Person())
原型对象都包含一个指向构造函数想指针(constructor),
而实例对象都包含一个指向原型对象的内部指针(__proto__)。
如果让原型对象等于另一个类型的实例,
此时的原型对象将包含一个指向另一个原型的指针(__proto__),
另一个原型也包含着一个指向另一个构造函数的指针(constructor)。
假如另一个原型又是另一个类型的实例……这就构成了实例与原型的链条。
-->
<script type="text/javascript">
/*
1. 函数显示原型指向的对象是默认是空的实例对象(但object不满足)
* */
console.log(Fn.prototype instanceof Object)//true
console.log(Object.prototype instanceof Object)//false
console.log(Function.prototype instanceof Object)//ture
/*
2.所有的函数都是Function的实例(包含Function)
* */
console.log(Function.__proto__===Function.prototype)
/*
3. Object的原型对象是原型链的尽头
* */
console.log(Object.prototype.__proto__)//null
/*清楚举例说明*/
// function animal(){
// this.type = "animal";
// }
// animal.prototype.getType = function(){
// return this.type;
// }
//
// function dog(){
// this.name = "dog";
// }
// dog.prototype = new animal();
//
// dog.prototype.getName = function(){
// return this.name;
// }
// var xiaohuang = new dog();
//原型链关系
// xiaohuang.__proto__ === dog.prototype
// dog.prototype.__proto__ === animal.prototype
// animal.prototype.__proto__ === Object.prototype
// Object.prototype.__proto__ === null
</script>
</body>
</html>
6.探索instanceof
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
1.instanceof是如何判断的?
* 表达式:A instanceof B
* 如果函数B的显示原型对象在A对象的原型链上,返回true,否则返回false
2.Function是通过new自己产生的实例
-->
</body>
<script type="text/javascript">
/*
1.案例
* */
function Foo(){}
var f1 = new Foo()
console.log(f1 instanceof Foo)//true
console.log(f1 instanceof Object)//true
/*
2. 案例
* */
console.log(Object instanceof Function)//true
console.log(Object instanceof Object)//true
console.log(Function instanceof Function)//true
console.log(Function instanceof Object)//true
function foo(){}
console.log(Object instanceof Foo)//false
</script>
</html>
7.面试常问
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
测试题1
-->
<script type="text/javascript">
function A(){
}
A.prototype.n = 1
var b = new A()
A.prototype = {
n: 2,
m: 3
}
var c = new A()
console.log(b.n,b.m,c.n,c.m)//1,undefine,2 3
/*测试题2*/
function F(){}
Object.prototype.prototype.a = function(){}{
console.log('a()')
}
Function.prototype.b = function(){
console.log('b()')
}
var f = new F()
f.a()//a
f.b()//null
F.a()//a
F.b()//b
</script>
</body>
</html>
8.变量提升与函数执行(待补充)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
1. 变量声明提升(变量声明提前执行 但是没有赋值)
* 通过var定义(声明)的变量,在定义语句之前就访问到
* 值:undefined
2. 函数声明提升
* 通过function声明的函数,在之前就可以直接调用
* 值:函数定义(对象)
3. 问题:变量提升和函数提升如何产生的?
-->
<script type="text/javascript">
/*
面试题:输出underfind
为什么:在函数体执行之前,先这样声明了var a; 但是没有定义赋值
所以输出的时候按照规则先输出了上面的var a
* */
var a = 3
function fn(){
//var a ; 默认
console.log(a)//输出underfind
var a = 4
}
fn()
//第一种情况:变量提升
console.log(b)//输出:undefined 变量提升
var b = 3
//第二种情况:函数提升
fn2()//可调用 函数提升
fn3()//不能 变量提升
function fn2(){
console.log("fn()")//输出 :fn()
}
//第三种情况:一个用变量声明的函数(变量提升)
var fn3 = function(){
console.log('fn3()')
}
</script>
</body>
</html>
9.执行上下文
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
1. 代码分类(位置)
* 全局代码
* 函数(局部)代码
*
2. 全局执行上下文
* 在执行全局代码前将window确定为全局执行上下文
* 对全局数据进行预处理(马上即将要执行 做准备工作)
* var定义的全局变量==>underfind ,添加window的属性
* function声明的全局函数==>赋值(fun),添加window的方法
* this==>赋值(window)
*开始执行全局代码
*
3. 函数执行上下文
* 在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象
* 对局部数据进行预处理
* 形参变量==>赋值(实参)==>添加为执行上下文的属性
* argument==>赋值(实参列表),添加为执行上下文的属性
* var定义的局部变量==>underfind,添加执行上下文的属性
* function声明的函数==>赋值(fun),添加为执行上下文的方法
* this==>赋值(调用函数的对象)
* 开始执行函数体的代码
总结:总的来说是一个预处理 让栈给他分配内存 进行预处理的一个操作,这样就会理解变量提升和函数提升了
-->
<script type="text/javascript">
console.log(a1,window.a1)
window.a2()
console.log(this)
var a1 = 3//35直接跳到39 说明中间的执行过了
function a2(){
console.log("a2()")
}
console.log(a1)
console.log("2333333333333333333333333333333333");
//函数执行上下文
function fn(a1){
console.log(a1)//2
console.log(a2)//underfind
a3()//a3()
console.log(this)//window
console.log(arguments)//arguments[2]伪数组(2,3)
var a2 = 3
function a3(){
console.log('a3()')
}
}
fn(2,3)
</script>
</body>
</html>
10.执行上下文栈
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
栈:先进后出
1. 在代码执行执行前 ,JS引擎就会创建一个栈来存储管理所有的执行上下文对象
2. 在全局执行上下文(window)确定后,将其添加到栈中(压栈)
3. 在函数执行上下文创建后,将其添加到栈中(压栈)
4. 在当前函数执行完后,将栈顶的对象移除(出栈)
5. 当所有的代码执行完后,栈中只剩下window
-->
<script type="text/javascript">
var a = 10
var bar = function(x){
var b = 5
foo(x + b)
}
var foo = function(y){
var c = 5
console.log( a + c + y)//
}
bar(10)
bar(10)
//一共有5次
//调用的时候执行上下文
//1.window执行上下文 2.32行 3.26行
//预处理进行执行上下文:n+1
</script>
</body>
</html>
11.执行上下文2
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
1. 依次输出什么
2. 整个过程中产生了几个执行上下文 5个
-->
<script type="text/javascript">
console.log('global begin' + i)//global begin underfind
var i = 1
foo(1);
function foo(i){
if(i==4){
return;
}//递归内部都有结束调用的条件
console.log('foo() begin:'+i);//foo() begin:1 2 3
foo(i + 1);//递归调用:在函数内部自己调用自己
console.log('foo() end:' + i);//foo() end:3 2 1
}
console.log('global end:' + i);
</script>
</body>
</html>
12.面试题
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript">
//测试题1:先执行变量提升 再执行函数提升
function a(){}
var a;
console.log(typeof a)//输出:function
//测试题2:
//(!(在)不在)
if (!(b in window)) {//b在window有没有
var b = 1;
}
console.log(b)//underfind
//测试题3:
var c = 1
function c(c){//里面代码 没机会执行 上下文预处理
console.log(c)//输出:报错
}
c(2)
//和函数名有关系 var 声明了
//所以c不是一个函数
</script>
</body>
</html>
13.作用域
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
1. 理解
* 就是一块‘地盘’,一个代码所在的区域
* 它是静态的(相对于上下文对象),在编写代码时就确定了
2. 分类
* 全局作用域
* 函数作用域
* 没有块作用域(ES6有了)
3. 作用
* 隔离变量,不同作用域下的同名变量不会有冲突
-->
<script type="text/javascript">
/*
没有块作用域
if(true){
var c = 3
}
console.log(c)
*/
var a = 10, b = 20;
function fn(x){
var a = 100,c= 300;
console.log('fn()',a,b,c,x)//100 20 300 10
function bar(x){
var a =1000,
d = 400
console.log('bar()',a,b,c,d,x)//1000 20 300 400 100 //1000 20 300 400 200
}
bar(100)
bar(200)
}
fn(10)
</script>
</body>
</html>
14.作用域与上下文
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
1. 区别1
* 全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了。而不是在函数调用时
* 全局执行上下文环境是在全局作用域确定之后,js代码马上执行创建
* 函数执行上下文环境是在调用函数时,函数体代码执行之前创建
2. 区别2
* 作用域是静态的,只要函数定义好了就一直存在,且不会再变回
* 执行上下文是动态的,调用函数时创建,函数调用结束时就会自动释放
3.联系3
* 执行上下文环境(对象)是从属于所在的作用域
* 全局上下文环境==>全局作用域
* 函数上下文环境==>对应的函数使用域
-->
<script type="text/javascript">
var a = 10, b = 20;
function fn(x){
var a = 100,c= 300;
console.log('fn()',a,b,c,x)//100 20 300 10
function bar(x){
var a =1000,
d = 400
console.log('bar()',a,b,c,d,x)//1000 20 300 400 100 //1000 20 300 400 200
}
bar(100)
bar(200)
}
fn(10)
</script>
</body>
</html>
15.作用域链
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
?
<!--
1. 理解
* 多个上下级关系的作用域形成的链,它的方向是从下到上(从内到外)
* 查找变量时就是沿着作用域链来查找的
2. 查找一个变量的查找规则
* 在当前作用域下的执行上下文查找对应的属性,如果有直接返回,否则进入2
* 在上一级作用域的执行上下文中查找对应的属性,如果有直接返回,否则进入3
* 再次执行2的相同操作,直到全局作用域。如果还找不到就抛出找不到的异常
-->
<script type="text/javascript">
var a = 1
function fn1(){
var b = 2
function fn2(){
var c =3
console.log(a)
console.log(b)
console.log(c)
console.log(d)
}
fn2()
}
fn1()
</script>
</body>
</html>
16.作用域面试题
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript">
var x = 10;
function fn(){
console.log(x)//10
}
function show(f){
var x = 20;
f();
}
show(fn);
</script>
</body>
</html>
17.作用域面试题2
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript">
var fn = function(){
console.log(fn)//输出整个函数
}
fn()
var obj = {
fn2:function(){
console.log(this.fn2)//这样才能找到
console.log(fn2)//报错找不到对象
}
}
obj.fn2()
</script>
</body>
</html>
18.引入
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>引入</title>
</head>
<body>
<button>测试1</button>
<button>测试2</button>
<button>测试3</button>
<!--
需求:点击某个按钮,提示点击的是第n个按钮
-->
<script type="text/javascript">
/*var btns = document.getElementsByTagName('button');
//添加历遍和监听
for (var i=0,length=btns.length;i<length;i++)
var btn = btns[i]
btn.onclick = function(){
alert("第"+(i+1)+"个");//不可行
}*/
/* var btns =document.getElementsByTagName('button')
for (var i = 0; i <btns.length ; i++) {//length=btns.length;i<length效率提升:面试会问
var btn = btns[i]
btn.onclick = function(){
alert('第'+(i+1)+'个');
}
}错误:都是第四个
*/
//第二种:
/*var btns = document.getElementsByTagName('button')
for (var i = 0; i < btns.length; i++) {
var btn = btns[i]
//得出下标
btn.index = i
btn.onclick =function(){
alert('第' + (this.index+i)+ '个')
}
}*/
//第三种:
/*var btns = document.getElementsByTagName('button')
for (var i = 0; i < btns.length; i++) {
(function (i){
var btn = btns[i]
btn.onclick = function(){
alert('第' + (this.index+i)+ '个')
}
})(i)
}*/
//第三种:自己练习:闭包
var btns = document.getElementsByTagName('button')
for (var i = 0; i < btns.length; i++) {
(function(i){
var btn = btns[i]
btn.onclick= function(){
alert('第'+(i+1)+'个')
}
})(i)
}
</script>
</body>
</html>
总结
有待补充完善