JS原型和原型链,JS对象,js递归经典案例,构造函数继承
myzbx 2025-08-31 06:14 59 浏览
原型和原型链
面向对象编程:
1,对象:
面向对象编程(oop)是目前主流的编程范式,它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间分工与合作,完成对真实世界的模拟。
每一个对象都是功能中心,具有明确分工,可以完成接收信息,处理数据,发出信息等任务。对象可以复用,通过继承机制还可以定制。因此,面向对象编程具有灵活、代码可复用、高度模块化等特点,容易维护和开发,比起由一些列函数或指令组成的传统的过程是编程更适合多人合作的大型软件项目。
根据我们以往经验,如果学习过java的话,对于类和对象就很容易理解了
01,对象是单个实物的抽象
02,对象是一个容器,封装了属性(property)和方法(method),属性就是描述对象的特征,方法则表示对象的一系列行为动作。
2,构造函数:
面向对象编程的第一步,就是要生成对象。我们在面向对象语言(java)中说过,对象是一个具体的、单个实物的抽象。通常需要一个模板,表示某一类实物的共同特征,然后对象根据这个模板生成,这个模板在面向对象语言中,都有一个class(类)的概念在里面,但是在JavaScript语言的对象体系,是基于构造函数(constructor)和原型链(prototype)。
JavaScript中,所谓的构造函数,就是专门用来生成实例对象的函数。他就是对象的模板,描述实例对象的基本结构。一个构造函数,可以生成多个实例对象,这些实例对象都有相同的结构。
let Good = function(){
this.price = 100;
}
Good 就是构造函数,为了与之前学的普通函数区别,构造函数首字母通常大写。
构造函数的特点:
01,函数体内部使用了this关键字,代表了所要生成的对象实例
02,生成对象的时候,必须使用new关键字
3,new:
01,new命令的作用就是执行构造函数,返回一个实例对象。在我们刚才的构造函数基础上
let good1 = new Good();
good1.price //100
此时我们分析this的指向,之前我们this的词法作用域分析,this指向调用this所在的函数对象。在构造函数中,this代表的是新生成的实例对象。
构造函数也可以接受参数。
这里在有一种不被推荐但是仍正确的写法:
let good = new good;
new本身就可以执行构造函数,所以后面的括号可以不带,但是推荐使用括号。
同时,我们可以关注一个问题,如果我们不写new
此时就 变成了一个普通函数,这时候,我们关注下this指向
let Good = function(){
this.price = 100;
}
let good = Good();
good //undefined
price // 1000
调用的时候没有写new,this指向变化,price变成了全局变量
如果还有印象,我们java里有一个判断实例对象所属类,instanceof,同时在js里一样的
good instanceof Good
02,分析new命令执行时,函数执行步骤:
(1)创建一个空对象,作为将要返回的对象实例。
(2)将这个空对象的原型,指向构造函数的prototype属性。
(3)将这个空对象赋值给函数内部的this的关键字
(4)开始执行构造函数内部的代码
构造函数内部,this指的是一个新生成的空对象,所有针对this的操作,都会发生在这个空对象上。构造函数之所以叫构造函数,是说这个函数的目的就是操作一个空对象(即this对象),将其构造为需要的样子。
*如果构造函数内部有return语句,而且return语句后面跟着一个对象,new命令会返回return语句指定的对象;否则,就会不管return语句,返回this对象;
let Good =function(){
this.price =100;
return 100;
}
new Good();
let Good =function(){
this.price =100;
return {"aa":1};
}
new Good();
*如果普通函数(没有this关键字),使用new命令,则返回一个空对象。
4,Object.create()创建实例对象:
构造函数作为模板,可以生成实例对象,但是有时拿不到构造函数,只能拿到一个现有的对象。我们希望以这个现有的对象作为模板,生成新的实例对象,这时就可以使用Object.create()方法
let person1 ={
name:"张三",
age:20,
sayHello:function(){
console.log("我是"+this.name)
}
};
let person2 = Object.create(person1);
person2.name //张三
person2.sayHello() //我是张三
对象person1是person2的模板,后者继承了前者的属性和方法
4,构造函数的缺点
JavaScript 通过构造函数生成新对象,因此构造函数可以视为对象的模板。实例对象的属性和方法,可以定义在构造函数内部
function Cat(name,color){
this.name =name;
this.color = color;
}
let cat = new Cat("小花","花色");
cat.name
cat.color
Cat 函数是一个构造函数,函数内部定义了name属性和color属性,所有实例对象都会生成这两个属性。
通过构造函数 为实例对象定义属性,虽然方便,但是有一个缺点。同一个构造函数的多个实例之间,无法共享属性,从而造成对系统资源的浪费。
function Cat(name,color){
this.name = name;
this.color=color;
this.meow = function(){
console.log("喵喵");
};
}
let cat1 = new Cat("大毛","黄色");
let cat2 = new Cat("二毛","灰色");
cat1.meow === cat2.meow //false
这段代码里,cat1和cat2是同一个构造函数的两个实例,它们都具有meow()方法。由于meow方法是生成在每个实例对象上面,所以两个实例就生成了两次。也就是说,每新生成一个实例,就会新建一个meow方法。这即没有必要,又浪费系统资源,因为所有meow方法都是同样的行为,完全应该共享。
这个问题的解决方法,就是JavaScript的原型对象(prototype)
5,prototype属性的作用
JavaScript 继承机制的设计思想就是,原型对象的所有属性和方法,都能被实例对象共享,也就是说,如果属性和方法定义在原型上,那么所有的实例对象就能共享,不仅节省了内存,还体现了实例对象之间的联系。
JavaScript规定,每个函数都有一个prototype属性指向一个对象
function f(){
typeof f.protype //object
}
上面代码中,函数f默认具有protype属性,指向一个对象。
对于普通函数来说,该属性基本无用。但是,对于构造函数来说,生成实例的时候,该属性会自动称为实例对象的原型。
function Animal(name){
this.name = name;
}
Animal.prototype.color = 'white';
let cat1 = new Animal('大毛');
let cat2 = new Animal('二毛');
cat1.color
cat2.color
上面代码里,构造函数Animal的prototype属性,就是实例对象cat1和cat2的原型对象。原型对象上添加一个color属性,所有的实例对象都共享了该属性。
我们通过prototype来改写下之前构造函数缺陷的问题:
function Cat(name,color){
this.name = name;
this.color=color;
}
Cat.prototype.meow = function(){
console.log("喵喵");
};
let cat1 = new Cat("大毛","黄色");
let cat2 = new Cat("二毛","灰色");
cat1.meow === cat2.meow
原型对象的属性不是实例对象自身的属性。只要修改原型对象,变动就会立刻体现在所有的实例对象上
function Animal(name){
this.name = name;
}
Animal.prototype.color = 'white';
let cat1 = new Animal('大毛');
let cat2 = new Animal('二毛');
cat1.color
cat2.color
Animal.protype.color ='yellow';
cat1.color
cat2.color
原型对象的color属性值变为yellow,两个实例对象的color属性立刻跟着变了。这是因为实例对象其实没有color属性,都是读取原型对象的color属性。也就是说,当实例对象本身没有某个属性或方法的时候,它会到原型对象去寻找该属性或放啊。这就是原型对象的特殊之处
如果实例对象自身就有某个属性或方法,它就不会再去原型对象寻找这个属性或方法。
cat1.color ='black';
cat1.color
cat2.color
Animal.prototype.color
由此可见,原型对象的作用,就是定义所有实例对象共享的属性和方法。这也是它被称为原型对象的原因,而实例对象可以视作从原型对象衍生出来的子对象。
1.3原型链
JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型...
如果一层层的上溯,所有对象的原型最终都可以上溯到Object.protype,即Object构造函数的portotype属性。也就是说,所有对象都继承了Object.prototype的属性。这就是所有对象都有valueof和toString 方法的原因,因为这是从Object.prototype继承的。
Object.prototype 对象的原型是null,由于null没有任何属性,所以原型链到此为止。Object.getPrototypeOf 方法返回参数对象的原型。
object.getPrototypeof(Object.protoype)
读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到他的原型去找,如果还是找不到,就到原型的原型去找。如果知道最顶层的Object.prototype还是找不到,则返回undefined 如果对象自身和他的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这在js里可以被翻译为“覆盖”,即overriding,在java、c++这些严格面向对象语言里,我们很熟悉,就是重写
*注意,一级级向上,在整个原型链上寻找某个属性,对性能是有影响的,所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。
可以通过分析一段代码看下:
let MyArr = function(){};
MyArr.prototype = new Array();
MyArr.prototype.constructor = MyArr;
let mine = new MyArr();
mine.push(1,2,3);
mine.length
mine instanceof Array
分析这段代码,mine是构造函数MyArr的实例对象,由于MyArr.prototype指向一个数组实例,使得mine可以调用数组方法(这些方法定义在数组实例的prototype对象上面)。最后的instanceof表达式,用来比较一个对象是否是某个构造函数的实例,结果就证明,mine是Array的实例
6,constructor属性
prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。
function P(){}
P.prototype.constructor === P
由于constructor属性定义在prototype对象上面,意味着可以被所有实例对象继承
function P(){}
let p =new P();
p.constructor === P
p.constructor === P.prototype.constructor
p.hasOwnProperty('constructor') //检测p自身是否有constructor
p是构造函数P的实例对象,但是p自身没有constructor属性,该属性其实是读取原型链上面的P.prototype.constructor属性
constructor属性的作用是,可以得知某个实例对象,到底是哪一个构造函数产生的。
function F(){}
let f = new F();
f.constructor === F
f.constructor ===RegExp
constructor属性确定了对象f的构造函数是F而不是RegExp
有了constructor属性,就可以从一个实例对象创建另一个实例
function Constr(){}
let x = new Constr();
let y = new x.constructor();
y.instanceof Constr //true
x是构造函数Constr的实例,可以从x.constructor
间接调用构造函数。这使得在实例方法中,调用自身的构造函数成为可能。
Constr.prototype.createCopy = function(){
return new this.constructor();
}
这里createCopy方法调用构造函数,新建另一个实例。
constructor属性标识原型对象与构造函数之间的关联关系,如果修改了原型对象,一般会同时修改constructor属性,防止引用的时候出错。
function Person(name){
this.name = name;
}
Person.prototype.constructor === Person
Person.prototype ={
method:function(){}
};
Person.prototype.constructor === Person
Person.prototype.constructor === Object
这段代码里,构造函数Person的原型对象改掉了,但是没有修改constructor属性,导致这个属性不在指向Person。由于Person的新原型是一个普通对象,而普通对象的constructor属性指向object构造函数,导致
Person.prototype.constructor变成了Object。
所以,修改原型对象时,一般都要同时修改constructor属性的指向。
//有问题的写法
C.prototype ={
method1:function(...){...},
}
//正确的写法
C.prototype ={
constructor:C,
method1:function(...){...}
};
//更好的写法
C.prototype.method1 = function(...){...};
可以看到上面的写法里,要么将constructor属性重新指向原来的构造函数,要么只在原型对象上添加方法,这样可以保证instanceof运算符不会失真
7,构造函数的继承
让一个构造函数继承另一个构造函数,是非常常见的需求。这可以分成两步实现。第一步是在子类的构造函数中调用父类的构造函数。
function Sub(value){
Super.call(this);
this.prop = value;
}
Sub是子类的构造函数,this是子类的实例,在实例上调用父类的构造函数Super,就会让子类实例具有父类实例的属性。
第二步,让子类的原型指向父类的原型,这样子类就可以继承父类的原型。
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.prototype.method ='...';
Sub.prototype是子类的原型,要将它直接赋值为Object.create(Super.prototype),而不是直接等于Super.prototype。否则后面两行对Sub.prototype的操作,会连父类的原型Super.prototype一起修改掉。
//动物的构造函数
function Animal(name,age){
this.name = name;
this.age = age;
}
//猫的构造函数
function Cat(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
我们使用继承的一个重要的原因就是可以省略很多重复性的代码,现在作为猫,它本身属于动物,因此猫的name和age如果我们可以从动物上继承就可以不用在猫里重复写了。
我们先根据我们往常的经验进行一波改造
function Cat (name,age,sex){
Animal(name,age);
this.sex = sex;
}
let miao = new Cat('miaomiao',2,'boy');
miao.sex
miao.name
miao.age
运行可以看下结果
这里我们可以按照词法作用域来分析下,这个name和age实际上是在window上了
所以这个思路实际 上是有问题的,问题就是在执行Animal的时候里面this的指向出了问题。
思考一下,我们其实有一种强制扭转this指向的东西,call和apply。根据这个思路修改下代码
function Cat (name,age,sex){
Animal.call(this,name,age);
this.sex = sex;
}
let miao = new Cat('miaomiao',2,'boy');
miao.sex
miao.name
miao.age
但是我们现在再回归我们的主题,现在我们的代码是真正意义上的继承么?其实只是伪继承,只是借用call来执行了下Animal,甚至都没有把两个构造函数关联起来。我们真正的继承一定是通过原型去做继承的。因此我们的任务还是没有完成。
//把子类的原型指向父类的原型,并把子类的构造函数改回成子类
Cat.prototype = Object.create(Animal.prototype);
也可以直接:
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat
这就是目前通用的组合继承
8,Object.getPrototypeOf()
让Object.getPrototypeOf方法返回参数对象的原型。这是获取原型对象的标准方法。
let F = function(){}
let f = new F();
Object.getPrototypeOf(f) === F.prototype
空对象的原型是Object.prototype
Object的原型是null
函数的原型是Function.prototype
9,Object.setPrototypeOf()
Object.setPrototypeOf 方法为参数对象设置原型,返回该参数对象。它接受两个参数,第一个是现有对象,第二个是原型对象。
let a = {};
let b = {x:1};
Object.setPrototypeOf(a,b);
Object.getPrototypeOf(a) === b
new 命令可以使用Object.setPrototypeOf方法模拟
let F = function(){
this.foo ="bar";
};
下面两个代码相当于:let f = new F();
let f = Object.setPrototypeOf({},F.prototype);
F.call(f);
第一步,将一个空对象的原型设为构造函数的prototype属性,
setPrototypeof方法返回设置好的对象,赋值给f
第二部,将构造函数内部的this绑定这个空对象,然后执行构造函数,使得定义在this上面的方法和属性都转移到空对象上
10,Object.create()
生成实例对象的常用方法是,使用new命令让构造函数返回一个实例。但是很多时候,只能拿到一个实例对象,它可能根本不是由构建函数生成的,所以借助create可以从一个实例对象生成另一个实例对象。
该方法接受一个对象作为参数,然后以它为原型,返回一个实例对象。该实例完全继承原型对象的属性。
let A = {
print:function(){
console.log("hello,world");
}
}
let B = Object.create(A);
Object.getPrototypeOf(B) ===A
B.print === A.print
11,Object.prototype.isPrototypeOf()
实例对象的isPrototypeOf方法,用来判断该对象是否为参数对象的原型
let a1 = {};
let a2 =Object.create(a1);
let a3 = Object.create(a2);
a2.isPrototypeOf(a3)
a1.isPrototypeOf(a3)
a1和a2都是a3的原型
12,Object.prototype.__proto__
实例对象__proto__属性,前后各两个下划线,返回该对象的原型。改属性可读写。
let obj = {};
let p ={};
obj.__proto__ =p;
Object.getPrototypeOf(obj) === p
上面代码通过__proto__属性,将p对象设为obj对象的原型。
根据语言标准,__prototype__属性只有浏览器才需要部署,其他环境可以没有这个属性。他前后的两根下划线,表明他本质是一个内部属性,不应该对使用者暴露,因此,应该尽量少用这个属性。而是用,Object.getPrototypeOf()和Object.setPrototype(),进行原型对象的读写操作
原型链可以用__proto__很直观的表示
let A ={
name:'张三'
}
let B ={
name:'李四'
}
let proto = {
print:function(){
console.log(this.name);
}
}
A.__proto__ = proto;
B.__proto__ = proto;
A.print();
B.print();
A.print === B.print
A.print === proto.print
B.print ===proto.print
A对象和B对象的原型都是proto对象,他们都共享proto对象的print方法,也就是说,A和B的print方法,都是在调用proto对象的print方法
let obj = new Object();
obj.__proto__ ===Object.protottype
obj.__proto__ === obj.constructor.prototype
上面的代码新建了obj对象,他的__proto__属性,指向构造函数(object或obj.constructor)的prototype属性。
因此,获取实例对象obj的原型对象有三种方法:
01,obj.__proto__
02,obj.constructor.prototype
03,Object.getPrototypeOf(obj)
上面三个方法里面,前两种都不是很可靠,__proto__属性只有浏览器才需要部署,其他环境可以不部署。而obj.constructor.prototype在手动改变原型对象时,可能会失效。比如下面的例子:
let P=function(){};
let p = new P();
let C =function(){};
C.prototype = P;
let c = new C();
c.constructor.prototype === p //false
因此推荐使用第三种Object.getPrototype()方法,获取原型对象
13,Object.getOwnPropertyNames()
Object.getOwnPropertyNames()方法返回一个数组,成员是参数对象本身所有属性的键名,不不含继承属性键名。
Object.getOwnPropertyNames(String);
String.prototype
对象本身的属性里,有的是可以遍历的,有的是不可以遍历的,这取决于内部关于他们属性的访问特性,类似于java的访问修饰符,js里分别是:readonly,dontEnum,dontDelete,internal.我们这里这个方法返回所有的键名,不管是否可以遍历。
如果需要只获取可以遍历的属性,需要使用Object.keys方法
Object.keys(String)
可以发现,String对象所有自身的属性是不可以遍历的
14,Object.prototype.hasOwnProperty()
对象实例hasOwnProperty方法返回一个布尔值,用于判断某个属性是定义在对象自身上还是定义在原型链上
String.hasOwnProperty("length")
String.hasOwnProperty("substring")
15,in运算符和for...in循环
in运算符返回一个布尔值,标识一个对象是否具有某个属性。它不区分该属性是对象自身的属性,还是继承的属性。
’length' in String
'substring' in String
in用于检查一个属性是否存在
因此,获得对象的所有可遍历属性(不管是自身的还是继承的),可以使用for...in循环
let a1 ={p1:123};
let a2 =Object.create(a1,{p2:{value:"abc",enumerable:true}};
for(p in a2){
console.log(p);
}
这里补充点Object.create()方法的知识。这个方法创建一个拥有指定原型和若干个指定属性的对象,我们之前只学了他的前半句。现在补充下
第一个参数:新对象的原型对象
第二个参数:新对象指定的属性,是一个对象形式的配置
value:属性的默认值,默认为undefined
congigurable:能否使用delete、能否修改属性特性、或能否修改访问器属性,false为不可重新定义,默认是true
writeable:对象属性是否可修改,默认为true,可修改,设施false可以理解为不可修改的常量
16,对象的拷贝
引用数据类型在内存中:名存在栈内存中,值存在堆内存里,但是栈内存会提供一个引用地址指向堆内存里的值
let a = [1,2,3];
let b = a;
b[1]=5;
a[1]
这里可以看到[1,2,3]在堆内存里只有一份,被a和b共享着,所以a和b只是地址指向堆内存里,并且b=a的时候,只是a把地址告诉了b,这就是浅拷贝
深拷贝:
一个变量对另外一个变量的值进行拷贝,并且两个对象值改变相互没有影响,深拷贝针对的是引用数据类型。
补充知识:递归算法
有个讲故事的例子可以浅显的说明递归:
从前有座山,山里有个庙,庙里有个老和尚讲故事,讲的是从前有座山,山里有个庙,庙里有个老和尚在给小和尚讲故事,讲的是.....
这就是一个典型的递归算法思路,但是是一个失败的递归,因为这个递归是个死胡同,永远没有出口,也就是终止条件。
递归本质上是将原来的问题,转换成为一个更小的同一问题。也就是一个函数不断的调用自己,直到把问题解决完。
最经典的应用就是斐波那契数列:
1、1、2、3、5、8、13、21、34...
这个通项可以使用线性代数里的特征方程推导。
F(0) =0,F(1)=1,F(n)=F(n-1)+F(n-2) (n>=2)
转换成代码:
function Fibonacci(n){
if(n<=2){ return 1};
return Fibonacci(n-1)+Fibonacci(n-2);
}
function deepClone(obj) {
let objClone = Array.isArray(obj) ? [] : {};
if(obj && typeof obj === "object") {
for(key in obj) {
if(obj.hasOwnProperty(key)) {
//判断ojb子元素是否为对象,如果是,递归复制
if(obj[key] && typeof obj[key] === "object") {
objClone[key] = deepClone(obj[key]);
} else {
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
对象原型
"__proto__"是每一个对象都有的特殊属性
"__proto__"属性引用的就是对象原型
对象原型也是一个对象;
对象原型的属性/方法同样可以通过对象调用,被称为对象的原型属性/方法
随便创建一个对象,看下他的原型
let obj ={
name:"obj"
}
console.log(obj.__proto__) ;
在原型上添加的属性
obj.__proto__.age=13;
console.log(obj.name+","+obj.age)
在实例上直接添加的属性和方法叫:实例属性和实例方法
通过或在原型上添加的属性和方法叫:原型属性和原型方法
原型链
相关推荐
- 如何设计一个优秀的电子商务产品详情页
 - 
        
加入人人都是产品经理【起点学院】产品经理实战训练营,BAT产品总监手把手带你学产品电子商务网站的产品详情页面无疑是设计师和开发人员关注的最重要的网页之一。产品详情页面是客户作出“加入购物车”决定的页面...
 
- 怎么在JS中使用Ajax进行异步请求?
 - 
        
大家好,今天我来分享一项JavaScript的实战技巧,即如何在JS中使用Ajax进行异步请求,让你的网页速度瞬间提升。Ajax是一种在不刷新整个网页的情况下与服务器进行数据交互的技术,可以实现异步加...
 
- 中小企业如何组建,管理团队_中小企业应当如何开展组织结构设计变革
 - 
        
前言写了太多关于产品的东西觉得应该换换口味.从码农到架构师,从前端到平面再到UI、UE,最后走向了产品这条不归路,其实以前一直再给你们讲.产品经理跟项目经理区别没有特别大,两个岗位之间有很...
 
- 前端监控 SDK 开发分享_前端监控系统 开源
 - 
        
一、前言随着前端的发展和被重视,慢慢的行业内对于前端监控系统的重视程度也在增加。这里不对为什么需要监控再做解释。那我们先直接说说需求。对于中小型公司来说,可以直接使用三方的监控,比如自己搭建一套免费的...
 
- Ajax 会被 fetch 取代吗?Axios 怎么办?
 - 
        
大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!今天给大家带来的主题是ajax、fetch...
 
- 前端面试题《AJAX》_前端面试ajax考点汇总
 - 
        
1.什么是ajax?ajax作用是什么?AJAX=异步JavaScript和XML。AJAX是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX可以使网页实...
 
- Ajax 详细介绍_ajax
 - 
        
1、ajax是什么?asynchronousjavascriptandxml:异步的javascript和xml。ajax是用来改善用户体验的一种技术,其本质是利用浏览器内置的一个特殊的...
 
- 6款可替代dreamweaver的工具_替代powerdesigner的工具
 - 
        
dreamweaver对一个web前端工作者来说,再熟悉不过了,像我07年接触web前端开发就是用的dreamweaver,一直用到现在,身边的朋友有跟我推荐过各种更好用的可替代dreamweaver...
 
- 我敢保证,全网没有再比这更详细的Java知识点总结了,送你啊
 - 
        
接下来你看到的将是全网最详细的Java知识点总结,全文分为三大部分:Java基础、Java框架、Java+云数据小编将为大家仔细讲解每大部分里面的详细知识点,别眨眼,从小白到大佬、零基础到精通,你绝...
 
- 福斯《死侍》发布新剧照 "小贱贱"韦德被改造前造型曝光
 - 
        
时光网讯福斯出品的科幻片《死侍》今天发布新剧照,其中一张是较为罕见的死侍在被改造之前的剧照,其余两张剧照都是死侍在执行任务中的状态。据外媒推测,片方此时发布剧照,预计是为了给不久之后影片发布首款正式预...
 
- 2021年超详细的java学习路线总结—纯干货分享
 - 
        
本文整理了java开发的学习路线和相关的学习资源,非常适合零基础入门java的同学,希望大家在学习的时候,能够节省时间。纯干货,良心推荐!第一阶段:Java基础重点知识点:数据类型、核心语法、面向对象...
 
- 不用海淘,真黑五来到你身边:亚马逊15件热卖爆款推荐!
 - 
        
Fujifilm富士instaxMini8小黄人拍立得相机(黄色/蓝色)扫二维码进入购物页面黑五是入手一个轻巧可爱的拍立得相机的好时机,此款是mini8的小黄人特别版,除了颜色涂装成小黄人...
 
- 2025 年 Python 爬虫四大前沿技术:从异步到 AI
 - 
        
作为互联网大厂的后端Python爬虫开发,你是否也曾遇到过这些痛点:面对海量目标URL,单线程爬虫爬取一周还没完成任务;动态渲染的SPA页面,requests库返回的全是空白代码;好不容易...
 
- 最贱超级英雄《死侍》来了!_死侍超燃
 - 
        
死侍Deadpool(2016)导演:蒂姆·米勒编剧:略特·里斯/保罗·沃尼克主演:瑞恩·雷诺兹/莫蕾娜·巴卡林/吉娜·卡拉诺/艾德·斯克林/T·J·米勒类型:动作/...
 
- 停止javascript的ajax请求,取消axios请求,取消reactfetch请求
 - 
        
一、Ajax原生里可以通过XMLHttpRequest对象上的abort方法来中断ajax。注意abort方法不能阻止向服务器发送请求,只能停止当前ajax请求。停止javascript的ajax请求...
 
- 一周热门
 
- 最近发表
 
- 标签列表
 - 
- HTML 简介 (30)
 - HTML 响应式设计 (31)
 - HTML URL 编码 (32)
 - HTML Web 服务器 (31)
 - HTML 表单属性 (32)
 - HTML 音频 (31)
 - HTML5 支持 (33)
 - HTML API (36)
 - HTML 总结 (32)
 - HTML 全局属性 (32)
 - HTML 事件 (31)
 - HTML 画布 (32)
 - HTTP 方法 (30)
 - 键盘快捷键 (30)
 - CSS 语法 (35)
 - CSS 轮廓宽度 (31)
 - CSS 谷歌字体 (33)
 - CSS 链接 (31)
 - CSS 定位 (31)
 - CSS 图片库 (32)
 - CSS 图像精灵 (31)
 - SVG 文本 (32)
 - 时钟启动 (33)
 - HTML 游戏 (34)
 - JS Loop For (32)
 
 
