javascript高级程序设计 -- 读书笔记(一)

这是我学习javascript时候的学习笔记,个人一直认为学习时做好笔记是个好习惯. 不管是保存在电脑上还是写在纸上.

在开发的也偶也会去翻翻,毕竟不是什么知识点都记得很清. 在这里分享给大家,希望对大家有用.

我看的这本书叫<javascript高级程序设计>  作者:Nicholas C.Zakas

 

我现在正在看<javascript设计模式> 和 <高性能javascript> 很不错

如果大家对javascript喜欢的话建议一读.

--------------------------------------------------------

isFinite(num)
判断一个数是否无穷大,不是则返回true

isNaN(num)
判断是否不是一个数字,如果num不是数字则返回true,反之返回false

toString()
可以将布尔值,数字转化成字符串。
数字转化成字符串还可以: var num = 10; num.toString(2); // 1010 num.toString(8); // 12

parseInt(sNum)
对字符串型转化成int型
parseInt('12ab')// 12, parseInt('12.2')// 12, parseInt('da22')// NaN, parseInt('oxA')// 10
parseInt('10',2)// 2 , parseInt('10',8)// 8 , parseInt('10',10)// 10
parseInt('010')// 8  , parseInt('010',8)//8 , parseInt('010',10)// 10

parseFloat(sNum)
对字符串型转化成float型
parseFloat('12ab')// 12.0, parseFloat('12.2')// 12.2, parseFloat('da22')// NaN, parseFloat('oxA')// NaN
parseFloat('090')// 90

强制转换:
Boolean(value)
Boolean('')// false, Boolean('hi')// true, Boolean(100)// true,
Boolean(null)// false Boolean(0)// false,  Boolean(new Object())// true

Number(value)
Number(false)// 0, Number(true)// 1, Number(undefined)// NaN, Number(null)// 0
Number('5.5')// 5.5 Number('56')// 56 Number('1.2.3')// NaN, Number(new Object())// NaN, Number(100)// 100

String(value)
String(null)// 'null', var oNull = null; oNull.toString()// 报错

Object类
具有的属性:
constructor:对创建对象的函数的引用(指针)。对于Object类,该指针指向原始的object()函数
prototype: 对该对象的对象原型的应用。对于所有的类,它默认返回Object对象的一个实例
hasOwnproperty(property): 判断对象是否有某个特定的属性。必须用字符串指定该属性(o.hasOwnProperty('name'))
isPrototypeOf(object): 判断该对象是否为另一个对象的原型
propertyIsEnumerable(property): 判断给定的属性是否可以用for...in语句
toString(): 返回对象原始的字符串表示
valueOf(): 返回最适合该对象的原始值。对于许多类,该方法返回的值都与toString()方法相同

Boolean类
是原始类行的引用类型。
var o = new Boolean(true);
Boolean对象将覆盖object类的valueOf方法,返回原始值,即true,false;
var oFalseObject = new Boolean(false);
var bResult = oFalseObject && true;// true
原因:在Boolean类中所有对象都会自动转换成true,所以oFalseObject的值是true

Number类
是Number原始类型的引用类型。
var oNumberObject = new Number(10);
要得到原始类型则: var iNum = oNumberObject.valueOf();

toFixed()
返回指定位数小数的数字字符串表示 var oNumberObject = new Number(99); oNumberObject.toFixed(2);// '99.00'

toExponential()
返回的是用科学计数法表示的数字的字符串形式。 var oNumberObject = new Number(99); oNumberObject.toExponential(1);// '9.9e+1'

toPrecision()
根据最有意义的形式来返回数字的预定形式或指数形式。var oNumberObject = new Number(99); oNumberObject.toPrecision(1)// 1e+2 ,oNumberObject.toPrecision(2)// 99, oNumberObject.toPrecision(3)// 99.0

String类
是String原始类型的对象表示方法。
var oStringObject = new String('Hello World');
String对象的valueOf方法和toString方法都返回String的原始类型

charAt()
访问字符串中单个字符。oStringObject.charAt(1)// 'e'

charCodeAt()
访问字符串中单个字符,且返回的是ASCII值。oStringObject.charCodeAt(1)// 101

