JavaScript - 2 基础语法-1

参考链接:学习JavaScript这一篇就够了_轻松的小希的博客-CSDN博客

1. 标识符

起名规则:

第一个字符必须是字母,下划线或者$

其它字符可以是字母,下划线,$,数字

驼峰命名法,第一个单词小写,之后的单词首字母大写

不能是关键字和保留字符

2. 变量

变量声明, 与C语言类似,在C中,需要声明使用数据类型,但是变量类型为var,可以保存任何类型的数据,若没有初始化,则会保存undefined

var a;

参考:JavaScript 变量声明详解 - 知乎

3. 数据类型

JS中5种基本数据类型:

string number boolean undefined null,这5种之外都为Object

可以用typeof获取数据类型。

typeof xxx

特殊的数字,属于number类型,Infinity, -Infinity, NaN (Not A Number) 分别是正无穷,负无穷,还有非法数字。

undifined类型只有一个值,即为undifined,也就是说这个类型是undefined,值也是undifned。

Null类型也只有一个值,即为null,undifined由null衍生出来,比较undefined和null是否相等,会返回true。用typeof检查null会返回Object,表示一个空的对象。

3.1 数据类型强制转换

当给null使用toString时报的错,不支持该方法,使用String() or +""

// cast to string, notice the capital "S" in String()
var a = 123;
a = a.toString();
b = String(a);
c = a + "";
console.log(a, b, c);

// for null and undefined type, toString() is not available
// there will be an error
var a1 = null;
var a2 = undefined;
a1 = String(a1);
a2 = String(a2);

// cast to number
var b1 = "1234";
// Number(0 can be used to cast any type of data to number type
b1 = Number(b1);
// only be used when operation object type is String and the result will be //integer.
b1_1 = parseInt(b1); 
//transfer a string to float
b1_2 = parseFloat(b1);

// cast to boolean
Number c1 = 1;
c1 = Boolean(c1);

3. 运算符

没有接触过的,其他的运算符类似:

全等 ===,和相等==的区别:

== 会自动做类型转换,如果式子两端的类型不同,会自动转换为同一类型进行比较

=== 则不会自动做类型转换,如果两个值的类型不同 直接返回false

不全等  !== 与!= 的关系和全等与相等类似

4. 对象基础

对象,类似C语言种的结构体,会包含对象的一些共有属性。

Object类型是JS中的引用数据类型,可以将很多值聚合到一起,通过名字进行访问,每个属性都是一个名字+值的数据对。对象可以创建自有属性,也可以从名为原型的对象那里继承属性。

两种创建对象的方式

// the first method
var student = new Object();
student.name = "Jack";
student.sex = "male";
student.age = 13;

// the second method
var student_1 = {
    name: "Jack",
    sex: "male",
    age: 18
};

两种访问属性的方式:

student.name
// or
student['name']

删除属性:

delete student.name

遍历对象

// loop all keys in student object
for (var studentKey in student)
{
  var studentValue = student[studentKey];
  console.log(studentKey + ":" + studentValue);
}

5. 引用数据类型

引用数据类型是保存在内存中的对象。 当一个变量是一个对象Object时,实际上变量中保存的并不是对象本身,而是对象的引用。

当从一个变量向另一个变量复制引用类型的值时,会将对象的引用复制到变量中,并不是创建一个新的对象。 这时,两个变量指向的是同一个对象。因此,改变其中一个变量会影响另一个。

6. 栈 堆

栈内存 - 保存变量和基本类型(Number boolean 等), 先进后出,后进先出

堆内存 - 保存对象

6. 函数

JS中的函数时一个对象, 用typeof检查函数时,会返回function

6.1 函数创建的几种方式

使用函数对象创建一个函数

var testF = new Function("statement");

使用函数声明创建一个函数

function testF ([param1, param2, param3,...,paramN])
{
statement;
}

使用函数表达式来创建一个函数2, 即匿名函数

var testF = function([param1, param2,..., paramN])
{
  statement;
}

使用函数名进行调用

一个函数可以作为一个对象的属性进行保存,这个函数则是这个对象的方法

this对象,解析器在调用函数时,每次都会向函数内部传递一个隐含的参数,即this,this指向一个对象,根据函数的调用方式不同,this 会指向不同的对象,

以函数的形式调用时,this 为 window

以方法的形式调用时,this 为调用方法的那个属性所属于的那个对象

7. 对象进阶

7.1 创建多个具有相同属性的对象时的方法

创建多个对象,使用工厂模式。

function createStudent(name, age){
  // create new object
  var obj = new Object();
  // set attributes
  obj.name = name;
  obj.age = age;
  // set method
  obj.printName = function() {
    console.log(this.name);
  };
  return obj;
}

// loop
for (var i = 1; i <= 1000; i++)
{
  // It's difficult to set " unique string" name, like Jack, Rose
  var student = createStudent("student" + i, 18);
  console.log(person);
}

