JavaScript对象,包装类,原型,原型链及call/apply的知识学习(三)

对象

学习包装类的前提一定是建立在,了解对象及使用的,简单来说,一个对象包含属性和方法,它形似于函数,但通过new的方式来创建他的实例,对象可以定义为空,当创建他的实例之后再通过.调用的方法创建实例对象的属性以及方法。

function Person() {
    
     }

var person = new Person();
person.name = "xxx";
person.work = function () {
    
    
	console.log("i am working!");
}

通常我们用this关键字来指代对象内部的属性和方法,使用new关键字调用构造方法:

  • 1.会在构造函数的执行期上下文中隐式的创建this{}空对象
  • 2.然后在这个this对象当中去定义原有对象的属性和方法,并将实参赋值
  • 3.最后再隐式的将这个this对象返回
    如果对象中写明要返回常量,在new的时候也不会执行,而是继续隐式的返回这个this{}。
    在访问对象中不存在的属性或方法,不会报错,而是显示undefined
    我们在日常程序创建当中,常用**对象名={}**的方式直接来创建一个对象,它会隐式的帮我们完成相关操作,使得代码更加简洁。

包装类

我们所熟知的number,string这都是属于基本类型,不具备对象的功能,但是我们给它做一些的对象操作,结果却并非我们想象的那样。

var a = 10;
a.abc = "hello!";
console.log(a.abc)

既然a是基本类型,但是我们用a.abc给它来增加属性,运行得知,系统并没有报错,可是当我们console这个属性的时候,却又会显示undefined,这究竟是怎么回事。
其实它也执行了几步操作:

  • 1.在a.abc的时候,系统发现它不是对象,无法这样操作,就自动帮我们把a转换成数字对象(包装类)。
  • 2然后对这个a对象进行定义abc属性,在定义完成之后又自动销毁这个对象。
  • 3.当我们再次调用a.abc的时候,他又发现a不是对象,于是隐式的将a转换,然后在他的内部寻找abc属性,最后发现这个新的对象并没有此属性,于是就会返回undefined。

我们用类似的string定义变量尝试,结果也会是这样,但是为什么我们可以使用**字符串.length()**去获取字符串的长度,这是因为这是对象字符串原始定义的就存在这个属性,所以在隐式转换之后,能够得到我们想要的结果。

知识小补充

字符串.charCodeAt(x)
这是对象字符串里的另一个方法,可以返回字符串指定字符的unicode编码序号,利用这个方法我们可以判断出字符串所占字节数,当返回值小于255时占一位,反之占两位。

原型

所有的对象被实例化出来之后,他们都有一个共同的父内,他被包含在function对象当中,原型也是对象,在函数对象定义时,它就被隐式包含在内,即prototype{},我们可以在当中定义一些方法和属性,那么被实例化出来的对象将自动继承这些,且被共有。

Student.prototype.name = "xxx";
function Student() {
    
    }
var student = new Student();

这样定义后,我们查看student.name,就会返回“xxx”,但是如果我们想要更改原型中的属性,决不能student.name = “yyy”,,这样的话会在原有对象内部重新定义name属性,而不会修改原型当中的属性,当对象和原型属性重名时,选择就近原则调取相应的值。

constructor

这是原型对象中的一个原始属性,当原型建立初期就存在,表示了当前对象的构造方法,也可以自己手动更改。

__ proto __

这个属性也被包含于prototype对象,他相当于java中的super,保证了子对象和祖先能够通过__proto__为连接轴一直关联,直到顶端的Object.prototype,可以手动的修改某一父辈的原型,但他们最后还是会连接到顶端。它是大多数对象的顶层原型,这里强调是大多数,而并非所有。js中也存在方法覆盖,toString()就是来自于Object.prototype当中的方法,但在很多对象当中都被覆盖重写了。

Object.create(原型)

这个方法就是存在于绝大部分外的一小部分。

obj = {
    
    name="xxxx"}
var obj1 = Object.create(obj)

这样也可以起到创建对象的作用,但是你不会在它的里面找到__proto__对象,因为他在创建时已经被指定了唯一的原型。参数是一定要填的,否则会语法报错。
当我们想要B构造函数可以获取到A构造函数的原型,我们常常设置中间变量temp,让他的原型指向A的原型,再把B的原型指向temp,这样既保证了继承的需求,又保证了当B对原型属性修改时,不会影响到A的原型。

function Person() {
    
    
	name:"xxx";
}
var A={
    
    }
A.prototype = Person;
function extend(target,origin){
    
    
	var F = {
    
    }
	F.prototype = A.prototype;
	target.prototype = F;
}
extend(B,A);
var a = new A();
var b = new B();

call/apply

call的作用是用来改变this的指向,利用其他的构造函数来完成自身构造函数的实现。

function Person(name,age) {
    
    
	this.name = name;
	this.age = age;
}
function Studetn(name.age.socer) {
    
    
	Person.call(this,name,age);
	this.socer = socer;
}
var stu = new Student("xxx",18,99);

Person.call()的作用等于Person,都是去调用这个函数,唯一的区别就是.call的第一位参数要指定this修改到哪个对象身上,从第二个参数才开始是真正的参数。如上代码,正是展示了他的最常用做法,利用已有的部分相同属性的对象来创建自身属性,减少了代码的冗余,使得代码更加精炼简洁。
apply的用法和call一模一样,只不过他要求传入的实参必须是一个数组,如Person.call(this,[name,age]);

猜你喜欢

转载自blog.csdn.net/baldicoot_/article/details/106215797
今日推荐