concat()
把一个或多个字符串连接到String对象上的原始值上
oStringObject.concat(' gaga')// 'Hello World gaga'

indexOf(),lastIndexOf()
指定字符串在另一个字符串中的位置
oStringObject.indexOf('0')// '4', oStringObject.lastIndexOf('0')// '7'

localeCompare()
对字符串值进行排序
var oStringObject = new String('yellow');
oStringObject.localeCompare('bri');// 1
oStringObject.localeCompare('yellow');// 0
oStringObject.localeCompare('zz');// -1

slice()和substring()
都是创建子字符串区别在与,传入的参数是正数时,没区别,传入的参数为负数时,slice()方法会用字符串的长度加上参数,substring()则用0代替。
var oStringObject = new String('Hello World');
oStringObject.slice(-3);// 'rld',  oStringObject.substring(-3);// 'Hello World'
oStringObject.substring(3,-4);// 'Hel' 因为substring方法总是把较小的数字放在前面,较大数字放在后面
oStringObject.slice(3,-8)// ''

toLowerCase(),toLocaleLowerCase()
将字符串转化成全小写

toUpperCase(),toLocaleUpperCase()
将字符串转化成全大写

instanceof
识别正在处理对象的类型
var oStringObject = new String('Hello World');
alert(oStringObject instanceof String);// true

运算符:
delete
var o = new Object;
o.name = "jack";
alert(o.name);// "jack"
delete o.name;
alert(o.name);// "undefined"
delete不能删除开发者未定义的属性和方法, delete  o.toString()// 错误,toString()是原始的方法,不是开发者定义的

void
对任何值对返回undefined
<a href = 'javascript:window.open("about:blank")'>Click Me</a>

<a href = 'javascript:void(window.open("about:blank"))'>Click Me</a>


// 此处省略位运算符

关系运算符:
var bRet = "Black" < "alph";
alert(bRet);// "true"
字母B的ASCII码值为77,a为97,第一个相同就比较第二个,依次类推

var bRet = "23" < 3;
alert(bRet)// "false"
这里会先把字符串“23”转换成数字类型的23,然后在做比较

var bRet = "a" < 3;
alert(bRet)// "false"
字符串“a”不能转换成数字,即记过为NaN,任何包涵NaN的关系运算都要返回false

var bRet = "a" >= 3;
alert(bRet)// "false"

等号(==)
如果比较的两个两个元素类型不一样是要进行类型转换,规则如下:
1. 如果有一个是Boolean类型,一个是数字类型,则将Boolean类型转化成数字,false转化成0,true转成1
2. 如果有一个是字符串类型,一个是数字类型,则把字符串转化成数字
3. 如果有一个是字符串类型,一个是对象类型,则把对象转化成字符串(toString())
4. 如果有一个是对象类型,一个是数字类型,则把对象转化成数字
5. null和undefined相等
6. 不能把null和undefined转化成其他值
7. 如果有一个为NaN,等号返回false,非等号返回true。即使两个都是NaN,等号任然返回false
8. 如果两个元素是对象,这比较的是他们的引用值。如果俩个运算数指向同一个对象,那么等号返回true,不相等

== 和 ===:
var sNum = "22";
var iNum = 22;
alert(sNum == iNum);// "true"
alert(sNum === iNum);// "false"
===是在sNum没有转化成数字类型的情况下进行比较

var sNum = "22";
var iNum = 22;
alert(sNum != iNum);// "false"
alert(sNum !== iNum);// "true"

条件运算符(?:)

符合赋值运算符:
*=, /=, %=, +=, -=, <<=, >>=(有符号右移赋值), >>>=(无符号右移赋值)

逗号运算符(,)
可以在一条语句中执行多次运算

语句:
if()

do-while

for(var i = 0;i<10;i++){
    alert(i)
}

for-in
for(sProp in window){
    alert(sProp)
}

有标签的语句:
可被后来的break语句或continue语句调用
label:statement
start:var iCoutn = 10;


var iNum = 0;
start:
for(var i=0;i<10;i++){
    for(var j=0;j<10;j++){
 if(i==5&&j==5){
     break start;
 }
 iNum++;
    }
}
alert(iNum)

with 语句
with语句用于设置代码在特定对象中的作用域。语法:
 with(expression) statement