用构造函数来创建对象,每个构造函数类似一个Class,每一个student都属于Student这个class, 用这种方法创建的对象被称为类的实例。

构造函数和普通函数的区别:调用方式不同,普通函数直接调用,但构造函数需要用new关键字来调用

1. 调用构造函数,会立刻创建一个新的对象

2. 将新建的对象设置为函数中的this, 在构造函数中可以使用this来引用新建的对象

3. 逐行执行函数中的代码

4. 将新建的对象作为返回值返回

与工厂创建方法相比:隐藏了创建对象(var objt = new Object() ) 和返回对象 (return Obj).

使用同一个构造函数创建的对象,称为一类对象,所以也将一个构造函数称为一个类。

通过一个构造函数创建的对象,称为该类的实例(instance)

以构造函数的形式调用时,this是新创建的那个对象Student

function Student(name, age)
{
  // attribute
  this.name = name;
  this.age = age;
  // method
  this.printName = function (){
    console.log(this.name)
  };
}

var student1 = new Student("Jack", 18);
var student2 = new Student("Rose", 18);

7.2 原型

使用构造函数的方式创建多个对象,会保存多个相同的方法--> this.printName, 当创建的对象数量非常多时,会占用极大的内存。所以,将该方法的函数抽取出来,作为全局函数,直接在构造函数中引用。

// extract method as a global function
function printName()
{
  console.log(this.name);
}

function Student(name, age)
{
  this.name = name;
  this.age = age;
  this.printName = printName;
}

如果出现同名方法,会导致conflict。只在Student这个类的全局度喜庆中添加该函数,然后在类中引用-->在原型对象中添加, 之后直接在实例中使用,student1.printname();

Student.prototype.printName = function()
{
  console.log(this.name);
}

原型 prototype

每创建一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,即原型对象(显式原型),相当于一个公共的区域(一块公共的内存,地址是同一个),所有的同一个类的实例都可以共享的区域,都能够访问到这个原型对象,所以可以将一类对象中共有的内容,统一设置到原型对象中。

当函数作为普通函数被调用时,prototype没有作用

当函数作为构造函数被调用时,该函数所创建的对象中都会含有一个隐含的属性,指向该构造函数的原型对象,可以通过__proto__(隐式原型)来访问该属性。当访问对象的一个属性或方法时,规则是现在对象自身中寻找,如果有则直接使用,没有则到原型对象中寻找,如果找到则直接使用。

以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了。

7.4 原型链

上面👆所说的,访问一个对象的属性时,先在对象自身属性找,找不到的话通过__proto__来访问公共区域内的属性,如果最终还没有,就返回undefined。这一搜索or访问顺序称为隐式原型链,作用就是查找对象的属性偶or方法。原型对象也有原型,顺着这样一直往下找,直到找到Object对象的原型,Object的原型为空,返回值为undefined。用构造函数创建的最原始的对象就是Object对象。

7.5 toString方法

该方法属于Object对象(最原始的那个对象,而不是对象实例),功能是将当前对象以字符串的形式返回。该方法属于内置的方法,不需要自己定义。对于类型为Object的变量,返回[object, ObjectName], ObjectName是对象类型的名称,类型可以是Number, Boolean等

ObjectType JS对象分类_js 对象类型_跨越海沟的博客-CSDN博客

JavaScript中的toString方法详解_js tostring()方法_周晓风的博客-CSDN博客

 7.6 hasOwnProperty()

功能: 检查自身对象是否含有某个方法或属性,属于Object原型中(最初创建的对象的原型)的属性

hasOwnProperty("属性名"); 返回值为布尔

7.7 对象继承

JS通过prototype来实现面向对象编程,而不是类

继承,可以使子对象使用父对象的属性和方法,从而简化一部分代码

6种继承方式,

  1. 原型链继承
  2. 使用构造函数继承
  3. 组合继承
  4. 原型式继承
  5. 寄生式继承
  6. 寄生组合式继承

1.原型链继承

子类型的原型prototype为父类型的一个实例

通用方法,

  • 用构造函数创建一个父类型的原始对象
  • 给父类型对象的原型添加方法 (定义另一个函数)
  • 定义子类型的构造函数
  • 创建父类型的一个对象实例,将其赋值给子类型的原型,用于通过原型链搜索到添加在父类型中的方法
  • 将子类型的原型的构造属性constructor设置为子类型
  • 给子类型的原型添加方法
  • 创建子类型的对象实例,调用父类型的方法和子类型的方法,发现可以实现继承。

局限性

// 定义父类型构造函数
function SupperType() {
    this.supProp = 'Supper property';
}

// 给父类型的原型添加方法
SupperType.prototype.showSupperProp = function () {
    console.log(this.supProp);
};

