一、原型对象
1.定义:声明一个函数,那么这个函数默认有一个属性叫prototype,通过这个属性去获取函数的原型对象。
声明一个对象,它默认有一个属性是__proto__,获取原型对象:obj.__proto__
说明:函数、数组都属于特殊的对象
修改原型对象的属性:Person.prototype.x = 20
给原型对象添加属性:var a={y:200};Person.prototype.x = a
2.访问原型对象中成员的方式:
1. 直接访问。对象访问成员时,自己没有就访问到原型对象中的成员
2. 通过对象的__proto__属性访问。先访问到原型对象,然后通过原型对象访问原型对象的成员
3. 通过对象的构造函数的prototype属性访问。访问到原型对象然后通过原型对象访问原型对象的成员
例子:
function Person() {
this.age = 1;
}
Person.prototype.x = 100;
var p1 = new Person();
//方式1:p1对象没有x成员,则在p1的原型对象Person.prototype中找x
console.log(p1.x); //打印100
//方式2:通过p1的原型对象访问x
console.log(p1.__proto__.x); //打印100
//方式3:通过p1的构造函数的原型对象访问x
console.log(Person.prototype.x);//打印100
笔试题:原型对象的操作(设置、获取原型对象内部成员、修改原型对象)(访问后操作,只距离第一种访问方式)
obj.x:若是取x成员,先取自己存储空间中的x,没有就去原型对象中取;
若是存数据到x成员,自己有就更新数据x;如果没有就添加一个x成员,不修改原型对象的数据。
笔试常考技术点:修改系统的、官方设计的原型对象会被静默(不报错,但代码不生效)。对象不能修改原型对象的成员,但可以修改原型对象的成员的内部数据。
验证:
function Person() { }
Person.prototype = { x: 100, y: { age: 20 } };
p1 = new Person;
p1.x = 11; //p1中添加x成员,原型对象的x不变
p1.y.age = 666; //没有修改原型对象的成员y的值,而是修改了y内部的数据
console.log(p1); //打印{x:100,y:{age:666}}
二、this与原型对象
this代表它所在的函数运行时, 哪个对象让它运行,谁就是this
1.例题:
function Parent() {
this.a = 1;
this.b = [1, 2, this.a];
this.c = {
demo: 5,
};
this.show = function () {
console.log(this.a, this.b, this.c.demo);
};
}
function Child() {
this.a = 2;
this.change = function () {
this.b.push(this.a);
this.a = this.b.length;
this.c.demo = this.a++;
};
}
Child.prototype = new Parent();
//Child.prototype={a:1,b:[1,2,1],c:{demo: 5},show:f,__proto__:Parent.prototype{}}
var parent = new Parent();
//parent={a:1,b:[1,2,1],c:{demo: 5},show:f,__proto__:Parent.prototype{}}
var child1 = new Child();
//child1={a:2,change:f,Child.prototype}
var child2 = new Child();
//child2={a:2,change:f,Child.prototype}
child1.a = 11;
//child1{11,change:f,Child.prototype}
child2.a = 12;
//child2{12,change:f,Child.prototype}
parent.show(); //1 [1,2,1] 5
child1.show(); //11 [1,2,1] 5
child2.show(); //12 [1,2,1] 5
child1.change();
//b=[1,2,1,11] a=11=>4==>5 c=5==>4
//改变了child的原型对象
//a:11==>4==>5 c:5 b:[1,2,1,11]
//Child.prototype = {a:1,b:[1,2,1,11],c{demo:5},show:f,__proto__:Parent.prototype{}}
child2.change(); //b=[1,2,1,12] a=4 c=6 a=5
//改变了child的原型对象
//a:12==>5==>6 b:[1,2,1,11,12] c:5
//Child.prototype = {a:1,b:[1,2,1,11,12],c{demo:5},show:f,__proto__:Parent.prototype{}}
parent.show(); //1 [1,2,1] 5
child1.show(); //5 [1,2,1,11] 5
child2.show(); //6 [1,2,1,12] 6
2.改变this的指向
1. 通过添加并赋值来调用函数
var obj = {
say: function () { console.log(this); },
name: "karen",
};
var obj2 = { name: "jack" };
obj.say(); //打印含有karen的这个函数
obj2.fn = obj.say; //给obj2添加fn函数属性,以便调用
obj2.fn(); //打印含有jack的这个函数
2. fn.call(obj,29,30,10)
call:将函数的this指向call的第一个参数,并调用该函数;其余参数实际传给了函数 例:getA.call(obj,1,2,3)。
所有函数都有一个call函数,调用时改变函数内部的this。call是一个函数,所以它也有call函数。所有函数都有一个length属性(形参个数)和name属性(函数名)
3.fn.apply(obj,[29,30,10])
将函数的this指向apply的第一个参数,并调用该函数;其余参数需要用数组包裹成一个参数,再传给函数 例:getA.apply(obj,[1,2,3])
4.bind() 只能用在函数的定义式写法中
将函数的this指向bind的第一个参数,不会调用函数,而是返回一个函数的引用地址。要调用该函数时加上小括号,然后在小括号里面传其余参数例:getA.bind(obj)(1,2,3)
function fn(a, b, c) {
console.log(a, b, c, this);
}
//function fn(a,b,c){}.bind 报错,不可以这样写,必须写在定义式里面
fn(10, 20, 30); //打印10,20,30,window...没有调用的对象时,默认为window
var obj = { name: "Allen" };
fn.call(obj, 29, 30, 10);//打印29,30,10 Allen
fn.apply(obj, [29, 30, 10]);//打印29,30,10 Allen
fn.bind(obj, 29, 30, 10)();//打印29,30,10 Allen
声明式: function fn(){}.bind({name:'111'})
定义式:say:function(){}
三、全局标识
全局指script脚本的作用域。在全局作用域中声明的变量或者函数,运行的时候会默认添加成为window对象的成员。