var sStr = 'hello';
with(sStr){
    alert(toUpperCase());// "HELLO"
}
with运行缓慢,最好避免

switch 语句
与Java不同的地方:可以使用字符串

函数:
如果函数无明确的返回值,或调用了没有参数的return语句,那么它真正的返回的值是undefined
函数不能重载,如果声明了两个一样的函数,则使用的是后一个

arguments对象:
function fArgu(){
   alert(arguments[0] + arguments[1]);
}
fArgu('hello',' world');// 'hello world'

Function类
var function_name = new Function(argument1,argument2,...argumentN,function_body);
function sayHi(name,say){
   alert(name + say);
}
写成:
var sayHi = new Function("name","say","alert(name+say)");
少使用,比传统的定义要慢的多,多有的函数都是Function类的实例。具有length属性,返回的参数个数


闭包:
指词法表示包括不必计算的变量的函数,也就是说,该函数能使用函数外定义的变量
var sMsg = "Hello World";
function say(){
    alert(sMsg);
}
say();
解释程序直到在调用该函数时要检查sMsg的值。sMsg将在函数调用时被赋值。

 

var iNum = 10;
function addNumbers(iNum1,iNum2){
    function doAddition(){
 return iNum1 + iNum2 + iNum;   
    }
    return doAddition();
}
alert(addNumbers(10,10));// 30
doAddition()是闭包,addNumbers()最后一步调用了内部函数,把两个参数和全局变量相加,并返回它们的和。


对象的声明:
var o = new Object(); 或 var o = new Object;

对象引用:
每次创建对象,存储在变量中的都是该对象的引用,而不是对象本身。

对象废除:
JavaScript有无用存储单元收集程序。每当函数执行完代码,该程序都会执行,释放所有的局部变量,还有在一些其他不可预知的情况下,该程序也会运行。

把对象所有引用都设置为null,可以强制性的废除对象。
var oObject = new Object();
oObject = null;
废除对象的所有引用时要当心。如果一个对象有两个或多个引用,则要正确废除该对象,必须将其所有引用都设置为null


早绑定和晚绑定:
早绑定:实例化对象之前定义它的特性和方法。JavaScript不支持
晚绑定:编译器或解释程序在运行前,不知道对象类型。使用晚绑定,无需检查对象的类型,只需要检查对象是否支持特性和方法即可。JavaScript中所有变量都采用晚绑定方法。


本地对象:
Object, Function, Array, String,Boolean, Number, Date, RegExp, Error,
EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError

=========
Array类:
声明:var oArr = new Array(); 或 var oArr = new Array(10); 或var oArr = ["red","blue"];
或者var sStr = "red,blue"; var oArr = sStr.split(",");

存入元素:
方法1. oArr[0] = "red"; oArr[1] = "blue";
方法2. oArr.push("red"); // 可以输入多个参数
方法3. oArr.unshift("black"); // 把black放在数组第一个位置,余下部分向下移动一个位置

删除元素:
oArr.pop(); // 删除最后一个元素,并作函数的返回值
oArr.shift() // 删除数组中的第一项,并作为函数的返回值


其它方法:
toString() // 返回数组字符串形式,以逗号隔开
join() //  将数组中的元素以给定的字符串相连
concat() // 与字符串一样,参数被加在数字末尾
slice() // 返回具有特定的数组,类似于substring()
sort() // 将数组中的元素排序,数字排序特殊,以后再介绍
reverse() // 颠倒数组元素顺序

splice()
arr.splice(0,2) // 删除数组中前两项
arr.splice(2,0,"red","blue"); // 在数组第二个元素后面插入red,blue
arr.splice(2,1,"red","blue"); // 先删除数组位置2中的项,然后在数组位置2处插入red,blue,如果想删除位置1中的项,则把参数2改为1
arr.splice(2,2,"red","blue"); //  先删除数组位置2,3中的项,然后在位置2处插入red,blue

==========
Date类:
JavaScript把日期存储为距离UTC时间1970年1月1日凌晨12点的毫秒数。

申明:var d = new Date();
var d = new Date(0); // 声明距离1970年1月1日凌晨12点的毫秒数
var d = new Date(2009,1,1);

