笔记目录
小概
本章学习内容:原型链的介绍理解(图解),instanceOf,arguments复习。代码量虽少,但是都是一些理解性的知识。关键字:prototype ,__ proto __ ,constructor ,Object , Function , instanceOf.
1. 原型链
对象都有原型,原型也是对象,那原型也有原型,这样就形成了一个链式结构 ,称为原型链
.
原型链的作用:体现在对象访问成员的访问规则,一个对象去点一个方法,先在对象自己上找,如果没有就去自己的原型找,原型没有就沿着原型链一直往上查找,如果找不到就报错或是返回undefined
原理其实是继承
function Student(name, age) {
this.name = name;
this.age = age;
this.swmming = function () {
console.log('我在游泳....');
}
}
//每一个学生都有一个学习的方法
Student.prototype.study = function () {
console.log('我是学生,我在学习....');
}
//每一个学生都一个type属性,都是人.
Student.prototype.type = '人';
//实例化一个学生对象.
let s1 = new Student('闫正', 34);
console.log(s1);
// console.log(s1.name);//'闫正'
// console.log(s1.type);//'人'
// console.log(s1.sb);//undefined
// s1.swmming();//对象自己有,可以调用
// s1.study();//对象虽然自己没有,但是原型有,所以也可以调用.
// s1.dsb();//对象自己没有,原型也没有,所以报错了
s1.toString(); //上层原型对象里有tostring这个方法
1.2 js内置对象的原型
//内置对象的原型链.
//1.数组
// let arr = [10,20,30]; //let arr = new Array(10,20,30);
// console.log(arr);
// console.log(arr.__proto__ === Array.prototype); //true
// console.log(arr.__proto__.__proto__.constructor);//Object()
// console.log(arr.__proto__.__proto__ === Object.prototype);//true
//------------------------------------
//为什么数组对象toString()得到的结果和普通对象toString()得到的结果不一样?
//arr1调用的toString()是Array.prototype中的toString();
//obj1调用的toString()是Object.prototype中的toString();
// let arr1 = new Array(10,20,30);
// console.log(arr1.toString()); //'10,20,30'
// let obj1 = new Object();
// console.log(obj1.toString());//'[object Object]'
//2.日期对象
// let date1 = new Date();
// //用console.log()直接打印日期对象,相当于是日期对象调用了toString()方法.
// console.log(date1);
// console.log(date1.toString());
// console.log(date1.toLocaleString());
// //如果想要查看日期对象本身,就要使用console.dir();
// console.dir(date1);
// console.log(date1.__proto__ === Date.prototype);//true
// console.log(date1.__proto__.__proto__.constructor); //Object()
// console.log(date1.__proto__.__proto__ === Object.prototype);//true
//3.dom对象
// let div1 = document.querySelector('div');
// let p1 = document.querySelector('p');
// let a1 = document.querySelector('a');
// console.log(div1.__proto__ === HTMLDivElement.prototype);//true
//移除属性
//removeAttribute()这个方法在Element.prototype原型中定义的.
//div1.removeAttribute('aaa');
//普通对象
let obj = {
name:'德磊',
age:18
};
console.log(obj);
//报错了,obj.removeAttribute is not a function
//普通对象的原型中是没有这个方法的.
//这个方法是地能以在Element.prototype原型中的. 意味着只有元素才能点出这个方法来.
obj.removeAttribute('age');
原型中的方法是可以重写的,Object.toString() ,Array.toString()重写了。
1.2 函数
函数是一个对象,是由Function构造函数实例化出来的.
//1.函数也是一个对象.
function test(){
console.log('我是一个函数');
}
//把函数当做一个对象,往中添加sb属性和dsb方法.
test.sb = '随便';
test.dsb = function(){
console.log('你是一个da随便...');
}
//验证.
console.dir(test);
console.log(test.sb);
test.dsb();
//2.既然函数是一个对象,那这个对象是由哪个构造函数实例化的呢?
console.log(test.__proto__.constructor);//Function()
console.log(test.__proto__ === Function.prototype);//true
console.log(test.__proto__.__proto__.constructor);//Object()
console.log(test.__proto__.__proto__ === Object.prototype);//true
//1. 声明了一个无参无函数体的函数.
// let fn1 = new Function();
// console.log(fn1);
//2. 声明一个无参有函数体的函数.
// let fn2 = new Function('console.log("德华你好....")');
// console.log(fn2);
// fn2();
//3. 声明一个有参有函数体的函数.
// let fn3 = new Function('num1','num2','console.log(num1+num2,"哈哈哈");');
// fn3(10,20);
//4. 声明一个有参有函数体有返回值的函数.
// let fn4 = new Function('num1','num2','console.log(num1+num2,"哈哈哈");return num1*10;');
// console.log(fn4(10,20));;
函数可以像对象一样,通过函数名 . 属性值 =属性值,或者函数名 . 方法名=function() 给函数自身添加属性和方法 并且 通过点语法来调用
2. 静态成员和实例成员
静态成员: 构造函数直接点出来的.
实例成员: 实例化对象点出来的.
function Student(name,age){
this.name = name;
this.age = age;
this.sayHi = function(){
console.log('呵呵呵呵');
}
}
//把Student看成是一个对象,往中添加一个sayHi方法
Student.sayHi = function(){
console.log('你好');
}
Student.sayHi(); //静态成员.
//实例化对象.
let s1 = new Student('正正',19);
console.log(s1.name); //实例成员
s1.sayHi(); //实例成员
3. instanceOf
语法: 对象 instanceof 构造函数
作用: 判断这个构造函数的prototype属性 在不在这个对象的原型链上,如果在返回true,如果不在返回false.
实际用途:
- 可以用来判断这个对象的构造函数(判断类型)
- 可以放心的去使用这个构造函数的prototype里面的成员
//1.
// let arr = [10,20,30];
console.log(arr instanceof Array);//true
console.log(arr instanceof Object);//true
//2.
//根据instanceof运算符的语法来看,前面的Object应该看成是对象,后面的Object看成是构造函数.
Object对象的原型链: Function.prototype => Object.prototype => null
console.log( Object instanceof Object); //true
console.log( Object instanceof Function);//true
//3.
//根据instanceof运算符的语法,前面的Function看成是对象, 后面的Function看成是构造函数.
//Function对象的原型链: Function.prototype => Object.prototype => null
console.log(Function instanceof Function);//true
console.log(Function instanceof Object);//true
4. Object.prototype成员介绍
//1.constructor
//指向构造函数
//2.hasOwnProperty
//语法: 对象.hasOwnPropert('属性名/方法');
//作用: 判断这个属性/方法 是否是属于对象自己的,如果是就返回true,否则返回false,
// let obj = {
// name:'正正',
// age:18,
// sayHi:function(){
// console.log('你好');
// }
// }
// obj.__proto__.type = '人';
// obj.__proto__.sayHello = function(){
// console.log('sayhello');
// }
// console.log(obj.hasOwnProperty('name'));//true
// console.log(obj.hasOwnProperty('sayHi'));//true
// console.log(obj.hasOwnProperty('type'));//false
// console.log(obj.hasOwnProperty('sayHello'));//false
//3.isPrototypeOf
//语法: 对象1.isPrototypeOf(对象2);
//作用: 判断对象1是否是对象2的原型, 如果是返回true,否则返回false.
// let obj1 = {name:'哈哈1'};
// let obj2 = {name:'呵呵2'};
// obj2.__proto__ = obj1;//这句话的意思是修改obj2的原型为obj1,也就是说现在obj1是obj2的原型了.
// console.log(obj1.isPrototypeOf(obj2));//true
// let arr = [10,20,30];
// console.log(Array.prototype.isPrototypeOf(arr));//true
//4. propertyIsEnumerable
//语法: 对象.propertyIsEnumerable('属性名/方法名');
//作用: 判断属性是否是对象自己的,以及是否可以遍历. 都符合才是true.
// let obj = {
// name:'正正',
// age:18,
// sayHi:function(){
// console.log('你好');
// }
// }
// obj.__proto__.type = '人';
// obj.__proto__.sayHello = function(){
// console.log('sayhello');
// }
// //自己的属性以及原型中自己添加的属性,都是可以遍历的.
// // for(let key in obj){
// // console.log(key);
// // }
// console.log(obj.propertyIsEnumerable('name'));//true
// console.log(obj.propertyIsEnumerable('age'));//true
// console.log(obj.propertyIsEnumerable('sayHi'));//true
// console.log(obj.propertyIsEnumerable('type'));//false
// console.log(obj.propertyIsEnumerable('sayHello'));//false
//5. toLocaleString
// 本地字符串.
//6. toString
// 字符串
// [object type], 其中type是数据类型
//7. valueOf
// 原始值
// let num = new Number(10);
// num.toString();
// console.log(num);
// console.log(num.toString());//'10'
// console.log(num.valueOf());//10
5. 函数作为对象的成员介绍.
5.1 caller
如果test2函数是在test1函数中调用的,那么test2函数的caller就是test1.
test1没有在任何一个函数中调用,那test1的caller就是null.
function test1(){
console.log('我是test1函数');
console.log(test1.caller);
test2();
}
function test2(){
console.log('我是test2函数');
console.log(test2.caller);
}
test1();
5.2 length
形参长度(个数)
function test1(){
console.log('我是test1函数');
console.log(test1.caller);
test2();
}
function test2(){
console.log('我是test2函数');
console.log(test2.caller);
}
test1();
5.3 name
函数名
5.4 prototype原型
每个构造函数都有一个原型 :函数名.prototype,构造函数的实例对象中也有一个参数__proto__ 指向 构造函数的原型。
5.5 arguments
是一个伪数组 用于存放实参的值
//也是一个伪数组,也是存放实参的值.
//和以前我们学的arguments不是同一个东西.
//以前我们学的arguments和形参一一对应, 今天的这个并没有一一对应.
function test1(num1,num2){
num1 = 1000;
console.log(arguments); //和形参一一对应的
console.log(test1.arguments);//并没有和形参一一对应.
console.log(arguments === test1.arguments);//false
console.log(test1.arguments.__proto__ === Array.prototype);//false
}
test1(100,200,300);
这个了解即可,arguments用的更多,test1.arguments不知道应用场景是什么。
总结
是不是感觉很绕?俺也一样,反正记住构造函数有一个原型对象,构造函数操作原型对象:构造函数.prototype ,原型对象里面的constructor指向构造函数;构造函数实例化的p1,实例对象.__proto __指向原型。