// 定义子类型的构造函数
function SubType() {
    this.subProp = 'Sub property';
}

// 创建父类型的对象赋值给子类型的原型
SubType.prototype = new SupperType();

// 将子类型原型的构造属性设置为子类型
SubType.prototype.constructor = SubType;

// 给子类型原型添加方法
SubType.prototype.showSubProp = function () {
    console.log(this.subProp)
};

// 创建子类型的对象: 可以调用父类型的方法
var subType = new SubType();
subType.showSupperProp();
subType.showSubProp();

注意出错点: 拼写错误,新声明的对象实例,在后续引用时候名字保持一致 

2. 借用构造函数继承

.call() 和 .apply() 将父类构造函数引入子类函数,使用父类的构造函数来增强子类实例,等于复制父类的实例给子类

步骤:

  • 构建父类函数,创建父类的方法
  • 构建子类函数,在子类中应用call函数,继承父类的属性,fatherType.call(this, name);相当于将子类的名字作为一个入参传入到父类构建函数,当创建实例的时候,调用父类方法,单参数是子类的
  • 把子类方法加入到子类的原型中
  • 创建子类的实例,然后调用各种方法
function fatherType(name)
{
    this.name = name;
    this.showFatherName = function()
    {
        console.log(this.name);
    };
}

function sonType(name, age)
{
    // use call to extend the attributes from fatherType
    fatherType.call(this, name); // this is father object, name is from sonType
    // but when use showFatherName method, it can use this method to show son's name.
    this.age = age;
}

sonType.prototype.showSonName = function()
{
    console.log(this.name);
}

var sonType1 = new sonType('Jack', 12);
sonType1.showFatherName();
sonType1.showSonName();
console.log(sonType1.name);
console.log(sonType1.age);

无法继承父类型的原型内的属性和方法,只能继承父类型的实例属性和方法

3. 组合继承 (最常用的继承模式)

原型链 + 借用构造函数

步骤

  • 利用原型链实现对父类型对象的方法继承
  • 利用super()借用父类型构建函数初始化相同属性

 这种方法导致父类中的实例属性和方法既存在于子类的实例中,也存在于子类的原型中,造成重复

function flower(name, color)
{
    this.name = name;
    this.color = color;
    this.showName = function(){
        console.log(this.name);
    };

}

flower.prototype.setNewColor = function(newColor)
{
    // this means flower
    this.color = newColor;
}

function goods(name, color, price)
{
    flower.call(this, name, color);
    this.price = price;
}

// the order of adding function should be after the two
// otherwise there will be an error that setPrice is not a function
goods.prototype = new flower();
goods.prototype.constructor = goods;
goods.prototype.setPrice = function(price)
{
    this.price = price;
}
var goods1 = new goods("rose", "red", 20);
console.log(goods1.name, goods1.color, goods1.price);
goods1.setNewColor("yellow");
goods1.setPrice(30);
goods1.showName();
console.log(goods1.color, goods1.price);

 4. 垃圾回收

GC garbage cycle, 处理程序运行过程中产生的垃圾

当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,所以这种垃圾必须进行清理。 dead code? 声明了,但未被实际使用

在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,我们不需要也不能进行垃圾回收的操作,我们需要做的只是要将不再使用的对象设置null即可。

var flower1 = new flower("rose","red");

// GC
flower1 = null;

8. 作用域

8.1 声明提前

变量声明提前-- 使用var,不管在哪个位置使用,会在所有代码被执行前声明,如果不用var声明,则变量不会被声明提前

函数的声明提前 -- 使用函数声明形式创建的函数 function () {}会被声明提前,提前到所有代码执行之前,所以,在声明该函数的语句之前,可以调用该函数

  使用函数表达式创建的函数,不会被声明提前

// 函数声明形式
function sum(i, j)
{
  return i + j;
}

// 函数表达式
var sum = function(i, j){
  return i + j;
}

8.2 全局作用域

在全局作用域中有一个全局对象window,代表浏览器的窗口,由浏览器创建

在全局作用域中创建的变量都会作为window对象的属性保存,创建的函数都会作为window对象的方法保存

在打开页面时,创建全局作用域,关闭页面时销毁全局作用域。

直接编写在script变迁中的JS代码,属于全局作用域

8.3 函数作用域

调用函数时创建的作用域,函数执行完毕后销毁。

每调用一次函数就会创建一个新的作用域,它们之间是相互独立的。

在函数中想要访问全局变量可以使用window对象

在函数作用域中可以访问到全局作用域的变量,在全局作用域中无法访问到函数作用域的变量

8.4 作用域链

多个上下级关系的作用域形成的链,方向:从下到上,从内到外

查找变量时,现在自身作用域中寻找,如果有,就直接使用,如果没有就向上一级作用域寻找,以此类推,直到找到全局作用域,如果依然没有,则报错referenceError

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值