方法:
Date.parse(); // var d = new Date(Date.parse("May 3,2004"));
Date.UTC(); // 参数是年,月,日,时,分,秒。其中年,月必须,其它可选。月份从0开始 var d = new Date(Date.UTC(2009,1,1)); 2009年2月1日  var d = new Date(Date.UTC(2009,1,1,13,2)); 2009年2月1日下午1点2分

toString(); // 返回有实现特定的字符串,采用人们可读懂的格式。
valueOf(); // 返回日期的毫秒表示。
toDateString(); // 以实现特定格式显示Date的日期部分(显示年,月,日)
toTimeString(); // 以实现特定格式显示Date的时间部分(时,分,秒,时区)
toLocaleString(); // 以地点特定的格式显示Date的日期和时间。如:2010年4月24日星期三 0:00:0
toLocaleDateString(); // 以地点特定的格式显示Date的日期部分。 如:2010年4月24日星期三
toLocaleTimeString(); // 以地点特定的格式显示Date的时间部分。 如:0:00:0
toUTCString();  // 以实现特定的格式显示Date的UTC时间
getTimezoneOffset(); // 某个时区与UTC之间的关系 new Date().getTimezoneOffset(); -480(即8个小时)

其它常见方法:
getTime(); // 返回日期毫秒表示。
getFullYear(); // 返回4位数字的年份
getMonth(); // 返回日期的月份,从0开始
getDate(); // 返回该月中的某天
getHours(); // 返回小时
getMinutes(); // 返回分钟
getSeconds(); // 返回秒
getMilliseconds(); // 返回毫秒值
... 其它百度之


=============

内置对象
两个:Global , Math 每个内置对象也是本地对象

Global对象:
实际上不存在,JavaScript中所有的函数都必须是某个对象的方法。例如  isNaN(),parseInt() 等方法都是Global对象的方法。

Global的其他方法:
encodeURI(),encodeURIComponent() :
对浏览器的URI进行编码,比如将空格转换成 %20
两者之间的区别: encodeURI()用于处理完整的URI,encodeURIComponent()处理某个URI片段,encodeURI()不对URI中的特殊字符进行编码,如冒号,前斜杠,问号,英镑符号。encodeURIComponent()对它发现的所有非标准字符进行编码。
var sUri = "http://www.baidu.com/hello world.html";
alert(encodeURI(sUri)); // http://www.baidu.com/hello%20world.html
alert(encodeURIComponent(sUri)); // http%3A%2F%2Fwww.baidu.com%2Fhello%20world.html

decodeURI(),decodeURIComponent():
使用方法与encodeURI(),encodeURIComponent()相反

encodeURI(),encodeURIComponent() ,decodeURI(),decodeURIComponent()这些方法代替了BOM的escape()和 unescape()方法。
URI方法对所有的Unicode符号编码,BOM只能对ASCII符号编码。尽量避免使用escape()和 unescape()方法。

eval():
能够执行字符串程序,eval("alert('hi')");

Global属性:
所有本地对象的构造函数都是Global对象的属性
undefined, NaN, Infinity(无穷大), Object(Object的构造函数), Array(Array的构造函数),Function, Boolean,
String, Number, Date, RegExp, Error, EvalError, RangeError, ReferenceError, SyntaxError, SyntaxError, TypeError URIError

-------------
Math对象:

Math属性:
E 值e,对数的底
LN10 10的自然对数
LN2 2的自然对数
LOG2E 以2为底E的对数
LOG10E 以10为底E的对数
PI 值π
SQRT1_2 1/2的平方根
SQER2 2的平方根

方法:
min();// 判断一组素中最小值,参数可以任意个 Math.min(1,2,5,33,4,5);
max();// 判断一组素中最大值,参数可以任意个 Math.max(1,2,5,33,4,5);
abs();// 返回数字的绝对值
舍入方法:
ceil();//  向上舍入,把数字向上舍入到最接近的值
floor()//  向下舍入,把数字向下舍入到最接近的值
round()//  标准的四舍五入

exp(); // 用于把Math.E 升到指定的幂
log(); // 返回特定数字的自然数底
pow(); // 把指定数字升到指定的幂
sqrt();// 返回指定数字的平方根

