prototype
内存浪费问题
function Stu(name,age,sex){ // 构造函数中的this指代当前对象,创建的是哪个对象就指向哪个对象
this.name = name
this.age = age
this.sex= sex
this.sayHi = function(){
console.log("大家好,我叫"+this.name+",今年"+this.age+"岁了,
是一个"+this.sex+"生");
}
}
var zs = new Stu("张三",20,"男");
// console.log(zs);
zs.sayHi();
var ls = new Stu("李四",19,"男");
// console.log(ls);
ls.sayHi();
console.log(zs.sayHi===ls.sayHi) // false
由以上案例不难看出, 函数的功能就是用来打印输出一句话的,函数功能是一样的.
函数也是一个对象没有必要开辟多个空间来存储函数.
只开辟一块空间来存储特定的函数即可.
function Stu(name,age,sex){ // 构造函数中的this指代当前对象,创建的是哪个对象就指向哪个对象
this.name = name
this.age = age
this.sex= sex
this.sayHi = fn
}
function fn(){
console.log("大家好,我叫"+this.name+",今年"+this.age+"岁了,是一个"+this.sex+"生");
}
var zs = new Stu("张三",20,"男");
// console.log(zs);
zs.sayHi();
var ls = new Stu("李四",19,"男");
// console.log(ls);
ls.sayHi();
console.log(zs.sayHi===ls.sayHi) // true
上面的案例实现的效果和第一个是一模一样的,但是更节约内存空间,但是代码呢,似乎有些格格不入,何解?
prototype应用
既然这样,我们可以把方法单独的进行一个设置,如下:
function Stu(name,age,sex){ // 构造函数中的this指代当前对象,创建的是哪个对象就指向哪个对象
this.name = name
this.age = age
this.sex= sex
}
Stu.prototype.sayHi = function (){
console.log("大家好,我叫"+this.name+",今年"+this.age+"岁了,是一个"+this.sex+"生");
}
var zs = new Stu("张三",20,"男");
// console.log(zs);
zs.sayHi();
var ls = new Stu("李四",19,"男");
// console.log(ls);
ls.sayHi();
console.log(zs.sayHi===ls.sayHi) // true
prototype的方法扩展
凡是定义在prototype原型对象上的方法,都可以被其实例所调用
/**
* 所有的构造函数都有prototype原型对象
* 原型对象可以用来扩展方法,以创建出来的实例对象调用
* 在prototype上面定义或是扩展的方法,能够被所有的实例子对象来调用
*/
var arr = new Array(10,20);
Array.prototype.log1 =function (){
console.log(1122334645);
}
// arr.push()
// console.dir(arr);
// arr.log1();
// var arr1 = ["Abc","aaa"];
// arr1.log1()
var date = new Date();
Date.prototype.getLog = function (){
console.log("hello");
}
date.getLog();
属性的访问规则
实例对象优先访问构造函数中的属性,如果没有的话才会到原型对象上去查找
/*
* 原型对象prototype不但可以定义方法还可以添加属性
* 原型对象上的方法和属性被所有的实例对象所共有
* 如果实例对象上有自己的属性的话,则优先使用自身的属性,如果自身没有这个属性再去原型对象上找
* 如果原型对象上也没有,则是undefined
*
* 一般的用法是尽量不要在原型对象上定义属性,把属性于自己的属性定义构造函数里面
* 要在原型对象上定义公共的函数或是方法
* 所以通用的做法是
* 将属性定义在构造函数里面
* 将方法或是函数定义在原型对象上
*/
function Stu(name,age,sex){ // 构造函数中的this指代当前对象,创建的是哪个对象
就指向哪个对象
this.name = name
this.age = age
this.sex= sex
}
Stu.prototype.sayHi = function (){
console.log("大家好,我叫"+this.name+",今年"+this.age+"岁了,是一个"+this.sex+"生");
}
Stu.prototype.address="上海市";
Stu.prototype.name = "小明";
var zs = new Stu("张三",19,"男");
// zs.sayHi();
// console.log(zs.address); // 凡是定义在prototype原型对象上的属性或是方法可以
用实例对象直接调用
var ls = new Stu("李四",19,"男");
// console.log(ls.address);
console.log(zs.name);
console.log(ls.name);
console.dir(Stu);
console.log(zs.score);
三者之间的关系
构造函数、实例对象、原型对象之间的关系
1.凡是构造函数都有一个prototype属性和一个prototype原型对象
2.凡是实例对象都有一个**proto**属性
3.凡是构造函数的原型对象都有一个constructor属性
这三者的关系可以用一个最简单的原型链来表示:
模拟forEach
var nums = [10,20,30,40,50,60];
Array.prototype.myForEach = function(fn,arr){
for(var i=0;i<this.length;i++){
fn(this[i],i,arr);
}
}
nums.myForEach(function(item,index,arr){
console.log(item,index,arr);
})
模拟filter
function myFilter(fn,arr){
var newArr = []
for(var i=0;i<arr.length;i++){
if(fn(arr[i],i)){
newArr.push(arr[i])
}
}
return newArr;
}
var nums = [10,20,30,40,50,60,12,13,15,16,22];
var arr = myFilter(function(item,index,){
return item > 20;
},nums)
console.log(arr);
模拟sort
function mySort(fn, arr) {
for (var i = 0; i < arr.length - 1; i++) {
for (var j = 0; j < arr.length - 1 - i; j++) {
// if(arr[j]>arr[j+1]){
// if (arr[j] - arr[j + 1] > 0) {
if (fn(arr[j], arr[j + 1]) > 0) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
var arr = [10, 20, 12, 32, 25, 26, 78, 96, 36, 21];
mySort(function (a, b) {
return a - b ;
}, arr)
console.log(arr);