acos(x); // 返回x的反余弦值
asin(x); // 返回x的反正弦值
atan(x); // 返回x的反正切值
atan2(y,x);// 返回y/x的反余弦值
cos(x); // 返回x的余弦值
sin(x); // 返回x的正弦值
tan(x); // 返回x的正切值

random(); // 随机方法,返回一个0-1之间的随机数,不包括0和1
随机1-10:var iNum = Math.floor(Math.random()*10+1);
随机2-10:var iNum = Math.floor(Math.random()*9+2);
function myRandom(startIndex,endIndex){
    var i = endIndex - startIndex;
    return Math.floor(Math.random()*i + startIndex);
}

===============
宿主对象:
所有非本地对象都是宿主对象,即由JavaScript实现宿主环境提供的对象。所有BOM和DOM 对象都是宿主对象。


===============
作用域:

只存在一种作用域:公有域。JavaScript中所有对象的所有属性和方法都是公用的。

为了解决区分私有域,开发者们指定了一个规约,用来说明这些属性和方法是私有的。规约规定在属性名前后加上下划线。obj._name_ = 'Jim'
但是_name_属性还是公有的。也有只在前面加下划线的情况。 obj._name = 'Jim'

-------------
静态作用域并非静态的
JavaScript并没有静态作用域,但可以结合构造函数提供属性和方法。构造函数是函数,函数是对象,对象可以有属性和方法:
function sayHi(){
    alert("hi");
}
sayHi.sayhaha = function(){
    alert("haha");
}
sayHi(); // hi
sayHi.sayhaha(); // haha
sayhaha()方法是sayHi()中的一个方法。

-------------
关键字 this
用在对象的方法中。this总是指向调用该方法的对象。
var oCar = new Object;
oCar.color = "red";
oCar.showColor = function(){
    alert(this.color);
}
oCar.showColor();// red
这里关键字this用在对象的showColor()方法中,此时this等于oCar,下面的代码与上面的代码相同:
var oCar = new Object;
oCar.color = "red";
oCar.showColor = function(){
    alert(oCar.color);
}
oCar.showColor();// red

使用this变量的一个好处,看下面的例子:
function showColor(){
    alert(this.color);
}

var oCar1 =  new Object;
oCar1.color = "red";
oCar1.showColor = showColor;

var oCar2 =  new Object;
oCar2.color = "blue";
oCar2.showColor = showColor;

oCar1.showColor(); // red
oCar2.showColor(); // blue
注意,oCar1.showColor = showColor; 这两个showColor并不一样,前者是对象的属性,后者是全局函数

===============
定义类或对象:

工厂方式:
function createCar(){
    var oTempCar = new Object;
    oTempCar.color = "red";
    oTempCar.doors = 4;
    oTempCar.showColor = function(){
 alert(this.color);
    }
   
    return oTempCar;
}

var oCar1 = createCar();
var oCar2 = createCar();

------------------
构造函数方式:
按照惯例,首字母大写,例如:
function Car(sColor,iDoors){
 this.color = sColor;
 this.doors = iDoors;
 this.showColor = function(){
  alert(this.color);
 }
}

var oCar1 = new Car("red",4);
var oCar3 = new Car("blue",2);
这里与工厂方式不同,没有临时对象,事实上用new关键字创建对象时,先创建了一个对象,只有this才能访问这个对象。
然后可以直接赋予this属性,默认情况下是构造函数的返回值(不必明确使用return)

-------------------
原型方式:
利用prototype属性,可把它看成创建新对象所依赖的原型。
用空的构造方法来设置类名,然后所有的属性和方法都被直接赋予prototype属性。

function Car(){}

Car.prototype.color = "red";
Car.prototype.doors = 4;
Car.prototype.showColor(){
 alert(this.color);
}

var oCar1 = new Car();
var oCar2 = new Car();
这里oCar1和oCar2的showColor方法都指向同一个showColor方法的指针。当showColor()方法改变时,这两个对象中的showColor()方法都要修改。
例如:

function Car(){}

Car.prototype.drivers = new Array("Mike","Jim");
var oCar1 = new Car();
var oCar2 = new Car();

oCar1.drivers.push("Tom");

alert(oCar1.drivers); // Mike,Jim,Tom
alert(oCar2.drivers); // Mike,Jim,Tom
因为oCar1和oCar2的drivers属性都指向同一个对象,为了解决该问题,应该使用“混合的构造函数/原型方式”

-------------------
混合的构造函数/原型方式:
这里也就是联合使用构造函数和原型方式,这样可以像其他程序一样创建对象。
原理:用构造函数定义对象的所有非函数属性,用原型方式定义对象的函数属性(方法)。
这样所有函数只能创建一次,而且每个对象都有自己的对象属性实例。
function Car(sColor,iDoors){
 this.color = sColor;
 this.doors = iDoors;
 this.drivers = new Array("Mike","Jim");
}

Car.prototype.showColor = function(){
 alert(this.color);
}

var oCar1 = new Car("red",4);
var oCar2 = new Car("blue",2);

oCar1.drivers.push("Tom");

alert(oCar1.drivers); // Mike,Jim,Tom
alert(oCar2.drivers); // Mike,Jim

-------------------
动态原型方法:
混合的构造函数/原型方式并不令人满意,因为有人认为在构造函数中找属性做法不好。
因此设计出了动态原型方法。原理:在构造函数中定义非函数属性,函数属性则利用原型属性定义。例如:
function Car(sColor,iDoors){
 this.color = sColor;
 this.doors = iDoors;
 this.drivers = new Array("Mike","Jim");

 if(typeof Car._initialized == "undefined"){
  Car.prototype.showColor = function(){
   alert(this.color);
  };
  
  Car._initialized = true;
 }
}
Car._initialized的作用就是使用标志来判断是否已给原型赋予了任何方法。该方法只创建了一次。

--------------------
混合工厂方式:
function Car(){
    var oTempCar = new Object;
    oTempCar.color = "red";
    oTempCar.doors = 4;
    oTempCar.showColor = function(){
 alert(this.color);
    }
   
    return oTempCar;
}

var car = new Car();
由于Car()构造函数内部使用了new关键字,所以第二个new关键字将忽略(位于构造函数之外的)

=====================
采用哪种方式:
目前使用最广泛的是混合的构造函数/原型方式,动态原型方法也很流行。不要单独的使用构造函数或原型方式。

实例:
var str = "hello";
str += "world";

这两段代码的实现步骤如下:
 1. 创建存储hello的字符串
 2. 创建存储world的字符串
 3. 创建存储连接结果的字符串
 4. 把str的当前内容复制到结果中
 5. 把world复制到结果中
 6. 更新str,使它指向结果

每次这样做会非常耗资源,因此推荐使用Array类来包装。
例如:
var arr = new Array;
arr[0] = "hello";
arr[1] = "world";
var str = arr.join(""); // helloworld

在引申下就可以模仿一个 StringBuffer类:
function StringBuffer(){
 this._strings = new Array;
}

StringBuffer.prototype.append = function(s){
 this._strings.push(s);
}

StringBuffer.prototype.toString = function(){
 return this._strings.join("");
}

var sb = new StringBuffer();
sb.append("hello ");
sb.append("world");
alert(sb.toString()); // hello world

=================
修改对象:

创建新方法:
可以用prototype属性为任何已有的类定义新的方法.

例如:
Number.prototype.toHexString = function(){
 return this.toString(16);
}

var i = 12;
alert(i.toHexString());// c

Object.prototype.showValue = function(){
 alert(this.valueOf());
}
var str = "aaa";
str.showValue();

----------------
重定义已有的方法:
函数名只是指向函数的指针,因此可以轻易使它指向其他函数.
例如:
Function.prototype.toString = function(){
 return "haha";
}
function say(){
 alert("hi");
}
alert(say.toString()); // haha
通常Function的toString方法是返回方法的源代码,这里覆盖了toString方法,返回的是haha
原来的那个toString函数被无用的存储单元回收. 因此可以对原始方法进行存储.例如:

Function.prototype.oldToString = Function.toString;
Function.prototype.toString = function(){
 return "haha";
}
function say(){
 alert("hi");
}
alert(say.toString()); // haha
alert(say.oldToString()); // 打印say方法源码

-----------------
极晚绑定:

既能够在对象实例化之后再定义它的方法.
var o = new Object;

Object.prototype.say = function(){
 alert("hello world");
}
o.say();// hello world

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值